##// END OF EJS Templates
bundle: do no check the changegroup version if no changegroup is included...
marmoute -
r52450:cc44b3df default
parent child Browse files
Show More
@@ -1,8030 +1,8033 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import os
9 import os
10 import re
10 import re
11 import sys
11 import sys
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullid,
16 nullid,
17 nullrev,
17 nullrev,
18 short,
18 short,
19 wdirrev,
19 wdirrev,
20 )
20 )
21 from . import (
21 from . import (
22 admin_commands as admin_commands_mod,
22 admin_commands as admin_commands_mod,
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 bundlecaches,
26 bundlecaches,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 diffutil,
32 diffutil,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 filemerge,
38 filemerge,
39 formatter,
39 formatter,
40 graphmod,
40 graphmod,
41 grep as grepmod,
41 grep as grepmod,
42 hbisect,
42 hbisect,
43 help,
43 help,
44 hg,
44 hg,
45 logcmdutil,
45 logcmdutil,
46 merge as mergemod,
46 merge as mergemod,
47 mergestate as mergestatemod,
47 mergestate as mergestatemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 requirements,
56 requirements,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 tags as tagsmod,
63 tags as tagsmod,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 verify as verifymod,
66 verify as verifymod,
67 vfs as vfsmod,
67 vfs as vfsmod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 procutil,
72 procutil,
73 stringutil,
73 stringutil,
74 urlutil,
74 urlutil,
75 )
75 )
76
76
77 table = {}
77 table = {}
78 table.update(debugcommandsmod.command._table)
78 table.update(debugcommandsmod.command._table)
79 table.update(admin_commands_mod.command._table)
79 table.update(admin_commands_mod.command._table)
80
80
81 command = registrar.command(table)
81 command = registrar.command(table)
82 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
83
83
84 # common command options
84 # common command options
85
85
86 globalopts = [
86 globalopts = [
87 (
87 (
88 b'R',
88 b'R',
89 b'repository',
89 b'repository',
90 b'',
90 b'',
91 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
92 _(b'REPO'),
92 _(b'REPO'),
93 ),
93 ),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (
95 (
96 b'y',
96 b'y',
97 b'noninteractive',
97 b'noninteractive',
98 None,
98 None,
99 _(
99 _(
100 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
101 ),
101 ),
102 ),
102 ),
103 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
105 (
105 (
106 b'',
106 b'',
107 b'color',
107 b'color',
108 b'',
108 b'',
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # and should not be translated
110 # and should not be translated
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b'TYPE'),
112 _(b'TYPE'),
113 ),
113 ),
114 (
114 (
115 b'',
115 b'',
116 b'config',
116 b'config',
117 [],
117 [],
118 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'CONFIG'),
119 _(b'CONFIG'),
120 ),
120 ),
121 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
123 (
123 (
124 b'',
124 b'',
125 b'encoding',
125 b'encoding',
126 encoding.encoding,
126 encoding.encoding,
127 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
128 _(b'ENCODE'),
128 _(b'ENCODE'),
129 ),
129 ),
130 (
130 (
131 b'',
131 b'',
132 b'encodingmode',
132 b'encodingmode',
133 encoding.encodingmode,
133 encoding.encodingmode,
134 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
135 _(b'MODE'),
135 _(b'MODE'),
136 ),
136 ),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (
143 (
144 b'',
144 b'',
145 b'pager',
145 b'pager',
146 b'auto',
146 b'auto',
147 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b'TYPE'),
148 _(b'TYPE'),
149 ),
149 ),
150 ]
150 ]
151
151
152 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
153 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
154 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
155 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
156 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
157 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
158 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
159 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
160 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
161 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
162 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
163 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
164 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
165 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
166 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
167 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
168
168
169 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
170
170
171
171
172 @command(
172 @command(
173 b'abort',
173 b'abort',
174 dryrunopts,
174 dryrunopts,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpbasic=True,
176 helpbasic=True,
177 )
177 )
178 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
179 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
180
180
181 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
182 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
183
183
184 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
185 """
185 """
186 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
187 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
188 if not abortstate:
188 if not abortstate:
189 raise error.StateError(_(b'no operation in progress'))
189 raise error.StateError(_(b'no operation in progress'))
190 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
191 raise error.InputError(
191 raise error.InputError(
192 (
192 (
193 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
194 % (abortstate._opname)
194 % (abortstate._opname)
195 ),
195 ),
196 hint=abortstate.hint(),
196 hint=abortstate.hint(),
197 )
197 )
198 if dryrun:
198 if dryrun:
199 ui.status(
199 ui.status(
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 )
201 )
202 return
202 return
203 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
204
204
205
205
206 @command(
206 @command(
207 b'add',
207 b'add',
208 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
209 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpbasic=True,
211 helpbasic=True,
212 inferrepo=True,
212 inferrepo=True,
213 )
213 )
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 with repo.wlock(), repo.dirstate.changing_files(repo):
257 with repo.wlock(), repo.dirstate.changing_files(repo):
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 with repo.wlock(), repo.dirstate.changing_files(repo):
336 with repo.wlock(), repo.dirstate.changing_files(repo):
337 matcher = scmutil.match(repo[None], pats, opts)
337 matcher = scmutil.match(repo[None], pats, opts)
338 relative = scmutil.anypats(pats, opts)
338 relative = scmutil.anypats(pats, opts)
339 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
340 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
341
341
342
342
343 @command(
343 @command(
344 b'annotate|blame',
344 b'annotate|blame',
345 [
345 [
346 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
347 (
347 (
348 b'',
348 b'',
349 b'follow',
349 b'follow',
350 None,
350 None,
351 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 _(b'follow copies/renames and list the filename (DEPRECATED)'),
352 ),
352 ),
353 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
354 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'a', b'text', None, _(b'treat all files as text')),
355 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'u', b'user', None, _(b'list the author (long with -v)')),
356 (b'f', b'file', None, _(b'list the filename')),
356 (b'f', b'file', None, _(b'list the filename')),
357 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'd', b'date', None, _(b'list the date (short with -q)')),
358 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'n', b'number', None, _(b'list the revision number (default)')),
359 (b'c', b'changeset', None, _(b'list the changeset')),
359 (b'c', b'changeset', None, _(b'list the changeset')),
360 (
360 (
361 b'l',
361 b'l',
362 b'line-number',
362 b'line-number',
363 None,
363 None,
364 _(b'show line number at the first appearance'),
364 _(b'show line number at the first appearance'),
365 ),
365 ),
366 (
366 (
367 b'',
367 b'',
368 b'skip',
368 b'skip',
369 [],
369 [],
370 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'revset to not display (EXPERIMENTAL)'),
371 _(b'REV'),
371 _(b'REV'),
372 ),
372 ),
373 (
373 (
374 b'L',
374 b'L',
375 b'line-range',
375 b'line-range',
376 [],
376 [],
377 _(b'follow line range of specified file (EXPERIMENTAL)'),
377 _(b'follow line range of specified file (EXPERIMENTAL)'),
378 _(b'FILE,RANGE'),
378 _(b'FILE,RANGE'),
379 ),
379 ),
380 ]
380 ]
381 + diffwsopts
381 + diffwsopts
382 + walkopts
382 + walkopts
383 + formatteropts,
383 + formatteropts,
384 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
384 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
385 helpcategory=command.CATEGORY_FILE_CONTENTS,
385 helpcategory=command.CATEGORY_FILE_CONTENTS,
386 helpbasic=True,
386 helpbasic=True,
387 inferrepo=True,
387 inferrepo=True,
388 )
388 )
389 def annotate(ui, repo, *pats, **opts):
389 def annotate(ui, repo, *pats, **opts):
390 """show changeset information by line for each file
390 """show changeset information by line for each file
391
391
392 List changes in files, showing the revision id responsible for
392 List changes in files, showing the revision id responsible for
393 each line.
393 each line.
394
394
395 This command is useful for discovering when a change was made and
395 This command is useful for discovering when a change was made and
396 by whom.
396 by whom.
397
397
398 If you include --file, --user, or --date, the revision number is
398 If you include --file, --user, or --date, the revision number is
399 suppressed unless you also include --number.
399 suppressed unless you also include --number.
400
400
401 Without the -a/--text option, annotate will avoid processing files
401 Without the -a/--text option, annotate will avoid processing files
402 it detects as binary. With -a, annotate will annotate the file
402 it detects as binary. With -a, annotate will annotate the file
403 anyway, although the results will probably be neither useful
403 anyway, although the results will probably be neither useful
404 nor desirable.
404 nor desirable.
405
405
406 .. container:: verbose
406 .. container:: verbose
407
407
408 Use -L/--line-range FILE,M:N options to filter the output to the lines
408 Use -L/--line-range FILE,M:N options to filter the output to the lines
409 from M to N in FILE. This option is incompatible with --no-follow and
409 from M to N in FILE. This option is incompatible with --no-follow and
410 cannot be combined with file pattern arguments. When combined with --rev
410 cannot be combined with file pattern arguments. When combined with --rev
411 the line ranges refer to the state of the file at the requested revision.
411 the line ranges refer to the state of the file at the requested revision.
412
412
413 .. container:: verbose
413 .. container:: verbose
414
414
415 Template:
415 Template:
416
416
417 The following keywords are supported in addition to the common template
417 The following keywords are supported in addition to the common template
418 keywords and functions. See also :hg:`help templates`.
418 keywords and functions. See also :hg:`help templates`.
419
419
420 :lines: List of lines with annotation data.
420 :lines: List of lines with annotation data.
421 :path: String. Repository-absolute path of the specified file.
421 :path: String. Repository-absolute path of the specified file.
422
422
423 And each entry of ``{lines}`` provides the following sub-keywords in
423 And each entry of ``{lines}`` provides the following sub-keywords in
424 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
424 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
425
425
426 :line: String. Line content.
426 :line: String. Line content.
427 :lineno: Integer. Line number at that revision.
427 :lineno: Integer. Line number at that revision.
428 :path: String. Repository-absolute path of the file at that revision.
428 :path: String. Repository-absolute path of the file at that revision.
429
429
430 See :hg:`help templates.operators` for the list expansion syntax.
430 See :hg:`help templates.operators` for the list expansion syntax.
431
431
432 Returns 0 on success.
432 Returns 0 on success.
433 """
433 """
434 opts = pycompat.byteskwargs(opts)
434 opts = pycompat.byteskwargs(opts)
435
435
436 linerange = opts.get(b'line_range')
436 linerange = opts.get(b'line_range')
437
437
438 if linerange and opts.get(b'no_follow'):
438 if linerange and opts.get(b'no_follow'):
439 raise error.InputError(
439 raise error.InputError(
440 _(b'--line-range is incompatible with --no-follow')
440 _(b'--line-range is incompatible with --no-follow')
441 )
441 )
442
442
443 if pats and linerange:
443 if pats and linerange:
444 raise error.InputError(
444 raise error.InputError(
445 _(b'cannot combine filename or pattern and --line-range')
445 _(b'cannot combine filename or pattern and --line-range')
446 )
446 )
447
447
448 if not pats and not linerange:
448 if not pats and not linerange:
449 raise error.InputError(
449 raise error.InputError(
450 _(b'at least one filename or pattern is required')
450 _(b'at least one filename or pattern is required')
451 )
451 )
452
452
453 if opts.get(b'follow'):
453 if opts.get(b'follow'):
454 # --follow is deprecated and now just an alias for -f/--file
454 # --follow is deprecated and now just an alias for -f/--file
455 # to mimic the behavior of Mercurial before version 1.5
455 # to mimic the behavior of Mercurial before version 1.5
456 opts[b'file'] = True
456 opts[b'file'] = True
457
457
458 if (
458 if (
459 not opts.get(b'user')
459 not opts.get(b'user')
460 and not opts.get(b'changeset')
460 and not opts.get(b'changeset')
461 and not opts.get(b'date')
461 and not opts.get(b'date')
462 and not opts.get(b'file')
462 and not opts.get(b'file')
463 ):
463 ):
464 opts[b'number'] = True
464 opts[b'number'] = True
465
465
466 linenumber = opts.get(b'line_number') is not None
466 linenumber = opts.get(b'line_number') is not None
467 if (
467 if (
468 linenumber
468 linenumber
469 and (not opts.get(b'changeset'))
469 and (not opts.get(b'changeset'))
470 and (not opts.get(b'number'))
470 and (not opts.get(b'number'))
471 ):
471 ):
472 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
472 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
473
473
474 rev = opts.get(b'rev')
474 rev = opts.get(b'rev')
475 if rev:
475 if rev:
476 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
476 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
477 ctx = logcmdutil.revsingle(repo, rev)
477 ctx = logcmdutil.revsingle(repo, rev)
478
478
479 if not pats:
479 if not pats:
480 pats = [
480 pats = [
481 fname
481 fname
482 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
482 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
483 ]
483 ]
484
484
485 ui.pager(b'annotate')
485 ui.pager(b'annotate')
486 rootfm = ui.formatter(b'annotate', opts)
486 rootfm = ui.formatter(b'annotate', opts)
487 if ui.debugflag:
487 if ui.debugflag:
488 shorthex = pycompat.identity
488 shorthex = pycompat.identity
489 else:
489 else:
490
490
491 def shorthex(h):
491 def shorthex(h):
492 return h[:12]
492 return h[:12]
493
493
494 if ui.quiet:
494 if ui.quiet:
495 datefunc = dateutil.shortdate
495 datefunc = dateutil.shortdate
496 else:
496 else:
497 datefunc = dateutil.datestr
497 datefunc = dateutil.datestr
498 if ctx.rev() is None:
498 if ctx.rev() is None:
499 if opts.get(b'changeset'):
499 if opts.get(b'changeset'):
500 # omit "+" suffix which is appended to node hex
500 # omit "+" suffix which is appended to node hex
501 def formatrev(rev):
501 def formatrev(rev):
502 if rev == wdirrev:
502 if rev == wdirrev:
503 return b'%d' % ctx.p1().rev()
503 return b'%d' % ctx.p1().rev()
504 else:
504 else:
505 return b'%d' % rev
505 return b'%d' % rev
506
506
507 else:
507 else:
508
508
509 def formatrev(rev):
509 def formatrev(rev):
510 if rev == wdirrev:
510 if rev == wdirrev:
511 return b'%d+' % ctx.p1().rev()
511 return b'%d+' % ctx.p1().rev()
512 else:
512 else:
513 return b'%d ' % rev
513 return b'%d ' % rev
514
514
515 def formathex(h):
515 def formathex(h):
516 if h == repo.nodeconstants.wdirhex:
516 if h == repo.nodeconstants.wdirhex:
517 return b'%s+' % shorthex(hex(ctx.p1().node()))
517 return b'%s+' % shorthex(hex(ctx.p1().node()))
518 else:
518 else:
519 return b'%s ' % shorthex(h)
519 return b'%s ' % shorthex(h)
520
520
521 else:
521 else:
522 formatrev = b'%d'.__mod__
522 formatrev = b'%d'.__mod__
523 formathex = shorthex
523 formathex = shorthex
524
524
525 opmap = [
525 opmap = [
526 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
526 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
527 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
527 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
528 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
528 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
529 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
529 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
530 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
530 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
531 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
531 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
532 ]
532 ]
533 opnamemap = {
533 opnamemap = {
534 b'rev': b'number',
534 b'rev': b'number',
535 b'node': b'changeset',
535 b'node': b'changeset',
536 b'path': b'file',
536 b'path': b'file',
537 b'lineno': b'line_number',
537 b'lineno': b'line_number',
538 }
538 }
539
539
540 if rootfm.isplain():
540 if rootfm.isplain():
541
541
542 def makefunc(get, fmt):
542 def makefunc(get, fmt):
543 return lambda x: fmt(get(x))
543 return lambda x: fmt(get(x))
544
544
545 else:
545 else:
546
546
547 def makefunc(get, fmt):
547 def makefunc(get, fmt):
548 return get
548 return get
549
549
550 datahint = rootfm.datahint()
550 datahint = rootfm.datahint()
551 funcmap = [
551 funcmap = [
552 (makefunc(get, fmt), sep)
552 (makefunc(get, fmt), sep)
553 for fn, sep, get, fmt in opmap
553 for fn, sep, get, fmt in opmap
554 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
554 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
555 ]
555 ]
556 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
556 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
557 fields = b' '.join(
557 fields = b' '.join(
558 fn
558 fn
559 for fn, sep, get, fmt in opmap
559 for fn, sep, get, fmt in opmap
560 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
560 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
561 )
561 )
562
562
563 def bad(x, y):
563 def bad(x, y):
564 raise error.InputError(b"%s: %s" % (x, y))
564 raise error.InputError(b"%s: %s" % (x, y))
565
565
566 m = scmutil.match(ctx, pats, opts, badfn=bad)
566 m = scmutil.match(ctx, pats, opts, badfn=bad)
567
567
568 follow = not opts.get(b'no_follow')
568 follow = not opts.get(b'no_follow')
569 diffopts = patch.difffeatureopts(
569 diffopts = patch.difffeatureopts(
570 ui, opts, section=b'annotate', whitespace=True
570 ui, opts, section=b'annotate', whitespace=True
571 )
571 )
572 skiprevs = opts.get(b'skip')
572 skiprevs = opts.get(b'skip')
573 if skiprevs:
573 if skiprevs:
574 skiprevs = logcmdutil.revrange(repo, skiprevs)
574 skiprevs = logcmdutil.revrange(repo, skiprevs)
575
575
576 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
576 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
577 for abs in ctx.walk(m):
577 for abs in ctx.walk(m):
578 fctx = ctx[abs]
578 fctx = ctx[abs]
579 rootfm.startitem()
579 rootfm.startitem()
580 rootfm.data(path=abs)
580 rootfm.data(path=abs)
581 if not opts.get(b'text') and fctx.isbinary():
581 if not opts.get(b'text') and fctx.isbinary():
582 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
582 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
583 continue
583 continue
584
584
585 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
585 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
586 lines = fctx.annotate(
586 lines = fctx.annotate(
587 follow=follow, skiprevs=skiprevs, diffopts=diffopts
587 follow=follow, skiprevs=skiprevs, diffopts=diffopts
588 )
588 )
589 if linerange:
589 if linerange:
590 _fname, (line_start, line_end) = list(
590 _fname, (line_start, line_end) = list(
591 logcmdutil._parselinerangeopt(repo, opts)
591 logcmdutil._parselinerangeopt(repo, opts)
592 )[0]
592 )[0]
593 lines = [
593 lines = [
594 line
594 line
595 for no, line in enumerate(lines)
595 for no, line in enumerate(lines)
596 if line_start <= no < line_end
596 if line_start <= no < line_end
597 ]
597 ]
598
598
599 if not lines:
599 if not lines:
600 fm.end()
600 fm.end()
601 continue
601 continue
602 formats = []
602 formats = []
603 pieces = []
603 pieces = []
604
604
605 for f, sep in funcmap:
605 for f, sep in funcmap:
606 l = [f(n) for n in lines]
606 l = [f(n) for n in lines]
607 if fm.isplain():
607 if fm.isplain():
608 sizes = [encoding.colwidth(x) for x in l]
608 sizes = [encoding.colwidth(x) for x in l]
609 ml = max(sizes)
609 ml = max(sizes)
610 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
610 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
611 else:
611 else:
612 formats.append([b'%s'] * len(l))
612 formats.append([b'%s'] * len(l))
613 pieces.append(l)
613 pieces.append(l)
614
614
615 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
615 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
616 fm.startitem()
616 fm.startitem()
617 fm.context(fctx=n.fctx)
617 fm.context(fctx=n.fctx)
618 fm.write(fields, b"".join(f), *p)
618 fm.write(fields, b"".join(f), *p)
619 if n.skip:
619 if n.skip:
620 fmt = b"* %s"
620 fmt = b"* %s"
621 else:
621 else:
622 fmt = b": %s"
622 fmt = b": %s"
623 fm.write(b'line', fmt, n.text)
623 fm.write(b'line', fmt, n.text)
624
624
625 if not lines[-1].text.endswith(b'\n'):
625 if not lines[-1].text.endswith(b'\n'):
626 fm.plain(b'\n')
626 fm.plain(b'\n')
627 fm.end()
627 fm.end()
628
628
629 rootfm.end()
629 rootfm.end()
630
630
631
631
632 @command(
632 @command(
633 b'archive',
633 b'archive',
634 [
634 [
635 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
635 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
636 (
636 (
637 b'p',
637 b'p',
638 b'prefix',
638 b'prefix',
639 b'',
639 b'',
640 _(b'directory prefix for files in archive'),
640 _(b'directory prefix for files in archive'),
641 _(b'PREFIX'),
641 _(b'PREFIX'),
642 ),
642 ),
643 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
643 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
644 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
644 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
645 ]
645 ]
646 + subrepoopts
646 + subrepoopts
647 + walkopts,
647 + walkopts,
648 _(b'[OPTION]... DEST'),
648 _(b'[OPTION]... DEST'),
649 helpcategory=command.CATEGORY_IMPORT_EXPORT,
649 helpcategory=command.CATEGORY_IMPORT_EXPORT,
650 )
650 )
651 def archive(ui, repo, dest, **opts):
651 def archive(ui, repo, dest, **opts):
652 """create an unversioned archive of a repository revision
652 """create an unversioned archive of a repository revision
653
653
654 By default, the revision used is the parent of the working
654 By default, the revision used is the parent of the working
655 directory; use -r/--rev to specify a different revision.
655 directory; use -r/--rev to specify a different revision.
656
656
657 The archive type is automatically detected based on file
657 The archive type is automatically detected based on file
658 extension (to override, use -t/--type).
658 extension (to override, use -t/--type).
659
659
660 .. container:: verbose
660 .. container:: verbose
661
661
662 Examples:
662 Examples:
663
663
664 - create a zip file containing the 1.0 release::
664 - create a zip file containing the 1.0 release::
665
665
666 hg archive -r 1.0 project-1.0.zip
666 hg archive -r 1.0 project-1.0.zip
667
667
668 - create a tarball excluding .hg files::
668 - create a tarball excluding .hg files::
669
669
670 hg archive project.tar.gz -X ".hg*"
670 hg archive project.tar.gz -X ".hg*"
671
671
672 Valid types are:
672 Valid types are:
673
673
674 :``files``: a directory full of files (default)
674 :``files``: a directory full of files (default)
675 :``tar``: tar archive, uncompressed
675 :``tar``: tar archive, uncompressed
676 :``tbz2``: tar archive, compressed using bzip2
676 :``tbz2``: tar archive, compressed using bzip2
677 :``tgz``: tar archive, compressed using gzip
677 :``tgz``: tar archive, compressed using gzip
678 :``txz``: tar archive, compressed using lzma (only in Python 3)
678 :``txz``: tar archive, compressed using lzma (only in Python 3)
679 :``uzip``: zip archive, uncompressed
679 :``uzip``: zip archive, uncompressed
680 :``zip``: zip archive, compressed using deflate
680 :``zip``: zip archive, compressed using deflate
681
681
682 The exact name of the destination archive or directory is given
682 The exact name of the destination archive or directory is given
683 using a format string; see :hg:`help export` for details.
683 using a format string; see :hg:`help export` for details.
684
684
685 Each member added to an archive file has a directory prefix
685 Each member added to an archive file has a directory prefix
686 prepended. Use -p/--prefix to specify a format string for the
686 prepended. Use -p/--prefix to specify a format string for the
687 prefix. The default is the basename of the archive, with suffixes
687 prefix. The default is the basename of the archive, with suffixes
688 removed.
688 removed.
689
689
690 Returns 0 on success.
690 Returns 0 on success.
691 """
691 """
692
692
693 rev = opts.get('rev')
693 rev = opts.get('rev')
694 if rev:
694 if rev:
695 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
695 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
696 ctx = logcmdutil.revsingle(repo, rev)
696 ctx = logcmdutil.revsingle(repo, rev)
697 if not ctx:
697 if not ctx:
698 raise error.InputError(
698 raise error.InputError(
699 _(b'no working directory: please specify a revision')
699 _(b'no working directory: please specify a revision')
700 )
700 )
701 node = ctx.node()
701 node = ctx.node()
702 dest = cmdutil.makefilename(ctx, dest)
702 dest = cmdutil.makefilename(ctx, dest)
703 if os.path.realpath(dest) == repo.root:
703 if os.path.realpath(dest) == repo.root:
704 raise error.InputError(_(b'repository root cannot be destination'))
704 raise error.InputError(_(b'repository root cannot be destination'))
705
705
706 kind = opts.get('type') or archival.guesskind(dest) or b'files'
706 kind = opts.get('type') or archival.guesskind(dest) or b'files'
707 prefix = opts.get('prefix')
707 prefix = opts.get('prefix')
708
708
709 if dest == b'-':
709 if dest == b'-':
710 if kind == b'files':
710 if kind == b'files':
711 raise error.InputError(_(b'cannot archive plain files to stdout'))
711 raise error.InputError(_(b'cannot archive plain files to stdout'))
712 dest = cmdutil.makefileobj(ctx, dest)
712 dest = cmdutil.makefileobj(ctx, dest)
713 if not prefix:
713 if not prefix:
714 prefix = os.path.basename(repo.root) + b'-%h'
714 prefix = os.path.basename(repo.root) + b'-%h'
715
715
716 prefix = cmdutil.makefilename(ctx, prefix)
716 prefix = cmdutil.makefilename(ctx, prefix)
717 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
717 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
718 archival.archive(
718 archival.archive(
719 repo,
719 repo,
720 dest,
720 dest,
721 node,
721 node,
722 kind,
722 kind,
723 not opts.get('no_decode'),
723 not opts.get('no_decode'),
724 match,
724 match,
725 prefix,
725 prefix,
726 subrepos=opts.get('subrepos'),
726 subrepos=opts.get('subrepos'),
727 )
727 )
728
728
729
729
730 @command(
730 @command(
731 b'backout',
731 b'backout',
732 [
732 [
733 (
733 (
734 b'',
734 b'',
735 b'merge',
735 b'merge',
736 None,
736 None,
737 _(b'merge with old dirstate parent after backout'),
737 _(b'merge with old dirstate parent after backout'),
738 ),
738 ),
739 (
739 (
740 b'',
740 b'',
741 b'commit',
741 b'commit',
742 None,
742 None,
743 _(b'commit if no conflicts were encountered (DEPRECATED)'),
743 _(b'commit if no conflicts were encountered (DEPRECATED)'),
744 ),
744 ),
745 (b'', b'no-commit', None, _(b'do not commit')),
745 (b'', b'no-commit', None, _(b'do not commit')),
746 (
746 (
747 b'',
747 b'',
748 b'parent',
748 b'parent',
749 b'',
749 b'',
750 _(b'parent to choose when backing out merge (DEPRECATED)'),
750 _(b'parent to choose when backing out merge (DEPRECATED)'),
751 _(b'REV'),
751 _(b'REV'),
752 ),
752 ),
753 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
753 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
754 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
754 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
755 ]
755 ]
756 + mergetoolopts
756 + mergetoolopts
757 + walkopts
757 + walkopts
758 + commitopts
758 + commitopts
759 + commitopts2,
759 + commitopts2,
760 _(b'[OPTION]... [-r] REV'),
760 _(b'[OPTION]... [-r] REV'),
761 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
761 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
762 )
762 )
763 def backout(ui, repo, node=None, rev=None, **opts):
763 def backout(ui, repo, node=None, rev=None, **opts):
764 """reverse effect of earlier changeset
764 """reverse effect of earlier changeset
765
765
766 Prepare a new changeset with the effect of REV undone in the
766 Prepare a new changeset with the effect of REV undone in the
767 current working directory. If no conflicts were encountered,
767 current working directory. If no conflicts were encountered,
768 it will be committed immediately.
768 it will be committed immediately.
769
769
770 If REV is the parent of the working directory, then this new changeset
770 If REV is the parent of the working directory, then this new changeset
771 is committed automatically (unless --no-commit is specified).
771 is committed automatically (unless --no-commit is specified).
772
772
773 .. note::
773 .. note::
774
774
775 :hg:`backout` cannot be used to fix either an unwanted or
775 :hg:`backout` cannot be used to fix either an unwanted or
776 incorrect merge.
776 incorrect merge.
777
777
778 .. container:: verbose
778 .. container:: verbose
779
779
780 Examples:
780 Examples:
781
781
782 - Reverse the effect of the parent of the working directory.
782 - Reverse the effect of the parent of the working directory.
783 This backout will be committed immediately::
783 This backout will be committed immediately::
784
784
785 hg backout -r .
785 hg backout -r .
786
786
787 - Reverse the effect of previous bad revision 23::
787 - Reverse the effect of previous bad revision 23::
788
788
789 hg backout -r 23
789 hg backout -r 23
790
790
791 - Reverse the effect of previous bad revision 23 and
791 - Reverse the effect of previous bad revision 23 and
792 leave changes uncommitted::
792 leave changes uncommitted::
793
793
794 hg backout -r 23 --no-commit
794 hg backout -r 23 --no-commit
795 hg commit -m "Backout revision 23"
795 hg commit -m "Backout revision 23"
796
796
797 By default, the pending changeset will have one parent,
797 By default, the pending changeset will have one parent,
798 maintaining a linear history. With --merge, the pending
798 maintaining a linear history. With --merge, the pending
799 changeset will instead have two parents: the old parent of the
799 changeset will instead have two parents: the old parent of the
800 working directory and a new child of REV that simply undoes REV.
800 working directory and a new child of REV that simply undoes REV.
801
801
802 Before version 1.7, the behavior without --merge was equivalent
802 Before version 1.7, the behavior without --merge was equivalent
803 to specifying --merge followed by :hg:`update --clean .` to
803 to specifying --merge followed by :hg:`update --clean .` to
804 cancel the merge and leave the child of REV as a head to be
804 cancel the merge and leave the child of REV as a head to be
805 merged separately.
805 merged separately.
806
806
807 See :hg:`help dates` for a list of formats valid for -d/--date.
807 See :hg:`help dates` for a list of formats valid for -d/--date.
808
808
809 See :hg:`help revert` for a way to restore files to the state
809 See :hg:`help revert` for a way to restore files to the state
810 of another revision.
810 of another revision.
811
811
812 Returns 0 on success, 1 if nothing to backout or there are unresolved
812 Returns 0 on success, 1 if nothing to backout or there are unresolved
813 files.
813 files.
814 """
814 """
815 with repo.wlock(), repo.lock():
815 with repo.wlock(), repo.lock():
816 return _dobackout(ui, repo, node, rev, **opts)
816 return _dobackout(ui, repo, node, rev, **opts)
817
817
818
818
819 def _dobackout(ui, repo, node=None, rev=None, **opts):
819 def _dobackout(ui, repo, node=None, rev=None, **opts):
820 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
820 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
821
821
822 if rev and node:
822 if rev and node:
823 raise error.InputError(_(b"please specify just one revision"))
823 raise error.InputError(_(b"please specify just one revision"))
824
824
825 if not rev:
825 if not rev:
826 rev = node
826 rev = node
827
827
828 if not rev:
828 if not rev:
829 raise error.InputError(_(b"please specify a revision to backout"))
829 raise error.InputError(_(b"please specify a revision to backout"))
830
830
831 date = opts.get('date')
831 date = opts.get('date')
832 if date:
832 if date:
833 opts['date'] = dateutil.parsedate(date)
833 opts['date'] = dateutil.parsedate(date)
834
834
835 cmdutil.checkunfinished(repo)
835 cmdutil.checkunfinished(repo)
836 cmdutil.bailifchanged(repo)
836 cmdutil.bailifchanged(repo)
837 ctx = logcmdutil.revsingle(repo, rev)
837 ctx = logcmdutil.revsingle(repo, rev)
838 node = ctx.node()
838 node = ctx.node()
839
839
840 op1, op2 = repo.dirstate.parents()
840 op1, op2 = repo.dirstate.parents()
841 if not repo.changelog.isancestor(node, op1):
841 if not repo.changelog.isancestor(node, op1):
842 raise error.InputError(
842 raise error.InputError(
843 _(b'cannot backout change that is not an ancestor')
843 _(b'cannot backout change that is not an ancestor')
844 )
844 )
845
845
846 p1, p2 = repo.changelog.parents(node)
846 p1, p2 = repo.changelog.parents(node)
847 if p1 == repo.nullid:
847 if p1 == repo.nullid:
848 raise error.InputError(_(b'cannot backout a change with no parents'))
848 raise error.InputError(_(b'cannot backout a change with no parents'))
849 if p2 != repo.nullid:
849 if p2 != repo.nullid:
850 if not opts.get('parent'):
850 if not opts.get('parent'):
851 raise error.InputError(_(b'cannot backout a merge changeset'))
851 raise error.InputError(_(b'cannot backout a merge changeset'))
852 p = repo.lookup(opts['parent'])
852 p = repo.lookup(opts['parent'])
853 if p not in (p1, p2):
853 if p not in (p1, p2):
854 raise error.InputError(
854 raise error.InputError(
855 _(b'%s is not a parent of %s') % (short(p), short(node))
855 _(b'%s is not a parent of %s') % (short(p), short(node))
856 )
856 )
857 parent = p
857 parent = p
858 else:
858 else:
859 if opts.get('parent'):
859 if opts.get('parent'):
860 raise error.InputError(
860 raise error.InputError(
861 _(b'cannot use --parent on non-merge changeset')
861 _(b'cannot use --parent on non-merge changeset')
862 )
862 )
863 parent = p1
863 parent = p1
864
864
865 # the backout should appear on the same branch
865 # the backout should appear on the same branch
866 branch = repo.dirstate.branch()
866 branch = repo.dirstate.branch()
867 bheads = repo.branchheads(branch)
867 bheads = repo.branchheads(branch)
868 rctx = scmutil.revsingle(repo, hex(parent))
868 rctx = scmutil.revsingle(repo, hex(parent))
869 if not opts.get('merge') and op1 != node:
869 if not opts.get('merge') and op1 != node:
870 with repo.transaction(b"backout"):
870 with repo.transaction(b"backout"):
871 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
871 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
872 with ui.configoverride(overrides, b'backout'):
872 with ui.configoverride(overrides, b'backout'):
873 stats = mergemod.back_out(ctx, parent=repo[parent])
873 stats = mergemod.back_out(ctx, parent=repo[parent])
874 repo.setparents(op1, op2)
874 repo.setparents(op1, op2)
875 hg._showstats(repo, stats)
875 hg._showstats(repo, stats)
876 if stats.unresolvedcount:
876 if stats.unresolvedcount:
877 repo.ui.status(
877 repo.ui.status(
878 _(b"use 'hg resolve' to retry unresolved file merges\n")
878 _(b"use 'hg resolve' to retry unresolved file merges\n")
879 )
879 )
880 return 1
880 return 1
881 else:
881 else:
882 hg.clean(repo, node, show_stats=False)
882 hg.clean(repo, node, show_stats=False)
883 repo.dirstate.setbranch(branch, repo.currenttransaction())
883 repo.dirstate.setbranch(branch, repo.currenttransaction())
884 cmdutil.revert(ui, repo, rctx)
884 cmdutil.revert(ui, repo, rctx)
885
885
886 if opts.get('no_commit'):
886 if opts.get('no_commit'):
887 msg = _(b"changeset %s backed out, don't forget to commit.\n")
887 msg = _(b"changeset %s backed out, don't forget to commit.\n")
888 ui.status(msg % short(node))
888 ui.status(msg % short(node))
889 return 0
889 return 0
890
890
891 def commitfunc(ui, repo, message, match, opts):
891 def commitfunc(ui, repo, message, match, opts):
892 editform = b'backout'
892 editform = b'backout'
893 e = cmdutil.getcommiteditor(
893 e = cmdutil.getcommiteditor(
894 editform=editform, **pycompat.strkwargs(opts)
894 editform=editform, **pycompat.strkwargs(opts)
895 )
895 )
896 if not message:
896 if not message:
897 # we don't translate commit messages
897 # we don't translate commit messages
898 message = b"Backed out changeset %s" % short(node)
898 message = b"Backed out changeset %s" % short(node)
899 e = cmdutil.getcommiteditor(edit=True, editform=editform)
899 e = cmdutil.getcommiteditor(edit=True, editform=editform)
900 return repo.commit(
900 return repo.commit(
901 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
901 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
902 )
902 )
903
903
904 # save to detect changes
904 # save to detect changes
905 tip = repo.changelog.tip()
905 tip = repo.changelog.tip()
906
906
907 newnode = cmdutil.commit(
907 newnode = cmdutil.commit(
908 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
908 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
909 )
909 )
910 if not newnode:
910 if not newnode:
911 ui.status(_(b"nothing changed\n"))
911 ui.status(_(b"nothing changed\n"))
912 return 1
912 return 1
913 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
913 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
914
914
915 def nice(node):
915 def nice(node):
916 return b'%d:%s' % (repo.changelog.rev(node), short(node))
916 return b'%d:%s' % (repo.changelog.rev(node), short(node))
917
917
918 ui.status(
918 ui.status(
919 _(b'changeset %s backs out changeset %s\n')
919 _(b'changeset %s backs out changeset %s\n')
920 % (nice(newnode), nice(node))
920 % (nice(newnode), nice(node))
921 )
921 )
922 if opts.get('merge') and op1 != node:
922 if opts.get('merge') and op1 != node:
923 hg.clean(repo, op1, show_stats=False)
923 hg.clean(repo, op1, show_stats=False)
924 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
924 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
925 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
925 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
926 with ui.configoverride(overrides, b'backout'):
926 with ui.configoverride(overrides, b'backout'):
927 return hg.merge(repo[b'tip'])
927 return hg.merge(repo[b'tip'])
928 return 0
928 return 0
929
929
930
930
931 @command(
931 @command(
932 b'bisect',
932 b'bisect',
933 [
933 [
934 (b'r', b'reset', False, _(b'reset bisect state')),
934 (b'r', b'reset', False, _(b'reset bisect state')),
935 (b'g', b'good', False, _(b'mark changeset good')),
935 (b'g', b'good', False, _(b'mark changeset good')),
936 (b'b', b'bad', False, _(b'mark changeset bad')),
936 (b'b', b'bad', False, _(b'mark changeset bad')),
937 (b's', b'skip', False, _(b'skip testing changeset')),
937 (b's', b'skip', False, _(b'skip testing changeset')),
938 (b'e', b'extend', False, _(b'extend the bisect range')),
938 (b'e', b'extend', False, _(b'extend the bisect range')),
939 (
939 (
940 b'c',
940 b'c',
941 b'command',
941 b'command',
942 b'',
942 b'',
943 _(b'use command to check changeset state'),
943 _(b'use command to check changeset state'),
944 _(b'CMD'),
944 _(b'CMD'),
945 ),
945 ),
946 (b'U', b'noupdate', False, _(b'do not update to target')),
946 (b'U', b'noupdate', False, _(b'do not update to target')),
947 ],
947 ],
948 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
948 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
949 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
949 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
950 )
950 )
951 def bisect(
951 def bisect(
952 ui,
952 ui,
953 repo,
953 repo,
954 positional_1=None,
954 positional_1=None,
955 positional_2=None,
955 positional_2=None,
956 command=None,
956 command=None,
957 reset=None,
957 reset=None,
958 good=None,
958 good=None,
959 bad=None,
959 bad=None,
960 skip=None,
960 skip=None,
961 extend=None,
961 extend=None,
962 noupdate=None,
962 noupdate=None,
963 ):
963 ):
964 """subdivision search of changesets
964 """subdivision search of changesets
965
965
966 This command helps to find changesets which introduce problems. To
966 This command helps to find changesets which introduce problems. To
967 use, mark the earliest changeset you know exhibits the problem as
967 use, mark the earliest changeset you know exhibits the problem as
968 bad, then mark the latest changeset which is free from the problem
968 bad, then mark the latest changeset which is free from the problem
969 as good. Bisect will update your working directory to a revision
969 as good. Bisect will update your working directory to a revision
970 for testing (unless the -U/--noupdate option is specified). Once
970 for testing (unless the -U/--noupdate option is specified). Once
971 you have performed tests, mark the working directory as good or
971 you have performed tests, mark the working directory as good or
972 bad, and bisect will either update to another candidate changeset
972 bad, and bisect will either update to another candidate changeset
973 or announce that it has found the bad revision.
973 or announce that it has found the bad revision.
974
974
975 As a shortcut, you can also use the revision argument to mark a
975 As a shortcut, you can also use the revision argument to mark a
976 revision as good or bad without checking it out first.
976 revision as good or bad without checking it out first.
977
977
978 If you supply a command, it will be used for automatic bisection.
978 If you supply a command, it will be used for automatic bisection.
979 The environment variable HG_NODE will contain the ID of the
979 The environment variable HG_NODE will contain the ID of the
980 changeset being tested. The exit status of the command will be
980 changeset being tested. The exit status of the command will be
981 used to mark revisions as good or bad: status 0 means good, 125
981 used to mark revisions as good or bad: status 0 means good, 125
982 means to skip the revision, 127 (command not found) will abort the
982 means to skip the revision, 127 (command not found) will abort the
983 bisection, and any other non-zero exit status means the revision
983 bisection, and any other non-zero exit status means the revision
984 is bad.
984 is bad.
985
985
986 .. container:: verbose
986 .. container:: verbose
987
987
988 Some examples:
988 Some examples:
989
989
990 - start a bisection with known bad revision 34, and good revision 12::
990 - start a bisection with known bad revision 34, and good revision 12::
991
991
992 hg bisect --bad 34
992 hg bisect --bad 34
993 hg bisect --good 12
993 hg bisect --good 12
994
994
995 - advance the current bisection by marking current revision as good or
995 - advance the current bisection by marking current revision as good or
996 bad::
996 bad::
997
997
998 hg bisect --good
998 hg bisect --good
999 hg bisect --bad
999 hg bisect --bad
1000
1000
1001 - mark the current revision, or a known revision, to be skipped (e.g. if
1001 - mark the current revision, or a known revision, to be skipped (e.g. if
1002 that revision is not usable because of another issue)::
1002 that revision is not usable because of another issue)::
1003
1003
1004 hg bisect --skip
1004 hg bisect --skip
1005 hg bisect --skip 23
1005 hg bisect --skip 23
1006
1006
1007 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1007 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1008
1008
1009 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1009 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1010
1010
1011 - forget the current bisection::
1011 - forget the current bisection::
1012
1012
1013 hg bisect --reset
1013 hg bisect --reset
1014
1014
1015 - use 'make && make tests' to automatically find the first broken
1015 - use 'make && make tests' to automatically find the first broken
1016 revision::
1016 revision::
1017
1017
1018 hg bisect --reset
1018 hg bisect --reset
1019 hg bisect --bad 34
1019 hg bisect --bad 34
1020 hg bisect --good 12
1020 hg bisect --good 12
1021 hg bisect --command "make && make tests"
1021 hg bisect --command "make && make tests"
1022
1022
1023 - see all changesets whose states are already known in the current
1023 - see all changesets whose states are already known in the current
1024 bisection::
1024 bisection::
1025
1025
1026 hg log -r "bisect(pruned)"
1026 hg log -r "bisect(pruned)"
1027
1027
1028 - see the changeset currently being bisected (especially useful
1028 - see the changeset currently being bisected (especially useful
1029 if running with -U/--noupdate)::
1029 if running with -U/--noupdate)::
1030
1030
1031 hg log -r "bisect(current)"
1031 hg log -r "bisect(current)"
1032
1032
1033 - see all changesets that took part in the current bisection::
1033 - see all changesets that took part in the current bisection::
1034
1034
1035 hg log -r "bisect(range)"
1035 hg log -r "bisect(range)"
1036
1036
1037 - you can even get a nice graph::
1037 - you can even get a nice graph::
1038
1038
1039 hg log --graph -r "bisect(range)"
1039 hg log --graph -r "bisect(range)"
1040
1040
1041 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1041 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1042
1042
1043 Returns 0 on success.
1043 Returns 0 on success.
1044 """
1044 """
1045 rev = []
1045 rev = []
1046 # backward compatibility
1046 # backward compatibility
1047 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1047 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1048 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1048 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1049 cmd = positional_1
1049 cmd = positional_1
1050 rev.append(positional_2)
1050 rev.append(positional_2)
1051 if cmd == b"good":
1051 if cmd == b"good":
1052 good = True
1052 good = True
1053 elif cmd == b"bad":
1053 elif cmd == b"bad":
1054 bad = True
1054 bad = True
1055 else:
1055 else:
1056 reset = True
1056 reset = True
1057 elif positional_2:
1057 elif positional_2:
1058 raise error.InputError(_(b'incompatible arguments'))
1058 raise error.InputError(_(b'incompatible arguments'))
1059 elif positional_1 is not None:
1059 elif positional_1 is not None:
1060 rev.append(positional_1)
1060 rev.append(positional_1)
1061
1061
1062 incompatibles = {
1062 incompatibles = {
1063 b'--bad': bad,
1063 b'--bad': bad,
1064 b'--command': bool(command),
1064 b'--command': bool(command),
1065 b'--extend': extend,
1065 b'--extend': extend,
1066 b'--good': good,
1066 b'--good': good,
1067 b'--reset': reset,
1067 b'--reset': reset,
1068 b'--skip': skip,
1068 b'--skip': skip,
1069 }
1069 }
1070
1070
1071 enabled = [x for x in incompatibles if incompatibles[x]]
1071 enabled = [x for x in incompatibles if incompatibles[x]]
1072
1072
1073 if len(enabled) > 1:
1073 if len(enabled) > 1:
1074 raise error.InputError(
1074 raise error.InputError(
1075 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1075 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1076 )
1076 )
1077
1077
1078 if reset:
1078 if reset:
1079 hbisect.resetstate(repo)
1079 hbisect.resetstate(repo)
1080 return
1080 return
1081
1081
1082 state = hbisect.load_state(repo)
1082 state = hbisect.load_state(repo)
1083
1083
1084 if rev:
1084 if rev:
1085 revs = logcmdutil.revrange(repo, rev)
1085 revs = logcmdutil.revrange(repo, rev)
1086 goodnodes = state[b'good']
1086 goodnodes = state[b'good']
1087 badnodes = state[b'bad']
1087 badnodes = state[b'bad']
1088 if goodnodes and badnodes:
1088 if goodnodes and badnodes:
1089 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1089 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1090 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1090 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1091 revs = candidates & revs
1091 revs = candidates & revs
1092 nodes = [repo.changelog.node(i) for i in revs]
1092 nodes = [repo.changelog.node(i) for i in revs]
1093 else:
1093 else:
1094 nodes = [repo.lookup(b'.')]
1094 nodes = [repo.lookup(b'.')]
1095
1095
1096 # update state
1096 # update state
1097 if good or bad or skip:
1097 if good or bad or skip:
1098 if good:
1098 if good:
1099 state[b'good'] += nodes
1099 state[b'good'] += nodes
1100 elif bad:
1100 elif bad:
1101 state[b'bad'] += nodes
1101 state[b'bad'] += nodes
1102 elif skip:
1102 elif skip:
1103 state[b'skip'] += nodes
1103 state[b'skip'] += nodes
1104 hbisect.save_state(repo, state)
1104 hbisect.save_state(repo, state)
1105 if not (state[b'good'] and state[b'bad']):
1105 if not (state[b'good'] and state[b'bad']):
1106 return
1106 return
1107
1107
1108 def mayupdate(repo, node, show_stats=True):
1108 def mayupdate(repo, node, show_stats=True):
1109 """common used update sequence"""
1109 """common used update sequence"""
1110 if noupdate:
1110 if noupdate:
1111 return
1111 return
1112 cmdutil.checkunfinished(repo)
1112 cmdutil.checkunfinished(repo)
1113 cmdutil.bailifchanged(repo)
1113 cmdutil.bailifchanged(repo)
1114 return hg.clean(repo, node, show_stats=show_stats)
1114 return hg.clean(repo, node, show_stats=show_stats)
1115
1115
1116 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1116 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1117
1117
1118 if command:
1118 if command:
1119 changesets = 1
1119 changesets = 1
1120 if noupdate:
1120 if noupdate:
1121 try:
1121 try:
1122 node = state[b'current'][0]
1122 node = state[b'current'][0]
1123 except LookupError:
1123 except LookupError:
1124 raise error.StateError(
1124 raise error.StateError(
1125 _(
1125 _(
1126 b'current bisect revision is unknown - '
1126 b'current bisect revision is unknown - '
1127 b'start a new bisect to fix'
1127 b'start a new bisect to fix'
1128 )
1128 )
1129 )
1129 )
1130 else:
1130 else:
1131 node, p2 = repo.dirstate.parents()
1131 node, p2 = repo.dirstate.parents()
1132 if p2 != repo.nullid:
1132 if p2 != repo.nullid:
1133 raise error.StateError(_(b'current bisect revision is a merge'))
1133 raise error.StateError(_(b'current bisect revision is a merge'))
1134 if rev:
1134 if rev:
1135 if not nodes:
1135 if not nodes:
1136 raise error.InputError(_(b'empty revision set'))
1136 raise error.InputError(_(b'empty revision set'))
1137 node = repo[nodes[-1]].node()
1137 node = repo[nodes[-1]].node()
1138 with hbisect.restore_state(repo, state, node):
1138 with hbisect.restore_state(repo, state, node):
1139 while changesets:
1139 while changesets:
1140 # update state
1140 # update state
1141 state[b'current'] = [node]
1141 state[b'current'] = [node]
1142 hbisect.save_state(repo, state)
1142 hbisect.save_state(repo, state)
1143 status = ui.system(
1143 status = ui.system(
1144 command,
1144 command,
1145 environ={b'HG_NODE': hex(node)},
1145 environ={b'HG_NODE': hex(node)},
1146 blockedtag=b'bisect_check',
1146 blockedtag=b'bisect_check',
1147 )
1147 )
1148 if status == 125:
1148 if status == 125:
1149 transition = b"skip"
1149 transition = b"skip"
1150 elif status == 0:
1150 elif status == 0:
1151 transition = b"good"
1151 transition = b"good"
1152 # status < 0 means process was killed
1152 # status < 0 means process was killed
1153 elif status == 127:
1153 elif status == 127:
1154 raise error.Abort(_(b"failed to execute %s") % command)
1154 raise error.Abort(_(b"failed to execute %s") % command)
1155 elif status < 0:
1155 elif status < 0:
1156 raise error.Abort(_(b"%s killed") % command)
1156 raise error.Abort(_(b"%s killed") % command)
1157 else:
1157 else:
1158 transition = b"bad"
1158 transition = b"bad"
1159 state[transition].append(node)
1159 state[transition].append(node)
1160 ctx = repo[node]
1160 ctx = repo[node]
1161 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1161 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1162 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1162 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1163 hbisect.checkstate(state)
1163 hbisect.checkstate(state)
1164 # bisect
1164 # bisect
1165 nodes, changesets, bgood = hbisect.bisect(repo, state)
1165 nodes, changesets, bgood = hbisect.bisect(repo, state)
1166 # update to next check
1166 # update to next check
1167 node = nodes[0]
1167 node = nodes[0]
1168 mayupdate(repo, node, show_stats=False)
1168 mayupdate(repo, node, show_stats=False)
1169 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1169 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1170 return
1170 return
1171
1171
1172 hbisect.checkstate(state)
1172 hbisect.checkstate(state)
1173
1173
1174 # actually bisect
1174 # actually bisect
1175 nodes, changesets, good = hbisect.bisect(repo, state)
1175 nodes, changesets, good = hbisect.bisect(repo, state)
1176 if extend:
1176 if extend:
1177 if not changesets:
1177 if not changesets:
1178 extendctx = hbisect.extendrange(repo, state, nodes, good)
1178 extendctx = hbisect.extendrange(repo, state, nodes, good)
1179 if extendctx is not None:
1179 if extendctx is not None:
1180 ui.write(
1180 ui.write(
1181 _(b"Extending search to changeset %s\n")
1181 _(b"Extending search to changeset %s\n")
1182 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1182 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1183 )
1183 )
1184 state[b'current'] = [extendctx.node()]
1184 state[b'current'] = [extendctx.node()]
1185 hbisect.save_state(repo, state)
1185 hbisect.save_state(repo, state)
1186 return mayupdate(repo, extendctx.node())
1186 return mayupdate(repo, extendctx.node())
1187 raise error.StateError(_(b"nothing to extend"))
1187 raise error.StateError(_(b"nothing to extend"))
1188
1188
1189 if changesets == 0:
1189 if changesets == 0:
1190 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1190 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1191 else:
1191 else:
1192 assert len(nodes) == 1 # only a single node can be tested next
1192 assert len(nodes) == 1 # only a single node can be tested next
1193 node = nodes[0]
1193 node = nodes[0]
1194 # compute the approximate number of remaining tests
1194 # compute the approximate number of remaining tests
1195 tests, size = 0, 2
1195 tests, size = 0, 2
1196 while size <= changesets:
1196 while size <= changesets:
1197 tests, size = tests + 1, size * 2
1197 tests, size = tests + 1, size * 2
1198 rev = repo.changelog.rev(node)
1198 rev = repo.changelog.rev(node)
1199 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1199 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1200 ui.write(
1200 ui.write(
1201 _(
1201 _(
1202 b"Testing changeset %s "
1202 b"Testing changeset %s "
1203 b"(%d changesets remaining, ~%d tests)\n"
1203 b"(%d changesets remaining, ~%d tests)\n"
1204 )
1204 )
1205 % (summary, changesets, tests)
1205 % (summary, changesets, tests)
1206 )
1206 )
1207 state[b'current'] = [node]
1207 state[b'current'] = [node]
1208 hbisect.save_state(repo, state)
1208 hbisect.save_state(repo, state)
1209 return mayupdate(repo, node)
1209 return mayupdate(repo, node)
1210
1210
1211
1211
1212 @command(
1212 @command(
1213 b'bookmarks|bookmark',
1213 b'bookmarks|bookmark',
1214 [
1214 [
1215 (b'f', b'force', False, _(b'force')),
1215 (b'f', b'force', False, _(b'force')),
1216 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1216 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1217 (b'd', b'delete', False, _(b'delete a given bookmark')),
1217 (b'd', b'delete', False, _(b'delete a given bookmark')),
1218 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1218 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1219 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1219 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1220 (b'l', b'list', False, _(b'list existing bookmarks')),
1220 (b'l', b'list', False, _(b'list existing bookmarks')),
1221 ]
1221 ]
1222 + formatteropts,
1222 + formatteropts,
1223 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1223 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1224 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1224 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1225 )
1225 )
1226 def bookmark(ui, repo, *names, **opts):
1226 def bookmark(ui, repo, *names, **opts):
1227 """create a new bookmark or list existing bookmarks
1227 """create a new bookmark or list existing bookmarks
1228
1228
1229 Bookmarks are labels on changesets to help track lines of development.
1229 Bookmarks are labels on changesets to help track lines of development.
1230 Bookmarks are unversioned and can be moved, renamed and deleted.
1230 Bookmarks are unversioned and can be moved, renamed and deleted.
1231 Deleting or moving a bookmark has no effect on the associated changesets.
1231 Deleting or moving a bookmark has no effect on the associated changesets.
1232
1232
1233 Creating or updating to a bookmark causes it to be marked as 'active'.
1233 Creating or updating to a bookmark causes it to be marked as 'active'.
1234 The active bookmark is indicated with a '*'.
1234 The active bookmark is indicated with a '*'.
1235 When a commit is made, the active bookmark will advance to the new commit.
1235 When a commit is made, the active bookmark will advance to the new commit.
1236 A plain :hg:`update` will also advance an active bookmark, if possible.
1236 A plain :hg:`update` will also advance an active bookmark, if possible.
1237 Updating away from a bookmark will cause it to be deactivated.
1237 Updating away from a bookmark will cause it to be deactivated.
1238
1238
1239 Bookmarks can be pushed and pulled between repositories (see
1239 Bookmarks can be pushed and pulled between repositories (see
1240 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1240 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1241 diverged, a new 'divergent bookmark' of the form 'name@path' will
1241 diverged, a new 'divergent bookmark' of the form 'name@path' will
1242 be created. Using :hg:`merge` will resolve the divergence.
1242 be created. Using :hg:`merge` will resolve the divergence.
1243
1243
1244 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1244 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1245 the active bookmark's name.
1245 the active bookmark's name.
1246
1246
1247 A bookmark named '@' has the special property that :hg:`clone` will
1247 A bookmark named '@' has the special property that :hg:`clone` will
1248 check it out by default if it exists.
1248 check it out by default if it exists.
1249
1249
1250 .. container:: verbose
1250 .. container:: verbose
1251
1251
1252 Template:
1252 Template:
1253
1253
1254 The following keywords are supported in addition to the common template
1254 The following keywords are supported in addition to the common template
1255 keywords and functions such as ``{bookmark}``. See also
1255 keywords and functions such as ``{bookmark}``. See also
1256 :hg:`help templates`.
1256 :hg:`help templates`.
1257
1257
1258 :active: Boolean. True if the bookmark is active.
1258 :active: Boolean. True if the bookmark is active.
1259
1259
1260 Examples:
1260 Examples:
1261
1261
1262 - create an active bookmark for a new line of development::
1262 - create an active bookmark for a new line of development::
1263
1263
1264 hg book new-feature
1264 hg book new-feature
1265
1265
1266 - create an inactive bookmark as a place marker::
1266 - create an inactive bookmark as a place marker::
1267
1267
1268 hg book -i reviewed
1268 hg book -i reviewed
1269
1269
1270 - create an inactive bookmark on another changeset::
1270 - create an inactive bookmark on another changeset::
1271
1271
1272 hg book -r .^ tested
1272 hg book -r .^ tested
1273
1273
1274 - rename bookmark turkey to dinner::
1274 - rename bookmark turkey to dinner::
1275
1275
1276 hg book -m turkey dinner
1276 hg book -m turkey dinner
1277
1277
1278 - move the '@' bookmark from another branch::
1278 - move the '@' bookmark from another branch::
1279
1279
1280 hg book -f @
1280 hg book -f @
1281
1281
1282 - print only the active bookmark name::
1282 - print only the active bookmark name::
1283
1283
1284 hg book -ql .
1284 hg book -ql .
1285 """
1285 """
1286 force = opts.get('force')
1286 force = opts.get('force')
1287 rev = opts.get('rev')
1287 rev = opts.get('rev')
1288 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1288 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1289
1289
1290 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1290 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1291 if action:
1291 if action:
1292 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1292 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1293 elif names or rev:
1293 elif names or rev:
1294 action = 'add'
1294 action = 'add'
1295 elif inactive:
1295 elif inactive:
1296 action = 'inactive' # meaning deactivate
1296 action = 'inactive' # meaning deactivate
1297 else:
1297 else:
1298 action = 'list'
1298 action = 'list'
1299
1299
1300 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1300 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1301 if not names and action in {'add', 'delete'}:
1301 if not names and action in {'add', 'delete'}:
1302 raise error.InputError(_(b"bookmark name required"))
1302 raise error.InputError(_(b"bookmark name required"))
1303
1303
1304 if action in {'add', 'delete', 'rename', 'inactive'}:
1304 if action in {'add', 'delete', 'rename', 'inactive'}:
1305 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1305 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1306 if action == 'delete':
1306 if action == 'delete':
1307 names = pycompat.maplist(repo._bookmarks.expandname, names)
1307 names = pycompat.maplist(repo._bookmarks.expandname, names)
1308 bookmarks.delete(repo, tr, names)
1308 bookmarks.delete(repo, tr, names)
1309 elif action == 'rename':
1309 elif action == 'rename':
1310 if not names:
1310 if not names:
1311 raise error.InputError(_(b"new bookmark name required"))
1311 raise error.InputError(_(b"new bookmark name required"))
1312 elif len(names) > 1:
1312 elif len(names) > 1:
1313 raise error.InputError(
1313 raise error.InputError(
1314 _(b"only one new bookmark name allowed")
1314 _(b"only one new bookmark name allowed")
1315 )
1315 )
1316 oldname = repo._bookmarks.expandname(opts['rename'])
1316 oldname = repo._bookmarks.expandname(opts['rename'])
1317 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1317 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1318 elif action == 'add':
1318 elif action == 'add':
1319 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1319 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1320 elif action == 'inactive':
1320 elif action == 'inactive':
1321 if len(repo._bookmarks) == 0:
1321 if len(repo._bookmarks) == 0:
1322 ui.status(_(b"no bookmarks set\n"))
1322 ui.status(_(b"no bookmarks set\n"))
1323 elif not repo._activebookmark:
1323 elif not repo._activebookmark:
1324 ui.status(_(b"no active bookmark\n"))
1324 ui.status(_(b"no active bookmark\n"))
1325 else:
1325 else:
1326 bookmarks.deactivate(repo)
1326 bookmarks.deactivate(repo)
1327 elif action == 'list':
1327 elif action == 'list':
1328 names = pycompat.maplist(repo._bookmarks.expandname, names)
1328 names = pycompat.maplist(repo._bookmarks.expandname, names)
1329 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1329 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1330 bookmarks.printbookmarks(ui, repo, fm, names)
1330 bookmarks.printbookmarks(ui, repo, fm, names)
1331 else:
1331 else:
1332 raise error.ProgrammingError(
1332 raise error.ProgrammingError(
1333 b'invalid action: %s' % pycompat.sysbytes(action)
1333 b'invalid action: %s' % pycompat.sysbytes(action)
1334 )
1334 )
1335
1335
1336
1336
1337 @command(
1337 @command(
1338 b'branch',
1338 b'branch',
1339 [
1339 [
1340 (
1340 (
1341 b'f',
1341 b'f',
1342 b'force',
1342 b'force',
1343 None,
1343 None,
1344 _(b'set branch name even if it shadows an existing branch'),
1344 _(b'set branch name even if it shadows an existing branch'),
1345 ),
1345 ),
1346 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1346 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1347 (
1347 (
1348 b'r',
1348 b'r',
1349 b'rev',
1349 b'rev',
1350 [],
1350 [],
1351 _(b'change branches of the given revs (EXPERIMENTAL)'),
1351 _(b'change branches of the given revs (EXPERIMENTAL)'),
1352 ),
1352 ),
1353 ],
1353 ],
1354 _(b'[-fC] [NAME]'),
1354 _(b'[-fC] [NAME]'),
1355 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1355 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1356 )
1356 )
1357 def branch(ui, repo, label=None, **opts):
1357 def branch(ui, repo, label=None, **opts):
1358 """set or show the current branch name
1358 """set or show the current branch name
1359
1359
1360 .. note::
1360 .. note::
1361
1361
1362 Branch names are permanent and global. Use :hg:`bookmark` to create a
1362 Branch names are permanent and global. Use :hg:`bookmark` to create a
1363 light-weight bookmark instead. See :hg:`help glossary` for more
1363 light-weight bookmark instead. See :hg:`help glossary` for more
1364 information about named branches and bookmarks.
1364 information about named branches and bookmarks.
1365
1365
1366 With no argument, show the current branch name. With one argument,
1366 With no argument, show the current branch name. With one argument,
1367 set the working directory branch name (the branch will not exist
1367 set the working directory branch name (the branch will not exist
1368 in the repository until the next commit). Standard practice
1368 in the repository until the next commit). Standard practice
1369 recommends that primary development take place on the 'default'
1369 recommends that primary development take place on the 'default'
1370 branch.
1370 branch.
1371
1371
1372 Unless -f/--force is specified, branch will not let you set a
1372 Unless -f/--force is specified, branch will not let you set a
1373 branch name that already exists.
1373 branch name that already exists.
1374
1374
1375 Use -C/--clean to reset the working directory branch to that of
1375 Use -C/--clean to reset the working directory branch to that of
1376 the parent of the working directory, negating a previous branch
1376 the parent of the working directory, negating a previous branch
1377 change.
1377 change.
1378
1378
1379 Use the command :hg:`update` to switch to an existing branch. Use
1379 Use the command :hg:`update` to switch to an existing branch. Use
1380 :hg:`commit --close-branch` to mark this branch head as closed.
1380 :hg:`commit --close-branch` to mark this branch head as closed.
1381 When all heads of a branch are closed, the branch will be
1381 When all heads of a branch are closed, the branch will be
1382 considered closed.
1382 considered closed.
1383
1383
1384 Returns 0 on success.
1384 Returns 0 on success.
1385 """
1385 """
1386 revs = opts.get('rev')
1386 revs = opts.get('rev')
1387 if label:
1387 if label:
1388 label = label.strip()
1388 label = label.strip()
1389
1389
1390 if not opts.get('clean') and not label:
1390 if not opts.get('clean') and not label:
1391 if revs:
1391 if revs:
1392 raise error.InputError(
1392 raise error.InputError(
1393 _(b"no branch name specified for the revisions")
1393 _(b"no branch name specified for the revisions")
1394 )
1394 )
1395 ui.write(b"%s\n" % repo.dirstate.branch())
1395 ui.write(b"%s\n" % repo.dirstate.branch())
1396 return
1396 return
1397
1397
1398 with repo.wlock():
1398 with repo.wlock():
1399 if opts.get('clean'):
1399 if opts.get('clean'):
1400 label = repo[b'.'].branch()
1400 label = repo[b'.'].branch()
1401 repo.dirstate.setbranch(label, repo.currenttransaction())
1401 repo.dirstate.setbranch(label, repo.currenttransaction())
1402 ui.status(_(b'reset working directory to branch %s\n') % label)
1402 ui.status(_(b'reset working directory to branch %s\n') % label)
1403 elif label:
1403 elif label:
1404 scmutil.checknewlabel(repo, label, b'branch')
1404 scmutil.checknewlabel(repo, label, b'branch')
1405 if revs:
1405 if revs:
1406 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1406 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1407
1407
1408 if not opts.get('force') and label in repo.branchmap():
1408 if not opts.get('force') and label in repo.branchmap():
1409 if label not in [p.branch() for p in repo[None].parents()]:
1409 if label not in [p.branch() for p in repo[None].parents()]:
1410 raise error.InputError(
1410 raise error.InputError(
1411 _(b'a branch of the same name already exists'),
1411 _(b'a branch of the same name already exists'),
1412 # i18n: "it" refers to an existing branch
1412 # i18n: "it" refers to an existing branch
1413 hint=_(b"use 'hg update' to switch to it"),
1413 hint=_(b"use 'hg update' to switch to it"),
1414 )
1414 )
1415
1415
1416 repo.dirstate.setbranch(label, repo.currenttransaction())
1416 repo.dirstate.setbranch(label, repo.currenttransaction())
1417 ui.status(_(b'marked working directory as branch %s\n') % label)
1417 ui.status(_(b'marked working directory as branch %s\n') % label)
1418
1418
1419 # find any open named branches aside from default
1419 # find any open named branches aside from default
1420 for n, h, t, c in repo.branchmap().iterbranches():
1420 for n, h, t, c in repo.branchmap().iterbranches():
1421 if n != b"default" and not c:
1421 if n != b"default" and not c:
1422 return 0
1422 return 0
1423 ui.status(
1423 ui.status(
1424 _(
1424 _(
1425 b'(branches are permanent and global, '
1425 b'(branches are permanent and global, '
1426 b'did you want a bookmark?)\n'
1426 b'did you want a bookmark?)\n'
1427 )
1427 )
1428 )
1428 )
1429
1429
1430
1430
1431 @command(
1431 @command(
1432 b'branches',
1432 b'branches',
1433 [
1433 [
1434 (
1434 (
1435 b'a',
1435 b'a',
1436 b'active',
1436 b'active',
1437 False,
1437 False,
1438 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1438 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1439 ),
1439 ),
1440 (b'c', b'closed', False, _(b'show normal and closed branches')),
1440 (b'c', b'closed', False, _(b'show normal and closed branches')),
1441 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1441 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1442 ]
1442 ]
1443 + formatteropts,
1443 + formatteropts,
1444 _(b'[-c]'),
1444 _(b'[-c]'),
1445 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1445 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1446 intents={INTENT_READONLY},
1446 intents={INTENT_READONLY},
1447 )
1447 )
1448 def branches(ui, repo, active=False, closed=False, **opts):
1448 def branches(ui, repo, active=False, closed=False, **opts):
1449 """list repository named branches
1449 """list repository named branches
1450
1450
1451 List the repository's named branches, indicating which ones are
1451 List the repository's named branches, indicating which ones are
1452 inactive. If -c/--closed is specified, also list branches which have
1452 inactive. If -c/--closed is specified, also list branches which have
1453 been marked closed (see :hg:`commit --close-branch`).
1453 been marked closed (see :hg:`commit --close-branch`).
1454
1454
1455 Use the command :hg:`update` to switch to an existing branch.
1455 Use the command :hg:`update` to switch to an existing branch.
1456
1456
1457 .. container:: verbose
1457 .. container:: verbose
1458
1458
1459 Template:
1459 Template:
1460
1460
1461 The following keywords are supported in addition to the common template
1461 The following keywords are supported in addition to the common template
1462 keywords and functions such as ``{branch}``. See also
1462 keywords and functions such as ``{branch}``. See also
1463 :hg:`help templates`.
1463 :hg:`help templates`.
1464
1464
1465 :active: Boolean. True if the branch is active.
1465 :active: Boolean. True if the branch is active.
1466 :closed: Boolean. True if the branch is closed.
1466 :closed: Boolean. True if the branch is closed.
1467 :current: Boolean. True if it is the current branch.
1467 :current: Boolean. True if it is the current branch.
1468
1468
1469 Returns 0.
1469 Returns 0.
1470 """
1470 """
1471
1471
1472 revs = opts.get('rev')
1472 revs = opts.get('rev')
1473 selectedbranches = None
1473 selectedbranches = None
1474 if revs:
1474 if revs:
1475 revs = logcmdutil.revrange(repo, revs)
1475 revs = logcmdutil.revrange(repo, revs)
1476 getbi = repo.revbranchcache().branchinfo
1476 getbi = repo.revbranchcache().branchinfo
1477 selectedbranches = {getbi(r)[0] for r in revs}
1477 selectedbranches = {getbi(r)[0] for r in revs}
1478
1478
1479 ui.pager(b'branches')
1479 ui.pager(b'branches')
1480 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1480 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1481 hexfunc = fm.hexfunc
1481 hexfunc = fm.hexfunc
1482
1482
1483 allheads = set(repo.heads())
1483 allheads = set(repo.heads())
1484 branches = []
1484 branches = []
1485 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1485 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1486 if selectedbranches is not None and tag not in selectedbranches:
1486 if selectedbranches is not None and tag not in selectedbranches:
1487 continue
1487 continue
1488 isactive = False
1488 isactive = False
1489 if not isclosed:
1489 if not isclosed:
1490 openheads = set(repo.branchmap().iteropen(heads))
1490 openheads = set(repo.branchmap().iteropen(heads))
1491 isactive = bool(openheads & allheads)
1491 isactive = bool(openheads & allheads)
1492 branches.append((tag, repo[tip], isactive, not isclosed))
1492 branches.append((tag, repo[tip], isactive, not isclosed))
1493 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1493 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1494
1494
1495 for tag, ctx, isactive, isopen in branches:
1495 for tag, ctx, isactive, isopen in branches:
1496 if active and not isactive:
1496 if active and not isactive:
1497 continue
1497 continue
1498 if isactive:
1498 if isactive:
1499 label = b'branches.active'
1499 label = b'branches.active'
1500 notice = b''
1500 notice = b''
1501 elif not isopen:
1501 elif not isopen:
1502 if not closed:
1502 if not closed:
1503 continue
1503 continue
1504 label = b'branches.closed'
1504 label = b'branches.closed'
1505 notice = _(b' (closed)')
1505 notice = _(b' (closed)')
1506 else:
1506 else:
1507 label = b'branches.inactive'
1507 label = b'branches.inactive'
1508 notice = _(b' (inactive)')
1508 notice = _(b' (inactive)')
1509 current = tag == repo.dirstate.branch()
1509 current = tag == repo.dirstate.branch()
1510 if current:
1510 if current:
1511 label = b'branches.current'
1511 label = b'branches.current'
1512
1512
1513 fm.startitem()
1513 fm.startitem()
1514 fm.write(b'branch', b'%s', tag, label=label)
1514 fm.write(b'branch', b'%s', tag, label=label)
1515 rev = ctx.rev()
1515 rev = ctx.rev()
1516 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1516 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1517 fmt = b' ' * padsize + b' %d:%s'
1517 fmt = b' ' * padsize + b' %d:%s'
1518 fm.condwrite(
1518 fm.condwrite(
1519 not ui.quiet,
1519 not ui.quiet,
1520 b'rev node',
1520 b'rev node',
1521 fmt,
1521 fmt,
1522 rev,
1522 rev,
1523 hexfunc(ctx.node()),
1523 hexfunc(ctx.node()),
1524 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1524 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1525 )
1525 )
1526 fm.context(ctx=ctx)
1526 fm.context(ctx=ctx)
1527 fm.data(active=isactive, closed=not isopen, current=current)
1527 fm.data(active=isactive, closed=not isopen, current=current)
1528 if not ui.quiet:
1528 if not ui.quiet:
1529 fm.plain(notice)
1529 fm.plain(notice)
1530 fm.plain(b'\n')
1530 fm.plain(b'\n')
1531 fm.end()
1531 fm.end()
1532
1532
1533
1533
1534 @command(
1534 @command(
1535 b'bundle',
1535 b'bundle',
1536 [
1536 [
1537 (
1537 (
1538 b'',
1538 b'',
1539 b'exact',
1539 b'exact',
1540 None,
1540 None,
1541 _(b'compute the base from the revision specified'),
1541 _(b'compute the base from the revision specified'),
1542 ),
1542 ),
1543 (
1543 (
1544 b'f',
1544 b'f',
1545 b'force',
1545 b'force',
1546 None,
1546 None,
1547 _(b'run even when the destination is unrelated'),
1547 _(b'run even when the destination is unrelated'),
1548 ),
1548 ),
1549 (
1549 (
1550 b'r',
1550 b'r',
1551 b'rev',
1551 b'rev',
1552 [],
1552 [],
1553 _(b'a changeset intended to be added to the destination'),
1553 _(b'a changeset intended to be added to the destination'),
1554 _(b'REV'),
1554 _(b'REV'),
1555 ),
1555 ),
1556 (
1556 (
1557 b'b',
1557 b'b',
1558 b'branch',
1558 b'branch',
1559 [],
1559 [],
1560 _(b'a specific branch you would like to bundle'),
1560 _(b'a specific branch you would like to bundle'),
1561 _(b'BRANCH'),
1561 _(b'BRANCH'),
1562 ),
1562 ),
1563 (
1563 (
1564 b'',
1564 b'',
1565 b'base',
1565 b'base',
1566 [],
1566 [],
1567 _(b'a base changeset assumed to be available at the destination'),
1567 _(b'a base changeset assumed to be available at the destination'),
1568 _(b'REV'),
1568 _(b'REV'),
1569 ),
1569 ),
1570 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1570 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1571 (
1571 (
1572 b't',
1572 b't',
1573 b'type',
1573 b'type',
1574 b'bzip2',
1574 b'bzip2',
1575 _(b'bundle compression type to use'),
1575 _(b'bundle compression type to use'),
1576 _(b'TYPE'),
1576 _(b'TYPE'),
1577 ),
1577 ),
1578 ]
1578 ]
1579 + remoteopts,
1579 + remoteopts,
1580 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1580 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1581 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1581 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1582 )
1582 )
1583 def bundle(ui, repo, fname, *dests, **opts):
1583 def bundle(ui, repo, fname, *dests, **opts):
1584 """create a bundle file
1584 """create a bundle file
1585
1585
1586 Generate a bundle file containing data to be transferred to another
1586 Generate a bundle file containing data to be transferred to another
1587 repository.
1587 repository.
1588
1588
1589 To create a bundle containing all changesets, use -a/--all
1589 To create a bundle containing all changesets, use -a/--all
1590 (or --base null). Otherwise, hg assumes the destination will have
1590 (or --base null). Otherwise, hg assumes the destination will have
1591 all the nodes you specify with --base parameters. Otherwise, hg
1591 all the nodes you specify with --base parameters. Otherwise, hg
1592 will assume the repository has all the nodes in destination, or
1592 will assume the repository has all the nodes in destination, or
1593 default-push/default if no destination is specified, where destination
1593 default-push/default if no destination is specified, where destination
1594 is the repositories you provide through DEST option.
1594 is the repositories you provide through DEST option.
1595
1595
1596 You can change bundle format with the -t/--type option. See
1596 You can change bundle format with the -t/--type option. See
1597 :hg:`help bundlespec` for documentation on this format. By default,
1597 :hg:`help bundlespec` for documentation on this format. By default,
1598 the most appropriate format is used and compression defaults to
1598 the most appropriate format is used and compression defaults to
1599 bzip2.
1599 bzip2.
1600
1600
1601 The bundle file can then be transferred using conventional means
1601 The bundle file can then be transferred using conventional means
1602 and applied to another repository with the unbundle or pull
1602 and applied to another repository with the unbundle or pull
1603 command. This is useful when direct push and pull are not
1603 command. This is useful when direct push and pull are not
1604 available or when exporting an entire repository is undesirable.
1604 available or when exporting an entire repository is undesirable.
1605
1605
1606 Applying bundles preserves all changeset contents including
1606 Applying bundles preserves all changeset contents including
1607 permissions, copy/rename information, and revision history.
1607 permissions, copy/rename information, and revision history.
1608
1608
1609 Returns 0 on success, 1 if no changes found.
1609 Returns 0 on success, 1 if no changes found.
1610 """
1610 """
1611
1611
1612 revs = None
1612 revs = None
1613 if 'rev' in opts:
1613 if 'rev' in opts:
1614 revstrings = opts['rev']
1614 revstrings = opts['rev']
1615 revs = logcmdutil.revrange(repo, revstrings)
1615 revs = logcmdutil.revrange(repo, revstrings)
1616 if revstrings and not revs:
1616 if revstrings and not revs:
1617 raise error.InputError(_(b'no commits to bundle'))
1617 raise error.InputError(_(b'no commits to bundle'))
1618
1618
1619 bundletype = opts.get('type', b'bzip2').lower()
1619 bundletype = opts.get('type', b'bzip2').lower()
1620 try:
1620 try:
1621 bundlespec = bundlecaches.parsebundlespec(
1621 bundlespec = bundlecaches.parsebundlespec(
1622 repo, bundletype, strict=False
1622 repo, bundletype, strict=False
1623 )
1623 )
1624 except error.UnsupportedBundleSpecification as e:
1624 except error.UnsupportedBundleSpecification as e:
1625 raise error.InputError(
1625 raise error.InputError(
1626 pycompat.bytestr(e),
1626 pycompat.bytestr(e),
1627 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1627 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1628 )
1628 )
1629
1630 has_changegroup = bundlespec.params.get(b"changegroup", False)
1629 cgversion = bundlespec.params[b"cg.version"]
1631 cgversion = bundlespec.params[b"cg.version"]
1630
1632
1631 # Packed bundles are a pseudo bundle format for now.
1633 # Packed bundles are a pseudo bundle format for now.
1632 if cgversion == b's1':
1634 if cgversion == b's1':
1633 raise error.InputError(
1635 raise error.InputError(
1634 _(b'packed bundles cannot be produced by "hg bundle"'),
1636 _(b'packed bundles cannot be produced by "hg bundle"'),
1635 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1637 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1636 )
1638 )
1637 base_opt = opts.get('base')
1639 base_opt = opts.get('base')
1638 if opts.get('all'):
1640 if opts.get('all'):
1639 if dests:
1641 if dests:
1640 raise error.InputError(
1642 raise error.InputError(
1641 _(b"--all is incompatible with specifying destinations")
1643 _(b"--all is incompatible with specifying destinations")
1642 )
1644 )
1643 if base_opt:
1645 if base_opt:
1644 ui.warn(_(b"ignoring --base because --all was specified\n"))
1646 ui.warn(_(b"ignoring --base because --all was specified\n"))
1645 if opts.get('exact'):
1647 if opts.get('exact'):
1646 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1648 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1647 base = [nullrev]
1649 base = [nullrev]
1648 elif opts.get('exact'):
1650 elif opts.get('exact'):
1649 if dests:
1651 if dests:
1650 raise error.InputError(
1652 raise error.InputError(
1651 _(b"--exact is incompatible with specifying destinations")
1653 _(b"--exact is incompatible with specifying destinations")
1652 )
1654 )
1653 if base_opt:
1655 if base_opt:
1654 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1656 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1655 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1657 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1656 if not base:
1658 if not base:
1657 base = [nullrev]
1659 base = [nullrev]
1658 elif base_opt:
1660 elif base_opt:
1659 base = logcmdutil.revrange(repo, base_opt)
1661 base = logcmdutil.revrange(repo, base_opt)
1660 if not base:
1662 if not base:
1661 # base specified, but nothing was selected
1663 # base specified, but nothing was selected
1662 base = [nullrev]
1664 base = [nullrev]
1663 else:
1665 else:
1664 base = None
1666 base = None
1665 if cgversion not in changegroup.supportedoutgoingversions(repo):
1667 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1668 if has_changegroup and cgversion not in supported_cg_versions:
1666 raise error.Abort(
1669 raise error.Abort(
1667 _(b"repository does not support bundle version %s") % cgversion
1670 _(b"repository does not support bundle version %s") % cgversion
1668 )
1671 )
1669
1672
1670 if base is not None:
1673 if base is not None:
1671 if dests:
1674 if dests:
1672 raise error.InputError(
1675 raise error.InputError(
1673 _(b"--base is incompatible with specifying destinations")
1676 _(b"--base is incompatible with specifying destinations")
1674 )
1677 )
1675 cl = repo.changelog
1678 cl = repo.changelog
1676 common = [cl.node(rev) for rev in base]
1679 common = [cl.node(rev) for rev in base]
1677 heads = [cl.node(r) for r in revs] if revs else None
1680 heads = [cl.node(r) for r in revs] if revs else None
1678 outgoing = discovery.outgoing(repo, common, heads)
1681 outgoing = discovery.outgoing(repo, common, heads)
1679 missing = outgoing.missing
1682 missing = outgoing.missing
1680 excluded = outgoing.excluded
1683 excluded = outgoing.excluded
1681 else:
1684 else:
1682 missing = set()
1685 missing = set()
1683 excluded = set()
1686 excluded = set()
1684 for path in urlutil.get_push_paths(repo, ui, dests):
1687 for path in urlutil.get_push_paths(repo, ui, dests):
1685 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1688 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1686 if revs is not None:
1689 if revs is not None:
1687 hex_revs = [repo[r].hex() for r in revs]
1690 hex_revs = [repo[r].hex() for r in revs]
1688 else:
1691 else:
1689 hex_revs = None
1692 hex_revs = None
1690 branches = (path.branch, [])
1693 branches = (path.branch, [])
1691 head_revs, checkout = hg.addbranchrevs(
1694 head_revs, checkout = hg.addbranchrevs(
1692 repo, repo, branches, hex_revs
1695 repo, repo, branches, hex_revs
1693 )
1696 )
1694 heads = (
1697 heads = (
1695 head_revs
1698 head_revs
1696 and pycompat.maplist(repo.lookup, head_revs)
1699 and pycompat.maplist(repo.lookup, head_revs)
1697 or head_revs
1700 or head_revs
1698 )
1701 )
1699 outgoing = discovery.findcommonoutgoing(
1702 outgoing = discovery.findcommonoutgoing(
1700 repo,
1703 repo,
1701 other,
1704 other,
1702 onlyheads=heads,
1705 onlyheads=heads,
1703 force=opts.get('force'),
1706 force=opts.get('force'),
1704 portable=True,
1707 portable=True,
1705 )
1708 )
1706 missing.update(outgoing.missing)
1709 missing.update(outgoing.missing)
1707 excluded.update(outgoing.excluded)
1710 excluded.update(outgoing.excluded)
1708
1711
1709 if not missing:
1712 if not missing:
1710 scmutil.nochangesfound(ui, repo, not base and excluded)
1713 scmutil.nochangesfound(ui, repo, not base and excluded)
1711 return 1
1714 return 1
1712
1715
1713 # internal changeset are internal implementation details that should not
1716 # internal changeset are internal implementation details that should not
1714 # leave the repository. Bundling with `hg bundle` create such risk.
1717 # leave the repository. Bundling with `hg bundle` create such risk.
1715 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1718 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1716 if bundled_internal:
1719 if bundled_internal:
1717 msg = _(b"cannot bundle internal changesets")
1720 msg = _(b"cannot bundle internal changesets")
1718 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1721 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1719 raise error.Abort(msg, hint=hint)
1722 raise error.Abort(msg, hint=hint)
1720
1723
1721 if heads:
1724 if heads:
1722 outgoing = discovery.outgoing(
1725 outgoing = discovery.outgoing(
1723 repo, missingroots=missing, ancestorsof=heads
1726 repo, missingroots=missing, ancestorsof=heads
1724 )
1727 )
1725 else:
1728 else:
1726 outgoing = discovery.outgoing(repo, missingroots=missing)
1729 outgoing = discovery.outgoing(repo, missingroots=missing)
1727 outgoing.excluded = sorted(excluded)
1730 outgoing.excluded = sorted(excluded)
1728
1731
1729 if cgversion == b'01': # bundle1
1732 if cgversion == b'01': # bundle1
1730 bversion = b'HG10' + bundlespec.wirecompression
1733 bversion = b'HG10' + bundlespec.wirecompression
1731 bcompression = None
1734 bcompression = None
1732 elif cgversion in (b'02', b'03'):
1735 elif cgversion in (b'02', b'03'):
1733 bversion = b'HG20'
1736 bversion = b'HG20'
1734 bcompression = bundlespec.wirecompression
1737 bcompression = bundlespec.wirecompression
1735 else:
1738 else:
1736 raise error.ProgrammingError(
1739 raise error.ProgrammingError(
1737 b'bundle: unexpected changegroup version %s' % cgversion
1740 b'bundle: unexpected changegroup version %s' % cgversion
1738 )
1741 )
1739
1742
1740 # TODO compression options should be derived from bundlespec parsing.
1743 # TODO compression options should be derived from bundlespec parsing.
1741 # This is a temporary hack to allow adjusting bundle compression
1744 # This is a temporary hack to allow adjusting bundle compression
1742 # level without a) formalizing the bundlespec changes to declare it
1745 # level without a) formalizing the bundlespec changes to declare it
1743 # b) introducing a command flag.
1746 # b) introducing a command flag.
1744 compopts = {}
1747 compopts = {}
1745 complevel = ui.configint(
1748 complevel = ui.configint(
1746 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1749 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1747 )
1750 )
1748 if complevel is None:
1751 if complevel is None:
1749 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1752 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1750 if complevel is not None:
1753 if complevel is not None:
1751 compopts[b'level'] = complevel
1754 compopts[b'level'] = complevel
1752
1755
1753 compthreads = ui.configint(
1756 compthreads = ui.configint(
1754 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1757 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1755 )
1758 )
1756 if compthreads is None:
1759 if compthreads is None:
1757 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1760 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1758 if compthreads is not None:
1761 if compthreads is not None:
1759 compopts[b'threads'] = compthreads
1762 compopts[b'threads'] = compthreads
1760
1763
1761 # Bundling of obsmarker and phases is optional as not all clients
1764 # Bundling of obsmarker and phases is optional as not all clients
1762 # support the necessary features.
1765 # support the necessary features.
1763 cfg = ui.configbool
1766 cfg = ui.configbool
1764 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1767 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1765 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1768 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1766 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1769 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1767 bundlespec.set_param(
1770 bundlespec.set_param(
1768 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1771 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1769 )
1772 )
1770 if not bundlespec.params.get(b'phases', False):
1773 if not bundlespec.params.get(b'phases', False):
1771 phases_cfg = cfg(b'experimental', b'bundle-phases')
1774 phases_cfg = cfg(b'experimental', b'bundle-phases')
1772 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1775 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1773
1776
1774 bundle2.writenewbundle(
1777 bundle2.writenewbundle(
1775 ui,
1778 ui,
1776 repo,
1779 repo,
1777 b'bundle',
1780 b'bundle',
1778 fname,
1781 fname,
1779 bversion,
1782 bversion,
1780 outgoing,
1783 outgoing,
1781 bundlespec.params,
1784 bundlespec.params,
1782 compression=bcompression,
1785 compression=bcompression,
1783 compopts=compopts,
1786 compopts=compopts,
1784 )
1787 )
1785
1788
1786
1789
1787 @command(
1790 @command(
1788 b'cat',
1791 b'cat',
1789 [
1792 [
1790 (
1793 (
1791 b'o',
1794 b'o',
1792 b'output',
1795 b'output',
1793 b'',
1796 b'',
1794 _(b'print output to file with formatted name'),
1797 _(b'print output to file with formatted name'),
1795 _(b'FORMAT'),
1798 _(b'FORMAT'),
1796 ),
1799 ),
1797 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1800 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1798 (b'', b'decode', None, _(b'apply any matching decode filter')),
1801 (b'', b'decode', None, _(b'apply any matching decode filter')),
1799 ]
1802 ]
1800 + walkopts
1803 + walkopts
1801 + formatteropts,
1804 + formatteropts,
1802 _(b'[OPTION]... FILE...'),
1805 _(b'[OPTION]... FILE...'),
1803 helpcategory=command.CATEGORY_FILE_CONTENTS,
1806 helpcategory=command.CATEGORY_FILE_CONTENTS,
1804 inferrepo=True,
1807 inferrepo=True,
1805 intents={INTENT_READONLY},
1808 intents={INTENT_READONLY},
1806 )
1809 )
1807 def cat(ui, repo, file1, *pats, **opts):
1810 def cat(ui, repo, file1, *pats, **opts):
1808 """output the current or given revision of files
1811 """output the current or given revision of files
1809
1812
1810 Print the specified files as they were at the given revision. If
1813 Print the specified files as they were at the given revision. If
1811 no revision is given, the parent of the working directory is used.
1814 no revision is given, the parent of the working directory is used.
1812
1815
1813 Output may be to a file, in which case the name of the file is
1816 Output may be to a file, in which case the name of the file is
1814 given using a template string. See :hg:`help templates`. In addition
1817 given using a template string. See :hg:`help templates`. In addition
1815 to the common template keywords, the following formatting rules are
1818 to the common template keywords, the following formatting rules are
1816 supported:
1819 supported:
1817
1820
1818 :``%%``: literal "%" character
1821 :``%%``: literal "%" character
1819 :``%s``: basename of file being printed
1822 :``%s``: basename of file being printed
1820 :``%d``: dirname of file being printed, or '.' if in repository root
1823 :``%d``: dirname of file being printed, or '.' if in repository root
1821 :``%p``: root-relative path name of file being printed
1824 :``%p``: root-relative path name of file being printed
1822 :``%H``: changeset hash (40 hexadecimal digits)
1825 :``%H``: changeset hash (40 hexadecimal digits)
1823 :``%R``: changeset revision number
1826 :``%R``: changeset revision number
1824 :``%h``: short-form changeset hash (12 hexadecimal digits)
1827 :``%h``: short-form changeset hash (12 hexadecimal digits)
1825 :``%r``: zero-padded changeset revision number
1828 :``%r``: zero-padded changeset revision number
1826 :``%b``: basename of the exporting repository
1829 :``%b``: basename of the exporting repository
1827 :``\\``: literal "\\" character
1830 :``\\``: literal "\\" character
1828
1831
1829 .. container:: verbose
1832 .. container:: verbose
1830
1833
1831 Template:
1834 Template:
1832
1835
1833 The following keywords are supported in addition to the common template
1836 The following keywords are supported in addition to the common template
1834 keywords and functions. See also :hg:`help templates`.
1837 keywords and functions. See also :hg:`help templates`.
1835
1838
1836 :data: String. File content.
1839 :data: String. File content.
1837 :path: String. Repository-absolute path of the file.
1840 :path: String. Repository-absolute path of the file.
1838
1841
1839 Returns 0 on success.
1842 Returns 0 on success.
1840 """
1843 """
1841 rev = opts.get('rev')
1844 rev = opts.get('rev')
1842 if rev:
1845 if rev:
1843 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1846 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1844 ctx = logcmdutil.revsingle(repo, rev)
1847 ctx = logcmdutil.revsingle(repo, rev)
1845 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1848 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1846 fntemplate = opts.pop('output', b'')
1849 fntemplate = opts.pop('output', b'')
1847 if cmdutil.isstdiofilename(fntemplate):
1850 if cmdutil.isstdiofilename(fntemplate):
1848 fntemplate = b''
1851 fntemplate = b''
1849
1852
1850 if fntemplate:
1853 if fntemplate:
1851 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1854 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1852 else:
1855 else:
1853 ui.pager(b'cat')
1856 ui.pager(b'cat')
1854 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1857 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1855 with fm:
1858 with fm:
1856 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1859 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1857
1860
1858
1861
1859 @command(
1862 @command(
1860 b'clone',
1863 b'clone',
1861 [
1864 [
1862 (
1865 (
1863 b'U',
1866 b'U',
1864 b'noupdate',
1867 b'noupdate',
1865 None,
1868 None,
1866 _(
1869 _(
1867 b'the clone will include an empty working '
1870 b'the clone will include an empty working '
1868 b'directory (only a repository)'
1871 b'directory (only a repository)'
1869 ),
1872 ),
1870 ),
1873 ),
1871 (
1874 (
1872 b'u',
1875 b'u',
1873 b'updaterev',
1876 b'updaterev',
1874 b'',
1877 b'',
1875 _(b'revision, tag, or branch to check out'),
1878 _(b'revision, tag, or branch to check out'),
1876 _(b'REV'),
1879 _(b'REV'),
1877 ),
1880 ),
1878 (
1881 (
1879 b'r',
1882 b'r',
1880 b'rev',
1883 b'rev',
1881 [],
1884 [],
1882 _(
1885 _(
1883 b'do not clone everything, but include this changeset'
1886 b'do not clone everything, but include this changeset'
1884 b' and its ancestors'
1887 b' and its ancestors'
1885 ),
1888 ),
1886 _(b'REV'),
1889 _(b'REV'),
1887 ),
1890 ),
1888 (
1891 (
1889 b'b',
1892 b'b',
1890 b'branch',
1893 b'branch',
1891 [],
1894 [],
1892 _(
1895 _(
1893 b'do not clone everything, but include this branch\'s'
1896 b'do not clone everything, but include this branch\'s'
1894 b' changesets and their ancestors'
1897 b' changesets and their ancestors'
1895 ),
1898 ),
1896 _(b'BRANCH'),
1899 _(b'BRANCH'),
1897 ),
1900 ),
1898 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1901 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1899 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1902 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1900 (b'', b'stream', None, _(b'clone with minimal data processing')),
1903 (b'', b'stream', None, _(b'clone with minimal data processing')),
1901 ]
1904 ]
1902 + remoteopts,
1905 + remoteopts,
1903 _(b'[OPTION]... SOURCE [DEST]'),
1906 _(b'[OPTION]... SOURCE [DEST]'),
1904 helpcategory=command.CATEGORY_REPO_CREATION,
1907 helpcategory=command.CATEGORY_REPO_CREATION,
1905 helpbasic=True,
1908 helpbasic=True,
1906 norepo=True,
1909 norepo=True,
1907 )
1910 )
1908 def clone(ui, source, dest=None, **opts):
1911 def clone(ui, source, dest=None, **opts):
1909 """make a copy of an existing repository
1912 """make a copy of an existing repository
1910
1913
1911 Create a copy of an existing repository in a new directory.
1914 Create a copy of an existing repository in a new directory.
1912
1915
1913 If no destination directory name is specified, it defaults to the
1916 If no destination directory name is specified, it defaults to the
1914 basename of the source.
1917 basename of the source.
1915
1918
1916 The location of the source is added to the new repository's
1919 The location of the source is added to the new repository's
1917 ``.hg/hgrc`` file, as the default to be used for future pulls.
1920 ``.hg/hgrc`` file, as the default to be used for future pulls.
1918
1921
1919 Only local paths and ``ssh://`` URLs are supported as
1922 Only local paths and ``ssh://`` URLs are supported as
1920 destinations. For ``ssh://`` destinations, no working directory or
1923 destinations. For ``ssh://`` destinations, no working directory or
1921 ``.hg/hgrc`` will be created on the remote side.
1924 ``.hg/hgrc`` will be created on the remote side.
1922
1925
1923 If the source repository has a bookmark called '@' set, that
1926 If the source repository has a bookmark called '@' set, that
1924 revision will be checked out in the new repository by default.
1927 revision will be checked out in the new repository by default.
1925
1928
1926 To check out a particular version, use -u/--update, or
1929 To check out a particular version, use -u/--update, or
1927 -U/--noupdate to create a clone with no working directory.
1930 -U/--noupdate to create a clone with no working directory.
1928
1931
1929 To pull only a subset of changesets, specify one or more revisions
1932 To pull only a subset of changesets, specify one or more revisions
1930 identifiers with -r/--rev or branches with -b/--branch. The
1933 identifiers with -r/--rev or branches with -b/--branch. The
1931 resulting clone will contain only the specified changesets and
1934 resulting clone will contain only the specified changesets and
1932 their ancestors. These options (or 'clone src#rev dest') imply
1935 their ancestors. These options (or 'clone src#rev dest') imply
1933 --pull, even for local source repositories.
1936 --pull, even for local source repositories.
1934
1937
1935 In normal clone mode, the remote normalizes repository data into a common
1938 In normal clone mode, the remote normalizes repository data into a common
1936 exchange format and the receiving end translates this data into its local
1939 exchange format and the receiving end translates this data into its local
1937 storage format. --stream activates a different clone mode that essentially
1940 storage format. --stream activates a different clone mode that essentially
1938 copies repository files from the remote with minimal data processing. This
1941 copies repository files from the remote with minimal data processing. This
1939 significantly reduces the CPU cost of a clone both remotely and locally.
1942 significantly reduces the CPU cost of a clone both remotely and locally.
1940 However, it often increases the transferred data size by 30-40%. This can
1943 However, it often increases the transferred data size by 30-40%. This can
1941 result in substantially faster clones where I/O throughput is plentiful,
1944 result in substantially faster clones where I/O throughput is plentiful,
1942 especially for larger repositories. A side-effect of --stream clones is
1945 especially for larger repositories. A side-effect of --stream clones is
1943 that storage settings and requirements on the remote are applied locally:
1946 that storage settings and requirements on the remote are applied locally:
1944 a modern client may inherit legacy or inefficient storage used by the
1947 a modern client may inherit legacy or inefficient storage used by the
1945 remote or a legacy Mercurial client may not be able to clone from a
1948 remote or a legacy Mercurial client may not be able to clone from a
1946 modern Mercurial remote.
1949 modern Mercurial remote.
1947
1950
1948 .. note::
1951 .. note::
1949
1952
1950 Specifying a tag will include the tagged changeset but not the
1953 Specifying a tag will include the tagged changeset but not the
1951 changeset containing the tag.
1954 changeset containing the tag.
1952
1955
1953 .. container:: verbose
1956 .. container:: verbose
1954
1957
1955 For efficiency, hardlinks are used for cloning whenever the
1958 For efficiency, hardlinks are used for cloning whenever the
1956 source and destination are on the same filesystem (note this
1959 source and destination are on the same filesystem (note this
1957 applies only to the repository data, not to the working
1960 applies only to the repository data, not to the working
1958 directory). Some filesystems, such as AFS, implement hardlinking
1961 directory). Some filesystems, such as AFS, implement hardlinking
1959 incorrectly, but do not report errors. In these cases, use the
1962 incorrectly, but do not report errors. In these cases, use the
1960 --pull option to avoid hardlinking.
1963 --pull option to avoid hardlinking.
1961
1964
1962 Mercurial will update the working directory to the first applicable
1965 Mercurial will update the working directory to the first applicable
1963 revision from this list:
1966 revision from this list:
1964
1967
1965 a) null if -U or the source repository has no changesets
1968 a) null if -U or the source repository has no changesets
1966 b) if -u . and the source repository is local, the first parent of
1969 b) if -u . and the source repository is local, the first parent of
1967 the source repository's working directory
1970 the source repository's working directory
1968 c) the changeset specified with -u (if a branch name, this means the
1971 c) the changeset specified with -u (if a branch name, this means the
1969 latest head of that branch)
1972 latest head of that branch)
1970 d) the changeset specified with -r
1973 d) the changeset specified with -r
1971 e) the tipmost head specified with -b
1974 e) the tipmost head specified with -b
1972 f) the tipmost head specified with the url#branch source syntax
1975 f) the tipmost head specified with the url#branch source syntax
1973 g) the revision marked with the '@' bookmark, if present
1976 g) the revision marked with the '@' bookmark, if present
1974 h) the tipmost head of the default branch
1977 h) the tipmost head of the default branch
1975 i) tip
1978 i) tip
1976
1979
1977 When cloning from servers that support it, Mercurial may fetch
1980 When cloning from servers that support it, Mercurial may fetch
1978 pre-generated data from a server-advertised URL or inline from the
1981 pre-generated data from a server-advertised URL or inline from the
1979 same stream. When this is done, hooks operating on incoming changesets
1982 same stream. When this is done, hooks operating on incoming changesets
1980 and changegroups may fire more than once, once for each pre-generated
1983 and changegroups may fire more than once, once for each pre-generated
1981 bundle and as well as for any additional remaining data. In addition,
1984 bundle and as well as for any additional remaining data. In addition,
1982 if an error occurs, the repository may be rolled back to a partial
1985 if an error occurs, the repository may be rolled back to a partial
1983 clone. This behavior may change in future releases.
1986 clone. This behavior may change in future releases.
1984 See :hg:`help -e clonebundles` for more.
1987 See :hg:`help -e clonebundles` for more.
1985
1988
1986 Examples:
1989 Examples:
1987
1990
1988 - clone a remote repository to a new directory named hg/::
1991 - clone a remote repository to a new directory named hg/::
1989
1992
1990 hg clone https://www.mercurial-scm.org/repo/hg/
1993 hg clone https://www.mercurial-scm.org/repo/hg/
1991
1994
1992 - create a lightweight local clone::
1995 - create a lightweight local clone::
1993
1996
1994 hg clone project/ project-feature/
1997 hg clone project/ project-feature/
1995
1998
1996 - clone from an absolute path on an ssh server (note double-slash)::
1999 - clone from an absolute path on an ssh server (note double-slash)::
1997
2000
1998 hg clone ssh://user@server//home/projects/alpha/
2001 hg clone ssh://user@server//home/projects/alpha/
1999
2002
2000 - do a streaming clone while checking out a specified version::
2003 - do a streaming clone while checking out a specified version::
2001
2004
2002 hg clone --stream http://server/repo -u 1.5
2005 hg clone --stream http://server/repo -u 1.5
2003
2006
2004 - create a repository without changesets after a particular revision::
2007 - create a repository without changesets after a particular revision::
2005
2008
2006 hg clone -r 04e544 experimental/ good/
2009 hg clone -r 04e544 experimental/ good/
2007
2010
2008 - clone (and track) a particular named branch::
2011 - clone (and track) a particular named branch::
2009
2012
2010 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2013 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2011
2014
2012 See :hg:`help urls` for details on specifying URLs.
2015 See :hg:`help urls` for details on specifying URLs.
2013
2016
2014 Returns 0 on success.
2017 Returns 0 on success.
2015 """
2018 """
2016 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2019 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2017
2020
2018 # --include/--exclude can come from narrow or sparse.
2021 # --include/--exclude can come from narrow or sparse.
2019 includepats, excludepats = None, None
2022 includepats, excludepats = None, None
2020
2023
2021 # hg.clone() differentiates between None and an empty set. So make sure
2024 # hg.clone() differentiates between None and an empty set. So make sure
2022 # patterns are sets if narrow is requested without patterns.
2025 # patterns are sets if narrow is requested without patterns.
2023 if opts.get('narrow'):
2026 if opts.get('narrow'):
2024 includepats = set()
2027 includepats = set()
2025 excludepats = set()
2028 excludepats = set()
2026
2029
2027 if opts.get('include'):
2030 if opts.get('include'):
2028 includepats = narrowspec.parsepatterns(opts.get('include'))
2031 includepats = narrowspec.parsepatterns(opts.get('include'))
2029 if opts.get('exclude'):
2032 if opts.get('exclude'):
2030 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2033 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2031
2034
2032 r = hg.clone(
2035 r = hg.clone(
2033 ui,
2036 ui,
2034 pycompat.byteskwargs(opts),
2037 pycompat.byteskwargs(opts),
2035 source,
2038 source,
2036 dest,
2039 dest,
2037 pull=opts.get('pull'),
2040 pull=opts.get('pull'),
2038 stream=opts.get('stream') or opts.get('uncompressed'),
2041 stream=opts.get('stream') or opts.get('uncompressed'),
2039 revs=opts.get('rev'),
2042 revs=opts.get('rev'),
2040 update=opts.get('updaterev') or not opts.get('noupdate'),
2043 update=opts.get('updaterev') or not opts.get('noupdate'),
2041 branch=opts.get('branch'),
2044 branch=opts.get('branch'),
2042 shareopts=opts.get('shareopts'),
2045 shareopts=opts.get('shareopts'),
2043 storeincludepats=includepats,
2046 storeincludepats=includepats,
2044 storeexcludepats=excludepats,
2047 storeexcludepats=excludepats,
2045 depth=opts.get('depth') or None,
2048 depth=opts.get('depth') or None,
2046 )
2049 )
2047
2050
2048 return r is None
2051 return r is None
2049
2052
2050
2053
2051 @command(
2054 @command(
2052 b'commit|ci',
2055 b'commit|ci',
2053 [
2056 [
2054 (
2057 (
2055 b'A',
2058 b'A',
2056 b'addremove',
2059 b'addremove',
2057 None,
2060 None,
2058 _(b'mark new/missing files as added/removed before committing'),
2061 _(b'mark new/missing files as added/removed before committing'),
2059 ),
2062 ),
2060 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2063 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2061 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2064 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2062 (b's', b'secret', None, _(b'use the secret phase for committing')),
2065 (b's', b'secret', None, _(b'use the secret phase for committing')),
2063 (b'', b'draft', None, _(b'use the draft phase for committing')),
2066 (b'', b'draft', None, _(b'use the draft phase for committing')),
2064 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2067 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2065 (
2068 (
2066 b'',
2069 b'',
2067 b'force-close-branch',
2070 b'force-close-branch',
2068 None,
2071 None,
2069 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2072 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2070 ),
2073 ),
2071 (b'i', b'interactive', None, _(b'use interactive mode')),
2074 (b'i', b'interactive', None, _(b'use interactive mode')),
2072 ]
2075 ]
2073 + walkopts
2076 + walkopts
2074 + commitopts
2077 + commitopts
2075 + commitopts2
2078 + commitopts2
2076 + subrepoopts,
2079 + subrepoopts,
2077 _(b'[OPTION]... [FILE]...'),
2080 _(b'[OPTION]... [FILE]...'),
2078 helpcategory=command.CATEGORY_COMMITTING,
2081 helpcategory=command.CATEGORY_COMMITTING,
2079 helpbasic=True,
2082 helpbasic=True,
2080 inferrepo=True,
2083 inferrepo=True,
2081 )
2084 )
2082 def commit(ui, repo, *pats, **opts):
2085 def commit(ui, repo, *pats, **opts):
2083 """commit the specified files or all outstanding changes
2086 """commit the specified files or all outstanding changes
2084
2087
2085 Commit changes to the given files into the repository. Unlike a
2088 Commit changes to the given files into the repository. Unlike a
2086 centralized SCM, this operation is a local operation. See
2089 centralized SCM, this operation is a local operation. See
2087 :hg:`push` for a way to actively distribute your changes.
2090 :hg:`push` for a way to actively distribute your changes.
2088
2091
2089 If a list of files is omitted, all changes reported by :hg:`status`
2092 If a list of files is omitted, all changes reported by :hg:`status`
2090 will be committed.
2093 will be committed.
2091
2094
2092 If you are committing the result of a merge, do not provide any
2095 If you are committing the result of a merge, do not provide any
2093 filenames or -I/-X filters.
2096 filenames or -I/-X filters.
2094
2097
2095 If no commit message is specified, Mercurial starts your
2098 If no commit message is specified, Mercurial starts your
2096 configured editor where you can enter a message. In case your
2099 configured editor where you can enter a message. In case your
2097 commit fails, you will find a backup of your message in
2100 commit fails, you will find a backup of your message in
2098 ``.hg/last-message.txt``.
2101 ``.hg/last-message.txt``.
2099
2102
2100 The --close-branch flag can be used to mark the current branch
2103 The --close-branch flag can be used to mark the current branch
2101 head closed. When all heads of a branch are closed, the branch
2104 head closed. When all heads of a branch are closed, the branch
2102 will be considered closed and no longer listed.
2105 will be considered closed and no longer listed.
2103
2106
2104 The --amend flag can be used to amend the parent of the
2107 The --amend flag can be used to amend the parent of the
2105 working directory with a new commit that contains the changes
2108 working directory with a new commit that contains the changes
2106 in the parent in addition to those currently reported by :hg:`status`,
2109 in the parent in addition to those currently reported by :hg:`status`,
2107 if there are any. The old commit is stored in a backup bundle in
2110 if there are any. The old commit is stored in a backup bundle in
2108 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2111 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2109 on how to restore it).
2112 on how to restore it).
2110
2113
2111 Message, user and date are taken from the amended commit unless
2114 Message, user and date are taken from the amended commit unless
2112 specified. When a message isn't specified on the command line,
2115 specified. When a message isn't specified on the command line,
2113 the editor will open with the message of the amended commit.
2116 the editor will open with the message of the amended commit.
2114
2117
2115 It is not possible to amend public changesets (see :hg:`help phases`)
2118 It is not possible to amend public changesets (see :hg:`help phases`)
2116 or changesets that have children.
2119 or changesets that have children.
2117
2120
2118 See :hg:`help dates` for a list of formats valid for -d/--date.
2121 See :hg:`help dates` for a list of formats valid for -d/--date.
2119
2122
2120 Returns 0 on success, 1 if nothing changed.
2123 Returns 0 on success, 1 if nothing changed.
2121
2124
2122 .. container:: verbose
2125 .. container:: verbose
2123
2126
2124 Examples:
2127 Examples:
2125
2128
2126 - commit all files ending in .py::
2129 - commit all files ending in .py::
2127
2130
2128 hg commit --include "set:**.py"
2131 hg commit --include "set:**.py"
2129
2132
2130 - commit all non-binary files::
2133 - commit all non-binary files::
2131
2134
2132 hg commit --exclude "set:binary()"
2135 hg commit --exclude "set:binary()"
2133
2136
2134 - amend the current commit and set the date to now::
2137 - amend the current commit and set the date to now::
2135
2138
2136 hg commit --amend --date now
2139 hg commit --amend --date now
2137 """
2140 """
2138 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2141 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2139 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2142 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2140 with repo.wlock(), repo.lock():
2143 with repo.wlock(), repo.lock():
2141 return _docommit(ui, repo, *pats, **opts)
2144 return _docommit(ui, repo, *pats, **opts)
2142
2145
2143
2146
2144 def _docommit(ui, repo, *pats, **opts):
2147 def _docommit(ui, repo, *pats, **opts):
2145 if opts.get('interactive'):
2148 if opts.get('interactive'):
2146 opts.pop('interactive')
2149 opts.pop('interactive')
2147 ret = cmdutil.dorecord(
2150 ret = cmdutil.dorecord(
2148 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2151 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2149 )
2152 )
2150 # ret can be 0 (no changes to record) or the value returned by
2153 # ret can be 0 (no changes to record) or the value returned by
2151 # commit(), 1 if nothing changed or None on success.
2154 # commit(), 1 if nothing changed or None on success.
2152 return 1 if ret == 0 else ret
2155 return 1 if ret == 0 else ret
2153
2156
2154 if opts.get('subrepos'):
2157 if opts.get('subrepos'):
2155 # Let --subrepos on the command line override config setting.
2158 # Let --subrepos on the command line override config setting.
2156 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2159 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2157
2160
2158 cmdutil.checkunfinished(repo, commit=True)
2161 cmdutil.checkunfinished(repo, commit=True)
2159
2162
2160 branch = repo[None].branch()
2163 branch = repo[None].branch()
2161 bheads = repo.branchheads(branch)
2164 bheads = repo.branchheads(branch)
2162 tip = repo.changelog.tip()
2165 tip = repo.changelog.tip()
2163
2166
2164 extra = {}
2167 extra = {}
2165 if opts.get('close_branch') or opts.get('force_close_branch'):
2168 if opts.get('close_branch') or opts.get('force_close_branch'):
2166 extra[b'close'] = b'1'
2169 extra[b'close'] = b'1'
2167
2170
2168 if repo[b'.'].closesbranch():
2171 if repo[b'.'].closesbranch():
2169 # Not ideal, but let us do an extra status early to prevent early
2172 # Not ideal, but let us do an extra status early to prevent early
2170 # bail out.
2173 # bail out.
2171 matcher = scmutil.match(
2174 matcher = scmutil.match(
2172 repo[None], pats, pycompat.byteskwargs(opts)
2175 repo[None], pats, pycompat.byteskwargs(opts)
2173 )
2176 )
2174 s = repo.status(match=matcher)
2177 s = repo.status(match=matcher)
2175 if s.modified or s.added or s.removed:
2178 if s.modified or s.added or s.removed:
2176 bheads = repo.branchheads(branch, closed=True)
2179 bheads = repo.branchheads(branch, closed=True)
2177 else:
2180 else:
2178 msg = _(b'current revision is already a branch closing head')
2181 msg = _(b'current revision is already a branch closing head')
2179 raise error.InputError(msg)
2182 raise error.InputError(msg)
2180
2183
2181 if not bheads:
2184 if not bheads:
2182 raise error.InputError(
2185 raise error.InputError(
2183 _(b'branch "%s" has no heads to close') % branch
2186 _(b'branch "%s" has no heads to close') % branch
2184 )
2187 )
2185 elif (
2188 elif (
2186 branch == repo[b'.'].branch()
2189 branch == repo[b'.'].branch()
2187 and repo[b'.'].node() not in bheads
2190 and repo[b'.'].node() not in bheads
2188 and not opts.get('force_close_branch')
2191 and not opts.get('force_close_branch')
2189 ):
2192 ):
2190 hint = _(
2193 hint = _(
2191 b'use --force-close-branch to close branch from a non-head'
2194 b'use --force-close-branch to close branch from a non-head'
2192 b' changeset'
2195 b' changeset'
2193 )
2196 )
2194 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2197 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2195 elif opts.get('amend'):
2198 elif opts.get('amend'):
2196 if (
2199 if (
2197 repo[b'.'].p1().branch() != branch
2200 repo[b'.'].p1().branch() != branch
2198 and repo[b'.'].p2().branch() != branch
2201 and repo[b'.'].p2().branch() != branch
2199 ):
2202 ):
2200 raise error.InputError(_(b'can only close branch heads'))
2203 raise error.InputError(_(b'can only close branch heads'))
2201
2204
2202 if opts.get('amend'):
2205 if opts.get('amend'):
2203 if ui.configbool(b'ui', b'commitsubrepos'):
2206 if ui.configbool(b'ui', b'commitsubrepos'):
2204 raise error.InputError(
2207 raise error.InputError(
2205 _(b'cannot amend with ui.commitsubrepos enabled')
2208 _(b'cannot amend with ui.commitsubrepos enabled')
2206 )
2209 )
2207
2210
2208 old = repo[b'.']
2211 old = repo[b'.']
2209 rewriteutil.precheck(repo, [old.rev()], b'amend')
2212 rewriteutil.precheck(repo, [old.rev()], b'amend')
2210
2213
2211 # Currently histedit gets confused if an amend happens while histedit
2214 # Currently histedit gets confused if an amend happens while histedit
2212 # is in progress. Since we have a checkunfinished command, we are
2215 # is in progress. Since we have a checkunfinished command, we are
2213 # temporarily honoring it.
2216 # temporarily honoring it.
2214 #
2217 #
2215 # Note: eventually this guard will be removed. Please do not expect
2218 # Note: eventually this guard will be removed. Please do not expect
2216 # this behavior to remain.
2219 # this behavior to remain.
2217 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2220 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2218 cmdutil.checkunfinished(repo)
2221 cmdutil.checkunfinished(repo)
2219
2222
2220 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2223 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2221 if node == old.node():
2224 if node == old.node():
2222 ui.status(_(b"nothing changed\n"))
2225 ui.status(_(b"nothing changed\n"))
2223 return 1
2226 return 1
2224 else:
2227 else:
2225
2228
2226 def commitfunc(ui, repo, message, match, opts):
2229 def commitfunc(ui, repo, message, match, opts):
2227 overrides = {}
2230 overrides = {}
2228 if opts.get(b'secret'):
2231 if opts.get(b'secret'):
2229 overrides[(b'phases', b'new-commit')] = b'secret'
2232 overrides[(b'phases', b'new-commit')] = b'secret'
2230 elif opts.get(b'draft'):
2233 elif opts.get(b'draft'):
2231 overrides[(b'phases', b'new-commit')] = b'draft'
2234 overrides[(b'phases', b'new-commit')] = b'draft'
2232
2235
2233 baseui = repo.baseui
2236 baseui = repo.baseui
2234 with baseui.configoverride(overrides, b'commit'):
2237 with baseui.configoverride(overrides, b'commit'):
2235 with ui.configoverride(overrides, b'commit'):
2238 with ui.configoverride(overrides, b'commit'):
2236 editform = cmdutil.mergeeditform(
2239 editform = cmdutil.mergeeditform(
2237 repo[None], b'commit.normal'
2240 repo[None], b'commit.normal'
2238 )
2241 )
2239 editor = cmdutil.getcommiteditor(
2242 editor = cmdutil.getcommiteditor(
2240 editform=editform, **pycompat.strkwargs(opts)
2243 editform=editform, **pycompat.strkwargs(opts)
2241 )
2244 )
2242 return repo.commit(
2245 return repo.commit(
2243 message,
2246 message,
2244 opts.get(b'user'),
2247 opts.get(b'user'),
2245 opts.get(b'date'),
2248 opts.get(b'date'),
2246 match,
2249 match,
2247 editor=editor,
2250 editor=editor,
2248 extra=extra,
2251 extra=extra,
2249 )
2252 )
2250
2253
2251 node = cmdutil.commit(
2254 node = cmdutil.commit(
2252 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2255 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2253 )
2256 )
2254
2257
2255 if not node:
2258 if not node:
2256 stat = cmdutil.postcommitstatus(
2259 stat = cmdutil.postcommitstatus(
2257 repo, pats, pycompat.byteskwargs(opts)
2260 repo, pats, pycompat.byteskwargs(opts)
2258 )
2261 )
2259 if stat.deleted:
2262 if stat.deleted:
2260 ui.status(
2263 ui.status(
2261 _(
2264 _(
2262 b"nothing changed (%d missing files, see "
2265 b"nothing changed (%d missing files, see "
2263 b"'hg status')\n"
2266 b"'hg status')\n"
2264 )
2267 )
2265 % len(stat.deleted)
2268 % len(stat.deleted)
2266 )
2269 )
2267 else:
2270 else:
2268 ui.status(_(b"nothing changed\n"))
2271 ui.status(_(b"nothing changed\n"))
2269 return 1
2272 return 1
2270
2273
2271 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2274 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2272
2275
2273 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2276 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2274 status(
2277 status(
2275 ui,
2278 ui,
2276 repo,
2279 repo,
2277 modified=True,
2280 modified=True,
2278 added=True,
2281 added=True,
2279 removed=True,
2282 removed=True,
2280 deleted=True,
2283 deleted=True,
2281 unknown=True,
2284 unknown=True,
2282 subrepos=opts.get('subrepos'),
2285 subrepos=opts.get('subrepos'),
2283 )
2286 )
2284
2287
2285
2288
2286 @command(
2289 @command(
2287 b'config|showconfig|debugconfig',
2290 b'config|showconfig|debugconfig',
2288 [
2291 [
2289 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2292 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2290 # This is experimental because we need
2293 # This is experimental because we need
2291 # * reasonable behavior around aliases,
2294 # * reasonable behavior around aliases,
2292 # * decide if we display [debug] [experimental] and [devel] section par
2295 # * decide if we display [debug] [experimental] and [devel] section par
2293 # default
2296 # default
2294 # * some way to display "generic" config entry (the one matching
2297 # * some way to display "generic" config entry (the one matching
2295 # regexp,
2298 # regexp,
2296 # * proper display of the different value type
2299 # * proper display of the different value type
2297 # * a better way to handle <DYNAMIC> values (and variable types),
2300 # * a better way to handle <DYNAMIC> values (and variable types),
2298 # * maybe some type information ?
2301 # * maybe some type information ?
2299 (
2302 (
2300 b'',
2303 b'',
2301 b'exp-all-known',
2304 b'exp-all-known',
2302 None,
2305 None,
2303 _(b'show all known config option (EXPERIMENTAL)'),
2306 _(b'show all known config option (EXPERIMENTAL)'),
2304 ),
2307 ),
2305 (b'e', b'edit', None, _(b'edit user config')),
2308 (b'e', b'edit', None, _(b'edit user config')),
2306 (b'l', b'local', None, _(b'edit repository config')),
2309 (b'l', b'local', None, _(b'edit repository config')),
2307 (b'', b'source', None, _(b'show source of configuration value')),
2310 (b'', b'source', None, _(b'show source of configuration value')),
2308 (
2311 (
2309 b'',
2312 b'',
2310 b'shared',
2313 b'shared',
2311 None,
2314 None,
2312 _(b'edit shared source repository config (EXPERIMENTAL)'),
2315 _(b'edit shared source repository config (EXPERIMENTAL)'),
2313 ),
2316 ),
2314 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2317 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2315 (b'g', b'global', None, _(b'edit global config')),
2318 (b'g', b'global', None, _(b'edit global config')),
2316 ]
2319 ]
2317 + formatteropts,
2320 + formatteropts,
2318 _(b'[-u] [NAME]...'),
2321 _(b'[-u] [NAME]...'),
2319 helpcategory=command.CATEGORY_HELP,
2322 helpcategory=command.CATEGORY_HELP,
2320 optionalrepo=True,
2323 optionalrepo=True,
2321 intents={INTENT_READONLY},
2324 intents={INTENT_READONLY},
2322 )
2325 )
2323 def config(ui, repo, *values, **opts):
2326 def config(ui, repo, *values, **opts):
2324 """show combined config settings from all hgrc files
2327 """show combined config settings from all hgrc files
2325
2328
2326 With no arguments, print names and values of all config items.
2329 With no arguments, print names and values of all config items.
2327
2330
2328 With one argument of the form section.name, print just the value
2331 With one argument of the form section.name, print just the value
2329 of that config item.
2332 of that config item.
2330
2333
2331 With multiple arguments, print names and values of all config
2334 With multiple arguments, print names and values of all config
2332 items with matching section names or section.names.
2335 items with matching section names or section.names.
2333
2336
2334 With --edit, start an editor on the user-level config file. With
2337 With --edit, start an editor on the user-level config file. With
2335 --global, edit the system-wide config file. With --local, edit the
2338 --global, edit the system-wide config file. With --local, edit the
2336 repository-level config file.
2339 repository-level config file.
2337
2340
2338 With --source, the source (filename and line number) is printed
2341 With --source, the source (filename and line number) is printed
2339 for each config item.
2342 for each config item.
2340
2343
2341 See :hg:`help config` for more information about config files.
2344 See :hg:`help config` for more information about config files.
2342
2345
2343 .. container:: verbose
2346 .. container:: verbose
2344
2347
2345 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2348 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2346 This file is not shared across shares when in share-safe mode.
2349 This file is not shared across shares when in share-safe mode.
2347
2350
2348 Template:
2351 Template:
2349
2352
2350 The following keywords are supported. See also :hg:`help templates`.
2353 The following keywords are supported. See also :hg:`help templates`.
2351
2354
2352 :name: String. Config name.
2355 :name: String. Config name.
2353 :source: String. Filename and line number where the item is defined.
2356 :source: String. Filename and line number where the item is defined.
2354 :value: String. Config value.
2357 :value: String. Config value.
2355
2358
2356 The --shared flag can be used to edit the config file of shared source
2359 The --shared flag can be used to edit the config file of shared source
2357 repository. It only works when you have shared using the experimental
2360 repository. It only works when you have shared using the experimental
2358 share safe feature.
2361 share safe feature.
2359
2362
2360 Returns 0 on success, 1 if NAME does not exist.
2363 Returns 0 on success, 1 if NAME does not exist.
2361
2364
2362 """
2365 """
2363
2366
2364 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2367 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2365 if any(opts.get(o) for o in editopts):
2368 if any(opts.get(o) for o in editopts):
2366 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2369 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2367 if opts.get('local'):
2370 if opts.get('local'):
2368 if not repo:
2371 if not repo:
2369 raise error.InputError(
2372 raise error.InputError(
2370 _(b"can't use --local outside a repository")
2373 _(b"can't use --local outside a repository")
2371 )
2374 )
2372 paths = [repo.vfs.join(b'hgrc')]
2375 paths = [repo.vfs.join(b'hgrc')]
2373 elif opts.get('global'):
2376 elif opts.get('global'):
2374 paths = rcutil.systemrcpath()
2377 paths = rcutil.systemrcpath()
2375 elif opts.get('shared'):
2378 elif opts.get('shared'):
2376 if not repo.shared():
2379 if not repo.shared():
2377 raise error.InputError(
2380 raise error.InputError(
2378 _(b"repository is not shared; can't use --shared")
2381 _(b"repository is not shared; can't use --shared")
2379 )
2382 )
2380 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2383 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2381 raise error.InputError(
2384 raise error.InputError(
2382 _(
2385 _(
2383 b"share safe feature not enabled; "
2386 b"share safe feature not enabled; "
2384 b"unable to edit shared source repository config"
2387 b"unable to edit shared source repository config"
2385 )
2388 )
2386 )
2389 )
2387 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2390 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2388 elif opts.get('non_shared'):
2391 elif opts.get('non_shared'):
2389 paths = [repo.vfs.join(b'hgrc-not-shared')]
2392 paths = [repo.vfs.join(b'hgrc-not-shared')]
2390 else:
2393 else:
2391 paths = rcutil.userrcpath()
2394 paths = rcutil.userrcpath()
2392
2395
2393 for f in paths:
2396 for f in paths:
2394 if os.path.exists(f):
2397 if os.path.exists(f):
2395 break
2398 break
2396 else:
2399 else:
2397 if opts.get('global'):
2400 if opts.get('global'):
2398 samplehgrc = uimod.samplehgrcs[b'global']
2401 samplehgrc = uimod.samplehgrcs[b'global']
2399 elif opts.get('local'):
2402 elif opts.get('local'):
2400 samplehgrc = uimod.samplehgrcs[b'local']
2403 samplehgrc = uimod.samplehgrcs[b'local']
2401 else:
2404 else:
2402 samplehgrc = uimod.samplehgrcs[b'user']
2405 samplehgrc = uimod.samplehgrcs[b'user']
2403
2406
2404 f = paths[0]
2407 f = paths[0]
2405 util.writefile(f, util.tonativeeol(samplehgrc))
2408 util.writefile(f, util.tonativeeol(samplehgrc))
2406
2409
2407 editor = ui.geteditor()
2410 editor = ui.geteditor()
2408 ui.system(
2411 ui.system(
2409 b"%s \"%s\"" % (editor, f),
2412 b"%s \"%s\"" % (editor, f),
2410 onerr=error.InputError,
2413 onerr=error.InputError,
2411 errprefix=_(b"edit failed"),
2414 errprefix=_(b"edit failed"),
2412 blockedtag=b'config_edit',
2415 blockedtag=b'config_edit',
2413 )
2416 )
2414 return
2417 return
2415 ui.pager(b'config')
2418 ui.pager(b'config')
2416 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2419 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2417 for t, f in rcutil.rccomponents():
2420 for t, f in rcutil.rccomponents():
2418 if t == b'path':
2421 if t == b'path':
2419 ui.debug(b'read config from: %s\n' % f)
2422 ui.debug(b'read config from: %s\n' % f)
2420 elif t == b'resource':
2423 elif t == b'resource':
2421 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2424 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2422 elif t == b'items':
2425 elif t == b'items':
2423 # Don't print anything for 'items'.
2426 # Don't print anything for 'items'.
2424 pass
2427 pass
2425 else:
2428 else:
2426 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2429 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2427 untrusted = bool(opts.get('untrusted'))
2430 untrusted = bool(opts.get('untrusted'))
2428
2431
2429 selsections = selentries = []
2432 selsections = selentries = []
2430 if values:
2433 if values:
2431 selsections = [v for v in values if b'.' not in v]
2434 selsections = [v for v in values if b'.' not in v]
2432 selentries = [v for v in values if b'.' in v]
2435 selentries = [v for v in values if b'.' in v]
2433 uniquesel = len(selentries) == 1 and not selsections
2436 uniquesel = len(selentries) == 1 and not selsections
2434 selsections = set(selsections)
2437 selsections = set(selsections)
2435 selentries = set(selentries)
2438 selentries = set(selentries)
2436
2439
2437 matched = False
2440 matched = False
2438 all_known = opts['exp_all_known']
2441 all_known = opts['exp_all_known']
2439 show_source = ui.debugflag or opts.get('source')
2442 show_source = ui.debugflag or opts.get('source')
2440 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2443 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2441 for section, name, value in entries:
2444 for section, name, value in entries:
2442 source = ui.configsource(section, name, untrusted)
2445 source = ui.configsource(section, name, untrusted)
2443 value = pycompat.bytestr(value)
2446 value = pycompat.bytestr(value)
2444 defaultvalue = ui.configdefault(section, name)
2447 defaultvalue = ui.configdefault(section, name)
2445 if fm.isplain():
2448 if fm.isplain():
2446 source = source or b'none'
2449 source = source or b'none'
2447 value = value.replace(b'\n', b'\\n')
2450 value = value.replace(b'\n', b'\\n')
2448 entryname = section + b'.' + name
2451 entryname = section + b'.' + name
2449 if values and not (section in selsections or entryname in selentries):
2452 if values and not (section in selsections or entryname in selentries):
2450 continue
2453 continue
2451 fm.startitem()
2454 fm.startitem()
2452 fm.condwrite(show_source, b'source', b'%s: ', source)
2455 fm.condwrite(show_source, b'source', b'%s: ', source)
2453 if uniquesel:
2456 if uniquesel:
2454 fm.data(name=entryname)
2457 fm.data(name=entryname)
2455 fm.write(b'value', b'%s\n', value)
2458 fm.write(b'value', b'%s\n', value)
2456 else:
2459 else:
2457 fm.write(b'name value', b'%s=%s\n', entryname, value)
2460 fm.write(b'name value', b'%s=%s\n', entryname, value)
2458 if formatter.isprintable(defaultvalue):
2461 if formatter.isprintable(defaultvalue):
2459 fm.data(defaultvalue=defaultvalue)
2462 fm.data(defaultvalue=defaultvalue)
2460 elif isinstance(defaultvalue, list) and all(
2463 elif isinstance(defaultvalue, list) and all(
2461 formatter.isprintable(e) for e in defaultvalue
2464 formatter.isprintable(e) for e in defaultvalue
2462 ):
2465 ):
2463 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2466 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2464 # TODO: no idea how to process unsupported defaultvalue types
2467 # TODO: no idea how to process unsupported defaultvalue types
2465 matched = True
2468 matched = True
2466 fm.end()
2469 fm.end()
2467 if matched:
2470 if matched:
2468 return 0
2471 return 0
2469 return 1
2472 return 1
2470
2473
2471
2474
2472 @command(
2475 @command(
2473 b'continue',
2476 b'continue',
2474 dryrunopts,
2477 dryrunopts,
2475 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2478 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2476 helpbasic=True,
2479 helpbasic=True,
2477 )
2480 )
2478 def continuecmd(ui, repo, **opts):
2481 def continuecmd(ui, repo, **opts):
2479 """resumes an interrupted operation (EXPERIMENTAL)
2482 """resumes an interrupted operation (EXPERIMENTAL)
2480
2483
2481 Finishes a multistep operation like graft, histedit, rebase, merge,
2484 Finishes a multistep operation like graft, histedit, rebase, merge,
2482 and unshelve if they are in an interrupted state.
2485 and unshelve if they are in an interrupted state.
2483
2486
2484 use --dry-run/-n to dry run the command.
2487 use --dry-run/-n to dry run the command.
2485 """
2488 """
2486 dryrun = opts.get('dry_run')
2489 dryrun = opts.get('dry_run')
2487 contstate = cmdutil.getunfinishedstate(repo)
2490 contstate = cmdutil.getunfinishedstate(repo)
2488 if not contstate:
2491 if not contstate:
2489 raise error.StateError(_(b'no operation in progress'))
2492 raise error.StateError(_(b'no operation in progress'))
2490 if not contstate.continuefunc:
2493 if not contstate.continuefunc:
2491 raise error.StateError(
2494 raise error.StateError(
2492 (
2495 (
2493 _(b"%s in progress but does not support 'hg continue'")
2496 _(b"%s in progress but does not support 'hg continue'")
2494 % (contstate._opname)
2497 % (contstate._opname)
2495 ),
2498 ),
2496 hint=contstate.continuemsg(),
2499 hint=contstate.continuemsg(),
2497 )
2500 )
2498 if dryrun:
2501 if dryrun:
2499 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2502 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2500 return
2503 return
2501 return contstate.continuefunc(ui, repo)
2504 return contstate.continuefunc(ui, repo)
2502
2505
2503
2506
2504 @command(
2507 @command(
2505 b'copy|cp',
2508 b'copy|cp',
2506 [
2509 [
2507 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2510 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2508 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2511 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2509 (
2512 (
2510 b'',
2513 b'',
2511 b'at-rev',
2514 b'at-rev',
2512 b'',
2515 b'',
2513 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2516 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2514 _(b'REV'),
2517 _(b'REV'),
2515 ),
2518 ),
2516 (
2519 (
2517 b'f',
2520 b'f',
2518 b'force',
2521 b'force',
2519 None,
2522 None,
2520 _(b'forcibly copy over an existing managed file'),
2523 _(b'forcibly copy over an existing managed file'),
2521 ),
2524 ),
2522 ]
2525 ]
2523 + walkopts
2526 + walkopts
2524 + dryrunopts,
2527 + dryrunopts,
2525 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2528 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2526 helpcategory=command.CATEGORY_FILE_CONTENTS,
2529 helpcategory=command.CATEGORY_FILE_CONTENTS,
2527 )
2530 )
2528 def copy(ui, repo, *pats, **opts):
2531 def copy(ui, repo, *pats, **opts):
2529 """mark files as copied for the next commit
2532 """mark files as copied for the next commit
2530
2533
2531 Mark dest as having copies of source files. If dest is a
2534 Mark dest as having copies of source files. If dest is a
2532 directory, copies are put in that directory. If dest is a file,
2535 directory, copies are put in that directory. If dest is a file,
2533 the source must be a single file.
2536 the source must be a single file.
2534
2537
2535 By default, this command copies the contents of files as they
2538 By default, this command copies the contents of files as they
2536 exist in the working directory. If invoked with -A/--after, the
2539 exist in the working directory. If invoked with -A/--after, the
2537 operation is recorded, but no copying is performed.
2540 operation is recorded, but no copying is performed.
2538
2541
2539 To undo marking a destination file as copied, use --forget. With that
2542 To undo marking a destination file as copied, use --forget. With that
2540 option, all given (positional) arguments are unmarked as copies. The
2543 option, all given (positional) arguments are unmarked as copies. The
2541 destination file(s) will be left in place (still tracked). Note that
2544 destination file(s) will be left in place (still tracked). Note that
2542 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2545 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2543
2546
2544 This command takes effect with the next commit by default.
2547 This command takes effect with the next commit by default.
2545
2548
2546 Returns 0 on success, 1 if errors are encountered.
2549 Returns 0 on success, 1 if errors are encountered.
2547 """
2550 """
2548
2551
2549 context = lambda repo: repo.dirstate.changing_files(repo)
2552 context = lambda repo: repo.dirstate.changing_files(repo)
2550 rev = opts.get('at_rev')
2553 rev = opts.get('at_rev')
2551
2554
2552 if rev:
2555 if rev:
2553 ctx = logcmdutil.revsingle(repo, rev)
2556 ctx = logcmdutil.revsingle(repo, rev)
2554 if ctx.rev() is not None:
2557 if ctx.rev() is not None:
2555
2558
2556 def context(repo):
2559 def context(repo):
2557 return util.nullcontextmanager()
2560 return util.nullcontextmanager()
2558
2561
2559 opts['at_rev'] = ctx.rev()
2562 opts['at_rev'] = ctx.rev()
2560 with repo.wlock(), context(repo):
2563 with repo.wlock(), context(repo):
2561 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2564 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2562
2565
2563
2566
2564 @command(
2567 @command(
2565 b'debugcommands',
2568 b'debugcommands',
2566 [],
2569 [],
2567 _(b'[COMMAND]'),
2570 _(b'[COMMAND]'),
2568 helpcategory=command.CATEGORY_HELP,
2571 helpcategory=command.CATEGORY_HELP,
2569 norepo=True,
2572 norepo=True,
2570 )
2573 )
2571 def debugcommands(ui, cmd=b'', *args):
2574 def debugcommands(ui, cmd=b'', *args):
2572 """list all available commands and options"""
2575 """list all available commands and options"""
2573 for cmd, vals in sorted(table.items()):
2576 for cmd, vals in sorted(table.items()):
2574 cmd = cmd.split(b'|')[0]
2577 cmd = cmd.split(b'|')[0]
2575 opts = b', '.join([i[1] for i in vals[1]])
2578 opts = b', '.join([i[1] for i in vals[1]])
2576 ui.write(b'%s: %s\n' % (cmd, opts))
2579 ui.write(b'%s: %s\n' % (cmd, opts))
2577
2580
2578
2581
2579 @command(
2582 @command(
2580 b'debugcomplete',
2583 b'debugcomplete',
2581 [(b'o', b'options', None, _(b'show the command options'))],
2584 [(b'o', b'options', None, _(b'show the command options'))],
2582 _(b'[-o] CMD'),
2585 _(b'[-o] CMD'),
2583 helpcategory=command.CATEGORY_HELP,
2586 helpcategory=command.CATEGORY_HELP,
2584 norepo=True,
2587 norepo=True,
2585 )
2588 )
2586 def debugcomplete(ui, cmd=b'', **opts):
2589 def debugcomplete(ui, cmd=b'', **opts):
2587 """returns the completion list associated with the given command"""
2590 """returns the completion list associated with the given command"""
2588
2591
2589 if opts.get('options'):
2592 if opts.get('options'):
2590 options = []
2593 options = []
2591 otables = [globalopts]
2594 otables = [globalopts]
2592 if cmd:
2595 if cmd:
2593 aliases, entry = cmdutil.findcmd(cmd, table, False)
2596 aliases, entry = cmdutil.findcmd(cmd, table, False)
2594 otables.append(entry[1])
2597 otables.append(entry[1])
2595 for t in otables:
2598 for t in otables:
2596 for o in t:
2599 for o in t:
2597 if b"(DEPRECATED)" in o[3]:
2600 if b"(DEPRECATED)" in o[3]:
2598 continue
2601 continue
2599 if o[0]:
2602 if o[0]:
2600 options.append(b'-%s' % o[0])
2603 options.append(b'-%s' % o[0])
2601 options.append(b'--%s' % o[1])
2604 options.append(b'--%s' % o[1])
2602 ui.write(b"%s\n" % b"\n".join(options))
2605 ui.write(b"%s\n" % b"\n".join(options))
2603 return
2606 return
2604
2607
2605 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2608 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2606 if ui.verbose:
2609 if ui.verbose:
2607 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2610 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2608 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2611 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2609
2612
2610
2613
2611 @command(
2614 @command(
2612 b'diff',
2615 b'diff',
2613 [
2616 [
2614 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2617 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2615 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2618 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2616 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2619 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2617 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2620 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2618 ]
2621 ]
2619 + diffopts
2622 + diffopts
2620 + diffopts2
2623 + diffopts2
2621 + walkopts
2624 + walkopts
2622 + subrepoopts,
2625 + subrepoopts,
2623 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2626 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2624 helpcategory=command.CATEGORY_FILE_CONTENTS,
2627 helpcategory=command.CATEGORY_FILE_CONTENTS,
2625 helpbasic=True,
2628 helpbasic=True,
2626 inferrepo=True,
2629 inferrepo=True,
2627 intents={INTENT_READONLY},
2630 intents={INTENT_READONLY},
2628 )
2631 )
2629 def diff(ui, repo, *pats, **opts):
2632 def diff(ui, repo, *pats, **opts):
2630 """diff repository (or selected files)
2633 """diff repository (or selected files)
2631
2634
2632 Show differences between revisions for the specified files.
2635 Show differences between revisions for the specified files.
2633
2636
2634 Differences between files are shown using the unified diff format.
2637 Differences between files are shown using the unified diff format.
2635
2638
2636 .. note::
2639 .. note::
2637
2640
2638 :hg:`diff` may generate unexpected results for merges, as it will
2641 :hg:`diff` may generate unexpected results for merges, as it will
2639 default to comparing against the working directory's first
2642 default to comparing against the working directory's first
2640 parent changeset if no revisions are specified. To diff against the
2643 parent changeset if no revisions are specified. To diff against the
2641 conflict regions, you can use `--config diff.merge=yes`.
2644 conflict regions, you can use `--config diff.merge=yes`.
2642
2645
2643 By default, the working directory files are compared to its first parent. To
2646 By default, the working directory files are compared to its first parent. To
2644 see the differences from another revision, use --from. To see the difference
2647 see the differences from another revision, use --from. To see the difference
2645 to another revision, use --to. For example, :hg:`diff --from .^` will show
2648 to another revision, use --to. For example, :hg:`diff --from .^` will show
2646 the differences from the working copy's grandparent to the working copy,
2649 the differences from the working copy's grandparent to the working copy,
2647 :hg:`diff --to .` will show the diff from the working copy to its parent
2650 :hg:`diff --to .` will show the diff from the working copy to its parent
2648 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2651 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2649 show the diff between those two revisions.
2652 show the diff between those two revisions.
2650
2653
2651 Alternatively you can specify -c/--change with a revision to see the changes
2654 Alternatively you can specify -c/--change with a revision to see the changes
2652 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2655 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2653 equivalent to :hg:`diff --from 42^ --to 42`)
2656 equivalent to :hg:`diff --from 42^ --to 42`)
2654
2657
2655 Without the -a/--text option, diff will avoid generating diffs of
2658 Without the -a/--text option, diff will avoid generating diffs of
2656 files it detects as binary. With -a, diff will generate a diff
2659 files it detects as binary. With -a, diff will generate a diff
2657 anyway, probably with undesirable results.
2660 anyway, probably with undesirable results.
2658
2661
2659 Use the -g/--git option to generate diffs in the git extended diff
2662 Use the -g/--git option to generate diffs in the git extended diff
2660 format. For more information, read :hg:`help diffs`.
2663 format. For more information, read :hg:`help diffs`.
2661
2664
2662 .. container:: verbose
2665 .. container:: verbose
2663
2666
2664 Examples:
2667 Examples:
2665
2668
2666 - compare a file in the current working directory to its parent::
2669 - compare a file in the current working directory to its parent::
2667
2670
2668 hg diff foo.c
2671 hg diff foo.c
2669
2672
2670 - compare two historical versions of a directory, with rename info::
2673 - compare two historical versions of a directory, with rename info::
2671
2674
2672 hg diff --git --from 1.0 --to 1.2 lib/
2675 hg diff --git --from 1.0 --to 1.2 lib/
2673
2676
2674 - get change stats relative to the last change on some date::
2677 - get change stats relative to the last change on some date::
2675
2678
2676 hg diff --stat --from "date('may 2')"
2679 hg diff --stat --from "date('may 2')"
2677
2680
2678 - diff all newly-added files that contain a keyword::
2681 - diff all newly-added files that contain a keyword::
2679
2682
2680 hg diff "set:added() and grep(GNU)"
2683 hg diff "set:added() and grep(GNU)"
2681
2684
2682 - compare a revision and its parents::
2685 - compare a revision and its parents::
2683
2686
2684 hg diff -c 9353 # compare against first parent
2687 hg diff -c 9353 # compare against first parent
2685 hg diff --from 9353^ --to 9353 # same using revset syntax
2688 hg diff --from 9353^ --to 9353 # same using revset syntax
2686 hg diff --from 9353^2 --to 9353 # compare against the second parent
2689 hg diff --from 9353^2 --to 9353 # compare against the second parent
2687
2690
2688 Returns 0 on success.
2691 Returns 0 on success.
2689 """
2692 """
2690
2693
2691 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2694 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2692 opts = pycompat.byteskwargs(opts)
2695 opts = pycompat.byteskwargs(opts)
2693 revs = opts.get(b'rev')
2696 revs = opts.get(b'rev')
2694 change = opts.get(b'change')
2697 change = opts.get(b'change')
2695 from_rev = opts.get(b'from')
2698 from_rev = opts.get(b'from')
2696 to_rev = opts.get(b'to')
2699 to_rev = opts.get(b'to')
2697 stat = opts.get(b'stat')
2700 stat = opts.get(b'stat')
2698 reverse = opts.get(b'reverse')
2701 reverse = opts.get(b'reverse')
2699
2702
2700 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2703 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2701 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2704 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2702 if change:
2705 if change:
2703 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2706 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2704 ctx2 = logcmdutil.revsingle(repo, change, None)
2707 ctx2 = logcmdutil.revsingle(repo, change, None)
2705 ctx1 = diffutil.diff_parent(ctx2)
2708 ctx1 = diffutil.diff_parent(ctx2)
2706 elif from_rev or to_rev:
2709 elif from_rev or to_rev:
2707 repo = scmutil.unhidehashlikerevs(
2710 repo = scmutil.unhidehashlikerevs(
2708 repo, [from_rev] + [to_rev], b'nowarn'
2711 repo, [from_rev] + [to_rev], b'nowarn'
2709 )
2712 )
2710 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2713 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2711 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2714 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2712 else:
2715 else:
2713 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2716 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2714 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2717 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2715
2718
2716 if reverse:
2719 if reverse:
2717 ctxleft = ctx2
2720 ctxleft = ctx2
2718 ctxright = ctx1
2721 ctxright = ctx1
2719 else:
2722 else:
2720 ctxleft = ctx1
2723 ctxleft = ctx1
2721 ctxright = ctx2
2724 ctxright = ctx2
2722
2725
2723 diffopts = patch.diffallopts(ui, opts)
2726 diffopts = patch.diffallopts(ui, opts)
2724 m = scmutil.match(ctx2, pats, opts)
2727 m = scmutil.match(ctx2, pats, opts)
2725 m = repo.narrowmatch(m)
2728 m = repo.narrowmatch(m)
2726 ui.pager(b'diff')
2729 ui.pager(b'diff')
2727 logcmdutil.diffordiffstat(
2730 logcmdutil.diffordiffstat(
2728 ui,
2731 ui,
2729 repo,
2732 repo,
2730 diffopts,
2733 diffopts,
2731 ctxleft,
2734 ctxleft,
2732 ctxright,
2735 ctxright,
2733 m,
2736 m,
2734 stat=stat,
2737 stat=stat,
2735 listsubrepos=opts.get(b'subrepos'),
2738 listsubrepos=opts.get(b'subrepos'),
2736 root=opts.get(b'root'),
2739 root=opts.get(b'root'),
2737 )
2740 )
2738
2741
2739
2742
2740 @command(
2743 @command(
2741 b'export',
2744 b'export',
2742 [
2745 [
2743 (
2746 (
2744 b'B',
2747 b'B',
2745 b'bookmark',
2748 b'bookmark',
2746 b'',
2749 b'',
2747 _(b'export changes only reachable by given bookmark'),
2750 _(b'export changes only reachable by given bookmark'),
2748 _(b'BOOKMARK'),
2751 _(b'BOOKMARK'),
2749 ),
2752 ),
2750 (
2753 (
2751 b'o',
2754 b'o',
2752 b'output',
2755 b'output',
2753 b'',
2756 b'',
2754 _(b'print output to file with formatted name'),
2757 _(b'print output to file with formatted name'),
2755 _(b'FORMAT'),
2758 _(b'FORMAT'),
2756 ),
2759 ),
2757 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2760 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2758 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2761 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2759 ]
2762 ]
2760 + diffopts
2763 + diffopts
2761 + formatteropts,
2764 + formatteropts,
2762 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2765 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2763 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2766 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2764 helpbasic=True,
2767 helpbasic=True,
2765 intents={INTENT_READONLY},
2768 intents={INTENT_READONLY},
2766 )
2769 )
2767 def export(ui, repo, *changesets, **opts):
2770 def export(ui, repo, *changesets, **opts):
2768 """dump the header and diffs for one or more changesets
2771 """dump the header and diffs for one or more changesets
2769
2772
2770 Print the changeset header and diffs for one or more revisions.
2773 Print the changeset header and diffs for one or more revisions.
2771 If no revision is given, the parent of the working directory is used.
2774 If no revision is given, the parent of the working directory is used.
2772
2775
2773 The information shown in the changeset header is: author, date,
2776 The information shown in the changeset header is: author, date,
2774 branch name (if non-default), changeset hash, parent(s) and commit
2777 branch name (if non-default), changeset hash, parent(s) and commit
2775 comment.
2778 comment.
2776
2779
2777 .. note::
2780 .. note::
2778
2781
2779 :hg:`export` may generate unexpected diff output for merge
2782 :hg:`export` may generate unexpected diff output for merge
2780 changesets, as it will compare the merge changeset against its
2783 changesets, as it will compare the merge changeset against its
2781 first parent only.
2784 first parent only.
2782
2785
2783 Output may be to a file, in which case the name of the file is
2786 Output may be to a file, in which case the name of the file is
2784 given using a template string. See :hg:`help templates`. In addition
2787 given using a template string. See :hg:`help templates`. In addition
2785 to the common template keywords, the following formatting rules are
2788 to the common template keywords, the following formatting rules are
2786 supported:
2789 supported:
2787
2790
2788 :``%%``: literal "%" character
2791 :``%%``: literal "%" character
2789 :``%H``: changeset hash (40 hexadecimal digits)
2792 :``%H``: changeset hash (40 hexadecimal digits)
2790 :``%N``: number of patches being generated
2793 :``%N``: number of patches being generated
2791 :``%R``: changeset revision number
2794 :``%R``: changeset revision number
2792 :``%b``: basename of the exporting repository
2795 :``%b``: basename of the exporting repository
2793 :``%h``: short-form changeset hash (12 hexadecimal digits)
2796 :``%h``: short-form changeset hash (12 hexadecimal digits)
2794 :``%m``: first line of the commit message (only alphanumeric characters)
2797 :``%m``: first line of the commit message (only alphanumeric characters)
2795 :``%n``: zero-padded sequence number, starting at 1
2798 :``%n``: zero-padded sequence number, starting at 1
2796 :``%r``: zero-padded changeset revision number
2799 :``%r``: zero-padded changeset revision number
2797 :``\\``: literal "\\" character
2800 :``\\``: literal "\\" character
2798
2801
2799 Without the -a/--text option, export will avoid generating diffs
2802 Without the -a/--text option, export will avoid generating diffs
2800 of files it detects as binary. With -a, export will generate a
2803 of files it detects as binary. With -a, export will generate a
2801 diff anyway, probably with undesirable results.
2804 diff anyway, probably with undesirable results.
2802
2805
2803 With -B/--bookmark changesets reachable by the given bookmark are
2806 With -B/--bookmark changesets reachable by the given bookmark are
2804 selected.
2807 selected.
2805
2808
2806 Use the -g/--git option to generate diffs in the git extended diff
2809 Use the -g/--git option to generate diffs in the git extended diff
2807 format. See :hg:`help diffs` for more information.
2810 format. See :hg:`help diffs` for more information.
2808
2811
2809 With the --switch-parent option, the diff will be against the
2812 With the --switch-parent option, the diff will be against the
2810 second parent. It can be useful to review a merge.
2813 second parent. It can be useful to review a merge.
2811
2814
2812 .. container:: verbose
2815 .. container:: verbose
2813
2816
2814 Template:
2817 Template:
2815
2818
2816 The following keywords are supported in addition to the common template
2819 The following keywords are supported in addition to the common template
2817 keywords and functions. See also :hg:`help templates`.
2820 keywords and functions. See also :hg:`help templates`.
2818
2821
2819 :diff: String. Diff content.
2822 :diff: String. Diff content.
2820 :parents: List of strings. Parent nodes of the changeset.
2823 :parents: List of strings. Parent nodes of the changeset.
2821
2824
2822 Examples:
2825 Examples:
2823
2826
2824 - use export and import to transplant a bugfix to the current
2827 - use export and import to transplant a bugfix to the current
2825 branch::
2828 branch::
2826
2829
2827 hg export -r 9353 | hg import -
2830 hg export -r 9353 | hg import -
2828
2831
2829 - export all the changesets between two revisions to a file with
2832 - export all the changesets between two revisions to a file with
2830 rename information::
2833 rename information::
2831
2834
2832 hg export --git -r 123:150 > changes.txt
2835 hg export --git -r 123:150 > changes.txt
2833
2836
2834 - split outgoing changes into a series of patches with
2837 - split outgoing changes into a series of patches with
2835 descriptive names::
2838 descriptive names::
2836
2839
2837 hg export -r "outgoing()" -o "%n-%m.patch"
2840 hg export -r "outgoing()" -o "%n-%m.patch"
2838
2841
2839 Returns 0 on success.
2842 Returns 0 on success.
2840 """
2843 """
2841 opts = pycompat.byteskwargs(opts)
2844 opts = pycompat.byteskwargs(opts)
2842 bookmark = opts.get(b'bookmark')
2845 bookmark = opts.get(b'bookmark')
2843 changesets += tuple(opts.get(b'rev', []))
2846 changesets += tuple(opts.get(b'rev', []))
2844
2847
2845 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2848 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2846
2849
2847 if bookmark:
2850 if bookmark:
2848 if bookmark not in repo._bookmarks:
2851 if bookmark not in repo._bookmarks:
2849 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2852 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2850
2853
2851 revs = scmutil.bookmarkrevs(repo, bookmark)
2854 revs = scmutil.bookmarkrevs(repo, bookmark)
2852 else:
2855 else:
2853 if not changesets:
2856 if not changesets:
2854 changesets = [b'.']
2857 changesets = [b'.']
2855
2858
2856 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2859 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2857 revs = logcmdutil.revrange(repo, changesets)
2860 revs = logcmdutil.revrange(repo, changesets)
2858
2861
2859 if not revs:
2862 if not revs:
2860 raise error.InputError(_(b"export requires at least one changeset"))
2863 raise error.InputError(_(b"export requires at least one changeset"))
2861 if len(revs) > 1:
2864 if len(revs) > 1:
2862 ui.note(_(b'exporting patches:\n'))
2865 ui.note(_(b'exporting patches:\n'))
2863 else:
2866 else:
2864 ui.note(_(b'exporting patch:\n'))
2867 ui.note(_(b'exporting patch:\n'))
2865
2868
2866 fntemplate = opts.get(b'output')
2869 fntemplate = opts.get(b'output')
2867 if cmdutil.isstdiofilename(fntemplate):
2870 if cmdutil.isstdiofilename(fntemplate):
2868 fntemplate = b''
2871 fntemplate = b''
2869
2872
2870 if fntemplate:
2873 if fntemplate:
2871 fm = formatter.nullformatter(ui, b'export', opts)
2874 fm = formatter.nullformatter(ui, b'export', opts)
2872 else:
2875 else:
2873 ui.pager(b'export')
2876 ui.pager(b'export')
2874 fm = ui.formatter(b'export', opts)
2877 fm = ui.formatter(b'export', opts)
2875 with fm:
2878 with fm:
2876 cmdutil.export(
2879 cmdutil.export(
2877 repo,
2880 repo,
2878 revs,
2881 revs,
2879 fm,
2882 fm,
2880 fntemplate=fntemplate,
2883 fntemplate=fntemplate,
2881 switch_parent=opts.get(b'switch_parent'),
2884 switch_parent=opts.get(b'switch_parent'),
2882 opts=patch.diffallopts(ui, opts),
2885 opts=patch.diffallopts(ui, opts),
2883 )
2886 )
2884
2887
2885
2888
2886 @command(
2889 @command(
2887 b'files',
2890 b'files',
2888 [
2891 [
2889 (
2892 (
2890 b'r',
2893 b'r',
2891 b'rev',
2894 b'rev',
2892 b'',
2895 b'',
2893 _(b'search the repository as it is in REV'),
2896 _(b'search the repository as it is in REV'),
2894 _(b'REV'),
2897 _(b'REV'),
2895 ),
2898 ),
2896 (
2899 (
2897 b'0',
2900 b'0',
2898 b'print0',
2901 b'print0',
2899 None,
2902 None,
2900 _(b'end filenames with NUL, for use with xargs'),
2903 _(b'end filenames with NUL, for use with xargs'),
2901 ),
2904 ),
2902 ]
2905 ]
2903 + walkopts
2906 + walkopts
2904 + formatteropts
2907 + formatteropts
2905 + subrepoopts,
2908 + subrepoopts,
2906 _(b'[OPTION]... [FILE]...'),
2909 _(b'[OPTION]... [FILE]...'),
2907 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2910 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2908 intents={INTENT_READONLY},
2911 intents={INTENT_READONLY},
2909 )
2912 )
2910 def files(ui, repo, *pats, **opts):
2913 def files(ui, repo, *pats, **opts):
2911 """list tracked files
2914 """list tracked files
2912
2915
2913 Print files under Mercurial control in the working directory or
2916 Print files under Mercurial control in the working directory or
2914 specified revision for given files (excluding removed files).
2917 specified revision for given files (excluding removed files).
2915 Files can be specified as filenames or filesets.
2918 Files can be specified as filenames or filesets.
2916
2919
2917 If no files are given to match, this command prints the names
2920 If no files are given to match, this command prints the names
2918 of all files under Mercurial control.
2921 of all files under Mercurial control.
2919
2922
2920 .. container:: verbose
2923 .. container:: verbose
2921
2924
2922 Template:
2925 Template:
2923
2926
2924 The following keywords are supported in addition to the common template
2927 The following keywords are supported in addition to the common template
2925 keywords and functions. See also :hg:`help templates`.
2928 keywords and functions. See also :hg:`help templates`.
2926
2929
2927 :flags: String. Character denoting file's symlink and executable bits.
2930 :flags: String. Character denoting file's symlink and executable bits.
2928 :path: String. Repository-absolute path of the file.
2931 :path: String. Repository-absolute path of the file.
2929 :size: Integer. Size of the file in bytes.
2932 :size: Integer. Size of the file in bytes.
2930
2933
2931 Examples:
2934 Examples:
2932
2935
2933 - list all files under the current directory::
2936 - list all files under the current directory::
2934
2937
2935 hg files .
2938 hg files .
2936
2939
2937 - shows sizes and flags for current revision::
2940 - shows sizes and flags for current revision::
2938
2941
2939 hg files -vr .
2942 hg files -vr .
2940
2943
2941 - list all files named README::
2944 - list all files named README::
2942
2945
2943 hg files -I "**/README"
2946 hg files -I "**/README"
2944
2947
2945 - list all binary files::
2948 - list all binary files::
2946
2949
2947 hg files "set:binary()"
2950 hg files "set:binary()"
2948
2951
2949 - find files containing a regular expression::
2952 - find files containing a regular expression::
2950
2953
2951 hg files "set:grep('bob')"
2954 hg files "set:grep('bob')"
2952
2955
2953 - search tracked file contents with xargs and grep::
2956 - search tracked file contents with xargs and grep::
2954
2957
2955 hg files -0 | xargs -0 grep foo
2958 hg files -0 | xargs -0 grep foo
2956
2959
2957 See :hg:`help patterns` and :hg:`help filesets` for more information
2960 See :hg:`help patterns` and :hg:`help filesets` for more information
2958 on specifying file patterns.
2961 on specifying file patterns.
2959
2962
2960 Returns 0 if a match is found, 1 otherwise.
2963 Returns 0 if a match is found, 1 otherwise.
2961
2964
2962 """
2965 """
2963
2966
2964 opts = pycompat.byteskwargs(opts)
2967 opts = pycompat.byteskwargs(opts)
2965 rev = opts.get(b'rev')
2968 rev = opts.get(b'rev')
2966 if rev:
2969 if rev:
2967 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2970 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2968 ctx = logcmdutil.revsingle(repo, rev, None)
2971 ctx = logcmdutil.revsingle(repo, rev, None)
2969
2972
2970 end = b'\n'
2973 end = b'\n'
2971 if opts.get(b'print0'):
2974 if opts.get(b'print0'):
2972 end = b'\0'
2975 end = b'\0'
2973 fmt = b'%s' + end
2976 fmt = b'%s' + end
2974
2977
2975 m = scmutil.match(ctx, pats, opts)
2978 m = scmutil.match(ctx, pats, opts)
2976 ui.pager(b'files')
2979 ui.pager(b'files')
2977 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2980 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2978 with ui.formatter(b'files', opts) as fm:
2981 with ui.formatter(b'files', opts) as fm:
2979 return cmdutil.files(
2982 return cmdutil.files(
2980 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2983 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2981 )
2984 )
2982
2985
2983
2986
2984 @command(
2987 @command(
2985 b'forget',
2988 b'forget',
2986 [
2989 [
2987 (b'i', b'interactive', None, _(b'use interactive mode')),
2990 (b'i', b'interactive', None, _(b'use interactive mode')),
2988 ]
2991 ]
2989 + walkopts
2992 + walkopts
2990 + dryrunopts,
2993 + dryrunopts,
2991 _(b'[OPTION]... FILE...'),
2994 _(b'[OPTION]... FILE...'),
2992 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2995 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2993 helpbasic=True,
2996 helpbasic=True,
2994 inferrepo=True,
2997 inferrepo=True,
2995 )
2998 )
2996 def forget(ui, repo, *pats, **opts):
2999 def forget(ui, repo, *pats, **opts):
2997 """forget the specified files on the next commit
3000 """forget the specified files on the next commit
2998
3001
2999 Mark the specified files so they will no longer be tracked
3002 Mark the specified files so they will no longer be tracked
3000 after the next commit.
3003 after the next commit.
3001
3004
3002 This only removes files from the current branch, not from the
3005 This only removes files from the current branch, not from the
3003 entire project history, and it does not delete them from the
3006 entire project history, and it does not delete them from the
3004 working directory.
3007 working directory.
3005
3008
3006 To delete the file from the working directory, see :hg:`remove`.
3009 To delete the file from the working directory, see :hg:`remove`.
3007
3010
3008 To undo a forget before the next commit, see :hg:`add`.
3011 To undo a forget before the next commit, see :hg:`add`.
3009
3012
3010 .. container:: verbose
3013 .. container:: verbose
3011
3014
3012 Examples:
3015 Examples:
3013
3016
3014 - forget newly-added binary files::
3017 - forget newly-added binary files::
3015
3018
3016 hg forget "set:added() and binary()"
3019 hg forget "set:added() and binary()"
3017
3020
3018 - forget files that would be excluded by .hgignore::
3021 - forget files that would be excluded by .hgignore::
3019
3022
3020 hg forget "set:hgignore()"
3023 hg forget "set:hgignore()"
3021
3024
3022 Returns 0 on success.
3025 Returns 0 on success.
3023 """
3026 """
3024
3027
3025 if not pats:
3028 if not pats:
3026 raise error.InputError(_(b'no files specified'))
3029 raise error.InputError(_(b'no files specified'))
3027
3030
3028 with repo.wlock(), repo.dirstate.changing_files(repo):
3031 with repo.wlock(), repo.dirstate.changing_files(repo):
3029 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3032 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3030 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3033 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3031 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3034 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3032 rejected = cmdutil.forget(
3035 rejected = cmdutil.forget(
3033 ui,
3036 ui,
3034 repo,
3037 repo,
3035 m,
3038 m,
3036 prefix=b"",
3039 prefix=b"",
3037 uipathfn=uipathfn,
3040 uipathfn=uipathfn,
3038 explicitonly=False,
3041 explicitonly=False,
3039 dryrun=dryrun,
3042 dryrun=dryrun,
3040 interactive=interactive,
3043 interactive=interactive,
3041 )[0]
3044 )[0]
3042 return rejected and 1 or 0
3045 return rejected and 1 or 0
3043
3046
3044
3047
3045 @command(
3048 @command(
3046 b'graft',
3049 b'graft',
3047 [
3050 [
3048 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3051 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3049 (
3052 (
3050 b'',
3053 b'',
3051 b'base',
3054 b'base',
3052 b'',
3055 b'',
3053 _(b'base revision when doing the graft merge (ADVANCED)'),
3056 _(b'base revision when doing the graft merge (ADVANCED)'),
3054 _(b'REV'),
3057 _(b'REV'),
3055 ),
3058 ),
3056 (b'c', b'continue', False, _(b'resume interrupted graft')),
3059 (b'c', b'continue', False, _(b'resume interrupted graft')),
3057 (b'', b'stop', False, _(b'stop interrupted graft')),
3060 (b'', b'stop', False, _(b'stop interrupted graft')),
3058 (b'', b'abort', False, _(b'abort interrupted graft')),
3061 (b'', b'abort', False, _(b'abort interrupted graft')),
3059 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3062 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3060 (b'', b'log', None, _(b'append graft info to log message')),
3063 (b'', b'log', None, _(b'append graft info to log message')),
3061 (
3064 (
3062 b'',
3065 b'',
3063 b'no-commit',
3066 b'no-commit',
3064 None,
3067 None,
3065 _(b"don't commit, just apply the changes in working directory"),
3068 _(b"don't commit, just apply the changes in working directory"),
3066 ),
3069 ),
3067 (b'f', b'force', False, _(b'force graft')),
3070 (b'f', b'force', False, _(b'force graft')),
3068 (
3071 (
3069 b'D',
3072 b'D',
3070 b'currentdate',
3073 b'currentdate',
3071 False,
3074 False,
3072 _(b'record the current date as commit date'),
3075 _(b'record the current date as commit date'),
3073 ),
3076 ),
3074 (
3077 (
3075 b'U',
3078 b'U',
3076 b'currentuser',
3079 b'currentuser',
3077 False,
3080 False,
3078 _(b'record the current user as committer'),
3081 _(b'record the current user as committer'),
3079 ),
3082 ),
3080 ]
3083 ]
3081 + commitopts2
3084 + commitopts2
3082 + mergetoolopts
3085 + mergetoolopts
3083 + dryrunopts,
3086 + dryrunopts,
3084 _(b'[OPTION]... [-r REV]... REV...'),
3087 _(b'[OPTION]... [-r REV]... REV...'),
3085 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3088 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3086 )
3089 )
3087 def graft(ui, repo, *revs, **opts):
3090 def graft(ui, repo, *revs, **opts):
3088 """copy changes from other branches onto the current branch
3091 """copy changes from other branches onto the current branch
3089
3092
3090 This command uses Mercurial's merge logic to copy individual
3093 This command uses Mercurial's merge logic to copy individual
3091 changes from other branches without merging branches in the
3094 changes from other branches without merging branches in the
3092 history graph. This is sometimes known as 'backporting' or
3095 history graph. This is sometimes known as 'backporting' or
3093 'cherry-picking'. By default, graft will copy user, date, and
3096 'cherry-picking'. By default, graft will copy user, date, and
3094 description from the source changesets.
3097 description from the source changesets.
3095
3098
3096 Changesets that are ancestors of the current revision, that have
3099 Changesets that are ancestors of the current revision, that have
3097 already been grafted, or that are merges will be skipped.
3100 already been grafted, or that are merges will be skipped.
3098
3101
3099 If --log is specified, log messages will have a comment appended
3102 If --log is specified, log messages will have a comment appended
3100 of the form::
3103 of the form::
3101
3104
3102 (grafted from CHANGESETHASH)
3105 (grafted from CHANGESETHASH)
3103
3106
3104 If --force is specified, revisions will be grafted even if they
3107 If --force is specified, revisions will be grafted even if they
3105 are already ancestors of, or have been grafted to, the destination.
3108 are already ancestors of, or have been grafted to, the destination.
3106 This is useful when the revisions have since been backed out.
3109 This is useful when the revisions have since been backed out.
3107
3110
3108 If a graft merge results in conflicts, the graft process is
3111 If a graft merge results in conflicts, the graft process is
3109 interrupted so that the current merge can be manually resolved.
3112 interrupted so that the current merge can be manually resolved.
3110 Once all conflicts are addressed, the graft process can be
3113 Once all conflicts are addressed, the graft process can be
3111 continued with the -c/--continue option.
3114 continued with the -c/--continue option.
3112
3115
3113 The -c/--continue option reapplies all the earlier options.
3116 The -c/--continue option reapplies all the earlier options.
3114
3117
3115 .. container:: verbose
3118 .. container:: verbose
3116
3119
3117 The --base option exposes more of how graft internally uses merge with a
3120 The --base option exposes more of how graft internally uses merge with a
3118 custom base revision. --base can be used to specify another ancestor than
3121 custom base revision. --base can be used to specify another ancestor than
3119 the first and only parent.
3122 the first and only parent.
3120
3123
3121 The command::
3124 The command::
3122
3125
3123 hg graft -r 345 --base 234
3126 hg graft -r 345 --base 234
3124
3127
3125 is thus pretty much the same as::
3128 is thus pretty much the same as::
3126
3129
3127 hg diff --from 234 --to 345 | hg import
3130 hg diff --from 234 --to 345 | hg import
3128
3131
3129 but using merge to resolve conflicts and track moved files.
3132 but using merge to resolve conflicts and track moved files.
3130
3133
3131 The result of a merge can thus be backported as a single commit by
3134 The result of a merge can thus be backported as a single commit by
3132 specifying one of the merge parents as base, and thus effectively
3135 specifying one of the merge parents as base, and thus effectively
3133 grafting the changes from the other side.
3136 grafting the changes from the other side.
3134
3137
3135 It is also possible to collapse multiple changesets and clean up history
3138 It is also possible to collapse multiple changesets and clean up history
3136 by specifying another ancestor as base, much like rebase --collapse
3139 by specifying another ancestor as base, much like rebase --collapse
3137 --keep.
3140 --keep.
3138
3141
3139 The commit message can be tweaked after the fact using commit --amend .
3142 The commit message can be tweaked after the fact using commit --amend .
3140
3143
3141 For using non-ancestors as the base to backout changes, see the backout
3144 For using non-ancestors as the base to backout changes, see the backout
3142 command and the hidden --parent option.
3145 command and the hidden --parent option.
3143
3146
3144 .. container:: verbose
3147 .. container:: verbose
3145
3148
3146 Examples:
3149 Examples:
3147
3150
3148 - copy a single change to the stable branch and edit its description::
3151 - copy a single change to the stable branch and edit its description::
3149
3152
3150 hg update stable
3153 hg update stable
3151 hg graft --edit 9393
3154 hg graft --edit 9393
3152
3155
3153 - graft a range of changesets with one exception, updating dates::
3156 - graft a range of changesets with one exception, updating dates::
3154
3157
3155 hg graft -D "2085::2093 and not 2091"
3158 hg graft -D "2085::2093 and not 2091"
3156
3159
3157 - continue a graft after resolving conflicts::
3160 - continue a graft after resolving conflicts::
3158
3161
3159 hg graft -c
3162 hg graft -c
3160
3163
3161 - show the source of a grafted changeset::
3164 - show the source of a grafted changeset::
3162
3165
3163 hg log --debug -r .
3166 hg log --debug -r .
3164
3167
3165 - show revisions sorted by date::
3168 - show revisions sorted by date::
3166
3169
3167 hg log -r "sort(all(), date)"
3170 hg log -r "sort(all(), date)"
3168
3171
3169 - backport the result of a merge as a single commit::
3172 - backport the result of a merge as a single commit::
3170
3173
3171 hg graft -r 123 --base 123^
3174 hg graft -r 123 --base 123^
3172
3175
3173 - land a feature branch as one changeset::
3176 - land a feature branch as one changeset::
3174
3177
3175 hg up -cr default
3178 hg up -cr default
3176 hg graft -r featureX --base "ancestor('featureX', 'default')"
3179 hg graft -r featureX --base "ancestor('featureX', 'default')"
3177
3180
3178 See :hg:`help revisions` for more about specifying revisions.
3181 See :hg:`help revisions` for more about specifying revisions.
3179
3182
3180 Returns 0 on successful completion, 1 if there are unresolved files.
3183 Returns 0 on successful completion, 1 if there are unresolved files.
3181 """
3184 """
3182 with repo.wlock():
3185 with repo.wlock():
3183 return _dograft(ui, repo, *revs, **opts)
3186 return _dograft(ui, repo, *revs, **opts)
3184
3187
3185
3188
3186 def _dograft(ui, repo, *revs, **opts):
3189 def _dograft(ui, repo, *revs, **opts):
3187 if revs and opts.get('rev'):
3190 if revs and opts.get('rev'):
3188 ui.warn(
3191 ui.warn(
3189 _(
3192 _(
3190 b'warning: inconsistent use of --rev might give unexpected '
3193 b'warning: inconsistent use of --rev might give unexpected '
3191 b'revision ordering!\n'
3194 b'revision ordering!\n'
3192 )
3195 )
3193 )
3196 )
3194
3197
3195 revs = list(revs)
3198 revs = list(revs)
3196 revs.extend(opts.get('rev'))
3199 revs.extend(opts.get('rev'))
3197 # a dict of data to be stored in state file
3200 # a dict of data to be stored in state file
3198 statedata = {}
3201 statedata = {}
3199 # list of new nodes created by ongoing graft
3202 # list of new nodes created by ongoing graft
3200 statedata[b'newnodes'] = []
3203 statedata[b'newnodes'] = []
3201
3204
3202 cmdutil.resolve_commit_options(ui, opts)
3205 cmdutil.resolve_commit_options(ui, opts)
3203
3206
3204 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3207 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3205
3208
3206 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3209 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3207
3210
3208 cont = False
3211 cont = False
3209 if opts.get('no_commit'):
3212 if opts.get('no_commit'):
3210 cmdutil.check_incompatible_arguments(
3213 cmdutil.check_incompatible_arguments(
3211 opts,
3214 opts,
3212 'no_commit',
3215 'no_commit',
3213 ['edit', 'currentuser', 'currentdate', 'log'],
3216 ['edit', 'currentuser', 'currentdate', 'log'],
3214 )
3217 )
3215
3218
3216 graftstate = statemod.cmdstate(repo, b'graftstate')
3219 graftstate = statemod.cmdstate(repo, b'graftstate')
3217
3220
3218 if opts.get('stop'):
3221 if opts.get('stop'):
3219 cmdutil.check_incompatible_arguments(
3222 cmdutil.check_incompatible_arguments(
3220 opts,
3223 opts,
3221 'stop',
3224 'stop',
3222 [
3225 [
3223 'edit',
3226 'edit',
3224 'log',
3227 'log',
3225 'user',
3228 'user',
3226 'date',
3229 'date',
3227 'currentdate',
3230 'currentdate',
3228 'currentuser',
3231 'currentuser',
3229 'rev',
3232 'rev',
3230 ],
3233 ],
3231 )
3234 )
3232 return _stopgraft(ui, repo, graftstate)
3235 return _stopgraft(ui, repo, graftstate)
3233 elif opts.get('abort'):
3236 elif opts.get('abort'):
3234 cmdutil.check_incompatible_arguments(
3237 cmdutil.check_incompatible_arguments(
3235 opts,
3238 opts,
3236 'abort',
3239 'abort',
3237 [
3240 [
3238 'edit',
3241 'edit',
3239 'log',
3242 'log',
3240 'user',
3243 'user',
3241 'date',
3244 'date',
3242 'currentdate',
3245 'currentdate',
3243 'currentuser',
3246 'currentuser',
3244 'rev',
3247 'rev',
3245 ],
3248 ],
3246 )
3249 )
3247 return cmdutil.abortgraft(ui, repo, graftstate)
3250 return cmdutil.abortgraft(ui, repo, graftstate)
3248 elif opts.get('continue'):
3251 elif opts.get('continue'):
3249 cont = True
3252 cont = True
3250 if revs:
3253 if revs:
3251 raise error.InputError(_(b"can't specify --continue and revisions"))
3254 raise error.InputError(_(b"can't specify --continue and revisions"))
3252 # read in unfinished revisions
3255 # read in unfinished revisions
3253 if graftstate.exists():
3256 if graftstate.exists():
3254 statedata = cmdutil.readgraftstate(repo, graftstate)
3257 statedata = cmdutil.readgraftstate(repo, graftstate)
3255 if statedata.get(b'date'):
3258 if statedata.get(b'date'):
3256 opts['date'] = statedata[b'date']
3259 opts['date'] = statedata[b'date']
3257 if statedata.get(b'user'):
3260 if statedata.get(b'user'):
3258 opts['user'] = statedata[b'user']
3261 opts['user'] = statedata[b'user']
3259 if statedata.get(b'log'):
3262 if statedata.get(b'log'):
3260 opts['log'] = True
3263 opts['log'] = True
3261 if statedata.get(b'no_commit'):
3264 if statedata.get(b'no_commit'):
3262 opts['no_commit'] = statedata.get(b'no_commit')
3265 opts['no_commit'] = statedata.get(b'no_commit')
3263 if statedata.get(b'base'):
3266 if statedata.get(b'base'):
3264 opts['base'] = statedata.get(b'base')
3267 opts['base'] = statedata.get(b'base')
3265 nodes = statedata[b'nodes']
3268 nodes = statedata[b'nodes']
3266 revs = [repo[node].rev() for node in nodes]
3269 revs = [repo[node].rev() for node in nodes]
3267 else:
3270 else:
3268 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3271 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3269 else:
3272 else:
3270 if not revs:
3273 if not revs:
3271 raise error.InputError(_(b'no revisions specified'))
3274 raise error.InputError(_(b'no revisions specified'))
3272 cmdutil.checkunfinished(repo)
3275 cmdutil.checkunfinished(repo)
3273 cmdutil.bailifchanged(repo)
3276 cmdutil.bailifchanged(repo)
3274 revs = logcmdutil.revrange(repo, revs)
3277 revs = logcmdutil.revrange(repo, revs)
3275
3278
3276 skipped = set()
3279 skipped = set()
3277 basectx = None
3280 basectx = None
3278 if opts.get('base'):
3281 if opts.get('base'):
3279 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3282 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3280 if basectx is None:
3283 if basectx is None:
3281 # check for merges
3284 # check for merges
3282 for rev in repo.revs(b'%ld and merge()', revs):
3285 for rev in repo.revs(b'%ld and merge()', revs):
3283 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3286 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3284 skipped.add(rev)
3287 skipped.add(rev)
3285 revs = [r for r in revs if r not in skipped]
3288 revs = [r for r in revs if r not in skipped]
3286 if not revs:
3289 if not revs:
3287 return -1
3290 return -1
3288 if basectx is not None and len(revs) != 1:
3291 if basectx is not None and len(revs) != 1:
3289 raise error.InputError(_(b'only one revision allowed with --base '))
3292 raise error.InputError(_(b'only one revision allowed with --base '))
3290
3293
3291 # Don't check in the --continue case, in effect retaining --force across
3294 # Don't check in the --continue case, in effect retaining --force across
3292 # --continues. That's because without --force, any revisions we decided to
3295 # --continues. That's because without --force, any revisions we decided to
3293 # skip would have been filtered out here, so they wouldn't have made their
3296 # skip would have been filtered out here, so they wouldn't have made their
3294 # way to the graftstate. With --force, any revisions we would have otherwise
3297 # way to the graftstate. With --force, any revisions we would have otherwise
3295 # skipped would not have been filtered out, and if they hadn't been applied
3298 # skipped would not have been filtered out, and if they hadn't been applied
3296 # already, they'd have been in the graftstate.
3299 # already, they'd have been in the graftstate.
3297 if not (cont or opts.get('force')) and basectx is None:
3300 if not (cont or opts.get('force')) and basectx is None:
3298 # check for ancestors of dest branch
3301 # check for ancestors of dest branch
3299 ancestors = repo.revs(b'%ld & (::.)', revs)
3302 ancestors = repo.revs(b'%ld & (::.)', revs)
3300 for rev in ancestors:
3303 for rev in ancestors:
3301 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3304 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3302
3305
3303 revs = [r for r in revs if r not in ancestors]
3306 revs = [r for r in revs if r not in ancestors]
3304
3307
3305 if not revs:
3308 if not revs:
3306 return -1
3309 return -1
3307
3310
3308 # analyze revs for earlier grafts
3311 # analyze revs for earlier grafts
3309 ids = {}
3312 ids = {}
3310 for ctx in repo.set(b"%ld", revs):
3313 for ctx in repo.set(b"%ld", revs):
3311 ids[ctx.hex()] = ctx.rev()
3314 ids[ctx.hex()] = ctx.rev()
3312 n = ctx.extra().get(b'source')
3315 n = ctx.extra().get(b'source')
3313 if n:
3316 if n:
3314 ids[n] = ctx.rev()
3317 ids[n] = ctx.rev()
3315
3318
3316 # check ancestors for earlier grafts
3319 # check ancestors for earlier grafts
3317 ui.debug(b'scanning for duplicate grafts\n')
3320 ui.debug(b'scanning for duplicate grafts\n')
3318
3321
3319 # The only changesets we can be sure doesn't contain grafts of any
3322 # The only changesets we can be sure doesn't contain grafts of any
3320 # revs, are the ones that are common ancestors of *all* revs:
3323 # revs, are the ones that are common ancestors of *all* revs:
3321 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3324 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3322 ctx = repo[rev]
3325 ctx = repo[rev]
3323 n = ctx.extra().get(b'source')
3326 n = ctx.extra().get(b'source')
3324 if n in ids:
3327 if n in ids:
3325 try:
3328 try:
3326 r = repo[n].rev()
3329 r = repo[n].rev()
3327 except error.RepoLookupError:
3330 except error.RepoLookupError:
3328 r = None
3331 r = None
3329 if r in revs:
3332 if r in revs:
3330 ui.warn(
3333 ui.warn(
3331 _(
3334 _(
3332 b'skipping revision %d:%s '
3335 b'skipping revision %d:%s '
3333 b'(already grafted to %d:%s)\n'
3336 b'(already grafted to %d:%s)\n'
3334 )
3337 )
3335 % (r, repo[r], rev, ctx)
3338 % (r, repo[r], rev, ctx)
3336 )
3339 )
3337 revs.remove(r)
3340 revs.remove(r)
3338 elif ids[n] in revs:
3341 elif ids[n] in revs:
3339 if r is None:
3342 if r is None:
3340 ui.warn(
3343 ui.warn(
3341 _(
3344 _(
3342 b'skipping already grafted revision %d:%s '
3345 b'skipping already grafted revision %d:%s '
3343 b'(%d:%s also has unknown origin %s)\n'
3346 b'(%d:%s also has unknown origin %s)\n'
3344 )
3347 )
3345 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3348 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3346 )
3349 )
3347 else:
3350 else:
3348 ui.warn(
3351 ui.warn(
3349 _(
3352 _(
3350 b'skipping already grafted revision %d:%s '
3353 b'skipping already grafted revision %d:%s '
3351 b'(%d:%s also has origin %d:%s)\n'
3354 b'(%d:%s also has origin %d:%s)\n'
3352 )
3355 )
3353 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3356 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3354 )
3357 )
3355 revs.remove(ids[n])
3358 revs.remove(ids[n])
3356 elif ctx.hex() in ids:
3359 elif ctx.hex() in ids:
3357 r = ids[ctx.hex()]
3360 r = ids[ctx.hex()]
3358 if r in revs:
3361 if r in revs:
3359 ui.warn(
3362 ui.warn(
3360 _(
3363 _(
3361 b'skipping already grafted revision %d:%s '
3364 b'skipping already grafted revision %d:%s '
3362 b'(was grafted from %d:%s)\n'
3365 b'(was grafted from %d:%s)\n'
3363 )
3366 )
3364 % (r, repo[r], rev, ctx)
3367 % (r, repo[r], rev, ctx)
3365 )
3368 )
3366 revs.remove(r)
3369 revs.remove(r)
3367 if not revs:
3370 if not revs:
3368 return -1
3371 return -1
3369
3372
3370 if opts.get('no_commit'):
3373 if opts.get('no_commit'):
3371 statedata[b'no_commit'] = True
3374 statedata[b'no_commit'] = True
3372 if opts.get('base'):
3375 if opts.get('base'):
3373 statedata[b'base'] = opts['base']
3376 statedata[b'base'] = opts['base']
3374 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3377 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3375 desc = b'%d:%s "%s"' % (
3378 desc = b'%d:%s "%s"' % (
3376 ctx.rev(),
3379 ctx.rev(),
3377 ctx,
3380 ctx,
3378 ctx.description().split(b'\n', 1)[0],
3381 ctx.description().split(b'\n', 1)[0],
3379 )
3382 )
3380 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3383 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3381 if names:
3384 if names:
3382 desc += b' (%s)' % b' '.join(names)
3385 desc += b' (%s)' % b' '.join(names)
3383 ui.status(_(b'grafting %s\n') % desc)
3386 ui.status(_(b'grafting %s\n') % desc)
3384 if opts.get('dry_run'):
3387 if opts.get('dry_run'):
3385 continue
3388 continue
3386
3389
3387 source = ctx.extra().get(b'source')
3390 source = ctx.extra().get(b'source')
3388 extra = {}
3391 extra = {}
3389 if source:
3392 if source:
3390 extra[b'source'] = source
3393 extra[b'source'] = source
3391 extra[b'intermediate-source'] = ctx.hex()
3394 extra[b'intermediate-source'] = ctx.hex()
3392 else:
3395 else:
3393 extra[b'source'] = ctx.hex()
3396 extra[b'source'] = ctx.hex()
3394 user = ctx.user()
3397 user = ctx.user()
3395 if opts.get('user'):
3398 if opts.get('user'):
3396 user = opts['user']
3399 user = opts['user']
3397 statedata[b'user'] = user
3400 statedata[b'user'] = user
3398 date = ctx.date()
3401 date = ctx.date()
3399 if opts.get('date'):
3402 if opts.get('date'):
3400 date = opts['date']
3403 date = opts['date']
3401 statedata[b'date'] = date
3404 statedata[b'date'] = date
3402 message = ctx.description()
3405 message = ctx.description()
3403 if opts.get('log'):
3406 if opts.get('log'):
3404 message += b'\n(grafted from %s)' % ctx.hex()
3407 message += b'\n(grafted from %s)' % ctx.hex()
3405 statedata[b'log'] = True
3408 statedata[b'log'] = True
3406
3409
3407 # we don't merge the first commit when continuing
3410 # we don't merge the first commit when continuing
3408 if not cont:
3411 if not cont:
3409 # perform the graft merge with p1(rev) as 'ancestor'
3412 # perform the graft merge with p1(rev) as 'ancestor'
3410 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3413 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3411 base = ctx.p1() if basectx is None else basectx
3414 base = ctx.p1() if basectx is None else basectx
3412 with ui.configoverride(overrides, b'graft'):
3415 with ui.configoverride(overrides, b'graft'):
3413 stats = mergemod.graft(
3416 stats = mergemod.graft(
3414 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3417 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3415 )
3418 )
3416 # report any conflicts
3419 # report any conflicts
3417 if stats.unresolvedcount > 0:
3420 if stats.unresolvedcount > 0:
3418 # write out state for --continue
3421 # write out state for --continue
3419 nodes = [repo[rev].hex() for rev in revs[pos:]]
3422 nodes = [repo[rev].hex() for rev in revs[pos:]]
3420 statedata[b'nodes'] = nodes
3423 statedata[b'nodes'] = nodes
3421 stateversion = 1
3424 stateversion = 1
3422 graftstate.save(stateversion, statedata)
3425 graftstate.save(stateversion, statedata)
3423 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3426 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3424 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3427 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3425 return 1
3428 return 1
3426 else:
3429 else:
3427 cont = False
3430 cont = False
3428
3431
3429 # commit if --no-commit is false
3432 # commit if --no-commit is false
3430 if not opts.get('no_commit'):
3433 if not opts.get('no_commit'):
3431 node = repo.commit(
3434 node = repo.commit(
3432 text=message, user=user, date=date, extra=extra, editor=editor
3435 text=message, user=user, date=date, extra=extra, editor=editor
3433 )
3436 )
3434 if node is None:
3437 if node is None:
3435 ui.warn(
3438 ui.warn(
3436 _(b'note: graft of %d:%s created no changes to commit\n')
3439 _(b'note: graft of %d:%s created no changes to commit\n')
3437 % (ctx.rev(), ctx)
3440 % (ctx.rev(), ctx)
3438 )
3441 )
3439 # checking that newnodes exist because old state files won't have it
3442 # checking that newnodes exist because old state files won't have it
3440 elif statedata.get(b'newnodes') is not None:
3443 elif statedata.get(b'newnodes') is not None:
3441 nn = statedata[b'newnodes']
3444 nn = statedata[b'newnodes']
3442 assert isinstance(nn, list) # list of bytes
3445 assert isinstance(nn, list) # list of bytes
3443 nn.append(node)
3446 nn.append(node)
3444
3447
3445 # remove state when we complete successfully
3448 # remove state when we complete successfully
3446 if not opts.get('dry_run'):
3449 if not opts.get('dry_run'):
3447 graftstate.delete()
3450 graftstate.delete()
3448
3451
3449 return 0
3452 return 0
3450
3453
3451
3454
3452 def _stopgraft(ui, repo, graftstate):
3455 def _stopgraft(ui, repo, graftstate):
3453 """stop the interrupted graft"""
3456 """stop the interrupted graft"""
3454 if not graftstate.exists():
3457 if not graftstate.exists():
3455 raise error.StateError(_(b"no interrupted graft found"))
3458 raise error.StateError(_(b"no interrupted graft found"))
3456 pctx = repo[b'.']
3459 pctx = repo[b'.']
3457 mergemod.clean_update(pctx)
3460 mergemod.clean_update(pctx)
3458 graftstate.delete()
3461 graftstate.delete()
3459 ui.status(_(b"stopped the interrupted graft\n"))
3462 ui.status(_(b"stopped the interrupted graft\n"))
3460 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3463 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3461 return 0
3464 return 0
3462
3465
3463
3466
3464 statemod.addunfinished(
3467 statemod.addunfinished(
3465 b'graft',
3468 b'graft',
3466 fname=b'graftstate',
3469 fname=b'graftstate',
3467 clearable=True,
3470 clearable=True,
3468 stopflag=True,
3471 stopflag=True,
3469 continueflag=True,
3472 continueflag=True,
3470 abortfunc=cmdutil.hgabortgraft,
3473 abortfunc=cmdutil.hgabortgraft,
3471 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3474 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3472 )
3475 )
3473
3476
3474
3477
3475 @command(
3478 @command(
3476 b'grep',
3479 b'grep',
3477 [
3480 [
3478 (b'0', b'print0', None, _(b'end fields with NUL')),
3481 (b'0', b'print0', None, _(b'end fields with NUL')),
3479 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3482 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3480 (
3483 (
3481 b'',
3484 b'',
3482 b'diff',
3485 b'diff',
3483 None,
3486 None,
3484 _(
3487 _(
3485 b'search revision differences for when the pattern was added '
3488 b'search revision differences for when the pattern was added '
3486 b'or removed'
3489 b'or removed'
3487 ),
3490 ),
3488 ),
3491 ),
3489 (b'a', b'text', None, _(b'treat all files as text')),
3492 (b'a', b'text', None, _(b'treat all files as text')),
3490 (
3493 (
3491 b'f',
3494 b'f',
3492 b'follow',
3495 b'follow',
3493 None,
3496 None,
3494 _(
3497 _(
3495 b'follow changeset history,'
3498 b'follow changeset history,'
3496 b' or file history across copies and renames'
3499 b' or file history across copies and renames'
3497 ),
3500 ),
3498 ),
3501 ),
3499 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3502 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3500 (
3503 (
3501 b'l',
3504 b'l',
3502 b'files-with-matches',
3505 b'files-with-matches',
3503 None,
3506 None,
3504 _(b'print only filenames and revisions that match'),
3507 _(b'print only filenames and revisions that match'),
3505 ),
3508 ),
3506 (b'n', b'line-number', None, _(b'print matching line numbers')),
3509 (b'n', b'line-number', None, _(b'print matching line numbers')),
3507 (
3510 (
3508 b'r',
3511 b'r',
3509 b'rev',
3512 b'rev',
3510 [],
3513 [],
3511 _(b'search files changed within revision range'),
3514 _(b'search files changed within revision range'),
3512 _(b'REV'),
3515 _(b'REV'),
3513 ),
3516 ),
3514 (
3517 (
3515 b'',
3518 b'',
3516 b'all-files',
3519 b'all-files',
3517 None,
3520 None,
3518 _(
3521 _(
3519 b'include all files in the changeset while grepping (DEPRECATED)'
3522 b'include all files in the changeset while grepping (DEPRECATED)'
3520 ),
3523 ),
3521 ),
3524 ),
3522 (b'u', b'user', None, _(b'list the author (long with -v)')),
3525 (b'u', b'user', None, _(b'list the author (long with -v)')),
3523 (b'd', b'date', None, _(b'list the date (short with -q)')),
3526 (b'd', b'date', None, _(b'list the date (short with -q)')),
3524 ]
3527 ]
3525 + formatteropts
3528 + formatteropts
3526 + walkopts,
3529 + walkopts,
3527 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3530 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3528 helpcategory=command.CATEGORY_FILE_CONTENTS,
3531 helpcategory=command.CATEGORY_FILE_CONTENTS,
3529 inferrepo=True,
3532 inferrepo=True,
3530 intents={INTENT_READONLY},
3533 intents={INTENT_READONLY},
3531 )
3534 )
3532 def grep(ui, repo, pattern, *pats, **opts):
3535 def grep(ui, repo, pattern, *pats, **opts):
3533 """search for a pattern in specified files
3536 """search for a pattern in specified files
3534
3537
3535 Search the working directory or revision history for a regular
3538 Search the working directory or revision history for a regular
3536 expression in the specified files for the entire repository.
3539 expression in the specified files for the entire repository.
3537
3540
3538 By default, grep searches the repository files in the working
3541 By default, grep searches the repository files in the working
3539 directory and prints the files where it finds a match. To specify
3542 directory and prints the files where it finds a match. To specify
3540 historical revisions instead of the working directory, use the
3543 historical revisions instead of the working directory, use the
3541 --rev flag.
3544 --rev flag.
3542
3545
3543 To search instead historical revision differences that contains a
3546 To search instead historical revision differences that contains a
3544 change in match status ("-" for a match that becomes a non-match,
3547 change in match status ("-" for a match that becomes a non-match,
3545 or "+" for a non-match that becomes a match), use the --diff flag.
3548 or "+" for a non-match that becomes a match), use the --diff flag.
3546
3549
3547 PATTERN can be any Python (roughly Perl-compatible) regular
3550 PATTERN can be any Python (roughly Perl-compatible) regular
3548 expression.
3551 expression.
3549
3552
3550 If no FILEs are specified and the --rev flag isn't supplied, all
3553 If no FILEs are specified and the --rev flag isn't supplied, all
3551 files in the working directory are searched. When using the --rev
3554 files in the working directory are searched. When using the --rev
3552 flag and specifying FILEs, use the --follow argument to also
3555 flag and specifying FILEs, use the --follow argument to also
3553 follow the specified FILEs across renames and copies.
3556 follow the specified FILEs across renames and copies.
3554
3557
3555 .. container:: verbose
3558 .. container:: verbose
3556
3559
3557 Template:
3560 Template:
3558
3561
3559 The following keywords are supported in addition to the common template
3562 The following keywords are supported in addition to the common template
3560 keywords and functions. See also :hg:`help templates`.
3563 keywords and functions. See also :hg:`help templates`.
3561
3564
3562 :change: String. Character denoting insertion ``+`` or removal ``-``.
3565 :change: String. Character denoting insertion ``+`` or removal ``-``.
3563 Available if ``--diff`` is specified.
3566 Available if ``--diff`` is specified.
3564 :lineno: Integer. Line number of the match.
3567 :lineno: Integer. Line number of the match.
3565 :path: String. Repository-absolute path of the file.
3568 :path: String. Repository-absolute path of the file.
3566 :texts: List of text chunks.
3569 :texts: List of text chunks.
3567
3570
3568 And each entry of ``{texts}`` provides the following sub-keywords.
3571 And each entry of ``{texts}`` provides the following sub-keywords.
3569
3572
3570 :matched: Boolean. True if the chunk matches the specified pattern.
3573 :matched: Boolean. True if the chunk matches the specified pattern.
3571 :text: String. Chunk content.
3574 :text: String. Chunk content.
3572
3575
3573 See :hg:`help templates.operators` for the list expansion syntax.
3576 See :hg:`help templates.operators` for the list expansion syntax.
3574
3577
3575 Returns 0 if a match is found, 1 otherwise.
3578 Returns 0 if a match is found, 1 otherwise.
3576
3579
3577 """
3580 """
3578 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3581 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3579
3582
3580 diff = opts.get('all') or opts.get('diff')
3583 diff = opts.get('all') or opts.get('diff')
3581 follow = opts.get('follow')
3584 follow = opts.get('follow')
3582 if opts.get('all_files') is None and not diff:
3585 if opts.get('all_files') is None and not diff:
3583 opts['all_files'] = True
3586 opts['all_files'] = True
3584 plaingrep = (
3587 plaingrep = (
3585 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3588 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3586 )
3589 )
3587 all_files = opts.get('all_files')
3590 all_files = opts.get('all_files')
3588 if plaingrep:
3591 if plaingrep:
3589 opts['rev'] = [b'wdir()']
3592 opts['rev'] = [b'wdir()']
3590
3593
3591 reflags = re.M
3594 reflags = re.M
3592 if opts.get('ignore_case'):
3595 if opts.get('ignore_case'):
3593 reflags |= re.I
3596 reflags |= re.I
3594 try:
3597 try:
3595 regexp = util.re.compile(pattern, reflags)
3598 regexp = util.re.compile(pattern, reflags)
3596 except re.error as inst:
3599 except re.error as inst:
3597 ui.warn(
3600 ui.warn(
3598 _(b"grep: invalid match pattern: %s\n")
3601 _(b"grep: invalid match pattern: %s\n")
3599 % stringutil.forcebytestr(inst)
3602 % stringutil.forcebytestr(inst)
3600 )
3603 )
3601 return 1
3604 return 1
3602 sep, eol = b':', b'\n'
3605 sep, eol = b':', b'\n'
3603 if opts.get('print0'):
3606 if opts.get('print0'):
3604 sep = eol = b'\0'
3607 sep = eol = b'\0'
3605
3608
3606 searcher = grepmod.grepsearcher(
3609 searcher = grepmod.grepsearcher(
3607 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3610 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3608 )
3611 )
3609
3612
3610 getfile = searcher._getfile
3613 getfile = searcher._getfile
3611
3614
3612 uipathfn = scmutil.getuipathfn(repo)
3615 uipathfn = scmutil.getuipathfn(repo)
3613
3616
3614 def display(fm, fn, ctx, pstates, states):
3617 def display(fm, fn, ctx, pstates, states):
3615 rev = scmutil.intrev(ctx)
3618 rev = scmutil.intrev(ctx)
3616 if fm.isplain():
3619 if fm.isplain():
3617 formatuser = ui.shortuser
3620 formatuser = ui.shortuser
3618 else:
3621 else:
3619 formatuser = pycompat.bytestr
3622 formatuser = pycompat.bytestr
3620 if ui.quiet:
3623 if ui.quiet:
3621 datefmt = b'%Y-%m-%d'
3624 datefmt = b'%Y-%m-%d'
3622 else:
3625 else:
3623 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3626 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3624 found = False
3627 found = False
3625
3628
3626 @util.cachefunc
3629 @util.cachefunc
3627 def binary():
3630 def binary():
3628 flog = getfile(fn)
3631 flog = getfile(fn)
3629 try:
3632 try:
3630 return stringutil.binary(flog.read(ctx.filenode(fn)))
3633 return stringutil.binary(flog.read(ctx.filenode(fn)))
3631 except error.WdirUnsupported:
3634 except error.WdirUnsupported:
3632 return ctx[fn].isbinary()
3635 return ctx[fn].isbinary()
3633
3636
3634 fieldnamemap = {b'linenumber': b'lineno'}
3637 fieldnamemap = {b'linenumber': b'lineno'}
3635 if diff:
3638 if diff:
3636 iter = grepmod.difflinestates(pstates, states)
3639 iter = grepmod.difflinestates(pstates, states)
3637 else:
3640 else:
3638 iter = [(b'', l) for l in states]
3641 iter = [(b'', l) for l in states]
3639 for change, l in iter:
3642 for change, l in iter:
3640 fm.startitem()
3643 fm.startitem()
3641 fm.context(ctx=ctx)
3644 fm.context(ctx=ctx)
3642 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3645 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3643 fm.plain(uipathfn(fn), label=b'grep.filename')
3646 fm.plain(uipathfn(fn), label=b'grep.filename')
3644
3647
3645 cols = [
3648 cols = [
3646 (b'rev', b'%d', rev, not plaingrep, b''),
3649 (b'rev', b'%d', rev, not plaingrep, b''),
3647 (
3650 (
3648 b'linenumber',
3651 b'linenumber',
3649 b'%d',
3652 b'%d',
3650 l.linenum,
3653 l.linenum,
3651 opts.get('line_number'),
3654 opts.get('line_number'),
3652 b'',
3655 b'',
3653 ),
3656 ),
3654 ]
3657 ]
3655 if diff:
3658 if diff:
3656 cols.append(
3659 cols.append(
3657 (
3660 (
3658 b'change',
3661 b'change',
3659 b'%s',
3662 b'%s',
3660 change,
3663 change,
3661 True,
3664 True,
3662 b'grep.inserted '
3665 b'grep.inserted '
3663 if change == b'+'
3666 if change == b'+'
3664 else b'grep.deleted ',
3667 else b'grep.deleted ',
3665 )
3668 )
3666 )
3669 )
3667 cols.extend(
3670 cols.extend(
3668 [
3671 [
3669 (
3672 (
3670 b'user',
3673 b'user',
3671 b'%s',
3674 b'%s',
3672 formatuser(ctx.user()),
3675 formatuser(ctx.user()),
3673 opts.get('user'),
3676 opts.get('user'),
3674 b'',
3677 b'',
3675 ),
3678 ),
3676 (
3679 (
3677 b'date',
3680 b'date',
3678 b'%s',
3681 b'%s',
3679 fm.formatdate(ctx.date(), datefmt),
3682 fm.formatdate(ctx.date(), datefmt),
3680 opts.get('date'),
3683 opts.get('date'),
3681 b'',
3684 b'',
3682 ),
3685 ),
3683 ]
3686 ]
3684 )
3687 )
3685 for name, fmt, data, cond, extra_label in cols:
3688 for name, fmt, data, cond, extra_label in cols:
3686 if cond:
3689 if cond:
3687 fm.plain(sep, label=b'grep.sep')
3690 fm.plain(sep, label=b'grep.sep')
3688 field = fieldnamemap.get(name, name)
3691 field = fieldnamemap.get(name, name)
3689 label = extra_label + (b'grep.%s' % name)
3692 label = extra_label + (b'grep.%s' % name)
3690 fm.condwrite(cond, field, fmt, data, label=label)
3693 fm.condwrite(cond, field, fmt, data, label=label)
3691 if not opts.get('files_with_matches'):
3694 if not opts.get('files_with_matches'):
3692 fm.plain(sep, label=b'grep.sep')
3695 fm.plain(sep, label=b'grep.sep')
3693 if not opts.get('text') and binary():
3696 if not opts.get('text') and binary():
3694 fm.plain(_(b" Binary file matches"))
3697 fm.plain(_(b" Binary file matches"))
3695 else:
3698 else:
3696 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3699 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3697 fm.plain(eol)
3700 fm.plain(eol)
3698 found = True
3701 found = True
3699 if opts.get('files_with_matches'):
3702 if opts.get('files_with_matches'):
3700 break
3703 break
3701 return found
3704 return found
3702
3705
3703 def displaymatches(fm, l):
3706 def displaymatches(fm, l):
3704 p = 0
3707 p = 0
3705 for s, e in l.findpos(regexp):
3708 for s, e in l.findpos(regexp):
3706 if p < s:
3709 if p < s:
3707 fm.startitem()
3710 fm.startitem()
3708 fm.write(b'text', b'%s', l.line[p:s])
3711 fm.write(b'text', b'%s', l.line[p:s])
3709 fm.data(matched=False)
3712 fm.data(matched=False)
3710 fm.startitem()
3713 fm.startitem()
3711 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3714 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3712 fm.data(matched=True)
3715 fm.data(matched=True)
3713 p = e
3716 p = e
3714 if p < len(l.line):
3717 if p < len(l.line):
3715 fm.startitem()
3718 fm.startitem()
3716 fm.write(b'text', b'%s', l.line[p:])
3719 fm.write(b'text', b'%s', l.line[p:])
3717 fm.data(matched=False)
3720 fm.data(matched=False)
3718 fm.end()
3721 fm.end()
3719
3722
3720 found = False
3723 found = False
3721
3724
3722 wopts = logcmdutil.walkopts(
3725 wopts = logcmdutil.walkopts(
3723 pats=pats,
3726 pats=pats,
3724 opts=pycompat.byteskwargs(opts),
3727 opts=pycompat.byteskwargs(opts),
3725 revspec=opts['rev'],
3728 revspec=opts['rev'],
3726 include_pats=opts['include'],
3729 include_pats=opts['include'],
3727 exclude_pats=opts['exclude'],
3730 exclude_pats=opts['exclude'],
3728 follow=follow,
3731 follow=follow,
3729 force_changelog_traversal=all_files,
3732 force_changelog_traversal=all_files,
3730 filter_revisions_by_pats=not all_files,
3733 filter_revisions_by_pats=not all_files,
3731 )
3734 )
3732 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3735 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3733
3736
3734 ui.pager(b'grep')
3737 ui.pager(b'grep')
3735 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3738 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3736 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3739 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3737 r = display(fm, fn, ctx, pstates, states)
3740 r = display(fm, fn, ctx, pstates, states)
3738 found = found or r
3741 found = found or r
3739 if r and not diff and not all_files:
3742 if r and not diff and not all_files:
3740 searcher.skipfile(fn, ctx.rev())
3743 searcher.skipfile(fn, ctx.rev())
3741 fm.end()
3744 fm.end()
3742
3745
3743 return not found
3746 return not found
3744
3747
3745
3748
3746 @command(
3749 @command(
3747 b'heads',
3750 b'heads',
3748 [
3751 [
3749 (
3752 (
3750 b'r',
3753 b'r',
3751 b'rev',
3754 b'rev',
3752 b'',
3755 b'',
3753 _(b'show only heads which are descendants of STARTREV'),
3756 _(b'show only heads which are descendants of STARTREV'),
3754 _(b'STARTREV'),
3757 _(b'STARTREV'),
3755 ),
3758 ),
3756 (b't', b'topo', False, _(b'show topological heads only')),
3759 (b't', b'topo', False, _(b'show topological heads only')),
3757 (
3760 (
3758 b'a',
3761 b'a',
3759 b'active',
3762 b'active',
3760 False,
3763 False,
3761 _(b'show active branchheads only (DEPRECATED)'),
3764 _(b'show active branchheads only (DEPRECATED)'),
3762 ),
3765 ),
3763 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3766 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3764 ]
3767 ]
3765 + templateopts,
3768 + templateopts,
3766 _(b'[-ct] [-r STARTREV] [REV]...'),
3769 _(b'[-ct] [-r STARTREV] [REV]...'),
3767 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3770 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3768 intents={INTENT_READONLY},
3771 intents={INTENT_READONLY},
3769 )
3772 )
3770 def heads(ui, repo, *branchrevs, **opts):
3773 def heads(ui, repo, *branchrevs, **opts):
3771 """show branch heads
3774 """show branch heads
3772
3775
3773 With no arguments, show all open branch heads in the repository.
3776 With no arguments, show all open branch heads in the repository.
3774 Branch heads are changesets that have no descendants on the
3777 Branch heads are changesets that have no descendants on the
3775 same branch. They are where development generally takes place and
3778 same branch. They are where development generally takes place and
3776 are the usual targets for update and merge operations.
3779 are the usual targets for update and merge operations.
3777
3780
3778 If one or more REVs are given, only open branch heads on the
3781 If one or more REVs are given, only open branch heads on the
3779 branches associated with the specified changesets are shown. This
3782 branches associated with the specified changesets are shown. This
3780 means that you can use :hg:`heads .` to see the heads on the
3783 means that you can use :hg:`heads .` to see the heads on the
3781 currently checked-out branch.
3784 currently checked-out branch.
3782
3785
3783 If -c/--closed is specified, also show branch heads marked closed
3786 If -c/--closed is specified, also show branch heads marked closed
3784 (see :hg:`commit --close-branch`).
3787 (see :hg:`commit --close-branch`).
3785
3788
3786 If STARTREV is specified, only those heads that are descendants of
3789 If STARTREV is specified, only those heads that are descendants of
3787 STARTREV will be displayed.
3790 STARTREV will be displayed.
3788
3791
3789 If -t/--topo is specified, named branch mechanics will be ignored and only
3792 If -t/--topo is specified, named branch mechanics will be ignored and only
3790 topological heads (changesets with no children) will be shown.
3793 topological heads (changesets with no children) will be shown.
3791
3794
3792 Returns 0 if matching heads are found, 1 if not.
3795 Returns 0 if matching heads are found, 1 if not.
3793 """
3796 """
3794
3797
3795 start = None
3798 start = None
3796 rev = opts.get('rev')
3799 rev = opts.get('rev')
3797 if rev:
3800 if rev:
3798 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3801 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3799 start = logcmdutil.revsingle(repo, rev, None).node()
3802 start = logcmdutil.revsingle(repo, rev, None).node()
3800
3803
3801 if opts.get('topo'):
3804 if opts.get('topo'):
3802 heads = [repo[h] for h in repo.heads(start)]
3805 heads = [repo[h] for h in repo.heads(start)]
3803 else:
3806 else:
3804 heads = []
3807 heads = []
3805 for branch in repo.branchmap():
3808 for branch in repo.branchmap():
3806 heads += repo.branchheads(branch, start, opts.get('closed'))
3809 heads += repo.branchheads(branch, start, opts.get('closed'))
3807 heads = [repo[h] for h in heads]
3810 heads = [repo[h] for h in heads]
3808
3811
3809 if branchrevs:
3812 if branchrevs:
3810 branches = {
3813 branches = {
3811 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3814 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3812 }
3815 }
3813 heads = [h for h in heads if h.branch() in branches]
3816 heads = [h for h in heads if h.branch() in branches]
3814
3817
3815 if opts.get('active') and branchrevs:
3818 if opts.get('active') and branchrevs:
3816 dagheads = repo.heads(start)
3819 dagheads = repo.heads(start)
3817 heads = [h for h in heads if h.node() in dagheads]
3820 heads = [h for h in heads if h.node() in dagheads]
3818
3821
3819 if branchrevs:
3822 if branchrevs:
3820 haveheads = {h.branch() for h in heads}
3823 haveheads = {h.branch() for h in heads}
3821 if branches - haveheads:
3824 if branches - haveheads:
3822 headless = b', '.join(b for b in branches - haveheads)
3825 headless = b', '.join(b for b in branches - haveheads)
3823 msg = _(b'no open branch heads found on branches %s')
3826 msg = _(b'no open branch heads found on branches %s')
3824 if opts.get('rev'):
3827 if opts.get('rev'):
3825 msg += _(b' (started at %s)') % opts['rev']
3828 msg += _(b' (started at %s)') % opts['rev']
3826 ui.warn((msg + b'\n') % headless)
3829 ui.warn((msg + b'\n') % headless)
3827
3830
3828 if not heads:
3831 if not heads:
3829 return 1
3832 return 1
3830
3833
3831 ui.pager(b'heads')
3834 ui.pager(b'heads')
3832 heads = sorted(heads, key=lambda x: -(x.rev()))
3835 heads = sorted(heads, key=lambda x: -(x.rev()))
3833 displayer = logcmdutil.changesetdisplayer(
3836 displayer = logcmdutil.changesetdisplayer(
3834 ui, repo, pycompat.byteskwargs(opts)
3837 ui, repo, pycompat.byteskwargs(opts)
3835 )
3838 )
3836 for ctx in heads:
3839 for ctx in heads:
3837 displayer.show(ctx)
3840 displayer.show(ctx)
3838 displayer.close()
3841 displayer.close()
3839
3842
3840
3843
3841 @command(
3844 @command(
3842 b'help',
3845 b'help',
3843 [
3846 [
3844 (b'e', b'extension', None, _(b'show only help for extensions')),
3847 (b'e', b'extension', None, _(b'show only help for extensions')),
3845 (b'c', b'command', None, _(b'show only help for commands')),
3848 (b'c', b'command', None, _(b'show only help for commands')),
3846 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3849 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3847 (
3850 (
3848 b's',
3851 b's',
3849 b'system',
3852 b'system',
3850 [],
3853 [],
3851 _(b'show help for specific platform(s)'),
3854 _(b'show help for specific platform(s)'),
3852 _(b'PLATFORM'),
3855 _(b'PLATFORM'),
3853 ),
3856 ),
3854 ],
3857 ],
3855 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3858 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3856 helpcategory=command.CATEGORY_HELP,
3859 helpcategory=command.CATEGORY_HELP,
3857 norepo=True,
3860 norepo=True,
3858 intents={INTENT_READONLY},
3861 intents={INTENT_READONLY},
3859 )
3862 )
3860 def help_(ui, name=None, **opts):
3863 def help_(ui, name=None, **opts):
3861 """show help for a given topic or a help overview
3864 """show help for a given topic or a help overview
3862
3865
3863 With no arguments, print a list of commands with short help messages.
3866 With no arguments, print a list of commands with short help messages.
3864
3867
3865 Given a topic, extension, or command name, print help for that
3868 Given a topic, extension, or command name, print help for that
3866 topic.
3869 topic.
3867
3870
3868 Returns 0 if successful.
3871 Returns 0 if successful.
3869 """
3872 """
3870
3873
3871 keep = opts.get('system') or []
3874 keep = opts.get('system') or []
3872 if len(keep) == 0:
3875 if len(keep) == 0:
3873 if pycompat.sysplatform.startswith(b'win'):
3876 if pycompat.sysplatform.startswith(b'win'):
3874 keep.append(b'windows')
3877 keep.append(b'windows')
3875 elif pycompat.sysplatform == b'OpenVMS':
3878 elif pycompat.sysplatform == b'OpenVMS':
3876 keep.append(b'vms')
3879 keep.append(b'vms')
3877 elif pycompat.sysplatform == b'plan9':
3880 elif pycompat.sysplatform == b'plan9':
3878 keep.append(b'plan9')
3881 keep.append(b'plan9')
3879 else:
3882 else:
3880 keep.append(b'unix')
3883 keep.append(b'unix')
3881 keep.append(pycompat.sysplatform.lower())
3884 keep.append(pycompat.sysplatform.lower())
3882 if ui.verbose:
3885 if ui.verbose:
3883 keep.append(b'verbose')
3886 keep.append(b'verbose')
3884
3887
3885 commands = sys.modules[__name__]
3888 commands = sys.modules[__name__]
3886 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3889 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3887 ui.pager(b'help')
3890 ui.pager(b'help')
3888 ui.write(formatted)
3891 ui.write(formatted)
3889
3892
3890
3893
3891 @command(
3894 @command(
3892 b'identify|id',
3895 b'identify|id',
3893 [
3896 [
3894 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3897 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3895 (b'n', b'num', None, _(b'show local revision number')),
3898 (b'n', b'num', None, _(b'show local revision number')),
3896 (b'i', b'id', None, _(b'show global revision id')),
3899 (b'i', b'id', None, _(b'show global revision id')),
3897 (b'b', b'branch', None, _(b'show branch')),
3900 (b'b', b'branch', None, _(b'show branch')),
3898 (b't', b'tags', None, _(b'show tags')),
3901 (b't', b'tags', None, _(b'show tags')),
3899 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3902 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3900 ]
3903 ]
3901 + remoteopts
3904 + remoteopts
3902 + formatteropts,
3905 + formatteropts,
3903 _(b'[-nibtB] [-r REV] [SOURCE]'),
3906 _(b'[-nibtB] [-r REV] [SOURCE]'),
3904 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3907 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3905 optionalrepo=True,
3908 optionalrepo=True,
3906 intents={INTENT_READONLY},
3909 intents={INTENT_READONLY},
3907 )
3910 )
3908 def identify(
3911 def identify(
3909 ui,
3912 ui,
3910 repo,
3913 repo,
3911 source=None,
3914 source=None,
3912 rev=None,
3915 rev=None,
3913 num=None,
3916 num=None,
3914 id=None,
3917 id=None,
3915 branch=None,
3918 branch=None,
3916 tags=None,
3919 tags=None,
3917 bookmarks=None,
3920 bookmarks=None,
3918 **opts
3921 **opts
3919 ):
3922 ):
3920 """identify the working directory or specified revision
3923 """identify the working directory or specified revision
3921
3924
3922 Print a summary identifying the repository state at REV using one or
3925 Print a summary identifying the repository state at REV using one or
3923 two parent hash identifiers, followed by a "+" if the working
3926 two parent hash identifiers, followed by a "+" if the working
3924 directory has uncommitted changes, the branch name (if not default),
3927 directory has uncommitted changes, the branch name (if not default),
3925 a list of tags, and a list of bookmarks.
3928 a list of tags, and a list of bookmarks.
3926
3929
3927 When REV is not given, print a summary of the current state of the
3930 When REV is not given, print a summary of the current state of the
3928 repository including the working directory. Specify -r. to get information
3931 repository including the working directory. Specify -r. to get information
3929 of the working directory parent without scanning uncommitted changes.
3932 of the working directory parent without scanning uncommitted changes.
3930
3933
3931 Specifying a path to a repository root or Mercurial bundle will
3934 Specifying a path to a repository root or Mercurial bundle will
3932 cause lookup to operate on that repository/bundle.
3935 cause lookup to operate on that repository/bundle.
3933
3936
3934 .. container:: verbose
3937 .. container:: verbose
3935
3938
3936 Template:
3939 Template:
3937
3940
3938 The following keywords are supported in addition to the common template
3941 The following keywords are supported in addition to the common template
3939 keywords and functions. See also :hg:`help templates`.
3942 keywords and functions. See also :hg:`help templates`.
3940
3943
3941 :dirty: String. Character ``+`` denoting if the working directory has
3944 :dirty: String. Character ``+`` denoting if the working directory has
3942 uncommitted changes.
3945 uncommitted changes.
3943 :id: String. One or two nodes, optionally followed by ``+``.
3946 :id: String. One or two nodes, optionally followed by ``+``.
3944 :parents: List of strings. Parent nodes of the changeset.
3947 :parents: List of strings. Parent nodes of the changeset.
3945
3948
3946 Examples:
3949 Examples:
3947
3950
3948 - generate a build identifier for the working directory::
3951 - generate a build identifier for the working directory::
3949
3952
3950 hg id --id > build-id.dat
3953 hg id --id > build-id.dat
3951
3954
3952 - find the revision corresponding to a tag::
3955 - find the revision corresponding to a tag::
3953
3956
3954 hg id -n -r 1.3
3957 hg id -n -r 1.3
3955
3958
3956 - check the most recent revision of a remote repository::
3959 - check the most recent revision of a remote repository::
3957
3960
3958 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3961 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3959
3962
3960 See :hg:`log` for generating more information about specific revisions,
3963 See :hg:`log` for generating more information about specific revisions,
3961 including full hash identifiers.
3964 including full hash identifiers.
3962
3965
3963 Returns 0 if successful.
3966 Returns 0 if successful.
3964 """
3967 """
3965
3968
3966 opts = pycompat.byteskwargs(opts)
3969 opts = pycompat.byteskwargs(opts)
3967 if not repo and not source:
3970 if not repo and not source:
3968 raise error.InputError(
3971 raise error.InputError(
3969 _(b"there is no Mercurial repository here (.hg not found)")
3972 _(b"there is no Mercurial repository here (.hg not found)")
3970 )
3973 )
3971
3974
3972 default = not (num or id or branch or tags or bookmarks)
3975 default = not (num or id or branch or tags or bookmarks)
3973 output = []
3976 output = []
3974 revs = []
3977 revs = []
3975
3978
3976 peer = None
3979 peer = None
3977 try:
3980 try:
3978 if source:
3981 if source:
3979 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3982 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3980 # only pass ui when no repo
3983 # only pass ui when no repo
3981 peer = hg.peer(repo or ui, opts, path)
3984 peer = hg.peer(repo or ui, opts, path)
3982 repo = peer.local()
3985 repo = peer.local()
3983 branches = (path.branch, [])
3986 branches = (path.branch, [])
3984 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3987 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3985
3988
3986 fm = ui.formatter(b'identify', opts)
3989 fm = ui.formatter(b'identify', opts)
3987 fm.startitem()
3990 fm.startitem()
3988
3991
3989 if not repo:
3992 if not repo:
3990 if num or branch or tags:
3993 if num or branch or tags:
3991 raise error.InputError(
3994 raise error.InputError(
3992 _(b"can't query remote revision number, branch, or tags")
3995 _(b"can't query remote revision number, branch, or tags")
3993 )
3996 )
3994 if not rev and revs:
3997 if not rev and revs:
3995 rev = revs[0]
3998 rev = revs[0]
3996 if not rev:
3999 if not rev:
3997 rev = b"tip"
4000 rev = b"tip"
3998
4001
3999 remoterev = peer.lookup(rev)
4002 remoterev = peer.lookup(rev)
4000 hexrev = fm.hexfunc(remoterev)
4003 hexrev = fm.hexfunc(remoterev)
4001 if default or id:
4004 if default or id:
4002 output = [hexrev]
4005 output = [hexrev]
4003 fm.data(id=hexrev)
4006 fm.data(id=hexrev)
4004
4007
4005 @util.cachefunc
4008 @util.cachefunc
4006 def getbms():
4009 def getbms():
4007 bms = []
4010 bms = []
4008
4011
4009 if b'bookmarks' in peer.listkeys(b'namespaces'):
4012 if b'bookmarks' in peer.listkeys(b'namespaces'):
4010 hexremoterev = hex(remoterev)
4013 hexremoterev = hex(remoterev)
4011 bms = [
4014 bms = [
4012 bm
4015 bm
4013 for bm, bmr in peer.listkeys(b'bookmarks').items()
4016 for bm, bmr in peer.listkeys(b'bookmarks').items()
4014 if bmr == hexremoterev
4017 if bmr == hexremoterev
4015 ]
4018 ]
4016
4019
4017 return sorted(bms)
4020 return sorted(bms)
4018
4021
4019 if fm.isplain():
4022 if fm.isplain():
4020 if bookmarks:
4023 if bookmarks:
4021 output.extend(getbms())
4024 output.extend(getbms())
4022 elif default and not ui.quiet:
4025 elif default and not ui.quiet:
4023 # multiple bookmarks for a single parent separated by '/'
4026 # multiple bookmarks for a single parent separated by '/'
4024 bm = b'/'.join(getbms())
4027 bm = b'/'.join(getbms())
4025 if bm:
4028 if bm:
4026 output.append(bm)
4029 output.append(bm)
4027 else:
4030 else:
4028 fm.data(node=hex(remoterev))
4031 fm.data(node=hex(remoterev))
4029 if bookmarks or b'bookmarks' in fm.datahint():
4032 if bookmarks or b'bookmarks' in fm.datahint():
4030 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
4033 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
4031 else:
4034 else:
4032 if rev:
4035 if rev:
4033 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4036 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4034 ctx = logcmdutil.revsingle(repo, rev, None)
4037 ctx = logcmdutil.revsingle(repo, rev, None)
4035
4038
4036 if ctx.rev() is None:
4039 if ctx.rev() is None:
4037 ctx = repo[None]
4040 ctx = repo[None]
4038 parents = ctx.parents()
4041 parents = ctx.parents()
4039 taglist = []
4042 taglist = []
4040 for p in parents:
4043 for p in parents:
4041 taglist.extend(p.tags())
4044 taglist.extend(p.tags())
4042
4045
4043 dirty = b""
4046 dirty = b""
4044 if ctx.dirty(missing=True, merge=False, branch=False):
4047 if ctx.dirty(missing=True, merge=False, branch=False):
4045 dirty = b'+'
4048 dirty = b'+'
4046 fm.data(dirty=dirty)
4049 fm.data(dirty=dirty)
4047
4050
4048 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4051 hexoutput = [fm.hexfunc(p.node()) for p in parents]
4049 if default or id:
4052 if default or id:
4050 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4053 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4051 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4054 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4052
4055
4053 if num:
4056 if num:
4054 numoutput = [b"%d" % p.rev() for p in parents]
4057 numoutput = [b"%d" % p.rev() for p in parents]
4055 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4058 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4056
4059
4057 fm.data(
4060 fm.data(
4058 parents=fm.formatlist(
4061 parents=fm.formatlist(
4059 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4062 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4060 )
4063 )
4061 )
4064 )
4062 else:
4065 else:
4063 hexoutput = fm.hexfunc(ctx.node())
4066 hexoutput = fm.hexfunc(ctx.node())
4064 if default or id:
4067 if default or id:
4065 output = [hexoutput]
4068 output = [hexoutput]
4066 fm.data(id=hexoutput)
4069 fm.data(id=hexoutput)
4067
4070
4068 if num:
4071 if num:
4069 output.append(pycompat.bytestr(ctx.rev()))
4072 output.append(pycompat.bytestr(ctx.rev()))
4070 taglist = ctx.tags()
4073 taglist = ctx.tags()
4071
4074
4072 if default and not ui.quiet:
4075 if default and not ui.quiet:
4073 b = ctx.branch()
4076 b = ctx.branch()
4074 if b != b'default':
4077 if b != b'default':
4075 output.append(b"(%s)" % b)
4078 output.append(b"(%s)" % b)
4076
4079
4077 # multiple tags for a single parent separated by '/'
4080 # multiple tags for a single parent separated by '/'
4078 t = b'/'.join(taglist)
4081 t = b'/'.join(taglist)
4079 if t:
4082 if t:
4080 output.append(t)
4083 output.append(t)
4081
4084
4082 # multiple bookmarks for a single parent separated by '/'
4085 # multiple bookmarks for a single parent separated by '/'
4083 bm = b'/'.join(ctx.bookmarks())
4086 bm = b'/'.join(ctx.bookmarks())
4084 if bm:
4087 if bm:
4085 output.append(bm)
4088 output.append(bm)
4086 else:
4089 else:
4087 if branch:
4090 if branch:
4088 output.append(ctx.branch())
4091 output.append(ctx.branch())
4089
4092
4090 if tags:
4093 if tags:
4091 output.extend(taglist)
4094 output.extend(taglist)
4092
4095
4093 if bookmarks:
4096 if bookmarks:
4094 output.extend(ctx.bookmarks())
4097 output.extend(ctx.bookmarks())
4095
4098
4096 fm.data(node=ctx.hex())
4099 fm.data(node=ctx.hex())
4097 fm.data(branch=ctx.branch())
4100 fm.data(branch=ctx.branch())
4098 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4101 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4099 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4102 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4100 fm.context(ctx=ctx)
4103 fm.context(ctx=ctx)
4101
4104
4102 fm.plain(b"%s\n" % b' '.join(output))
4105 fm.plain(b"%s\n" % b' '.join(output))
4103 fm.end()
4106 fm.end()
4104 finally:
4107 finally:
4105 if peer:
4108 if peer:
4106 peer.close()
4109 peer.close()
4107
4110
4108
4111
4109 @command(
4112 @command(
4110 b'import|patch',
4113 b'import|patch',
4111 [
4114 [
4112 (
4115 (
4113 b'p',
4116 b'p',
4114 b'strip',
4117 b'strip',
4115 1,
4118 1,
4116 _(
4119 _(
4117 b'directory strip option for patch. This has the same '
4120 b'directory strip option for patch. This has the same '
4118 b'meaning as the corresponding patch option'
4121 b'meaning as the corresponding patch option'
4119 ),
4122 ),
4120 _(b'NUM'),
4123 _(b'NUM'),
4121 ),
4124 ),
4122 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4125 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4123 (b'', b'secret', None, _(b'use the secret phase for committing')),
4126 (b'', b'secret', None, _(b'use the secret phase for committing')),
4124 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4127 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4125 (
4128 (
4126 b'f',
4129 b'f',
4127 b'force',
4130 b'force',
4128 None,
4131 None,
4129 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4132 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4130 ),
4133 ),
4131 (
4134 (
4132 b'',
4135 b'',
4133 b'no-commit',
4136 b'no-commit',
4134 None,
4137 None,
4135 _(b"don't commit, just update the working directory"),
4138 _(b"don't commit, just update the working directory"),
4136 ),
4139 ),
4137 (
4140 (
4138 b'',
4141 b'',
4139 b'bypass',
4142 b'bypass',
4140 None,
4143 None,
4141 _(b"apply patch without touching the working directory"),
4144 _(b"apply patch without touching the working directory"),
4142 ),
4145 ),
4143 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4146 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4144 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4147 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4145 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4148 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4146 (
4149 (
4147 b'',
4150 b'',
4148 b'import-branch',
4151 b'import-branch',
4149 None,
4152 None,
4150 _(b'use any branch information in patch (implied by --exact)'),
4153 _(b'use any branch information in patch (implied by --exact)'),
4151 ),
4154 ),
4152 ]
4155 ]
4153 + commitopts
4156 + commitopts
4154 + commitopts2
4157 + commitopts2
4155 + similarityopts,
4158 + similarityopts,
4156 _(b'[OPTION]... PATCH...'),
4159 _(b'[OPTION]... PATCH...'),
4157 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4160 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4158 )
4161 )
4159 def import_(ui, repo, patch1=None, *patches, **opts):
4162 def import_(ui, repo, patch1=None, *patches, **opts):
4160 """import an ordered set of patches
4163 """import an ordered set of patches
4161
4164
4162 Import a list of patches and commit them individually (unless
4165 Import a list of patches and commit them individually (unless
4163 --no-commit is specified).
4166 --no-commit is specified).
4164
4167
4165 To read a patch from standard input (stdin), use "-" as the patch
4168 To read a patch from standard input (stdin), use "-" as the patch
4166 name. If a URL is specified, the patch will be downloaded from
4169 name. If a URL is specified, the patch will be downloaded from
4167 there.
4170 there.
4168
4171
4169 Import first applies changes to the working directory (unless
4172 Import first applies changes to the working directory (unless
4170 --bypass is specified), import will abort if there are outstanding
4173 --bypass is specified), import will abort if there are outstanding
4171 changes.
4174 changes.
4172
4175
4173 Use --bypass to apply and commit patches directly to the
4176 Use --bypass to apply and commit patches directly to the
4174 repository, without affecting the working directory. Without
4177 repository, without affecting the working directory. Without
4175 --exact, patches will be applied on top of the working directory
4178 --exact, patches will be applied on top of the working directory
4176 parent revision.
4179 parent revision.
4177
4180
4178 You can import a patch straight from a mail message. Even patches
4181 You can import a patch straight from a mail message. Even patches
4179 as attachments work (to use the body part, it must have type
4182 as attachments work (to use the body part, it must have type
4180 text/plain or text/x-patch). From and Subject headers of email
4183 text/plain or text/x-patch). From and Subject headers of email
4181 message are used as default committer and commit message. All
4184 message are used as default committer and commit message. All
4182 text/plain body parts before first diff are added to the commit
4185 text/plain body parts before first diff are added to the commit
4183 message.
4186 message.
4184
4187
4185 If the imported patch was generated by :hg:`export`, user and
4188 If the imported patch was generated by :hg:`export`, user and
4186 description from patch override values from message headers and
4189 description from patch override values from message headers and
4187 body. Values given on command line with -m/--message and -u/--user
4190 body. Values given on command line with -m/--message and -u/--user
4188 override these.
4191 override these.
4189
4192
4190 If --exact is specified, import will set the working directory to
4193 If --exact is specified, import will set the working directory to
4191 the parent of each patch before applying it, and will abort if the
4194 the parent of each patch before applying it, and will abort if the
4192 resulting changeset has a different ID than the one recorded in
4195 resulting changeset has a different ID than the one recorded in
4193 the patch. This will guard against various ways that portable
4196 the patch. This will guard against various ways that portable
4194 patch formats and mail systems might fail to transfer Mercurial
4197 patch formats and mail systems might fail to transfer Mercurial
4195 data or metadata. See :hg:`bundle` for lossless transmission.
4198 data or metadata. See :hg:`bundle` for lossless transmission.
4196
4199
4197 Use --partial to ensure a changeset will be created from the patch
4200 Use --partial to ensure a changeset will be created from the patch
4198 even if some hunks fail to apply. Hunks that fail to apply will be
4201 even if some hunks fail to apply. Hunks that fail to apply will be
4199 written to a <target-file>.rej file. Conflicts can then be resolved
4202 written to a <target-file>.rej file. Conflicts can then be resolved
4200 by hand before :hg:`commit --amend` is run to update the created
4203 by hand before :hg:`commit --amend` is run to update the created
4201 changeset. This flag exists to let people import patches that
4204 changeset. This flag exists to let people import patches that
4202 partially apply without losing the associated metadata (author,
4205 partially apply without losing the associated metadata (author,
4203 date, description, ...).
4206 date, description, ...).
4204
4207
4205 .. note::
4208 .. note::
4206
4209
4207 When no hunks apply cleanly, :hg:`import --partial` will create
4210 When no hunks apply cleanly, :hg:`import --partial` will create
4208 an empty changeset, importing only the patch metadata.
4211 an empty changeset, importing only the patch metadata.
4209
4212
4210 With -s/--similarity, hg will attempt to discover renames and
4213 With -s/--similarity, hg will attempt to discover renames and
4211 copies in the patch in the same way as :hg:`addremove`.
4214 copies in the patch in the same way as :hg:`addremove`.
4212
4215
4213 It is possible to use external patch programs to perform the patch
4216 It is possible to use external patch programs to perform the patch
4214 by setting the ``ui.patch`` configuration option. For the default
4217 by setting the ``ui.patch`` configuration option. For the default
4215 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4218 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4216 See :hg:`help config` for more information about configuration
4219 See :hg:`help config` for more information about configuration
4217 files and how to use these options.
4220 files and how to use these options.
4218
4221
4219 See :hg:`help dates` for a list of formats valid for -d/--date.
4222 See :hg:`help dates` for a list of formats valid for -d/--date.
4220
4223
4221 .. container:: verbose
4224 .. container:: verbose
4222
4225
4223 Examples:
4226 Examples:
4224
4227
4225 - import a traditional patch from a website and detect renames::
4228 - import a traditional patch from a website and detect renames::
4226
4229
4227 hg import -s 80 http://example.com/bugfix.patch
4230 hg import -s 80 http://example.com/bugfix.patch
4228
4231
4229 - import a changeset from an hgweb server::
4232 - import a changeset from an hgweb server::
4230
4233
4231 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4234 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4232
4235
4233 - import all the patches in an Unix-style mbox::
4236 - import all the patches in an Unix-style mbox::
4234
4237
4235 hg import incoming-patches.mbox
4238 hg import incoming-patches.mbox
4236
4239
4237 - import patches from stdin::
4240 - import patches from stdin::
4238
4241
4239 hg import -
4242 hg import -
4240
4243
4241 - attempt to exactly restore an exported changeset (not always
4244 - attempt to exactly restore an exported changeset (not always
4242 possible)::
4245 possible)::
4243
4246
4244 hg import --exact proposed-fix.patch
4247 hg import --exact proposed-fix.patch
4245
4248
4246 - use an external tool to apply a patch which is too fuzzy for
4249 - use an external tool to apply a patch which is too fuzzy for
4247 the default internal tool.
4250 the default internal tool.
4248
4251
4249 hg import --config ui.patch="patch --merge" fuzzy.patch
4252 hg import --config ui.patch="patch --merge" fuzzy.patch
4250
4253
4251 - change the default fuzzing from 2 to a less strict 7
4254 - change the default fuzzing from 2 to a less strict 7
4252
4255
4253 hg import --config ui.fuzz=7 fuzz.patch
4256 hg import --config ui.fuzz=7 fuzz.patch
4254
4257
4255 Returns 0 on success, 1 on partial success (see --partial).
4258 Returns 0 on success, 1 on partial success (see --partial).
4256 """
4259 """
4257
4260
4258 cmdutil.check_incompatible_arguments(
4261 cmdutil.check_incompatible_arguments(
4259 opts, 'no_commit', ['bypass', 'secret']
4262 opts, 'no_commit', ['bypass', 'secret']
4260 )
4263 )
4261 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4264 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4262
4265
4263 if not patch1:
4266 if not patch1:
4264 raise error.InputError(_(b'need at least one patch to import'))
4267 raise error.InputError(_(b'need at least one patch to import'))
4265
4268
4266 patches = (patch1,) + patches
4269 patches = (patch1,) + patches
4267
4270
4268 date = opts.get('date')
4271 date = opts.get('date')
4269 if date:
4272 if date:
4270 opts['date'] = dateutil.parsedate(date)
4273 opts['date'] = dateutil.parsedate(date)
4271
4274
4272 exact = opts.get('exact')
4275 exact = opts.get('exact')
4273 update = not opts.get('bypass')
4276 update = not opts.get('bypass')
4274 try:
4277 try:
4275 sim = float(opts.get('similarity') or 0)
4278 sim = float(opts.get('similarity') or 0)
4276 except ValueError:
4279 except ValueError:
4277 raise error.InputError(_(b'similarity must be a number'))
4280 raise error.InputError(_(b'similarity must be a number'))
4278 if sim < 0 or sim > 100:
4281 if sim < 0 or sim > 100:
4279 raise error.InputError(_(b'similarity must be between 0 and 100'))
4282 raise error.InputError(_(b'similarity must be between 0 and 100'))
4280 if sim and not update:
4283 if sim and not update:
4281 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4284 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4282
4285
4283 base = opts["base"]
4286 base = opts["base"]
4284 msgs = []
4287 msgs = []
4285 ret = 0
4288 ret = 0
4286
4289
4287 with repo.wlock():
4290 with repo.wlock():
4288 if update:
4291 if update:
4289 cmdutil.checkunfinished(repo)
4292 cmdutil.checkunfinished(repo)
4290 if exact or not opts.get('force'):
4293 if exact or not opts.get('force'):
4291 cmdutil.bailifchanged(repo)
4294 cmdutil.bailifchanged(repo)
4292
4295
4293 if not opts.get('no_commit'):
4296 if not opts.get('no_commit'):
4294 lock = repo.lock
4297 lock = repo.lock
4295 tr = lambda: repo.transaction(b'import')
4298 tr = lambda: repo.transaction(b'import')
4296 else:
4299 else:
4297 lock = util.nullcontextmanager
4300 lock = util.nullcontextmanager
4298 tr = util.nullcontextmanager
4301 tr = util.nullcontextmanager
4299 with lock(), tr():
4302 with lock(), tr():
4300 parents = repo[None].parents()
4303 parents = repo[None].parents()
4301 for patchurl in patches:
4304 for patchurl in patches:
4302 if patchurl == b'-':
4305 if patchurl == b'-':
4303 ui.status(_(b'applying patch from stdin\n'))
4306 ui.status(_(b'applying patch from stdin\n'))
4304 patchfile = ui.fin
4307 patchfile = ui.fin
4305 patchurl = b'stdin' # for error message
4308 patchurl = b'stdin' # for error message
4306 else:
4309 else:
4307 patchurl = os.path.join(base, patchurl)
4310 patchurl = os.path.join(base, patchurl)
4308 ui.status(_(b'applying %s\n') % patchurl)
4311 ui.status(_(b'applying %s\n') % patchurl)
4309 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4312 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4310
4313
4311 haspatch = False
4314 haspatch = False
4312 for hunk in patch.split(patchfile):
4315 for hunk in patch.split(patchfile):
4313 with patch.extract(ui, hunk) as patchdata:
4316 with patch.extract(ui, hunk) as patchdata:
4314 msg, node, rej = cmdutil.tryimportone(
4317 msg, node, rej = cmdutil.tryimportone(
4315 ui,
4318 ui,
4316 repo,
4319 repo,
4317 patchdata,
4320 patchdata,
4318 parents,
4321 parents,
4319 pycompat.byteskwargs(opts),
4322 pycompat.byteskwargs(opts),
4320 msgs,
4323 msgs,
4321 hg.clean,
4324 hg.clean,
4322 )
4325 )
4323 if msg:
4326 if msg:
4324 haspatch = True
4327 haspatch = True
4325 ui.note(msg + b'\n')
4328 ui.note(msg + b'\n')
4326 if update or exact:
4329 if update or exact:
4327 parents = repo[None].parents()
4330 parents = repo[None].parents()
4328 else:
4331 else:
4329 parents = [repo[node]]
4332 parents = [repo[node]]
4330 if rej:
4333 if rej:
4331 ui.write_err(_(b"patch applied partially\n"))
4334 ui.write_err(_(b"patch applied partially\n"))
4332 ui.write_err(
4335 ui.write_err(
4333 _(
4336 _(
4334 b"(fix the .rej files and run "
4337 b"(fix the .rej files and run "
4335 b"`hg commit --amend`)\n"
4338 b"`hg commit --amend`)\n"
4336 )
4339 )
4337 )
4340 )
4338 ret = 1
4341 ret = 1
4339 break
4342 break
4340
4343
4341 if not haspatch:
4344 if not haspatch:
4342 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4345 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4343
4346
4344 if msgs:
4347 if msgs:
4345 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4348 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4346 return ret
4349 return ret
4347
4350
4348
4351
4349 @command(
4352 @command(
4350 b'incoming|in',
4353 b'incoming|in',
4351 [
4354 [
4352 (
4355 (
4353 b'f',
4356 b'f',
4354 b'force',
4357 b'force',
4355 None,
4358 None,
4356 _(b'run even if remote repository is unrelated'),
4359 _(b'run even if remote repository is unrelated'),
4357 ),
4360 ),
4358 (b'n', b'newest-first', None, _(b'show newest record first')),
4361 (b'n', b'newest-first', None, _(b'show newest record first')),
4359 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4362 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4360 (
4363 (
4361 b'r',
4364 b'r',
4362 b'rev',
4365 b'rev',
4363 [],
4366 [],
4364 _(b'a remote changeset intended to be added'),
4367 _(b'a remote changeset intended to be added'),
4365 _(b'REV'),
4368 _(b'REV'),
4366 ),
4369 ),
4367 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4370 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4368 (
4371 (
4369 b'b',
4372 b'b',
4370 b'branch',
4373 b'branch',
4371 [],
4374 [],
4372 _(b'a specific branch you would like to pull'),
4375 _(b'a specific branch you would like to pull'),
4373 _(b'BRANCH'),
4376 _(b'BRANCH'),
4374 ),
4377 ),
4375 ]
4378 ]
4376 + logopts
4379 + logopts
4377 + remoteopts
4380 + remoteopts
4378 + subrepoopts,
4381 + subrepoopts,
4379 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4382 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4380 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4383 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4381 )
4384 )
4382 def incoming(ui, repo, source=b"default", **opts):
4385 def incoming(ui, repo, source=b"default", **opts):
4383 """show new changesets found in source
4386 """show new changesets found in source
4384
4387
4385 Show new changesets found in the specified path/URL or the default
4388 Show new changesets found in the specified path/URL or the default
4386 pull location. These are the changesets that would have been pulled
4389 pull location. These are the changesets that would have been pulled
4387 by :hg:`pull` at the time you issued this command.
4390 by :hg:`pull` at the time you issued this command.
4388
4391
4389 See pull for valid source format details.
4392 See pull for valid source format details.
4390
4393
4391 .. container:: verbose
4394 .. container:: verbose
4392
4395
4393 With -B/--bookmarks, the result of bookmark comparison between
4396 With -B/--bookmarks, the result of bookmark comparison between
4394 local and remote repositories is displayed. With -v/--verbose,
4397 local and remote repositories is displayed. With -v/--verbose,
4395 status is also displayed for each bookmark like below::
4398 status is also displayed for each bookmark like below::
4396
4399
4397 BM1 01234567890a added
4400 BM1 01234567890a added
4398 BM2 1234567890ab advanced
4401 BM2 1234567890ab advanced
4399 BM3 234567890abc diverged
4402 BM3 234567890abc diverged
4400 BM4 34567890abcd changed
4403 BM4 34567890abcd changed
4401
4404
4402 The action taken locally when pulling depends on the
4405 The action taken locally when pulling depends on the
4403 status of each bookmark:
4406 status of each bookmark:
4404
4407
4405 :``added``: pull will create it
4408 :``added``: pull will create it
4406 :``advanced``: pull will update it
4409 :``advanced``: pull will update it
4407 :``diverged``: pull will create a divergent bookmark
4410 :``diverged``: pull will create a divergent bookmark
4408 :``changed``: result depends on remote changesets
4411 :``changed``: result depends on remote changesets
4409
4412
4410 From the point of view of pulling behavior, bookmark
4413 From the point of view of pulling behavior, bookmark
4411 existing only in the remote repository are treated as ``added``,
4414 existing only in the remote repository are treated as ``added``,
4412 even if it is in fact locally deleted.
4415 even if it is in fact locally deleted.
4413
4416
4414 .. container:: verbose
4417 .. container:: verbose
4415
4418
4416 For remote repository, using --bundle avoids downloading the
4419 For remote repository, using --bundle avoids downloading the
4417 changesets twice if the incoming is followed by a pull.
4420 changesets twice if the incoming is followed by a pull.
4418
4421
4419 Examples:
4422 Examples:
4420
4423
4421 - show incoming changes with patches and full description::
4424 - show incoming changes with patches and full description::
4422
4425
4423 hg incoming -vp
4426 hg incoming -vp
4424
4427
4425 - show incoming changes excluding merges, store a bundle::
4428 - show incoming changes excluding merges, store a bundle::
4426
4429
4427 hg in -vpM --bundle incoming.hg
4430 hg in -vpM --bundle incoming.hg
4428 hg pull incoming.hg
4431 hg pull incoming.hg
4429
4432
4430 - briefly list changes inside a bundle::
4433 - briefly list changes inside a bundle::
4431
4434
4432 hg in changes.hg -T "{desc|firstline}\\n"
4435 hg in changes.hg -T "{desc|firstline}\\n"
4433
4436
4434 Returns 0 if there are incoming changes, 1 otherwise.
4437 Returns 0 if there are incoming changes, 1 otherwise.
4435 """
4438 """
4436 opts = pycompat.byteskwargs(opts)
4439 opts = pycompat.byteskwargs(opts)
4437 if opts.get(b'graph'):
4440 if opts.get(b'graph'):
4438 logcmdutil.checkunsupportedgraphflags([], opts)
4441 logcmdutil.checkunsupportedgraphflags([], opts)
4439
4442
4440 def display(other, chlist, displayer):
4443 def display(other, chlist, displayer):
4441 revdag = logcmdutil.graphrevs(other, chlist, opts)
4444 revdag = logcmdutil.graphrevs(other, chlist, opts)
4442 logcmdutil.displaygraph(
4445 logcmdutil.displaygraph(
4443 ui, repo, revdag, displayer, graphmod.asciiedges
4446 ui, repo, revdag, displayer, graphmod.asciiedges
4444 )
4447 )
4445
4448
4446 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4449 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4447 return 0
4450 return 0
4448
4451
4449 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4452 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4450
4453
4451 if opts.get(b'bookmarks'):
4454 if opts.get(b'bookmarks'):
4452 srcs = urlutil.get_pull_paths(repo, ui, [source])
4455 srcs = urlutil.get_pull_paths(repo, ui, [source])
4453 for path in srcs:
4456 for path in srcs:
4454 # XXX the "branches" options are not used. Should it be used?
4457 # XXX the "branches" options are not used. Should it be used?
4455 other = hg.peer(repo, opts, path)
4458 other = hg.peer(repo, opts, path)
4456 try:
4459 try:
4457 if b'bookmarks' not in other.listkeys(b'namespaces'):
4460 if b'bookmarks' not in other.listkeys(b'namespaces'):
4458 ui.warn(_(b"remote doesn't support bookmarks\n"))
4461 ui.warn(_(b"remote doesn't support bookmarks\n"))
4459 return 0
4462 return 0
4460 ui.pager(b'incoming')
4463 ui.pager(b'incoming')
4461 ui.status(
4464 ui.status(
4462 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4465 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4463 )
4466 )
4464 return bookmarks.incoming(
4467 return bookmarks.incoming(
4465 ui, repo, other, mode=path.bookmarks_mode
4468 ui, repo, other, mode=path.bookmarks_mode
4466 )
4469 )
4467 finally:
4470 finally:
4468 other.close()
4471 other.close()
4469
4472
4470 return hg.incoming(ui, repo, source, opts)
4473 return hg.incoming(ui, repo, source, opts)
4471
4474
4472
4475
4473 @command(
4476 @command(
4474 b'init',
4477 b'init',
4475 remoteopts,
4478 remoteopts,
4476 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4479 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4477 helpcategory=command.CATEGORY_REPO_CREATION,
4480 helpcategory=command.CATEGORY_REPO_CREATION,
4478 helpbasic=True,
4481 helpbasic=True,
4479 norepo=True,
4482 norepo=True,
4480 )
4483 )
4481 def init(ui, dest=b".", **opts):
4484 def init(ui, dest=b".", **opts):
4482 """create a new repository in the given directory
4485 """create a new repository in the given directory
4483
4486
4484 Initialize a new repository in the given directory. If the given
4487 Initialize a new repository in the given directory. If the given
4485 directory does not exist, it will be created.
4488 directory does not exist, it will be created.
4486
4489
4487 If no directory is given, the current directory is used.
4490 If no directory is given, the current directory is used.
4488
4491
4489 It is possible to specify an ``ssh://`` URL as the destination.
4492 It is possible to specify an ``ssh://`` URL as the destination.
4490 See :hg:`help urls` for more information.
4493 See :hg:`help urls` for more information.
4491
4494
4492 Returns 0 on success.
4495 Returns 0 on success.
4493 """
4496 """
4494 opts = pycompat.byteskwargs(opts)
4497 opts = pycompat.byteskwargs(opts)
4495 path = urlutil.get_clone_path_obj(ui, dest)
4498 path = urlutil.get_clone_path_obj(ui, dest)
4496 peer = hg.peer(ui, opts, path, create=True)
4499 peer = hg.peer(ui, opts, path, create=True)
4497 peer.close()
4500 peer.close()
4498
4501
4499
4502
4500 @command(
4503 @command(
4501 b'locate',
4504 b'locate',
4502 [
4505 [
4503 (
4506 (
4504 b'r',
4507 b'r',
4505 b'rev',
4508 b'rev',
4506 b'',
4509 b'',
4507 _(b'search the repository as it is in REV'),
4510 _(b'search the repository as it is in REV'),
4508 _(b'REV'),
4511 _(b'REV'),
4509 ),
4512 ),
4510 (
4513 (
4511 b'0',
4514 b'0',
4512 b'print0',
4515 b'print0',
4513 None,
4516 None,
4514 _(b'end filenames with NUL, for use with xargs'),
4517 _(b'end filenames with NUL, for use with xargs'),
4515 ),
4518 ),
4516 (
4519 (
4517 b'f',
4520 b'f',
4518 b'fullpath',
4521 b'fullpath',
4519 None,
4522 None,
4520 _(b'print complete paths from the filesystem root'),
4523 _(b'print complete paths from the filesystem root'),
4521 ),
4524 ),
4522 ]
4525 ]
4523 + walkopts,
4526 + walkopts,
4524 _(b'[OPTION]... [PATTERN]...'),
4527 _(b'[OPTION]... [PATTERN]...'),
4525 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4528 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4526 )
4529 )
4527 def locate(ui, repo, *pats, **opts):
4530 def locate(ui, repo, *pats, **opts):
4528 """locate files matching specific patterns (DEPRECATED)
4531 """locate files matching specific patterns (DEPRECATED)
4529
4532
4530 Print files under Mercurial control in the working directory whose
4533 Print files under Mercurial control in the working directory whose
4531 names match the given patterns.
4534 names match the given patterns.
4532
4535
4533 By default, this command searches all directories in the working
4536 By default, this command searches all directories in the working
4534 directory. To search just the current directory and its
4537 directory. To search just the current directory and its
4535 subdirectories, use "--include .".
4538 subdirectories, use "--include .".
4536
4539
4537 If no patterns are given to match, this command prints the names
4540 If no patterns are given to match, this command prints the names
4538 of all files under Mercurial control in the working directory.
4541 of all files under Mercurial control in the working directory.
4539
4542
4540 If you want to feed the output of this command into the "xargs"
4543 If you want to feed the output of this command into the "xargs"
4541 command, use the -0 option to both this command and "xargs". This
4544 command, use the -0 option to both this command and "xargs". This
4542 will avoid the problem of "xargs" treating single filenames that
4545 will avoid the problem of "xargs" treating single filenames that
4543 contain whitespace as multiple filenames.
4546 contain whitespace as multiple filenames.
4544
4547
4545 See :hg:`help files` for a more versatile command.
4548 See :hg:`help files` for a more versatile command.
4546
4549
4547 Returns 0 if a match is found, 1 otherwise.
4550 Returns 0 if a match is found, 1 otherwise.
4548 """
4551 """
4549 if opts.get('print0'):
4552 if opts.get('print0'):
4550 end = b'\0'
4553 end = b'\0'
4551 else:
4554 else:
4552 end = b'\n'
4555 end = b'\n'
4553 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4556 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4554
4557
4555 ret = 1
4558 ret = 1
4556 m = scmutil.match(
4559 m = scmutil.match(
4557 ctx,
4560 ctx,
4558 pats,
4561 pats,
4559 pycompat.byteskwargs(opts),
4562 pycompat.byteskwargs(opts),
4560 default=b'relglob',
4563 default=b'relglob',
4561 badfn=lambda x, y: False,
4564 badfn=lambda x, y: False,
4562 )
4565 )
4563
4566
4564 ui.pager(b'locate')
4567 ui.pager(b'locate')
4565 if ctx.rev() is None:
4568 if ctx.rev() is None:
4566 # When run on the working copy, "locate" includes removed files, so
4569 # When run on the working copy, "locate" includes removed files, so
4567 # we get the list of files from the dirstate.
4570 # we get the list of files from the dirstate.
4568 filesgen = sorted(repo.dirstate.matches(m))
4571 filesgen = sorted(repo.dirstate.matches(m))
4569 else:
4572 else:
4570 filesgen = ctx.matches(m)
4573 filesgen = ctx.matches(m)
4571 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4574 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4572 for abs in filesgen:
4575 for abs in filesgen:
4573 if opts.get('fullpath'):
4576 if opts.get('fullpath'):
4574 ui.write(repo.wjoin(abs), end)
4577 ui.write(repo.wjoin(abs), end)
4575 else:
4578 else:
4576 ui.write(uipathfn(abs), end)
4579 ui.write(uipathfn(abs), end)
4577 ret = 0
4580 ret = 0
4578
4581
4579 return ret
4582 return ret
4580
4583
4581
4584
4582 @command(
4585 @command(
4583 b'log|history',
4586 b'log|history',
4584 [
4587 [
4585 (
4588 (
4586 b'f',
4589 b'f',
4587 b'follow',
4590 b'follow',
4588 None,
4591 None,
4589 _(
4592 _(
4590 b'follow changeset history, or file history across copies and renames'
4593 b'follow changeset history, or file history across copies and renames'
4591 ),
4594 ),
4592 ),
4595 ),
4593 (
4596 (
4594 b'',
4597 b'',
4595 b'follow-first',
4598 b'follow-first',
4596 None,
4599 None,
4597 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4600 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4598 ),
4601 ),
4599 (
4602 (
4600 b'd',
4603 b'd',
4601 b'date',
4604 b'date',
4602 b'',
4605 b'',
4603 _(b'show revisions matching date spec'),
4606 _(b'show revisions matching date spec'),
4604 _(b'DATE'),
4607 _(b'DATE'),
4605 ),
4608 ),
4606 (b'C', b'copies', None, _(b'show copied files')),
4609 (b'C', b'copies', None, _(b'show copied files')),
4607 (
4610 (
4608 b'k',
4611 b'k',
4609 b'keyword',
4612 b'keyword',
4610 [],
4613 [],
4611 _(b'do case-insensitive search for a given text'),
4614 _(b'do case-insensitive search for a given text'),
4612 _(b'TEXT'),
4615 _(b'TEXT'),
4613 ),
4616 ),
4614 (
4617 (
4615 b'r',
4618 b'r',
4616 b'rev',
4619 b'rev',
4617 [],
4620 [],
4618 _(b'revisions to select or follow from'),
4621 _(b'revisions to select or follow from'),
4619 _(b'REV'),
4622 _(b'REV'),
4620 ),
4623 ),
4621 (
4624 (
4622 b'L',
4625 b'L',
4623 b'line-range',
4626 b'line-range',
4624 [],
4627 [],
4625 _(b'follow line range of specified file (EXPERIMENTAL)'),
4628 _(b'follow line range of specified file (EXPERIMENTAL)'),
4626 _(b'FILE,RANGE'),
4629 _(b'FILE,RANGE'),
4627 ),
4630 ),
4628 (
4631 (
4629 b'',
4632 b'',
4630 b'removed',
4633 b'removed',
4631 None,
4634 None,
4632 _(b'include revisions where files were removed'),
4635 _(b'include revisions where files were removed'),
4633 ),
4636 ),
4634 (
4637 (
4635 b'm',
4638 b'm',
4636 b'only-merges',
4639 b'only-merges',
4637 None,
4640 None,
4638 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4641 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4639 ),
4642 ),
4640 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4643 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4641 (
4644 (
4642 b'',
4645 b'',
4643 b'only-branch',
4646 b'only-branch',
4644 [],
4647 [],
4645 _(
4648 _(
4646 b'show only changesets within the given named branch (DEPRECATED)'
4649 b'show only changesets within the given named branch (DEPRECATED)'
4647 ),
4650 ),
4648 _(b'BRANCH'),
4651 _(b'BRANCH'),
4649 ),
4652 ),
4650 (
4653 (
4651 b'b',
4654 b'b',
4652 b'branch',
4655 b'branch',
4653 [],
4656 [],
4654 _(b'show changesets within the given named branch'),
4657 _(b'show changesets within the given named branch'),
4655 _(b'BRANCH'),
4658 _(b'BRANCH'),
4656 ),
4659 ),
4657 (
4660 (
4658 b'B',
4661 b'B',
4659 b'bookmark',
4662 b'bookmark',
4660 [],
4663 [],
4661 _(b"show changesets within the given bookmark"),
4664 _(b"show changesets within the given bookmark"),
4662 _(b'BOOKMARK'),
4665 _(b'BOOKMARK'),
4663 ),
4666 ),
4664 (
4667 (
4665 b'P',
4668 b'P',
4666 b'prune',
4669 b'prune',
4667 [],
4670 [],
4668 _(b'do not display revision or any of its ancestors'),
4671 _(b'do not display revision or any of its ancestors'),
4669 _(b'REV'),
4672 _(b'REV'),
4670 ),
4673 ),
4671 ]
4674 ]
4672 + logopts
4675 + logopts
4673 + walkopts,
4676 + walkopts,
4674 _(b'[OPTION]... [FILE]'),
4677 _(b'[OPTION]... [FILE]'),
4675 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4678 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4676 helpbasic=True,
4679 helpbasic=True,
4677 inferrepo=True,
4680 inferrepo=True,
4678 intents={INTENT_READONLY},
4681 intents={INTENT_READONLY},
4679 )
4682 )
4680 def log(ui, repo, *pats, **opts):
4683 def log(ui, repo, *pats, **opts):
4681 """show revision history of entire repository or files
4684 """show revision history of entire repository or files
4682
4685
4683 Print the revision history of the specified files or the entire
4686 Print the revision history of the specified files or the entire
4684 project.
4687 project.
4685
4688
4686 If no revision range is specified, the default is ``tip:0`` unless
4689 If no revision range is specified, the default is ``tip:0`` unless
4687 --follow is set.
4690 --follow is set.
4688
4691
4689 File history is shown without following rename or copy history of
4692 File history is shown without following rename or copy history of
4690 files. Use -f/--follow with a filename to follow history across
4693 files. Use -f/--follow with a filename to follow history across
4691 renames and copies. --follow without a filename will only show
4694 renames and copies. --follow without a filename will only show
4692 ancestors of the starting revisions. The starting revisions can be
4695 ancestors of the starting revisions. The starting revisions can be
4693 specified by -r/--rev, which default to the working directory parent.
4696 specified by -r/--rev, which default to the working directory parent.
4694
4697
4695 By default this command prints revision number and changeset id,
4698 By default this command prints revision number and changeset id,
4696 tags, non-trivial parents, user, date and time, and a summary for
4699 tags, non-trivial parents, user, date and time, and a summary for
4697 each commit. When the -v/--verbose switch is used, the list of
4700 each commit. When the -v/--verbose switch is used, the list of
4698 changed files and full commit message are shown.
4701 changed files and full commit message are shown.
4699
4702
4700 With --graph the revisions are shown as an ASCII art DAG with the most
4703 With --graph the revisions are shown as an ASCII art DAG with the most
4701 recent changeset at the top.
4704 recent changeset at the top.
4702 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4705 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4703 involved in an unresolved merge conflict, '_' closes a branch,
4706 involved in an unresolved merge conflict, '_' closes a branch,
4704 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4707 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4705 changeset from the lines below is a parent of the 'o' merge on the same
4708 changeset from the lines below is a parent of the 'o' merge on the same
4706 line.
4709 line.
4707 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4710 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4708 of a '|' indicates one or more revisions in a path are omitted.
4711 of a '|' indicates one or more revisions in a path are omitted.
4709
4712
4710 .. container:: verbose
4713 .. container:: verbose
4711
4714
4712 Use -L/--line-range FILE,M:N options to follow the history of lines
4715 Use -L/--line-range FILE,M:N options to follow the history of lines
4713 from M to N in FILE. With -p/--patch only diff hunks affecting
4716 from M to N in FILE. With -p/--patch only diff hunks affecting
4714 specified line range will be shown. This option requires --follow;
4717 specified line range will be shown. This option requires --follow;
4715 it can be specified multiple times. Currently, this option is not
4718 it can be specified multiple times. Currently, this option is not
4716 compatible with --graph. This option is experimental.
4719 compatible with --graph. This option is experimental.
4717
4720
4718 .. note::
4721 .. note::
4719
4722
4720 :hg:`log --patch` may generate unexpected diff output for merge
4723 :hg:`log --patch` may generate unexpected diff output for merge
4721 changesets, as it will only compare the merge changeset against
4724 changesets, as it will only compare the merge changeset against
4722 its first parent. Also, only files different from BOTH parents
4725 its first parent. Also, only files different from BOTH parents
4723 will appear in files:.
4726 will appear in files:.
4724
4727
4725 .. note::
4728 .. note::
4726
4729
4727 For performance reasons, :hg:`log FILE` may omit duplicate changes
4730 For performance reasons, :hg:`log FILE` may omit duplicate changes
4728 made on branches and will not show removals or mode changes. To
4731 made on branches and will not show removals or mode changes. To
4729 see all such changes, use the --removed switch.
4732 see all such changes, use the --removed switch.
4730
4733
4731 .. container:: verbose
4734 .. container:: verbose
4732
4735
4733 .. note::
4736 .. note::
4734
4737
4735 The history resulting from -L/--line-range options depends on diff
4738 The history resulting from -L/--line-range options depends on diff
4736 options; for instance if white-spaces are ignored, respective changes
4739 options; for instance if white-spaces are ignored, respective changes
4737 with only white-spaces in specified line range will not be listed.
4740 with only white-spaces in specified line range will not be listed.
4738
4741
4739 .. container:: verbose
4742 .. container:: verbose
4740
4743
4741 Some examples:
4744 Some examples:
4742
4745
4743 - changesets with full descriptions and file lists::
4746 - changesets with full descriptions and file lists::
4744
4747
4745 hg log -v
4748 hg log -v
4746
4749
4747 - changesets ancestral to the working directory::
4750 - changesets ancestral to the working directory::
4748
4751
4749 hg log -f
4752 hg log -f
4750
4753
4751 - last 10 commits on the current branch::
4754 - last 10 commits on the current branch::
4752
4755
4753 hg log -l 10 -b .
4756 hg log -l 10 -b .
4754
4757
4755 - changesets showing all modifications of a file, including removals::
4758 - changesets showing all modifications of a file, including removals::
4756
4759
4757 hg log --removed file.c
4760 hg log --removed file.c
4758
4761
4759 - all changesets that touch a directory, with diffs, excluding merges::
4762 - all changesets that touch a directory, with diffs, excluding merges::
4760
4763
4761 hg log -Mp lib/
4764 hg log -Mp lib/
4762
4765
4763 - all revision numbers that match a keyword::
4766 - all revision numbers that match a keyword::
4764
4767
4765 hg log -k bug --template "{rev}\\n"
4768 hg log -k bug --template "{rev}\\n"
4766
4769
4767 - the full hash identifier of the working directory parent::
4770 - the full hash identifier of the working directory parent::
4768
4771
4769 hg log -r . --template "{node}\\n"
4772 hg log -r . --template "{node}\\n"
4770
4773
4771 - list available log templates::
4774 - list available log templates::
4772
4775
4773 hg log -T list
4776 hg log -T list
4774
4777
4775 - check if a given changeset is included in a tagged release::
4778 - check if a given changeset is included in a tagged release::
4776
4779
4777 hg log -r "a21ccf and ancestor(1.9)"
4780 hg log -r "a21ccf and ancestor(1.9)"
4778
4781
4779 - find all changesets by some user in a date range::
4782 - find all changesets by some user in a date range::
4780
4783
4781 hg log -k alice -d "may 2008 to jul 2008"
4784 hg log -k alice -d "may 2008 to jul 2008"
4782
4785
4783 - summary of all changesets after the last tag::
4786 - summary of all changesets after the last tag::
4784
4787
4785 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4788 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4786
4789
4787 - changesets touching lines 13 to 23 for file.c::
4790 - changesets touching lines 13 to 23 for file.c::
4788
4791
4789 hg log -L file.c,13:23
4792 hg log -L file.c,13:23
4790
4793
4791 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4794 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4792 main.c with patch::
4795 main.c with patch::
4793
4796
4794 hg log -L file.c,13:23 -L main.c,2:6 -p
4797 hg log -L file.c,13:23 -L main.c,2:6 -p
4795
4798
4796 See :hg:`help dates` for a list of formats valid for -d/--date.
4799 See :hg:`help dates` for a list of formats valid for -d/--date.
4797
4800
4798 See :hg:`help revisions` for more about specifying and ordering
4801 See :hg:`help revisions` for more about specifying and ordering
4799 revisions.
4802 revisions.
4800
4803
4801 See :hg:`help templates` for more about pre-packaged styles and
4804 See :hg:`help templates` for more about pre-packaged styles and
4802 specifying custom templates. The default template used by the log
4805 specifying custom templates. The default template used by the log
4803 command can be customized via the ``command-templates.log`` configuration
4806 command can be customized via the ``command-templates.log`` configuration
4804 setting.
4807 setting.
4805
4808
4806 Returns 0 on success.
4809 Returns 0 on success.
4807
4810
4808 """
4811 """
4809 opts = pycompat.byteskwargs(opts)
4812 opts = pycompat.byteskwargs(opts)
4810 linerange = opts.get(b'line_range')
4813 linerange = opts.get(b'line_range')
4811
4814
4812 if linerange and not opts.get(b'follow'):
4815 if linerange and not opts.get(b'follow'):
4813 raise error.InputError(_(b'--line-range requires --follow'))
4816 raise error.InputError(_(b'--line-range requires --follow'))
4814
4817
4815 if linerange and pats:
4818 if linerange and pats:
4816 # TODO: take pats as patterns with no line-range filter
4819 # TODO: take pats as patterns with no line-range filter
4817 raise error.InputError(
4820 raise error.InputError(
4818 _(b'FILE arguments are not compatible with --line-range option')
4821 _(b'FILE arguments are not compatible with --line-range option')
4819 )
4822 )
4820
4823
4821 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4824 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4822 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4825 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4823 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4826 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4824 if linerange:
4827 if linerange:
4825 # TODO: should follow file history from logcmdutil._initialrevs(),
4828 # TODO: should follow file history from logcmdutil._initialrevs(),
4826 # then filter the result by logcmdutil._makerevset() and --limit
4829 # then filter the result by logcmdutil._makerevset() and --limit
4827 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4830 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4828
4831
4829 getcopies = None
4832 getcopies = None
4830 if opts.get(b'copies'):
4833 if opts.get(b'copies'):
4831 endrev = None
4834 endrev = None
4832 if revs:
4835 if revs:
4833 endrev = revs.max() + 1
4836 endrev = revs.max() + 1
4834 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4837 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4835
4838
4836 ui.pager(b'log')
4839 ui.pager(b'log')
4837 displayer = logcmdutil.changesetdisplayer(
4840 displayer = logcmdutil.changesetdisplayer(
4838 ui, repo, opts, differ, buffered=True
4841 ui, repo, opts, differ, buffered=True
4839 )
4842 )
4840 if opts.get(b'graph'):
4843 if opts.get(b'graph'):
4841 displayfn = logcmdutil.displaygraphrevs
4844 displayfn = logcmdutil.displaygraphrevs
4842 else:
4845 else:
4843 displayfn = logcmdutil.displayrevs
4846 displayfn = logcmdutil.displayrevs
4844 displayfn(ui, repo, revs, displayer, getcopies)
4847 displayfn(ui, repo, revs, displayer, getcopies)
4845
4848
4846
4849
4847 @command(
4850 @command(
4848 b'manifest',
4851 b'manifest',
4849 [
4852 [
4850 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4853 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4851 (b'', b'all', False, _(b"list files from all revisions")),
4854 (b'', b'all', False, _(b"list files from all revisions")),
4852 ]
4855 ]
4853 + formatteropts,
4856 + formatteropts,
4854 _(b'[-r REV]'),
4857 _(b'[-r REV]'),
4855 helpcategory=command.CATEGORY_MAINTENANCE,
4858 helpcategory=command.CATEGORY_MAINTENANCE,
4856 intents={INTENT_READONLY},
4859 intents={INTENT_READONLY},
4857 )
4860 )
4858 def manifest(ui, repo, node=None, rev=None, **opts):
4861 def manifest(ui, repo, node=None, rev=None, **opts):
4859 """output the current or given revision of the project manifest
4862 """output the current or given revision of the project manifest
4860
4863
4861 Print a list of version controlled files for the given revision.
4864 Print a list of version controlled files for the given revision.
4862 If no revision is given, the first parent of the working directory
4865 If no revision is given, the first parent of the working directory
4863 is used, or the null revision if no revision is checked out.
4866 is used, or the null revision if no revision is checked out.
4864
4867
4865 With -v, print file permissions, symlink and executable bits.
4868 With -v, print file permissions, symlink and executable bits.
4866 With --debug, print file revision hashes.
4869 With --debug, print file revision hashes.
4867
4870
4868 If option --all is specified, the list of all files from all revisions
4871 If option --all is specified, the list of all files from all revisions
4869 is printed. This includes deleted and renamed files.
4872 is printed. This includes deleted and renamed files.
4870
4873
4871 Returns 0 on success.
4874 Returns 0 on success.
4872 """
4875 """
4873 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4876 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4874
4877
4875 if opts.get('all'):
4878 if opts.get('all'):
4876 if rev or node:
4879 if rev or node:
4877 raise error.InputError(_(b"can't specify a revision with --all"))
4880 raise error.InputError(_(b"can't specify a revision with --all"))
4878
4881
4879 res = set()
4882 res = set()
4880 for rev in repo:
4883 for rev in repo:
4881 ctx = repo[rev]
4884 ctx = repo[rev]
4882 res |= set(ctx.files())
4885 res |= set(ctx.files())
4883
4886
4884 ui.pager(b'manifest')
4887 ui.pager(b'manifest')
4885 for f in sorted(res):
4888 for f in sorted(res):
4886 fm.startitem()
4889 fm.startitem()
4887 fm.write(b"path", b'%s\n', f)
4890 fm.write(b"path", b'%s\n', f)
4888 fm.end()
4891 fm.end()
4889 return
4892 return
4890
4893
4891 if rev and node:
4894 if rev and node:
4892 raise error.InputError(_(b"please specify just one revision"))
4895 raise error.InputError(_(b"please specify just one revision"))
4893
4896
4894 if not node:
4897 if not node:
4895 node = rev
4898 node = rev
4896
4899
4897 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4900 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4898 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4901 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4899 if node:
4902 if node:
4900 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4903 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4901 ctx = logcmdutil.revsingle(repo, node)
4904 ctx = logcmdutil.revsingle(repo, node)
4902 mf = ctx.manifest()
4905 mf = ctx.manifest()
4903 ui.pager(b'manifest')
4906 ui.pager(b'manifest')
4904 for f in ctx:
4907 for f in ctx:
4905 fm.startitem()
4908 fm.startitem()
4906 fm.context(ctx=ctx)
4909 fm.context(ctx=ctx)
4907 fl = ctx[f].flags()
4910 fl = ctx[f].flags()
4908 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4911 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4909 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4912 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4910 fm.write(b'path', b'%s\n', f)
4913 fm.write(b'path', b'%s\n', f)
4911 fm.end()
4914 fm.end()
4912
4915
4913
4916
4914 @command(
4917 @command(
4915 b'merge',
4918 b'merge',
4916 [
4919 [
4917 (
4920 (
4918 b'f',
4921 b'f',
4919 b'force',
4922 b'force',
4920 None,
4923 None,
4921 _(b'force a merge including outstanding changes (DEPRECATED)'),
4924 _(b'force a merge including outstanding changes (DEPRECATED)'),
4922 ),
4925 ),
4923 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4926 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4924 (
4927 (
4925 b'P',
4928 b'P',
4926 b'preview',
4929 b'preview',
4927 None,
4930 None,
4928 _(b'review revisions to merge (no merge is performed)'),
4931 _(b'review revisions to merge (no merge is performed)'),
4929 ),
4932 ),
4930 (b'', b'abort', None, _(b'abort the ongoing merge')),
4933 (b'', b'abort', None, _(b'abort the ongoing merge')),
4931 ]
4934 ]
4932 + mergetoolopts,
4935 + mergetoolopts,
4933 _(b'[-P] [[-r] REV]'),
4936 _(b'[-P] [[-r] REV]'),
4934 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4937 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4935 helpbasic=True,
4938 helpbasic=True,
4936 )
4939 )
4937 def merge(ui, repo, node=None, **opts):
4940 def merge(ui, repo, node=None, **opts):
4938 """merge another revision into working directory
4941 """merge another revision into working directory
4939
4942
4940 The current working directory is updated with all changes made in
4943 The current working directory is updated with all changes made in
4941 the requested revision since the last common predecessor revision.
4944 the requested revision since the last common predecessor revision.
4942
4945
4943 Files that changed between either parent are marked as changed for
4946 Files that changed between either parent are marked as changed for
4944 the next commit and a commit must be performed before any further
4947 the next commit and a commit must be performed before any further
4945 updates to the repository are allowed. The next commit will have
4948 updates to the repository are allowed. The next commit will have
4946 two parents.
4949 two parents.
4947
4950
4948 ``--tool`` can be used to specify the merge tool used for file
4951 ``--tool`` can be used to specify the merge tool used for file
4949 merges. It overrides the HGMERGE environment variable and your
4952 merges. It overrides the HGMERGE environment variable and your
4950 configuration files. See :hg:`help merge-tools` for options.
4953 configuration files. See :hg:`help merge-tools` for options.
4951
4954
4952 If no revision is specified, the working directory's parent is a
4955 If no revision is specified, the working directory's parent is a
4953 head revision, and the current branch contains exactly one other
4956 head revision, and the current branch contains exactly one other
4954 head, the other head is merged with by default. Otherwise, an
4957 head, the other head is merged with by default. Otherwise, an
4955 explicit revision with which to merge must be provided.
4958 explicit revision with which to merge must be provided.
4956
4959
4957 See :hg:`help resolve` for information on handling file conflicts.
4960 See :hg:`help resolve` for information on handling file conflicts.
4958
4961
4959 To undo an uncommitted merge, use :hg:`merge --abort` which
4962 To undo an uncommitted merge, use :hg:`merge --abort` which
4960 will check out a clean copy of the original merge parent, losing
4963 will check out a clean copy of the original merge parent, losing
4961 all changes.
4964 all changes.
4962
4965
4963 Returns 0 on success, 1 if there are unresolved files.
4966 Returns 0 on success, 1 if there are unresolved files.
4964 """
4967 """
4965
4968
4966 abort = opts.get('abort')
4969 abort = opts.get('abort')
4967 if abort and repo.dirstate.p2() == repo.nullid:
4970 if abort and repo.dirstate.p2() == repo.nullid:
4968 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4971 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4969 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4972 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4970 if abort:
4973 if abort:
4971 state = cmdutil.getunfinishedstate(repo)
4974 state = cmdutil.getunfinishedstate(repo)
4972 if state and state._opname != b'merge':
4975 if state and state._opname != b'merge':
4973 raise error.StateError(
4976 raise error.StateError(
4974 _(b'cannot abort merge with %s in progress') % (state._opname),
4977 _(b'cannot abort merge with %s in progress') % (state._opname),
4975 hint=state.hint(),
4978 hint=state.hint(),
4976 )
4979 )
4977 if node:
4980 if node:
4978 raise error.InputError(_(b"cannot specify a node with --abort"))
4981 raise error.InputError(_(b"cannot specify a node with --abort"))
4979 return hg.abortmerge(repo.ui, repo)
4982 return hg.abortmerge(repo.ui, repo)
4980
4983
4981 if opts.get('rev') and node:
4984 if opts.get('rev') and node:
4982 raise error.InputError(_(b"please specify just one revision"))
4985 raise error.InputError(_(b"please specify just one revision"))
4983 if not node:
4986 if not node:
4984 node = opts.get('rev')
4987 node = opts.get('rev')
4985
4988
4986 if node:
4989 if node:
4987 ctx = logcmdutil.revsingle(repo, node)
4990 ctx = logcmdutil.revsingle(repo, node)
4988 else:
4991 else:
4989 if ui.configbool(b'commands', b'merge.require-rev'):
4992 if ui.configbool(b'commands', b'merge.require-rev'):
4990 raise error.InputError(
4993 raise error.InputError(
4991 _(
4994 _(
4992 b'configuration requires specifying revision to merge '
4995 b'configuration requires specifying revision to merge '
4993 b'with'
4996 b'with'
4994 )
4997 )
4995 )
4998 )
4996 ctx = repo[destutil.destmerge(repo)]
4999 ctx = repo[destutil.destmerge(repo)]
4997
5000
4998 if ctx.node() is None:
5001 if ctx.node() is None:
4999 raise error.InputError(
5002 raise error.InputError(
5000 _(b'merging with the working copy has no effect')
5003 _(b'merging with the working copy has no effect')
5001 )
5004 )
5002
5005
5003 if opts.get('preview'):
5006 if opts.get('preview'):
5004 # find nodes that are ancestors of p2 but not of p1
5007 # find nodes that are ancestors of p2 but not of p1
5005 p1 = repo[b'.'].node()
5008 p1 = repo[b'.'].node()
5006 p2 = ctx.node()
5009 p2 = ctx.node()
5007 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5010 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5008
5011
5009 displayer = logcmdutil.changesetdisplayer(
5012 displayer = logcmdutil.changesetdisplayer(
5010 ui, repo, pycompat.byteskwargs(opts)
5013 ui, repo, pycompat.byteskwargs(opts)
5011 )
5014 )
5012 for node in nodes:
5015 for node in nodes:
5013 displayer.show(repo[node])
5016 displayer.show(repo[node])
5014 displayer.close()
5017 displayer.close()
5015 return 0
5018 return 0
5016
5019
5017 # ui.forcemerge is an internal variable, do not document
5020 # ui.forcemerge is an internal variable, do not document
5018 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
5021 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
5019 with ui.configoverride(overrides, b'merge'):
5022 with ui.configoverride(overrides, b'merge'):
5020 force = opts.get('force')
5023 force = opts.get('force')
5021 labels = [b'working copy', b'merge rev', b'common ancestor']
5024 labels = [b'working copy', b'merge rev', b'common ancestor']
5022 return hg.merge(ctx, force=force, labels=labels)
5025 return hg.merge(ctx, force=force, labels=labels)
5023
5026
5024
5027
5025 statemod.addunfinished(
5028 statemod.addunfinished(
5026 b'merge',
5029 b'merge',
5027 fname=None,
5030 fname=None,
5028 clearable=True,
5031 clearable=True,
5029 allowcommit=True,
5032 allowcommit=True,
5030 cmdmsg=_(b'outstanding uncommitted merge'),
5033 cmdmsg=_(b'outstanding uncommitted merge'),
5031 abortfunc=hg.abortmerge,
5034 abortfunc=hg.abortmerge,
5032 statushint=_(
5035 statushint=_(
5033 b'To continue: hg commit\nTo abort: hg merge --abort'
5036 b'To continue: hg commit\nTo abort: hg merge --abort'
5034 ),
5037 ),
5035 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
5038 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
5036 )
5039 )
5037
5040
5038
5041
5039 @command(
5042 @command(
5040 b'outgoing|out',
5043 b'outgoing|out',
5041 [
5044 [
5042 (
5045 (
5043 b'f',
5046 b'f',
5044 b'force',
5047 b'force',
5045 None,
5048 None,
5046 _(b'run even when the destination is unrelated'),
5049 _(b'run even when the destination is unrelated'),
5047 ),
5050 ),
5048 (
5051 (
5049 b'r',
5052 b'r',
5050 b'rev',
5053 b'rev',
5051 [],
5054 [],
5052 _(b'a changeset intended to be included in the destination'),
5055 _(b'a changeset intended to be included in the destination'),
5053 _(b'REV'),
5056 _(b'REV'),
5054 ),
5057 ),
5055 (b'n', b'newest-first', None, _(b'show newest record first')),
5058 (b'n', b'newest-first', None, _(b'show newest record first')),
5056 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5059 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
5057 (
5060 (
5058 b'b',
5061 b'b',
5059 b'branch',
5062 b'branch',
5060 [],
5063 [],
5061 _(b'a specific branch you would like to push'),
5064 _(b'a specific branch you would like to push'),
5062 _(b'BRANCH'),
5065 _(b'BRANCH'),
5063 ),
5066 ),
5064 ]
5067 ]
5065 + logopts
5068 + logopts
5066 + remoteopts
5069 + remoteopts
5067 + subrepoopts,
5070 + subrepoopts,
5068 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5071 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
5069 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5072 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5070 )
5073 )
5071 def outgoing(ui, repo, *dests, **opts):
5074 def outgoing(ui, repo, *dests, **opts):
5072 """show changesets not found in the destination
5075 """show changesets not found in the destination
5073
5076
5074 Show changesets not found in the specified destination repository
5077 Show changesets not found in the specified destination repository
5075 or the default push location. These are the changesets that would
5078 or the default push location. These are the changesets that would
5076 be pushed if a push was requested.
5079 be pushed if a push was requested.
5077
5080
5078 See pull for details of valid destination formats.
5081 See pull for details of valid destination formats.
5079
5082
5080 .. container:: verbose
5083 .. container:: verbose
5081
5084
5082 With -B/--bookmarks, the result of bookmark comparison between
5085 With -B/--bookmarks, the result of bookmark comparison between
5083 local and remote repositories is displayed. With -v/--verbose,
5086 local and remote repositories is displayed. With -v/--verbose,
5084 status is also displayed for each bookmark like below::
5087 status is also displayed for each bookmark like below::
5085
5088
5086 BM1 01234567890a added
5089 BM1 01234567890a added
5087 BM2 deleted
5090 BM2 deleted
5088 BM3 234567890abc advanced
5091 BM3 234567890abc advanced
5089 BM4 34567890abcd diverged
5092 BM4 34567890abcd diverged
5090 BM5 4567890abcde changed
5093 BM5 4567890abcde changed
5091
5094
5092 The action taken when pushing depends on the
5095 The action taken when pushing depends on the
5093 status of each bookmark:
5096 status of each bookmark:
5094
5097
5095 :``added``: push with ``-B`` will create it
5098 :``added``: push with ``-B`` will create it
5096 :``deleted``: push with ``-B`` will delete it
5099 :``deleted``: push with ``-B`` will delete it
5097 :``advanced``: push will update it
5100 :``advanced``: push will update it
5098 :``diverged``: push with ``-B`` will update it
5101 :``diverged``: push with ``-B`` will update it
5099 :``changed``: push with ``-B`` will update it
5102 :``changed``: push with ``-B`` will update it
5100
5103
5101 From the point of view of pushing behavior, bookmarks
5104 From the point of view of pushing behavior, bookmarks
5102 existing only in the remote repository are treated as
5105 existing only in the remote repository are treated as
5103 ``deleted``, even if it is in fact added remotely.
5106 ``deleted``, even if it is in fact added remotely.
5104
5107
5105 Returns 0 if there are outgoing changes, 1 otherwise.
5108 Returns 0 if there are outgoing changes, 1 otherwise.
5106 """
5109 """
5107 opts = pycompat.byteskwargs(opts)
5110 opts = pycompat.byteskwargs(opts)
5108 if opts.get(b'bookmarks'):
5111 if opts.get(b'bookmarks'):
5109 for path in urlutil.get_push_paths(repo, ui, dests):
5112 for path in urlutil.get_push_paths(repo, ui, dests):
5110 other = hg.peer(repo, opts, path)
5113 other = hg.peer(repo, opts, path)
5111 try:
5114 try:
5112 if b'bookmarks' not in other.listkeys(b'namespaces'):
5115 if b'bookmarks' not in other.listkeys(b'namespaces'):
5113 ui.warn(_(b"remote doesn't support bookmarks\n"))
5116 ui.warn(_(b"remote doesn't support bookmarks\n"))
5114 return 0
5117 return 0
5115 ui.status(
5118 ui.status(
5116 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5119 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
5117 )
5120 )
5118 ui.pager(b'outgoing')
5121 ui.pager(b'outgoing')
5119 return bookmarks.outgoing(ui, repo, other)
5122 return bookmarks.outgoing(ui, repo, other)
5120 finally:
5123 finally:
5121 other.close()
5124 other.close()
5122
5125
5123 return hg.outgoing(ui, repo, dests, opts)
5126 return hg.outgoing(ui, repo, dests, opts)
5124
5127
5125
5128
5126 @command(
5129 @command(
5127 b'parents',
5130 b'parents',
5128 [
5131 [
5129 (
5132 (
5130 b'r',
5133 b'r',
5131 b'rev',
5134 b'rev',
5132 b'',
5135 b'',
5133 _(b'show parents of the specified revision'),
5136 _(b'show parents of the specified revision'),
5134 _(b'REV'),
5137 _(b'REV'),
5135 ),
5138 ),
5136 ]
5139 ]
5137 + templateopts,
5140 + templateopts,
5138 _(b'[-r REV] [FILE]'),
5141 _(b'[-r REV] [FILE]'),
5139 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5142 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5140 inferrepo=True,
5143 inferrepo=True,
5141 )
5144 )
5142 def parents(ui, repo, file_=None, **opts):
5145 def parents(ui, repo, file_=None, **opts):
5143 """show the parents of the working directory or revision (DEPRECATED)
5146 """show the parents of the working directory or revision (DEPRECATED)
5144
5147
5145 Print the working directory's parent revisions. If a revision is
5148 Print the working directory's parent revisions. If a revision is
5146 given via -r/--rev, the parent of that revision will be printed.
5149 given via -r/--rev, the parent of that revision will be printed.
5147 If a file argument is given, the revision in which the file was
5150 If a file argument is given, the revision in which the file was
5148 last changed (before the working directory revision or the
5151 last changed (before the working directory revision or the
5149 argument to --rev if given) is printed.
5152 argument to --rev if given) is printed.
5150
5153
5151 This command is equivalent to::
5154 This command is equivalent to::
5152
5155
5153 hg log -r "p1()+p2()" or
5156 hg log -r "p1()+p2()" or
5154 hg log -r "p1(REV)+p2(REV)" or
5157 hg log -r "p1(REV)+p2(REV)" or
5155 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5158 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5156 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5159 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5157
5160
5158 See :hg:`summary` and :hg:`help revsets` for related information.
5161 See :hg:`summary` and :hg:`help revsets` for related information.
5159
5162
5160 Returns 0 on success.
5163 Returns 0 on success.
5161 """
5164 """
5162
5165
5163 opts = pycompat.byteskwargs(opts)
5166 opts = pycompat.byteskwargs(opts)
5164 rev = opts.get(b'rev')
5167 rev = opts.get(b'rev')
5165 if rev:
5168 if rev:
5166 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5169 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5167 ctx = logcmdutil.revsingle(repo, rev, None)
5170 ctx = logcmdutil.revsingle(repo, rev, None)
5168
5171
5169 if file_:
5172 if file_:
5170 m = scmutil.match(ctx, (file_,), opts)
5173 m = scmutil.match(ctx, (file_,), opts)
5171 if m.anypats() or len(m.files()) != 1:
5174 if m.anypats() or len(m.files()) != 1:
5172 raise error.InputError(_(b'can only specify an explicit filename'))
5175 raise error.InputError(_(b'can only specify an explicit filename'))
5173 file_ = m.files()[0]
5176 file_ = m.files()[0]
5174 filenodes = []
5177 filenodes = []
5175 for cp in ctx.parents():
5178 for cp in ctx.parents():
5176 if not cp:
5179 if not cp:
5177 continue
5180 continue
5178 try:
5181 try:
5179 filenodes.append(cp.filenode(file_))
5182 filenodes.append(cp.filenode(file_))
5180 except error.LookupError:
5183 except error.LookupError:
5181 pass
5184 pass
5182 if not filenodes:
5185 if not filenodes:
5183 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5186 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5184 p = []
5187 p = []
5185 for fn in filenodes:
5188 for fn in filenodes:
5186 fctx = repo.filectx(file_, fileid=fn)
5189 fctx = repo.filectx(file_, fileid=fn)
5187 p.append(fctx.node())
5190 p.append(fctx.node())
5188 else:
5191 else:
5189 p = [cp.node() for cp in ctx.parents()]
5192 p = [cp.node() for cp in ctx.parents()]
5190
5193
5191 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5194 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5192 for n in p:
5195 for n in p:
5193 if n != repo.nullid:
5196 if n != repo.nullid:
5194 displayer.show(repo[n])
5197 displayer.show(repo[n])
5195 displayer.close()
5198 displayer.close()
5196
5199
5197
5200
5198 @command(
5201 @command(
5199 b'paths',
5202 b'paths',
5200 formatteropts,
5203 formatteropts,
5201 _(b'[NAME]'),
5204 _(b'[NAME]'),
5202 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5205 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5203 optionalrepo=True,
5206 optionalrepo=True,
5204 intents={INTENT_READONLY},
5207 intents={INTENT_READONLY},
5205 )
5208 )
5206 def paths(ui, repo, search=None, **opts):
5209 def paths(ui, repo, search=None, **opts):
5207 """show aliases for remote repositories
5210 """show aliases for remote repositories
5208
5211
5209 Show definition of symbolic path name NAME. If no name is given,
5212 Show definition of symbolic path name NAME. If no name is given,
5210 show definition of all available names.
5213 show definition of all available names.
5211
5214
5212 Option -q/--quiet suppresses all output when searching for NAME
5215 Option -q/--quiet suppresses all output when searching for NAME
5213 and shows only the path names when listing all definitions.
5216 and shows only the path names when listing all definitions.
5214
5217
5215 Path names are defined in the [paths] section of your
5218 Path names are defined in the [paths] section of your
5216 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5219 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5217 repository, ``.hg/hgrc`` is used, too.
5220 repository, ``.hg/hgrc`` is used, too.
5218
5221
5219 The path names ``default`` and ``default-push`` have a special
5222 The path names ``default`` and ``default-push`` have a special
5220 meaning. When performing a push or pull operation, they are used
5223 meaning. When performing a push or pull operation, they are used
5221 as fallbacks if no location is specified on the command-line.
5224 as fallbacks if no location is specified on the command-line.
5222 When ``default-push`` is set, it will be used for push and
5225 When ``default-push`` is set, it will be used for push and
5223 ``default`` will be used for pull; otherwise ``default`` is used
5226 ``default`` will be used for pull; otherwise ``default`` is used
5224 as the fallback for both. When cloning a repository, the clone
5227 as the fallback for both. When cloning a repository, the clone
5225 source is written as ``default`` in ``.hg/hgrc``.
5228 source is written as ``default`` in ``.hg/hgrc``.
5226
5229
5227 .. note::
5230 .. note::
5228
5231
5229 ``default`` and ``default-push`` apply to all inbound (e.g.
5232 ``default`` and ``default-push`` apply to all inbound (e.g.
5230 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5233 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5231 and :hg:`bundle`) operations.
5234 and :hg:`bundle`) operations.
5232
5235
5233 See :hg:`help urls` for more information.
5236 See :hg:`help urls` for more information.
5234
5237
5235 .. container:: verbose
5238 .. container:: verbose
5236
5239
5237 Template:
5240 Template:
5238
5241
5239 The following keywords are supported. See also :hg:`help templates`.
5242 The following keywords are supported. See also :hg:`help templates`.
5240
5243
5241 :name: String. Symbolic name of the path alias.
5244 :name: String. Symbolic name of the path alias.
5242 :pushurl: String. URL for push operations.
5245 :pushurl: String. URL for push operations.
5243 :url: String. URL or directory path for the other operations.
5246 :url: String. URL or directory path for the other operations.
5244
5247
5245 Returns 0 on success.
5248 Returns 0 on success.
5246 """
5249 """
5247
5250
5248 pathitems = urlutil.list_paths(ui, search)
5251 pathitems = urlutil.list_paths(ui, search)
5249 ui.pager(b'paths')
5252 ui.pager(b'paths')
5250
5253
5251 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5254 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
5252 if fm.isplain():
5255 if fm.isplain():
5253 hidepassword = urlutil.hidepassword
5256 hidepassword = urlutil.hidepassword
5254 else:
5257 else:
5255 hidepassword = bytes
5258 hidepassword = bytes
5256 if ui.quiet:
5259 if ui.quiet:
5257 namefmt = b'%s\n'
5260 namefmt = b'%s\n'
5258 else:
5261 else:
5259 namefmt = b'%s = '
5262 namefmt = b'%s = '
5260 showsubopts = not search and not ui.quiet
5263 showsubopts = not search and not ui.quiet
5261
5264
5262 for name, path in pathitems:
5265 for name, path in pathitems:
5263 fm.startitem()
5266 fm.startitem()
5264 fm.condwrite(not search, b'name', namefmt, name)
5267 fm.condwrite(not search, b'name', namefmt, name)
5265 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5268 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5266 for subopt, value in sorted(path.suboptions.items()):
5269 for subopt, value in sorted(path.suboptions.items()):
5267 assert subopt not in (b'name', b'url')
5270 assert subopt not in (b'name', b'url')
5268 if showsubopts:
5271 if showsubopts:
5269 fm.plain(b'%s:%s = ' % (name, subopt))
5272 fm.plain(b'%s:%s = ' % (name, subopt))
5270 display = urlutil.path_suboptions_display[subopt]
5273 display = urlutil.path_suboptions_display[subopt]
5271 value = display(value)
5274 value = display(value)
5272 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5275 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5273
5276
5274 fm.end()
5277 fm.end()
5275
5278
5276 if search and not pathitems:
5279 if search and not pathitems:
5277 if not ui.quiet:
5280 if not ui.quiet:
5278 ui.warn(_(b"not found!\n"))
5281 ui.warn(_(b"not found!\n"))
5279 return 1
5282 return 1
5280 else:
5283 else:
5281 return 0
5284 return 0
5282
5285
5283
5286
5284 @command(
5287 @command(
5285 b'phase',
5288 b'phase',
5286 [
5289 [
5287 (b'p', b'public', False, _(b'set changeset phase to public')),
5290 (b'p', b'public', False, _(b'set changeset phase to public')),
5288 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5291 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5289 (b's', b'secret', False, _(b'set changeset phase to secret')),
5292 (b's', b'secret', False, _(b'set changeset phase to secret')),
5290 (b'f', b'force', False, _(b'allow to move boundary backward')),
5293 (b'f', b'force', False, _(b'allow to move boundary backward')),
5291 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5294 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5292 ],
5295 ],
5293 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5296 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5294 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5297 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5295 )
5298 )
5296 def phase(ui, repo, *revs, **opts):
5299 def phase(ui, repo, *revs, **opts):
5297 """set or show the current phase name
5300 """set or show the current phase name
5298
5301
5299 With no argument, show the phase name of the current revision(s).
5302 With no argument, show the phase name of the current revision(s).
5300
5303
5301 With one of -p/--public, -d/--draft or -s/--secret, change the
5304 With one of -p/--public, -d/--draft or -s/--secret, change the
5302 phase value of the specified revisions.
5305 phase value of the specified revisions.
5303
5306
5304 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5307 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5305 lower phase to a higher phase. Phases are ordered as follows::
5308 lower phase to a higher phase. Phases are ordered as follows::
5306
5309
5307 public < draft < secret
5310 public < draft < secret
5308
5311
5309 Returns 0 on success, 1 if some phases could not be changed.
5312 Returns 0 on success, 1 if some phases could not be changed.
5310
5313
5311 (For more information about the phases concept, see :hg:`help phases`.)
5314 (For more information about the phases concept, see :hg:`help phases`.)
5312 """
5315 """
5313 opts = pycompat.byteskwargs(opts)
5316 opts = pycompat.byteskwargs(opts)
5314 # search for a unique phase argument
5317 # search for a unique phase argument
5315 targetphase = None
5318 targetphase = None
5316 for idx, name in enumerate(phases.cmdphasenames):
5319 for idx, name in enumerate(phases.cmdphasenames):
5317 if opts[name]:
5320 if opts[name]:
5318 if targetphase is not None:
5321 if targetphase is not None:
5319 raise error.InputError(_(b'only one phase can be specified'))
5322 raise error.InputError(_(b'only one phase can be specified'))
5320 targetphase = idx
5323 targetphase = idx
5321
5324
5322 # look for specified revision
5325 # look for specified revision
5323 revs = list(revs)
5326 revs = list(revs)
5324 revs.extend(opts[b'rev'])
5327 revs.extend(opts[b'rev'])
5325 if revs:
5328 if revs:
5326 revs = logcmdutil.revrange(repo, revs)
5329 revs = logcmdutil.revrange(repo, revs)
5327 else:
5330 else:
5328 # display both parents as the second parent phase can influence
5331 # display both parents as the second parent phase can influence
5329 # the phase of a merge commit
5332 # the phase of a merge commit
5330 revs = [c.rev() for c in repo[None].parents()]
5333 revs = [c.rev() for c in repo[None].parents()]
5331
5334
5332 ret = 0
5335 ret = 0
5333 if targetphase is None:
5336 if targetphase is None:
5334 # display
5337 # display
5335 for r in revs:
5338 for r in revs:
5336 ctx = repo[r]
5339 ctx = repo[r]
5337 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5340 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5338 else:
5341 else:
5339 with repo.lock(), repo.transaction(b"phase") as tr:
5342 with repo.lock(), repo.transaction(b"phase") as tr:
5340 # set phase
5343 # set phase
5341 if not revs:
5344 if not revs:
5342 raise error.InputError(_(b'empty revision set'))
5345 raise error.InputError(_(b'empty revision set'))
5343 nodes = [repo[r].node() for r in revs]
5346 nodes = [repo[r].node() for r in revs]
5344 # moving revision from public to draft may hide them
5347 # moving revision from public to draft may hide them
5345 # We have to check result on an unfiltered repository
5348 # We have to check result on an unfiltered repository
5346 unfi = repo.unfiltered()
5349 unfi = repo.unfiltered()
5347 getphase = unfi._phasecache.phase
5350 getphase = unfi._phasecache.phase
5348 olddata = [getphase(unfi, r) for r in unfi]
5351 olddata = [getphase(unfi, r) for r in unfi]
5349 phases.advanceboundary(repo, tr, targetphase, nodes)
5352 phases.advanceboundary(repo, tr, targetphase, nodes)
5350 if opts[b'force']:
5353 if opts[b'force']:
5351 phases.retractboundary(repo, tr, targetphase, nodes)
5354 phases.retractboundary(repo, tr, targetphase, nodes)
5352 getphase = unfi._phasecache.phase
5355 getphase = unfi._phasecache.phase
5353 newdata = [getphase(unfi, r) for r in unfi]
5356 newdata = [getphase(unfi, r) for r in unfi]
5354 changes = sum(newdata[r] != olddata[r] for r in unfi)
5357 changes = sum(newdata[r] != olddata[r] for r in unfi)
5355 cl = unfi.changelog
5358 cl = unfi.changelog
5356 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5359 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5357 if rejected:
5360 if rejected:
5358 ui.warn(
5361 ui.warn(
5359 _(
5362 _(
5360 b'cannot move %i changesets to a higher '
5363 b'cannot move %i changesets to a higher '
5361 b'phase, use --force\n'
5364 b'phase, use --force\n'
5362 )
5365 )
5363 % len(rejected)
5366 % len(rejected)
5364 )
5367 )
5365 ret = 1
5368 ret = 1
5366 if changes:
5369 if changes:
5367 msg = _(b'phase changed for %i changesets\n') % changes
5370 msg = _(b'phase changed for %i changesets\n') % changes
5368 if ret:
5371 if ret:
5369 ui.status(msg)
5372 ui.status(msg)
5370 else:
5373 else:
5371 ui.note(msg)
5374 ui.note(msg)
5372 else:
5375 else:
5373 ui.warn(_(b'no phases changed\n'))
5376 ui.warn(_(b'no phases changed\n'))
5374 return ret
5377 return ret
5375
5378
5376
5379
5377 @command(
5380 @command(
5378 b'pull',
5381 b'pull',
5379 [
5382 [
5380 (
5383 (
5381 b'u',
5384 b'u',
5382 b'update',
5385 b'update',
5383 None,
5386 None,
5384 _(b'update to new branch head if new descendants were pulled'),
5387 _(b'update to new branch head if new descendants were pulled'),
5385 ),
5388 ),
5386 (
5389 (
5387 b'f',
5390 b'f',
5388 b'force',
5391 b'force',
5389 None,
5392 None,
5390 _(b'run even when remote repository is unrelated'),
5393 _(b'run even when remote repository is unrelated'),
5391 ),
5394 ),
5392 (
5395 (
5393 b'',
5396 b'',
5394 b'confirm',
5397 b'confirm',
5395 None,
5398 None,
5396 _(b'confirm pull before applying changes'),
5399 _(b'confirm pull before applying changes'),
5397 ),
5400 ),
5398 (
5401 (
5399 b'r',
5402 b'r',
5400 b'rev',
5403 b'rev',
5401 [],
5404 [],
5402 _(b'a remote changeset intended to be added'),
5405 _(b'a remote changeset intended to be added'),
5403 _(b'REV'),
5406 _(b'REV'),
5404 ),
5407 ),
5405 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5408 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5406 (
5409 (
5407 b'b',
5410 b'b',
5408 b'branch',
5411 b'branch',
5409 [],
5412 [],
5410 _(b'a specific branch you would like to pull'),
5413 _(b'a specific branch you would like to pull'),
5411 _(b'BRANCH'),
5414 _(b'BRANCH'),
5412 ),
5415 ),
5413 (
5416 (
5414 b'',
5417 b'',
5415 b'remote-hidden',
5418 b'remote-hidden',
5416 False,
5419 False,
5417 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5420 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5418 ),
5421 ),
5419 ]
5422 ]
5420 + remoteopts,
5423 + remoteopts,
5421 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5424 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5422 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5425 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5423 helpbasic=True,
5426 helpbasic=True,
5424 )
5427 )
5425 def pull(ui, repo, *sources, **opts):
5428 def pull(ui, repo, *sources, **opts):
5426 """pull changes from the specified source
5429 """pull changes from the specified source
5427
5430
5428 Pull changes from a remote repository to a local one.
5431 Pull changes from a remote repository to a local one.
5429
5432
5430 This finds all changes from the repository at the specified path
5433 This finds all changes from the repository at the specified path
5431 or URL and adds them to a local repository (the current one unless
5434 or URL and adds them to a local repository (the current one unless
5432 -R is specified). By default, this does not update the copy of the
5435 -R is specified). By default, this does not update the copy of the
5433 project in the working directory.
5436 project in the working directory.
5434
5437
5435 When cloning from servers that support it, Mercurial may fetch
5438 When cloning from servers that support it, Mercurial may fetch
5436 pre-generated data. When this is done, hooks operating on incoming
5439 pre-generated data. When this is done, hooks operating on incoming
5437 changesets and changegroups may fire more than once, once for each
5440 changesets and changegroups may fire more than once, once for each
5438 pre-generated bundle and as well as for any additional remaining
5441 pre-generated bundle and as well as for any additional remaining
5439 data. See :hg:`help -e clonebundles` for more.
5442 data. See :hg:`help -e clonebundles` for more.
5440
5443
5441 Use :hg:`incoming` if you want to see what would have been added
5444 Use :hg:`incoming` if you want to see what would have been added
5442 by a pull at the time you issued this command. If you then decide
5445 by a pull at the time you issued this command. If you then decide
5443 to add those changes to the repository, you should use :hg:`pull
5446 to add those changes to the repository, you should use :hg:`pull
5444 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5447 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5445
5448
5446 If SOURCE is omitted, the 'default' path will be used.
5449 If SOURCE is omitted, the 'default' path will be used.
5447 See :hg:`help urls` for more information.
5450 See :hg:`help urls` for more information.
5448
5451
5449 If multiple sources are specified, they will be pulled sequentially as if
5452 If multiple sources are specified, they will be pulled sequentially as if
5450 the command was run multiple time. If --update is specify and the command
5453 the command was run multiple time. If --update is specify and the command
5451 will stop at the first failed --update.
5454 will stop at the first failed --update.
5452
5455
5453 Specifying bookmark as ``.`` is equivalent to specifying the active
5456 Specifying bookmark as ``.`` is equivalent to specifying the active
5454 bookmark's name.
5457 bookmark's name.
5455
5458
5456 .. container:: verbose
5459 .. container:: verbose
5457
5460
5458 One can use the `--remote-hidden` flag to pull changesets
5461 One can use the `--remote-hidden` flag to pull changesets
5459 hidden on the remote. This flag is "best effort", and will only
5462 hidden on the remote. This flag is "best effort", and will only
5460 work if the server supports the feature and is configured to
5463 work if the server supports the feature and is configured to
5461 allow the user to access hidden changesets. This option is
5464 allow the user to access hidden changesets. This option is
5462 experimental and backwards compatibility is not garanteed.
5465 experimental and backwards compatibility is not garanteed.
5463
5466
5464 Returns 0 on success, 1 if an update had unresolved files.
5467 Returns 0 on success, 1 if an update had unresolved files.
5465 """
5468 """
5466
5469
5467 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5470 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5468 msg = _(b'update destination required by configuration')
5471 msg = _(b'update destination required by configuration')
5469 hint = _(b'use hg pull followed by hg update DEST')
5472 hint = _(b'use hg pull followed by hg update DEST')
5470 raise error.InputError(msg, hint=hint)
5473 raise error.InputError(msg, hint=hint)
5471
5474
5472 update_conflict = None
5475 update_conflict = None
5473
5476
5474 for path in urlutil.get_pull_paths(repo, ui, sources):
5477 for path in urlutil.get_pull_paths(repo, ui, sources):
5475 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5478 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5476 ui.flush()
5479 ui.flush()
5477 other = hg.peer(
5480 other = hg.peer(
5478 repo,
5481 repo,
5479 pycompat.byteskwargs(opts),
5482 pycompat.byteskwargs(opts),
5480 path,
5483 path,
5481 remotehidden=opts['remote_hidden'],
5484 remotehidden=opts['remote_hidden'],
5482 )
5485 )
5483 update_conflict = None
5486 update_conflict = None
5484 try:
5487 try:
5485 branches = (path.branch, opts.get('branch', []))
5488 branches = (path.branch, opts.get('branch', []))
5486 revs, checkout = hg.addbranchrevs(
5489 revs, checkout = hg.addbranchrevs(
5487 repo,
5490 repo,
5488 other,
5491 other,
5489 branches,
5492 branches,
5490 opts.get('rev'),
5493 opts.get('rev'),
5491 remotehidden=opts['remote_hidden'],
5494 remotehidden=opts['remote_hidden'],
5492 )
5495 )
5493
5496
5494 pullopargs = {}
5497 pullopargs = {}
5495
5498
5496 nodes = None
5499 nodes = None
5497 if opts.get('bookmark') or revs:
5500 if opts.get('bookmark') or revs:
5498 # The list of bookmark used here is the same used to actually update
5501 # The list of bookmark used here is the same used to actually update
5499 # the bookmark names, to avoid the race from issue 4689 and we do
5502 # the bookmark names, to avoid the race from issue 4689 and we do
5500 # all lookup and bookmark queries in one go so they see the same
5503 # all lookup and bookmark queries in one go so they see the same
5501 # version of the server state (issue 4700).
5504 # version of the server state (issue 4700).
5502 nodes = []
5505 nodes = []
5503 fnodes = []
5506 fnodes = []
5504 revs = revs or []
5507 revs = revs or []
5505 if revs and not other.capable(b'lookup'):
5508 if revs and not other.capable(b'lookup'):
5506 err = _(
5509 err = _(
5507 b"other repository doesn't support revision lookup, "
5510 b"other repository doesn't support revision lookup, "
5508 b"so a rev cannot be specified."
5511 b"so a rev cannot be specified."
5509 )
5512 )
5510 raise error.Abort(err)
5513 raise error.Abort(err)
5511 with other.commandexecutor() as e:
5514 with other.commandexecutor() as e:
5512 fremotebookmarks = e.callcommand(
5515 fremotebookmarks = e.callcommand(
5513 b'listkeys', {b'namespace': b'bookmarks'}
5516 b'listkeys', {b'namespace': b'bookmarks'}
5514 )
5517 )
5515 for r in revs:
5518 for r in revs:
5516 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5519 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5517 remotebookmarks = fremotebookmarks.result()
5520 remotebookmarks = fremotebookmarks.result()
5518 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5521 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5519 pullopargs[b'remotebookmarks'] = remotebookmarks
5522 pullopargs[b'remotebookmarks'] = remotebookmarks
5520 for b in opts.get('bookmark', []):
5523 for b in opts.get('bookmark', []):
5521 b = repo._bookmarks.expandname(b)
5524 b = repo._bookmarks.expandname(b)
5522 if b not in remotebookmarks:
5525 if b not in remotebookmarks:
5523 raise error.InputError(
5526 raise error.InputError(
5524 _(b'remote bookmark %s not found!') % b
5527 _(b'remote bookmark %s not found!') % b
5525 )
5528 )
5526 nodes.append(remotebookmarks[b])
5529 nodes.append(remotebookmarks[b])
5527 for i, rev in enumerate(revs):
5530 for i, rev in enumerate(revs):
5528 node = fnodes[i].result()
5531 node = fnodes[i].result()
5529 nodes.append(node)
5532 nodes.append(node)
5530 if rev == checkout:
5533 if rev == checkout:
5531 checkout = node
5534 checkout = node
5532
5535
5533 wlock = util.nullcontextmanager()
5536 wlock = util.nullcontextmanager()
5534 if opts.get('update'):
5537 if opts.get('update'):
5535 wlock = repo.wlock()
5538 wlock = repo.wlock()
5536 with wlock:
5539 with wlock:
5537 pullopargs.update(opts.get('opargs', {}))
5540 pullopargs.update(opts.get('opargs', {}))
5538 modheads = exchange.pull(
5541 modheads = exchange.pull(
5539 repo,
5542 repo,
5540 other,
5543 other,
5541 path=path,
5544 path=path,
5542 heads=nodes,
5545 heads=nodes,
5543 force=opts.get('force'),
5546 force=opts.get('force'),
5544 bookmarks=opts.get('bookmark', ()),
5547 bookmarks=opts.get('bookmark', ()),
5545 opargs=pullopargs,
5548 opargs=pullopargs,
5546 confirm=opts.get('confirm'),
5549 confirm=opts.get('confirm'),
5547 ).cgresult
5550 ).cgresult
5548
5551
5549 # brev is a name, which might be a bookmark to be activated at
5552 # brev is a name, which might be a bookmark to be activated at
5550 # the end of the update. In other words, it is an explicit
5553 # the end of the update. In other words, it is an explicit
5551 # destination of the update
5554 # destination of the update
5552 brev = None
5555 brev = None
5553
5556
5554 if checkout:
5557 if checkout:
5555 checkout = repo.unfiltered().changelog.rev(checkout)
5558 checkout = repo.unfiltered().changelog.rev(checkout)
5556
5559
5557 # order below depends on implementation of
5560 # order below depends on implementation of
5558 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5561 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5559 # because 'checkout' is determined without it.
5562 # because 'checkout' is determined without it.
5560 if opts.get('rev'):
5563 if opts.get('rev'):
5561 brev = opts['rev'][0]
5564 brev = opts['rev'][0]
5562 elif opts.get('branch'):
5565 elif opts.get('branch'):
5563 brev = opts['branch'][0]
5566 brev = opts['branch'][0]
5564 else:
5567 else:
5565 brev = path.branch
5568 brev = path.branch
5566
5569
5567 # XXX path: we are losing the `path` object here. Keeping it
5570 # XXX path: we are losing the `path` object here. Keeping it
5568 # would be valuable. For example as a "variant" as we do
5571 # would be valuable. For example as a "variant" as we do
5569 # for pushes.
5572 # for pushes.
5570 repo._subtoppath = path.loc
5573 repo._subtoppath = path.loc
5571 try:
5574 try:
5572 update_conflict = cmdutil.postincoming(
5575 update_conflict = cmdutil.postincoming(
5573 ui, repo, modheads, opts.get('update'), checkout, brev
5576 ui, repo, modheads, opts.get('update'), checkout, brev
5574 )
5577 )
5575 except error.FilteredRepoLookupError as exc:
5578 except error.FilteredRepoLookupError as exc:
5576 msg = _(b'cannot update to target: %s') % exc.args[0]
5579 msg = _(b'cannot update to target: %s') % exc.args[0]
5577 exc.args = (msg,) + exc.args[1:]
5580 exc.args = (msg,) + exc.args[1:]
5578 raise
5581 raise
5579 finally:
5582 finally:
5580 del repo._subtoppath
5583 del repo._subtoppath
5581
5584
5582 finally:
5585 finally:
5583 other.close()
5586 other.close()
5584 # skip the remaining pull source if they are some conflict.
5587 # skip the remaining pull source if they are some conflict.
5585 if update_conflict:
5588 if update_conflict:
5586 break
5589 break
5587 if update_conflict:
5590 if update_conflict:
5588 return 1
5591 return 1
5589 else:
5592 else:
5590 return 0
5593 return 0
5591
5594
5592
5595
5593 @command(
5596 @command(
5594 b'purge|clean',
5597 b'purge|clean',
5595 [
5598 [
5596 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5599 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5597 (b'', b'all', None, _(b'purge ignored files too')),
5600 (b'', b'all', None, _(b'purge ignored files too')),
5598 (b'i', b'ignored', None, _(b'purge only ignored files')),
5601 (b'i', b'ignored', None, _(b'purge only ignored files')),
5599 (b'', b'dirs', None, _(b'purge empty directories')),
5602 (b'', b'dirs', None, _(b'purge empty directories')),
5600 (b'', b'files', None, _(b'purge files')),
5603 (b'', b'files', None, _(b'purge files')),
5601 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5604 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5602 (
5605 (
5603 b'0',
5606 b'0',
5604 b'print0',
5607 b'print0',
5605 None,
5608 None,
5606 _(
5609 _(
5607 b'end filenames with NUL, for use with xargs'
5610 b'end filenames with NUL, for use with xargs'
5608 b' (implies -p/--print)'
5611 b' (implies -p/--print)'
5609 ),
5612 ),
5610 ),
5613 ),
5611 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5614 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5612 ]
5615 ]
5613 + cmdutil.walkopts,
5616 + cmdutil.walkopts,
5614 _(b'hg purge [OPTION]... [DIR]...'),
5617 _(b'hg purge [OPTION]... [DIR]...'),
5615 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5618 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5616 )
5619 )
5617 def purge(ui, repo, *dirs, **opts):
5620 def purge(ui, repo, *dirs, **opts):
5618 """removes files not tracked by Mercurial
5621 """removes files not tracked by Mercurial
5619
5622
5620 Delete files not known to Mercurial. This is useful to test local
5623 Delete files not known to Mercurial. This is useful to test local
5621 and uncommitted changes in an otherwise-clean source tree.
5624 and uncommitted changes in an otherwise-clean source tree.
5622
5625
5623 This means that purge will delete the following by default:
5626 This means that purge will delete the following by default:
5624
5627
5625 - Unknown files: files marked with "?" by :hg:`status`
5628 - Unknown files: files marked with "?" by :hg:`status`
5626 - Empty directories: in fact Mercurial ignores directories unless
5629 - Empty directories: in fact Mercurial ignores directories unless
5627 they contain files under source control management
5630 they contain files under source control management
5628
5631
5629 But it will leave untouched:
5632 But it will leave untouched:
5630
5633
5631 - Modified and unmodified tracked files
5634 - Modified and unmodified tracked files
5632 - Ignored files (unless -i or --all is specified)
5635 - Ignored files (unless -i or --all is specified)
5633 - New files added to the repository (with :hg:`add`)
5636 - New files added to the repository (with :hg:`add`)
5634
5637
5635 The --files and --dirs options can be used to direct purge to delete
5638 The --files and --dirs options can be used to direct purge to delete
5636 only files, only directories, or both. If neither option is given,
5639 only files, only directories, or both. If neither option is given,
5637 both will be deleted.
5640 both will be deleted.
5638
5641
5639 If directories are given on the command line, only files in these
5642 If directories are given on the command line, only files in these
5640 directories are considered.
5643 directories are considered.
5641
5644
5642 Be careful with purge, as you could irreversibly delete some files
5645 Be careful with purge, as you could irreversibly delete some files
5643 you forgot to add to the repository. If you only want to print the
5646 you forgot to add to the repository. If you only want to print the
5644 list of files that this program would delete, use the --print
5647 list of files that this program would delete, use the --print
5645 option.
5648 option.
5646 """
5649 """
5647 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5650 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5648
5651
5649 act = not opts.get('print')
5652 act = not opts.get('print')
5650 eol = b'\n'
5653 eol = b'\n'
5651 if opts.get('print0'):
5654 if opts.get('print0'):
5652 eol = b'\0'
5655 eol = b'\0'
5653 act = False # --print0 implies --print
5656 act = False # --print0 implies --print
5654 if opts.get('all', False):
5657 if opts.get('all', False):
5655 ignored = True
5658 ignored = True
5656 unknown = True
5659 unknown = True
5657 else:
5660 else:
5658 ignored = opts.get('ignored', False)
5661 ignored = opts.get('ignored', False)
5659 unknown = not ignored
5662 unknown = not ignored
5660
5663
5661 removefiles = opts.get('files')
5664 removefiles = opts.get('files')
5662 removedirs = opts.get('dirs')
5665 removedirs = opts.get('dirs')
5663 confirm = opts.get('confirm')
5666 confirm = opts.get('confirm')
5664 if confirm is None:
5667 if confirm is None:
5665 try:
5668 try:
5666 extensions.find(b'purge')
5669 extensions.find(b'purge')
5667 confirm = False
5670 confirm = False
5668 except KeyError:
5671 except KeyError:
5669 confirm = True
5672 confirm = True
5670
5673
5671 if not removefiles and not removedirs:
5674 if not removefiles and not removedirs:
5672 removefiles = True
5675 removefiles = True
5673 removedirs = True
5676 removedirs = True
5674
5677
5675 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5678 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5676
5679
5677 paths = mergemod.purge(
5680 paths = mergemod.purge(
5678 repo,
5681 repo,
5679 match,
5682 match,
5680 unknown=unknown,
5683 unknown=unknown,
5681 ignored=ignored,
5684 ignored=ignored,
5682 removeemptydirs=removedirs,
5685 removeemptydirs=removedirs,
5683 removefiles=removefiles,
5686 removefiles=removefiles,
5684 abortonerror=opts.get('abort_on_err'),
5687 abortonerror=opts.get('abort_on_err'),
5685 noop=not act,
5688 noop=not act,
5686 confirm=confirm,
5689 confirm=confirm,
5687 )
5690 )
5688
5691
5689 for path in paths:
5692 for path in paths:
5690 if not act:
5693 if not act:
5691 ui.write(b'%s%s' % (path, eol))
5694 ui.write(b'%s%s' % (path, eol))
5692
5695
5693
5696
5694 @command(
5697 @command(
5695 b'push',
5698 b'push',
5696 [
5699 [
5697 (b'f', b'force', None, _(b'force push')),
5700 (b'f', b'force', None, _(b'force push')),
5698 (
5701 (
5699 b'r',
5702 b'r',
5700 b'rev',
5703 b'rev',
5701 [],
5704 [],
5702 _(b'a changeset intended to be included in the destination'),
5705 _(b'a changeset intended to be included in the destination'),
5703 _(b'REV'),
5706 _(b'REV'),
5704 ),
5707 ),
5705 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5708 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5706 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5709 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5707 (
5710 (
5708 b'b',
5711 b'b',
5709 b'branch',
5712 b'branch',
5710 [],
5713 [],
5711 _(b'a specific branch you would like to push'),
5714 _(b'a specific branch you would like to push'),
5712 _(b'BRANCH'),
5715 _(b'BRANCH'),
5713 ),
5716 ),
5714 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5717 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5715 (
5718 (
5716 b'',
5719 b'',
5717 b'pushvars',
5720 b'pushvars',
5718 [],
5721 [],
5719 _(b'variables that can be sent to server (ADVANCED)'),
5722 _(b'variables that can be sent to server (ADVANCED)'),
5720 ),
5723 ),
5721 (
5724 (
5722 b'',
5725 b'',
5723 b'publish',
5726 b'publish',
5724 False,
5727 False,
5725 _(b'push the changeset as public (EXPERIMENTAL)'),
5728 _(b'push the changeset as public (EXPERIMENTAL)'),
5726 ),
5729 ),
5727 ]
5730 ]
5728 + remoteopts,
5731 + remoteopts,
5729 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5732 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5730 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5733 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5731 helpbasic=True,
5734 helpbasic=True,
5732 )
5735 )
5733 def push(ui, repo, *dests, **opts):
5736 def push(ui, repo, *dests, **opts):
5734 """push changes to the specified destination
5737 """push changes to the specified destination
5735
5738
5736 Push changesets from the local repository to the specified
5739 Push changesets from the local repository to the specified
5737 destination.
5740 destination.
5738
5741
5739 This operation is symmetrical to pull: it is identical to a pull
5742 This operation is symmetrical to pull: it is identical to a pull
5740 in the destination repository from the current one.
5743 in the destination repository from the current one.
5741
5744
5742 By default, push will not allow creation of new heads at the
5745 By default, push will not allow creation of new heads at the
5743 destination, since multiple heads would make it unclear which head
5746 destination, since multiple heads would make it unclear which head
5744 to use. In this situation, it is recommended to pull and merge
5747 to use. In this situation, it is recommended to pull and merge
5745 before pushing.
5748 before pushing.
5746
5749
5747 Use --new-branch if you want to allow push to create a new named
5750 Use --new-branch if you want to allow push to create a new named
5748 branch that is not present at the destination. This allows you to
5751 branch that is not present at the destination. This allows you to
5749 only create a new branch without forcing other changes.
5752 only create a new branch without forcing other changes.
5750
5753
5751 .. note::
5754 .. note::
5752
5755
5753 Extra care should be taken with the -f/--force option,
5756 Extra care should be taken with the -f/--force option,
5754 which will push all new heads on all branches, an action which will
5757 which will push all new heads on all branches, an action which will
5755 almost always cause confusion for collaborators.
5758 almost always cause confusion for collaborators.
5756
5759
5757 If -r/--rev is used, the specified revision and all its ancestors
5760 If -r/--rev is used, the specified revision and all its ancestors
5758 will be pushed to the remote repository.
5761 will be pushed to the remote repository.
5759
5762
5760 If -B/--bookmark is used, the specified bookmarked revision, its
5763 If -B/--bookmark is used, the specified bookmarked revision, its
5761 ancestors, and the bookmark will be pushed to the remote
5764 ancestors, and the bookmark will be pushed to the remote
5762 repository. Specifying ``.`` is equivalent to specifying the active
5765 repository. Specifying ``.`` is equivalent to specifying the active
5763 bookmark's name. Use the --all-bookmarks option for pushing all
5766 bookmark's name. Use the --all-bookmarks option for pushing all
5764 current bookmarks.
5767 current bookmarks.
5765
5768
5766 Please see :hg:`help urls` for important details about ``ssh://``
5769 Please see :hg:`help urls` for important details about ``ssh://``
5767 URLs. If DESTINATION is omitted, a default path will be used.
5770 URLs. If DESTINATION is omitted, a default path will be used.
5768
5771
5769 When passed multiple destinations, push will process them one after the
5772 When passed multiple destinations, push will process them one after the
5770 other, but stop should an error occur.
5773 other, but stop should an error occur.
5771
5774
5772 .. container:: verbose
5775 .. container:: verbose
5773
5776
5774 The --pushvars option sends strings to the server that become
5777 The --pushvars option sends strings to the server that become
5775 environment variables prepended with ``HG_USERVAR_``. For example,
5778 environment variables prepended with ``HG_USERVAR_``. For example,
5776 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5779 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5777 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5780 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5778
5781
5779 pushvars can provide for user-overridable hooks as well as set debug
5782 pushvars can provide for user-overridable hooks as well as set debug
5780 levels. One example is having a hook that blocks commits containing
5783 levels. One example is having a hook that blocks commits containing
5781 conflict markers, but enables the user to override the hook if the file
5784 conflict markers, but enables the user to override the hook if the file
5782 is using conflict markers for testing purposes or the file format has
5785 is using conflict markers for testing purposes or the file format has
5783 strings that look like conflict markers.
5786 strings that look like conflict markers.
5784
5787
5785 By default, servers will ignore `--pushvars`. To enable it add the
5788 By default, servers will ignore `--pushvars`. To enable it add the
5786 following to your configuration file::
5789 following to your configuration file::
5787
5790
5788 [push]
5791 [push]
5789 pushvars.server = true
5792 pushvars.server = true
5790
5793
5791 Returns 0 if push was successful, 1 if nothing to push.
5794 Returns 0 if push was successful, 1 if nothing to push.
5792 """
5795 """
5793
5796
5794 opts = pycompat.byteskwargs(opts)
5797 opts = pycompat.byteskwargs(opts)
5795
5798
5796 if opts.get(b'all_bookmarks'):
5799 if opts.get(b'all_bookmarks'):
5797 cmdutil.check_incompatible_arguments(
5800 cmdutil.check_incompatible_arguments(
5798 opts,
5801 opts,
5799 b'all_bookmarks',
5802 b'all_bookmarks',
5800 [b'bookmark', b'rev'],
5803 [b'bookmark', b'rev'],
5801 )
5804 )
5802 opts[b'bookmark'] = list(repo._bookmarks)
5805 opts[b'bookmark'] = list(repo._bookmarks)
5803
5806
5804 if opts.get(b'bookmark'):
5807 if opts.get(b'bookmark'):
5805 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5808 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5806 for b in opts[b'bookmark']:
5809 for b in opts[b'bookmark']:
5807 # translate -B options to -r so changesets get pushed
5810 # translate -B options to -r so changesets get pushed
5808 b = repo._bookmarks.expandname(b)
5811 b = repo._bookmarks.expandname(b)
5809 if b in repo._bookmarks:
5812 if b in repo._bookmarks:
5810 opts.setdefault(b'rev', []).append(b)
5813 opts.setdefault(b'rev', []).append(b)
5811 else:
5814 else:
5812 # if we try to push a deleted bookmark, translate it to null
5815 # if we try to push a deleted bookmark, translate it to null
5813 # this lets simultaneous -r, -b options continue working
5816 # this lets simultaneous -r, -b options continue working
5814 opts.setdefault(b'rev', []).append(b"null")
5817 opts.setdefault(b'rev', []).append(b"null")
5815
5818
5816 some_pushed = False
5819 some_pushed = False
5817 result = 0
5820 result = 0
5818 for path in urlutil.get_push_paths(repo, ui, dests):
5821 for path in urlutil.get_push_paths(repo, ui, dests):
5819 dest = path.loc
5822 dest = path.loc
5820 branches = (path.branch, opts.get(b'branch') or [])
5823 branches = (path.branch, opts.get(b'branch') or [])
5821 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5824 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5822 revs, checkout = hg.addbranchrevs(
5825 revs, checkout = hg.addbranchrevs(
5823 repo, repo, branches, opts.get(b'rev')
5826 repo, repo, branches, opts.get(b'rev')
5824 )
5827 )
5825 other = hg.peer(repo, opts, dest)
5828 other = hg.peer(repo, opts, dest)
5826
5829
5827 try:
5830 try:
5828 if revs:
5831 if revs:
5829 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5832 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5830 if not revs:
5833 if not revs:
5831 raise error.InputError(
5834 raise error.InputError(
5832 _(b"specified revisions evaluate to an empty set"),
5835 _(b"specified revisions evaluate to an empty set"),
5833 hint=_(b"use different revision arguments"),
5836 hint=_(b"use different revision arguments"),
5834 )
5837 )
5835 elif path.pushrev:
5838 elif path.pushrev:
5836 # It doesn't make any sense to specify ancestor revisions. So limit
5839 # It doesn't make any sense to specify ancestor revisions. So limit
5837 # to DAG heads to make discovery simpler.
5840 # to DAG heads to make discovery simpler.
5838 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5841 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5839 revs = scmutil.revrange(repo, [expr])
5842 revs = scmutil.revrange(repo, [expr])
5840 revs = [repo[rev].node() for rev in revs]
5843 revs = [repo[rev].node() for rev in revs]
5841 if not revs:
5844 if not revs:
5842 raise error.InputError(
5845 raise error.InputError(
5843 _(
5846 _(
5844 b'default push revset for path evaluates to an empty set'
5847 b'default push revset for path evaluates to an empty set'
5845 )
5848 )
5846 )
5849 )
5847 elif ui.configbool(b'commands', b'push.require-revs'):
5850 elif ui.configbool(b'commands', b'push.require-revs'):
5848 raise error.InputError(
5851 raise error.InputError(
5849 _(b'no revisions specified to push'),
5852 _(b'no revisions specified to push'),
5850 hint=_(b'did you mean "hg push -r ."?'),
5853 hint=_(b'did you mean "hg push -r ."?'),
5851 )
5854 )
5852
5855
5853 repo._subtoppath = dest
5856 repo._subtoppath = dest
5854 try:
5857 try:
5855 # push subrepos depth-first for coherent ordering
5858 # push subrepos depth-first for coherent ordering
5856 c = repo[b'.']
5859 c = repo[b'.']
5857 subs = c.substate # only repos that are committed
5860 subs = c.substate # only repos that are committed
5858 for s in sorted(subs):
5861 for s in sorted(subs):
5859 sub_result = c.sub(s).push(opts)
5862 sub_result = c.sub(s).push(opts)
5860 if sub_result == 0:
5863 if sub_result == 0:
5861 return 1
5864 return 1
5862 finally:
5865 finally:
5863 del repo._subtoppath
5866 del repo._subtoppath
5864
5867
5865 opargs = dict(
5868 opargs = dict(
5866 opts.get(b'opargs', {})
5869 opts.get(b'opargs', {})
5867 ) # copy opargs since we may mutate it
5870 ) # copy opargs since we may mutate it
5868 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5871 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5869
5872
5870 pushop = exchange.push(
5873 pushop = exchange.push(
5871 repo,
5874 repo,
5872 other,
5875 other,
5873 opts.get(b'force'),
5876 opts.get(b'force'),
5874 revs=revs,
5877 revs=revs,
5875 newbranch=opts.get(b'new_branch'),
5878 newbranch=opts.get(b'new_branch'),
5876 bookmarks=opts.get(b'bookmark', ()),
5879 bookmarks=opts.get(b'bookmark', ()),
5877 publish=opts.get(b'publish'),
5880 publish=opts.get(b'publish'),
5878 opargs=opargs,
5881 opargs=opargs,
5879 )
5882 )
5880
5883
5881 if pushop.cgresult == 0:
5884 if pushop.cgresult == 0:
5882 result = 1
5885 result = 1
5883 elif pushop.cgresult is not None:
5886 elif pushop.cgresult is not None:
5884 some_pushed = True
5887 some_pushed = True
5885
5888
5886 if pushop.bkresult is not None:
5889 if pushop.bkresult is not None:
5887 if pushop.bkresult == 2:
5890 if pushop.bkresult == 2:
5888 result = 2
5891 result = 2
5889 elif not result and pushop.bkresult:
5892 elif not result and pushop.bkresult:
5890 result = 2
5893 result = 2
5891
5894
5892 if result:
5895 if result:
5893 break
5896 break
5894
5897
5895 finally:
5898 finally:
5896 other.close()
5899 other.close()
5897 if result == 0 and not some_pushed:
5900 if result == 0 and not some_pushed:
5898 result = 1
5901 result = 1
5899 return result
5902 return result
5900
5903
5901
5904
5902 @command(
5905 @command(
5903 b'recover',
5906 b'recover',
5904 [
5907 [
5905 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5908 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5906 ],
5909 ],
5907 helpcategory=command.CATEGORY_MAINTENANCE,
5910 helpcategory=command.CATEGORY_MAINTENANCE,
5908 )
5911 )
5909 def recover(ui, repo, **opts):
5912 def recover(ui, repo, **opts):
5910 """roll back an interrupted transaction
5913 """roll back an interrupted transaction
5911
5914
5912 Recover from an interrupted commit or pull.
5915 Recover from an interrupted commit or pull.
5913
5916
5914 This command tries to fix the repository status after an
5917 This command tries to fix the repository status after an
5915 interrupted operation. It should only be necessary when Mercurial
5918 interrupted operation. It should only be necessary when Mercurial
5916 suggests it.
5919 suggests it.
5917
5920
5918 Returns 0 if successful, 1 if nothing to recover or verify fails.
5921 Returns 0 if successful, 1 if nothing to recover or verify fails.
5919 """
5922 """
5920 ret = repo.recover()
5923 ret = repo.recover()
5921 if ret:
5924 if ret:
5922 if opts['verify']:
5925 if opts['verify']:
5923 return hg.verify(repo)
5926 return hg.verify(repo)
5924 else:
5927 else:
5925 msg = _(
5928 msg = _(
5926 b"(verify step skipped, run `hg verify` to check your "
5929 b"(verify step skipped, run `hg verify` to check your "
5927 b"repository content)\n"
5930 b"repository content)\n"
5928 )
5931 )
5929 ui.warn(msg)
5932 ui.warn(msg)
5930 return 0
5933 return 0
5931 return 1
5934 return 1
5932
5935
5933
5936
5934 @command(
5937 @command(
5935 b'remove|rm',
5938 b'remove|rm',
5936 [
5939 [
5937 (b'A', b'after', None, _(b'record delete for missing files')),
5940 (b'A', b'after', None, _(b'record delete for missing files')),
5938 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5941 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5939 ]
5942 ]
5940 + subrepoopts
5943 + subrepoopts
5941 + walkopts
5944 + walkopts
5942 + dryrunopts,
5945 + dryrunopts,
5943 _(b'[OPTION]... FILE...'),
5946 _(b'[OPTION]... FILE...'),
5944 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5947 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5945 helpbasic=True,
5948 helpbasic=True,
5946 inferrepo=True,
5949 inferrepo=True,
5947 )
5950 )
5948 def remove(ui, repo, *pats, **opts):
5951 def remove(ui, repo, *pats, **opts):
5949 """remove the specified files on the next commit
5952 """remove the specified files on the next commit
5950
5953
5951 Schedule the indicated files for removal from the current branch.
5954 Schedule the indicated files for removal from the current branch.
5952
5955
5953 This command schedules the files to be removed at the next commit.
5956 This command schedules the files to be removed at the next commit.
5954 To undo a remove before that, see :hg:`revert`. To undo added
5957 To undo a remove before that, see :hg:`revert`. To undo added
5955 files, see :hg:`forget`.
5958 files, see :hg:`forget`.
5956
5959
5957 .. container:: verbose
5960 .. container:: verbose
5958
5961
5959 -A/--after can be used to remove only files that have already
5962 -A/--after can be used to remove only files that have already
5960 been deleted, -f/--force can be used to force deletion, and -Af
5963 been deleted, -f/--force can be used to force deletion, and -Af
5961 can be used to remove files from the next revision without
5964 can be used to remove files from the next revision without
5962 deleting them from the working directory.
5965 deleting them from the working directory.
5963
5966
5964 The following table details the behavior of remove for different
5967 The following table details the behavior of remove for different
5965 file states (columns) and option combinations (rows). The file
5968 file states (columns) and option combinations (rows). The file
5966 states are Added [A], Clean [C], Modified [M] and Missing [!]
5969 states are Added [A], Clean [C], Modified [M] and Missing [!]
5967 (as reported by :hg:`status`). The actions are Warn, Remove
5970 (as reported by :hg:`status`). The actions are Warn, Remove
5968 (from branch) and Delete (from disk):
5971 (from branch) and Delete (from disk):
5969
5972
5970 ========= == == == ==
5973 ========= == == == ==
5971 opt/state A C M !
5974 opt/state A C M !
5972 ========= == == == ==
5975 ========= == == == ==
5973 none W RD W R
5976 none W RD W R
5974 -f R RD RD R
5977 -f R RD RD R
5975 -A W W W R
5978 -A W W W R
5976 -Af R R R R
5979 -Af R R R R
5977 ========= == == == ==
5980 ========= == == == ==
5978
5981
5979 .. note::
5982 .. note::
5980
5983
5981 :hg:`remove` never deletes files in Added [A] state from the
5984 :hg:`remove` never deletes files in Added [A] state from the
5982 working directory, not even if ``--force`` is specified.
5985 working directory, not even if ``--force`` is specified.
5983
5986
5984 Returns 0 on success, 1 if any warnings encountered.
5987 Returns 0 on success, 1 if any warnings encountered.
5985 """
5988 """
5986
5989
5987 after, force = opts.get('after'), opts.get('force')
5990 after, force = opts.get('after'), opts.get('force')
5988 dryrun = opts.get('dry_run')
5991 dryrun = opts.get('dry_run')
5989 if not pats and not after:
5992 if not pats and not after:
5990 raise error.InputError(_(b'no files specified'))
5993 raise error.InputError(_(b'no files specified'))
5991
5994
5992 with repo.wlock(), repo.dirstate.changing_files(repo):
5995 with repo.wlock(), repo.dirstate.changing_files(repo):
5993 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5996 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5994 subrepos = opts.get('subrepos')
5997 subrepos = opts.get('subrepos')
5995 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5998 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5996 return cmdutil.remove(
5999 return cmdutil.remove(
5997 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
6000 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5998 )
6001 )
5999
6002
6000
6003
6001 @command(
6004 @command(
6002 b'rename|move|mv',
6005 b'rename|move|mv',
6003 [
6006 [
6004 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6007 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
6005 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6008 (b'A', b'after', None, _(b'record a rename that has already occurred')),
6006 (
6009 (
6007 b'',
6010 b'',
6008 b'at-rev',
6011 b'at-rev',
6009 b'',
6012 b'',
6010 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6013 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
6011 _(b'REV'),
6014 _(b'REV'),
6012 ),
6015 ),
6013 (
6016 (
6014 b'f',
6017 b'f',
6015 b'force',
6018 b'force',
6016 None,
6019 None,
6017 _(b'forcibly move over an existing managed file'),
6020 _(b'forcibly move over an existing managed file'),
6018 ),
6021 ),
6019 ]
6022 ]
6020 + walkopts
6023 + walkopts
6021 + dryrunopts,
6024 + dryrunopts,
6022 _(b'[OPTION]... SOURCE... DEST'),
6025 _(b'[OPTION]... SOURCE... DEST'),
6023 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6026 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6024 )
6027 )
6025 def rename(ui, repo, *pats, **opts):
6028 def rename(ui, repo, *pats, **opts):
6026 """rename files; equivalent of copy + remove
6029 """rename files; equivalent of copy + remove
6027
6030
6028 Mark dest as copies of sources; mark sources for deletion. If dest
6031 Mark dest as copies of sources; mark sources for deletion. If dest
6029 is a directory, copies are put in that directory. If dest is a
6032 is a directory, copies are put in that directory. If dest is a
6030 file, there can only be one source.
6033 file, there can only be one source.
6031
6034
6032 By default, this command copies the contents of files as they
6035 By default, this command copies the contents of files as they
6033 exist in the working directory. If invoked with -A/--after, the
6036 exist in the working directory. If invoked with -A/--after, the
6034 operation is recorded, but no copying is performed.
6037 operation is recorded, but no copying is performed.
6035
6038
6036 To undo marking a destination file as renamed, use --forget. With that
6039 To undo marking a destination file as renamed, use --forget. With that
6037 option, all given (positional) arguments are unmarked as renames. The
6040 option, all given (positional) arguments are unmarked as renames. The
6038 destination file(s) will be left in place (still tracked). The source
6041 destination file(s) will be left in place (still tracked). The source
6039 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6042 file(s) will not be restored. Note that :hg:`rename --forget` behaves
6040 the same way as :hg:`copy --forget`.
6043 the same way as :hg:`copy --forget`.
6041
6044
6042 This command takes effect with the next commit by default.
6045 This command takes effect with the next commit by default.
6043
6046
6044 Returns 0 on success, 1 if errors are encountered.
6047 Returns 0 on success, 1 if errors are encountered.
6045 """
6048 """
6046 context = lambda repo: repo.dirstate.changing_files(repo)
6049 context = lambda repo: repo.dirstate.changing_files(repo)
6047 rev = opts.get('at_rev')
6050 rev = opts.get('at_rev')
6048
6051
6049 if rev:
6052 if rev:
6050 ctx = logcmdutil.revsingle(repo, rev)
6053 ctx = logcmdutil.revsingle(repo, rev)
6051 if ctx.rev() is not None:
6054 if ctx.rev() is not None:
6052
6055
6053 def context(repo):
6056 def context(repo):
6054 return util.nullcontextmanager()
6057 return util.nullcontextmanager()
6055
6058
6056 opts['at_rev'] = ctx.rev()
6059 opts['at_rev'] = ctx.rev()
6057 with repo.wlock(), context(repo):
6060 with repo.wlock(), context(repo):
6058 return cmdutil.copy(
6061 return cmdutil.copy(
6059 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6062 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
6060 )
6063 )
6061
6064
6062
6065
6063 @command(
6066 @command(
6064 b'resolve',
6067 b'resolve',
6065 [
6068 [
6066 (b'a', b'all', None, _(b'select all unresolved files')),
6069 (b'a', b'all', None, _(b'select all unresolved files')),
6067 (b'l', b'list', None, _(b'list state of files needing merge')),
6070 (b'l', b'list', None, _(b'list state of files needing merge')),
6068 (b'm', b'mark', None, _(b'mark files as resolved')),
6071 (b'm', b'mark', None, _(b'mark files as resolved')),
6069 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6072 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6070 (b'n', b'no-status', None, _(b'hide status prefix')),
6073 (b'n', b'no-status', None, _(b'hide status prefix')),
6071 (b'', b're-merge', None, _(b're-merge files')),
6074 (b'', b're-merge', None, _(b're-merge files')),
6072 ]
6075 ]
6073 + mergetoolopts
6076 + mergetoolopts
6074 + walkopts
6077 + walkopts
6075 + formatteropts,
6078 + formatteropts,
6076 _(b'[OPTION]... [FILE]...'),
6079 _(b'[OPTION]... [FILE]...'),
6077 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6080 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6078 inferrepo=True,
6081 inferrepo=True,
6079 )
6082 )
6080 def resolve(ui, repo, *pats, **opts):
6083 def resolve(ui, repo, *pats, **opts):
6081 """redo merges or set/view the merge status of files
6084 """redo merges or set/view the merge status of files
6082
6085
6083 Merges with unresolved conflicts are often the result of
6086 Merges with unresolved conflicts are often the result of
6084 non-interactive merging using the ``internal:merge`` configuration
6087 non-interactive merging using the ``internal:merge`` configuration
6085 setting, or a command-line merge tool like ``diff3``. The resolve
6088 setting, or a command-line merge tool like ``diff3``. The resolve
6086 command is used to manage the files involved in a merge, after
6089 command is used to manage the files involved in a merge, after
6087 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6090 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6088 working directory must have two parents). See :hg:`help
6091 working directory must have two parents). See :hg:`help
6089 merge-tools` for information on configuring merge tools.
6092 merge-tools` for information on configuring merge tools.
6090
6093
6091 The resolve command can be used in the following ways:
6094 The resolve command can be used in the following ways:
6092
6095
6093 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6096 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6094 the specified files, discarding any previous merge attempts. Re-merging
6097 the specified files, discarding any previous merge attempts. Re-merging
6095 is not performed for files already marked as resolved. Use ``--all/-a``
6098 is not performed for files already marked as resolved. Use ``--all/-a``
6096 to select all unresolved files. ``--tool`` can be used to specify
6099 to select all unresolved files. ``--tool`` can be used to specify
6097 the merge tool used for the given files. It overrides the HGMERGE
6100 the merge tool used for the given files. It overrides the HGMERGE
6098 environment variable and your configuration files. Previous file
6101 environment variable and your configuration files. Previous file
6099 contents are saved with a ``.orig`` suffix.
6102 contents are saved with a ``.orig`` suffix.
6100
6103
6101 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6104 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6102 (e.g. after having manually fixed-up the files). The default is
6105 (e.g. after having manually fixed-up the files). The default is
6103 to mark all unresolved files.
6106 to mark all unresolved files.
6104
6107
6105 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6108 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6106 default is to mark all resolved files.
6109 default is to mark all resolved files.
6107
6110
6108 - :hg:`resolve -l`: list files which had or still have conflicts.
6111 - :hg:`resolve -l`: list files which had or still have conflicts.
6109 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6112 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6110 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6113 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6111 the list. See :hg:`help filesets` for details.
6114 the list. See :hg:`help filesets` for details.
6112
6115
6113 .. note::
6116 .. note::
6114
6117
6115 Mercurial will not let you commit files with unresolved merge
6118 Mercurial will not let you commit files with unresolved merge
6116 conflicts. You must use :hg:`resolve -m ...` before you can
6119 conflicts. You must use :hg:`resolve -m ...` before you can
6117 commit after a conflicting merge.
6120 commit after a conflicting merge.
6118
6121
6119 .. container:: verbose
6122 .. container:: verbose
6120
6123
6121 Template:
6124 Template:
6122
6125
6123 The following keywords are supported in addition to the common template
6126 The following keywords are supported in addition to the common template
6124 keywords and functions. See also :hg:`help templates`.
6127 keywords and functions. See also :hg:`help templates`.
6125
6128
6126 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6129 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6127 :path: String. Repository-absolute path of the file.
6130 :path: String. Repository-absolute path of the file.
6128
6131
6129 Returns 0 on success, 1 if any files fail a resolve attempt.
6132 Returns 0 on success, 1 if any files fail a resolve attempt.
6130 """
6133 """
6131
6134
6132 opts = pycompat.byteskwargs(opts)
6135 opts = pycompat.byteskwargs(opts)
6133 confirm = ui.configbool(b'commands', b'resolve.confirm')
6136 confirm = ui.configbool(b'commands', b'resolve.confirm')
6134 flaglist = b'all mark unmark list no_status re_merge'.split()
6137 flaglist = b'all mark unmark list no_status re_merge'.split()
6135 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6138 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6136
6139
6137 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6140 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6138 if actioncount > 1:
6141 if actioncount > 1:
6139 raise error.InputError(_(b"too many actions specified"))
6142 raise error.InputError(_(b"too many actions specified"))
6140 elif actioncount == 0 and ui.configbool(
6143 elif actioncount == 0 and ui.configbool(
6141 b'commands', b'resolve.explicit-re-merge'
6144 b'commands', b'resolve.explicit-re-merge'
6142 ):
6145 ):
6143 hint = _(b'use --mark, --unmark, --list or --re-merge')
6146 hint = _(b'use --mark, --unmark, --list or --re-merge')
6144 raise error.InputError(_(b'no action specified'), hint=hint)
6147 raise error.InputError(_(b'no action specified'), hint=hint)
6145 if pats and all:
6148 if pats and all:
6146 raise error.InputError(_(b"can't specify --all and patterns"))
6149 raise error.InputError(_(b"can't specify --all and patterns"))
6147 if not (all or pats or show or mark or unmark):
6150 if not (all or pats or show or mark or unmark):
6148 raise error.InputError(
6151 raise error.InputError(
6149 _(b'no files or directories specified'),
6152 _(b'no files or directories specified'),
6150 hint=b'use --all to re-merge all unresolved files',
6153 hint=b'use --all to re-merge all unresolved files',
6151 )
6154 )
6152
6155
6153 if confirm:
6156 if confirm:
6154 if all:
6157 if all:
6155 if ui.promptchoice(
6158 if ui.promptchoice(
6156 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6159 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6157 ):
6160 ):
6158 raise error.CanceledError(_(b'user quit'))
6161 raise error.CanceledError(_(b'user quit'))
6159 if mark and not pats:
6162 if mark and not pats:
6160 if ui.promptchoice(
6163 if ui.promptchoice(
6161 _(
6164 _(
6162 b'mark all unresolved files as resolved (yn)?'
6165 b'mark all unresolved files as resolved (yn)?'
6163 b'$$ &Yes $$ &No'
6166 b'$$ &Yes $$ &No'
6164 )
6167 )
6165 ):
6168 ):
6166 raise error.CanceledError(_(b'user quit'))
6169 raise error.CanceledError(_(b'user quit'))
6167 if unmark and not pats:
6170 if unmark and not pats:
6168 if ui.promptchoice(
6171 if ui.promptchoice(
6169 _(
6172 _(
6170 b'mark all resolved files as unresolved (yn)?'
6173 b'mark all resolved files as unresolved (yn)?'
6171 b'$$ &Yes $$ &No'
6174 b'$$ &Yes $$ &No'
6172 )
6175 )
6173 ):
6176 ):
6174 raise error.CanceledError(_(b'user quit'))
6177 raise error.CanceledError(_(b'user quit'))
6175
6178
6176 uipathfn = scmutil.getuipathfn(repo)
6179 uipathfn = scmutil.getuipathfn(repo)
6177
6180
6178 if show:
6181 if show:
6179 ui.pager(b'resolve')
6182 ui.pager(b'resolve')
6180 fm = ui.formatter(b'resolve', opts)
6183 fm = ui.formatter(b'resolve', opts)
6181 ms = mergestatemod.mergestate.read(repo)
6184 ms = mergestatemod.mergestate.read(repo)
6182 wctx = repo[None]
6185 wctx = repo[None]
6183 m = scmutil.match(wctx, pats, opts)
6186 m = scmutil.match(wctx, pats, opts)
6184
6187
6185 # Labels and keys based on merge state. Unresolved path conflicts show
6188 # Labels and keys based on merge state. Unresolved path conflicts show
6186 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6189 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6187 # resolved conflicts.
6190 # resolved conflicts.
6188 mergestateinfo = {
6191 mergestateinfo = {
6189 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6192 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6190 b'resolve.unresolved',
6193 b'resolve.unresolved',
6191 b'U',
6194 b'U',
6192 ),
6195 ),
6193 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6196 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6194 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6197 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6195 b'resolve.unresolved',
6198 b'resolve.unresolved',
6196 b'P',
6199 b'P',
6197 ),
6200 ),
6198 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6201 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6199 b'resolve.resolved',
6202 b'resolve.resolved',
6200 b'R',
6203 b'R',
6201 ),
6204 ),
6202 }
6205 }
6203
6206
6204 for f in ms:
6207 for f in ms:
6205 if not m(f):
6208 if not m(f):
6206 continue
6209 continue
6207
6210
6208 label, key = mergestateinfo[ms[f]]
6211 label, key = mergestateinfo[ms[f]]
6209 fm.startitem()
6212 fm.startitem()
6210 fm.context(ctx=wctx)
6213 fm.context(ctx=wctx)
6211 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6214 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6212 fm.data(path=f)
6215 fm.data(path=f)
6213 fm.plain(b'%s\n' % uipathfn(f), label=label)
6216 fm.plain(b'%s\n' % uipathfn(f), label=label)
6214 fm.end()
6217 fm.end()
6215 return 0
6218 return 0
6216
6219
6217 with repo.wlock():
6220 with repo.wlock():
6218 ms = mergestatemod.mergestate.read(repo)
6221 ms = mergestatemod.mergestate.read(repo)
6219
6222
6220 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6223 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6221 raise error.StateError(
6224 raise error.StateError(
6222 _(b'resolve command not applicable when not merging')
6225 _(b'resolve command not applicable when not merging')
6223 )
6226 )
6224
6227
6225 wctx = repo[None]
6228 wctx = repo[None]
6226 m = scmutil.match(wctx, pats, opts)
6229 m = scmutil.match(wctx, pats, opts)
6227 ret = 0
6230 ret = 0
6228 didwork = False
6231 didwork = False
6229
6232
6230 hasconflictmarkers = []
6233 hasconflictmarkers = []
6231 if mark:
6234 if mark:
6232 markcheck = ui.config(b'commands', b'resolve.mark-check')
6235 markcheck = ui.config(b'commands', b'resolve.mark-check')
6233 if markcheck not in [b'warn', b'abort']:
6236 if markcheck not in [b'warn', b'abort']:
6234 # Treat all invalid / unrecognized values as 'none'.
6237 # Treat all invalid / unrecognized values as 'none'.
6235 markcheck = False
6238 markcheck = False
6236 for f in ms:
6239 for f in ms:
6237 if not m(f):
6240 if not m(f):
6238 continue
6241 continue
6239
6242
6240 didwork = True
6243 didwork = True
6241
6244
6242 # path conflicts must be resolved manually
6245 # path conflicts must be resolved manually
6243 if ms[f] in (
6246 if ms[f] in (
6244 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6247 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6245 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6248 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6246 ):
6249 ):
6247 if mark:
6250 if mark:
6248 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6251 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6249 elif unmark:
6252 elif unmark:
6250 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6253 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6251 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6254 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6252 ui.warn(
6255 ui.warn(
6253 _(b'%s: path conflict must be resolved manually\n')
6256 _(b'%s: path conflict must be resolved manually\n')
6254 % uipathfn(f)
6257 % uipathfn(f)
6255 )
6258 )
6256 continue
6259 continue
6257
6260
6258 if mark:
6261 if mark:
6259 if markcheck:
6262 if markcheck:
6260 fdata = repo.wvfs.tryread(f)
6263 fdata = repo.wvfs.tryread(f)
6261 if (
6264 if (
6262 filemerge.hasconflictmarkers(fdata)
6265 filemerge.hasconflictmarkers(fdata)
6263 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6266 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6264 ):
6267 ):
6265 hasconflictmarkers.append(f)
6268 hasconflictmarkers.append(f)
6266 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6269 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6267 elif unmark:
6270 elif unmark:
6268 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6271 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6269 else:
6272 else:
6270 # backup pre-resolve (merge uses .orig for its own purposes)
6273 # backup pre-resolve (merge uses .orig for its own purposes)
6271 a = repo.wjoin(f)
6274 a = repo.wjoin(f)
6272 try:
6275 try:
6273 util.copyfile(a, a + b".resolve")
6276 util.copyfile(a, a + b".resolve")
6274 except FileNotFoundError:
6277 except FileNotFoundError:
6275 pass
6278 pass
6276
6279
6277 try:
6280 try:
6278 # preresolve file
6281 # preresolve file
6279 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6282 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6280 with ui.configoverride(overrides, b'resolve'):
6283 with ui.configoverride(overrides, b'resolve'):
6281 r = ms.resolve(f, wctx)
6284 r = ms.resolve(f, wctx)
6282 if r:
6285 if r:
6283 ret = 1
6286 ret = 1
6284 finally:
6287 finally:
6285 ms.commit()
6288 ms.commit()
6286
6289
6287 # replace filemerge's .orig file with our resolve file
6290 # replace filemerge's .orig file with our resolve file
6288 try:
6291 try:
6289 util.rename(
6292 util.rename(
6290 a + b".resolve", scmutil.backuppath(ui, repo, f)
6293 a + b".resolve", scmutil.backuppath(ui, repo, f)
6291 )
6294 )
6292 except FileNotFoundError:
6295 except FileNotFoundError:
6293 pass
6296 pass
6294
6297
6295 if hasconflictmarkers:
6298 if hasconflictmarkers:
6296 ui.warn(
6299 ui.warn(
6297 _(
6300 _(
6298 b'warning: the following files still have conflict '
6301 b'warning: the following files still have conflict '
6299 b'markers:\n'
6302 b'markers:\n'
6300 )
6303 )
6301 + b''.join(
6304 + b''.join(
6302 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6305 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6303 )
6306 )
6304 )
6307 )
6305 if markcheck == b'abort' and not all and not pats:
6308 if markcheck == b'abort' and not all and not pats:
6306 raise error.StateError(
6309 raise error.StateError(
6307 _(b'conflict markers detected'),
6310 _(b'conflict markers detected'),
6308 hint=_(b'use --all to mark anyway'),
6311 hint=_(b'use --all to mark anyway'),
6309 )
6312 )
6310
6313
6311 ms.commit()
6314 ms.commit()
6312 branchmerge = repo.dirstate.p2() != repo.nullid
6315 branchmerge = repo.dirstate.p2() != repo.nullid
6313 # resolve is not doing a parent change here, however, `record updates`
6316 # resolve is not doing a parent change here, however, `record updates`
6314 # will call some dirstate API that at intended for parent changes call.
6317 # will call some dirstate API that at intended for parent changes call.
6315 # Ideally we would not need this and could implement a lighter version
6318 # Ideally we would not need this and could implement a lighter version
6316 # of the recordupdateslogic that will not have to deal with the part
6319 # of the recordupdateslogic that will not have to deal with the part
6317 # related to parent changes. However this would requires that:
6320 # related to parent changes. However this would requires that:
6318 # - we are sure we passed around enough information at update/merge
6321 # - we are sure we passed around enough information at update/merge
6319 # time to no longer needs it at `hg resolve time`
6322 # time to no longer needs it at `hg resolve time`
6320 # - we are sure we store that information well enough to be able to reuse it
6323 # - we are sure we store that information well enough to be able to reuse it
6321 # - we are the necessary logic to reuse it right.
6324 # - we are the necessary logic to reuse it right.
6322 #
6325 #
6323 # All this should eventually happens, but in the mean time, we use this
6326 # All this should eventually happens, but in the mean time, we use this
6324 # context manager slightly out of the context it should be.
6327 # context manager slightly out of the context it should be.
6325 with repo.dirstate.changing_parents(repo):
6328 with repo.dirstate.changing_parents(repo):
6326 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6329 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6327
6330
6328 if not didwork and pats:
6331 if not didwork and pats:
6329 hint = None
6332 hint = None
6330 if not any([p for p in pats if p.find(b':') >= 0]):
6333 if not any([p for p in pats if p.find(b':') >= 0]):
6331 pats = [b'path:%s' % p for p in pats]
6334 pats = [b'path:%s' % p for p in pats]
6332 m = scmutil.match(wctx, pats, opts)
6335 m = scmutil.match(wctx, pats, opts)
6333 for f in ms:
6336 for f in ms:
6334 if not m(f):
6337 if not m(f):
6335 continue
6338 continue
6336
6339
6337 def flag(o):
6340 def flag(o):
6338 if o == b're_merge':
6341 if o == b're_merge':
6339 return b'--re-merge '
6342 return b'--re-merge '
6340 return b'-%s ' % o[0:1]
6343 return b'-%s ' % o[0:1]
6341
6344
6342 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6345 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6343 hint = _(b"(try: hg resolve %s%s)\n") % (
6346 hint = _(b"(try: hg resolve %s%s)\n") % (
6344 flags,
6347 flags,
6345 b' '.join(pats),
6348 b' '.join(pats),
6346 )
6349 )
6347 break
6350 break
6348 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6351 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6349 if hint:
6352 if hint:
6350 ui.warn(hint)
6353 ui.warn(hint)
6351
6354
6352 unresolvedf = ms.unresolvedcount()
6355 unresolvedf = ms.unresolvedcount()
6353 if not unresolvedf:
6356 if not unresolvedf:
6354 ui.status(_(b'(no more unresolved files)\n'))
6357 ui.status(_(b'(no more unresolved files)\n'))
6355 cmdutil.checkafterresolved(repo)
6358 cmdutil.checkafterresolved(repo)
6356
6359
6357 return ret
6360 return ret
6358
6361
6359
6362
6360 @command(
6363 @command(
6361 b'revert',
6364 b'revert',
6362 [
6365 [
6363 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6366 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6364 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6367 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6365 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6368 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6366 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6369 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6367 (b'i', b'interactive', None, _(b'interactively select the changes')),
6370 (b'i', b'interactive', None, _(b'interactively select the changes')),
6368 ]
6371 ]
6369 + walkopts
6372 + walkopts
6370 + dryrunopts,
6373 + dryrunopts,
6371 _(b'[OPTION]... [-r REV] [NAME]...'),
6374 _(b'[OPTION]... [-r REV] [NAME]...'),
6372 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6375 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6373 )
6376 )
6374 def revert(ui, repo, *pats, **opts):
6377 def revert(ui, repo, *pats, **opts):
6375 """restore files to their checkout state
6378 """restore files to their checkout state
6376
6379
6377 .. note::
6380 .. note::
6378
6381
6379 To check out earlier revisions, you should use :hg:`update REV`.
6382 To check out earlier revisions, you should use :hg:`update REV`.
6380 To cancel an uncommitted merge (and lose your changes),
6383 To cancel an uncommitted merge (and lose your changes),
6381 use :hg:`merge --abort`.
6384 use :hg:`merge --abort`.
6382
6385
6383 With no revision specified, revert the specified files or directories
6386 With no revision specified, revert the specified files or directories
6384 to the contents they had in the parent of the working directory.
6387 to the contents they had in the parent of the working directory.
6385 This restores the contents of files to an unmodified
6388 This restores the contents of files to an unmodified
6386 state and unschedules adds, removes, copies, and renames. If the
6389 state and unschedules adds, removes, copies, and renames. If the
6387 working directory has two parents, you must explicitly specify a
6390 working directory has two parents, you must explicitly specify a
6388 revision.
6391 revision.
6389
6392
6390 Using the -r/--rev or -d/--date options, revert the given files or
6393 Using the -r/--rev or -d/--date options, revert the given files or
6391 directories to their states as of a specific revision. Because
6394 directories to their states as of a specific revision. Because
6392 revert does not change the working directory parents, this will
6395 revert does not change the working directory parents, this will
6393 cause these files to appear modified. This can be helpful to "back
6396 cause these files to appear modified. This can be helpful to "back
6394 out" some or all of an earlier change. See :hg:`backout` for a
6397 out" some or all of an earlier change. See :hg:`backout` for a
6395 related method.
6398 related method.
6396
6399
6397 Modified files are saved with a .orig suffix before reverting.
6400 Modified files are saved with a .orig suffix before reverting.
6398 To disable these backups, use --no-backup. It is possible to store
6401 To disable these backups, use --no-backup. It is possible to store
6399 the backup files in a custom directory relative to the root of the
6402 the backup files in a custom directory relative to the root of the
6400 repository by setting the ``ui.origbackuppath`` configuration
6403 repository by setting the ``ui.origbackuppath`` configuration
6401 option.
6404 option.
6402
6405
6403 See :hg:`help dates` for a list of formats valid for -d/--date.
6406 See :hg:`help dates` for a list of formats valid for -d/--date.
6404
6407
6405 See :hg:`help backout` for a way to reverse the effect of an
6408 See :hg:`help backout` for a way to reverse the effect of an
6406 earlier changeset.
6409 earlier changeset.
6407
6410
6408 Returns 0 on success.
6411 Returns 0 on success.
6409 """
6412 """
6410
6413
6411 if opts.get("date"):
6414 if opts.get("date"):
6412 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6415 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6413 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6414
6417
6415 parent, p2 = repo.dirstate.parents()
6418 parent, p2 = repo.dirstate.parents()
6416 if not opts.get('rev') and p2 != repo.nullid:
6419 if not opts.get('rev') and p2 != repo.nullid:
6417 # revert after merge is a trap for new users (issue2915)
6420 # revert after merge is a trap for new users (issue2915)
6418 raise error.InputError(
6421 raise error.InputError(
6419 _(b'uncommitted merge with no revision specified'),
6422 _(b'uncommitted merge with no revision specified'),
6420 hint=_(b"use 'hg update' or see 'hg help revert'"),
6423 hint=_(b"use 'hg update' or see 'hg help revert'"),
6421 )
6424 )
6422
6425
6423 rev = opts.get('rev')
6426 rev = opts.get('rev')
6424 if rev:
6427 if rev:
6425 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6428 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6426 ctx = logcmdutil.revsingle(repo, rev)
6429 ctx = logcmdutil.revsingle(repo, rev)
6427
6430
6428 if not (
6431 if not (
6429 pats
6432 pats
6430 or opts.get('include')
6433 or opts.get('include')
6431 or opts.get('exclude')
6434 or opts.get('exclude')
6432 or opts.get('all')
6435 or opts.get('all')
6433 or opts.get('interactive')
6436 or opts.get('interactive')
6434 ):
6437 ):
6435 msg = _(b"no files or directories specified")
6438 msg = _(b"no files or directories specified")
6436 if p2 != repo.nullid:
6439 if p2 != repo.nullid:
6437 hint = _(
6440 hint = _(
6438 b"uncommitted merge, use --all to discard all changes,"
6441 b"uncommitted merge, use --all to discard all changes,"
6439 b" or 'hg update -C .' to abort the merge"
6442 b" or 'hg update -C .' to abort the merge"
6440 )
6443 )
6441 raise error.InputError(msg, hint=hint)
6444 raise error.InputError(msg, hint=hint)
6442 dirty = any(repo.status())
6445 dirty = any(repo.status())
6443 node = ctx.node()
6446 node = ctx.node()
6444 if node != parent:
6447 if node != parent:
6445 if dirty:
6448 if dirty:
6446 hint = (
6449 hint = (
6447 _(
6450 _(
6448 b"uncommitted changes, use --all to discard all"
6451 b"uncommitted changes, use --all to discard all"
6449 b" changes, or 'hg update %d' to update"
6452 b" changes, or 'hg update %d' to update"
6450 )
6453 )
6451 % ctx.rev()
6454 % ctx.rev()
6452 )
6455 )
6453 else:
6456 else:
6454 hint = (
6457 hint = (
6455 _(
6458 _(
6456 b"use --all to revert all files,"
6459 b"use --all to revert all files,"
6457 b" or 'hg update %d' to update"
6460 b" or 'hg update %d' to update"
6458 )
6461 )
6459 % ctx.rev()
6462 % ctx.rev()
6460 )
6463 )
6461 elif dirty:
6464 elif dirty:
6462 hint = _(b"uncommitted changes, use --all to discard all changes")
6465 hint = _(b"uncommitted changes, use --all to discard all changes")
6463 else:
6466 else:
6464 hint = _(b"use --all to revert all files")
6467 hint = _(b"use --all to revert all files")
6465 raise error.InputError(msg, hint=hint)
6468 raise error.InputError(msg, hint=hint)
6466
6469
6467 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6470 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6468
6471
6469
6472
6470 @command(
6473 @command(
6471 b'rollback',
6474 b'rollback',
6472 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6475 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6473 helpcategory=command.CATEGORY_MAINTENANCE,
6476 helpcategory=command.CATEGORY_MAINTENANCE,
6474 )
6477 )
6475 def rollback(ui, repo, **opts):
6478 def rollback(ui, repo, **opts):
6476 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6479 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6477
6480
6478 Please use :hg:`commit --amend` instead of rollback to correct
6481 Please use :hg:`commit --amend` instead of rollback to correct
6479 mistakes in the last commit.
6482 mistakes in the last commit.
6480
6483
6481 This command should be used with care. There is only one level of
6484 This command should be used with care. There is only one level of
6482 rollback, and there is no way to undo a rollback. It will also
6485 rollback, and there is no way to undo a rollback. It will also
6483 restore the dirstate at the time of the last transaction, losing
6486 restore the dirstate at the time of the last transaction, losing
6484 any dirstate changes since that time. This command does not alter
6487 any dirstate changes since that time. This command does not alter
6485 the working directory.
6488 the working directory.
6486
6489
6487 Transactions are used to encapsulate the effects of all commands
6490 Transactions are used to encapsulate the effects of all commands
6488 that create new changesets or propagate existing changesets into a
6491 that create new changesets or propagate existing changesets into a
6489 repository.
6492 repository.
6490
6493
6491 .. container:: verbose
6494 .. container:: verbose
6492
6495
6493 For example, the following commands are transactional, and their
6496 For example, the following commands are transactional, and their
6494 effects can be rolled back:
6497 effects can be rolled back:
6495
6498
6496 - commit
6499 - commit
6497 - import
6500 - import
6498 - pull
6501 - pull
6499 - push (with this repository as the destination)
6502 - push (with this repository as the destination)
6500 - unbundle
6503 - unbundle
6501
6504
6502 To avoid permanent data loss, rollback will refuse to rollback a
6505 To avoid permanent data loss, rollback will refuse to rollback a
6503 commit transaction if it isn't checked out. Use --force to
6506 commit transaction if it isn't checked out. Use --force to
6504 override this protection.
6507 override this protection.
6505
6508
6506 The rollback command can be entirely disabled by setting the
6509 The rollback command can be entirely disabled by setting the
6507 ``ui.rollback`` configuration setting to false. If you're here
6510 ``ui.rollback`` configuration setting to false. If you're here
6508 because you want to use rollback and it's disabled, you can
6511 because you want to use rollback and it's disabled, you can
6509 re-enable the command by setting ``ui.rollback`` to true.
6512 re-enable the command by setting ``ui.rollback`` to true.
6510
6513
6511 This command is not intended for use on public repositories. Once
6514 This command is not intended for use on public repositories. Once
6512 changes are visible for pull by other users, rolling a transaction
6515 changes are visible for pull by other users, rolling a transaction
6513 back locally is ineffective (someone else may already have pulled
6516 back locally is ineffective (someone else may already have pulled
6514 the changes). Furthermore, a race is possible with readers of the
6517 the changes). Furthermore, a race is possible with readers of the
6515 repository; for example an in-progress pull from the repository
6518 repository; for example an in-progress pull from the repository
6516 may fail if a rollback is performed.
6519 may fail if a rollback is performed.
6517
6520
6518 Returns 0 on success, 1 if no rollback data is available.
6521 Returns 0 on success, 1 if no rollback data is available.
6519 """
6522 """
6520 if not ui.configbool(b'ui', b'rollback'):
6523 if not ui.configbool(b'ui', b'rollback'):
6521 raise error.Abort(
6524 raise error.Abort(
6522 _(b'rollback is disabled because it is unsafe'),
6525 _(b'rollback is disabled because it is unsafe'),
6523 hint=b'see `hg help -v rollback` for information',
6526 hint=b'see `hg help -v rollback` for information',
6524 )
6527 )
6525 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6528 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6526
6529
6527
6530
6528 @command(
6531 @command(
6529 b'root',
6532 b'root',
6530 [] + formatteropts,
6533 [] + formatteropts,
6531 intents={INTENT_READONLY},
6534 intents={INTENT_READONLY},
6532 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6535 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6533 )
6536 )
6534 def root(ui, repo, **opts):
6537 def root(ui, repo, **opts):
6535 """print the root (top) of the current working directory
6538 """print the root (top) of the current working directory
6536
6539
6537 Print the root directory of the current repository.
6540 Print the root directory of the current repository.
6538
6541
6539 .. container:: verbose
6542 .. container:: verbose
6540
6543
6541 Template:
6544 Template:
6542
6545
6543 The following keywords are supported in addition to the common template
6546 The following keywords are supported in addition to the common template
6544 keywords and functions. See also :hg:`help templates`.
6547 keywords and functions. See also :hg:`help templates`.
6545
6548
6546 :hgpath: String. Path to the .hg directory.
6549 :hgpath: String. Path to the .hg directory.
6547 :storepath: String. Path to the directory holding versioned data.
6550 :storepath: String. Path to the directory holding versioned data.
6548
6551
6549 Returns 0 on success.
6552 Returns 0 on success.
6550 """
6553 """
6551 opts = pycompat.byteskwargs(opts)
6554 opts = pycompat.byteskwargs(opts)
6552 with ui.formatter(b'root', opts) as fm:
6555 with ui.formatter(b'root', opts) as fm:
6553 fm.startitem()
6556 fm.startitem()
6554 fm.write(b'reporoot', b'%s\n', repo.root)
6557 fm.write(b'reporoot', b'%s\n', repo.root)
6555 fm.data(hgpath=repo.path, storepath=repo.spath)
6558 fm.data(hgpath=repo.path, storepath=repo.spath)
6556
6559
6557
6560
6558 @command(
6561 @command(
6559 b'serve',
6562 b'serve',
6560 [
6563 [
6561 (
6564 (
6562 b'A',
6565 b'A',
6563 b'accesslog',
6566 b'accesslog',
6564 b'',
6567 b'',
6565 _(b'name of access log file to write to'),
6568 _(b'name of access log file to write to'),
6566 _(b'FILE'),
6569 _(b'FILE'),
6567 ),
6570 ),
6568 (b'd', b'daemon', None, _(b'run server in background')),
6571 (b'd', b'daemon', None, _(b'run server in background')),
6569 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6572 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6570 (
6573 (
6571 b'E',
6574 b'E',
6572 b'errorlog',
6575 b'errorlog',
6573 b'',
6576 b'',
6574 _(b'name of error log file to write to'),
6577 _(b'name of error log file to write to'),
6575 _(b'FILE'),
6578 _(b'FILE'),
6576 ),
6579 ),
6577 # use string type, then we can check if something was passed
6580 # use string type, then we can check if something was passed
6578 (
6581 (
6579 b'p',
6582 b'p',
6580 b'port',
6583 b'port',
6581 b'',
6584 b'',
6582 _(b'port to listen on (default: 8000)'),
6585 _(b'port to listen on (default: 8000)'),
6583 _(b'PORT'),
6586 _(b'PORT'),
6584 ),
6587 ),
6585 (
6588 (
6586 b'a',
6589 b'a',
6587 b'address',
6590 b'address',
6588 b'',
6591 b'',
6589 _(b'address to listen on (default: all interfaces)'),
6592 _(b'address to listen on (default: all interfaces)'),
6590 _(b'ADDR'),
6593 _(b'ADDR'),
6591 ),
6594 ),
6592 (
6595 (
6593 b'',
6596 b'',
6594 b'prefix',
6597 b'prefix',
6595 b'',
6598 b'',
6596 _(b'prefix path to serve from (default: server root)'),
6599 _(b'prefix path to serve from (default: server root)'),
6597 _(b'PREFIX'),
6600 _(b'PREFIX'),
6598 ),
6601 ),
6599 (
6602 (
6600 b'n',
6603 b'n',
6601 b'name',
6604 b'name',
6602 b'',
6605 b'',
6603 _(b'name to show in web pages (default: working directory)'),
6606 _(b'name to show in web pages (default: working directory)'),
6604 _(b'NAME'),
6607 _(b'NAME'),
6605 ),
6608 ),
6606 (
6609 (
6607 b'',
6610 b'',
6608 b'web-conf',
6611 b'web-conf',
6609 b'',
6612 b'',
6610 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6613 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6611 _(b'FILE'),
6614 _(b'FILE'),
6612 ),
6615 ),
6613 (
6616 (
6614 b'',
6617 b'',
6615 b'webdir-conf',
6618 b'webdir-conf',
6616 b'',
6619 b'',
6617 _(b'name of the hgweb config file (DEPRECATED)'),
6620 _(b'name of the hgweb config file (DEPRECATED)'),
6618 _(b'FILE'),
6621 _(b'FILE'),
6619 ),
6622 ),
6620 (
6623 (
6621 b'',
6624 b'',
6622 b'pid-file',
6625 b'pid-file',
6623 b'',
6626 b'',
6624 _(b'name of file to write process ID to'),
6627 _(b'name of file to write process ID to'),
6625 _(b'FILE'),
6628 _(b'FILE'),
6626 ),
6629 ),
6627 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6630 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6628 (
6631 (
6629 b'',
6632 b'',
6630 b'cmdserver',
6633 b'cmdserver',
6631 b'',
6634 b'',
6632 _(b'for remote clients (ADVANCED)'),
6635 _(b'for remote clients (ADVANCED)'),
6633 _(b'MODE'),
6636 _(b'MODE'),
6634 ),
6637 ),
6635 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6638 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6636 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6639 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6637 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6640 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6638 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6641 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6639 (b'', b'print-url', None, _(b'start and print only the URL')),
6642 (b'', b'print-url', None, _(b'start and print only the URL')),
6640 ]
6643 ]
6641 + subrepoopts,
6644 + subrepoopts,
6642 _(b'[OPTION]...'),
6645 _(b'[OPTION]...'),
6643 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6646 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6644 helpbasic=True,
6647 helpbasic=True,
6645 optionalrepo=True,
6648 optionalrepo=True,
6646 )
6649 )
6647 def serve(ui, repo, **opts):
6650 def serve(ui, repo, **opts):
6648 """start stand-alone webserver
6651 """start stand-alone webserver
6649
6652
6650 Start a local HTTP repository browser and pull server. You can use
6653 Start a local HTTP repository browser and pull server. You can use
6651 this for ad-hoc sharing and browsing of repositories. It is
6654 this for ad-hoc sharing and browsing of repositories. It is
6652 recommended to use a real web server to serve a repository for
6655 recommended to use a real web server to serve a repository for
6653 longer periods of time.
6656 longer periods of time.
6654
6657
6655 Please note that the server does not implement access control.
6658 Please note that the server does not implement access control.
6656 This means that, by default, anybody can read from the server and
6659 This means that, by default, anybody can read from the server and
6657 nobody can write to it by default. Set the ``web.allow-push``
6660 nobody can write to it by default. Set the ``web.allow-push``
6658 option to ``*`` to allow everybody to push to the server. You
6661 option to ``*`` to allow everybody to push to the server. You
6659 should use a real web server if you need to authenticate users.
6662 should use a real web server if you need to authenticate users.
6660
6663
6661 By default, the server logs accesses to stdout and errors to
6664 By default, the server logs accesses to stdout and errors to
6662 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6665 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6663 files.
6666 files.
6664
6667
6665 To have the server choose a free port number to listen on, specify
6668 To have the server choose a free port number to listen on, specify
6666 a port number of 0; in this case, the server will print the port
6669 a port number of 0; in this case, the server will print the port
6667 number it uses.
6670 number it uses.
6668
6671
6669 Returns 0 on success.
6672 Returns 0 on success.
6670 """
6673 """
6671
6674
6672 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6675 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6673 opts = pycompat.byteskwargs(opts)
6676 opts = pycompat.byteskwargs(opts)
6674 if opts[b"print_url"] and ui.verbose:
6677 if opts[b"print_url"] and ui.verbose:
6675 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6678 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6676
6679
6677 if opts[b"stdio"]:
6680 if opts[b"stdio"]:
6678 if repo is None:
6681 if repo is None:
6679 raise error.RepoError(
6682 raise error.RepoError(
6680 _(b"there is no Mercurial repository here (.hg not found)")
6683 _(b"there is no Mercurial repository here (.hg not found)")
6681 )
6684 )
6682 accesshidden = False
6685 accesshidden = False
6683 if repo.filtername is None:
6686 if repo.filtername is None:
6684 allow = ui.configlist(
6687 allow = ui.configlist(
6685 b'experimental', b'server.allow-hidden-access'
6688 b'experimental', b'server.allow-hidden-access'
6686 )
6689 )
6687 user = procutil.getuser()
6690 user = procutil.getuser()
6688 if allow and scmutil.ismember(ui, user, allow):
6691 if allow and scmutil.ismember(ui, user, allow):
6689 accesshidden = True
6692 accesshidden = True
6690 else:
6693 else:
6691 msg = (
6694 msg = (
6692 _(
6695 _(
6693 b'ignoring request to access hidden changeset by '
6696 b'ignoring request to access hidden changeset by '
6694 b'unauthorized user: %s\n'
6697 b'unauthorized user: %s\n'
6695 )
6698 )
6696 % user
6699 % user
6697 )
6700 )
6698 ui.warn(msg)
6701 ui.warn(msg)
6699
6702
6700 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6703 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6701 s.serve_forever()
6704 s.serve_forever()
6702 return
6705 return
6703
6706
6704 service = server.createservice(ui, repo, opts)
6707 service = server.createservice(ui, repo, opts)
6705 return server.runservice(opts, initfn=service.init, runfn=service.run)
6708 return server.runservice(opts, initfn=service.init, runfn=service.run)
6706
6709
6707
6710
6708 @command(
6711 @command(
6709 b'shelve',
6712 b'shelve',
6710 [
6713 [
6711 (
6714 (
6712 b'A',
6715 b'A',
6713 b'addremove',
6716 b'addremove',
6714 None,
6717 None,
6715 _(b'mark new/missing files as added/removed before shelving'),
6718 _(b'mark new/missing files as added/removed before shelving'),
6716 ),
6719 ),
6717 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6720 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6718 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6721 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6719 (
6722 (
6720 b'',
6723 b'',
6721 b'date',
6724 b'date',
6722 b'',
6725 b'',
6723 _(b'shelve with the specified commit date'),
6726 _(b'shelve with the specified commit date'),
6724 _(b'DATE'),
6727 _(b'DATE'),
6725 ),
6728 ),
6726 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6729 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6727 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6730 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6728 (
6731 (
6729 b'k',
6732 b'k',
6730 b'keep',
6733 b'keep',
6731 False,
6734 False,
6732 _(b'shelve, but keep changes in the working directory'),
6735 _(b'shelve, but keep changes in the working directory'),
6733 ),
6736 ),
6734 (b'l', b'list', None, _(b'list current shelves')),
6737 (b'l', b'list', None, _(b'list current shelves')),
6735 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6738 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6736 (
6739 (
6737 b'n',
6740 b'n',
6738 b'name',
6741 b'name',
6739 b'',
6742 b'',
6740 _(b'use the given name for the shelved commit'),
6743 _(b'use the given name for the shelved commit'),
6741 _(b'NAME'),
6744 _(b'NAME'),
6742 ),
6745 ),
6743 (
6746 (
6744 b'p',
6747 b'p',
6745 b'patch',
6748 b'patch',
6746 None,
6749 None,
6747 _(
6750 _(
6748 b'output patches for changes (provide the names of the shelved '
6751 b'output patches for changes (provide the names of the shelved '
6749 b'changes as positional arguments)'
6752 b'changes as positional arguments)'
6750 ),
6753 ),
6751 ),
6754 ),
6752 (b'i', b'interactive', None, _(b'interactive mode')),
6755 (b'i', b'interactive', None, _(b'interactive mode')),
6753 (
6756 (
6754 b'',
6757 b'',
6755 b'stat',
6758 b'stat',
6756 None,
6759 None,
6757 _(
6760 _(
6758 b'output diffstat-style summary of changes (provide the names of '
6761 b'output diffstat-style summary of changes (provide the names of '
6759 b'the shelved changes as positional arguments)'
6762 b'the shelved changes as positional arguments)'
6760 ),
6763 ),
6761 ),
6764 ),
6762 ]
6765 ]
6763 + cmdutil.walkopts,
6766 + cmdutil.walkopts,
6764 _(b'hg shelve [OPTION]... [FILE]...'),
6767 _(b'hg shelve [OPTION]... [FILE]...'),
6765 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6768 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6766 )
6769 )
6767 def shelve(ui, repo, *pats, **opts):
6770 def shelve(ui, repo, *pats, **opts):
6768 """save and set aside changes from the working directory
6771 """save and set aside changes from the working directory
6769
6772
6770 Shelving takes files that "hg status" reports as not clean, saves
6773 Shelving takes files that "hg status" reports as not clean, saves
6771 the modifications to a bundle (a shelved change), and reverts the
6774 the modifications to a bundle (a shelved change), and reverts the
6772 files so that their state in the working directory becomes clean.
6775 files so that their state in the working directory becomes clean.
6773
6776
6774 To restore these changes to the working directory, using "hg
6777 To restore these changes to the working directory, using "hg
6775 unshelve"; this will work even if you switch to a different
6778 unshelve"; this will work even if you switch to a different
6776 commit.
6779 commit.
6777
6780
6778 When no files are specified, "hg shelve" saves all not-clean
6781 When no files are specified, "hg shelve" saves all not-clean
6779 files. If specific files or directories are named, only changes to
6782 files. If specific files or directories are named, only changes to
6780 those files are shelved.
6783 those files are shelved.
6781
6784
6782 In bare shelve (when no files are specified, without interactive,
6785 In bare shelve (when no files are specified, without interactive,
6783 include and exclude option), shelving remembers information if the
6786 include and exclude option), shelving remembers information if the
6784 working directory was on newly created branch, in other words working
6787 working directory was on newly created branch, in other words working
6785 directory was on different branch than its first parent. In this
6788 directory was on different branch than its first parent. In this
6786 situation unshelving restores branch information to the working directory.
6789 situation unshelving restores branch information to the working directory.
6787
6790
6788 Each shelved change has a name that makes it easier to find later.
6791 Each shelved change has a name that makes it easier to find later.
6789 The name of a shelved change defaults to being based on the active
6792 The name of a shelved change defaults to being based on the active
6790 bookmark, or if there is no active bookmark, the current named
6793 bookmark, or if there is no active bookmark, the current named
6791 branch. To specify a different name, use ``--name``.
6794 branch. To specify a different name, use ``--name``.
6792
6795
6793 To see a list of existing shelved changes, use the ``--list``
6796 To see a list of existing shelved changes, use the ``--list``
6794 option. For each shelved change, this will print its name, age,
6797 option. For each shelved change, this will print its name, age,
6795 and description; use ``--patch`` or ``--stat`` for more details.
6798 and description; use ``--patch`` or ``--stat`` for more details.
6796
6799
6797 To delete specific shelved changes, use ``--delete``. To delete
6800 To delete specific shelved changes, use ``--delete``. To delete
6798 all shelved changes, use ``--cleanup``.
6801 all shelved changes, use ``--cleanup``.
6799 """
6802 """
6800 opts = pycompat.byteskwargs(opts)
6803 opts = pycompat.byteskwargs(opts)
6801 allowables = [
6804 allowables = [
6802 (b'addremove', {b'create'}), # 'create' is pseudo action
6805 (b'addremove', {b'create'}), # 'create' is pseudo action
6803 (b'unknown', {b'create'}),
6806 (b'unknown', {b'create'}),
6804 (b'cleanup', {b'cleanup'}),
6807 (b'cleanup', {b'cleanup'}),
6805 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6808 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6806 (b'delete', {b'delete'}),
6809 (b'delete', {b'delete'}),
6807 (b'edit', {b'create'}),
6810 (b'edit', {b'create'}),
6808 (b'keep', {b'create'}),
6811 (b'keep', {b'create'}),
6809 (b'list', {b'list'}),
6812 (b'list', {b'list'}),
6810 (b'message', {b'create'}),
6813 (b'message', {b'create'}),
6811 (b'name', {b'create'}),
6814 (b'name', {b'create'}),
6812 (b'patch', {b'patch', b'list'}),
6815 (b'patch', {b'patch', b'list'}),
6813 (b'stat', {b'stat', b'list'}),
6816 (b'stat', {b'stat', b'list'}),
6814 ]
6817 ]
6815
6818
6816 def checkopt(opt):
6819 def checkopt(opt):
6817 if opts.get(opt):
6820 if opts.get(opt):
6818 for i, allowable in allowables:
6821 for i, allowable in allowables:
6819 if opts[i] and opt not in allowable:
6822 if opts[i] and opt not in allowable:
6820 raise error.InputError(
6823 raise error.InputError(
6821 _(
6824 _(
6822 b"options '--%s' and '--%s' may not be "
6825 b"options '--%s' and '--%s' may not be "
6823 b"used together"
6826 b"used together"
6824 )
6827 )
6825 % (opt, i)
6828 % (opt, i)
6826 )
6829 )
6827 return True
6830 return True
6828
6831
6829 if checkopt(b'cleanup'):
6832 if checkopt(b'cleanup'):
6830 if pats:
6833 if pats:
6831 raise error.InputError(
6834 raise error.InputError(
6832 _(b"cannot specify names when using '--cleanup'")
6835 _(b"cannot specify names when using '--cleanup'")
6833 )
6836 )
6834 return shelvemod.cleanupcmd(ui, repo)
6837 return shelvemod.cleanupcmd(ui, repo)
6835 elif checkopt(b'delete'):
6838 elif checkopt(b'delete'):
6836 return shelvemod.deletecmd(ui, repo, pats)
6839 return shelvemod.deletecmd(ui, repo, pats)
6837 elif checkopt(b'list'):
6840 elif checkopt(b'list'):
6838 return shelvemod.listcmd(ui, repo, pats, opts)
6841 return shelvemod.listcmd(ui, repo, pats, opts)
6839 elif checkopt(b'patch') or checkopt(b'stat'):
6842 elif checkopt(b'patch') or checkopt(b'stat'):
6840 return shelvemod.patchcmds(ui, repo, pats, opts)
6843 return shelvemod.patchcmds(ui, repo, pats, opts)
6841 else:
6844 else:
6842 return shelvemod.createcmd(ui, repo, pats, opts)
6845 return shelvemod.createcmd(ui, repo, pats, opts)
6843
6846
6844
6847
6845 _NOTTERSE = b'nothing'
6848 _NOTTERSE = b'nothing'
6846
6849
6847
6850
6848 @command(
6851 @command(
6849 b'status|st',
6852 b'status|st',
6850 [
6853 [
6851 (b'A', b'all', None, _(b'show status of all files')),
6854 (b'A', b'all', None, _(b'show status of all files')),
6852 (b'm', b'modified', None, _(b'show only modified files')),
6855 (b'm', b'modified', None, _(b'show only modified files')),
6853 (b'a', b'added', None, _(b'show only added files')),
6856 (b'a', b'added', None, _(b'show only added files')),
6854 (b'r', b'removed', None, _(b'show only removed files')),
6857 (b'r', b'removed', None, _(b'show only removed files')),
6855 (b'd', b'deleted', None, _(b'show only missing files')),
6858 (b'd', b'deleted', None, _(b'show only missing files')),
6856 (b'c', b'clean', None, _(b'show only files without changes')),
6859 (b'c', b'clean', None, _(b'show only files without changes')),
6857 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6860 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6858 (b'i', b'ignored', None, _(b'show only ignored files')),
6861 (b'i', b'ignored', None, _(b'show only ignored files')),
6859 (b'n', b'no-status', None, _(b'hide status prefix')),
6862 (b'n', b'no-status', None, _(b'hide status prefix')),
6860 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6863 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6861 (
6864 (
6862 b'C',
6865 b'C',
6863 b'copies',
6866 b'copies',
6864 None,
6867 None,
6865 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6868 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6866 ),
6869 ),
6867 (
6870 (
6868 b'0',
6871 b'0',
6869 b'print0',
6872 b'print0',
6870 None,
6873 None,
6871 _(b'end filenames with NUL, for use with xargs'),
6874 _(b'end filenames with NUL, for use with xargs'),
6872 ),
6875 ),
6873 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6876 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6874 (
6877 (
6875 b'',
6878 b'',
6876 b'change',
6879 b'change',
6877 b'',
6880 b'',
6878 _(b'list the changed files of a revision'),
6881 _(b'list the changed files of a revision'),
6879 _(b'REV'),
6882 _(b'REV'),
6880 ),
6883 ),
6881 ]
6884 ]
6882 + walkopts
6885 + walkopts
6883 + subrepoopts
6886 + subrepoopts
6884 + formatteropts,
6887 + formatteropts,
6885 _(b'[OPTION]... [FILE]...'),
6888 _(b'[OPTION]... [FILE]...'),
6886 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6889 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6887 helpbasic=True,
6890 helpbasic=True,
6888 inferrepo=True,
6891 inferrepo=True,
6889 intents={INTENT_READONLY},
6892 intents={INTENT_READONLY},
6890 )
6893 )
6891 def status(ui, repo, *pats, **opts):
6894 def status(ui, repo, *pats, **opts):
6892 """show changed files in the working directory
6895 """show changed files in the working directory
6893
6896
6894 Show status of files in the repository. If names are given, only
6897 Show status of files in the repository. If names are given, only
6895 files that match are shown. Files that are clean or ignored or
6898 files that match are shown. Files that are clean or ignored or
6896 the source of a copy/move operation, are not listed unless
6899 the source of a copy/move operation, are not listed unless
6897 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6900 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6898 Unless options described with "show only ..." are given, the
6901 Unless options described with "show only ..." are given, the
6899 options -mardu are used.
6902 options -mardu are used.
6900
6903
6901 Option -q/--quiet hides untracked (unknown and ignored) files
6904 Option -q/--quiet hides untracked (unknown and ignored) files
6902 unless explicitly requested with -u/--unknown or -i/--ignored.
6905 unless explicitly requested with -u/--unknown or -i/--ignored.
6903
6906
6904 .. note::
6907 .. note::
6905
6908
6906 :hg:`status` may appear to disagree with diff if permissions have
6909 :hg:`status` may appear to disagree with diff if permissions have
6907 changed or a merge has occurred. The standard diff format does
6910 changed or a merge has occurred. The standard diff format does
6908 not report permission changes and diff only reports changes
6911 not report permission changes and diff only reports changes
6909 relative to one merge parent.
6912 relative to one merge parent.
6910
6913
6911 If one revision is given, it is used as the base revision.
6914 If one revision is given, it is used as the base revision.
6912 If two revisions are given, the differences between them are
6915 If two revisions are given, the differences between them are
6913 shown. The --change option can also be used as a shortcut to list
6916 shown. The --change option can also be used as a shortcut to list
6914 the changed files of a revision from its first parent.
6917 the changed files of a revision from its first parent.
6915
6918
6916 The codes used to show the status of files are::
6919 The codes used to show the status of files are::
6917
6920
6918 M = modified
6921 M = modified
6919 A = added
6922 A = added
6920 R = removed
6923 R = removed
6921 C = clean
6924 C = clean
6922 ! = missing (deleted by non-hg command, but still tracked)
6925 ! = missing (deleted by non-hg command, but still tracked)
6923 ? = not tracked
6926 ? = not tracked
6924 I = ignored
6927 I = ignored
6925 = origin of the previous file (with --copies)
6928 = origin of the previous file (with --copies)
6926
6929
6927 .. container:: verbose
6930 .. container:: verbose
6928
6931
6929 The -t/--terse option abbreviates the output by showing only the directory
6932 The -t/--terse option abbreviates the output by showing only the directory
6930 name if all the files in it share the same status. The option takes an
6933 name if all the files in it share the same status. The option takes an
6931 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6934 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6932 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6935 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6933 for 'ignored' and 'c' for clean.
6936 for 'ignored' and 'c' for clean.
6934
6937
6935 It abbreviates only those statuses which are passed. Note that clean and
6938 It abbreviates only those statuses which are passed. Note that clean and
6936 ignored files are not displayed with '--terse ic' unless the -c/--clean
6939 ignored files are not displayed with '--terse ic' unless the -c/--clean
6937 and -i/--ignored options are also used.
6940 and -i/--ignored options are also used.
6938
6941
6939 The -v/--verbose option shows information when the repository is in an
6942 The -v/--verbose option shows information when the repository is in an
6940 unfinished merge, shelve, rebase state etc. You can have this behavior
6943 unfinished merge, shelve, rebase state etc. You can have this behavior
6941 turned on by default by enabling the ``commands.status.verbose`` option.
6944 turned on by default by enabling the ``commands.status.verbose`` option.
6942
6945
6943 You can skip displaying some of these states by setting
6946 You can skip displaying some of these states by setting
6944 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6947 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6945 'histedit', 'merge', 'rebase', or 'unshelve'.
6948 'histedit', 'merge', 'rebase', or 'unshelve'.
6946
6949
6947 Template:
6950 Template:
6948
6951
6949 The following keywords are supported in addition to the common template
6952 The following keywords are supported in addition to the common template
6950 keywords and functions. See also :hg:`help templates`.
6953 keywords and functions. See also :hg:`help templates`.
6951
6954
6952 :path: String. Repository-absolute path of the file.
6955 :path: String. Repository-absolute path of the file.
6953 :source: String. Repository-absolute path of the file originated from.
6956 :source: String. Repository-absolute path of the file originated from.
6954 Available if ``--copies`` is specified.
6957 Available if ``--copies`` is specified.
6955 :status: String. Character denoting file's status.
6958 :status: String. Character denoting file's status.
6956
6959
6957 Examples:
6960 Examples:
6958
6961
6959 - show changes in the working directory relative to a
6962 - show changes in the working directory relative to a
6960 changeset::
6963 changeset::
6961
6964
6962 hg status --rev 9353
6965 hg status --rev 9353
6963
6966
6964 - show changes in the working directory relative to the
6967 - show changes in the working directory relative to the
6965 current directory (see :hg:`help patterns` for more information)::
6968 current directory (see :hg:`help patterns` for more information)::
6966
6969
6967 hg status re:
6970 hg status re:
6968
6971
6969 - show all changes including copies in an existing changeset::
6972 - show all changes including copies in an existing changeset::
6970
6973
6971 hg status --copies --change 9353
6974 hg status --copies --change 9353
6972
6975
6973 - get a NUL separated list of added files, suitable for xargs::
6976 - get a NUL separated list of added files, suitable for xargs::
6974
6977
6975 hg status -an0
6978 hg status -an0
6976
6979
6977 - show more information about the repository status, abbreviating
6980 - show more information about the repository status, abbreviating
6978 added, removed, modified, deleted, and untracked paths::
6981 added, removed, modified, deleted, and untracked paths::
6979
6982
6980 hg status -v -t mardu
6983 hg status -v -t mardu
6981
6984
6982 Returns 0 on success.
6985 Returns 0 on success.
6983
6986
6984 """
6987 """
6985
6988
6986 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6989 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6987 opts = pycompat.byteskwargs(opts)
6990 opts = pycompat.byteskwargs(opts)
6988 revs = opts.get(b'rev', [])
6991 revs = opts.get(b'rev', [])
6989 change = opts.get(b'change', b'')
6992 change = opts.get(b'change', b'')
6990 terse = opts.get(b'terse', _NOTTERSE)
6993 terse = opts.get(b'terse', _NOTTERSE)
6991 if terse is _NOTTERSE:
6994 if terse is _NOTTERSE:
6992 if revs:
6995 if revs:
6993 terse = b''
6996 terse = b''
6994 else:
6997 else:
6995 terse = ui.config(b'commands', b'status.terse')
6998 terse = ui.config(b'commands', b'status.terse')
6996
6999
6997 if revs and terse:
7000 if revs and terse:
6998 msg = _(b'cannot use --terse with --rev')
7001 msg = _(b'cannot use --terse with --rev')
6999 raise error.InputError(msg)
7002 raise error.InputError(msg)
7000 elif change:
7003 elif change:
7001 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
7004 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
7002 ctx2 = logcmdutil.revsingle(repo, change, None)
7005 ctx2 = logcmdutil.revsingle(repo, change, None)
7003 ctx1 = ctx2.p1()
7006 ctx1 = ctx2.p1()
7004 else:
7007 else:
7005 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7008 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
7006 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7009 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
7007
7010
7008 forcerelativevalue = None
7011 forcerelativevalue = None
7009 if ui.hasconfig(b'commands', b'status.relative'):
7012 if ui.hasconfig(b'commands', b'status.relative'):
7010 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7013 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
7011 uipathfn = scmutil.getuipathfn(
7014 uipathfn = scmutil.getuipathfn(
7012 repo,
7015 repo,
7013 legacyrelativevalue=bool(pats),
7016 legacyrelativevalue=bool(pats),
7014 forcerelativevalue=forcerelativevalue,
7017 forcerelativevalue=forcerelativevalue,
7015 )
7018 )
7016
7019
7017 if opts.get(b'print0'):
7020 if opts.get(b'print0'):
7018 end = b'\0'
7021 end = b'\0'
7019 else:
7022 else:
7020 end = b'\n'
7023 end = b'\n'
7021 states = b'modified added removed deleted unknown ignored clean'.split()
7024 states = b'modified added removed deleted unknown ignored clean'.split()
7022 show = [k for k in states if opts.get(k)]
7025 show = [k for k in states if opts.get(k)]
7023 if opts.get(b'all'):
7026 if opts.get(b'all'):
7024 show += ui.quiet and (states[:4] + [b'clean']) or states
7027 show += ui.quiet and (states[:4] + [b'clean']) or states
7025
7028
7026 if not show:
7029 if not show:
7027 if ui.quiet:
7030 if ui.quiet:
7028 show = states[:4]
7031 show = states[:4]
7029 else:
7032 else:
7030 show = states[:5]
7033 show = states[:5]
7031
7034
7032 m = scmutil.match(ctx2, pats, opts)
7035 m = scmutil.match(ctx2, pats, opts)
7033 if terse:
7036 if terse:
7034 # we need to compute clean and unknown to terse
7037 # we need to compute clean and unknown to terse
7035 stat = repo.status(
7038 stat = repo.status(
7036 ctx1.node(),
7039 ctx1.node(),
7037 ctx2.node(),
7040 ctx2.node(),
7038 m,
7041 m,
7039 b'ignored' in show or b'i' in terse,
7042 b'ignored' in show or b'i' in terse,
7040 clean=True,
7043 clean=True,
7041 unknown=True,
7044 unknown=True,
7042 listsubrepos=opts.get(b'subrepos'),
7045 listsubrepos=opts.get(b'subrepos'),
7043 )
7046 )
7044
7047
7045 stat = cmdutil.tersedir(stat, terse)
7048 stat = cmdutil.tersedir(stat, terse)
7046 else:
7049 else:
7047 stat = repo.status(
7050 stat = repo.status(
7048 ctx1.node(),
7051 ctx1.node(),
7049 ctx2.node(),
7052 ctx2.node(),
7050 m,
7053 m,
7051 b'ignored' in show,
7054 b'ignored' in show,
7052 b'clean' in show,
7055 b'clean' in show,
7053 b'unknown' in show,
7056 b'unknown' in show,
7054 opts.get(b'subrepos'),
7057 opts.get(b'subrepos'),
7055 )
7058 )
7056
7059
7057 changestates = zip(
7060 changestates = zip(
7058 states,
7061 states,
7059 pycompat.iterbytestr(b'MAR!?IC'),
7062 pycompat.iterbytestr(b'MAR!?IC'),
7060 [getattr(stat, s.decode('utf8')) for s in states],
7063 [getattr(stat, s.decode('utf8')) for s in states],
7061 )
7064 )
7062
7065
7063 copy = {}
7066 copy = {}
7064 show_copies = ui.configbool(b'ui', b'statuscopies')
7067 show_copies = ui.configbool(b'ui', b'statuscopies')
7065 if opts.get(b'copies') is not None:
7068 if opts.get(b'copies') is not None:
7066 show_copies = opts.get(b'copies')
7069 show_copies = opts.get(b'copies')
7067 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7070 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
7068 b'no_status'
7071 b'no_status'
7069 )
7072 )
7070 if show_copies:
7073 if show_copies:
7071 copy = copies.pathcopies(ctx1, ctx2, m)
7074 copy = copies.pathcopies(ctx1, ctx2, m)
7072
7075
7073 morestatus = None
7076 morestatus = None
7074 if (
7077 if (
7075 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7078 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
7076 and not ui.plain()
7079 and not ui.plain()
7077 and not opts.get(b'print0')
7080 and not opts.get(b'print0')
7078 ):
7081 ):
7079 morestatus = cmdutil.readmorestatus(repo)
7082 morestatus = cmdutil.readmorestatus(repo)
7080
7083
7081 ui.pager(b'status')
7084 ui.pager(b'status')
7082 fm = ui.formatter(b'status', opts)
7085 fm = ui.formatter(b'status', opts)
7083 fmt = b'%s' + end
7086 fmt = b'%s' + end
7084 showchar = not opts.get(b'no_status')
7087 showchar = not opts.get(b'no_status')
7085
7088
7086 for state, char, files in changestates:
7089 for state, char, files in changestates:
7087 if state in show:
7090 if state in show:
7088 label = b'status.' + state
7091 label = b'status.' + state
7089 for f in files:
7092 for f in files:
7090 fm.startitem()
7093 fm.startitem()
7091 fm.context(ctx=ctx2)
7094 fm.context(ctx=ctx2)
7092 fm.data(itemtype=b'file', path=f)
7095 fm.data(itemtype=b'file', path=f)
7093 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7096 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7094 fm.plain(fmt % uipathfn(f), label=label)
7097 fm.plain(fmt % uipathfn(f), label=label)
7095 if f in copy:
7098 if f in copy:
7096 fm.data(source=copy[f])
7099 fm.data(source=copy[f])
7097 fm.plain(
7100 fm.plain(
7098 (b' %s' + end) % uipathfn(copy[f]),
7101 (b' %s' + end) % uipathfn(copy[f]),
7099 label=b'status.copied',
7102 label=b'status.copied',
7100 )
7103 )
7101 if morestatus:
7104 if morestatus:
7102 morestatus.formatfile(f, fm)
7105 morestatus.formatfile(f, fm)
7103
7106
7104 if morestatus:
7107 if morestatus:
7105 morestatus.formatfooter(fm)
7108 morestatus.formatfooter(fm)
7106 fm.end()
7109 fm.end()
7107
7110
7108
7111
7109 @command(
7112 @command(
7110 b'summary|sum',
7113 b'summary|sum',
7111 [(b'', b'remote', None, _(b'check for push and pull'))],
7114 [(b'', b'remote', None, _(b'check for push and pull'))],
7112 b'[--remote]',
7115 b'[--remote]',
7113 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7116 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7114 helpbasic=True,
7117 helpbasic=True,
7115 intents={INTENT_READONLY},
7118 intents={INTENT_READONLY},
7116 )
7119 )
7117 def summary(ui, repo, **opts):
7120 def summary(ui, repo, **opts):
7118 """summarize working directory state
7121 """summarize working directory state
7119
7122
7120 This generates a brief summary of the working directory state,
7123 This generates a brief summary of the working directory state,
7121 including parents, branch, commit status, phase and available updates.
7124 including parents, branch, commit status, phase and available updates.
7122
7125
7123 With the --remote option, this will check the default paths for
7126 With the --remote option, this will check the default paths for
7124 incoming and outgoing changes. This can be time-consuming.
7127 incoming and outgoing changes. This can be time-consuming.
7125
7128
7126 Returns 0 on success.
7129 Returns 0 on success.
7127 """
7130 """
7128
7131
7129 ui.pager(b'summary')
7132 ui.pager(b'summary')
7130 ctx = repo[None]
7133 ctx = repo[None]
7131 parents = ctx.parents()
7134 parents = ctx.parents()
7132 pnode = parents[0].node()
7135 pnode = parents[0].node()
7133 marks = []
7136 marks = []
7134
7137
7135 try:
7138 try:
7136 ms = mergestatemod.mergestate.read(repo)
7139 ms = mergestatemod.mergestate.read(repo)
7137 except error.UnsupportedMergeRecords as e:
7140 except error.UnsupportedMergeRecords as e:
7138 s = b' '.join(e.recordtypes)
7141 s = b' '.join(e.recordtypes)
7139 ui.warn(
7142 ui.warn(
7140 _(b'warning: merge state has unsupported record types: %s\n') % s
7143 _(b'warning: merge state has unsupported record types: %s\n') % s
7141 )
7144 )
7142 unresolved = []
7145 unresolved = []
7143 else:
7146 else:
7144 unresolved = list(ms.unresolved())
7147 unresolved = list(ms.unresolved())
7145
7148
7146 for p in parents:
7149 for p in parents:
7147 # label with log.changeset (instead of log.parent) since this
7150 # label with log.changeset (instead of log.parent) since this
7148 # shows a working directory parent *changeset*:
7151 # shows a working directory parent *changeset*:
7149 # i18n: column positioning for "hg summary"
7152 # i18n: column positioning for "hg summary"
7150 ui.write(
7153 ui.write(
7151 _(b'parent: %d:%s ') % (p.rev(), p),
7154 _(b'parent: %d:%s ') % (p.rev(), p),
7152 label=logcmdutil.changesetlabels(p),
7155 label=logcmdutil.changesetlabels(p),
7153 )
7156 )
7154 ui.write(b' '.join(p.tags()), label=b'log.tag')
7157 ui.write(b' '.join(p.tags()), label=b'log.tag')
7155 if p.bookmarks():
7158 if p.bookmarks():
7156 marks.extend(p.bookmarks())
7159 marks.extend(p.bookmarks())
7157 if p.rev() == -1:
7160 if p.rev() == -1:
7158 if not len(repo):
7161 if not len(repo):
7159 ui.write(_(b' (empty repository)'))
7162 ui.write(_(b' (empty repository)'))
7160 else:
7163 else:
7161 ui.write(_(b' (no revision checked out)'))
7164 ui.write(_(b' (no revision checked out)'))
7162 if p.obsolete():
7165 if p.obsolete():
7163 ui.write(_(b' (obsolete)'))
7166 ui.write(_(b' (obsolete)'))
7164 if p.isunstable():
7167 if p.isunstable():
7165 instabilities = (
7168 instabilities = (
7166 ui.label(instability, b'trouble.%s' % instability)
7169 ui.label(instability, b'trouble.%s' % instability)
7167 for instability in p.instabilities()
7170 for instability in p.instabilities()
7168 )
7171 )
7169 ui.write(b' (' + b', '.join(instabilities) + b')')
7172 ui.write(b' (' + b', '.join(instabilities) + b')')
7170 ui.write(b'\n')
7173 ui.write(b'\n')
7171 if p.description():
7174 if p.description():
7172 ui.status(
7175 ui.status(
7173 b' ' + p.description().splitlines()[0].strip() + b'\n',
7176 b' ' + p.description().splitlines()[0].strip() + b'\n',
7174 label=b'log.summary',
7177 label=b'log.summary',
7175 )
7178 )
7176
7179
7177 branch = ctx.branch()
7180 branch = ctx.branch()
7178 bheads = repo.branchheads(branch)
7181 bheads = repo.branchheads(branch)
7179 # i18n: column positioning for "hg summary"
7182 # i18n: column positioning for "hg summary"
7180 m = _(b'branch: %s\n') % branch
7183 m = _(b'branch: %s\n') % branch
7181 if branch != b'default':
7184 if branch != b'default':
7182 ui.write(m, label=b'log.branch')
7185 ui.write(m, label=b'log.branch')
7183 else:
7186 else:
7184 ui.status(m, label=b'log.branch')
7187 ui.status(m, label=b'log.branch')
7185
7188
7186 if marks:
7189 if marks:
7187 active = repo._activebookmark
7190 active = repo._activebookmark
7188 # i18n: column positioning for "hg summary"
7191 # i18n: column positioning for "hg summary"
7189 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7192 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7190 if active is not None:
7193 if active is not None:
7191 if active in marks:
7194 if active in marks:
7192 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7195 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7193 marks.remove(active)
7196 marks.remove(active)
7194 else:
7197 else:
7195 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7198 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7196 for m in marks:
7199 for m in marks:
7197 ui.write(b' ' + m, label=b'log.bookmark')
7200 ui.write(b' ' + m, label=b'log.bookmark')
7198 ui.write(b'\n', label=b'log.bookmark')
7201 ui.write(b'\n', label=b'log.bookmark')
7199
7202
7200 status = repo.status(unknown=True)
7203 status = repo.status(unknown=True)
7201
7204
7202 c = repo.dirstate.copies()
7205 c = repo.dirstate.copies()
7203 copied, renamed = [], []
7206 copied, renamed = [], []
7204 for d, s in c.items():
7207 for d, s in c.items():
7205 if s in status.removed:
7208 if s in status.removed:
7206 status.removed.remove(s)
7209 status.removed.remove(s)
7207 renamed.append(d)
7210 renamed.append(d)
7208 else:
7211 else:
7209 copied.append(d)
7212 copied.append(d)
7210 if d in status.added:
7213 if d in status.added:
7211 status.added.remove(d)
7214 status.added.remove(d)
7212
7215
7213 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7216 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7214
7217
7215 labels = [
7218 labels = [
7216 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7219 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7217 (ui.label(_(b'%d added'), b'status.added'), status.added),
7220 (ui.label(_(b'%d added'), b'status.added'), status.added),
7218 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7221 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7219 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7222 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7220 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7223 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7221 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7224 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7222 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7225 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7223 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7226 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7224 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7227 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7225 ]
7228 ]
7226 t = []
7229 t = []
7227 for l, s in labels:
7230 for l, s in labels:
7228 if s:
7231 if s:
7229 t.append(l % len(s))
7232 t.append(l % len(s))
7230
7233
7231 t = b', '.join(t)
7234 t = b', '.join(t)
7232 cleanworkdir = False
7235 cleanworkdir = False
7233
7236
7234 if repo.vfs.exists(b'graftstate'):
7237 if repo.vfs.exists(b'graftstate'):
7235 t += _(b' (graft in progress)')
7238 t += _(b' (graft in progress)')
7236 if repo.vfs.exists(b'updatestate'):
7239 if repo.vfs.exists(b'updatestate'):
7237 t += _(b' (interrupted update)')
7240 t += _(b' (interrupted update)')
7238 elif len(parents) > 1:
7241 elif len(parents) > 1:
7239 t += _(b' (merge)')
7242 t += _(b' (merge)')
7240 elif branch != parents[0].branch():
7243 elif branch != parents[0].branch():
7241 t += _(b' (new branch)')
7244 t += _(b' (new branch)')
7242 elif parents[0].closesbranch() and pnode in repo.branchheads(
7245 elif parents[0].closesbranch() and pnode in repo.branchheads(
7243 branch, closed=True
7246 branch, closed=True
7244 ):
7247 ):
7245 t += _(b' (head closed)')
7248 t += _(b' (head closed)')
7246 elif not (
7249 elif not (
7247 status.modified
7250 status.modified
7248 or status.added
7251 or status.added
7249 or status.removed
7252 or status.removed
7250 or renamed
7253 or renamed
7251 or copied
7254 or copied
7252 or subs
7255 or subs
7253 ):
7256 ):
7254 t += _(b' (clean)')
7257 t += _(b' (clean)')
7255 cleanworkdir = True
7258 cleanworkdir = True
7256 elif pnode not in bheads:
7259 elif pnode not in bheads:
7257 t += _(b' (new branch head)')
7260 t += _(b' (new branch head)')
7258
7261
7259 if parents:
7262 if parents:
7260 pendingphase = max(p.phase() for p in parents)
7263 pendingphase = max(p.phase() for p in parents)
7261 else:
7264 else:
7262 pendingphase = phases.public
7265 pendingphase = phases.public
7263
7266
7264 if pendingphase > phases.newcommitphase(ui):
7267 if pendingphase > phases.newcommitphase(ui):
7265 t += b' (%s)' % phases.phasenames[pendingphase]
7268 t += b' (%s)' % phases.phasenames[pendingphase]
7266
7269
7267 if cleanworkdir:
7270 if cleanworkdir:
7268 # i18n: column positioning for "hg summary"
7271 # i18n: column positioning for "hg summary"
7269 ui.status(_(b'commit: %s\n') % t.strip())
7272 ui.status(_(b'commit: %s\n') % t.strip())
7270 else:
7273 else:
7271 # i18n: column positioning for "hg summary"
7274 # i18n: column positioning for "hg summary"
7272 ui.write(_(b'commit: %s\n') % t.strip())
7275 ui.write(_(b'commit: %s\n') % t.strip())
7273
7276
7274 # all ancestors of branch heads - all ancestors of parent = new csets
7277 # all ancestors of branch heads - all ancestors of parent = new csets
7275 new = len(
7278 new = len(
7276 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7279 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7277 )
7280 )
7278
7281
7279 if new == 0:
7282 if new == 0:
7280 # i18n: column positioning for "hg summary"
7283 # i18n: column positioning for "hg summary"
7281 ui.status(_(b'update: (current)\n'))
7284 ui.status(_(b'update: (current)\n'))
7282 elif pnode not in bheads:
7285 elif pnode not in bheads:
7283 # i18n: column positioning for "hg summary"
7286 # i18n: column positioning for "hg summary"
7284 ui.write(_(b'update: %d new changesets (update)\n') % new)
7287 ui.write(_(b'update: %d new changesets (update)\n') % new)
7285 else:
7288 else:
7286 # i18n: column positioning for "hg summary"
7289 # i18n: column positioning for "hg summary"
7287 ui.write(
7290 ui.write(
7288 _(b'update: %d new changesets, %d branch heads (merge)\n')
7291 _(b'update: %d new changesets, %d branch heads (merge)\n')
7289 % (new, len(bheads))
7292 % (new, len(bheads))
7290 )
7293 )
7291
7294
7292 t = []
7295 t = []
7293 draft = len(repo.revs(b'draft()'))
7296 draft = len(repo.revs(b'draft()'))
7294 if draft:
7297 if draft:
7295 t.append(_(b'%d draft') % draft)
7298 t.append(_(b'%d draft') % draft)
7296 secret = len(repo.revs(b'secret()'))
7299 secret = len(repo.revs(b'secret()'))
7297 if secret:
7300 if secret:
7298 t.append(_(b'%d secret') % secret)
7301 t.append(_(b'%d secret') % secret)
7299
7302
7300 if draft or secret:
7303 if draft or secret:
7301 ui.status(_(b'phases: %s\n') % b', '.join(t))
7304 ui.status(_(b'phases: %s\n') % b', '.join(t))
7302
7305
7303 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7306 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7304 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7307 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7305 numtrouble = len(repo.revs(trouble + b"()"))
7308 numtrouble = len(repo.revs(trouble + b"()"))
7306 # We write all the possibilities to ease translation
7309 # We write all the possibilities to ease translation
7307 troublemsg = {
7310 troublemsg = {
7308 b"orphan": _(b"orphan: %d changesets"),
7311 b"orphan": _(b"orphan: %d changesets"),
7309 b"contentdivergent": _(b"content-divergent: %d changesets"),
7312 b"contentdivergent": _(b"content-divergent: %d changesets"),
7310 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7313 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7311 }
7314 }
7312 if numtrouble > 0:
7315 if numtrouble > 0:
7313 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7316 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7314
7317
7315 cmdutil.summaryhooks(ui, repo)
7318 cmdutil.summaryhooks(ui, repo)
7316
7319
7317 if opts.get('remote'):
7320 if opts.get('remote'):
7318 needsincoming, needsoutgoing = True, True
7321 needsincoming, needsoutgoing = True, True
7319 else:
7322 else:
7320 needsincoming, needsoutgoing = False, False
7323 needsincoming, needsoutgoing = False, False
7321 for i, o in cmdutil.summaryremotehooks(
7324 for i, o in cmdutil.summaryremotehooks(
7322 ui, repo, pycompat.byteskwargs(opts), None
7325 ui, repo, pycompat.byteskwargs(opts), None
7323 ):
7326 ):
7324 if i:
7327 if i:
7325 needsincoming = True
7328 needsincoming = True
7326 if o:
7329 if o:
7327 needsoutgoing = True
7330 needsoutgoing = True
7328 if not needsincoming and not needsoutgoing:
7331 if not needsincoming and not needsoutgoing:
7329 return
7332 return
7330
7333
7331 def getincoming():
7334 def getincoming():
7332 # XXX We should actually skip this if no default is specified, instead
7335 # XXX We should actually skip this if no default is specified, instead
7333 # of passing "default" which will resolve as "./default/" if no default
7336 # of passing "default" which will resolve as "./default/" if no default
7334 # path is defined.
7337 # path is defined.
7335 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7338 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7336 sbranch = path.branch
7339 sbranch = path.branch
7337 try:
7340 try:
7338 other = hg.peer(repo, {}, path)
7341 other = hg.peer(repo, {}, path)
7339 except error.RepoError:
7342 except error.RepoError:
7340 if opts.get('remote'):
7343 if opts.get('remote'):
7341 raise
7344 raise
7342 return path.loc, sbranch, None, None, None
7345 return path.loc, sbranch, None, None, None
7343 branches = (path.branch, [])
7346 branches = (path.branch, [])
7344 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7347 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7345 if revs:
7348 if revs:
7346 revs = [other.lookup(rev) for rev in revs]
7349 revs = [other.lookup(rev) for rev in revs]
7347 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7350 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7348 with repo.ui.silent():
7351 with repo.ui.silent():
7349 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7352 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7350 return path.loc, sbranch, other, commoninc, commoninc[1]
7353 return path.loc, sbranch, other, commoninc, commoninc[1]
7351
7354
7352 if needsincoming:
7355 if needsincoming:
7353 source, sbranch, sother, commoninc, incoming = getincoming()
7356 source, sbranch, sother, commoninc, incoming = getincoming()
7354 else:
7357 else:
7355 source = sbranch = sother = commoninc = incoming = None
7358 source = sbranch = sother = commoninc = incoming = None
7356
7359
7357 def getoutgoing():
7360 def getoutgoing():
7358 # XXX We should actually skip this if no default is specified, instead
7361 # XXX We should actually skip this if no default is specified, instead
7359 # of passing "default" which will resolve as "./default/" if no default
7362 # of passing "default" which will resolve as "./default/" if no default
7360 # path is defined.
7363 # path is defined.
7361 d = None
7364 d = None
7362 if b'default-push' in ui.paths:
7365 if b'default-push' in ui.paths:
7363 d = b'default-push'
7366 d = b'default-push'
7364 elif b'default' in ui.paths:
7367 elif b'default' in ui.paths:
7365 d = b'default'
7368 d = b'default'
7366 path = None
7369 path = None
7367 if d is not None:
7370 if d is not None:
7368 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7371 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7369 dest = path.loc
7372 dest = path.loc
7370 dbranch = path.branch
7373 dbranch = path.branch
7371 else:
7374 else:
7372 dest = b'default'
7375 dest = b'default'
7373 dbranch = None
7376 dbranch = None
7374 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7377 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7375 if source != dest:
7378 if source != dest:
7376 try:
7379 try:
7377 dother = hg.peer(repo, {}, path if path is not None else dest)
7380 dother = hg.peer(repo, {}, path if path is not None else dest)
7378 except error.RepoError:
7381 except error.RepoError:
7379 if opts.get('remote'):
7382 if opts.get('remote'):
7380 raise
7383 raise
7381 return dest, dbranch, None, None
7384 return dest, dbranch, None, None
7382 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7385 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7383 elif sother is None:
7386 elif sother is None:
7384 # there is no explicit destination peer, but source one is invalid
7387 # there is no explicit destination peer, but source one is invalid
7385 return dest, dbranch, None, None
7388 return dest, dbranch, None, None
7386 else:
7389 else:
7387 dother = sother
7390 dother = sother
7388 if source != dest or (sbranch is not None and sbranch != dbranch):
7391 if source != dest or (sbranch is not None and sbranch != dbranch):
7389 common = None
7392 common = None
7390 else:
7393 else:
7391 common = commoninc
7394 common = commoninc
7392 if revs:
7395 if revs:
7393 revs = [repo.lookup(rev) for rev in revs]
7396 revs = [repo.lookup(rev) for rev in revs]
7394 with repo.ui.silent():
7397 with repo.ui.silent():
7395 outgoing = discovery.findcommonoutgoing(
7398 outgoing = discovery.findcommonoutgoing(
7396 repo, dother, onlyheads=revs, commoninc=common
7399 repo, dother, onlyheads=revs, commoninc=common
7397 )
7400 )
7398 return dest, dbranch, dother, outgoing
7401 return dest, dbranch, dother, outgoing
7399
7402
7400 if needsoutgoing:
7403 if needsoutgoing:
7401 dest, dbranch, dother, outgoing = getoutgoing()
7404 dest, dbranch, dother, outgoing = getoutgoing()
7402 else:
7405 else:
7403 dest = dbranch = dother = outgoing = None
7406 dest = dbranch = dother = outgoing = None
7404
7407
7405 if opts.get('remote'):
7408 if opts.get('remote'):
7406 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7409 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7407 # The former always sets `sother` (or raises an exception if it can't);
7410 # The former always sets `sother` (or raises an exception if it can't);
7408 # the latter always sets `outgoing`.
7411 # the latter always sets `outgoing`.
7409 assert sother is not None
7412 assert sother is not None
7410 assert outgoing is not None
7413 assert outgoing is not None
7411
7414
7412 t = []
7415 t = []
7413 if incoming:
7416 if incoming:
7414 t.append(_(b'1 or more incoming'))
7417 t.append(_(b'1 or more incoming'))
7415 o = outgoing.missing
7418 o = outgoing.missing
7416 if o:
7419 if o:
7417 t.append(_(b'%d outgoing') % len(o))
7420 t.append(_(b'%d outgoing') % len(o))
7418 other = dother or sother
7421 other = dother or sother
7419 if b'bookmarks' in other.listkeys(b'namespaces'):
7422 if b'bookmarks' in other.listkeys(b'namespaces'):
7420 counts = bookmarks.summary(repo, other)
7423 counts = bookmarks.summary(repo, other)
7421 if counts[0] > 0:
7424 if counts[0] > 0:
7422 t.append(_(b'%d incoming bookmarks') % counts[0])
7425 t.append(_(b'%d incoming bookmarks') % counts[0])
7423 if counts[1] > 0:
7426 if counts[1] > 0:
7424 t.append(_(b'%d outgoing bookmarks') % counts[1])
7427 t.append(_(b'%d outgoing bookmarks') % counts[1])
7425
7428
7426 if t:
7429 if t:
7427 # i18n: column positioning for "hg summary"
7430 # i18n: column positioning for "hg summary"
7428 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7431 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7429 else:
7432 else:
7430 # i18n: column positioning for "hg summary"
7433 # i18n: column positioning for "hg summary"
7431 ui.status(_(b'remote: (synced)\n'))
7434 ui.status(_(b'remote: (synced)\n'))
7432
7435
7433 cmdutil.summaryremotehooks(
7436 cmdutil.summaryremotehooks(
7434 ui,
7437 ui,
7435 repo,
7438 repo,
7436 pycompat.byteskwargs(opts),
7439 pycompat.byteskwargs(opts),
7437 (
7440 (
7438 (source, sbranch, sother, commoninc),
7441 (source, sbranch, sother, commoninc),
7439 (dest, dbranch, dother, outgoing),
7442 (dest, dbranch, dother, outgoing),
7440 ),
7443 ),
7441 )
7444 )
7442
7445
7443
7446
7444 @command(
7447 @command(
7445 b'tag',
7448 b'tag',
7446 [
7449 [
7447 (b'f', b'force', None, _(b'force tag')),
7450 (b'f', b'force', None, _(b'force tag')),
7448 (b'l', b'local', None, _(b'make the tag local')),
7451 (b'l', b'local', None, _(b'make the tag local')),
7449 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7452 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7450 (b'', b'remove', None, _(b'remove a tag')),
7453 (b'', b'remove', None, _(b'remove a tag')),
7451 # -l/--local is already there, commitopts cannot be used
7454 # -l/--local is already there, commitopts cannot be used
7452 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7455 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7453 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7456 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7454 ]
7457 ]
7455 + commitopts2,
7458 + commitopts2,
7456 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7459 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7457 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7460 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7458 )
7461 )
7459 def tag(ui, repo, name1, *names, **opts):
7462 def tag(ui, repo, name1, *names, **opts):
7460 """add one or more tags for the current or given revision
7463 """add one or more tags for the current or given revision
7461
7464
7462 Name a particular revision using <name>.
7465 Name a particular revision using <name>.
7463
7466
7464 Tags are used to name particular revisions of the repository and are
7467 Tags are used to name particular revisions of the repository and are
7465 very useful to compare different revisions, to go back to significant
7468 very useful to compare different revisions, to go back to significant
7466 earlier versions or to mark branch points as releases, etc. Changing
7469 earlier versions or to mark branch points as releases, etc. Changing
7467 an existing tag is normally disallowed; use -f/--force to override.
7470 an existing tag is normally disallowed; use -f/--force to override.
7468
7471
7469 If no revision is given, the parent of the working directory is
7472 If no revision is given, the parent of the working directory is
7470 used.
7473 used.
7471
7474
7472 To facilitate version control, distribution, and merging of tags,
7475 To facilitate version control, distribution, and merging of tags,
7473 they are stored as a file named ".hgtags" which is managed similarly
7476 they are stored as a file named ".hgtags" which is managed similarly
7474 to other project files and can be hand-edited if necessary. This
7477 to other project files and can be hand-edited if necessary. This
7475 also means that tagging creates a new commit. The file
7478 also means that tagging creates a new commit. The file
7476 ".hg/localtags" is used for local tags (not shared among
7479 ".hg/localtags" is used for local tags (not shared among
7477 repositories).
7480 repositories).
7478
7481
7479 Tag commits are usually made at the head of a branch. If the parent
7482 Tag commits are usually made at the head of a branch. If the parent
7480 of the working directory is not a branch head, :hg:`tag` aborts; use
7483 of the working directory is not a branch head, :hg:`tag` aborts; use
7481 -f/--force to force the tag commit to be based on a non-head
7484 -f/--force to force the tag commit to be based on a non-head
7482 changeset.
7485 changeset.
7483
7486
7484 See :hg:`help dates` for a list of formats valid for -d/--date.
7487 See :hg:`help dates` for a list of formats valid for -d/--date.
7485
7488
7486 Since tag names have priority over branch names during revision
7489 Since tag names have priority over branch names during revision
7487 lookup, using an existing branch name as a tag name is discouraged.
7490 lookup, using an existing branch name as a tag name is discouraged.
7488
7491
7489 Returns 0 on success.
7492 Returns 0 on success.
7490 """
7493 """
7491 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7494 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7492
7495
7493 with repo.wlock(), repo.lock():
7496 with repo.wlock(), repo.lock():
7494 rev_ = b"."
7497 rev_ = b"."
7495 names = [t.strip() for t in (name1,) + names]
7498 names = [t.strip() for t in (name1,) + names]
7496 if len(names) != len(set(names)):
7499 if len(names) != len(set(names)):
7497 raise error.InputError(_(b'tag names must be unique'))
7500 raise error.InputError(_(b'tag names must be unique'))
7498 for n in names:
7501 for n in names:
7499 scmutil.checknewlabel(repo, n, b'tag')
7502 scmutil.checknewlabel(repo, n, b'tag')
7500 if not n:
7503 if not n:
7501 raise error.InputError(
7504 raise error.InputError(
7502 _(b'tag names cannot consist entirely of whitespace')
7505 _(b'tag names cannot consist entirely of whitespace')
7503 )
7506 )
7504 if opts.get('rev'):
7507 if opts.get('rev'):
7505 rev_ = opts['rev']
7508 rev_ = opts['rev']
7506 message = opts.get('message')
7509 message = opts.get('message')
7507 if opts.get('remove'):
7510 if opts.get('remove'):
7508 if opts.get('local'):
7511 if opts.get('local'):
7509 expectedtype = b'local'
7512 expectedtype = b'local'
7510 else:
7513 else:
7511 expectedtype = b'global'
7514 expectedtype = b'global'
7512
7515
7513 for n in names:
7516 for n in names:
7514 if repo.tagtype(n) == b'global':
7517 if repo.tagtype(n) == b'global':
7515 alltags = tagsmod.findglobaltags(ui, repo)
7518 alltags = tagsmod.findglobaltags(ui, repo)
7516 if alltags[n][0] == repo.nullid:
7519 if alltags[n][0] == repo.nullid:
7517 raise error.InputError(
7520 raise error.InputError(
7518 _(b"tag '%s' is already removed") % n
7521 _(b"tag '%s' is already removed") % n
7519 )
7522 )
7520 if not repo.tagtype(n):
7523 if not repo.tagtype(n):
7521 raise error.InputError(_(b"tag '%s' does not exist") % n)
7524 raise error.InputError(_(b"tag '%s' does not exist") % n)
7522 if repo.tagtype(n) != expectedtype:
7525 if repo.tagtype(n) != expectedtype:
7523 if expectedtype == b'global':
7526 if expectedtype == b'global':
7524 raise error.InputError(
7527 raise error.InputError(
7525 _(b"tag '%s' is not a global tag") % n
7528 _(b"tag '%s' is not a global tag") % n
7526 )
7529 )
7527 else:
7530 else:
7528 raise error.InputError(
7531 raise error.InputError(
7529 _(b"tag '%s' is not a local tag") % n
7532 _(b"tag '%s' is not a local tag") % n
7530 )
7533 )
7531 rev_ = b'null'
7534 rev_ = b'null'
7532 if not message:
7535 if not message:
7533 # we don't translate commit messages
7536 # we don't translate commit messages
7534 message = b'Removed tag %s' % b', '.join(names)
7537 message = b'Removed tag %s' % b', '.join(names)
7535 elif not opts.get('force'):
7538 elif not opts.get('force'):
7536 for n in names:
7539 for n in names:
7537 if n in repo.tags():
7540 if n in repo.tags():
7538 raise error.InputError(
7541 raise error.InputError(
7539 _(b"tag '%s' already exists (use -f to force)") % n
7542 _(b"tag '%s' already exists (use -f to force)") % n
7540 )
7543 )
7541 if not opts.get('local'):
7544 if not opts.get('local'):
7542 p1, p2 = repo.dirstate.parents()
7545 p1, p2 = repo.dirstate.parents()
7543 if p2 != repo.nullid:
7546 if p2 != repo.nullid:
7544 raise error.StateError(_(b'uncommitted merge'))
7547 raise error.StateError(_(b'uncommitted merge'))
7545 bheads = repo.branchheads()
7548 bheads = repo.branchheads()
7546 if not opts.get('force') and bheads and p1 not in bheads:
7549 if not opts.get('force') and bheads and p1 not in bheads:
7547 raise error.InputError(
7550 raise error.InputError(
7548 _(
7551 _(
7549 b'working directory is not at a branch head '
7552 b'working directory is not at a branch head '
7550 b'(use -f to force)'
7553 b'(use -f to force)'
7551 )
7554 )
7552 )
7555 )
7553 node = logcmdutil.revsingle(repo, rev_).node()
7556 node = logcmdutil.revsingle(repo, rev_).node()
7554
7557
7555 # don't allow tagging the null rev or the working directory
7558 # don't allow tagging the null rev or the working directory
7556 if node is None:
7559 if node is None:
7557 raise error.InputError(_(b"cannot tag working directory"))
7560 raise error.InputError(_(b"cannot tag working directory"))
7558 elif not opts.get('remove') and node == nullid:
7561 elif not opts.get('remove') and node == nullid:
7559 raise error.InputError(_(b"cannot tag null revision"))
7562 raise error.InputError(_(b"cannot tag null revision"))
7560
7563
7561 if not message:
7564 if not message:
7562 # we don't translate commit messages
7565 # we don't translate commit messages
7563 message = b'Added tag %s for changeset %s' % (
7566 message = b'Added tag %s for changeset %s' % (
7564 b', '.join(names),
7567 b', '.join(names),
7565 short(node),
7568 short(node),
7566 )
7569 )
7567
7570
7568 date = opts.get('date')
7571 date = opts.get('date')
7569 if date:
7572 if date:
7570 date = dateutil.parsedate(date)
7573 date = dateutil.parsedate(date)
7571
7574
7572 if opts.get('remove'):
7575 if opts.get('remove'):
7573 editform = b'tag.remove'
7576 editform = b'tag.remove'
7574 else:
7577 else:
7575 editform = b'tag.add'
7578 editform = b'tag.add'
7576 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7579 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7577
7580
7578 tagsmod.tag(
7581 tagsmod.tag(
7579 repo,
7582 repo,
7580 names,
7583 names,
7581 node,
7584 node,
7582 message,
7585 message,
7583 opts.get('local'),
7586 opts.get('local'),
7584 opts.get('user'),
7587 opts.get('user'),
7585 date,
7588 date,
7586 editor=editor,
7589 editor=editor,
7587 )
7590 )
7588
7591
7589
7592
7590 @command(
7593 @command(
7591 b'tags',
7594 b'tags',
7592 formatteropts,
7595 formatteropts,
7593 b'',
7596 b'',
7594 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7597 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7595 intents={INTENT_READONLY},
7598 intents={INTENT_READONLY},
7596 )
7599 )
7597 def tags(ui, repo, **opts):
7600 def tags(ui, repo, **opts):
7598 """list repository tags
7601 """list repository tags
7599
7602
7600 This lists both regular and local tags. When the -v/--verbose
7603 This lists both regular and local tags. When the -v/--verbose
7601 switch is used, a third column "local" is printed for local tags.
7604 switch is used, a third column "local" is printed for local tags.
7602 When the -q/--quiet switch is used, only the tag name is printed.
7605 When the -q/--quiet switch is used, only the tag name is printed.
7603
7606
7604 .. container:: verbose
7607 .. container:: verbose
7605
7608
7606 Template:
7609 Template:
7607
7610
7608 The following keywords are supported in addition to the common template
7611 The following keywords are supported in addition to the common template
7609 keywords and functions such as ``{tag}``. See also
7612 keywords and functions such as ``{tag}``. See also
7610 :hg:`help templates`.
7613 :hg:`help templates`.
7611
7614
7612 :type: String. ``local`` for local tags.
7615 :type: String. ``local`` for local tags.
7613
7616
7614 Returns 0 on success.
7617 Returns 0 on success.
7615 """
7618 """
7616
7619
7617 ui.pager(b'tags')
7620 ui.pager(b'tags')
7618 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7621 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7619 hexfunc = fm.hexfunc
7622 hexfunc = fm.hexfunc
7620
7623
7621 for t, n in reversed(repo.tagslist()):
7624 for t, n in reversed(repo.tagslist()):
7622 hn = hexfunc(n)
7625 hn = hexfunc(n)
7623 label = b'tags.normal'
7626 label = b'tags.normal'
7624 tagtype = repo.tagtype(t)
7627 tagtype = repo.tagtype(t)
7625 if not tagtype or tagtype == b'global':
7628 if not tagtype or tagtype == b'global':
7626 tagtype = b''
7629 tagtype = b''
7627 else:
7630 else:
7628 label = b'tags.' + tagtype
7631 label = b'tags.' + tagtype
7629
7632
7630 fm.startitem()
7633 fm.startitem()
7631 fm.context(repo=repo)
7634 fm.context(repo=repo)
7632 fm.write(b'tag', b'%s', t, label=label)
7635 fm.write(b'tag', b'%s', t, label=label)
7633 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7636 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7634 fm.condwrite(
7637 fm.condwrite(
7635 not ui.quiet,
7638 not ui.quiet,
7636 b'rev node',
7639 b'rev node',
7637 fmt,
7640 fmt,
7638 repo.changelog.rev(n),
7641 repo.changelog.rev(n),
7639 hn,
7642 hn,
7640 label=label,
7643 label=label,
7641 )
7644 )
7642 fm.condwrite(
7645 fm.condwrite(
7643 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7646 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7644 )
7647 )
7645 fm.plain(b'\n')
7648 fm.plain(b'\n')
7646 fm.end()
7649 fm.end()
7647
7650
7648
7651
7649 @command(
7652 @command(
7650 b'tip',
7653 b'tip',
7651 [
7654 [
7652 (b'p', b'patch', None, _(b'show patch')),
7655 (b'p', b'patch', None, _(b'show patch')),
7653 (b'g', b'git', None, _(b'use git extended diff format')),
7656 (b'g', b'git', None, _(b'use git extended diff format')),
7654 ]
7657 ]
7655 + templateopts,
7658 + templateopts,
7656 _(b'[-p] [-g]'),
7659 _(b'[-p] [-g]'),
7657 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7660 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7658 )
7661 )
7659 def tip(ui, repo, **opts):
7662 def tip(ui, repo, **opts):
7660 """show the tip revision (DEPRECATED)
7663 """show the tip revision (DEPRECATED)
7661
7664
7662 The tip revision (usually just called the tip) is the changeset
7665 The tip revision (usually just called the tip) is the changeset
7663 most recently added to the repository (and therefore the most
7666 most recently added to the repository (and therefore the most
7664 recently changed head).
7667 recently changed head).
7665
7668
7666 If you have just made a commit, that commit will be the tip. If
7669 If you have just made a commit, that commit will be the tip. If
7667 you have just pulled changes from another repository, the tip of
7670 you have just pulled changes from another repository, the tip of
7668 that repository becomes the current tip. The "tip" tag is special
7671 that repository becomes the current tip. The "tip" tag is special
7669 and cannot be renamed or assigned to a different changeset.
7672 and cannot be renamed or assigned to a different changeset.
7670
7673
7671 This command is deprecated, please use :hg:`heads` instead.
7674 This command is deprecated, please use :hg:`heads` instead.
7672
7675
7673 Returns 0 on success.
7676 Returns 0 on success.
7674 """
7677 """
7675 opts = pycompat.byteskwargs(opts)
7678 opts = pycompat.byteskwargs(opts)
7676 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7677 displayer.show(repo[b'tip'])
7680 displayer.show(repo[b'tip'])
7678 displayer.close()
7681 displayer.close()
7679
7682
7680
7683
7681 @command(
7684 @command(
7682 b'unbundle',
7685 b'unbundle',
7683 [
7686 [
7684 (
7687 (
7685 b'u',
7688 b'u',
7686 b'update',
7689 b'update',
7687 None,
7690 None,
7688 _(b'update to new branch head if changesets were unbundled'),
7691 _(b'update to new branch head if changesets were unbundled'),
7689 )
7692 )
7690 ],
7693 ],
7691 _(b'[-u] FILE...'),
7694 _(b'[-u] FILE...'),
7692 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7695 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7693 )
7696 )
7694 def unbundle(ui, repo, fname1, *fnames, **opts):
7697 def unbundle(ui, repo, fname1, *fnames, **opts):
7695 """apply one or more bundle files
7698 """apply one or more bundle files
7696
7699
7697 Apply one or more bundle files generated by :hg:`bundle`.
7700 Apply one or more bundle files generated by :hg:`bundle`.
7698
7701
7699 Returns 0 on success, 1 if an update has unresolved files.
7702 Returns 0 on success, 1 if an update has unresolved files.
7700 """
7703 """
7701 fnames = (fname1,) + fnames
7704 fnames = (fname1,) + fnames
7702 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7705 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7703
7706
7704 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7707 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7705 return 1
7708 return 1
7706 else:
7709 else:
7707 return 0
7710 return 0
7708
7711
7709
7712
7710 @command(
7713 @command(
7711 b'unshelve',
7714 b'unshelve',
7712 [
7715 [
7713 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7716 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7714 (
7717 (
7715 b'c',
7718 b'c',
7716 b'continue',
7719 b'continue',
7717 None,
7720 None,
7718 _(b'continue an incomplete unshelve operation'),
7721 _(b'continue an incomplete unshelve operation'),
7719 ),
7722 ),
7720 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7723 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7721 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7724 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7722 (
7725 (
7723 b'n',
7726 b'n',
7724 b'name',
7727 b'name',
7725 b'',
7728 b'',
7726 _(b'restore shelved change with given name'),
7729 _(b'restore shelved change with given name'),
7727 _(b'NAME'),
7730 _(b'NAME'),
7728 ),
7731 ),
7729 (b't', b'tool', b'', _(b'specify merge tool')),
7732 (b't', b'tool', b'', _(b'specify merge tool')),
7730 (
7733 (
7731 b'',
7734 b'',
7732 b'date',
7735 b'date',
7733 b'',
7736 b'',
7734 _(b'set date for temporary commits (DEPRECATED)'),
7737 _(b'set date for temporary commits (DEPRECATED)'),
7735 _(b'DATE'),
7738 _(b'DATE'),
7736 ),
7739 ),
7737 ],
7740 ],
7738 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7741 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7739 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7742 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7740 )
7743 )
7741 def unshelve(ui, repo, *shelved, **opts):
7744 def unshelve(ui, repo, *shelved, **opts):
7742 """restore a shelved change to the working directory
7745 """restore a shelved change to the working directory
7743
7746
7744 This command accepts an optional name of a shelved change to
7747 This command accepts an optional name of a shelved change to
7745 restore. If none is given, the most recent shelved change is used.
7748 restore. If none is given, the most recent shelved change is used.
7746
7749
7747 If a shelved change is applied successfully, the bundle that
7750 If a shelved change is applied successfully, the bundle that
7748 contains the shelved changes is moved to a backup location
7751 contains the shelved changes is moved to a backup location
7749 (.hg/shelve-backup).
7752 (.hg/shelve-backup).
7750
7753
7751 Since you can restore a shelved change on top of an arbitrary
7754 Since you can restore a shelved change on top of an arbitrary
7752 commit, it is possible that unshelving will result in a conflict
7755 commit, it is possible that unshelving will result in a conflict
7753 between your changes and the commits you are unshelving onto. If
7756 between your changes and the commits you are unshelving onto. If
7754 this occurs, you must resolve the conflict, then use
7757 this occurs, you must resolve the conflict, then use
7755 ``--continue`` to complete the unshelve operation. (The bundle
7758 ``--continue`` to complete the unshelve operation. (The bundle
7756 will not be moved until you successfully complete the unshelve.)
7759 will not be moved until you successfully complete the unshelve.)
7757
7760
7758 (Alternatively, you can use ``--abort`` to abandon an unshelve
7761 (Alternatively, you can use ``--abort`` to abandon an unshelve
7759 that causes a conflict. This reverts the unshelved changes, and
7762 that causes a conflict. This reverts the unshelved changes, and
7760 leaves the bundle in place.)
7763 leaves the bundle in place.)
7761
7764
7762 If bare shelved change (without interactive, include and exclude
7765 If bare shelved change (without interactive, include and exclude
7763 option) was done on newly created branch it would restore branch
7766 option) was done on newly created branch it would restore branch
7764 information to the working directory.
7767 information to the working directory.
7765
7768
7766 After a successful unshelve, the shelved changes are stored in a
7769 After a successful unshelve, the shelved changes are stored in a
7767 backup directory. Only the N most recent backups are kept. N
7770 backup directory. Only the N most recent backups are kept. N
7768 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7771 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7769 configuration option.
7772 configuration option.
7770
7773
7771 .. container:: verbose
7774 .. container:: verbose
7772
7775
7773 Timestamp in seconds is used to decide order of backups. More
7776 Timestamp in seconds is used to decide order of backups. More
7774 than ``maxbackups`` backups are kept, if same timestamp
7777 than ``maxbackups`` backups are kept, if same timestamp
7775 prevents from deciding exact order of them, for safety.
7778 prevents from deciding exact order of them, for safety.
7776
7779
7777 Selected changes can be unshelved with ``--interactive`` flag.
7780 Selected changes can be unshelved with ``--interactive`` flag.
7778 The working directory is updated with the selected changes, and
7781 The working directory is updated with the selected changes, and
7779 only the unselected changes remain shelved.
7782 only the unselected changes remain shelved.
7780 Note: The whole shelve is applied to working directory first before
7783 Note: The whole shelve is applied to working directory first before
7781 running interactively. So, this will bring up all the conflicts between
7784 running interactively. So, this will bring up all the conflicts between
7782 working directory and the shelve, irrespective of which changes will be
7785 working directory and the shelve, irrespective of which changes will be
7783 unshelved.
7786 unshelved.
7784 """
7787 """
7785 with repo.wlock():
7788 with repo.wlock():
7786 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7789 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7787
7790
7788
7791
7789 statemod.addunfinished(
7792 statemod.addunfinished(
7790 b'unshelve',
7793 b'unshelve',
7791 fname=b'shelvedstate',
7794 fname=b'shelvedstate',
7792 continueflag=True,
7795 continueflag=True,
7793 abortfunc=shelvemod.hgabortunshelve,
7796 abortfunc=shelvemod.hgabortunshelve,
7794 continuefunc=shelvemod.hgcontinueunshelve,
7797 continuefunc=shelvemod.hgcontinueunshelve,
7795 cmdmsg=_(b'unshelve already in progress'),
7798 cmdmsg=_(b'unshelve already in progress'),
7796 )
7799 )
7797
7800
7798
7801
7799 @command(
7802 @command(
7800 b'update|up|checkout|co',
7803 b'update|up|checkout|co',
7801 [
7804 [
7802 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7805 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7803 (b'c', b'check', None, _(b'require clean working directory')),
7806 (b'c', b'check', None, _(b'require clean working directory')),
7804 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7807 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7805 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7808 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7806 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7809 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7807 ]
7810 ]
7808 + mergetoolopts,
7811 + mergetoolopts,
7809 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7812 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7810 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7811 helpbasic=True,
7814 helpbasic=True,
7812 )
7815 )
7813 def update(ui, repo, node=None, **opts):
7816 def update(ui, repo, node=None, **opts):
7814 """update working directory (or switch revisions)
7817 """update working directory (or switch revisions)
7815
7818
7816 Update the repository's working directory to the specified
7819 Update the repository's working directory to the specified
7817 changeset. If no changeset is specified, update to the tip of the
7820 changeset. If no changeset is specified, update to the tip of the
7818 current named branch and move the active bookmark (see :hg:`help
7821 current named branch and move the active bookmark (see :hg:`help
7819 bookmarks`).
7822 bookmarks`).
7820
7823
7821 Update sets the working directory's parent revision to the specified
7824 Update sets the working directory's parent revision to the specified
7822 changeset (see :hg:`help parents`).
7825 changeset (see :hg:`help parents`).
7823
7826
7824 If the changeset is not a descendant or ancestor of the working
7827 If the changeset is not a descendant or ancestor of the working
7825 directory's parent and there are uncommitted changes, the update is
7828 directory's parent and there are uncommitted changes, the update is
7826 aborted. With the -c/--check option, the working directory is checked
7829 aborted. With the -c/--check option, the working directory is checked
7827 for uncommitted changes; if none are found, the working directory is
7830 for uncommitted changes; if none are found, the working directory is
7828 updated to the specified changeset.
7831 updated to the specified changeset.
7829
7832
7830 .. container:: verbose
7833 .. container:: verbose
7831
7834
7832 The -C/--clean, -c/--check, and -m/--merge options control what
7835 The -C/--clean, -c/--check, and -m/--merge options control what
7833 happens if the working directory contains uncommitted changes.
7836 happens if the working directory contains uncommitted changes.
7834 At most of one of them can be specified.
7837 At most of one of them can be specified.
7835
7838
7836 1. If no option is specified, and if
7839 1. If no option is specified, and if
7837 the requested changeset is an ancestor or descendant of
7840 the requested changeset is an ancestor or descendant of
7838 the working directory's parent, the uncommitted changes
7841 the working directory's parent, the uncommitted changes
7839 are merged into the requested changeset and the merged
7842 are merged into the requested changeset and the merged
7840 result is left uncommitted. If the requested changeset is
7843 result is left uncommitted. If the requested changeset is
7841 not an ancestor or descendant (that is, it is on another
7844 not an ancestor or descendant (that is, it is on another
7842 branch), the update is aborted and the uncommitted changes
7845 branch), the update is aborted and the uncommitted changes
7843 are preserved.
7846 are preserved.
7844
7847
7845 2. With the -m/--merge option, the update is allowed even if the
7848 2. With the -m/--merge option, the update is allowed even if the
7846 requested changeset is not an ancestor or descendant of
7849 requested changeset is not an ancestor or descendant of
7847 the working directory's parent.
7850 the working directory's parent.
7848
7851
7849 3. With the -c/--check option, the update is aborted and the
7852 3. With the -c/--check option, the update is aborted and the
7850 uncommitted changes are preserved.
7853 uncommitted changes are preserved.
7851
7854
7852 4. With the -C/--clean option, uncommitted changes are discarded and
7855 4. With the -C/--clean option, uncommitted changes are discarded and
7853 the working directory is updated to the requested changeset.
7856 the working directory is updated to the requested changeset.
7854
7857
7855 To cancel an uncommitted merge (and lose your changes), use
7858 To cancel an uncommitted merge (and lose your changes), use
7856 :hg:`merge --abort`.
7859 :hg:`merge --abort`.
7857
7860
7858 Use null as the changeset to remove the working directory (like
7861 Use null as the changeset to remove the working directory (like
7859 :hg:`clone -U`).
7862 :hg:`clone -U`).
7860
7863
7861 If you want to revert just one file to an older revision, use
7864 If you want to revert just one file to an older revision, use
7862 :hg:`revert [-r REV] NAME`.
7865 :hg:`revert [-r REV] NAME`.
7863
7866
7864 See :hg:`help dates` for a list of formats valid for -d/--date.
7867 See :hg:`help dates` for a list of formats valid for -d/--date.
7865
7868
7866 Returns 0 on success, 1 if there are unresolved files.
7869 Returns 0 on success, 1 if there are unresolved files.
7867 """
7870 """
7868 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7871 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7869 rev = opts.get('rev')
7872 rev = opts.get('rev')
7870 date = opts.get('date')
7873 date = opts.get('date')
7871 clean = opts.get('clean')
7874 clean = opts.get('clean')
7872 check = opts.get('check')
7875 check = opts.get('check')
7873 merge = opts.get('merge')
7876 merge = opts.get('merge')
7874 if rev and node:
7877 if rev and node:
7875 raise error.InputError(_(b"please specify just one revision"))
7878 raise error.InputError(_(b"please specify just one revision"))
7876
7879
7877 if ui.configbool(b'commands', b'update.requiredest'):
7880 if ui.configbool(b'commands', b'update.requiredest'):
7878 if not node and not rev and not date:
7881 if not node and not rev and not date:
7879 raise error.InputError(
7882 raise error.InputError(
7880 _(b'you must specify a destination'),
7883 _(b'you must specify a destination'),
7881 hint=_(b'for example: hg update ".::"'),
7884 hint=_(b'for example: hg update ".::"'),
7882 )
7885 )
7883
7886
7884 if rev is None or rev == b'':
7887 if rev is None or rev == b'':
7885 rev = node
7888 rev = node
7886
7889
7887 if date and rev is not None:
7890 if date and rev is not None:
7888 raise error.InputError(_(b"you can't specify a revision and a date"))
7891 raise error.InputError(_(b"you can't specify a revision and a date"))
7889
7892
7890 updatecheck = None
7893 updatecheck = None
7891 if check or merge is not None and not merge:
7894 if check or merge is not None and not merge:
7892 updatecheck = b'abort'
7895 updatecheck = b'abort'
7893 elif merge or check is not None and not check:
7896 elif merge or check is not None and not check:
7894 updatecheck = b'none'
7897 updatecheck = b'none'
7895
7898
7896 with repo.wlock():
7899 with repo.wlock():
7897 cmdutil.clearunfinished(repo)
7900 cmdutil.clearunfinished(repo)
7898 if date:
7901 if date:
7899 rev = cmdutil.finddate(ui, repo, date)
7902 rev = cmdutil.finddate(ui, repo, date)
7900
7903
7901 # if we defined a bookmark, we have to remember the original name
7904 # if we defined a bookmark, we have to remember the original name
7902 brev = rev
7905 brev = rev
7903 if rev:
7906 if rev:
7904 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7907 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7905 ctx = logcmdutil.revsingle(repo, rev, default=None)
7908 ctx = logcmdutil.revsingle(repo, rev, default=None)
7906 rev = ctx.rev()
7909 rev = ctx.rev()
7907 hidden = ctx.hidden()
7910 hidden = ctx.hidden()
7908 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7911 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7909 with ui.configoverride(overrides, b'update'):
7912 with ui.configoverride(overrides, b'update'):
7910 ret = hg.updatetotally(
7913 ret = hg.updatetotally(
7911 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7914 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7912 )
7915 )
7913 if hidden:
7916 if hidden:
7914 ctxstr = ctx.hex()[:12]
7917 ctxstr = ctx.hex()[:12]
7915 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7918 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7916
7919
7917 if ctx.obsolete():
7920 if ctx.obsolete():
7918 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7921 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7919 ui.warn(b"(%s)\n" % obsfatemsg)
7922 ui.warn(b"(%s)\n" % obsfatemsg)
7920 return ret
7923 return ret
7921
7924
7922
7925
7923 @command(
7926 @command(
7924 b'verify',
7927 b'verify',
7925 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7928 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7926 helpcategory=command.CATEGORY_MAINTENANCE,
7929 helpcategory=command.CATEGORY_MAINTENANCE,
7927 )
7930 )
7928 def verify(ui, repo, **opts):
7931 def verify(ui, repo, **opts):
7929 """verify the integrity of the repository
7932 """verify the integrity of the repository
7930
7933
7931 Verify the integrity of the current repository.
7934 Verify the integrity of the current repository.
7932
7935
7933 This will perform an extensive check of the repository's
7936 This will perform an extensive check of the repository's
7934 integrity, validating the hashes and checksums of each entry in
7937 integrity, validating the hashes and checksums of each entry in
7935 the changelog, manifest, and tracked files, as well as the
7938 the changelog, manifest, and tracked files, as well as the
7936 integrity of their crosslinks and indices.
7939 integrity of their crosslinks and indices.
7937
7940
7938 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7941 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7939 for more information about recovery from corruption of the
7942 for more information about recovery from corruption of the
7940 repository.
7943 repository.
7941
7944
7942 For an alternative UI with a lot more control over the verification
7945 For an alternative UI with a lot more control over the verification
7943 process and better error reporting, try `hg help admin::verify`.
7946 process and better error reporting, try `hg help admin::verify`.
7944
7947
7945 Returns 0 on success, 1 if errors are encountered.
7948 Returns 0 on success, 1 if errors are encountered.
7946 """
7949 """
7947 level = None
7950 level = None
7948 if opts['full']:
7951 if opts['full']:
7949 level = verifymod.VERIFY_FULL
7952 level = verifymod.VERIFY_FULL
7950 return hg.verify(repo, level)
7953 return hg.verify(repo, level)
7951
7954
7952
7955
7953 @command(
7956 @command(
7954 b'version',
7957 b'version',
7955 [] + formatteropts,
7958 [] + formatteropts,
7956 helpcategory=command.CATEGORY_HELP,
7959 helpcategory=command.CATEGORY_HELP,
7957 norepo=True,
7960 norepo=True,
7958 intents={INTENT_READONLY},
7961 intents={INTENT_READONLY},
7959 )
7962 )
7960 def version_(ui, **opts):
7963 def version_(ui, **opts):
7961 """output version and copyright information
7964 """output version and copyright information
7962
7965
7963 .. container:: verbose
7966 .. container:: verbose
7964
7967
7965 Template:
7968 Template:
7966
7969
7967 The following keywords are supported. See also :hg:`help templates`.
7970 The following keywords are supported. See also :hg:`help templates`.
7968
7971
7969 :extensions: List of extensions.
7972 :extensions: List of extensions.
7970 :ver: String. Version number.
7973 :ver: String. Version number.
7971
7974
7972 And each entry of ``{extensions}`` provides the following sub-keywords
7975 And each entry of ``{extensions}`` provides the following sub-keywords
7973 in addition to ``{ver}``.
7976 in addition to ``{ver}``.
7974
7977
7975 :bundled: Boolean. True if included in the release.
7978 :bundled: Boolean. True if included in the release.
7976 :name: String. Extension name.
7979 :name: String. Extension name.
7977 """
7980 """
7978 if ui.verbose:
7981 if ui.verbose:
7979 ui.pager(b'version')
7982 ui.pager(b'version')
7980 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7983 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7981 fm.startitem()
7984 fm.startitem()
7982 fm.write(
7985 fm.write(
7983 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7986 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7984 )
7987 )
7985 license = _(
7988 license = _(
7986 b"(see https://mercurial-scm.org for more information)\n"
7989 b"(see https://mercurial-scm.org for more information)\n"
7987 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
7990 b"\nCopyright (C) 2005-2023 Olivia Mackall and others\n"
7988 b"This is free software; see the source for copying conditions. "
7991 b"This is free software; see the source for copying conditions. "
7989 b"There is NO\nwarranty; "
7992 b"There is NO\nwarranty; "
7990 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7993 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7991 )
7994 )
7992 if not ui.quiet:
7995 if not ui.quiet:
7993 fm.plain(license)
7996 fm.plain(license)
7994
7997
7995 if ui.verbose:
7998 if ui.verbose:
7996 fm.plain(_(b"\nEnabled extensions:\n\n"))
7999 fm.plain(_(b"\nEnabled extensions:\n\n"))
7997 # format names and versions into columns
8000 # format names and versions into columns
7998 names = []
8001 names = []
7999 vers = []
8002 vers = []
8000 isinternals = []
8003 isinternals = []
8001 for name, module in sorted(extensions.extensions()):
8004 for name, module in sorted(extensions.extensions()):
8002 names.append(name)
8005 names.append(name)
8003 vers.append(extensions.moduleversion(module) or None)
8006 vers.append(extensions.moduleversion(module) or None)
8004 isinternals.append(extensions.ismoduleinternal(module))
8007 isinternals.append(extensions.ismoduleinternal(module))
8005 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8008 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
8006 if names:
8009 if names:
8007 namefmt = b" %%-%ds " % max(len(n) for n in names)
8010 namefmt = b" %%-%ds " % max(len(n) for n in names)
8008 places = [_(b"external"), _(b"internal")]
8011 places = [_(b"external"), _(b"internal")]
8009 for n, v, p in zip(names, vers, isinternals):
8012 for n, v, p in zip(names, vers, isinternals):
8010 fn.startitem()
8013 fn.startitem()
8011 fn.condwrite(ui.verbose, b"name", namefmt, n)
8014 fn.condwrite(ui.verbose, b"name", namefmt, n)
8012 if ui.verbose:
8015 if ui.verbose:
8013 fn.plain(b"%s " % places[p])
8016 fn.plain(b"%s " % places[p])
8014 fn.data(bundled=p)
8017 fn.data(bundled=p)
8015 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8018 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
8016 if ui.verbose:
8019 if ui.verbose:
8017 fn.plain(b"\n")
8020 fn.plain(b"\n")
8018 fn.end()
8021 fn.end()
8019 fm.end()
8022 fm.end()
8020
8023
8021
8024
8022 def loadcmdtable(ui, name, cmdtable):
8025 def loadcmdtable(ui, name, cmdtable):
8023 """Load command functions from specified cmdtable"""
8026 """Load command functions from specified cmdtable"""
8024 overrides = [cmd for cmd in cmdtable if cmd in table]
8027 overrides = [cmd for cmd in cmdtable if cmd in table]
8025 if overrides:
8028 if overrides:
8026 ui.warn(
8029 ui.warn(
8027 _(b"extension '%s' overrides commands: %s\n")
8030 _(b"extension '%s' overrides commands: %s\n")
8028 % (name, b" ".join(overrides))
8031 % (name, b" ".join(overrides))
8029 )
8032 )
8030 table.update(cmdtable)
8033 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now