##// END OF EJS Templates
bisect: avoid adding irrelevant revisions to bisect state...
Arun Kulshreshtha -
r50337:81623652 default
parent child Browse files
Show More
@@ -1,7974 +1,7981
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 nullrev,
16 nullrev,
17 short,
17 short,
18 wdirrev,
18 wdirrev,
19 )
19 )
20 from .pycompat import open
20 from .pycompat import open
21 from . import (
21 from . import (
22 archival,
22 archival,
23 bookmarks,
23 bookmarks,
24 bundle2,
24 bundle2,
25 bundlecaches,
25 bundlecaches,
26 changegroup,
26 changegroup,
27 cmdutil,
27 cmdutil,
28 copies,
28 copies,
29 debugcommands as debugcommandsmod,
29 debugcommands as debugcommandsmod,
30 destutil,
30 destutil,
31 dirstateguard,
31 dirstateguard,
32 discovery,
32 discovery,
33 encoding,
33 encoding,
34 error,
34 error,
35 exchange,
35 exchange,
36 extensions,
36 extensions,
37 filemerge,
37 filemerge,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 grep as grepmod,
40 grep as grepmod,
41 hbisect,
41 hbisect,
42 help,
42 help,
43 hg,
43 hg,
44 logcmdutil,
44 logcmdutil,
45 merge as mergemod,
45 merge as mergemod,
46 mergestate as mergestatemod,
46 mergestate as mergestatemod,
47 narrowspec,
47 narrowspec,
48 obsolete,
48 obsolete,
49 obsutil,
49 obsutil,
50 patch,
50 patch,
51 phases,
51 phases,
52 pycompat,
52 pycompat,
53 rcutil,
53 rcutil,
54 registrar,
54 registrar,
55 requirements,
55 requirements,
56 revsetlang,
56 revsetlang,
57 rewriteutil,
57 rewriteutil,
58 scmutil,
58 scmutil,
59 server,
59 server,
60 shelve as shelvemod,
60 shelve as shelvemod,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
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 stringutil,
72 stringutil,
73 urlutil,
73 urlutil,
74 )
74 )
75
75
76 table = {}
76 table = {}
77 table.update(debugcommandsmod.command._table)
77 table.update(debugcommandsmod.command._table)
78
78
79 command = registrar.command(table)
79 command = registrar.command(table)
80 INTENT_READONLY = registrar.INTENT_READONLY
80 INTENT_READONLY = registrar.INTENT_READONLY
81
81
82 # common command options
82 # common command options
83
83
84 globalopts = [
84 globalopts = [
85 (
85 (
86 b'R',
86 b'R',
87 b'repository',
87 b'repository',
88 b'',
88 b'',
89 _(b'repository root directory or name of overlay bundle file'),
89 _(b'repository root directory or name of overlay bundle file'),
90 _(b'REPO'),
90 _(b'REPO'),
91 ),
91 ),
92 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
93 (
93 (
94 b'y',
94 b'y',
95 b'noninteractive',
95 b'noninteractive',
96 None,
96 None,
97 _(
97 _(
98 b'do not prompt, automatically pick the first choice for all prompts'
98 b'do not prompt, automatically pick the first choice for all prompts'
99 ),
99 ),
100 ),
100 ),
101 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'q', b'quiet', None, _(b'suppress output')),
102 (b'v', b'verbose', None, _(b'enable additional output')),
102 (b'v', b'verbose', None, _(b'enable additional output')),
103 (
103 (
104 b'',
104 b'',
105 b'color',
105 b'color',
106 b'',
106 b'',
107 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
108 # and should not be translated
108 # and should not be translated
109 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b"when to colorize (boolean, always, auto, never, or debug)"),
110 _(b'TYPE'),
110 _(b'TYPE'),
111 ),
111 ),
112 (
112 (
113 b'',
113 b'',
114 b'config',
114 b'config',
115 [],
115 [],
116 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'set/override config option (use \'section.name=value\')'),
117 _(b'CONFIG'),
117 _(b'CONFIG'),
118 ),
118 ),
119 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debug', None, _(b'enable debugging output')),
120 (b'', b'debugger', None, _(b'start debugger')),
120 (b'', b'debugger', None, _(b'start debugger')),
121 (
121 (
122 b'',
122 b'',
123 b'encoding',
123 b'encoding',
124 encoding.encoding,
124 encoding.encoding,
125 _(b'set the charset encoding'),
125 _(b'set the charset encoding'),
126 _(b'ENCODE'),
126 _(b'ENCODE'),
127 ),
127 ),
128 (
128 (
129 b'',
129 b'',
130 b'encodingmode',
130 b'encodingmode',
131 encoding.encodingmode,
131 encoding.encodingmode,
132 _(b'set the charset encoding mode'),
132 _(b'set the charset encoding mode'),
133 _(b'MODE'),
133 _(b'MODE'),
134 ),
134 ),
135 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'traceback', None, _(b'always print a traceback on exception')),
136 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'time', None, _(b'time how long the command takes')),
137 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'profile', None, _(b'print command execution profile')),
138 (b'', b'version', None, _(b'output version information and exit')),
138 (b'', b'version', None, _(b'output version information and exit')),
139 (b'h', b'help', None, _(b'display help and exit')),
139 (b'h', b'help', None, _(b'display help and exit')),
140 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (b'', b'hidden', False, _(b'consider hidden changesets')),
141 (
141 (
142 b'',
142 b'',
143 b'pager',
143 b'pager',
144 b'auto',
144 b'auto',
145 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b"when to paginate (boolean, always, auto, or never)"),
146 _(b'TYPE'),
146 _(b'TYPE'),
147 ),
147 ),
148 ]
148 ]
149
149
150 dryrunopts = cmdutil.dryrunopts
150 dryrunopts = cmdutil.dryrunopts
151 remoteopts = cmdutil.remoteopts
151 remoteopts = cmdutil.remoteopts
152 walkopts = cmdutil.walkopts
152 walkopts = cmdutil.walkopts
153 commitopts = cmdutil.commitopts
153 commitopts = cmdutil.commitopts
154 commitopts2 = cmdutil.commitopts2
154 commitopts2 = cmdutil.commitopts2
155 commitopts3 = cmdutil.commitopts3
155 commitopts3 = cmdutil.commitopts3
156 formatteropts = cmdutil.formatteropts
156 formatteropts = cmdutil.formatteropts
157 templateopts = cmdutil.templateopts
157 templateopts = cmdutil.templateopts
158 logopts = cmdutil.logopts
158 logopts = cmdutil.logopts
159 diffopts = cmdutil.diffopts
159 diffopts = cmdutil.diffopts
160 diffwsopts = cmdutil.diffwsopts
160 diffwsopts = cmdutil.diffwsopts
161 diffopts2 = cmdutil.diffopts2
161 diffopts2 = cmdutil.diffopts2
162 mergetoolopts = cmdutil.mergetoolopts
162 mergetoolopts = cmdutil.mergetoolopts
163 similarityopts = cmdutil.similarityopts
163 similarityopts = cmdutil.similarityopts
164 subrepoopts = cmdutil.subrepoopts
164 subrepoopts = cmdutil.subrepoopts
165 debugrevlogopts = cmdutil.debugrevlogopts
165 debugrevlogopts = cmdutil.debugrevlogopts
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169
169
170 @command(
170 @command(
171 b'abort',
171 b'abort',
172 dryrunopts,
172 dryrunopts,
173 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
174 helpbasic=True,
174 helpbasic=True,
175 )
175 )
176 def abort(ui, repo, **opts):
176 def abort(ui, repo, **opts):
177 """abort an unfinished operation (EXPERIMENTAL)
177 """abort an unfinished operation (EXPERIMENTAL)
178
178
179 Aborts a multistep operation like graft, histedit, rebase, merge,
179 Aborts a multistep operation like graft, histedit, rebase, merge,
180 and unshelve if they are in an unfinished state.
180 and unshelve if they are in an unfinished state.
181
181
182 use --dry-run/-n to dry run the command.
182 use --dry-run/-n to dry run the command.
183 """
183 """
184 dryrun = opts.get('dry_run')
184 dryrun = opts.get('dry_run')
185 abortstate = cmdutil.getunfinishedstate(repo)
185 abortstate = cmdutil.getunfinishedstate(repo)
186 if not abortstate:
186 if not abortstate:
187 raise error.StateError(_(b'no operation in progress'))
187 raise error.StateError(_(b'no operation in progress'))
188 if not abortstate.abortfunc:
188 if not abortstate.abortfunc:
189 raise error.InputError(
189 raise error.InputError(
190 (
190 (
191 _(b"%s in progress but does not support 'hg abort'")
191 _(b"%s in progress but does not support 'hg abort'")
192 % (abortstate._opname)
192 % (abortstate._opname)
193 ),
193 ),
194 hint=abortstate.hint(),
194 hint=abortstate.hint(),
195 )
195 )
196 if dryrun:
196 if dryrun:
197 ui.status(
197 ui.status(
198 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
199 )
199 )
200 return
200 return
201 return abortstate.abortfunc(ui, repo)
201 return abortstate.abortfunc(ui, repo)
202
202
203
203
204 @command(
204 @command(
205 b'add',
205 b'add',
206 walkopts + subrepoopts + dryrunopts,
206 walkopts + subrepoopts + dryrunopts,
207 _(b'[OPTION]... [FILE]...'),
207 _(b'[OPTION]... [FILE]...'),
208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
209 helpbasic=True,
209 helpbasic=True,
210 inferrepo=True,
210 inferrepo=True,
211 )
211 )
212 def add(ui, repo, *pats, **opts):
212 def add(ui, repo, *pats, **opts):
213 """add the specified files on the next commit
213 """add the specified files on the next commit
214
214
215 Schedule files to be version controlled and added to the
215 Schedule files to be version controlled and added to the
216 repository.
216 repository.
217
217
218 The files will be added to the repository at the next commit. To
218 The files will be added to the repository at the next commit. To
219 undo an add before that, see :hg:`forget`.
219 undo an add before that, see :hg:`forget`.
220
220
221 If no names are given, add all files to the repository (except
221 If no names are given, add all files to the repository (except
222 files matching ``.hgignore``).
222 files matching ``.hgignore``).
223
223
224 .. container:: verbose
224 .. container:: verbose
225
225
226 Examples:
226 Examples:
227
227
228 - New (unknown) files are added
228 - New (unknown) files are added
229 automatically by :hg:`add`::
229 automatically by :hg:`add`::
230
230
231 $ ls
231 $ ls
232 foo.c
232 foo.c
233 $ hg status
233 $ hg status
234 ? foo.c
234 ? foo.c
235 $ hg add
235 $ hg add
236 adding foo.c
236 adding foo.c
237 $ hg status
237 $ hg status
238 A foo.c
238 A foo.c
239
239
240 - Specific files to be added can be specified::
240 - Specific files to be added can be specified::
241
241
242 $ ls
242 $ ls
243 bar.c foo.c
243 bar.c foo.c
244 $ hg status
244 $ hg status
245 ? bar.c
245 ? bar.c
246 ? foo.c
246 ? foo.c
247 $ hg add bar.c
247 $ hg add bar.c
248 $ hg status
248 $ hg status
249 A bar.c
249 A bar.c
250 ? foo.c
250 ? foo.c
251
251
252 Returns 0 if all files are successfully added.
252 Returns 0 if all files are successfully added.
253 """
253 """
254
254
255 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
256 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
257 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
258 return rejected and 1 or 0
258 return rejected and 1 or 0
259
259
260
260
261 @command(
261 @command(
262 b'addremove',
262 b'addremove',
263 similarityopts + subrepoopts + walkopts + dryrunopts,
263 similarityopts + subrepoopts + walkopts + dryrunopts,
264 _(b'[OPTION]... [FILE]...'),
264 _(b'[OPTION]... [FILE]...'),
265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
266 inferrepo=True,
266 inferrepo=True,
267 )
267 )
268 def addremove(ui, repo, *pats, **opts):
268 def addremove(ui, repo, *pats, **opts):
269 """add all new files, delete all missing files
269 """add all new files, delete all missing files
270
270
271 Add all new files and remove all missing files from the
271 Add all new files and remove all missing files from the
272 repository.
272 repository.
273
273
274 Unless names are given, new files are ignored if they match any of
274 Unless names are given, new files are ignored if they match any of
275 the patterns in ``.hgignore``. As with add, these changes take
275 the patterns in ``.hgignore``. As with add, these changes take
276 effect at the next commit.
276 effect at the next commit.
277
277
278 Use the -s/--similarity option to detect renamed files. This
278 Use the -s/--similarity option to detect renamed files. This
279 option takes a percentage between 0 (disabled) and 100 (files must
279 option takes a percentage between 0 (disabled) and 100 (files must
280 be identical) as its parameter. With a parameter greater than 0,
280 be identical) as its parameter. With a parameter greater than 0,
281 this compares every removed file with every added file and records
281 this compares every removed file with every added file and records
282 those similar enough as renames. Detecting renamed files this way
282 those similar enough as renames. Detecting renamed files this way
283 can be expensive. After using this option, :hg:`status -C` can be
283 can be expensive. After using this option, :hg:`status -C` can be
284 used to check which files were identified as moved or renamed. If
284 used to check which files were identified as moved or renamed. If
285 not specified, -s/--similarity defaults to 100 and only renames of
285 not specified, -s/--similarity defaults to 100 and only renames of
286 identical files are detected.
286 identical files are detected.
287
287
288 .. container:: verbose
288 .. container:: verbose
289
289
290 Examples:
290 Examples:
291
291
292 - A number of files (bar.c and foo.c) are new,
292 - A number of files (bar.c and foo.c) are new,
293 while foobar.c has been removed (without using :hg:`remove`)
293 while foobar.c has been removed (without using :hg:`remove`)
294 from the repository::
294 from the repository::
295
295
296 $ ls
296 $ ls
297 bar.c foo.c
297 bar.c foo.c
298 $ hg status
298 $ hg status
299 ! foobar.c
299 ! foobar.c
300 ? bar.c
300 ? bar.c
301 ? foo.c
301 ? foo.c
302 $ hg addremove
302 $ hg addremove
303 adding bar.c
303 adding bar.c
304 adding foo.c
304 adding foo.c
305 removing foobar.c
305 removing foobar.c
306 $ hg status
306 $ hg status
307 A bar.c
307 A bar.c
308 A foo.c
308 A foo.c
309 R foobar.c
309 R foobar.c
310
310
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 Afterwards, it was edited slightly::
312 Afterwards, it was edited slightly::
313
313
314 $ ls
314 $ ls
315 foo.c
315 foo.c
316 $ hg status
316 $ hg status
317 ! foobar.c
317 ! foobar.c
318 ? foo.c
318 ? foo.c
319 $ hg addremove --similarity 90
319 $ hg addremove --similarity 90
320 removing foobar.c
320 removing foobar.c
321 adding foo.c
321 adding foo.c
322 recording removal of foobar.c as rename to foo.c (94% similar)
322 recording removal of foobar.c as rename to foo.c (94% similar)
323 $ hg status -C
323 $ hg status -C
324 A foo.c
324 A foo.c
325 foobar.c
325 foobar.c
326 R foobar.c
326 R foobar.c
327
327
328 Returns 0 if all files are successfully added.
328 Returns 0 if all files are successfully added.
329 """
329 """
330 opts = pycompat.byteskwargs(opts)
330 opts = pycompat.byteskwargs(opts)
331 if not opts.get(b'similarity'):
331 if not opts.get(b'similarity'):
332 opts[b'similarity'] = b'100'
332 opts[b'similarity'] = b'100'
333 matcher = scmutil.match(repo[None], pats, opts)
333 matcher = scmutil.match(repo[None], pats, opts)
334 relative = scmutil.anypats(pats, opts)
334 relative = scmutil.anypats(pats, opts)
335 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
336 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
337
337
338
338
339 @command(
339 @command(
340 b'annotate|blame',
340 b'annotate|blame',
341 [
341 [
342 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
343 (
343 (
344 b'',
344 b'',
345 b'follow',
345 b'follow',
346 None,
346 None,
347 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 _(b'follow copies/renames and list the filename (DEPRECATED)'),
348 ),
348 ),
349 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
350 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'a', b'text', None, _(b'treat all files as text')),
351 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'u', b'user', None, _(b'list the author (long with -v)')),
352 (b'f', b'file', None, _(b'list the filename')),
352 (b'f', b'file', None, _(b'list the filename')),
353 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'd', b'date', None, _(b'list the date (short with -q)')),
354 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'n', b'number', None, _(b'list the revision number (default)')),
355 (b'c', b'changeset', None, _(b'list the changeset')),
355 (b'c', b'changeset', None, _(b'list the changeset')),
356 (
356 (
357 b'l',
357 b'l',
358 b'line-number',
358 b'line-number',
359 None,
359 None,
360 _(b'show line number at the first appearance'),
360 _(b'show line number at the first appearance'),
361 ),
361 ),
362 (
362 (
363 b'',
363 b'',
364 b'skip',
364 b'skip',
365 [],
365 [],
366 _(b'revset to not display (EXPERIMENTAL)'),
366 _(b'revset to not display (EXPERIMENTAL)'),
367 _(b'REV'),
367 _(b'REV'),
368 ),
368 ),
369 ]
369 ]
370 + diffwsopts
370 + diffwsopts
371 + walkopts
371 + walkopts
372 + formatteropts,
372 + formatteropts,
373 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
374 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpcategory=command.CATEGORY_FILE_CONTENTS,
375 helpbasic=True,
375 helpbasic=True,
376 inferrepo=True,
376 inferrepo=True,
377 )
377 )
378 def annotate(ui, repo, *pats, **opts):
378 def annotate(ui, repo, *pats, **opts):
379 """show changeset information by line for each file
379 """show changeset information by line for each file
380
380
381 List changes in files, showing the revision id responsible for
381 List changes in files, showing the revision id responsible for
382 each line.
382 each line.
383
383
384 This command is useful for discovering when a change was made and
384 This command is useful for discovering when a change was made and
385 by whom.
385 by whom.
386
386
387 If you include --file, --user, or --date, the revision number is
387 If you include --file, --user, or --date, the revision number is
388 suppressed unless you also include --number.
388 suppressed unless you also include --number.
389
389
390 Without the -a/--text option, annotate will avoid processing files
390 Without the -a/--text option, annotate will avoid processing files
391 it detects as binary. With -a, annotate will annotate the file
391 it detects as binary. With -a, annotate will annotate the file
392 anyway, although the results will probably be neither useful
392 anyway, although the results will probably be neither useful
393 nor desirable.
393 nor desirable.
394
394
395 .. container:: verbose
395 .. container:: verbose
396
396
397 Template:
397 Template:
398
398
399 The following keywords are supported in addition to the common template
399 The following keywords are supported in addition to the common template
400 keywords and functions. See also :hg:`help templates`.
400 keywords and functions. See also :hg:`help templates`.
401
401
402 :lines: List of lines with annotation data.
402 :lines: List of lines with annotation data.
403 :path: String. Repository-absolute path of the specified file.
403 :path: String. Repository-absolute path of the specified file.
404
404
405 And each entry of ``{lines}`` provides the following sub-keywords in
405 And each entry of ``{lines}`` provides the following sub-keywords in
406 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
407
407
408 :line: String. Line content.
408 :line: String. Line content.
409 :lineno: Integer. Line number at that revision.
409 :lineno: Integer. Line number at that revision.
410 :path: String. Repository-absolute path of the file at that revision.
410 :path: String. Repository-absolute path of the file at that revision.
411
411
412 See :hg:`help templates.operators` for the list expansion syntax.
412 See :hg:`help templates.operators` for the list expansion syntax.
413
413
414 Returns 0 on success.
414 Returns 0 on success.
415 """
415 """
416 opts = pycompat.byteskwargs(opts)
416 opts = pycompat.byteskwargs(opts)
417 if not pats:
417 if not pats:
418 raise error.InputError(
418 raise error.InputError(
419 _(b'at least one filename or pattern is required')
419 _(b'at least one filename or pattern is required')
420 )
420 )
421
421
422 if opts.get(b'follow'):
422 if opts.get(b'follow'):
423 # --follow is deprecated and now just an alias for -f/--file
423 # --follow is deprecated and now just an alias for -f/--file
424 # to mimic the behavior of Mercurial before version 1.5
424 # to mimic the behavior of Mercurial before version 1.5
425 opts[b'file'] = True
425 opts[b'file'] = True
426
426
427 if (
427 if (
428 not opts.get(b'user')
428 not opts.get(b'user')
429 and not opts.get(b'changeset')
429 and not opts.get(b'changeset')
430 and not opts.get(b'date')
430 and not opts.get(b'date')
431 and not opts.get(b'file')
431 and not opts.get(b'file')
432 ):
432 ):
433 opts[b'number'] = True
433 opts[b'number'] = True
434
434
435 linenumber = opts.get(b'line_number') is not None
435 linenumber = opts.get(b'line_number') is not None
436 if (
436 if (
437 linenumber
437 linenumber
438 and (not opts.get(b'changeset'))
438 and (not opts.get(b'changeset'))
439 and (not opts.get(b'number'))
439 and (not opts.get(b'number'))
440 ):
440 ):
441 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
441 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
442
442
443 rev = opts.get(b'rev')
443 rev = opts.get(b'rev')
444 if rev:
444 if rev:
445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 ctx = logcmdutil.revsingle(repo, rev)
446 ctx = logcmdutil.revsingle(repo, rev)
447
447
448 ui.pager(b'annotate')
448 ui.pager(b'annotate')
449 rootfm = ui.formatter(b'annotate', opts)
449 rootfm = ui.formatter(b'annotate', opts)
450 if ui.debugflag:
450 if ui.debugflag:
451 shorthex = pycompat.identity
451 shorthex = pycompat.identity
452 else:
452 else:
453
453
454 def shorthex(h):
454 def shorthex(h):
455 return h[:12]
455 return h[:12]
456
456
457 if ui.quiet:
457 if ui.quiet:
458 datefunc = dateutil.shortdate
458 datefunc = dateutil.shortdate
459 else:
459 else:
460 datefunc = dateutil.datestr
460 datefunc = dateutil.datestr
461 if ctx.rev() is None:
461 if ctx.rev() is None:
462 if opts.get(b'changeset'):
462 if opts.get(b'changeset'):
463 # omit "+" suffix which is appended to node hex
463 # omit "+" suffix which is appended to node hex
464 def formatrev(rev):
464 def formatrev(rev):
465 if rev == wdirrev:
465 if rev == wdirrev:
466 return b'%d' % ctx.p1().rev()
466 return b'%d' % ctx.p1().rev()
467 else:
467 else:
468 return b'%d' % rev
468 return b'%d' % rev
469
469
470 else:
470 else:
471
471
472 def formatrev(rev):
472 def formatrev(rev):
473 if rev == wdirrev:
473 if rev == wdirrev:
474 return b'%d+' % ctx.p1().rev()
474 return b'%d+' % ctx.p1().rev()
475 else:
475 else:
476 return b'%d ' % rev
476 return b'%d ' % rev
477
477
478 def formathex(h):
478 def formathex(h):
479 if h == repo.nodeconstants.wdirhex:
479 if h == repo.nodeconstants.wdirhex:
480 return b'%s+' % shorthex(hex(ctx.p1().node()))
480 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 else:
481 else:
482 return b'%s ' % shorthex(h)
482 return b'%s ' % shorthex(h)
483
483
484 else:
484 else:
485 formatrev = b'%d'.__mod__
485 formatrev = b'%d'.__mod__
486 formathex = shorthex
486 formathex = shorthex
487
487
488 opmap = [
488 opmap = [
489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 ]
495 ]
496 opnamemap = {
496 opnamemap = {
497 b'rev': b'number',
497 b'rev': b'number',
498 b'node': b'changeset',
498 b'node': b'changeset',
499 b'path': b'file',
499 b'path': b'file',
500 b'lineno': b'line_number',
500 b'lineno': b'line_number',
501 }
501 }
502
502
503 if rootfm.isplain():
503 if rootfm.isplain():
504
504
505 def makefunc(get, fmt):
505 def makefunc(get, fmt):
506 return lambda x: fmt(get(x))
506 return lambda x: fmt(get(x))
507
507
508 else:
508 else:
509
509
510 def makefunc(get, fmt):
510 def makefunc(get, fmt):
511 return get
511 return get
512
512
513 datahint = rootfm.datahint()
513 datahint = rootfm.datahint()
514 funcmap = [
514 funcmap = [
515 (makefunc(get, fmt), sep)
515 (makefunc(get, fmt), sep)
516 for fn, sep, get, fmt in opmap
516 for fn, sep, get, fmt in opmap
517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 ]
518 ]
519 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
519 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
520 fields = b' '.join(
520 fields = b' '.join(
521 fn
521 fn
522 for fn, sep, get, fmt in opmap
522 for fn, sep, get, fmt in opmap
523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 )
524 )
525
525
526 def bad(x, y):
526 def bad(x, y):
527 raise error.InputError(b"%s: %s" % (x, y))
527 raise error.InputError(b"%s: %s" % (x, y))
528
528
529 m = scmutil.match(ctx, pats, opts, badfn=bad)
529 m = scmutil.match(ctx, pats, opts, badfn=bad)
530
530
531 follow = not opts.get(b'no_follow')
531 follow = not opts.get(b'no_follow')
532 diffopts = patch.difffeatureopts(
532 diffopts = patch.difffeatureopts(
533 ui, opts, section=b'annotate', whitespace=True
533 ui, opts, section=b'annotate', whitespace=True
534 )
534 )
535 skiprevs = opts.get(b'skip')
535 skiprevs = opts.get(b'skip')
536 if skiprevs:
536 if skiprevs:
537 skiprevs = logcmdutil.revrange(repo, skiprevs)
537 skiprevs = logcmdutil.revrange(repo, skiprevs)
538
538
539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 for abs in ctx.walk(m):
540 for abs in ctx.walk(m):
541 fctx = ctx[abs]
541 fctx = ctx[abs]
542 rootfm.startitem()
542 rootfm.startitem()
543 rootfm.data(path=abs)
543 rootfm.data(path=abs)
544 if not opts.get(b'text') and fctx.isbinary():
544 if not opts.get(b'text') and fctx.isbinary():
545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 continue
546 continue
547
547
548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 lines = fctx.annotate(
549 lines = fctx.annotate(
550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 )
551 )
552 if not lines:
552 if not lines:
553 fm.end()
553 fm.end()
554 continue
554 continue
555 formats = []
555 formats = []
556 pieces = []
556 pieces = []
557
557
558 for f, sep in funcmap:
558 for f, sep in funcmap:
559 l = [f(n) for n in lines]
559 l = [f(n) for n in lines]
560 if fm.isplain():
560 if fm.isplain():
561 sizes = [encoding.colwidth(x) for x in l]
561 sizes = [encoding.colwidth(x) for x in l]
562 ml = max(sizes)
562 ml = max(sizes)
563 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
563 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
564 else:
564 else:
565 formats.append([b'%s'] * len(l))
565 formats.append([b'%s'] * len(l))
566 pieces.append(l)
566 pieces.append(l)
567
567
568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 fm.startitem()
569 fm.startitem()
570 fm.context(fctx=n.fctx)
570 fm.context(fctx=n.fctx)
571 fm.write(fields, b"".join(f), *p)
571 fm.write(fields, b"".join(f), *p)
572 if n.skip:
572 if n.skip:
573 fmt = b"* %s"
573 fmt = b"* %s"
574 else:
574 else:
575 fmt = b": %s"
575 fmt = b": %s"
576 fm.write(b'line', fmt, n.text)
576 fm.write(b'line', fmt, n.text)
577
577
578 if not lines[-1].text.endswith(b'\n'):
578 if not lines[-1].text.endswith(b'\n'):
579 fm.plain(b'\n')
579 fm.plain(b'\n')
580 fm.end()
580 fm.end()
581
581
582 rootfm.end()
582 rootfm.end()
583
583
584
584
585 @command(
585 @command(
586 b'archive',
586 b'archive',
587 [
587 [
588 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
588 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
589 (
589 (
590 b'p',
590 b'p',
591 b'prefix',
591 b'prefix',
592 b'',
592 b'',
593 _(b'directory prefix for files in archive'),
593 _(b'directory prefix for files in archive'),
594 _(b'PREFIX'),
594 _(b'PREFIX'),
595 ),
595 ),
596 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
596 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
597 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
598 ]
598 ]
599 + subrepoopts
599 + subrepoopts
600 + walkopts,
600 + walkopts,
601 _(b'[OPTION]... DEST'),
601 _(b'[OPTION]... DEST'),
602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 )
603 )
604 def archive(ui, repo, dest, **opts):
604 def archive(ui, repo, dest, **opts):
605 """create an unversioned archive of a repository revision
605 """create an unversioned archive of a repository revision
606
606
607 By default, the revision used is the parent of the working
607 By default, the revision used is the parent of the working
608 directory; use -r/--rev to specify a different revision.
608 directory; use -r/--rev to specify a different revision.
609
609
610 The archive type is automatically detected based on file
610 The archive type is automatically detected based on file
611 extension (to override, use -t/--type).
611 extension (to override, use -t/--type).
612
612
613 .. container:: verbose
613 .. container:: verbose
614
614
615 Examples:
615 Examples:
616
616
617 - create a zip file containing the 1.0 release::
617 - create a zip file containing the 1.0 release::
618
618
619 hg archive -r 1.0 project-1.0.zip
619 hg archive -r 1.0 project-1.0.zip
620
620
621 - create a tarball excluding .hg files::
621 - create a tarball excluding .hg files::
622
622
623 hg archive project.tar.gz -X ".hg*"
623 hg archive project.tar.gz -X ".hg*"
624
624
625 Valid types are:
625 Valid types are:
626
626
627 :``files``: a directory full of files (default)
627 :``files``: a directory full of files (default)
628 :``tar``: tar archive, uncompressed
628 :``tar``: tar archive, uncompressed
629 :``tbz2``: tar archive, compressed using bzip2
629 :``tbz2``: tar archive, compressed using bzip2
630 :``tgz``: tar archive, compressed using gzip
630 :``tgz``: tar archive, compressed using gzip
631 :``txz``: tar archive, compressed using lzma (only in Python 3)
631 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 :``uzip``: zip archive, uncompressed
632 :``uzip``: zip archive, uncompressed
633 :``zip``: zip archive, compressed using deflate
633 :``zip``: zip archive, compressed using deflate
634
634
635 The exact name of the destination archive or directory is given
635 The exact name of the destination archive or directory is given
636 using a format string; see :hg:`help export` for details.
636 using a format string; see :hg:`help export` for details.
637
637
638 Each member added to an archive file has a directory prefix
638 Each member added to an archive file has a directory prefix
639 prepended. Use -p/--prefix to specify a format string for the
639 prepended. Use -p/--prefix to specify a format string for the
640 prefix. The default is the basename of the archive, with suffixes
640 prefix. The default is the basename of the archive, with suffixes
641 removed.
641 removed.
642
642
643 Returns 0 on success.
643 Returns 0 on success.
644 """
644 """
645
645
646 opts = pycompat.byteskwargs(opts)
646 opts = pycompat.byteskwargs(opts)
647 rev = opts.get(b'rev')
647 rev = opts.get(b'rev')
648 if rev:
648 if rev:
649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 ctx = logcmdutil.revsingle(repo, rev)
650 ctx = logcmdutil.revsingle(repo, rev)
651 if not ctx:
651 if not ctx:
652 raise error.InputError(
652 raise error.InputError(
653 _(b'no working directory: please specify a revision')
653 _(b'no working directory: please specify a revision')
654 )
654 )
655 node = ctx.node()
655 node = ctx.node()
656 dest = cmdutil.makefilename(ctx, dest)
656 dest = cmdutil.makefilename(ctx, dest)
657 if os.path.realpath(dest) == repo.root:
657 if os.path.realpath(dest) == repo.root:
658 raise error.InputError(_(b'repository root cannot be destination'))
658 raise error.InputError(_(b'repository root cannot be destination'))
659
659
660 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
660 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
661 prefix = opts.get(b'prefix')
661 prefix = opts.get(b'prefix')
662
662
663 if dest == b'-':
663 if dest == b'-':
664 if kind == b'files':
664 if kind == b'files':
665 raise error.InputError(_(b'cannot archive plain files to stdout'))
665 raise error.InputError(_(b'cannot archive plain files to stdout'))
666 dest = cmdutil.makefileobj(ctx, dest)
666 dest = cmdutil.makefileobj(ctx, dest)
667 if not prefix:
667 if not prefix:
668 prefix = os.path.basename(repo.root) + b'-%h'
668 prefix = os.path.basename(repo.root) + b'-%h'
669
669
670 prefix = cmdutil.makefilename(ctx, prefix)
670 prefix = cmdutil.makefilename(ctx, prefix)
671 match = scmutil.match(ctx, [], opts)
671 match = scmutil.match(ctx, [], opts)
672 archival.archive(
672 archival.archive(
673 repo,
673 repo,
674 dest,
674 dest,
675 node,
675 node,
676 kind,
676 kind,
677 not opts.get(b'no_decode'),
677 not opts.get(b'no_decode'),
678 match,
678 match,
679 prefix,
679 prefix,
680 subrepos=opts.get(b'subrepos'),
680 subrepos=opts.get(b'subrepos'),
681 )
681 )
682
682
683
683
684 @command(
684 @command(
685 b'backout',
685 b'backout',
686 [
686 [
687 (
687 (
688 b'',
688 b'',
689 b'merge',
689 b'merge',
690 None,
690 None,
691 _(b'merge with old dirstate parent after backout'),
691 _(b'merge with old dirstate parent after backout'),
692 ),
692 ),
693 (
693 (
694 b'',
694 b'',
695 b'commit',
695 b'commit',
696 None,
696 None,
697 _(b'commit if no conflicts were encountered (DEPRECATED)'),
697 _(b'commit if no conflicts were encountered (DEPRECATED)'),
698 ),
698 ),
699 (b'', b'no-commit', None, _(b'do not commit')),
699 (b'', b'no-commit', None, _(b'do not commit')),
700 (
700 (
701 b'',
701 b'',
702 b'parent',
702 b'parent',
703 b'',
703 b'',
704 _(b'parent to choose when backing out merge (DEPRECATED)'),
704 _(b'parent to choose when backing out merge (DEPRECATED)'),
705 _(b'REV'),
705 _(b'REV'),
706 ),
706 ),
707 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
707 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
708 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
708 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
709 ]
709 ]
710 + mergetoolopts
710 + mergetoolopts
711 + walkopts
711 + walkopts
712 + commitopts
712 + commitopts
713 + commitopts2,
713 + commitopts2,
714 _(b'[OPTION]... [-r] REV'),
714 _(b'[OPTION]... [-r] REV'),
715 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
715 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
716 )
716 )
717 def backout(ui, repo, node=None, rev=None, **opts):
717 def backout(ui, repo, node=None, rev=None, **opts):
718 """reverse effect of earlier changeset
718 """reverse effect of earlier changeset
719
719
720 Prepare a new changeset with the effect of REV undone in the
720 Prepare a new changeset with the effect of REV undone in the
721 current working directory. If no conflicts were encountered,
721 current working directory. If no conflicts were encountered,
722 it will be committed immediately.
722 it will be committed immediately.
723
723
724 If REV is the parent of the working directory, then this new changeset
724 If REV is the parent of the working directory, then this new changeset
725 is committed automatically (unless --no-commit is specified).
725 is committed automatically (unless --no-commit is specified).
726
726
727 .. note::
727 .. note::
728
728
729 :hg:`backout` cannot be used to fix either an unwanted or
729 :hg:`backout` cannot be used to fix either an unwanted or
730 incorrect merge.
730 incorrect merge.
731
731
732 .. container:: verbose
732 .. container:: verbose
733
733
734 Examples:
734 Examples:
735
735
736 - Reverse the effect of the parent of the working directory.
736 - Reverse the effect of the parent of the working directory.
737 This backout will be committed immediately::
737 This backout will be committed immediately::
738
738
739 hg backout -r .
739 hg backout -r .
740
740
741 - Reverse the effect of previous bad revision 23::
741 - Reverse the effect of previous bad revision 23::
742
742
743 hg backout -r 23
743 hg backout -r 23
744
744
745 - Reverse the effect of previous bad revision 23 and
745 - Reverse the effect of previous bad revision 23 and
746 leave changes uncommitted::
746 leave changes uncommitted::
747
747
748 hg backout -r 23 --no-commit
748 hg backout -r 23 --no-commit
749 hg commit -m "Backout revision 23"
749 hg commit -m "Backout revision 23"
750
750
751 By default, the pending changeset will have one parent,
751 By default, the pending changeset will have one parent,
752 maintaining a linear history. With --merge, the pending
752 maintaining a linear history. With --merge, the pending
753 changeset will instead have two parents: the old parent of the
753 changeset will instead have two parents: the old parent of the
754 working directory and a new child of REV that simply undoes REV.
754 working directory and a new child of REV that simply undoes REV.
755
755
756 Before version 1.7, the behavior without --merge was equivalent
756 Before version 1.7, the behavior without --merge was equivalent
757 to specifying --merge followed by :hg:`update --clean .` to
757 to specifying --merge followed by :hg:`update --clean .` to
758 cancel the merge and leave the child of REV as a head to be
758 cancel the merge and leave the child of REV as a head to be
759 merged separately.
759 merged separately.
760
760
761 See :hg:`help dates` for a list of formats valid for -d/--date.
761 See :hg:`help dates` for a list of formats valid for -d/--date.
762
762
763 See :hg:`help revert` for a way to restore files to the state
763 See :hg:`help revert` for a way to restore files to the state
764 of another revision.
764 of another revision.
765
765
766 Returns 0 on success, 1 if nothing to backout or there are unresolved
766 Returns 0 on success, 1 if nothing to backout or there are unresolved
767 files.
767 files.
768 """
768 """
769 with repo.wlock(), repo.lock():
769 with repo.wlock(), repo.lock():
770 return _dobackout(ui, repo, node, rev, **opts)
770 return _dobackout(ui, repo, node, rev, **opts)
771
771
772
772
773 def _dobackout(ui, repo, node=None, rev=None, **opts):
773 def _dobackout(ui, repo, node=None, rev=None, **opts):
774 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
774 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
775 opts = pycompat.byteskwargs(opts)
775 opts = pycompat.byteskwargs(opts)
776
776
777 if rev and node:
777 if rev and node:
778 raise error.InputError(_(b"please specify just one revision"))
778 raise error.InputError(_(b"please specify just one revision"))
779
779
780 if not rev:
780 if not rev:
781 rev = node
781 rev = node
782
782
783 if not rev:
783 if not rev:
784 raise error.InputError(_(b"please specify a revision to backout"))
784 raise error.InputError(_(b"please specify a revision to backout"))
785
785
786 date = opts.get(b'date')
786 date = opts.get(b'date')
787 if date:
787 if date:
788 opts[b'date'] = dateutil.parsedate(date)
788 opts[b'date'] = dateutil.parsedate(date)
789
789
790 cmdutil.checkunfinished(repo)
790 cmdutil.checkunfinished(repo)
791 cmdutil.bailifchanged(repo)
791 cmdutil.bailifchanged(repo)
792 ctx = logcmdutil.revsingle(repo, rev)
792 ctx = logcmdutil.revsingle(repo, rev)
793 node = ctx.node()
793 node = ctx.node()
794
794
795 op1, op2 = repo.dirstate.parents()
795 op1, op2 = repo.dirstate.parents()
796 if not repo.changelog.isancestor(node, op1):
796 if not repo.changelog.isancestor(node, op1):
797 raise error.InputError(
797 raise error.InputError(
798 _(b'cannot backout change that is not an ancestor')
798 _(b'cannot backout change that is not an ancestor')
799 )
799 )
800
800
801 p1, p2 = repo.changelog.parents(node)
801 p1, p2 = repo.changelog.parents(node)
802 if p1 == repo.nullid:
802 if p1 == repo.nullid:
803 raise error.InputError(_(b'cannot backout a change with no parents'))
803 raise error.InputError(_(b'cannot backout a change with no parents'))
804 if p2 != repo.nullid:
804 if p2 != repo.nullid:
805 if not opts.get(b'parent'):
805 if not opts.get(b'parent'):
806 raise error.InputError(_(b'cannot backout a merge changeset'))
806 raise error.InputError(_(b'cannot backout a merge changeset'))
807 p = repo.lookup(opts[b'parent'])
807 p = repo.lookup(opts[b'parent'])
808 if p not in (p1, p2):
808 if p not in (p1, p2):
809 raise error.InputError(
809 raise error.InputError(
810 _(b'%s is not a parent of %s') % (short(p), short(node))
810 _(b'%s is not a parent of %s') % (short(p), short(node))
811 )
811 )
812 parent = p
812 parent = p
813 else:
813 else:
814 if opts.get(b'parent'):
814 if opts.get(b'parent'):
815 raise error.InputError(
815 raise error.InputError(
816 _(b'cannot use --parent on non-merge changeset')
816 _(b'cannot use --parent on non-merge changeset')
817 )
817 )
818 parent = p1
818 parent = p1
819
819
820 # the backout should appear on the same branch
820 # the backout should appear on the same branch
821 branch = repo.dirstate.branch()
821 branch = repo.dirstate.branch()
822 bheads = repo.branchheads(branch)
822 bheads = repo.branchheads(branch)
823 rctx = scmutil.revsingle(repo, hex(parent))
823 rctx = scmutil.revsingle(repo, hex(parent))
824 if not opts.get(b'merge') and op1 != node:
824 if not opts.get(b'merge') and op1 != node:
825 with dirstateguard.dirstateguard(repo, b'backout'):
825 with dirstateguard.dirstateguard(repo, b'backout'):
826 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
826 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
827 with ui.configoverride(overrides, b'backout'):
827 with ui.configoverride(overrides, b'backout'):
828 stats = mergemod.back_out(ctx, parent=repo[parent])
828 stats = mergemod.back_out(ctx, parent=repo[parent])
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx)
839 cmdutil.revert(ui, repo, rctx)
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 # save to detect changes
859 # save to detect changes
860 tip = repo.changelog.tip()
860 tip = repo.changelog.tip()
861
861
862 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
862 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
863 if not newnode:
863 if not newnode:
864 ui.status(_(b"nothing changed\n"))
864 ui.status(_(b"nothing changed\n"))
865 return 1
865 return 1
866 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
866 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
867
867
868 def nice(node):
868 def nice(node):
869 return b'%d:%s' % (repo.changelog.rev(node), short(node))
869 return b'%d:%s' % (repo.changelog.rev(node), short(node))
870
870
871 ui.status(
871 ui.status(
872 _(b'changeset %s backs out changeset %s\n')
872 _(b'changeset %s backs out changeset %s\n')
873 % (nice(newnode), nice(node))
873 % (nice(newnode), nice(node))
874 )
874 )
875 if opts.get(b'merge') and op1 != node:
875 if opts.get(b'merge') and op1 != node:
876 hg.clean(repo, op1, show_stats=False)
876 hg.clean(repo, op1, show_stats=False)
877 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
877 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
878 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
879 with ui.configoverride(overrides, b'backout'):
879 with ui.configoverride(overrides, b'backout'):
880 return hg.merge(repo[b'tip'])
880 return hg.merge(repo[b'tip'])
881 return 0
881 return 0
882
882
883
883
884 @command(
884 @command(
885 b'bisect',
885 b'bisect',
886 [
886 [
887 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'r', b'reset', False, _(b'reset bisect state')),
888 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'g', b'good', False, _(b'mark changeset good')),
889 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b'b', b'bad', False, _(b'mark changeset bad')),
890 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b's', b'skip', False, _(b'skip testing changeset')),
891 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (b'e', b'extend', False, _(b'extend the bisect range')),
892 (
892 (
893 b'c',
893 b'c',
894 b'command',
894 b'command',
895 b'',
895 b'',
896 _(b'use command to check changeset state'),
896 _(b'use command to check changeset state'),
897 _(b'CMD'),
897 _(b'CMD'),
898 ),
898 ),
899 (b'U', b'noupdate', False, _(b'do not update to target')),
899 (b'U', b'noupdate', False, _(b'do not update to target')),
900 ],
900 ],
901 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
902 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
903 )
903 )
904 def bisect(
904 def bisect(
905 ui,
905 ui,
906 repo,
906 repo,
907 positional_1=None,
907 positional_1=None,
908 positional_2=None,
908 positional_2=None,
909 command=None,
909 command=None,
910 reset=None,
910 reset=None,
911 good=None,
911 good=None,
912 bad=None,
912 bad=None,
913 skip=None,
913 skip=None,
914 extend=None,
914 extend=None,
915 noupdate=None,
915 noupdate=None,
916 ):
916 ):
917 """subdivision search of changesets
917 """subdivision search of changesets
918
918
919 This command helps to find changesets which introduce problems. To
919 This command helps to find changesets which introduce problems. To
920 use, mark the earliest changeset you know exhibits the problem as
920 use, mark the earliest changeset you know exhibits the problem as
921 bad, then mark the latest changeset which is free from the problem
921 bad, then mark the latest changeset which is free from the problem
922 as good. Bisect will update your working directory to a revision
922 as good. Bisect will update your working directory to a revision
923 for testing (unless the -U/--noupdate option is specified). Once
923 for testing (unless the -U/--noupdate option is specified). Once
924 you have performed tests, mark the working directory as good or
924 you have performed tests, mark the working directory as good or
925 bad, and bisect will either update to another candidate changeset
925 bad, and bisect will either update to another candidate changeset
926 or announce that it has found the bad revision.
926 or announce that it has found the bad revision.
927
927
928 As a shortcut, you can also use the revision argument to mark a
928 As a shortcut, you can also use the revision argument to mark a
929 revision as good or bad without checking it out first.
929 revision as good or bad without checking it out first.
930
930
931 If you supply a command, it will be used for automatic bisection.
931 If you supply a command, it will be used for automatic bisection.
932 The environment variable HG_NODE will contain the ID of the
932 The environment variable HG_NODE will contain the ID of the
933 changeset being tested. The exit status of the command will be
933 changeset being tested. The exit status of the command will be
934 used to mark revisions as good or bad: status 0 means good, 125
934 used to mark revisions as good or bad: status 0 means good, 125
935 means to skip the revision, 127 (command not found) will abort the
935 means to skip the revision, 127 (command not found) will abort the
936 bisection, and any other non-zero exit status means the revision
936 bisection, and any other non-zero exit status means the revision
937 is bad.
937 is bad.
938
938
939 .. container:: verbose
939 .. container:: verbose
940
940
941 Some examples:
941 Some examples:
942
942
943 - start a bisection with known bad revision 34, and good revision 12::
943 - start a bisection with known bad revision 34, and good revision 12::
944
944
945 hg bisect --bad 34
945 hg bisect --bad 34
946 hg bisect --good 12
946 hg bisect --good 12
947
947
948 - advance the current bisection by marking current revision as good or
948 - advance the current bisection by marking current revision as good or
949 bad::
949 bad::
950
950
951 hg bisect --good
951 hg bisect --good
952 hg bisect --bad
952 hg bisect --bad
953
953
954 - mark the current revision, or a known revision, to be skipped (e.g. if
954 - mark the current revision, or a known revision, to be skipped (e.g. if
955 that revision is not usable because of another issue)::
955 that revision is not usable because of another issue)::
956
956
957 hg bisect --skip
957 hg bisect --skip
958 hg bisect --skip 23
958 hg bisect --skip 23
959
959
960 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960 - skip all revisions that do not touch directories ``foo`` or ``bar``::
961
961
962 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
963
963
964 - forget the current bisection::
964 - forget the current bisection::
965
965
966 hg bisect --reset
966 hg bisect --reset
967
967
968 - use 'make && make tests' to automatically find the first broken
968 - use 'make && make tests' to automatically find the first broken
969 revision::
969 revision::
970
970
971 hg bisect --reset
971 hg bisect --reset
972 hg bisect --bad 34
972 hg bisect --bad 34
973 hg bisect --good 12
973 hg bisect --good 12
974 hg bisect --command "make && make tests"
974 hg bisect --command "make && make tests"
975
975
976 - see all changesets whose states are already known in the current
976 - see all changesets whose states are already known in the current
977 bisection::
977 bisection::
978
978
979 hg log -r "bisect(pruned)"
979 hg log -r "bisect(pruned)"
980
980
981 - see the changeset currently being bisected (especially useful
981 - see the changeset currently being bisected (especially useful
982 if running with -U/--noupdate)::
982 if running with -U/--noupdate)::
983
983
984 hg log -r "bisect(current)"
984 hg log -r "bisect(current)"
985
985
986 - see all changesets that took part in the current bisection::
986 - see all changesets that took part in the current bisection::
987
987
988 hg log -r "bisect(range)"
988 hg log -r "bisect(range)"
989
989
990 - you can even get a nice graph::
990 - you can even get a nice graph::
991
991
992 hg log --graph -r "bisect(range)"
992 hg log --graph -r "bisect(range)"
993
993
994 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
995
995
996 Returns 0 on success.
996 Returns 0 on success.
997 """
997 """
998 rev = []
998 rev = []
999 # backward compatibility
999 # backward compatibility
1000 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1000 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1001 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1001 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1002 cmd = positional_1
1002 cmd = positional_1
1003 rev.append(positional_2)
1003 rev.append(positional_2)
1004 if cmd == b"good":
1004 if cmd == b"good":
1005 good = True
1005 good = True
1006 elif cmd == b"bad":
1006 elif cmd == b"bad":
1007 bad = True
1007 bad = True
1008 else:
1008 else:
1009 reset = True
1009 reset = True
1010 elif positional_2:
1010 elif positional_2:
1011 raise error.InputError(_(b'incompatible arguments'))
1011 raise error.InputError(_(b'incompatible arguments'))
1012 elif positional_1 is not None:
1012 elif positional_1 is not None:
1013 rev.append(positional_1)
1013 rev.append(positional_1)
1014
1014
1015 incompatibles = {
1015 incompatibles = {
1016 b'--bad': bad,
1016 b'--bad': bad,
1017 b'--command': bool(command),
1017 b'--command': bool(command),
1018 b'--extend': extend,
1018 b'--extend': extend,
1019 b'--good': good,
1019 b'--good': good,
1020 b'--reset': reset,
1020 b'--reset': reset,
1021 b'--skip': skip,
1021 b'--skip': skip,
1022 }
1022 }
1023
1023
1024 enabled = [x for x in incompatibles if incompatibles[x]]
1024 enabled = [x for x in incompatibles if incompatibles[x]]
1025
1025
1026 if len(enabled) > 1:
1026 if len(enabled) > 1:
1027 raise error.InputError(
1027 raise error.InputError(
1028 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1028 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1029 )
1029 )
1030
1030
1031 if reset:
1031 if reset:
1032 hbisect.resetstate(repo)
1032 hbisect.resetstate(repo)
1033 return
1033 return
1034
1034
1035 state = hbisect.load_state(repo)
1035 state = hbisect.load_state(repo)
1036
1036
1037 if rev:
1037 if rev:
1038 nodes = [repo.changelog.node(i) for i in logcmdutil.revrange(repo, rev)]
1038 revs = logcmdutil.revrange(repo, rev)
1039 goodnodes = state[b'good']
1040 badnodes = state[b'bad']
1041 if goodnodes and badnodes:
1042 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1043 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1044 revs = candidates & revs
1045 nodes = [repo.changelog.node(i) for i in revs]
1039 else:
1046 else:
1040 nodes = [repo.lookup(b'.')]
1047 nodes = [repo.lookup(b'.')]
1041
1048
1042 # update state
1049 # update state
1043 if good or bad or skip:
1050 if good or bad or skip:
1044 if good:
1051 if good:
1045 state[b'good'] += nodes
1052 state[b'good'] += nodes
1046 elif bad:
1053 elif bad:
1047 state[b'bad'] += nodes
1054 state[b'bad'] += nodes
1048 elif skip:
1055 elif skip:
1049 state[b'skip'] += nodes
1056 state[b'skip'] += nodes
1050 hbisect.save_state(repo, state)
1057 hbisect.save_state(repo, state)
1051 if not (state[b'good'] and state[b'bad']):
1058 if not (state[b'good'] and state[b'bad']):
1052 return
1059 return
1053
1060
1054 def mayupdate(repo, node, show_stats=True):
1061 def mayupdate(repo, node, show_stats=True):
1055 """common used update sequence"""
1062 """common used update sequence"""
1056 if noupdate:
1063 if noupdate:
1057 return
1064 return
1058 cmdutil.checkunfinished(repo)
1065 cmdutil.checkunfinished(repo)
1059 cmdutil.bailifchanged(repo)
1066 cmdutil.bailifchanged(repo)
1060 return hg.clean(repo, node, show_stats=show_stats)
1067 return hg.clean(repo, node, show_stats=show_stats)
1061
1068
1062 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1069 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1063
1070
1064 if command:
1071 if command:
1065 changesets = 1
1072 changesets = 1
1066 if noupdate:
1073 if noupdate:
1067 try:
1074 try:
1068 node = state[b'current'][0]
1075 node = state[b'current'][0]
1069 except LookupError:
1076 except LookupError:
1070 raise error.StateError(
1077 raise error.StateError(
1071 _(
1078 _(
1072 b'current bisect revision is unknown - '
1079 b'current bisect revision is unknown - '
1073 b'start a new bisect to fix'
1080 b'start a new bisect to fix'
1074 )
1081 )
1075 )
1082 )
1076 else:
1083 else:
1077 node, p2 = repo.dirstate.parents()
1084 node, p2 = repo.dirstate.parents()
1078 if p2 != repo.nullid:
1085 if p2 != repo.nullid:
1079 raise error.StateError(_(b'current bisect revision is a merge'))
1086 raise error.StateError(_(b'current bisect revision is a merge'))
1080 if rev:
1087 if rev:
1081 if not nodes:
1088 if not nodes:
1082 raise error.InputError(_(b'empty revision set'))
1089 raise error.InputError(_(b'empty revision set'))
1083 node = repo[nodes[-1]].node()
1090 node = repo[nodes[-1]].node()
1084 with hbisect.restore_state(repo, state, node):
1091 with hbisect.restore_state(repo, state, node):
1085 while changesets:
1092 while changesets:
1086 # update state
1093 # update state
1087 state[b'current'] = [node]
1094 state[b'current'] = [node]
1088 hbisect.save_state(repo, state)
1095 hbisect.save_state(repo, state)
1089 status = ui.system(
1096 status = ui.system(
1090 command,
1097 command,
1091 environ={b'HG_NODE': hex(node)},
1098 environ={b'HG_NODE': hex(node)},
1092 blockedtag=b'bisect_check',
1099 blockedtag=b'bisect_check',
1093 )
1100 )
1094 if status == 125:
1101 if status == 125:
1095 transition = b"skip"
1102 transition = b"skip"
1096 elif status == 0:
1103 elif status == 0:
1097 transition = b"good"
1104 transition = b"good"
1098 # status < 0 means process was killed
1105 # status < 0 means process was killed
1099 elif status == 127:
1106 elif status == 127:
1100 raise error.Abort(_(b"failed to execute %s") % command)
1107 raise error.Abort(_(b"failed to execute %s") % command)
1101 elif status < 0:
1108 elif status < 0:
1102 raise error.Abort(_(b"%s killed") % command)
1109 raise error.Abort(_(b"%s killed") % command)
1103 else:
1110 else:
1104 transition = b"bad"
1111 transition = b"bad"
1105 state[transition].append(node)
1112 state[transition].append(node)
1106 ctx = repo[node]
1113 ctx = repo[node]
1107 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1114 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1108 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1115 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1109 hbisect.checkstate(state)
1116 hbisect.checkstate(state)
1110 # bisect
1117 # bisect
1111 nodes, changesets, bgood = hbisect.bisect(repo, state)
1118 nodes, changesets, bgood = hbisect.bisect(repo, state)
1112 # update to next check
1119 # update to next check
1113 node = nodes[0]
1120 node = nodes[0]
1114 mayupdate(repo, node, show_stats=False)
1121 mayupdate(repo, node, show_stats=False)
1115 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1122 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1116 return
1123 return
1117
1124
1118 hbisect.checkstate(state)
1125 hbisect.checkstate(state)
1119
1126
1120 # actually bisect
1127 # actually bisect
1121 nodes, changesets, good = hbisect.bisect(repo, state)
1128 nodes, changesets, good = hbisect.bisect(repo, state)
1122 if extend:
1129 if extend:
1123 if not changesets:
1130 if not changesets:
1124 extendctx = hbisect.extendrange(repo, state, nodes, good)
1131 extendctx = hbisect.extendrange(repo, state, nodes, good)
1125 if extendctx is not None:
1132 if extendctx is not None:
1126 ui.write(
1133 ui.write(
1127 _(b"Extending search to changeset %s\n")
1134 _(b"Extending search to changeset %s\n")
1128 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1135 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1129 )
1136 )
1130 state[b'current'] = [extendctx.node()]
1137 state[b'current'] = [extendctx.node()]
1131 hbisect.save_state(repo, state)
1138 hbisect.save_state(repo, state)
1132 return mayupdate(repo, extendctx.node())
1139 return mayupdate(repo, extendctx.node())
1133 raise error.StateError(_(b"nothing to extend"))
1140 raise error.StateError(_(b"nothing to extend"))
1134
1141
1135 if changesets == 0:
1142 if changesets == 0:
1136 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1143 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1137 else:
1144 else:
1138 assert len(nodes) == 1 # only a single node can be tested next
1145 assert len(nodes) == 1 # only a single node can be tested next
1139 node = nodes[0]
1146 node = nodes[0]
1140 # compute the approximate number of remaining tests
1147 # compute the approximate number of remaining tests
1141 tests, size = 0, 2
1148 tests, size = 0, 2
1142 while size <= changesets:
1149 while size <= changesets:
1143 tests, size = tests + 1, size * 2
1150 tests, size = tests + 1, size * 2
1144 rev = repo.changelog.rev(node)
1151 rev = repo.changelog.rev(node)
1145 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1152 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1146 ui.write(
1153 ui.write(
1147 _(
1154 _(
1148 b"Testing changeset %s "
1155 b"Testing changeset %s "
1149 b"(%d changesets remaining, ~%d tests)\n"
1156 b"(%d changesets remaining, ~%d tests)\n"
1150 )
1157 )
1151 % (summary, changesets, tests)
1158 % (summary, changesets, tests)
1152 )
1159 )
1153 state[b'current'] = [node]
1160 state[b'current'] = [node]
1154 hbisect.save_state(repo, state)
1161 hbisect.save_state(repo, state)
1155 return mayupdate(repo, node)
1162 return mayupdate(repo, node)
1156
1163
1157
1164
1158 @command(
1165 @command(
1159 b'bookmarks|bookmark',
1166 b'bookmarks|bookmark',
1160 [
1167 [
1161 (b'f', b'force', False, _(b'force')),
1168 (b'f', b'force', False, _(b'force')),
1162 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1169 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1163 (b'd', b'delete', False, _(b'delete a given bookmark')),
1170 (b'd', b'delete', False, _(b'delete a given bookmark')),
1164 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1171 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1165 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1172 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1166 (b'l', b'list', False, _(b'list existing bookmarks')),
1173 (b'l', b'list', False, _(b'list existing bookmarks')),
1167 ]
1174 ]
1168 + formatteropts,
1175 + formatteropts,
1169 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1176 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1170 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1177 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1171 )
1178 )
1172 def bookmark(ui, repo, *names, **opts):
1179 def bookmark(ui, repo, *names, **opts):
1173 """create a new bookmark or list existing bookmarks
1180 """create a new bookmark or list existing bookmarks
1174
1181
1175 Bookmarks are labels on changesets to help track lines of development.
1182 Bookmarks are labels on changesets to help track lines of development.
1176 Bookmarks are unversioned and can be moved, renamed and deleted.
1183 Bookmarks are unversioned and can be moved, renamed and deleted.
1177 Deleting or moving a bookmark has no effect on the associated changesets.
1184 Deleting or moving a bookmark has no effect on the associated changesets.
1178
1185
1179 Creating or updating to a bookmark causes it to be marked as 'active'.
1186 Creating or updating to a bookmark causes it to be marked as 'active'.
1180 The active bookmark is indicated with a '*'.
1187 The active bookmark is indicated with a '*'.
1181 When a commit is made, the active bookmark will advance to the new commit.
1188 When a commit is made, the active bookmark will advance to the new commit.
1182 A plain :hg:`update` will also advance an active bookmark, if possible.
1189 A plain :hg:`update` will also advance an active bookmark, if possible.
1183 Updating away from a bookmark will cause it to be deactivated.
1190 Updating away from a bookmark will cause it to be deactivated.
1184
1191
1185 Bookmarks can be pushed and pulled between repositories (see
1192 Bookmarks can be pushed and pulled between repositories (see
1186 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1193 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1187 diverged, a new 'divergent bookmark' of the form 'name@path' will
1194 diverged, a new 'divergent bookmark' of the form 'name@path' will
1188 be created. Using :hg:`merge` will resolve the divergence.
1195 be created. Using :hg:`merge` will resolve the divergence.
1189
1196
1190 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1197 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1191 the active bookmark's name.
1198 the active bookmark's name.
1192
1199
1193 A bookmark named '@' has the special property that :hg:`clone` will
1200 A bookmark named '@' has the special property that :hg:`clone` will
1194 check it out by default if it exists.
1201 check it out by default if it exists.
1195
1202
1196 .. container:: verbose
1203 .. container:: verbose
1197
1204
1198 Template:
1205 Template:
1199
1206
1200 The following keywords are supported in addition to the common template
1207 The following keywords are supported in addition to the common template
1201 keywords and functions such as ``{bookmark}``. See also
1208 keywords and functions such as ``{bookmark}``. See also
1202 :hg:`help templates`.
1209 :hg:`help templates`.
1203
1210
1204 :active: Boolean. True if the bookmark is active.
1211 :active: Boolean. True if the bookmark is active.
1205
1212
1206 Examples:
1213 Examples:
1207
1214
1208 - create an active bookmark for a new line of development::
1215 - create an active bookmark for a new line of development::
1209
1216
1210 hg book new-feature
1217 hg book new-feature
1211
1218
1212 - create an inactive bookmark as a place marker::
1219 - create an inactive bookmark as a place marker::
1213
1220
1214 hg book -i reviewed
1221 hg book -i reviewed
1215
1222
1216 - create an inactive bookmark on another changeset::
1223 - create an inactive bookmark on another changeset::
1217
1224
1218 hg book -r .^ tested
1225 hg book -r .^ tested
1219
1226
1220 - rename bookmark turkey to dinner::
1227 - rename bookmark turkey to dinner::
1221
1228
1222 hg book -m turkey dinner
1229 hg book -m turkey dinner
1223
1230
1224 - move the '@' bookmark from another branch::
1231 - move the '@' bookmark from another branch::
1225
1232
1226 hg book -f @
1233 hg book -f @
1227
1234
1228 - print only the active bookmark name::
1235 - print only the active bookmark name::
1229
1236
1230 hg book -ql .
1237 hg book -ql .
1231 """
1238 """
1232 opts = pycompat.byteskwargs(opts)
1239 opts = pycompat.byteskwargs(opts)
1233 force = opts.get(b'force')
1240 force = opts.get(b'force')
1234 rev = opts.get(b'rev')
1241 rev = opts.get(b'rev')
1235 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1242 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1236
1243
1237 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1244 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1238 if action:
1245 if action:
1239 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1246 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1240 elif names or rev:
1247 elif names or rev:
1241 action = b'add'
1248 action = b'add'
1242 elif inactive:
1249 elif inactive:
1243 action = b'inactive' # meaning deactivate
1250 action = b'inactive' # meaning deactivate
1244 else:
1251 else:
1245 action = b'list'
1252 action = b'list'
1246
1253
1247 cmdutil.check_incompatible_arguments(
1254 cmdutil.check_incompatible_arguments(
1248 opts, b'inactive', [b'delete', b'list']
1255 opts, b'inactive', [b'delete', b'list']
1249 )
1256 )
1250 if not names and action in {b'add', b'delete'}:
1257 if not names and action in {b'add', b'delete'}:
1251 raise error.InputError(_(b"bookmark name required"))
1258 raise error.InputError(_(b"bookmark name required"))
1252
1259
1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1260 if action in {b'add', b'delete', b'rename', b'inactive'}:
1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1261 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1255 if action == b'delete':
1262 if action == b'delete':
1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1263 names = pycompat.maplist(repo._bookmarks.expandname, names)
1257 bookmarks.delete(repo, tr, names)
1264 bookmarks.delete(repo, tr, names)
1258 elif action == b'rename':
1265 elif action == b'rename':
1259 if not names:
1266 if not names:
1260 raise error.InputError(_(b"new bookmark name required"))
1267 raise error.InputError(_(b"new bookmark name required"))
1261 elif len(names) > 1:
1268 elif len(names) > 1:
1262 raise error.InputError(
1269 raise error.InputError(
1263 _(b"only one new bookmark name allowed")
1270 _(b"only one new bookmark name allowed")
1264 )
1271 )
1265 oldname = repo._bookmarks.expandname(opts[b'rename'])
1272 oldname = repo._bookmarks.expandname(opts[b'rename'])
1266 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1273 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1267 elif action == b'add':
1274 elif action == b'add':
1268 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1275 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1269 elif action == b'inactive':
1276 elif action == b'inactive':
1270 if len(repo._bookmarks) == 0:
1277 if len(repo._bookmarks) == 0:
1271 ui.status(_(b"no bookmarks set\n"))
1278 ui.status(_(b"no bookmarks set\n"))
1272 elif not repo._activebookmark:
1279 elif not repo._activebookmark:
1273 ui.status(_(b"no active bookmark\n"))
1280 ui.status(_(b"no active bookmark\n"))
1274 else:
1281 else:
1275 bookmarks.deactivate(repo)
1282 bookmarks.deactivate(repo)
1276 elif action == b'list':
1283 elif action == b'list':
1277 names = pycompat.maplist(repo._bookmarks.expandname, names)
1284 names = pycompat.maplist(repo._bookmarks.expandname, names)
1278 with ui.formatter(b'bookmarks', opts) as fm:
1285 with ui.formatter(b'bookmarks', opts) as fm:
1279 bookmarks.printbookmarks(ui, repo, fm, names)
1286 bookmarks.printbookmarks(ui, repo, fm, names)
1280 else:
1287 else:
1281 raise error.ProgrammingError(b'invalid action: %s' % action)
1288 raise error.ProgrammingError(b'invalid action: %s' % action)
1282
1289
1283
1290
1284 @command(
1291 @command(
1285 b'branch',
1292 b'branch',
1286 [
1293 [
1287 (
1294 (
1288 b'f',
1295 b'f',
1289 b'force',
1296 b'force',
1290 None,
1297 None,
1291 _(b'set branch name even if it shadows an existing branch'),
1298 _(b'set branch name even if it shadows an existing branch'),
1292 ),
1299 ),
1293 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1300 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1294 (
1301 (
1295 b'r',
1302 b'r',
1296 b'rev',
1303 b'rev',
1297 [],
1304 [],
1298 _(b'change branches of the given revs (EXPERIMENTAL)'),
1305 _(b'change branches of the given revs (EXPERIMENTAL)'),
1299 ),
1306 ),
1300 ],
1307 ],
1301 _(b'[-fC] [NAME]'),
1308 _(b'[-fC] [NAME]'),
1302 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1309 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1303 )
1310 )
1304 def branch(ui, repo, label=None, **opts):
1311 def branch(ui, repo, label=None, **opts):
1305 """set or show the current branch name
1312 """set or show the current branch name
1306
1313
1307 .. note::
1314 .. note::
1308
1315
1309 Branch names are permanent and global. Use :hg:`bookmark` to create a
1316 Branch names are permanent and global. Use :hg:`bookmark` to create a
1310 light-weight bookmark instead. See :hg:`help glossary` for more
1317 light-weight bookmark instead. See :hg:`help glossary` for more
1311 information about named branches and bookmarks.
1318 information about named branches and bookmarks.
1312
1319
1313 With no argument, show the current branch name. With one argument,
1320 With no argument, show the current branch name. With one argument,
1314 set the working directory branch name (the branch will not exist
1321 set the working directory branch name (the branch will not exist
1315 in the repository until the next commit). Standard practice
1322 in the repository until the next commit). Standard practice
1316 recommends that primary development take place on the 'default'
1323 recommends that primary development take place on the 'default'
1317 branch.
1324 branch.
1318
1325
1319 Unless -f/--force is specified, branch will not let you set a
1326 Unless -f/--force is specified, branch will not let you set a
1320 branch name that already exists.
1327 branch name that already exists.
1321
1328
1322 Use -C/--clean to reset the working directory branch to that of
1329 Use -C/--clean to reset the working directory branch to that of
1323 the parent of the working directory, negating a previous branch
1330 the parent of the working directory, negating a previous branch
1324 change.
1331 change.
1325
1332
1326 Use the command :hg:`update` to switch to an existing branch. Use
1333 Use the command :hg:`update` to switch to an existing branch. Use
1327 :hg:`commit --close-branch` to mark this branch head as closed.
1334 :hg:`commit --close-branch` to mark this branch head as closed.
1328 When all heads of a branch are closed, the branch will be
1335 When all heads of a branch are closed, the branch will be
1329 considered closed.
1336 considered closed.
1330
1337
1331 Returns 0 on success.
1338 Returns 0 on success.
1332 """
1339 """
1333 opts = pycompat.byteskwargs(opts)
1340 opts = pycompat.byteskwargs(opts)
1334 revs = opts.get(b'rev')
1341 revs = opts.get(b'rev')
1335 if label:
1342 if label:
1336 label = label.strip()
1343 label = label.strip()
1337
1344
1338 if not opts.get(b'clean') and not label:
1345 if not opts.get(b'clean') and not label:
1339 if revs:
1346 if revs:
1340 raise error.InputError(
1347 raise error.InputError(
1341 _(b"no branch name specified for the revisions")
1348 _(b"no branch name specified for the revisions")
1342 )
1349 )
1343 ui.write(b"%s\n" % repo.dirstate.branch())
1350 ui.write(b"%s\n" % repo.dirstate.branch())
1344 return
1351 return
1345
1352
1346 with repo.wlock():
1353 with repo.wlock():
1347 if opts.get(b'clean'):
1354 if opts.get(b'clean'):
1348 label = repo[b'.'].branch()
1355 label = repo[b'.'].branch()
1349 repo.dirstate.setbranch(label)
1356 repo.dirstate.setbranch(label)
1350 ui.status(_(b'reset working directory to branch %s\n') % label)
1357 ui.status(_(b'reset working directory to branch %s\n') % label)
1351 elif label:
1358 elif label:
1352
1359
1353 scmutil.checknewlabel(repo, label, b'branch')
1360 scmutil.checknewlabel(repo, label, b'branch')
1354 if revs:
1361 if revs:
1355 return cmdutil.changebranch(ui, repo, revs, label, opts)
1362 return cmdutil.changebranch(ui, repo, revs, label, opts)
1356
1363
1357 if not opts.get(b'force') and label in repo.branchmap():
1364 if not opts.get(b'force') and label in repo.branchmap():
1358 if label not in [p.branch() for p in repo[None].parents()]:
1365 if label not in [p.branch() for p in repo[None].parents()]:
1359 raise error.InputError(
1366 raise error.InputError(
1360 _(b'a branch of the same name already exists'),
1367 _(b'a branch of the same name already exists'),
1361 # i18n: "it" refers to an existing branch
1368 # i18n: "it" refers to an existing branch
1362 hint=_(b"use 'hg update' to switch to it"),
1369 hint=_(b"use 'hg update' to switch to it"),
1363 )
1370 )
1364
1371
1365 repo.dirstate.setbranch(label)
1372 repo.dirstate.setbranch(label)
1366 ui.status(_(b'marked working directory as branch %s\n') % label)
1373 ui.status(_(b'marked working directory as branch %s\n') % label)
1367
1374
1368 # find any open named branches aside from default
1375 # find any open named branches aside from default
1369 for n, h, t, c in repo.branchmap().iterbranches():
1376 for n, h, t, c in repo.branchmap().iterbranches():
1370 if n != b"default" and not c:
1377 if n != b"default" and not c:
1371 return 0
1378 return 0
1372 ui.status(
1379 ui.status(
1373 _(
1380 _(
1374 b'(branches are permanent and global, '
1381 b'(branches are permanent and global, '
1375 b'did you want a bookmark?)\n'
1382 b'did you want a bookmark?)\n'
1376 )
1383 )
1377 )
1384 )
1378
1385
1379
1386
1380 @command(
1387 @command(
1381 b'branches',
1388 b'branches',
1382 [
1389 [
1383 (
1390 (
1384 b'a',
1391 b'a',
1385 b'active',
1392 b'active',
1386 False,
1393 False,
1387 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1394 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1388 ),
1395 ),
1389 (b'c', b'closed', False, _(b'show normal and closed branches')),
1396 (b'c', b'closed', False, _(b'show normal and closed branches')),
1390 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1397 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1391 ]
1398 ]
1392 + formatteropts,
1399 + formatteropts,
1393 _(b'[-c]'),
1400 _(b'[-c]'),
1394 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1401 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1395 intents={INTENT_READONLY},
1402 intents={INTENT_READONLY},
1396 )
1403 )
1397 def branches(ui, repo, active=False, closed=False, **opts):
1404 def branches(ui, repo, active=False, closed=False, **opts):
1398 """list repository named branches
1405 """list repository named branches
1399
1406
1400 List the repository's named branches, indicating which ones are
1407 List the repository's named branches, indicating which ones are
1401 inactive. If -c/--closed is specified, also list branches which have
1408 inactive. If -c/--closed is specified, also list branches which have
1402 been marked closed (see :hg:`commit --close-branch`).
1409 been marked closed (see :hg:`commit --close-branch`).
1403
1410
1404 Use the command :hg:`update` to switch to an existing branch.
1411 Use the command :hg:`update` to switch to an existing branch.
1405
1412
1406 .. container:: verbose
1413 .. container:: verbose
1407
1414
1408 Template:
1415 Template:
1409
1416
1410 The following keywords are supported in addition to the common template
1417 The following keywords are supported in addition to the common template
1411 keywords and functions such as ``{branch}``. See also
1418 keywords and functions such as ``{branch}``. See also
1412 :hg:`help templates`.
1419 :hg:`help templates`.
1413
1420
1414 :active: Boolean. True if the branch is active.
1421 :active: Boolean. True if the branch is active.
1415 :closed: Boolean. True if the branch is closed.
1422 :closed: Boolean. True if the branch is closed.
1416 :current: Boolean. True if it is the current branch.
1423 :current: Boolean. True if it is the current branch.
1417
1424
1418 Returns 0.
1425 Returns 0.
1419 """
1426 """
1420
1427
1421 opts = pycompat.byteskwargs(opts)
1428 opts = pycompat.byteskwargs(opts)
1422 revs = opts.get(b'rev')
1429 revs = opts.get(b'rev')
1423 selectedbranches = None
1430 selectedbranches = None
1424 if revs:
1431 if revs:
1425 revs = logcmdutil.revrange(repo, revs)
1432 revs = logcmdutil.revrange(repo, revs)
1426 getbi = repo.revbranchcache().branchinfo
1433 getbi = repo.revbranchcache().branchinfo
1427 selectedbranches = {getbi(r)[0] for r in revs}
1434 selectedbranches = {getbi(r)[0] for r in revs}
1428
1435
1429 ui.pager(b'branches')
1436 ui.pager(b'branches')
1430 fm = ui.formatter(b'branches', opts)
1437 fm = ui.formatter(b'branches', opts)
1431 hexfunc = fm.hexfunc
1438 hexfunc = fm.hexfunc
1432
1439
1433 allheads = set(repo.heads())
1440 allheads = set(repo.heads())
1434 branches = []
1441 branches = []
1435 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1442 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1436 if selectedbranches is not None and tag not in selectedbranches:
1443 if selectedbranches is not None and tag not in selectedbranches:
1437 continue
1444 continue
1438 isactive = False
1445 isactive = False
1439 if not isclosed:
1446 if not isclosed:
1440 openheads = set(repo.branchmap().iteropen(heads))
1447 openheads = set(repo.branchmap().iteropen(heads))
1441 isactive = bool(openheads & allheads)
1448 isactive = bool(openheads & allheads)
1442 branches.append((tag, repo[tip], isactive, not isclosed))
1449 branches.append((tag, repo[tip], isactive, not isclosed))
1443 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1450 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1444
1451
1445 for tag, ctx, isactive, isopen in branches:
1452 for tag, ctx, isactive, isopen in branches:
1446 if active and not isactive:
1453 if active and not isactive:
1447 continue
1454 continue
1448 if isactive:
1455 if isactive:
1449 label = b'branches.active'
1456 label = b'branches.active'
1450 notice = b''
1457 notice = b''
1451 elif not isopen:
1458 elif not isopen:
1452 if not closed:
1459 if not closed:
1453 continue
1460 continue
1454 label = b'branches.closed'
1461 label = b'branches.closed'
1455 notice = _(b' (closed)')
1462 notice = _(b' (closed)')
1456 else:
1463 else:
1457 label = b'branches.inactive'
1464 label = b'branches.inactive'
1458 notice = _(b' (inactive)')
1465 notice = _(b' (inactive)')
1459 current = tag == repo.dirstate.branch()
1466 current = tag == repo.dirstate.branch()
1460 if current:
1467 if current:
1461 label = b'branches.current'
1468 label = b'branches.current'
1462
1469
1463 fm.startitem()
1470 fm.startitem()
1464 fm.write(b'branch', b'%s', tag, label=label)
1471 fm.write(b'branch', b'%s', tag, label=label)
1465 rev = ctx.rev()
1472 rev = ctx.rev()
1466 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1473 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1467 fmt = b' ' * padsize + b' %d:%s'
1474 fmt = b' ' * padsize + b' %d:%s'
1468 fm.condwrite(
1475 fm.condwrite(
1469 not ui.quiet,
1476 not ui.quiet,
1470 b'rev node',
1477 b'rev node',
1471 fmt,
1478 fmt,
1472 rev,
1479 rev,
1473 hexfunc(ctx.node()),
1480 hexfunc(ctx.node()),
1474 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1481 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1475 )
1482 )
1476 fm.context(ctx=ctx)
1483 fm.context(ctx=ctx)
1477 fm.data(active=isactive, closed=not isopen, current=current)
1484 fm.data(active=isactive, closed=not isopen, current=current)
1478 if not ui.quiet:
1485 if not ui.quiet:
1479 fm.plain(notice)
1486 fm.plain(notice)
1480 fm.plain(b'\n')
1487 fm.plain(b'\n')
1481 fm.end()
1488 fm.end()
1482
1489
1483
1490
1484 @command(
1491 @command(
1485 b'bundle',
1492 b'bundle',
1486 [
1493 [
1487 (
1494 (
1488 b'',
1495 b'',
1489 b'exact',
1496 b'exact',
1490 None,
1497 None,
1491 _(b'compute the base from the revision specified'),
1498 _(b'compute the base from the revision specified'),
1492 ),
1499 ),
1493 (
1500 (
1494 b'f',
1501 b'f',
1495 b'force',
1502 b'force',
1496 None,
1503 None,
1497 _(b'run even when the destination is unrelated'),
1504 _(b'run even when the destination is unrelated'),
1498 ),
1505 ),
1499 (
1506 (
1500 b'r',
1507 b'r',
1501 b'rev',
1508 b'rev',
1502 [],
1509 [],
1503 _(b'a changeset intended to be added to the destination'),
1510 _(b'a changeset intended to be added to the destination'),
1504 _(b'REV'),
1511 _(b'REV'),
1505 ),
1512 ),
1506 (
1513 (
1507 b'b',
1514 b'b',
1508 b'branch',
1515 b'branch',
1509 [],
1516 [],
1510 _(b'a specific branch you would like to bundle'),
1517 _(b'a specific branch you would like to bundle'),
1511 _(b'BRANCH'),
1518 _(b'BRANCH'),
1512 ),
1519 ),
1513 (
1520 (
1514 b'',
1521 b'',
1515 b'base',
1522 b'base',
1516 [],
1523 [],
1517 _(b'a base changeset assumed to be available at the destination'),
1524 _(b'a base changeset assumed to be available at the destination'),
1518 _(b'REV'),
1525 _(b'REV'),
1519 ),
1526 ),
1520 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1527 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1521 (
1528 (
1522 b't',
1529 b't',
1523 b'type',
1530 b'type',
1524 b'bzip2',
1531 b'bzip2',
1525 _(b'bundle compression type to use'),
1532 _(b'bundle compression type to use'),
1526 _(b'TYPE'),
1533 _(b'TYPE'),
1527 ),
1534 ),
1528 ]
1535 ]
1529 + remoteopts,
1536 + remoteopts,
1530 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1537 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1531 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1538 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1532 )
1539 )
1533 def bundle(ui, repo, fname, *dests, **opts):
1540 def bundle(ui, repo, fname, *dests, **opts):
1534 """create a bundle file
1541 """create a bundle file
1535
1542
1536 Generate a bundle file containing data to be transferred to another
1543 Generate a bundle file containing data to be transferred to another
1537 repository.
1544 repository.
1538
1545
1539 To create a bundle containing all changesets, use -a/--all
1546 To create a bundle containing all changesets, use -a/--all
1540 (or --base null). Otherwise, hg assumes the destination will have
1547 (or --base null). Otherwise, hg assumes the destination will have
1541 all the nodes you specify with --base parameters. Otherwise, hg
1548 all the nodes you specify with --base parameters. Otherwise, hg
1542 will assume the repository has all the nodes in destination, or
1549 will assume the repository has all the nodes in destination, or
1543 default-push/default if no destination is specified, where destination
1550 default-push/default if no destination is specified, where destination
1544 is the repositories you provide through DEST option.
1551 is the repositories you provide through DEST option.
1545
1552
1546 You can change bundle format with the -t/--type option. See
1553 You can change bundle format with the -t/--type option. See
1547 :hg:`help bundlespec` for documentation on this format. By default,
1554 :hg:`help bundlespec` for documentation on this format. By default,
1548 the most appropriate format is used and compression defaults to
1555 the most appropriate format is used and compression defaults to
1549 bzip2.
1556 bzip2.
1550
1557
1551 The bundle file can then be transferred using conventional means
1558 The bundle file can then be transferred using conventional means
1552 and applied to another repository with the unbundle or pull
1559 and applied to another repository with the unbundle or pull
1553 command. This is useful when direct push and pull are not
1560 command. This is useful when direct push and pull are not
1554 available or when exporting an entire repository is undesirable.
1561 available or when exporting an entire repository is undesirable.
1555
1562
1556 Applying bundles preserves all changeset contents including
1563 Applying bundles preserves all changeset contents including
1557 permissions, copy/rename information, and revision history.
1564 permissions, copy/rename information, and revision history.
1558
1565
1559 Returns 0 on success, 1 if no changes found.
1566 Returns 0 on success, 1 if no changes found.
1560 """
1567 """
1561 opts = pycompat.byteskwargs(opts)
1568 opts = pycompat.byteskwargs(opts)
1562
1569
1563 revs = None
1570 revs = None
1564 if b'rev' in opts:
1571 if b'rev' in opts:
1565 revstrings = opts[b'rev']
1572 revstrings = opts[b'rev']
1566 revs = logcmdutil.revrange(repo, revstrings)
1573 revs = logcmdutil.revrange(repo, revstrings)
1567 if revstrings and not revs:
1574 if revstrings and not revs:
1568 raise error.InputError(_(b'no commits to bundle'))
1575 raise error.InputError(_(b'no commits to bundle'))
1569
1576
1570 bundletype = opts.get(b'type', b'bzip2').lower()
1577 bundletype = opts.get(b'type', b'bzip2').lower()
1571 try:
1578 try:
1572 bundlespec = bundlecaches.parsebundlespec(
1579 bundlespec = bundlecaches.parsebundlespec(
1573 repo, bundletype, strict=False
1580 repo, bundletype, strict=False
1574 )
1581 )
1575 except error.UnsupportedBundleSpecification as e:
1582 except error.UnsupportedBundleSpecification as e:
1576 raise error.InputError(
1583 raise error.InputError(
1577 pycompat.bytestr(e),
1584 pycompat.bytestr(e),
1578 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1585 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1579 )
1586 )
1580 cgversion = bundlespec.params[b"cg.version"]
1587 cgversion = bundlespec.params[b"cg.version"]
1581
1588
1582 # Packed bundles are a pseudo bundle format for now.
1589 # Packed bundles are a pseudo bundle format for now.
1583 if cgversion == b's1':
1590 if cgversion == b's1':
1584 raise error.InputError(
1591 raise error.InputError(
1585 _(b'packed bundles cannot be produced by "hg bundle"'),
1592 _(b'packed bundles cannot be produced by "hg bundle"'),
1586 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1593 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1587 )
1594 )
1588
1595
1589 if opts.get(b'all'):
1596 if opts.get(b'all'):
1590 if dests:
1597 if dests:
1591 raise error.InputError(
1598 raise error.InputError(
1592 _(b"--all is incompatible with specifying destinations")
1599 _(b"--all is incompatible with specifying destinations")
1593 )
1600 )
1594 if opts.get(b'base'):
1601 if opts.get(b'base'):
1595 ui.warn(_(b"ignoring --base because --all was specified\n"))
1602 ui.warn(_(b"ignoring --base because --all was specified\n"))
1596 if opts.get(b'exact'):
1603 if opts.get(b'exact'):
1597 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1604 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1598 base = [nullrev]
1605 base = [nullrev]
1599 elif opts.get(b'exact'):
1606 elif opts.get(b'exact'):
1600 if dests:
1607 if dests:
1601 raise error.InputError(
1608 raise error.InputError(
1602 _(b"--exact is incompatible with specifying destinations")
1609 _(b"--exact is incompatible with specifying destinations")
1603 )
1610 )
1604 if opts.get(b'base'):
1611 if opts.get(b'base'):
1605 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1612 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1606 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1613 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1607 if not base:
1614 if not base:
1608 base = [nullrev]
1615 base = [nullrev]
1609 else:
1616 else:
1610 base = logcmdutil.revrange(repo, opts.get(b'base'))
1617 base = logcmdutil.revrange(repo, opts.get(b'base'))
1611 if cgversion not in changegroup.supportedoutgoingversions(repo):
1618 if cgversion not in changegroup.supportedoutgoingversions(repo):
1612 raise error.Abort(
1619 raise error.Abort(
1613 _(b"repository does not support bundle version %s") % cgversion
1620 _(b"repository does not support bundle version %s") % cgversion
1614 )
1621 )
1615
1622
1616 if base:
1623 if base:
1617 if dests:
1624 if dests:
1618 raise error.InputError(
1625 raise error.InputError(
1619 _(b"--base is incompatible with specifying destinations")
1626 _(b"--base is incompatible with specifying destinations")
1620 )
1627 )
1621 cl = repo.changelog
1628 cl = repo.changelog
1622 common = [cl.node(rev) for rev in base]
1629 common = [cl.node(rev) for rev in base]
1623 heads = [cl.node(r) for r in revs] if revs else None
1630 heads = [cl.node(r) for r in revs] if revs else None
1624 outgoing = discovery.outgoing(repo, common, heads)
1631 outgoing = discovery.outgoing(repo, common, heads)
1625 missing = outgoing.missing
1632 missing = outgoing.missing
1626 excluded = outgoing.excluded
1633 excluded = outgoing.excluded
1627 else:
1634 else:
1628 missing = set()
1635 missing = set()
1629 excluded = set()
1636 excluded = set()
1630 for path in urlutil.get_push_paths(repo, ui, dests):
1637 for path in urlutil.get_push_paths(repo, ui, dests):
1631 other = hg.peer(repo, opts, path.rawloc)
1638 other = hg.peer(repo, opts, path.rawloc)
1632 if revs is not None:
1639 if revs is not None:
1633 hex_revs = [repo[r].hex() for r in revs]
1640 hex_revs = [repo[r].hex() for r in revs]
1634 else:
1641 else:
1635 hex_revs = None
1642 hex_revs = None
1636 branches = (path.branch, [])
1643 branches = (path.branch, [])
1637 head_revs, checkout = hg.addbranchrevs(
1644 head_revs, checkout = hg.addbranchrevs(
1638 repo, repo, branches, hex_revs
1645 repo, repo, branches, hex_revs
1639 )
1646 )
1640 heads = (
1647 heads = (
1641 head_revs
1648 head_revs
1642 and pycompat.maplist(repo.lookup, head_revs)
1649 and pycompat.maplist(repo.lookup, head_revs)
1643 or head_revs
1650 or head_revs
1644 )
1651 )
1645 outgoing = discovery.findcommonoutgoing(
1652 outgoing = discovery.findcommonoutgoing(
1646 repo,
1653 repo,
1647 other,
1654 other,
1648 onlyheads=heads,
1655 onlyheads=heads,
1649 force=opts.get(b'force'),
1656 force=opts.get(b'force'),
1650 portable=True,
1657 portable=True,
1651 )
1658 )
1652 missing.update(outgoing.missing)
1659 missing.update(outgoing.missing)
1653 excluded.update(outgoing.excluded)
1660 excluded.update(outgoing.excluded)
1654
1661
1655 if not missing:
1662 if not missing:
1656 scmutil.nochangesfound(ui, repo, not base and excluded)
1663 scmutil.nochangesfound(ui, repo, not base and excluded)
1657 return 1
1664 return 1
1658
1665
1659 if heads:
1666 if heads:
1660 outgoing = discovery.outgoing(
1667 outgoing = discovery.outgoing(
1661 repo, missingroots=missing, ancestorsof=heads
1668 repo, missingroots=missing, ancestorsof=heads
1662 )
1669 )
1663 else:
1670 else:
1664 outgoing = discovery.outgoing(repo, missingroots=missing)
1671 outgoing = discovery.outgoing(repo, missingroots=missing)
1665 outgoing.excluded = sorted(excluded)
1672 outgoing.excluded = sorted(excluded)
1666
1673
1667 if cgversion == b'01': # bundle1
1674 if cgversion == b'01': # bundle1
1668 bversion = b'HG10' + bundlespec.wirecompression
1675 bversion = b'HG10' + bundlespec.wirecompression
1669 bcompression = None
1676 bcompression = None
1670 elif cgversion in (b'02', b'03'):
1677 elif cgversion in (b'02', b'03'):
1671 bversion = b'HG20'
1678 bversion = b'HG20'
1672 bcompression = bundlespec.wirecompression
1679 bcompression = bundlespec.wirecompression
1673 else:
1680 else:
1674 raise error.ProgrammingError(
1681 raise error.ProgrammingError(
1675 b'bundle: unexpected changegroup version %s' % cgversion
1682 b'bundle: unexpected changegroup version %s' % cgversion
1676 )
1683 )
1677
1684
1678 # TODO compression options should be derived from bundlespec parsing.
1685 # TODO compression options should be derived from bundlespec parsing.
1679 # This is a temporary hack to allow adjusting bundle compression
1686 # This is a temporary hack to allow adjusting bundle compression
1680 # level without a) formalizing the bundlespec changes to declare it
1687 # level without a) formalizing the bundlespec changes to declare it
1681 # b) introducing a command flag.
1688 # b) introducing a command flag.
1682 compopts = {}
1689 compopts = {}
1683 complevel = ui.configint(
1690 complevel = ui.configint(
1684 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1691 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1685 )
1692 )
1686 if complevel is None:
1693 if complevel is None:
1687 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1694 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1688 if complevel is not None:
1695 if complevel is not None:
1689 compopts[b'level'] = complevel
1696 compopts[b'level'] = complevel
1690
1697
1691 compthreads = ui.configint(
1698 compthreads = ui.configint(
1692 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1699 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1693 )
1700 )
1694 if compthreads is None:
1701 if compthreads is None:
1695 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1702 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1696 if compthreads is not None:
1703 if compthreads is not None:
1697 compopts[b'threads'] = compthreads
1704 compopts[b'threads'] = compthreads
1698
1705
1699 # Bundling of obsmarker and phases is optional as not all clients
1706 # Bundling of obsmarker and phases is optional as not all clients
1700 # support the necessary features.
1707 # support the necessary features.
1701 cfg = ui.configbool
1708 cfg = ui.configbool
1702 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1709 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1703 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1710 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1704 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1711 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1705 bundlespec.set_param(
1712 bundlespec.set_param(
1706 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1713 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1707 )
1714 )
1708 phases_cfg = cfg(b'experimental', b'bundle-phases')
1715 phases_cfg = cfg(b'experimental', b'bundle-phases')
1709 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1716 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1710
1717
1711 bundle2.writenewbundle(
1718 bundle2.writenewbundle(
1712 ui,
1719 ui,
1713 repo,
1720 repo,
1714 b'bundle',
1721 b'bundle',
1715 fname,
1722 fname,
1716 bversion,
1723 bversion,
1717 outgoing,
1724 outgoing,
1718 bundlespec.params,
1725 bundlespec.params,
1719 compression=bcompression,
1726 compression=bcompression,
1720 compopts=compopts,
1727 compopts=compopts,
1721 )
1728 )
1722
1729
1723
1730
1724 @command(
1731 @command(
1725 b'cat',
1732 b'cat',
1726 [
1733 [
1727 (
1734 (
1728 b'o',
1735 b'o',
1729 b'output',
1736 b'output',
1730 b'',
1737 b'',
1731 _(b'print output to file with formatted name'),
1738 _(b'print output to file with formatted name'),
1732 _(b'FORMAT'),
1739 _(b'FORMAT'),
1733 ),
1740 ),
1734 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1741 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1735 (b'', b'decode', None, _(b'apply any matching decode filter')),
1742 (b'', b'decode', None, _(b'apply any matching decode filter')),
1736 ]
1743 ]
1737 + walkopts
1744 + walkopts
1738 + formatteropts,
1745 + formatteropts,
1739 _(b'[OPTION]... FILE...'),
1746 _(b'[OPTION]... FILE...'),
1740 helpcategory=command.CATEGORY_FILE_CONTENTS,
1747 helpcategory=command.CATEGORY_FILE_CONTENTS,
1741 inferrepo=True,
1748 inferrepo=True,
1742 intents={INTENT_READONLY},
1749 intents={INTENT_READONLY},
1743 )
1750 )
1744 def cat(ui, repo, file1, *pats, **opts):
1751 def cat(ui, repo, file1, *pats, **opts):
1745 """output the current or given revision of files
1752 """output the current or given revision of files
1746
1753
1747 Print the specified files as they were at the given revision. If
1754 Print the specified files as they were at the given revision. If
1748 no revision is given, the parent of the working directory is used.
1755 no revision is given, the parent of the working directory is used.
1749
1756
1750 Output may be to a file, in which case the name of the file is
1757 Output may be to a file, in which case the name of the file is
1751 given using a template string. See :hg:`help templates`. In addition
1758 given using a template string. See :hg:`help templates`. In addition
1752 to the common template keywords, the following formatting rules are
1759 to the common template keywords, the following formatting rules are
1753 supported:
1760 supported:
1754
1761
1755 :``%%``: literal "%" character
1762 :``%%``: literal "%" character
1756 :``%s``: basename of file being printed
1763 :``%s``: basename of file being printed
1757 :``%d``: dirname of file being printed, or '.' if in repository root
1764 :``%d``: dirname of file being printed, or '.' if in repository root
1758 :``%p``: root-relative path name of file being printed
1765 :``%p``: root-relative path name of file being printed
1759 :``%H``: changeset hash (40 hexadecimal digits)
1766 :``%H``: changeset hash (40 hexadecimal digits)
1760 :``%R``: changeset revision number
1767 :``%R``: changeset revision number
1761 :``%h``: short-form changeset hash (12 hexadecimal digits)
1768 :``%h``: short-form changeset hash (12 hexadecimal digits)
1762 :``%r``: zero-padded changeset revision number
1769 :``%r``: zero-padded changeset revision number
1763 :``%b``: basename of the exporting repository
1770 :``%b``: basename of the exporting repository
1764 :``\\``: literal "\\" character
1771 :``\\``: literal "\\" character
1765
1772
1766 .. container:: verbose
1773 .. container:: verbose
1767
1774
1768 Template:
1775 Template:
1769
1776
1770 The following keywords are supported in addition to the common template
1777 The following keywords are supported in addition to the common template
1771 keywords and functions. See also :hg:`help templates`.
1778 keywords and functions. See also :hg:`help templates`.
1772
1779
1773 :data: String. File content.
1780 :data: String. File content.
1774 :path: String. Repository-absolute path of the file.
1781 :path: String. Repository-absolute path of the file.
1775
1782
1776 Returns 0 on success.
1783 Returns 0 on success.
1777 """
1784 """
1778 opts = pycompat.byteskwargs(opts)
1785 opts = pycompat.byteskwargs(opts)
1779 rev = opts.get(b'rev')
1786 rev = opts.get(b'rev')
1780 if rev:
1787 if rev:
1781 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1788 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1782 ctx = logcmdutil.revsingle(repo, rev)
1789 ctx = logcmdutil.revsingle(repo, rev)
1783 m = scmutil.match(ctx, (file1,) + pats, opts)
1790 m = scmutil.match(ctx, (file1,) + pats, opts)
1784 fntemplate = opts.pop(b'output', b'')
1791 fntemplate = opts.pop(b'output', b'')
1785 if cmdutil.isstdiofilename(fntemplate):
1792 if cmdutil.isstdiofilename(fntemplate):
1786 fntemplate = b''
1793 fntemplate = b''
1787
1794
1788 if fntemplate:
1795 if fntemplate:
1789 fm = formatter.nullformatter(ui, b'cat', opts)
1796 fm = formatter.nullformatter(ui, b'cat', opts)
1790 else:
1797 else:
1791 ui.pager(b'cat')
1798 ui.pager(b'cat')
1792 fm = ui.formatter(b'cat', opts)
1799 fm = ui.formatter(b'cat', opts)
1793 with fm:
1800 with fm:
1794 return cmdutil.cat(
1801 return cmdutil.cat(
1795 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1802 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1796 )
1803 )
1797
1804
1798
1805
1799 @command(
1806 @command(
1800 b'clone',
1807 b'clone',
1801 [
1808 [
1802 (
1809 (
1803 b'U',
1810 b'U',
1804 b'noupdate',
1811 b'noupdate',
1805 None,
1812 None,
1806 _(
1813 _(
1807 b'the clone will include an empty working '
1814 b'the clone will include an empty working '
1808 b'directory (only a repository)'
1815 b'directory (only a repository)'
1809 ),
1816 ),
1810 ),
1817 ),
1811 (
1818 (
1812 b'u',
1819 b'u',
1813 b'updaterev',
1820 b'updaterev',
1814 b'',
1821 b'',
1815 _(b'revision, tag, or branch to check out'),
1822 _(b'revision, tag, or branch to check out'),
1816 _(b'REV'),
1823 _(b'REV'),
1817 ),
1824 ),
1818 (
1825 (
1819 b'r',
1826 b'r',
1820 b'rev',
1827 b'rev',
1821 [],
1828 [],
1822 _(
1829 _(
1823 b'do not clone everything, but include this changeset'
1830 b'do not clone everything, but include this changeset'
1824 b' and its ancestors'
1831 b' and its ancestors'
1825 ),
1832 ),
1826 _(b'REV'),
1833 _(b'REV'),
1827 ),
1834 ),
1828 (
1835 (
1829 b'b',
1836 b'b',
1830 b'branch',
1837 b'branch',
1831 [],
1838 [],
1832 _(
1839 _(
1833 b'do not clone everything, but include this branch\'s'
1840 b'do not clone everything, but include this branch\'s'
1834 b' changesets and their ancestors'
1841 b' changesets and their ancestors'
1835 ),
1842 ),
1836 _(b'BRANCH'),
1843 _(b'BRANCH'),
1837 ),
1844 ),
1838 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1845 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1839 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1846 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1840 (b'', b'stream', None, _(b'clone with minimal data processing')),
1847 (b'', b'stream', None, _(b'clone with minimal data processing')),
1841 ]
1848 ]
1842 + remoteopts,
1849 + remoteopts,
1843 _(b'[OPTION]... SOURCE [DEST]'),
1850 _(b'[OPTION]... SOURCE [DEST]'),
1844 helpcategory=command.CATEGORY_REPO_CREATION,
1851 helpcategory=command.CATEGORY_REPO_CREATION,
1845 helpbasic=True,
1852 helpbasic=True,
1846 norepo=True,
1853 norepo=True,
1847 )
1854 )
1848 def clone(ui, source, dest=None, **opts):
1855 def clone(ui, source, dest=None, **opts):
1849 """make a copy of an existing repository
1856 """make a copy of an existing repository
1850
1857
1851 Create a copy of an existing repository in a new directory.
1858 Create a copy of an existing repository in a new directory.
1852
1859
1853 If no destination directory name is specified, it defaults to the
1860 If no destination directory name is specified, it defaults to the
1854 basename of the source.
1861 basename of the source.
1855
1862
1856 The location of the source is added to the new repository's
1863 The location of the source is added to the new repository's
1857 ``.hg/hgrc`` file, as the default to be used for future pulls.
1864 ``.hg/hgrc`` file, as the default to be used for future pulls.
1858
1865
1859 Only local paths and ``ssh://`` URLs are supported as
1866 Only local paths and ``ssh://`` URLs are supported as
1860 destinations. For ``ssh://`` destinations, no working directory or
1867 destinations. For ``ssh://`` destinations, no working directory or
1861 ``.hg/hgrc`` will be created on the remote side.
1868 ``.hg/hgrc`` will be created on the remote side.
1862
1869
1863 If the source repository has a bookmark called '@' set, that
1870 If the source repository has a bookmark called '@' set, that
1864 revision will be checked out in the new repository by default.
1871 revision will be checked out in the new repository by default.
1865
1872
1866 To check out a particular version, use -u/--update, or
1873 To check out a particular version, use -u/--update, or
1867 -U/--noupdate to create a clone with no working directory.
1874 -U/--noupdate to create a clone with no working directory.
1868
1875
1869 To pull only a subset of changesets, specify one or more revisions
1876 To pull only a subset of changesets, specify one or more revisions
1870 identifiers with -r/--rev or branches with -b/--branch. The
1877 identifiers with -r/--rev or branches with -b/--branch. The
1871 resulting clone will contain only the specified changesets and
1878 resulting clone will contain only the specified changesets and
1872 their ancestors. These options (or 'clone src#rev dest') imply
1879 their ancestors. These options (or 'clone src#rev dest') imply
1873 --pull, even for local source repositories.
1880 --pull, even for local source repositories.
1874
1881
1875 In normal clone mode, the remote normalizes repository data into a common
1882 In normal clone mode, the remote normalizes repository data into a common
1876 exchange format and the receiving end translates this data into its local
1883 exchange format and the receiving end translates this data into its local
1877 storage format. --stream activates a different clone mode that essentially
1884 storage format. --stream activates a different clone mode that essentially
1878 copies repository files from the remote with minimal data processing. This
1885 copies repository files from the remote with minimal data processing. This
1879 significantly reduces the CPU cost of a clone both remotely and locally.
1886 significantly reduces the CPU cost of a clone both remotely and locally.
1880 However, it often increases the transferred data size by 30-40%. This can
1887 However, it often increases the transferred data size by 30-40%. This can
1881 result in substantially faster clones where I/O throughput is plentiful,
1888 result in substantially faster clones where I/O throughput is plentiful,
1882 especially for larger repositories. A side-effect of --stream clones is
1889 especially for larger repositories. A side-effect of --stream clones is
1883 that storage settings and requirements on the remote are applied locally:
1890 that storage settings and requirements on the remote are applied locally:
1884 a modern client may inherit legacy or inefficient storage used by the
1891 a modern client may inherit legacy or inefficient storage used by the
1885 remote or a legacy Mercurial client may not be able to clone from a
1892 remote or a legacy Mercurial client may not be able to clone from a
1886 modern Mercurial remote.
1893 modern Mercurial remote.
1887
1894
1888 .. note::
1895 .. note::
1889
1896
1890 Specifying a tag will include the tagged changeset but not the
1897 Specifying a tag will include the tagged changeset but not the
1891 changeset containing the tag.
1898 changeset containing the tag.
1892
1899
1893 .. container:: verbose
1900 .. container:: verbose
1894
1901
1895 For efficiency, hardlinks are used for cloning whenever the
1902 For efficiency, hardlinks are used for cloning whenever the
1896 source and destination are on the same filesystem (note this
1903 source and destination are on the same filesystem (note this
1897 applies only to the repository data, not to the working
1904 applies only to the repository data, not to the working
1898 directory). Some filesystems, such as AFS, implement hardlinking
1905 directory). Some filesystems, such as AFS, implement hardlinking
1899 incorrectly, but do not report errors. In these cases, use the
1906 incorrectly, but do not report errors. In these cases, use the
1900 --pull option to avoid hardlinking.
1907 --pull option to avoid hardlinking.
1901
1908
1902 Mercurial will update the working directory to the first applicable
1909 Mercurial will update the working directory to the first applicable
1903 revision from this list:
1910 revision from this list:
1904
1911
1905 a) null if -U or the source repository has no changesets
1912 a) null if -U or the source repository has no changesets
1906 b) if -u . and the source repository is local, the first parent of
1913 b) if -u . and the source repository is local, the first parent of
1907 the source repository's working directory
1914 the source repository's working directory
1908 c) the changeset specified with -u (if a branch name, this means the
1915 c) the changeset specified with -u (if a branch name, this means the
1909 latest head of that branch)
1916 latest head of that branch)
1910 d) the changeset specified with -r
1917 d) the changeset specified with -r
1911 e) the tipmost head specified with -b
1918 e) the tipmost head specified with -b
1912 f) the tipmost head specified with the url#branch source syntax
1919 f) the tipmost head specified with the url#branch source syntax
1913 g) the revision marked with the '@' bookmark, if present
1920 g) the revision marked with the '@' bookmark, if present
1914 h) the tipmost head of the default branch
1921 h) the tipmost head of the default branch
1915 i) tip
1922 i) tip
1916
1923
1917 When cloning from servers that support it, Mercurial may fetch
1924 When cloning from servers that support it, Mercurial may fetch
1918 pre-generated data from a server-advertised URL or inline from the
1925 pre-generated data from a server-advertised URL or inline from the
1919 same stream. When this is done, hooks operating on incoming changesets
1926 same stream. When this is done, hooks operating on incoming changesets
1920 and changegroups may fire more than once, once for each pre-generated
1927 and changegroups may fire more than once, once for each pre-generated
1921 bundle and as well as for any additional remaining data. In addition,
1928 bundle and as well as for any additional remaining data. In addition,
1922 if an error occurs, the repository may be rolled back to a partial
1929 if an error occurs, the repository may be rolled back to a partial
1923 clone. This behavior may change in future releases.
1930 clone. This behavior may change in future releases.
1924 See :hg:`help -e clonebundles` for more.
1931 See :hg:`help -e clonebundles` for more.
1925
1932
1926 Examples:
1933 Examples:
1927
1934
1928 - clone a remote repository to a new directory named hg/::
1935 - clone a remote repository to a new directory named hg/::
1929
1936
1930 hg clone https://www.mercurial-scm.org/repo/hg/
1937 hg clone https://www.mercurial-scm.org/repo/hg/
1931
1938
1932 - create a lightweight local clone::
1939 - create a lightweight local clone::
1933
1940
1934 hg clone project/ project-feature/
1941 hg clone project/ project-feature/
1935
1942
1936 - clone from an absolute path on an ssh server (note double-slash)::
1943 - clone from an absolute path on an ssh server (note double-slash)::
1937
1944
1938 hg clone ssh://user@server//home/projects/alpha/
1945 hg clone ssh://user@server//home/projects/alpha/
1939
1946
1940 - do a streaming clone while checking out a specified version::
1947 - do a streaming clone while checking out a specified version::
1941
1948
1942 hg clone --stream http://server/repo -u 1.5
1949 hg clone --stream http://server/repo -u 1.5
1943
1950
1944 - create a repository without changesets after a particular revision::
1951 - create a repository without changesets after a particular revision::
1945
1952
1946 hg clone -r 04e544 experimental/ good/
1953 hg clone -r 04e544 experimental/ good/
1947
1954
1948 - clone (and track) a particular named branch::
1955 - clone (and track) a particular named branch::
1949
1956
1950 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1957 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1951
1958
1952 See :hg:`help urls` for details on specifying URLs.
1959 See :hg:`help urls` for details on specifying URLs.
1953
1960
1954 Returns 0 on success.
1961 Returns 0 on success.
1955 """
1962 """
1956 opts = pycompat.byteskwargs(opts)
1963 opts = pycompat.byteskwargs(opts)
1957 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1964 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1958
1965
1959 # --include/--exclude can come from narrow or sparse.
1966 # --include/--exclude can come from narrow or sparse.
1960 includepats, excludepats = None, None
1967 includepats, excludepats = None, None
1961
1968
1962 # hg.clone() differentiates between None and an empty set. So make sure
1969 # hg.clone() differentiates between None and an empty set. So make sure
1963 # patterns are sets if narrow is requested without patterns.
1970 # patterns are sets if narrow is requested without patterns.
1964 if opts.get(b'narrow'):
1971 if opts.get(b'narrow'):
1965 includepats = set()
1972 includepats = set()
1966 excludepats = set()
1973 excludepats = set()
1967
1974
1968 if opts.get(b'include'):
1975 if opts.get(b'include'):
1969 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1976 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1970 if opts.get(b'exclude'):
1977 if opts.get(b'exclude'):
1971 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1978 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1972
1979
1973 r = hg.clone(
1980 r = hg.clone(
1974 ui,
1981 ui,
1975 opts,
1982 opts,
1976 source,
1983 source,
1977 dest,
1984 dest,
1978 pull=opts.get(b'pull'),
1985 pull=opts.get(b'pull'),
1979 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1986 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1980 revs=opts.get(b'rev'),
1987 revs=opts.get(b'rev'),
1981 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1988 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1982 branch=opts.get(b'branch'),
1989 branch=opts.get(b'branch'),
1983 shareopts=opts.get(b'shareopts'),
1990 shareopts=opts.get(b'shareopts'),
1984 storeincludepats=includepats,
1991 storeincludepats=includepats,
1985 storeexcludepats=excludepats,
1992 storeexcludepats=excludepats,
1986 depth=opts.get(b'depth') or None,
1993 depth=opts.get(b'depth') or None,
1987 )
1994 )
1988
1995
1989 return r is None
1996 return r is None
1990
1997
1991
1998
1992 @command(
1999 @command(
1993 b'commit|ci',
2000 b'commit|ci',
1994 [
2001 [
1995 (
2002 (
1996 b'A',
2003 b'A',
1997 b'addremove',
2004 b'addremove',
1998 None,
2005 None,
1999 _(b'mark new/missing files as added/removed before committing'),
2006 _(b'mark new/missing files as added/removed before committing'),
2000 ),
2007 ),
2001 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2008 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2002 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2009 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2003 (b's', b'secret', None, _(b'use the secret phase for committing')),
2010 (b's', b'secret', None, _(b'use the secret phase for committing')),
2004 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2011 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2005 (
2012 (
2006 b'',
2013 b'',
2007 b'force-close-branch',
2014 b'force-close-branch',
2008 None,
2015 None,
2009 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2016 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2010 ),
2017 ),
2011 (b'i', b'interactive', None, _(b'use interactive mode')),
2018 (b'i', b'interactive', None, _(b'use interactive mode')),
2012 ]
2019 ]
2013 + walkopts
2020 + walkopts
2014 + commitopts
2021 + commitopts
2015 + commitopts2
2022 + commitopts2
2016 + subrepoopts,
2023 + subrepoopts,
2017 _(b'[OPTION]... [FILE]...'),
2024 _(b'[OPTION]... [FILE]...'),
2018 helpcategory=command.CATEGORY_COMMITTING,
2025 helpcategory=command.CATEGORY_COMMITTING,
2019 helpbasic=True,
2026 helpbasic=True,
2020 inferrepo=True,
2027 inferrepo=True,
2021 )
2028 )
2022 def commit(ui, repo, *pats, **opts):
2029 def commit(ui, repo, *pats, **opts):
2023 """commit the specified files or all outstanding changes
2030 """commit the specified files or all outstanding changes
2024
2031
2025 Commit changes to the given files into the repository. Unlike a
2032 Commit changes to the given files into the repository. Unlike a
2026 centralized SCM, this operation is a local operation. See
2033 centralized SCM, this operation is a local operation. See
2027 :hg:`push` for a way to actively distribute your changes.
2034 :hg:`push` for a way to actively distribute your changes.
2028
2035
2029 If a list of files is omitted, all changes reported by :hg:`status`
2036 If a list of files is omitted, all changes reported by :hg:`status`
2030 will be committed.
2037 will be committed.
2031
2038
2032 If you are committing the result of a merge, do not provide any
2039 If you are committing the result of a merge, do not provide any
2033 filenames or -I/-X filters.
2040 filenames or -I/-X filters.
2034
2041
2035 If no commit message is specified, Mercurial starts your
2042 If no commit message is specified, Mercurial starts your
2036 configured editor where you can enter a message. In case your
2043 configured editor where you can enter a message. In case your
2037 commit fails, you will find a backup of your message in
2044 commit fails, you will find a backup of your message in
2038 ``.hg/last-message.txt``.
2045 ``.hg/last-message.txt``.
2039
2046
2040 The --close-branch flag can be used to mark the current branch
2047 The --close-branch flag can be used to mark the current branch
2041 head closed. When all heads of a branch are closed, the branch
2048 head closed. When all heads of a branch are closed, the branch
2042 will be considered closed and no longer listed.
2049 will be considered closed and no longer listed.
2043
2050
2044 The --amend flag can be used to amend the parent of the
2051 The --amend flag can be used to amend the parent of the
2045 working directory with a new commit that contains the changes
2052 working directory with a new commit that contains the changes
2046 in the parent in addition to those currently reported by :hg:`status`,
2053 in the parent in addition to those currently reported by :hg:`status`,
2047 if there are any. The old commit is stored in a backup bundle in
2054 if there are any. The old commit is stored in a backup bundle in
2048 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2055 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2049 on how to restore it).
2056 on how to restore it).
2050
2057
2051 Message, user and date are taken from the amended commit unless
2058 Message, user and date are taken from the amended commit unless
2052 specified. When a message isn't specified on the command line,
2059 specified. When a message isn't specified on the command line,
2053 the editor will open with the message of the amended commit.
2060 the editor will open with the message of the amended commit.
2054
2061
2055 It is not possible to amend public changesets (see :hg:`help phases`)
2062 It is not possible to amend public changesets (see :hg:`help phases`)
2056 or changesets that have children.
2063 or changesets that have children.
2057
2064
2058 See :hg:`help dates` for a list of formats valid for -d/--date.
2065 See :hg:`help dates` for a list of formats valid for -d/--date.
2059
2066
2060 Returns 0 on success, 1 if nothing changed.
2067 Returns 0 on success, 1 if nothing changed.
2061
2068
2062 .. container:: verbose
2069 .. container:: verbose
2063
2070
2064 Examples:
2071 Examples:
2065
2072
2066 - commit all files ending in .py::
2073 - commit all files ending in .py::
2067
2074
2068 hg commit --include "set:**.py"
2075 hg commit --include "set:**.py"
2069
2076
2070 - commit all non-binary files::
2077 - commit all non-binary files::
2071
2078
2072 hg commit --exclude "set:binary()"
2079 hg commit --exclude "set:binary()"
2073
2080
2074 - amend the current commit and set the date to now::
2081 - amend the current commit and set the date to now::
2075
2082
2076 hg commit --amend --date now
2083 hg commit --amend --date now
2077 """
2084 """
2078 with repo.wlock(), repo.lock():
2085 with repo.wlock(), repo.lock():
2079 return _docommit(ui, repo, *pats, **opts)
2086 return _docommit(ui, repo, *pats, **opts)
2080
2087
2081
2088
2082 def _docommit(ui, repo, *pats, **opts):
2089 def _docommit(ui, repo, *pats, **opts):
2083 if opts.get('interactive'):
2090 if opts.get('interactive'):
2084 opts.pop('interactive')
2091 opts.pop('interactive')
2085 ret = cmdutil.dorecord(
2092 ret = cmdutil.dorecord(
2086 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2093 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2087 )
2094 )
2088 # ret can be 0 (no changes to record) or the value returned by
2095 # ret can be 0 (no changes to record) or the value returned by
2089 # commit(), 1 if nothing changed or None on success.
2096 # commit(), 1 if nothing changed or None on success.
2090 return 1 if ret == 0 else ret
2097 return 1 if ret == 0 else ret
2091
2098
2092 if opts.get('subrepos'):
2099 if opts.get('subrepos'):
2093 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2100 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2094 # Let --subrepos on the command line override config setting.
2101 # Let --subrepos on the command line override config setting.
2095 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2102 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2096
2103
2097 cmdutil.checkunfinished(repo, commit=True)
2104 cmdutil.checkunfinished(repo, commit=True)
2098
2105
2099 branch = repo[None].branch()
2106 branch = repo[None].branch()
2100 bheads = repo.branchheads(branch)
2107 bheads = repo.branchheads(branch)
2101 tip = repo.changelog.tip()
2108 tip = repo.changelog.tip()
2102
2109
2103 extra = {}
2110 extra = {}
2104 if opts.get('close_branch') or opts.get('force_close_branch'):
2111 if opts.get('close_branch') or opts.get('force_close_branch'):
2105 extra[b'close'] = b'1'
2112 extra[b'close'] = b'1'
2106
2113
2107 if repo[b'.'].closesbranch():
2114 if repo[b'.'].closesbranch():
2108 # Not ideal, but let us do an extra status early to prevent early
2115 # Not ideal, but let us do an extra status early to prevent early
2109 # bail out.
2116 # bail out.
2110 matcher = scmutil.match(repo[None], pats, opts)
2117 matcher = scmutil.match(repo[None], pats, opts)
2111 s = repo.status(match=matcher)
2118 s = repo.status(match=matcher)
2112 if s.modified or s.added or s.removed:
2119 if s.modified or s.added or s.removed:
2113 bheads = repo.branchheads(branch, closed=True)
2120 bheads = repo.branchheads(branch, closed=True)
2114 else:
2121 else:
2115 msg = _(b'current revision is already a branch closing head')
2122 msg = _(b'current revision is already a branch closing head')
2116 raise error.InputError(msg)
2123 raise error.InputError(msg)
2117
2124
2118 if not bheads:
2125 if not bheads:
2119 raise error.InputError(
2126 raise error.InputError(
2120 _(b'branch "%s" has no heads to close') % branch
2127 _(b'branch "%s" has no heads to close') % branch
2121 )
2128 )
2122 elif (
2129 elif (
2123 branch == repo[b'.'].branch()
2130 branch == repo[b'.'].branch()
2124 and repo[b'.'].node() not in bheads
2131 and repo[b'.'].node() not in bheads
2125 and not opts.get('force_close_branch')
2132 and not opts.get('force_close_branch')
2126 ):
2133 ):
2127 hint = _(
2134 hint = _(
2128 b'use --force-close-branch to close branch from a non-head'
2135 b'use --force-close-branch to close branch from a non-head'
2129 b' changeset'
2136 b' changeset'
2130 )
2137 )
2131 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2138 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2132 elif opts.get('amend'):
2139 elif opts.get('amend'):
2133 if (
2140 if (
2134 repo[b'.'].p1().branch() != branch
2141 repo[b'.'].p1().branch() != branch
2135 and repo[b'.'].p2().branch() != branch
2142 and repo[b'.'].p2().branch() != branch
2136 ):
2143 ):
2137 raise error.InputError(_(b'can only close branch heads'))
2144 raise error.InputError(_(b'can only close branch heads'))
2138
2145
2139 if opts.get('amend'):
2146 if opts.get('amend'):
2140 if ui.configbool(b'ui', b'commitsubrepos'):
2147 if ui.configbool(b'ui', b'commitsubrepos'):
2141 raise error.InputError(
2148 raise error.InputError(
2142 _(b'cannot amend with ui.commitsubrepos enabled')
2149 _(b'cannot amend with ui.commitsubrepos enabled')
2143 )
2150 )
2144
2151
2145 old = repo[b'.']
2152 old = repo[b'.']
2146 rewriteutil.precheck(repo, [old.rev()], b'amend')
2153 rewriteutil.precheck(repo, [old.rev()], b'amend')
2147
2154
2148 # Currently histedit gets confused if an amend happens while histedit
2155 # Currently histedit gets confused if an amend happens while histedit
2149 # is in progress. Since we have a checkunfinished command, we are
2156 # is in progress. Since we have a checkunfinished command, we are
2150 # temporarily honoring it.
2157 # temporarily honoring it.
2151 #
2158 #
2152 # Note: eventually this guard will be removed. Please do not expect
2159 # Note: eventually this guard will be removed. Please do not expect
2153 # this behavior to remain.
2160 # this behavior to remain.
2154 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2161 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2155 cmdutil.checkunfinished(repo)
2162 cmdutil.checkunfinished(repo)
2156
2163
2157 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2164 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2158 opts = pycompat.byteskwargs(opts)
2165 opts = pycompat.byteskwargs(opts)
2159 if node == old.node():
2166 if node == old.node():
2160 ui.status(_(b"nothing changed\n"))
2167 ui.status(_(b"nothing changed\n"))
2161 return 1
2168 return 1
2162 else:
2169 else:
2163
2170
2164 def commitfunc(ui, repo, message, match, opts):
2171 def commitfunc(ui, repo, message, match, opts):
2165 overrides = {}
2172 overrides = {}
2166 if opts.get(b'secret'):
2173 if opts.get(b'secret'):
2167 overrides[(b'phases', b'new-commit')] = b'secret'
2174 overrides[(b'phases', b'new-commit')] = b'secret'
2168
2175
2169 baseui = repo.baseui
2176 baseui = repo.baseui
2170 with baseui.configoverride(overrides, b'commit'):
2177 with baseui.configoverride(overrides, b'commit'):
2171 with ui.configoverride(overrides, b'commit'):
2178 with ui.configoverride(overrides, b'commit'):
2172 editform = cmdutil.mergeeditform(
2179 editform = cmdutil.mergeeditform(
2173 repo[None], b'commit.normal'
2180 repo[None], b'commit.normal'
2174 )
2181 )
2175 editor = cmdutil.getcommiteditor(
2182 editor = cmdutil.getcommiteditor(
2176 editform=editform, **pycompat.strkwargs(opts)
2183 editform=editform, **pycompat.strkwargs(opts)
2177 )
2184 )
2178 return repo.commit(
2185 return repo.commit(
2179 message,
2186 message,
2180 opts.get(b'user'),
2187 opts.get(b'user'),
2181 opts.get(b'date'),
2188 opts.get(b'date'),
2182 match,
2189 match,
2183 editor=editor,
2190 editor=editor,
2184 extra=extra,
2191 extra=extra,
2185 )
2192 )
2186
2193
2187 opts = pycompat.byteskwargs(opts)
2194 opts = pycompat.byteskwargs(opts)
2188 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2195 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2189
2196
2190 if not node:
2197 if not node:
2191 stat = cmdutil.postcommitstatus(repo, pats, opts)
2198 stat = cmdutil.postcommitstatus(repo, pats, opts)
2192 if stat.deleted:
2199 if stat.deleted:
2193 ui.status(
2200 ui.status(
2194 _(
2201 _(
2195 b"nothing changed (%d missing files, see "
2202 b"nothing changed (%d missing files, see "
2196 b"'hg status')\n"
2203 b"'hg status')\n"
2197 )
2204 )
2198 % len(stat.deleted)
2205 % len(stat.deleted)
2199 )
2206 )
2200 else:
2207 else:
2201 ui.status(_(b"nothing changed\n"))
2208 ui.status(_(b"nothing changed\n"))
2202 return 1
2209 return 1
2203
2210
2204 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2211 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2205
2212
2206 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2213 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2207 status(
2214 status(
2208 ui,
2215 ui,
2209 repo,
2216 repo,
2210 modified=True,
2217 modified=True,
2211 added=True,
2218 added=True,
2212 removed=True,
2219 removed=True,
2213 deleted=True,
2220 deleted=True,
2214 unknown=True,
2221 unknown=True,
2215 subrepos=opts.get(b'subrepos'),
2222 subrepos=opts.get(b'subrepos'),
2216 )
2223 )
2217
2224
2218
2225
2219 @command(
2226 @command(
2220 b'config|showconfig|debugconfig',
2227 b'config|showconfig|debugconfig',
2221 [
2228 [
2222 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2229 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2223 # This is experimental because we need
2230 # This is experimental because we need
2224 # * reasonable behavior around aliases,
2231 # * reasonable behavior around aliases,
2225 # * decide if we display [debug] [experimental] and [devel] section par
2232 # * decide if we display [debug] [experimental] and [devel] section par
2226 # default
2233 # default
2227 # * some way to display "generic" config entry (the one matching
2234 # * some way to display "generic" config entry (the one matching
2228 # regexp,
2235 # regexp,
2229 # * proper display of the different value type
2236 # * proper display of the different value type
2230 # * a better way to handle <DYNAMIC> values (and variable types),
2237 # * a better way to handle <DYNAMIC> values (and variable types),
2231 # * maybe some type information ?
2238 # * maybe some type information ?
2232 (
2239 (
2233 b'',
2240 b'',
2234 b'exp-all-known',
2241 b'exp-all-known',
2235 None,
2242 None,
2236 _(b'show all known config option (EXPERIMENTAL)'),
2243 _(b'show all known config option (EXPERIMENTAL)'),
2237 ),
2244 ),
2238 (b'e', b'edit', None, _(b'edit user config')),
2245 (b'e', b'edit', None, _(b'edit user config')),
2239 (b'l', b'local', None, _(b'edit repository config')),
2246 (b'l', b'local', None, _(b'edit repository config')),
2240 (b'', b'source', None, _(b'show source of configuration value')),
2247 (b'', b'source', None, _(b'show source of configuration value')),
2241 (
2248 (
2242 b'',
2249 b'',
2243 b'shared',
2250 b'shared',
2244 None,
2251 None,
2245 _(b'edit shared source repository config (EXPERIMENTAL)'),
2252 _(b'edit shared source repository config (EXPERIMENTAL)'),
2246 ),
2253 ),
2247 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2254 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2248 (b'g', b'global', None, _(b'edit global config')),
2255 (b'g', b'global', None, _(b'edit global config')),
2249 ]
2256 ]
2250 + formatteropts,
2257 + formatteropts,
2251 _(b'[-u] [NAME]...'),
2258 _(b'[-u] [NAME]...'),
2252 helpcategory=command.CATEGORY_HELP,
2259 helpcategory=command.CATEGORY_HELP,
2253 optionalrepo=True,
2260 optionalrepo=True,
2254 intents={INTENT_READONLY},
2261 intents={INTENT_READONLY},
2255 )
2262 )
2256 def config(ui, repo, *values, **opts):
2263 def config(ui, repo, *values, **opts):
2257 """show combined config settings from all hgrc files
2264 """show combined config settings from all hgrc files
2258
2265
2259 With no arguments, print names and values of all config items.
2266 With no arguments, print names and values of all config items.
2260
2267
2261 With one argument of the form section.name, print just the value
2268 With one argument of the form section.name, print just the value
2262 of that config item.
2269 of that config item.
2263
2270
2264 With multiple arguments, print names and values of all config
2271 With multiple arguments, print names and values of all config
2265 items with matching section names or section.names.
2272 items with matching section names or section.names.
2266
2273
2267 With --edit, start an editor on the user-level config file. With
2274 With --edit, start an editor on the user-level config file. With
2268 --global, edit the system-wide config file. With --local, edit the
2275 --global, edit the system-wide config file. With --local, edit the
2269 repository-level config file.
2276 repository-level config file.
2270
2277
2271 With --source, the source (filename and line number) is printed
2278 With --source, the source (filename and line number) is printed
2272 for each config item.
2279 for each config item.
2273
2280
2274 See :hg:`help config` for more information about config files.
2281 See :hg:`help config` for more information about config files.
2275
2282
2276 .. container:: verbose
2283 .. container:: verbose
2277
2284
2278 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2285 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2279 This file is not shared across shares when in share-safe mode.
2286 This file is not shared across shares when in share-safe mode.
2280
2287
2281 Template:
2288 Template:
2282
2289
2283 The following keywords are supported. See also :hg:`help templates`.
2290 The following keywords are supported. See also :hg:`help templates`.
2284
2291
2285 :name: String. Config name.
2292 :name: String. Config name.
2286 :source: String. Filename and line number where the item is defined.
2293 :source: String. Filename and line number where the item is defined.
2287 :value: String. Config value.
2294 :value: String. Config value.
2288
2295
2289 The --shared flag can be used to edit the config file of shared source
2296 The --shared flag can be used to edit the config file of shared source
2290 repository. It only works when you have shared using the experimental
2297 repository. It only works when you have shared using the experimental
2291 share safe feature.
2298 share safe feature.
2292
2299
2293 Returns 0 on success, 1 if NAME does not exist.
2300 Returns 0 on success, 1 if NAME does not exist.
2294
2301
2295 """
2302 """
2296
2303
2297 opts = pycompat.byteskwargs(opts)
2304 opts = pycompat.byteskwargs(opts)
2298 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2305 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2299 if any(opts.get(o) for o in editopts):
2306 if any(opts.get(o) for o in editopts):
2300 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2307 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2301 if opts.get(b'local'):
2308 if opts.get(b'local'):
2302 if not repo:
2309 if not repo:
2303 raise error.InputError(
2310 raise error.InputError(
2304 _(b"can't use --local outside a repository")
2311 _(b"can't use --local outside a repository")
2305 )
2312 )
2306 paths = [repo.vfs.join(b'hgrc')]
2313 paths = [repo.vfs.join(b'hgrc')]
2307 elif opts.get(b'global'):
2314 elif opts.get(b'global'):
2308 paths = rcutil.systemrcpath()
2315 paths = rcutil.systemrcpath()
2309 elif opts.get(b'shared'):
2316 elif opts.get(b'shared'):
2310 if not repo.shared():
2317 if not repo.shared():
2311 raise error.InputError(
2318 raise error.InputError(
2312 _(b"repository is not shared; can't use --shared")
2319 _(b"repository is not shared; can't use --shared")
2313 )
2320 )
2314 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2321 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2315 raise error.InputError(
2322 raise error.InputError(
2316 _(
2323 _(
2317 b"share safe feature not enabled; "
2324 b"share safe feature not enabled; "
2318 b"unable to edit shared source repository config"
2325 b"unable to edit shared source repository config"
2319 )
2326 )
2320 )
2327 )
2321 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2328 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2322 elif opts.get(b'non_shared'):
2329 elif opts.get(b'non_shared'):
2323 paths = [repo.vfs.join(b'hgrc-not-shared')]
2330 paths = [repo.vfs.join(b'hgrc-not-shared')]
2324 else:
2331 else:
2325 paths = rcutil.userrcpath()
2332 paths = rcutil.userrcpath()
2326
2333
2327 for f in paths:
2334 for f in paths:
2328 if os.path.exists(f):
2335 if os.path.exists(f):
2329 break
2336 break
2330 else:
2337 else:
2331 if opts.get(b'global'):
2338 if opts.get(b'global'):
2332 samplehgrc = uimod.samplehgrcs[b'global']
2339 samplehgrc = uimod.samplehgrcs[b'global']
2333 elif opts.get(b'local'):
2340 elif opts.get(b'local'):
2334 samplehgrc = uimod.samplehgrcs[b'local']
2341 samplehgrc = uimod.samplehgrcs[b'local']
2335 else:
2342 else:
2336 samplehgrc = uimod.samplehgrcs[b'user']
2343 samplehgrc = uimod.samplehgrcs[b'user']
2337
2344
2338 f = paths[0]
2345 f = paths[0]
2339 fp = open(f, b"wb")
2346 fp = open(f, b"wb")
2340 fp.write(util.tonativeeol(samplehgrc))
2347 fp.write(util.tonativeeol(samplehgrc))
2341 fp.close()
2348 fp.close()
2342
2349
2343 editor = ui.geteditor()
2350 editor = ui.geteditor()
2344 ui.system(
2351 ui.system(
2345 b"%s \"%s\"" % (editor, f),
2352 b"%s \"%s\"" % (editor, f),
2346 onerr=error.InputError,
2353 onerr=error.InputError,
2347 errprefix=_(b"edit failed"),
2354 errprefix=_(b"edit failed"),
2348 blockedtag=b'config_edit',
2355 blockedtag=b'config_edit',
2349 )
2356 )
2350 return
2357 return
2351 ui.pager(b'config')
2358 ui.pager(b'config')
2352 fm = ui.formatter(b'config', opts)
2359 fm = ui.formatter(b'config', opts)
2353 for t, f in rcutil.rccomponents():
2360 for t, f in rcutil.rccomponents():
2354 if t == b'path':
2361 if t == b'path':
2355 ui.debug(b'read config from: %s\n' % f)
2362 ui.debug(b'read config from: %s\n' % f)
2356 elif t == b'resource':
2363 elif t == b'resource':
2357 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2364 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2358 elif t == b'items':
2365 elif t == b'items':
2359 # Don't print anything for 'items'.
2366 # Don't print anything for 'items'.
2360 pass
2367 pass
2361 else:
2368 else:
2362 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2369 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2363 untrusted = bool(opts.get(b'untrusted'))
2370 untrusted = bool(opts.get(b'untrusted'))
2364
2371
2365 selsections = selentries = []
2372 selsections = selentries = []
2366 if values:
2373 if values:
2367 selsections = [v for v in values if b'.' not in v]
2374 selsections = [v for v in values if b'.' not in v]
2368 selentries = [v for v in values if b'.' in v]
2375 selentries = [v for v in values if b'.' in v]
2369 uniquesel = len(selentries) == 1 and not selsections
2376 uniquesel = len(selentries) == 1 and not selsections
2370 selsections = set(selsections)
2377 selsections = set(selsections)
2371 selentries = set(selentries)
2378 selentries = set(selentries)
2372
2379
2373 matched = False
2380 matched = False
2374 all_known = opts[b'exp_all_known']
2381 all_known = opts[b'exp_all_known']
2375 show_source = ui.debugflag or opts.get(b'source')
2382 show_source = ui.debugflag or opts.get(b'source')
2376 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2383 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2377 for section, name, value in entries:
2384 for section, name, value in entries:
2378 source = ui.configsource(section, name, untrusted)
2385 source = ui.configsource(section, name, untrusted)
2379 value = pycompat.bytestr(value)
2386 value = pycompat.bytestr(value)
2380 defaultvalue = ui.configdefault(section, name)
2387 defaultvalue = ui.configdefault(section, name)
2381 if fm.isplain():
2388 if fm.isplain():
2382 source = source or b'none'
2389 source = source or b'none'
2383 value = value.replace(b'\n', b'\\n')
2390 value = value.replace(b'\n', b'\\n')
2384 entryname = section + b'.' + name
2391 entryname = section + b'.' + name
2385 if values and not (section in selsections or entryname in selentries):
2392 if values and not (section in selsections or entryname in selentries):
2386 continue
2393 continue
2387 fm.startitem()
2394 fm.startitem()
2388 fm.condwrite(show_source, b'source', b'%s: ', source)
2395 fm.condwrite(show_source, b'source', b'%s: ', source)
2389 if uniquesel:
2396 if uniquesel:
2390 fm.data(name=entryname)
2397 fm.data(name=entryname)
2391 fm.write(b'value', b'%s\n', value)
2398 fm.write(b'value', b'%s\n', value)
2392 else:
2399 else:
2393 fm.write(b'name value', b'%s=%s\n', entryname, value)
2400 fm.write(b'name value', b'%s=%s\n', entryname, value)
2394 if formatter.isprintable(defaultvalue):
2401 if formatter.isprintable(defaultvalue):
2395 fm.data(defaultvalue=defaultvalue)
2402 fm.data(defaultvalue=defaultvalue)
2396 elif isinstance(defaultvalue, list) and all(
2403 elif isinstance(defaultvalue, list) and all(
2397 formatter.isprintable(e) for e in defaultvalue
2404 formatter.isprintable(e) for e in defaultvalue
2398 ):
2405 ):
2399 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2406 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2400 # TODO: no idea how to process unsupported defaultvalue types
2407 # TODO: no idea how to process unsupported defaultvalue types
2401 matched = True
2408 matched = True
2402 fm.end()
2409 fm.end()
2403 if matched:
2410 if matched:
2404 return 0
2411 return 0
2405 return 1
2412 return 1
2406
2413
2407
2414
2408 @command(
2415 @command(
2409 b'continue',
2416 b'continue',
2410 dryrunopts,
2417 dryrunopts,
2411 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2418 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2412 helpbasic=True,
2419 helpbasic=True,
2413 )
2420 )
2414 def continuecmd(ui, repo, **opts):
2421 def continuecmd(ui, repo, **opts):
2415 """resumes an interrupted operation (EXPERIMENTAL)
2422 """resumes an interrupted operation (EXPERIMENTAL)
2416
2423
2417 Finishes a multistep operation like graft, histedit, rebase, merge,
2424 Finishes a multistep operation like graft, histedit, rebase, merge,
2418 and unshelve if they are in an interrupted state.
2425 and unshelve if they are in an interrupted state.
2419
2426
2420 use --dry-run/-n to dry run the command.
2427 use --dry-run/-n to dry run the command.
2421 """
2428 """
2422 dryrun = opts.get('dry_run')
2429 dryrun = opts.get('dry_run')
2423 contstate = cmdutil.getunfinishedstate(repo)
2430 contstate = cmdutil.getunfinishedstate(repo)
2424 if not contstate:
2431 if not contstate:
2425 raise error.StateError(_(b'no operation in progress'))
2432 raise error.StateError(_(b'no operation in progress'))
2426 if not contstate.continuefunc:
2433 if not contstate.continuefunc:
2427 raise error.StateError(
2434 raise error.StateError(
2428 (
2435 (
2429 _(b"%s in progress but does not support 'hg continue'")
2436 _(b"%s in progress but does not support 'hg continue'")
2430 % (contstate._opname)
2437 % (contstate._opname)
2431 ),
2438 ),
2432 hint=contstate.continuemsg(),
2439 hint=contstate.continuemsg(),
2433 )
2440 )
2434 if dryrun:
2441 if dryrun:
2435 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2442 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2436 return
2443 return
2437 return contstate.continuefunc(ui, repo)
2444 return contstate.continuefunc(ui, repo)
2438
2445
2439
2446
2440 @command(
2447 @command(
2441 b'copy|cp',
2448 b'copy|cp',
2442 [
2449 [
2443 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2450 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2444 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2451 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2445 (
2452 (
2446 b'',
2453 b'',
2447 b'at-rev',
2454 b'at-rev',
2448 b'',
2455 b'',
2449 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2456 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2450 _(b'REV'),
2457 _(b'REV'),
2451 ),
2458 ),
2452 (
2459 (
2453 b'f',
2460 b'f',
2454 b'force',
2461 b'force',
2455 None,
2462 None,
2456 _(b'forcibly copy over an existing managed file'),
2463 _(b'forcibly copy over an existing managed file'),
2457 ),
2464 ),
2458 ]
2465 ]
2459 + walkopts
2466 + walkopts
2460 + dryrunopts,
2467 + dryrunopts,
2461 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2468 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2462 helpcategory=command.CATEGORY_FILE_CONTENTS,
2469 helpcategory=command.CATEGORY_FILE_CONTENTS,
2463 )
2470 )
2464 def copy(ui, repo, *pats, **opts):
2471 def copy(ui, repo, *pats, **opts):
2465 """mark files as copied for the next commit
2472 """mark files as copied for the next commit
2466
2473
2467 Mark dest as having copies of source files. If dest is a
2474 Mark dest as having copies of source files. If dest is a
2468 directory, copies are put in that directory. If dest is a file,
2475 directory, copies are put in that directory. If dest is a file,
2469 the source must be a single file.
2476 the source must be a single file.
2470
2477
2471 By default, this command copies the contents of files as they
2478 By default, this command copies the contents of files as they
2472 exist in the working directory. If invoked with -A/--after, the
2479 exist in the working directory. If invoked with -A/--after, the
2473 operation is recorded, but no copying is performed.
2480 operation is recorded, but no copying is performed.
2474
2481
2475 To undo marking a destination file as copied, use --forget. With that
2482 To undo marking a destination file as copied, use --forget. With that
2476 option, all given (positional) arguments are unmarked as copies. The
2483 option, all given (positional) arguments are unmarked as copies. The
2477 destination file(s) will be left in place (still tracked). Note that
2484 destination file(s) will be left in place (still tracked). Note that
2478 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2485 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2479
2486
2480 This command takes effect with the next commit by default.
2487 This command takes effect with the next commit by default.
2481
2488
2482 Returns 0 on success, 1 if errors are encountered.
2489 Returns 0 on success, 1 if errors are encountered.
2483 """
2490 """
2484 opts = pycompat.byteskwargs(opts)
2491 opts = pycompat.byteskwargs(opts)
2485 with repo.wlock():
2492 with repo.wlock():
2486 return cmdutil.copy(ui, repo, pats, opts)
2493 return cmdutil.copy(ui, repo, pats, opts)
2487
2494
2488
2495
2489 @command(
2496 @command(
2490 b'debugcommands',
2497 b'debugcommands',
2491 [],
2498 [],
2492 _(b'[COMMAND]'),
2499 _(b'[COMMAND]'),
2493 helpcategory=command.CATEGORY_HELP,
2500 helpcategory=command.CATEGORY_HELP,
2494 norepo=True,
2501 norepo=True,
2495 )
2502 )
2496 def debugcommands(ui, cmd=b'', *args):
2503 def debugcommands(ui, cmd=b'', *args):
2497 """list all available commands and options"""
2504 """list all available commands and options"""
2498 for cmd, vals in sorted(table.items()):
2505 for cmd, vals in sorted(table.items()):
2499 cmd = cmd.split(b'|')[0]
2506 cmd = cmd.split(b'|')[0]
2500 opts = b', '.join([i[1] for i in vals[1]])
2507 opts = b', '.join([i[1] for i in vals[1]])
2501 ui.write(b'%s: %s\n' % (cmd, opts))
2508 ui.write(b'%s: %s\n' % (cmd, opts))
2502
2509
2503
2510
2504 @command(
2511 @command(
2505 b'debugcomplete',
2512 b'debugcomplete',
2506 [(b'o', b'options', None, _(b'show the command options'))],
2513 [(b'o', b'options', None, _(b'show the command options'))],
2507 _(b'[-o] CMD'),
2514 _(b'[-o] CMD'),
2508 helpcategory=command.CATEGORY_HELP,
2515 helpcategory=command.CATEGORY_HELP,
2509 norepo=True,
2516 norepo=True,
2510 )
2517 )
2511 def debugcomplete(ui, cmd=b'', **opts):
2518 def debugcomplete(ui, cmd=b'', **opts):
2512 """returns the completion list associated with the given command"""
2519 """returns the completion list associated with the given command"""
2513
2520
2514 if opts.get('options'):
2521 if opts.get('options'):
2515 options = []
2522 options = []
2516 otables = [globalopts]
2523 otables = [globalopts]
2517 if cmd:
2524 if cmd:
2518 aliases, entry = cmdutil.findcmd(cmd, table, False)
2525 aliases, entry = cmdutil.findcmd(cmd, table, False)
2519 otables.append(entry[1])
2526 otables.append(entry[1])
2520 for t in otables:
2527 for t in otables:
2521 for o in t:
2528 for o in t:
2522 if b"(DEPRECATED)" in o[3]:
2529 if b"(DEPRECATED)" in o[3]:
2523 continue
2530 continue
2524 if o[0]:
2531 if o[0]:
2525 options.append(b'-%s' % o[0])
2532 options.append(b'-%s' % o[0])
2526 options.append(b'--%s' % o[1])
2533 options.append(b'--%s' % o[1])
2527 ui.write(b"%s\n" % b"\n".join(options))
2534 ui.write(b"%s\n" % b"\n".join(options))
2528 return
2535 return
2529
2536
2530 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2537 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2531 if ui.verbose:
2538 if ui.verbose:
2532 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2539 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2533 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2540 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2534
2541
2535
2542
2536 @command(
2543 @command(
2537 b'diff',
2544 b'diff',
2538 [
2545 [
2539 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2546 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2540 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2547 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2541 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2548 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2542 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2549 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2543 ]
2550 ]
2544 + diffopts
2551 + diffopts
2545 + diffopts2
2552 + diffopts2
2546 + walkopts
2553 + walkopts
2547 + subrepoopts,
2554 + subrepoopts,
2548 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2555 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2549 helpcategory=command.CATEGORY_FILE_CONTENTS,
2556 helpcategory=command.CATEGORY_FILE_CONTENTS,
2550 helpbasic=True,
2557 helpbasic=True,
2551 inferrepo=True,
2558 inferrepo=True,
2552 intents={INTENT_READONLY},
2559 intents={INTENT_READONLY},
2553 )
2560 )
2554 def diff(ui, repo, *pats, **opts):
2561 def diff(ui, repo, *pats, **opts):
2555 """diff repository (or selected files)
2562 """diff repository (or selected files)
2556
2563
2557 Show differences between revisions for the specified files.
2564 Show differences between revisions for the specified files.
2558
2565
2559 Differences between files are shown using the unified diff format.
2566 Differences between files are shown using the unified diff format.
2560
2567
2561 .. note::
2568 .. note::
2562
2569
2563 :hg:`diff` may generate unexpected results for merges, as it will
2570 :hg:`diff` may generate unexpected results for merges, as it will
2564 default to comparing against the working directory's first
2571 default to comparing against the working directory's first
2565 parent changeset if no revisions are specified. To diff against the
2572 parent changeset if no revisions are specified. To diff against the
2566 conflict regions, you can use `--config diff.merge=yes`.
2573 conflict regions, you can use `--config diff.merge=yes`.
2567
2574
2568 By default, the working directory files are compared to its first parent. To
2575 By default, the working directory files are compared to its first parent. To
2569 see the differences from another revision, use --from. To see the difference
2576 see the differences from another revision, use --from. To see the difference
2570 to another revision, use --to. For example, :hg:`diff --from .^` will show
2577 to another revision, use --to. For example, :hg:`diff --from .^` will show
2571 the differences from the working copy's grandparent to the working copy,
2578 the differences from the working copy's grandparent to the working copy,
2572 :hg:`diff --to .` will show the diff from the working copy to its parent
2579 :hg:`diff --to .` will show the diff from the working copy to its parent
2573 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2580 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2574 show the diff between those two revisions.
2581 show the diff between those two revisions.
2575
2582
2576 Alternatively you can specify -c/--change with a revision to see the changes
2583 Alternatively you can specify -c/--change with a revision to see the changes
2577 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2584 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2578 equivalent to :hg:`diff --from 42^ --to 42`)
2585 equivalent to :hg:`diff --from 42^ --to 42`)
2579
2586
2580 Without the -a/--text option, diff will avoid generating diffs of
2587 Without the -a/--text option, diff will avoid generating diffs of
2581 files it detects as binary. With -a, diff will generate a diff
2588 files it detects as binary. With -a, diff will generate a diff
2582 anyway, probably with undesirable results.
2589 anyway, probably with undesirable results.
2583
2590
2584 Use the -g/--git option to generate diffs in the git extended diff
2591 Use the -g/--git option to generate diffs in the git extended diff
2585 format. For more information, read :hg:`help diffs`.
2592 format. For more information, read :hg:`help diffs`.
2586
2593
2587 .. container:: verbose
2594 .. container:: verbose
2588
2595
2589 Examples:
2596 Examples:
2590
2597
2591 - compare a file in the current working directory to its parent::
2598 - compare a file in the current working directory to its parent::
2592
2599
2593 hg diff foo.c
2600 hg diff foo.c
2594
2601
2595 - compare two historical versions of a directory, with rename info::
2602 - compare two historical versions of a directory, with rename info::
2596
2603
2597 hg diff --git --from 1.0 --to 1.2 lib/
2604 hg diff --git --from 1.0 --to 1.2 lib/
2598
2605
2599 - get change stats relative to the last change on some date::
2606 - get change stats relative to the last change on some date::
2600
2607
2601 hg diff --stat --from "date('may 2')"
2608 hg diff --stat --from "date('may 2')"
2602
2609
2603 - diff all newly-added files that contain a keyword::
2610 - diff all newly-added files that contain a keyword::
2604
2611
2605 hg diff "set:added() and grep(GNU)"
2612 hg diff "set:added() and grep(GNU)"
2606
2613
2607 - compare a revision and its parents::
2614 - compare a revision and its parents::
2608
2615
2609 hg diff -c 9353 # compare against first parent
2616 hg diff -c 9353 # compare against first parent
2610 hg diff --from 9353^ --to 9353 # same using revset syntax
2617 hg diff --from 9353^ --to 9353 # same using revset syntax
2611 hg diff --from 9353^2 --to 9353 # compare against the second parent
2618 hg diff --from 9353^2 --to 9353 # compare against the second parent
2612
2619
2613 Returns 0 on success.
2620 Returns 0 on success.
2614 """
2621 """
2615
2622
2616 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2623 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2617 opts = pycompat.byteskwargs(opts)
2624 opts = pycompat.byteskwargs(opts)
2618 revs = opts.get(b'rev')
2625 revs = opts.get(b'rev')
2619 change = opts.get(b'change')
2626 change = opts.get(b'change')
2620 from_rev = opts.get(b'from')
2627 from_rev = opts.get(b'from')
2621 to_rev = opts.get(b'to')
2628 to_rev = opts.get(b'to')
2622 stat = opts.get(b'stat')
2629 stat = opts.get(b'stat')
2623 reverse = opts.get(b'reverse')
2630 reverse = opts.get(b'reverse')
2624
2631
2625 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2632 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2626 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2633 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2627 if change:
2634 if change:
2628 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2635 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2629 ctx2 = logcmdutil.revsingle(repo, change, None)
2636 ctx2 = logcmdutil.revsingle(repo, change, None)
2630 ctx1 = logcmdutil.diff_parent(ctx2)
2637 ctx1 = logcmdutil.diff_parent(ctx2)
2631 elif from_rev or to_rev:
2638 elif from_rev or to_rev:
2632 repo = scmutil.unhidehashlikerevs(
2639 repo = scmutil.unhidehashlikerevs(
2633 repo, [from_rev] + [to_rev], b'nowarn'
2640 repo, [from_rev] + [to_rev], b'nowarn'
2634 )
2641 )
2635 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2642 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2636 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2643 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2637 else:
2644 else:
2638 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2645 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2639 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2646 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2640
2647
2641 if reverse:
2648 if reverse:
2642 ctxleft = ctx2
2649 ctxleft = ctx2
2643 ctxright = ctx1
2650 ctxright = ctx1
2644 else:
2651 else:
2645 ctxleft = ctx1
2652 ctxleft = ctx1
2646 ctxright = ctx2
2653 ctxright = ctx2
2647
2654
2648 diffopts = patch.diffallopts(ui, opts)
2655 diffopts = patch.diffallopts(ui, opts)
2649 m = scmutil.match(ctx2, pats, opts)
2656 m = scmutil.match(ctx2, pats, opts)
2650 m = repo.narrowmatch(m)
2657 m = repo.narrowmatch(m)
2651 ui.pager(b'diff')
2658 ui.pager(b'diff')
2652 logcmdutil.diffordiffstat(
2659 logcmdutil.diffordiffstat(
2653 ui,
2660 ui,
2654 repo,
2661 repo,
2655 diffopts,
2662 diffopts,
2656 ctxleft,
2663 ctxleft,
2657 ctxright,
2664 ctxright,
2658 m,
2665 m,
2659 stat=stat,
2666 stat=stat,
2660 listsubrepos=opts.get(b'subrepos'),
2667 listsubrepos=opts.get(b'subrepos'),
2661 root=opts.get(b'root'),
2668 root=opts.get(b'root'),
2662 )
2669 )
2663
2670
2664
2671
2665 @command(
2672 @command(
2666 b'export',
2673 b'export',
2667 [
2674 [
2668 (
2675 (
2669 b'B',
2676 b'B',
2670 b'bookmark',
2677 b'bookmark',
2671 b'',
2678 b'',
2672 _(b'export changes only reachable by given bookmark'),
2679 _(b'export changes only reachable by given bookmark'),
2673 _(b'BOOKMARK'),
2680 _(b'BOOKMARK'),
2674 ),
2681 ),
2675 (
2682 (
2676 b'o',
2683 b'o',
2677 b'output',
2684 b'output',
2678 b'',
2685 b'',
2679 _(b'print output to file with formatted name'),
2686 _(b'print output to file with formatted name'),
2680 _(b'FORMAT'),
2687 _(b'FORMAT'),
2681 ),
2688 ),
2682 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2689 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2683 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2690 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2684 ]
2691 ]
2685 + diffopts
2692 + diffopts
2686 + formatteropts,
2693 + formatteropts,
2687 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2694 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2688 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2695 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2689 helpbasic=True,
2696 helpbasic=True,
2690 intents={INTENT_READONLY},
2697 intents={INTENT_READONLY},
2691 )
2698 )
2692 def export(ui, repo, *changesets, **opts):
2699 def export(ui, repo, *changesets, **opts):
2693 """dump the header and diffs for one or more changesets
2700 """dump the header and diffs for one or more changesets
2694
2701
2695 Print the changeset header and diffs for one or more revisions.
2702 Print the changeset header and diffs for one or more revisions.
2696 If no revision is given, the parent of the working directory is used.
2703 If no revision is given, the parent of the working directory is used.
2697
2704
2698 The information shown in the changeset header is: author, date,
2705 The information shown in the changeset header is: author, date,
2699 branch name (if non-default), changeset hash, parent(s) and commit
2706 branch name (if non-default), changeset hash, parent(s) and commit
2700 comment.
2707 comment.
2701
2708
2702 .. note::
2709 .. note::
2703
2710
2704 :hg:`export` may generate unexpected diff output for merge
2711 :hg:`export` may generate unexpected diff output for merge
2705 changesets, as it will compare the merge changeset against its
2712 changesets, as it will compare the merge changeset against its
2706 first parent only.
2713 first parent only.
2707
2714
2708 Output may be to a file, in which case the name of the file is
2715 Output may be to a file, in which case the name of the file is
2709 given using a template string. See :hg:`help templates`. In addition
2716 given using a template string. See :hg:`help templates`. In addition
2710 to the common template keywords, the following formatting rules are
2717 to the common template keywords, the following formatting rules are
2711 supported:
2718 supported:
2712
2719
2713 :``%%``: literal "%" character
2720 :``%%``: literal "%" character
2714 :``%H``: changeset hash (40 hexadecimal digits)
2721 :``%H``: changeset hash (40 hexadecimal digits)
2715 :``%N``: number of patches being generated
2722 :``%N``: number of patches being generated
2716 :``%R``: changeset revision number
2723 :``%R``: changeset revision number
2717 :``%b``: basename of the exporting repository
2724 :``%b``: basename of the exporting repository
2718 :``%h``: short-form changeset hash (12 hexadecimal digits)
2725 :``%h``: short-form changeset hash (12 hexadecimal digits)
2719 :``%m``: first line of the commit message (only alphanumeric characters)
2726 :``%m``: first line of the commit message (only alphanumeric characters)
2720 :``%n``: zero-padded sequence number, starting at 1
2727 :``%n``: zero-padded sequence number, starting at 1
2721 :``%r``: zero-padded changeset revision number
2728 :``%r``: zero-padded changeset revision number
2722 :``\\``: literal "\\" character
2729 :``\\``: literal "\\" character
2723
2730
2724 Without the -a/--text option, export will avoid generating diffs
2731 Without the -a/--text option, export will avoid generating diffs
2725 of files it detects as binary. With -a, export will generate a
2732 of files it detects as binary. With -a, export will generate a
2726 diff anyway, probably with undesirable results.
2733 diff anyway, probably with undesirable results.
2727
2734
2728 With -B/--bookmark changesets reachable by the given bookmark are
2735 With -B/--bookmark changesets reachable by the given bookmark are
2729 selected.
2736 selected.
2730
2737
2731 Use the -g/--git option to generate diffs in the git extended diff
2738 Use the -g/--git option to generate diffs in the git extended diff
2732 format. See :hg:`help diffs` for more information.
2739 format. See :hg:`help diffs` for more information.
2733
2740
2734 With the --switch-parent option, the diff will be against the
2741 With the --switch-parent option, the diff will be against the
2735 second parent. It can be useful to review a merge.
2742 second parent. It can be useful to review a merge.
2736
2743
2737 .. container:: verbose
2744 .. container:: verbose
2738
2745
2739 Template:
2746 Template:
2740
2747
2741 The following keywords are supported in addition to the common template
2748 The following keywords are supported in addition to the common template
2742 keywords and functions. See also :hg:`help templates`.
2749 keywords and functions. See also :hg:`help templates`.
2743
2750
2744 :diff: String. Diff content.
2751 :diff: String. Diff content.
2745 :parents: List of strings. Parent nodes of the changeset.
2752 :parents: List of strings. Parent nodes of the changeset.
2746
2753
2747 Examples:
2754 Examples:
2748
2755
2749 - use export and import to transplant a bugfix to the current
2756 - use export and import to transplant a bugfix to the current
2750 branch::
2757 branch::
2751
2758
2752 hg export -r 9353 | hg import -
2759 hg export -r 9353 | hg import -
2753
2760
2754 - export all the changesets between two revisions to a file with
2761 - export all the changesets between two revisions to a file with
2755 rename information::
2762 rename information::
2756
2763
2757 hg export --git -r 123:150 > changes.txt
2764 hg export --git -r 123:150 > changes.txt
2758
2765
2759 - split outgoing changes into a series of patches with
2766 - split outgoing changes into a series of patches with
2760 descriptive names::
2767 descriptive names::
2761
2768
2762 hg export -r "outgoing()" -o "%n-%m.patch"
2769 hg export -r "outgoing()" -o "%n-%m.patch"
2763
2770
2764 Returns 0 on success.
2771 Returns 0 on success.
2765 """
2772 """
2766 opts = pycompat.byteskwargs(opts)
2773 opts = pycompat.byteskwargs(opts)
2767 bookmark = opts.get(b'bookmark')
2774 bookmark = opts.get(b'bookmark')
2768 changesets += tuple(opts.get(b'rev', []))
2775 changesets += tuple(opts.get(b'rev', []))
2769
2776
2770 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2777 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2771
2778
2772 if bookmark:
2779 if bookmark:
2773 if bookmark not in repo._bookmarks:
2780 if bookmark not in repo._bookmarks:
2774 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2781 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2775
2782
2776 revs = scmutil.bookmarkrevs(repo, bookmark)
2783 revs = scmutil.bookmarkrevs(repo, bookmark)
2777 else:
2784 else:
2778 if not changesets:
2785 if not changesets:
2779 changesets = [b'.']
2786 changesets = [b'.']
2780
2787
2781 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2788 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2782 revs = logcmdutil.revrange(repo, changesets)
2789 revs = logcmdutil.revrange(repo, changesets)
2783
2790
2784 if not revs:
2791 if not revs:
2785 raise error.InputError(_(b"export requires at least one changeset"))
2792 raise error.InputError(_(b"export requires at least one changeset"))
2786 if len(revs) > 1:
2793 if len(revs) > 1:
2787 ui.note(_(b'exporting patches:\n'))
2794 ui.note(_(b'exporting patches:\n'))
2788 else:
2795 else:
2789 ui.note(_(b'exporting patch:\n'))
2796 ui.note(_(b'exporting patch:\n'))
2790
2797
2791 fntemplate = opts.get(b'output')
2798 fntemplate = opts.get(b'output')
2792 if cmdutil.isstdiofilename(fntemplate):
2799 if cmdutil.isstdiofilename(fntemplate):
2793 fntemplate = b''
2800 fntemplate = b''
2794
2801
2795 if fntemplate:
2802 if fntemplate:
2796 fm = formatter.nullformatter(ui, b'export', opts)
2803 fm = formatter.nullformatter(ui, b'export', opts)
2797 else:
2804 else:
2798 ui.pager(b'export')
2805 ui.pager(b'export')
2799 fm = ui.formatter(b'export', opts)
2806 fm = ui.formatter(b'export', opts)
2800 with fm:
2807 with fm:
2801 cmdutil.export(
2808 cmdutil.export(
2802 repo,
2809 repo,
2803 revs,
2810 revs,
2804 fm,
2811 fm,
2805 fntemplate=fntemplate,
2812 fntemplate=fntemplate,
2806 switch_parent=opts.get(b'switch_parent'),
2813 switch_parent=opts.get(b'switch_parent'),
2807 opts=patch.diffallopts(ui, opts),
2814 opts=patch.diffallopts(ui, opts),
2808 )
2815 )
2809
2816
2810
2817
2811 @command(
2818 @command(
2812 b'files',
2819 b'files',
2813 [
2820 [
2814 (
2821 (
2815 b'r',
2822 b'r',
2816 b'rev',
2823 b'rev',
2817 b'',
2824 b'',
2818 _(b'search the repository as it is in REV'),
2825 _(b'search the repository as it is in REV'),
2819 _(b'REV'),
2826 _(b'REV'),
2820 ),
2827 ),
2821 (
2828 (
2822 b'0',
2829 b'0',
2823 b'print0',
2830 b'print0',
2824 None,
2831 None,
2825 _(b'end filenames with NUL, for use with xargs'),
2832 _(b'end filenames with NUL, for use with xargs'),
2826 ),
2833 ),
2827 ]
2834 ]
2828 + walkopts
2835 + walkopts
2829 + formatteropts
2836 + formatteropts
2830 + subrepoopts,
2837 + subrepoopts,
2831 _(b'[OPTION]... [FILE]...'),
2838 _(b'[OPTION]... [FILE]...'),
2832 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2839 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2833 intents={INTENT_READONLY},
2840 intents={INTENT_READONLY},
2834 )
2841 )
2835 def files(ui, repo, *pats, **opts):
2842 def files(ui, repo, *pats, **opts):
2836 """list tracked files
2843 """list tracked files
2837
2844
2838 Print files under Mercurial control in the working directory or
2845 Print files under Mercurial control in the working directory or
2839 specified revision for given files (excluding removed files).
2846 specified revision for given files (excluding removed files).
2840 Files can be specified as filenames or filesets.
2847 Files can be specified as filenames or filesets.
2841
2848
2842 If no files are given to match, this command prints the names
2849 If no files are given to match, this command prints the names
2843 of all files under Mercurial control.
2850 of all files under Mercurial control.
2844
2851
2845 .. container:: verbose
2852 .. container:: verbose
2846
2853
2847 Template:
2854 Template:
2848
2855
2849 The following keywords are supported in addition to the common template
2856 The following keywords are supported in addition to the common template
2850 keywords and functions. See also :hg:`help templates`.
2857 keywords and functions. See also :hg:`help templates`.
2851
2858
2852 :flags: String. Character denoting file's symlink and executable bits.
2859 :flags: String. Character denoting file's symlink and executable bits.
2853 :path: String. Repository-absolute path of the file.
2860 :path: String. Repository-absolute path of the file.
2854 :size: Integer. Size of the file in bytes.
2861 :size: Integer. Size of the file in bytes.
2855
2862
2856 Examples:
2863 Examples:
2857
2864
2858 - list all files under the current directory::
2865 - list all files under the current directory::
2859
2866
2860 hg files .
2867 hg files .
2861
2868
2862 - shows sizes and flags for current revision::
2869 - shows sizes and flags for current revision::
2863
2870
2864 hg files -vr .
2871 hg files -vr .
2865
2872
2866 - list all files named README::
2873 - list all files named README::
2867
2874
2868 hg files -I "**/README"
2875 hg files -I "**/README"
2869
2876
2870 - list all binary files::
2877 - list all binary files::
2871
2878
2872 hg files "set:binary()"
2879 hg files "set:binary()"
2873
2880
2874 - find files containing a regular expression::
2881 - find files containing a regular expression::
2875
2882
2876 hg files "set:grep('bob')"
2883 hg files "set:grep('bob')"
2877
2884
2878 - search tracked file contents with xargs and grep::
2885 - search tracked file contents with xargs and grep::
2879
2886
2880 hg files -0 | xargs -0 grep foo
2887 hg files -0 | xargs -0 grep foo
2881
2888
2882 See :hg:`help patterns` and :hg:`help filesets` for more information
2889 See :hg:`help patterns` and :hg:`help filesets` for more information
2883 on specifying file patterns.
2890 on specifying file patterns.
2884
2891
2885 Returns 0 if a match is found, 1 otherwise.
2892 Returns 0 if a match is found, 1 otherwise.
2886
2893
2887 """
2894 """
2888
2895
2889 opts = pycompat.byteskwargs(opts)
2896 opts = pycompat.byteskwargs(opts)
2890 rev = opts.get(b'rev')
2897 rev = opts.get(b'rev')
2891 if rev:
2898 if rev:
2892 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2899 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2893 ctx = logcmdutil.revsingle(repo, rev, None)
2900 ctx = logcmdutil.revsingle(repo, rev, None)
2894
2901
2895 end = b'\n'
2902 end = b'\n'
2896 if opts.get(b'print0'):
2903 if opts.get(b'print0'):
2897 end = b'\0'
2904 end = b'\0'
2898 fmt = b'%s' + end
2905 fmt = b'%s' + end
2899
2906
2900 m = scmutil.match(ctx, pats, opts)
2907 m = scmutil.match(ctx, pats, opts)
2901 ui.pager(b'files')
2908 ui.pager(b'files')
2902 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2909 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2903 with ui.formatter(b'files', opts) as fm:
2910 with ui.formatter(b'files', opts) as fm:
2904 return cmdutil.files(
2911 return cmdutil.files(
2905 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2912 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2906 )
2913 )
2907
2914
2908
2915
2909 @command(
2916 @command(
2910 b'forget',
2917 b'forget',
2911 [
2918 [
2912 (b'i', b'interactive', None, _(b'use interactive mode')),
2919 (b'i', b'interactive', None, _(b'use interactive mode')),
2913 ]
2920 ]
2914 + walkopts
2921 + walkopts
2915 + dryrunopts,
2922 + dryrunopts,
2916 _(b'[OPTION]... FILE...'),
2923 _(b'[OPTION]... FILE...'),
2917 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2924 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2918 helpbasic=True,
2925 helpbasic=True,
2919 inferrepo=True,
2926 inferrepo=True,
2920 )
2927 )
2921 def forget(ui, repo, *pats, **opts):
2928 def forget(ui, repo, *pats, **opts):
2922 """forget the specified files on the next commit
2929 """forget the specified files on the next commit
2923
2930
2924 Mark the specified files so they will no longer be tracked
2931 Mark the specified files so they will no longer be tracked
2925 after the next commit.
2932 after the next commit.
2926
2933
2927 This only removes files from the current branch, not from the
2934 This only removes files from the current branch, not from the
2928 entire project history, and it does not delete them from the
2935 entire project history, and it does not delete them from the
2929 working directory.
2936 working directory.
2930
2937
2931 To delete the file from the working directory, see :hg:`remove`.
2938 To delete the file from the working directory, see :hg:`remove`.
2932
2939
2933 To undo a forget before the next commit, see :hg:`add`.
2940 To undo a forget before the next commit, see :hg:`add`.
2934
2941
2935 .. container:: verbose
2942 .. container:: verbose
2936
2943
2937 Examples:
2944 Examples:
2938
2945
2939 - forget newly-added binary files::
2946 - forget newly-added binary files::
2940
2947
2941 hg forget "set:added() and binary()"
2948 hg forget "set:added() and binary()"
2942
2949
2943 - forget files that would be excluded by .hgignore::
2950 - forget files that would be excluded by .hgignore::
2944
2951
2945 hg forget "set:hgignore()"
2952 hg forget "set:hgignore()"
2946
2953
2947 Returns 0 on success.
2954 Returns 0 on success.
2948 """
2955 """
2949
2956
2950 opts = pycompat.byteskwargs(opts)
2957 opts = pycompat.byteskwargs(opts)
2951 if not pats:
2958 if not pats:
2952 raise error.InputError(_(b'no files specified'))
2959 raise error.InputError(_(b'no files specified'))
2953
2960
2954 m = scmutil.match(repo[None], pats, opts)
2961 m = scmutil.match(repo[None], pats, opts)
2955 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2962 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2956 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2963 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2957 rejected = cmdutil.forget(
2964 rejected = cmdutil.forget(
2958 ui,
2965 ui,
2959 repo,
2966 repo,
2960 m,
2967 m,
2961 prefix=b"",
2968 prefix=b"",
2962 uipathfn=uipathfn,
2969 uipathfn=uipathfn,
2963 explicitonly=False,
2970 explicitonly=False,
2964 dryrun=dryrun,
2971 dryrun=dryrun,
2965 interactive=interactive,
2972 interactive=interactive,
2966 )[0]
2973 )[0]
2967 return rejected and 1 or 0
2974 return rejected and 1 or 0
2968
2975
2969
2976
2970 @command(
2977 @command(
2971 b'graft',
2978 b'graft',
2972 [
2979 [
2973 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2980 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2974 (
2981 (
2975 b'',
2982 b'',
2976 b'base',
2983 b'base',
2977 b'',
2984 b'',
2978 _(b'base revision when doing the graft merge (ADVANCED)'),
2985 _(b'base revision when doing the graft merge (ADVANCED)'),
2979 _(b'REV'),
2986 _(b'REV'),
2980 ),
2987 ),
2981 (b'c', b'continue', False, _(b'resume interrupted graft')),
2988 (b'c', b'continue', False, _(b'resume interrupted graft')),
2982 (b'', b'stop', False, _(b'stop interrupted graft')),
2989 (b'', b'stop', False, _(b'stop interrupted graft')),
2983 (b'', b'abort', False, _(b'abort interrupted graft')),
2990 (b'', b'abort', False, _(b'abort interrupted graft')),
2984 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2991 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2985 (b'', b'log', None, _(b'append graft info to log message')),
2992 (b'', b'log', None, _(b'append graft info to log message')),
2986 (
2993 (
2987 b'',
2994 b'',
2988 b'no-commit',
2995 b'no-commit',
2989 None,
2996 None,
2990 _(b"don't commit, just apply the changes in working directory"),
2997 _(b"don't commit, just apply the changes in working directory"),
2991 ),
2998 ),
2992 (b'f', b'force', False, _(b'force graft')),
2999 (b'f', b'force', False, _(b'force graft')),
2993 (
3000 (
2994 b'D',
3001 b'D',
2995 b'currentdate',
3002 b'currentdate',
2996 False,
3003 False,
2997 _(b'record the current date as commit date'),
3004 _(b'record the current date as commit date'),
2998 ),
3005 ),
2999 (
3006 (
3000 b'U',
3007 b'U',
3001 b'currentuser',
3008 b'currentuser',
3002 False,
3009 False,
3003 _(b'record the current user as committer'),
3010 _(b'record the current user as committer'),
3004 ),
3011 ),
3005 ]
3012 ]
3006 + commitopts2
3013 + commitopts2
3007 + mergetoolopts
3014 + mergetoolopts
3008 + dryrunopts,
3015 + dryrunopts,
3009 _(b'[OPTION]... [-r REV]... REV...'),
3016 _(b'[OPTION]... [-r REV]... REV...'),
3010 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3017 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3011 )
3018 )
3012 def graft(ui, repo, *revs, **opts):
3019 def graft(ui, repo, *revs, **opts):
3013 """copy changes from other branches onto the current branch
3020 """copy changes from other branches onto the current branch
3014
3021
3015 This command uses Mercurial's merge logic to copy individual
3022 This command uses Mercurial's merge logic to copy individual
3016 changes from other branches without merging branches in the
3023 changes from other branches without merging branches in the
3017 history graph. This is sometimes known as 'backporting' or
3024 history graph. This is sometimes known as 'backporting' or
3018 'cherry-picking'. By default, graft will copy user, date, and
3025 'cherry-picking'. By default, graft will copy user, date, and
3019 description from the source changesets.
3026 description from the source changesets.
3020
3027
3021 Changesets that are ancestors of the current revision, that have
3028 Changesets that are ancestors of the current revision, that have
3022 already been grafted, or that are merges will be skipped.
3029 already been grafted, or that are merges will be skipped.
3023
3030
3024 If --log is specified, log messages will have a comment appended
3031 If --log is specified, log messages will have a comment appended
3025 of the form::
3032 of the form::
3026
3033
3027 (grafted from CHANGESETHASH)
3034 (grafted from CHANGESETHASH)
3028
3035
3029 If --force is specified, revisions will be grafted even if they
3036 If --force is specified, revisions will be grafted even if they
3030 are already ancestors of, or have been grafted to, the destination.
3037 are already ancestors of, or have been grafted to, the destination.
3031 This is useful when the revisions have since been backed out.
3038 This is useful when the revisions have since been backed out.
3032
3039
3033 If a graft merge results in conflicts, the graft process is
3040 If a graft merge results in conflicts, the graft process is
3034 interrupted so that the current merge can be manually resolved.
3041 interrupted so that the current merge can be manually resolved.
3035 Once all conflicts are addressed, the graft process can be
3042 Once all conflicts are addressed, the graft process can be
3036 continued with the -c/--continue option.
3043 continued with the -c/--continue option.
3037
3044
3038 The -c/--continue option reapplies all the earlier options.
3045 The -c/--continue option reapplies all the earlier options.
3039
3046
3040 .. container:: verbose
3047 .. container:: verbose
3041
3048
3042 The --base option exposes more of how graft internally uses merge with a
3049 The --base option exposes more of how graft internally uses merge with a
3043 custom base revision. --base can be used to specify another ancestor than
3050 custom base revision. --base can be used to specify another ancestor than
3044 the first and only parent.
3051 the first and only parent.
3045
3052
3046 The command::
3053 The command::
3047
3054
3048 hg graft -r 345 --base 234
3055 hg graft -r 345 --base 234
3049
3056
3050 is thus pretty much the same as::
3057 is thus pretty much the same as::
3051
3058
3052 hg diff --from 234 --to 345 | hg import
3059 hg diff --from 234 --to 345 | hg import
3053
3060
3054 but using merge to resolve conflicts and track moved files.
3061 but using merge to resolve conflicts and track moved files.
3055
3062
3056 The result of a merge can thus be backported as a single commit by
3063 The result of a merge can thus be backported as a single commit by
3057 specifying one of the merge parents as base, and thus effectively
3064 specifying one of the merge parents as base, and thus effectively
3058 grafting the changes from the other side.
3065 grafting the changes from the other side.
3059
3066
3060 It is also possible to collapse multiple changesets and clean up history
3067 It is also possible to collapse multiple changesets and clean up history
3061 by specifying another ancestor as base, much like rebase --collapse
3068 by specifying another ancestor as base, much like rebase --collapse
3062 --keep.
3069 --keep.
3063
3070
3064 The commit message can be tweaked after the fact using commit --amend .
3071 The commit message can be tweaked after the fact using commit --amend .
3065
3072
3066 For using non-ancestors as the base to backout changes, see the backout
3073 For using non-ancestors as the base to backout changes, see the backout
3067 command and the hidden --parent option.
3074 command and the hidden --parent option.
3068
3075
3069 .. container:: verbose
3076 .. container:: verbose
3070
3077
3071 Examples:
3078 Examples:
3072
3079
3073 - copy a single change to the stable branch and edit its description::
3080 - copy a single change to the stable branch and edit its description::
3074
3081
3075 hg update stable
3082 hg update stable
3076 hg graft --edit 9393
3083 hg graft --edit 9393
3077
3084
3078 - graft a range of changesets with one exception, updating dates::
3085 - graft a range of changesets with one exception, updating dates::
3079
3086
3080 hg graft -D "2085::2093 and not 2091"
3087 hg graft -D "2085::2093 and not 2091"
3081
3088
3082 - continue a graft after resolving conflicts::
3089 - continue a graft after resolving conflicts::
3083
3090
3084 hg graft -c
3091 hg graft -c
3085
3092
3086 - show the source of a grafted changeset::
3093 - show the source of a grafted changeset::
3087
3094
3088 hg log --debug -r .
3095 hg log --debug -r .
3089
3096
3090 - show revisions sorted by date::
3097 - show revisions sorted by date::
3091
3098
3092 hg log -r "sort(all(), date)"
3099 hg log -r "sort(all(), date)"
3093
3100
3094 - backport the result of a merge as a single commit::
3101 - backport the result of a merge as a single commit::
3095
3102
3096 hg graft -r 123 --base 123^
3103 hg graft -r 123 --base 123^
3097
3104
3098 - land a feature branch as one changeset::
3105 - land a feature branch as one changeset::
3099
3106
3100 hg up -cr default
3107 hg up -cr default
3101 hg graft -r featureX --base "ancestor('featureX', 'default')"
3108 hg graft -r featureX --base "ancestor('featureX', 'default')"
3102
3109
3103 See :hg:`help revisions` for more about specifying revisions.
3110 See :hg:`help revisions` for more about specifying revisions.
3104
3111
3105 Returns 0 on successful completion, 1 if there are unresolved files.
3112 Returns 0 on successful completion, 1 if there are unresolved files.
3106 """
3113 """
3107 with repo.wlock():
3114 with repo.wlock():
3108 return _dograft(ui, repo, *revs, **opts)
3115 return _dograft(ui, repo, *revs, **opts)
3109
3116
3110
3117
3111 def _dograft(ui, repo, *revs, **opts):
3118 def _dograft(ui, repo, *revs, **opts):
3112 if revs and opts.get('rev'):
3119 if revs and opts.get('rev'):
3113 ui.warn(
3120 ui.warn(
3114 _(
3121 _(
3115 b'warning: inconsistent use of --rev might give unexpected '
3122 b'warning: inconsistent use of --rev might give unexpected '
3116 b'revision ordering!\n'
3123 b'revision ordering!\n'
3117 )
3124 )
3118 )
3125 )
3119
3126
3120 revs = list(revs)
3127 revs = list(revs)
3121 revs.extend(opts.get('rev'))
3128 revs.extend(opts.get('rev'))
3122 # a dict of data to be stored in state file
3129 # a dict of data to be stored in state file
3123 statedata = {}
3130 statedata = {}
3124 # list of new nodes created by ongoing graft
3131 # list of new nodes created by ongoing graft
3125 statedata[b'newnodes'] = []
3132 statedata[b'newnodes'] = []
3126
3133
3127 cmdutil.resolve_commit_options(ui, opts)
3134 cmdutil.resolve_commit_options(ui, opts)
3128
3135
3129 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3136 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3130
3137
3131 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3138 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3132
3139
3133 cont = False
3140 cont = False
3134 if opts.get('no_commit'):
3141 if opts.get('no_commit'):
3135 cmdutil.check_incompatible_arguments(
3142 cmdutil.check_incompatible_arguments(
3136 opts,
3143 opts,
3137 'no_commit',
3144 'no_commit',
3138 ['edit', 'currentuser', 'currentdate', 'log'],
3145 ['edit', 'currentuser', 'currentdate', 'log'],
3139 )
3146 )
3140
3147
3141 graftstate = statemod.cmdstate(repo, b'graftstate')
3148 graftstate = statemod.cmdstate(repo, b'graftstate')
3142
3149
3143 if opts.get('stop'):
3150 if opts.get('stop'):
3144 cmdutil.check_incompatible_arguments(
3151 cmdutil.check_incompatible_arguments(
3145 opts,
3152 opts,
3146 'stop',
3153 'stop',
3147 [
3154 [
3148 'edit',
3155 'edit',
3149 'log',
3156 'log',
3150 'user',
3157 'user',
3151 'date',
3158 'date',
3152 'currentdate',
3159 'currentdate',
3153 'currentuser',
3160 'currentuser',
3154 'rev',
3161 'rev',
3155 ],
3162 ],
3156 )
3163 )
3157 return _stopgraft(ui, repo, graftstate)
3164 return _stopgraft(ui, repo, graftstate)
3158 elif opts.get('abort'):
3165 elif opts.get('abort'):
3159 cmdutil.check_incompatible_arguments(
3166 cmdutil.check_incompatible_arguments(
3160 opts,
3167 opts,
3161 'abort',
3168 'abort',
3162 [
3169 [
3163 'edit',
3170 'edit',
3164 'log',
3171 'log',
3165 'user',
3172 'user',
3166 'date',
3173 'date',
3167 'currentdate',
3174 'currentdate',
3168 'currentuser',
3175 'currentuser',
3169 'rev',
3176 'rev',
3170 ],
3177 ],
3171 )
3178 )
3172 return cmdutil.abortgraft(ui, repo, graftstate)
3179 return cmdutil.abortgraft(ui, repo, graftstate)
3173 elif opts.get('continue'):
3180 elif opts.get('continue'):
3174 cont = True
3181 cont = True
3175 if revs:
3182 if revs:
3176 raise error.InputError(_(b"can't specify --continue and revisions"))
3183 raise error.InputError(_(b"can't specify --continue and revisions"))
3177 # read in unfinished revisions
3184 # read in unfinished revisions
3178 if graftstate.exists():
3185 if graftstate.exists():
3179 statedata = cmdutil.readgraftstate(repo, graftstate)
3186 statedata = cmdutil.readgraftstate(repo, graftstate)
3180 if statedata.get(b'date'):
3187 if statedata.get(b'date'):
3181 opts['date'] = statedata[b'date']
3188 opts['date'] = statedata[b'date']
3182 if statedata.get(b'user'):
3189 if statedata.get(b'user'):
3183 opts['user'] = statedata[b'user']
3190 opts['user'] = statedata[b'user']
3184 if statedata.get(b'log'):
3191 if statedata.get(b'log'):
3185 opts['log'] = True
3192 opts['log'] = True
3186 if statedata.get(b'no_commit'):
3193 if statedata.get(b'no_commit'):
3187 opts['no_commit'] = statedata.get(b'no_commit')
3194 opts['no_commit'] = statedata.get(b'no_commit')
3188 if statedata.get(b'base'):
3195 if statedata.get(b'base'):
3189 opts['base'] = statedata.get(b'base')
3196 opts['base'] = statedata.get(b'base')
3190 nodes = statedata[b'nodes']
3197 nodes = statedata[b'nodes']
3191 revs = [repo[node].rev() for node in nodes]
3198 revs = [repo[node].rev() for node in nodes]
3192 else:
3199 else:
3193 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3200 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3194 else:
3201 else:
3195 if not revs:
3202 if not revs:
3196 raise error.InputError(_(b'no revisions specified'))
3203 raise error.InputError(_(b'no revisions specified'))
3197 cmdutil.checkunfinished(repo)
3204 cmdutil.checkunfinished(repo)
3198 cmdutil.bailifchanged(repo)
3205 cmdutil.bailifchanged(repo)
3199 revs = logcmdutil.revrange(repo, revs)
3206 revs = logcmdutil.revrange(repo, revs)
3200
3207
3201 skipped = set()
3208 skipped = set()
3202 basectx = None
3209 basectx = None
3203 if opts.get('base'):
3210 if opts.get('base'):
3204 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3211 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3205 if basectx is None:
3212 if basectx is None:
3206 # check for merges
3213 # check for merges
3207 for rev in repo.revs(b'%ld and merge()', revs):
3214 for rev in repo.revs(b'%ld and merge()', revs):
3208 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3215 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3209 skipped.add(rev)
3216 skipped.add(rev)
3210 revs = [r for r in revs if r not in skipped]
3217 revs = [r for r in revs if r not in skipped]
3211 if not revs:
3218 if not revs:
3212 return -1
3219 return -1
3213 if basectx is not None and len(revs) != 1:
3220 if basectx is not None and len(revs) != 1:
3214 raise error.InputError(_(b'only one revision allowed with --base '))
3221 raise error.InputError(_(b'only one revision allowed with --base '))
3215
3222
3216 # Don't check in the --continue case, in effect retaining --force across
3223 # Don't check in the --continue case, in effect retaining --force across
3217 # --continues. That's because without --force, any revisions we decided to
3224 # --continues. That's because without --force, any revisions we decided to
3218 # skip would have been filtered out here, so they wouldn't have made their
3225 # skip would have been filtered out here, so they wouldn't have made their
3219 # way to the graftstate. With --force, any revisions we would have otherwise
3226 # way to the graftstate. With --force, any revisions we would have otherwise
3220 # skipped would not have been filtered out, and if they hadn't been applied
3227 # skipped would not have been filtered out, and if they hadn't been applied
3221 # already, they'd have been in the graftstate.
3228 # already, they'd have been in the graftstate.
3222 if not (cont or opts.get('force')) and basectx is None:
3229 if not (cont or opts.get('force')) and basectx is None:
3223 # check for ancestors of dest branch
3230 # check for ancestors of dest branch
3224 ancestors = repo.revs(b'%ld & (::.)', revs)
3231 ancestors = repo.revs(b'%ld & (::.)', revs)
3225 for rev in ancestors:
3232 for rev in ancestors:
3226 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3233 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3227
3234
3228 revs = [r for r in revs if r not in ancestors]
3235 revs = [r for r in revs if r not in ancestors]
3229
3236
3230 if not revs:
3237 if not revs:
3231 return -1
3238 return -1
3232
3239
3233 # analyze revs for earlier grafts
3240 # analyze revs for earlier grafts
3234 ids = {}
3241 ids = {}
3235 for ctx in repo.set(b"%ld", revs):
3242 for ctx in repo.set(b"%ld", revs):
3236 ids[ctx.hex()] = ctx.rev()
3243 ids[ctx.hex()] = ctx.rev()
3237 n = ctx.extra().get(b'source')
3244 n = ctx.extra().get(b'source')
3238 if n:
3245 if n:
3239 ids[n] = ctx.rev()
3246 ids[n] = ctx.rev()
3240
3247
3241 # check ancestors for earlier grafts
3248 # check ancestors for earlier grafts
3242 ui.debug(b'scanning for duplicate grafts\n')
3249 ui.debug(b'scanning for duplicate grafts\n')
3243
3250
3244 # The only changesets we can be sure doesn't contain grafts of any
3251 # The only changesets we can be sure doesn't contain grafts of any
3245 # revs, are the ones that are common ancestors of *all* revs:
3252 # revs, are the ones that are common ancestors of *all* revs:
3246 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3253 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3247 ctx = repo[rev]
3254 ctx = repo[rev]
3248 n = ctx.extra().get(b'source')
3255 n = ctx.extra().get(b'source')
3249 if n in ids:
3256 if n in ids:
3250 try:
3257 try:
3251 r = repo[n].rev()
3258 r = repo[n].rev()
3252 except error.RepoLookupError:
3259 except error.RepoLookupError:
3253 r = None
3260 r = None
3254 if r in revs:
3261 if r in revs:
3255 ui.warn(
3262 ui.warn(
3256 _(
3263 _(
3257 b'skipping revision %d:%s '
3264 b'skipping revision %d:%s '
3258 b'(already grafted to %d:%s)\n'
3265 b'(already grafted to %d:%s)\n'
3259 )
3266 )
3260 % (r, repo[r], rev, ctx)
3267 % (r, repo[r], rev, ctx)
3261 )
3268 )
3262 revs.remove(r)
3269 revs.remove(r)
3263 elif ids[n] in revs:
3270 elif ids[n] in revs:
3264 if r is None:
3271 if r is None:
3265 ui.warn(
3272 ui.warn(
3266 _(
3273 _(
3267 b'skipping already grafted revision %d:%s '
3274 b'skipping already grafted revision %d:%s '
3268 b'(%d:%s also has unknown origin %s)\n'
3275 b'(%d:%s also has unknown origin %s)\n'
3269 )
3276 )
3270 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3277 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3271 )
3278 )
3272 else:
3279 else:
3273 ui.warn(
3280 ui.warn(
3274 _(
3281 _(
3275 b'skipping already grafted revision %d:%s '
3282 b'skipping already grafted revision %d:%s '
3276 b'(%d:%s also has origin %d:%s)\n'
3283 b'(%d:%s also has origin %d:%s)\n'
3277 )
3284 )
3278 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3285 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3279 )
3286 )
3280 revs.remove(ids[n])
3287 revs.remove(ids[n])
3281 elif ctx.hex() in ids:
3288 elif ctx.hex() in ids:
3282 r = ids[ctx.hex()]
3289 r = ids[ctx.hex()]
3283 if r in revs:
3290 if r in revs:
3284 ui.warn(
3291 ui.warn(
3285 _(
3292 _(
3286 b'skipping already grafted revision %d:%s '
3293 b'skipping already grafted revision %d:%s '
3287 b'(was grafted from %d:%s)\n'
3294 b'(was grafted from %d:%s)\n'
3288 )
3295 )
3289 % (r, repo[r], rev, ctx)
3296 % (r, repo[r], rev, ctx)
3290 )
3297 )
3291 revs.remove(r)
3298 revs.remove(r)
3292 if not revs:
3299 if not revs:
3293 return -1
3300 return -1
3294
3301
3295 if opts.get('no_commit'):
3302 if opts.get('no_commit'):
3296 statedata[b'no_commit'] = True
3303 statedata[b'no_commit'] = True
3297 if opts.get('base'):
3304 if opts.get('base'):
3298 statedata[b'base'] = opts['base']
3305 statedata[b'base'] = opts['base']
3299 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3306 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3300 desc = b'%d:%s "%s"' % (
3307 desc = b'%d:%s "%s"' % (
3301 ctx.rev(),
3308 ctx.rev(),
3302 ctx,
3309 ctx,
3303 ctx.description().split(b'\n', 1)[0],
3310 ctx.description().split(b'\n', 1)[0],
3304 )
3311 )
3305 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3312 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3306 if names:
3313 if names:
3307 desc += b' (%s)' % b' '.join(names)
3314 desc += b' (%s)' % b' '.join(names)
3308 ui.status(_(b'grafting %s\n') % desc)
3315 ui.status(_(b'grafting %s\n') % desc)
3309 if opts.get('dry_run'):
3316 if opts.get('dry_run'):
3310 continue
3317 continue
3311
3318
3312 source = ctx.extra().get(b'source')
3319 source = ctx.extra().get(b'source')
3313 extra = {}
3320 extra = {}
3314 if source:
3321 if source:
3315 extra[b'source'] = source
3322 extra[b'source'] = source
3316 extra[b'intermediate-source'] = ctx.hex()
3323 extra[b'intermediate-source'] = ctx.hex()
3317 else:
3324 else:
3318 extra[b'source'] = ctx.hex()
3325 extra[b'source'] = ctx.hex()
3319 user = ctx.user()
3326 user = ctx.user()
3320 if opts.get('user'):
3327 if opts.get('user'):
3321 user = opts['user']
3328 user = opts['user']
3322 statedata[b'user'] = user
3329 statedata[b'user'] = user
3323 date = ctx.date()
3330 date = ctx.date()
3324 if opts.get('date'):
3331 if opts.get('date'):
3325 date = opts['date']
3332 date = opts['date']
3326 statedata[b'date'] = date
3333 statedata[b'date'] = date
3327 message = ctx.description()
3334 message = ctx.description()
3328 if opts.get('log'):
3335 if opts.get('log'):
3329 message += b'\n(grafted from %s)' % ctx.hex()
3336 message += b'\n(grafted from %s)' % ctx.hex()
3330 statedata[b'log'] = True
3337 statedata[b'log'] = True
3331
3338
3332 # we don't merge the first commit when continuing
3339 # we don't merge the first commit when continuing
3333 if not cont:
3340 if not cont:
3334 # perform the graft merge with p1(rev) as 'ancestor'
3341 # perform the graft merge with p1(rev) as 'ancestor'
3335 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3342 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3336 base = ctx.p1() if basectx is None else basectx
3343 base = ctx.p1() if basectx is None else basectx
3337 with ui.configoverride(overrides, b'graft'):
3344 with ui.configoverride(overrides, b'graft'):
3338 stats = mergemod.graft(
3345 stats = mergemod.graft(
3339 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3346 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3340 )
3347 )
3341 # report any conflicts
3348 # report any conflicts
3342 if stats.unresolvedcount > 0:
3349 if stats.unresolvedcount > 0:
3343 # write out state for --continue
3350 # write out state for --continue
3344 nodes = [repo[rev].hex() for rev in revs[pos:]]
3351 nodes = [repo[rev].hex() for rev in revs[pos:]]
3345 statedata[b'nodes'] = nodes
3352 statedata[b'nodes'] = nodes
3346 stateversion = 1
3353 stateversion = 1
3347 graftstate.save(stateversion, statedata)
3354 graftstate.save(stateversion, statedata)
3348 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3355 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3349 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3356 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3350 return 1
3357 return 1
3351 else:
3358 else:
3352 cont = False
3359 cont = False
3353
3360
3354 # commit if --no-commit is false
3361 # commit if --no-commit is false
3355 if not opts.get('no_commit'):
3362 if not opts.get('no_commit'):
3356 node = repo.commit(
3363 node = repo.commit(
3357 text=message, user=user, date=date, extra=extra, editor=editor
3364 text=message, user=user, date=date, extra=extra, editor=editor
3358 )
3365 )
3359 if node is None:
3366 if node is None:
3360 ui.warn(
3367 ui.warn(
3361 _(b'note: graft of %d:%s created no changes to commit\n')
3368 _(b'note: graft of %d:%s created no changes to commit\n')
3362 % (ctx.rev(), ctx)
3369 % (ctx.rev(), ctx)
3363 )
3370 )
3364 # checking that newnodes exist because old state files won't have it
3371 # checking that newnodes exist because old state files won't have it
3365 elif statedata.get(b'newnodes') is not None:
3372 elif statedata.get(b'newnodes') is not None:
3366 nn = statedata[b'newnodes']
3373 nn = statedata[b'newnodes']
3367 assert isinstance(nn, list) # list of bytes
3374 assert isinstance(nn, list) # list of bytes
3368 nn.append(node)
3375 nn.append(node)
3369
3376
3370 # remove state when we complete successfully
3377 # remove state when we complete successfully
3371 if not opts.get('dry_run'):
3378 if not opts.get('dry_run'):
3372 graftstate.delete()
3379 graftstate.delete()
3373
3380
3374 return 0
3381 return 0
3375
3382
3376
3383
3377 def _stopgraft(ui, repo, graftstate):
3384 def _stopgraft(ui, repo, graftstate):
3378 """stop the interrupted graft"""
3385 """stop the interrupted graft"""
3379 if not graftstate.exists():
3386 if not graftstate.exists():
3380 raise error.StateError(_(b"no interrupted graft found"))
3387 raise error.StateError(_(b"no interrupted graft found"))
3381 pctx = repo[b'.']
3388 pctx = repo[b'.']
3382 mergemod.clean_update(pctx)
3389 mergemod.clean_update(pctx)
3383 graftstate.delete()
3390 graftstate.delete()
3384 ui.status(_(b"stopped the interrupted graft\n"))
3391 ui.status(_(b"stopped the interrupted graft\n"))
3385 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3392 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3386 return 0
3393 return 0
3387
3394
3388
3395
3389 statemod.addunfinished(
3396 statemod.addunfinished(
3390 b'graft',
3397 b'graft',
3391 fname=b'graftstate',
3398 fname=b'graftstate',
3392 clearable=True,
3399 clearable=True,
3393 stopflag=True,
3400 stopflag=True,
3394 continueflag=True,
3401 continueflag=True,
3395 abortfunc=cmdutil.hgabortgraft,
3402 abortfunc=cmdutil.hgabortgraft,
3396 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3403 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3397 )
3404 )
3398
3405
3399
3406
3400 @command(
3407 @command(
3401 b'grep',
3408 b'grep',
3402 [
3409 [
3403 (b'0', b'print0', None, _(b'end fields with NUL')),
3410 (b'0', b'print0', None, _(b'end fields with NUL')),
3404 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3411 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3405 (
3412 (
3406 b'',
3413 b'',
3407 b'diff',
3414 b'diff',
3408 None,
3415 None,
3409 _(
3416 _(
3410 b'search revision differences for when the pattern was added '
3417 b'search revision differences for when the pattern was added '
3411 b'or removed'
3418 b'or removed'
3412 ),
3419 ),
3413 ),
3420 ),
3414 (b'a', b'text', None, _(b'treat all files as text')),
3421 (b'a', b'text', None, _(b'treat all files as text')),
3415 (
3422 (
3416 b'f',
3423 b'f',
3417 b'follow',
3424 b'follow',
3418 None,
3425 None,
3419 _(
3426 _(
3420 b'follow changeset history,'
3427 b'follow changeset history,'
3421 b' or file history across copies and renames'
3428 b' or file history across copies and renames'
3422 ),
3429 ),
3423 ),
3430 ),
3424 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3431 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3425 (
3432 (
3426 b'l',
3433 b'l',
3427 b'files-with-matches',
3434 b'files-with-matches',
3428 None,
3435 None,
3429 _(b'print only filenames and revisions that match'),
3436 _(b'print only filenames and revisions that match'),
3430 ),
3437 ),
3431 (b'n', b'line-number', None, _(b'print matching line numbers')),
3438 (b'n', b'line-number', None, _(b'print matching line numbers')),
3432 (
3439 (
3433 b'r',
3440 b'r',
3434 b'rev',
3441 b'rev',
3435 [],
3442 [],
3436 _(b'search files changed within revision range'),
3443 _(b'search files changed within revision range'),
3437 _(b'REV'),
3444 _(b'REV'),
3438 ),
3445 ),
3439 (
3446 (
3440 b'',
3447 b'',
3441 b'all-files',
3448 b'all-files',
3442 None,
3449 None,
3443 _(
3450 _(
3444 b'include all files in the changeset while grepping (DEPRECATED)'
3451 b'include all files in the changeset while grepping (DEPRECATED)'
3445 ),
3452 ),
3446 ),
3453 ),
3447 (b'u', b'user', None, _(b'list the author (long with -v)')),
3454 (b'u', b'user', None, _(b'list the author (long with -v)')),
3448 (b'd', b'date', None, _(b'list the date (short with -q)')),
3455 (b'd', b'date', None, _(b'list the date (short with -q)')),
3449 ]
3456 ]
3450 + formatteropts
3457 + formatteropts
3451 + walkopts,
3458 + walkopts,
3452 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3459 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3453 helpcategory=command.CATEGORY_FILE_CONTENTS,
3460 helpcategory=command.CATEGORY_FILE_CONTENTS,
3454 inferrepo=True,
3461 inferrepo=True,
3455 intents={INTENT_READONLY},
3462 intents={INTENT_READONLY},
3456 )
3463 )
3457 def grep(ui, repo, pattern, *pats, **opts):
3464 def grep(ui, repo, pattern, *pats, **opts):
3458 """search for a pattern in specified files
3465 """search for a pattern in specified files
3459
3466
3460 Search the working directory or revision history for a regular
3467 Search the working directory or revision history for a regular
3461 expression in the specified files for the entire repository.
3468 expression in the specified files for the entire repository.
3462
3469
3463 By default, grep searches the repository files in the working
3470 By default, grep searches the repository files in the working
3464 directory and prints the files where it finds a match. To specify
3471 directory and prints the files where it finds a match. To specify
3465 historical revisions instead of the working directory, use the
3472 historical revisions instead of the working directory, use the
3466 --rev flag.
3473 --rev flag.
3467
3474
3468 To search instead historical revision differences that contains a
3475 To search instead historical revision differences that contains a
3469 change in match status ("-" for a match that becomes a non-match,
3476 change in match status ("-" for a match that becomes a non-match,
3470 or "+" for a non-match that becomes a match), use the --diff flag.
3477 or "+" for a non-match that becomes a match), use the --diff flag.
3471
3478
3472 PATTERN can be any Python (roughly Perl-compatible) regular
3479 PATTERN can be any Python (roughly Perl-compatible) regular
3473 expression.
3480 expression.
3474
3481
3475 If no FILEs are specified and the --rev flag isn't supplied, all
3482 If no FILEs are specified and the --rev flag isn't supplied, all
3476 files in the working directory are searched. When using the --rev
3483 files in the working directory are searched. When using the --rev
3477 flag and specifying FILEs, use the --follow argument to also
3484 flag and specifying FILEs, use the --follow argument to also
3478 follow the specified FILEs across renames and copies.
3485 follow the specified FILEs across renames and copies.
3479
3486
3480 .. container:: verbose
3487 .. container:: verbose
3481
3488
3482 Template:
3489 Template:
3483
3490
3484 The following keywords are supported in addition to the common template
3491 The following keywords are supported in addition to the common template
3485 keywords and functions. See also :hg:`help templates`.
3492 keywords and functions. See also :hg:`help templates`.
3486
3493
3487 :change: String. Character denoting insertion ``+`` or removal ``-``.
3494 :change: String. Character denoting insertion ``+`` or removal ``-``.
3488 Available if ``--diff`` is specified.
3495 Available if ``--diff`` is specified.
3489 :lineno: Integer. Line number of the match.
3496 :lineno: Integer. Line number of the match.
3490 :path: String. Repository-absolute path of the file.
3497 :path: String. Repository-absolute path of the file.
3491 :texts: List of text chunks.
3498 :texts: List of text chunks.
3492
3499
3493 And each entry of ``{texts}`` provides the following sub-keywords.
3500 And each entry of ``{texts}`` provides the following sub-keywords.
3494
3501
3495 :matched: Boolean. True if the chunk matches the specified pattern.
3502 :matched: Boolean. True if the chunk matches the specified pattern.
3496 :text: String. Chunk content.
3503 :text: String. Chunk content.
3497
3504
3498 See :hg:`help templates.operators` for the list expansion syntax.
3505 See :hg:`help templates.operators` for the list expansion syntax.
3499
3506
3500 Returns 0 if a match is found, 1 otherwise.
3507 Returns 0 if a match is found, 1 otherwise.
3501
3508
3502 """
3509 """
3503 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3510 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3504 opts = pycompat.byteskwargs(opts)
3511 opts = pycompat.byteskwargs(opts)
3505 diff = opts.get(b'all') or opts.get(b'diff')
3512 diff = opts.get(b'all') or opts.get(b'diff')
3506 follow = opts.get(b'follow')
3513 follow = opts.get(b'follow')
3507 if opts.get(b'all_files') is None and not diff:
3514 if opts.get(b'all_files') is None and not diff:
3508 opts[b'all_files'] = True
3515 opts[b'all_files'] = True
3509 plaingrep = (
3516 plaingrep = (
3510 opts.get(b'all_files')
3517 opts.get(b'all_files')
3511 and not opts.get(b'rev')
3518 and not opts.get(b'rev')
3512 and not opts.get(b'follow')
3519 and not opts.get(b'follow')
3513 )
3520 )
3514 all_files = opts.get(b'all_files')
3521 all_files = opts.get(b'all_files')
3515 if plaingrep:
3522 if plaingrep:
3516 opts[b'rev'] = [b'wdir()']
3523 opts[b'rev'] = [b'wdir()']
3517
3524
3518 reflags = re.M
3525 reflags = re.M
3519 if opts.get(b'ignore_case'):
3526 if opts.get(b'ignore_case'):
3520 reflags |= re.I
3527 reflags |= re.I
3521 try:
3528 try:
3522 regexp = util.re.compile(pattern, reflags)
3529 regexp = util.re.compile(pattern, reflags)
3523 except re.error as inst:
3530 except re.error as inst:
3524 ui.warn(
3531 ui.warn(
3525 _(b"grep: invalid match pattern: %s\n")
3532 _(b"grep: invalid match pattern: %s\n")
3526 % stringutil.forcebytestr(inst)
3533 % stringutil.forcebytestr(inst)
3527 )
3534 )
3528 return 1
3535 return 1
3529 sep, eol = b':', b'\n'
3536 sep, eol = b':', b'\n'
3530 if opts.get(b'print0'):
3537 if opts.get(b'print0'):
3531 sep = eol = b'\0'
3538 sep = eol = b'\0'
3532
3539
3533 searcher = grepmod.grepsearcher(
3540 searcher = grepmod.grepsearcher(
3534 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3541 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3535 )
3542 )
3536
3543
3537 getfile = searcher._getfile
3544 getfile = searcher._getfile
3538
3545
3539 uipathfn = scmutil.getuipathfn(repo)
3546 uipathfn = scmutil.getuipathfn(repo)
3540
3547
3541 def display(fm, fn, ctx, pstates, states):
3548 def display(fm, fn, ctx, pstates, states):
3542 rev = scmutil.intrev(ctx)
3549 rev = scmutil.intrev(ctx)
3543 if fm.isplain():
3550 if fm.isplain():
3544 formatuser = ui.shortuser
3551 formatuser = ui.shortuser
3545 else:
3552 else:
3546 formatuser = pycompat.bytestr
3553 formatuser = pycompat.bytestr
3547 if ui.quiet:
3554 if ui.quiet:
3548 datefmt = b'%Y-%m-%d'
3555 datefmt = b'%Y-%m-%d'
3549 else:
3556 else:
3550 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3557 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3551 found = False
3558 found = False
3552
3559
3553 @util.cachefunc
3560 @util.cachefunc
3554 def binary():
3561 def binary():
3555 flog = getfile(fn)
3562 flog = getfile(fn)
3556 try:
3563 try:
3557 return stringutil.binary(flog.read(ctx.filenode(fn)))
3564 return stringutil.binary(flog.read(ctx.filenode(fn)))
3558 except error.WdirUnsupported:
3565 except error.WdirUnsupported:
3559 return ctx[fn].isbinary()
3566 return ctx[fn].isbinary()
3560
3567
3561 fieldnamemap = {b'linenumber': b'lineno'}
3568 fieldnamemap = {b'linenumber': b'lineno'}
3562 if diff:
3569 if diff:
3563 iter = grepmod.difflinestates(pstates, states)
3570 iter = grepmod.difflinestates(pstates, states)
3564 else:
3571 else:
3565 iter = [(b'', l) for l in states]
3572 iter = [(b'', l) for l in states]
3566 for change, l in iter:
3573 for change, l in iter:
3567 fm.startitem()
3574 fm.startitem()
3568 fm.context(ctx=ctx)
3575 fm.context(ctx=ctx)
3569 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3576 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3570 fm.plain(uipathfn(fn), label=b'grep.filename')
3577 fm.plain(uipathfn(fn), label=b'grep.filename')
3571
3578
3572 cols = [
3579 cols = [
3573 (b'rev', b'%d', rev, not plaingrep, b''),
3580 (b'rev', b'%d', rev, not plaingrep, b''),
3574 (
3581 (
3575 b'linenumber',
3582 b'linenumber',
3576 b'%d',
3583 b'%d',
3577 l.linenum,
3584 l.linenum,
3578 opts.get(b'line_number'),
3585 opts.get(b'line_number'),
3579 b'',
3586 b'',
3580 ),
3587 ),
3581 ]
3588 ]
3582 if diff:
3589 if diff:
3583 cols.append(
3590 cols.append(
3584 (
3591 (
3585 b'change',
3592 b'change',
3586 b'%s',
3593 b'%s',
3587 change,
3594 change,
3588 True,
3595 True,
3589 b'grep.inserted '
3596 b'grep.inserted '
3590 if change == b'+'
3597 if change == b'+'
3591 else b'grep.deleted ',
3598 else b'grep.deleted ',
3592 )
3599 )
3593 )
3600 )
3594 cols.extend(
3601 cols.extend(
3595 [
3602 [
3596 (
3603 (
3597 b'user',
3604 b'user',
3598 b'%s',
3605 b'%s',
3599 formatuser(ctx.user()),
3606 formatuser(ctx.user()),
3600 opts.get(b'user'),
3607 opts.get(b'user'),
3601 b'',
3608 b'',
3602 ),
3609 ),
3603 (
3610 (
3604 b'date',
3611 b'date',
3605 b'%s',
3612 b'%s',
3606 fm.formatdate(ctx.date(), datefmt),
3613 fm.formatdate(ctx.date(), datefmt),
3607 opts.get(b'date'),
3614 opts.get(b'date'),
3608 b'',
3615 b'',
3609 ),
3616 ),
3610 ]
3617 ]
3611 )
3618 )
3612 for name, fmt, data, cond, extra_label in cols:
3619 for name, fmt, data, cond, extra_label in cols:
3613 if cond:
3620 if cond:
3614 fm.plain(sep, label=b'grep.sep')
3621 fm.plain(sep, label=b'grep.sep')
3615 field = fieldnamemap.get(name, name)
3622 field = fieldnamemap.get(name, name)
3616 label = extra_label + (b'grep.%s' % name)
3623 label = extra_label + (b'grep.%s' % name)
3617 fm.condwrite(cond, field, fmt, data, label=label)
3624 fm.condwrite(cond, field, fmt, data, label=label)
3618 if not opts.get(b'files_with_matches'):
3625 if not opts.get(b'files_with_matches'):
3619 fm.plain(sep, label=b'grep.sep')
3626 fm.plain(sep, label=b'grep.sep')
3620 if not opts.get(b'text') and binary():
3627 if not opts.get(b'text') and binary():
3621 fm.plain(_(b" Binary file matches"))
3628 fm.plain(_(b" Binary file matches"))
3622 else:
3629 else:
3623 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3630 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3624 fm.plain(eol)
3631 fm.plain(eol)
3625 found = True
3632 found = True
3626 if opts.get(b'files_with_matches'):
3633 if opts.get(b'files_with_matches'):
3627 break
3634 break
3628 return found
3635 return found
3629
3636
3630 def displaymatches(fm, l):
3637 def displaymatches(fm, l):
3631 p = 0
3638 p = 0
3632 for s, e in l.findpos(regexp):
3639 for s, e in l.findpos(regexp):
3633 if p < s:
3640 if p < s:
3634 fm.startitem()
3641 fm.startitem()
3635 fm.write(b'text', b'%s', l.line[p:s])
3642 fm.write(b'text', b'%s', l.line[p:s])
3636 fm.data(matched=False)
3643 fm.data(matched=False)
3637 fm.startitem()
3644 fm.startitem()
3638 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3645 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3639 fm.data(matched=True)
3646 fm.data(matched=True)
3640 p = e
3647 p = e
3641 if p < len(l.line):
3648 if p < len(l.line):
3642 fm.startitem()
3649 fm.startitem()
3643 fm.write(b'text', b'%s', l.line[p:])
3650 fm.write(b'text', b'%s', l.line[p:])
3644 fm.data(matched=False)
3651 fm.data(matched=False)
3645 fm.end()
3652 fm.end()
3646
3653
3647 found = False
3654 found = False
3648
3655
3649 wopts = logcmdutil.walkopts(
3656 wopts = logcmdutil.walkopts(
3650 pats=pats,
3657 pats=pats,
3651 opts=opts,
3658 opts=opts,
3652 revspec=opts[b'rev'],
3659 revspec=opts[b'rev'],
3653 include_pats=opts[b'include'],
3660 include_pats=opts[b'include'],
3654 exclude_pats=opts[b'exclude'],
3661 exclude_pats=opts[b'exclude'],
3655 follow=follow,
3662 follow=follow,
3656 force_changelog_traversal=all_files,
3663 force_changelog_traversal=all_files,
3657 filter_revisions_by_pats=not all_files,
3664 filter_revisions_by_pats=not all_files,
3658 )
3665 )
3659 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3666 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3660
3667
3661 ui.pager(b'grep')
3668 ui.pager(b'grep')
3662 fm = ui.formatter(b'grep', opts)
3669 fm = ui.formatter(b'grep', opts)
3663 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3670 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3664 r = display(fm, fn, ctx, pstates, states)
3671 r = display(fm, fn, ctx, pstates, states)
3665 found = found or r
3672 found = found or r
3666 if r and not diff and not all_files:
3673 if r and not diff and not all_files:
3667 searcher.skipfile(fn, ctx.rev())
3674 searcher.skipfile(fn, ctx.rev())
3668 fm.end()
3675 fm.end()
3669
3676
3670 return not found
3677 return not found
3671
3678
3672
3679
3673 @command(
3680 @command(
3674 b'heads',
3681 b'heads',
3675 [
3682 [
3676 (
3683 (
3677 b'r',
3684 b'r',
3678 b'rev',
3685 b'rev',
3679 b'',
3686 b'',
3680 _(b'show only heads which are descendants of STARTREV'),
3687 _(b'show only heads which are descendants of STARTREV'),
3681 _(b'STARTREV'),
3688 _(b'STARTREV'),
3682 ),
3689 ),
3683 (b't', b'topo', False, _(b'show topological heads only')),
3690 (b't', b'topo', False, _(b'show topological heads only')),
3684 (
3691 (
3685 b'a',
3692 b'a',
3686 b'active',
3693 b'active',
3687 False,
3694 False,
3688 _(b'show active branchheads only (DEPRECATED)'),
3695 _(b'show active branchheads only (DEPRECATED)'),
3689 ),
3696 ),
3690 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3697 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3691 ]
3698 ]
3692 + templateopts,
3699 + templateopts,
3693 _(b'[-ct] [-r STARTREV] [REV]...'),
3700 _(b'[-ct] [-r STARTREV] [REV]...'),
3694 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3701 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3695 intents={INTENT_READONLY},
3702 intents={INTENT_READONLY},
3696 )
3703 )
3697 def heads(ui, repo, *branchrevs, **opts):
3704 def heads(ui, repo, *branchrevs, **opts):
3698 """show branch heads
3705 """show branch heads
3699
3706
3700 With no arguments, show all open branch heads in the repository.
3707 With no arguments, show all open branch heads in the repository.
3701 Branch heads are changesets that have no descendants on the
3708 Branch heads are changesets that have no descendants on the
3702 same branch. They are where development generally takes place and
3709 same branch. They are where development generally takes place and
3703 are the usual targets for update and merge operations.
3710 are the usual targets for update and merge operations.
3704
3711
3705 If one or more REVs are given, only open branch heads on the
3712 If one or more REVs are given, only open branch heads on the
3706 branches associated with the specified changesets are shown. This
3713 branches associated with the specified changesets are shown. This
3707 means that you can use :hg:`heads .` to see the heads on the
3714 means that you can use :hg:`heads .` to see the heads on the
3708 currently checked-out branch.
3715 currently checked-out branch.
3709
3716
3710 If -c/--closed is specified, also show branch heads marked closed
3717 If -c/--closed is specified, also show branch heads marked closed
3711 (see :hg:`commit --close-branch`).
3718 (see :hg:`commit --close-branch`).
3712
3719
3713 If STARTREV is specified, only those heads that are descendants of
3720 If STARTREV is specified, only those heads that are descendants of
3714 STARTREV will be displayed.
3721 STARTREV will be displayed.
3715
3722
3716 If -t/--topo is specified, named branch mechanics will be ignored and only
3723 If -t/--topo is specified, named branch mechanics will be ignored and only
3717 topological heads (changesets with no children) will be shown.
3724 topological heads (changesets with no children) will be shown.
3718
3725
3719 Returns 0 if matching heads are found, 1 if not.
3726 Returns 0 if matching heads are found, 1 if not.
3720 """
3727 """
3721
3728
3722 opts = pycompat.byteskwargs(opts)
3729 opts = pycompat.byteskwargs(opts)
3723 start = None
3730 start = None
3724 rev = opts.get(b'rev')
3731 rev = opts.get(b'rev')
3725 if rev:
3732 if rev:
3726 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3733 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3727 start = logcmdutil.revsingle(repo, rev, None).node()
3734 start = logcmdutil.revsingle(repo, rev, None).node()
3728
3735
3729 if opts.get(b'topo'):
3736 if opts.get(b'topo'):
3730 heads = [repo[h] for h in repo.heads(start)]
3737 heads = [repo[h] for h in repo.heads(start)]
3731 else:
3738 else:
3732 heads = []
3739 heads = []
3733 for branch in repo.branchmap():
3740 for branch in repo.branchmap():
3734 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3741 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3735 heads = [repo[h] for h in heads]
3742 heads = [repo[h] for h in heads]
3736
3743
3737 if branchrevs:
3744 if branchrevs:
3738 branches = {
3745 branches = {
3739 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3746 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3740 }
3747 }
3741 heads = [h for h in heads if h.branch() in branches]
3748 heads = [h for h in heads if h.branch() in branches]
3742
3749
3743 if opts.get(b'active') and branchrevs:
3750 if opts.get(b'active') and branchrevs:
3744 dagheads = repo.heads(start)
3751 dagheads = repo.heads(start)
3745 heads = [h for h in heads if h.node() in dagheads]
3752 heads = [h for h in heads if h.node() in dagheads]
3746
3753
3747 if branchrevs:
3754 if branchrevs:
3748 haveheads = {h.branch() for h in heads}
3755 haveheads = {h.branch() for h in heads}
3749 if branches - haveheads:
3756 if branches - haveheads:
3750 headless = b', '.join(b for b in branches - haveheads)
3757 headless = b', '.join(b for b in branches - haveheads)
3751 msg = _(b'no open branch heads found on branches %s')
3758 msg = _(b'no open branch heads found on branches %s')
3752 if opts.get(b'rev'):
3759 if opts.get(b'rev'):
3753 msg += _(b' (started at %s)') % opts[b'rev']
3760 msg += _(b' (started at %s)') % opts[b'rev']
3754 ui.warn((msg + b'\n') % headless)
3761 ui.warn((msg + b'\n') % headless)
3755
3762
3756 if not heads:
3763 if not heads:
3757 return 1
3764 return 1
3758
3765
3759 ui.pager(b'heads')
3766 ui.pager(b'heads')
3760 heads = sorted(heads, key=lambda x: -(x.rev()))
3767 heads = sorted(heads, key=lambda x: -(x.rev()))
3761 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3768 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3762 for ctx in heads:
3769 for ctx in heads:
3763 displayer.show(ctx)
3770 displayer.show(ctx)
3764 displayer.close()
3771 displayer.close()
3765
3772
3766
3773
3767 @command(
3774 @command(
3768 b'help',
3775 b'help',
3769 [
3776 [
3770 (b'e', b'extension', None, _(b'show only help for extensions')),
3777 (b'e', b'extension', None, _(b'show only help for extensions')),
3771 (b'c', b'command', None, _(b'show only help for commands')),
3778 (b'c', b'command', None, _(b'show only help for commands')),
3772 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3779 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3773 (
3780 (
3774 b's',
3781 b's',
3775 b'system',
3782 b'system',
3776 [],
3783 [],
3777 _(b'show help for specific platform(s)'),
3784 _(b'show help for specific platform(s)'),
3778 _(b'PLATFORM'),
3785 _(b'PLATFORM'),
3779 ),
3786 ),
3780 ],
3787 ],
3781 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3788 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3782 helpcategory=command.CATEGORY_HELP,
3789 helpcategory=command.CATEGORY_HELP,
3783 norepo=True,
3790 norepo=True,
3784 intents={INTENT_READONLY},
3791 intents={INTENT_READONLY},
3785 )
3792 )
3786 def help_(ui, name=None, **opts):
3793 def help_(ui, name=None, **opts):
3787 """show help for a given topic or a help overview
3794 """show help for a given topic or a help overview
3788
3795
3789 With no arguments, print a list of commands with short help messages.
3796 With no arguments, print a list of commands with short help messages.
3790
3797
3791 Given a topic, extension, or command name, print help for that
3798 Given a topic, extension, or command name, print help for that
3792 topic.
3799 topic.
3793
3800
3794 Returns 0 if successful.
3801 Returns 0 if successful.
3795 """
3802 """
3796
3803
3797 keep = opts.get('system') or []
3804 keep = opts.get('system') or []
3798 if len(keep) == 0:
3805 if len(keep) == 0:
3799 if pycompat.sysplatform.startswith(b'win'):
3806 if pycompat.sysplatform.startswith(b'win'):
3800 keep.append(b'windows')
3807 keep.append(b'windows')
3801 elif pycompat.sysplatform == b'OpenVMS':
3808 elif pycompat.sysplatform == b'OpenVMS':
3802 keep.append(b'vms')
3809 keep.append(b'vms')
3803 elif pycompat.sysplatform == b'plan9':
3810 elif pycompat.sysplatform == b'plan9':
3804 keep.append(b'plan9')
3811 keep.append(b'plan9')
3805 else:
3812 else:
3806 keep.append(b'unix')
3813 keep.append(b'unix')
3807 keep.append(pycompat.sysplatform.lower())
3814 keep.append(pycompat.sysplatform.lower())
3808 if ui.verbose:
3815 if ui.verbose:
3809 keep.append(b'verbose')
3816 keep.append(b'verbose')
3810
3817
3811 commands = sys.modules[__name__]
3818 commands = sys.modules[__name__]
3812 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3819 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3813 ui.pager(b'help')
3820 ui.pager(b'help')
3814 ui.write(formatted)
3821 ui.write(formatted)
3815
3822
3816
3823
3817 @command(
3824 @command(
3818 b'identify|id',
3825 b'identify|id',
3819 [
3826 [
3820 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3827 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3821 (b'n', b'num', None, _(b'show local revision number')),
3828 (b'n', b'num', None, _(b'show local revision number')),
3822 (b'i', b'id', None, _(b'show global revision id')),
3829 (b'i', b'id', None, _(b'show global revision id')),
3823 (b'b', b'branch', None, _(b'show branch')),
3830 (b'b', b'branch', None, _(b'show branch')),
3824 (b't', b'tags', None, _(b'show tags')),
3831 (b't', b'tags', None, _(b'show tags')),
3825 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3832 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3826 ]
3833 ]
3827 + remoteopts
3834 + remoteopts
3828 + formatteropts,
3835 + formatteropts,
3829 _(b'[-nibtB] [-r REV] [SOURCE]'),
3836 _(b'[-nibtB] [-r REV] [SOURCE]'),
3830 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3837 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3831 optionalrepo=True,
3838 optionalrepo=True,
3832 intents={INTENT_READONLY},
3839 intents={INTENT_READONLY},
3833 )
3840 )
3834 def identify(
3841 def identify(
3835 ui,
3842 ui,
3836 repo,
3843 repo,
3837 source=None,
3844 source=None,
3838 rev=None,
3845 rev=None,
3839 num=None,
3846 num=None,
3840 id=None,
3847 id=None,
3841 branch=None,
3848 branch=None,
3842 tags=None,
3849 tags=None,
3843 bookmarks=None,
3850 bookmarks=None,
3844 **opts
3851 **opts
3845 ):
3852 ):
3846 """identify the working directory or specified revision
3853 """identify the working directory or specified revision
3847
3854
3848 Print a summary identifying the repository state at REV using one or
3855 Print a summary identifying the repository state at REV using one or
3849 two parent hash identifiers, followed by a "+" if the working
3856 two parent hash identifiers, followed by a "+" if the working
3850 directory has uncommitted changes, the branch name (if not default),
3857 directory has uncommitted changes, the branch name (if not default),
3851 a list of tags, and a list of bookmarks.
3858 a list of tags, and a list of bookmarks.
3852
3859
3853 When REV is not given, print a summary of the current state of the
3860 When REV is not given, print a summary of the current state of the
3854 repository including the working directory. Specify -r. to get information
3861 repository including the working directory. Specify -r. to get information
3855 of the working directory parent without scanning uncommitted changes.
3862 of the working directory parent without scanning uncommitted changes.
3856
3863
3857 Specifying a path to a repository root or Mercurial bundle will
3864 Specifying a path to a repository root or Mercurial bundle will
3858 cause lookup to operate on that repository/bundle.
3865 cause lookup to operate on that repository/bundle.
3859
3866
3860 .. container:: verbose
3867 .. container:: verbose
3861
3868
3862 Template:
3869 Template:
3863
3870
3864 The following keywords are supported in addition to the common template
3871 The following keywords are supported in addition to the common template
3865 keywords and functions. See also :hg:`help templates`.
3872 keywords and functions. See also :hg:`help templates`.
3866
3873
3867 :dirty: String. Character ``+`` denoting if the working directory has
3874 :dirty: String. Character ``+`` denoting if the working directory has
3868 uncommitted changes.
3875 uncommitted changes.
3869 :id: String. One or two nodes, optionally followed by ``+``.
3876 :id: String. One or two nodes, optionally followed by ``+``.
3870 :parents: List of strings. Parent nodes of the changeset.
3877 :parents: List of strings. Parent nodes of the changeset.
3871
3878
3872 Examples:
3879 Examples:
3873
3880
3874 - generate a build identifier for the working directory::
3881 - generate a build identifier for the working directory::
3875
3882
3876 hg id --id > build-id.dat
3883 hg id --id > build-id.dat
3877
3884
3878 - find the revision corresponding to a tag::
3885 - find the revision corresponding to a tag::
3879
3886
3880 hg id -n -r 1.3
3887 hg id -n -r 1.3
3881
3888
3882 - check the most recent revision of a remote repository::
3889 - check the most recent revision of a remote repository::
3883
3890
3884 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3891 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3885
3892
3886 See :hg:`log` for generating more information about specific revisions,
3893 See :hg:`log` for generating more information about specific revisions,
3887 including full hash identifiers.
3894 including full hash identifiers.
3888
3895
3889 Returns 0 if successful.
3896 Returns 0 if successful.
3890 """
3897 """
3891
3898
3892 opts = pycompat.byteskwargs(opts)
3899 opts = pycompat.byteskwargs(opts)
3893 if not repo and not source:
3900 if not repo and not source:
3894 raise error.InputError(
3901 raise error.InputError(
3895 _(b"there is no Mercurial repository here (.hg not found)")
3902 _(b"there is no Mercurial repository here (.hg not found)")
3896 )
3903 )
3897
3904
3898 default = not (num or id or branch or tags or bookmarks)
3905 default = not (num or id or branch or tags or bookmarks)
3899 output = []
3906 output = []
3900 revs = []
3907 revs = []
3901
3908
3902 peer = None
3909 peer = None
3903 try:
3910 try:
3904 if source:
3911 if source:
3905 source, branches = urlutil.get_unique_pull_path(
3912 source, branches = urlutil.get_unique_pull_path(
3906 b'identify', repo, ui, source
3913 b'identify', repo, ui, source
3907 )
3914 )
3908 # only pass ui when no repo
3915 # only pass ui when no repo
3909 peer = hg.peer(repo or ui, opts, source)
3916 peer = hg.peer(repo or ui, opts, source)
3910 repo = peer.local()
3917 repo = peer.local()
3911 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3918 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3912
3919
3913 fm = ui.formatter(b'identify', opts)
3920 fm = ui.formatter(b'identify', opts)
3914 fm.startitem()
3921 fm.startitem()
3915
3922
3916 if not repo:
3923 if not repo:
3917 if num or branch or tags:
3924 if num or branch or tags:
3918 raise error.InputError(
3925 raise error.InputError(
3919 _(b"can't query remote revision number, branch, or tags")
3926 _(b"can't query remote revision number, branch, or tags")
3920 )
3927 )
3921 if not rev and revs:
3928 if not rev and revs:
3922 rev = revs[0]
3929 rev = revs[0]
3923 if not rev:
3930 if not rev:
3924 rev = b"tip"
3931 rev = b"tip"
3925
3932
3926 remoterev = peer.lookup(rev)
3933 remoterev = peer.lookup(rev)
3927 hexrev = fm.hexfunc(remoterev)
3934 hexrev = fm.hexfunc(remoterev)
3928 if default or id:
3935 if default or id:
3929 output = [hexrev]
3936 output = [hexrev]
3930 fm.data(id=hexrev)
3937 fm.data(id=hexrev)
3931
3938
3932 @util.cachefunc
3939 @util.cachefunc
3933 def getbms():
3940 def getbms():
3934 bms = []
3941 bms = []
3935
3942
3936 if b'bookmarks' in peer.listkeys(b'namespaces'):
3943 if b'bookmarks' in peer.listkeys(b'namespaces'):
3937 hexremoterev = hex(remoterev)
3944 hexremoterev = hex(remoterev)
3938 bms = [
3945 bms = [
3939 bm
3946 bm
3940 for bm, bmr in peer.listkeys(b'bookmarks').items()
3947 for bm, bmr in peer.listkeys(b'bookmarks').items()
3941 if bmr == hexremoterev
3948 if bmr == hexremoterev
3942 ]
3949 ]
3943
3950
3944 return sorted(bms)
3951 return sorted(bms)
3945
3952
3946 if fm.isplain():
3953 if fm.isplain():
3947 if bookmarks:
3954 if bookmarks:
3948 output.extend(getbms())
3955 output.extend(getbms())
3949 elif default and not ui.quiet:
3956 elif default and not ui.quiet:
3950 # multiple bookmarks for a single parent separated by '/'
3957 # multiple bookmarks for a single parent separated by '/'
3951 bm = b'/'.join(getbms())
3958 bm = b'/'.join(getbms())
3952 if bm:
3959 if bm:
3953 output.append(bm)
3960 output.append(bm)
3954 else:
3961 else:
3955 fm.data(node=hex(remoterev))
3962 fm.data(node=hex(remoterev))
3956 if bookmarks or b'bookmarks' in fm.datahint():
3963 if bookmarks or b'bookmarks' in fm.datahint():
3957 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3964 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3958 else:
3965 else:
3959 if rev:
3966 if rev:
3960 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3967 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3961 ctx = logcmdutil.revsingle(repo, rev, None)
3968 ctx = logcmdutil.revsingle(repo, rev, None)
3962
3969
3963 if ctx.rev() is None:
3970 if ctx.rev() is None:
3964 ctx = repo[None]
3971 ctx = repo[None]
3965 parents = ctx.parents()
3972 parents = ctx.parents()
3966 taglist = []
3973 taglist = []
3967 for p in parents:
3974 for p in parents:
3968 taglist.extend(p.tags())
3975 taglist.extend(p.tags())
3969
3976
3970 dirty = b""
3977 dirty = b""
3971 if ctx.dirty(missing=True, merge=False, branch=False):
3978 if ctx.dirty(missing=True, merge=False, branch=False):
3972 dirty = b'+'
3979 dirty = b'+'
3973 fm.data(dirty=dirty)
3980 fm.data(dirty=dirty)
3974
3981
3975 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3982 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3976 if default or id:
3983 if default or id:
3977 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3984 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3978 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3985 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3979
3986
3980 if num:
3987 if num:
3981 numoutput = [b"%d" % p.rev() for p in parents]
3988 numoutput = [b"%d" % p.rev() for p in parents]
3982 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3989 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3983
3990
3984 fm.data(
3991 fm.data(
3985 parents=fm.formatlist(
3992 parents=fm.formatlist(
3986 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3993 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3987 )
3994 )
3988 )
3995 )
3989 else:
3996 else:
3990 hexoutput = fm.hexfunc(ctx.node())
3997 hexoutput = fm.hexfunc(ctx.node())
3991 if default or id:
3998 if default or id:
3992 output = [hexoutput]
3999 output = [hexoutput]
3993 fm.data(id=hexoutput)
4000 fm.data(id=hexoutput)
3994
4001
3995 if num:
4002 if num:
3996 output.append(pycompat.bytestr(ctx.rev()))
4003 output.append(pycompat.bytestr(ctx.rev()))
3997 taglist = ctx.tags()
4004 taglist = ctx.tags()
3998
4005
3999 if default and not ui.quiet:
4006 if default and not ui.quiet:
4000 b = ctx.branch()
4007 b = ctx.branch()
4001 if b != b'default':
4008 if b != b'default':
4002 output.append(b"(%s)" % b)
4009 output.append(b"(%s)" % b)
4003
4010
4004 # multiple tags for a single parent separated by '/'
4011 # multiple tags for a single parent separated by '/'
4005 t = b'/'.join(taglist)
4012 t = b'/'.join(taglist)
4006 if t:
4013 if t:
4007 output.append(t)
4014 output.append(t)
4008
4015
4009 # multiple bookmarks for a single parent separated by '/'
4016 # multiple bookmarks for a single parent separated by '/'
4010 bm = b'/'.join(ctx.bookmarks())
4017 bm = b'/'.join(ctx.bookmarks())
4011 if bm:
4018 if bm:
4012 output.append(bm)
4019 output.append(bm)
4013 else:
4020 else:
4014 if branch:
4021 if branch:
4015 output.append(ctx.branch())
4022 output.append(ctx.branch())
4016
4023
4017 if tags:
4024 if tags:
4018 output.extend(taglist)
4025 output.extend(taglist)
4019
4026
4020 if bookmarks:
4027 if bookmarks:
4021 output.extend(ctx.bookmarks())
4028 output.extend(ctx.bookmarks())
4022
4029
4023 fm.data(node=ctx.hex())
4030 fm.data(node=ctx.hex())
4024 fm.data(branch=ctx.branch())
4031 fm.data(branch=ctx.branch())
4025 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4032 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4026 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4033 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4027 fm.context(ctx=ctx)
4034 fm.context(ctx=ctx)
4028
4035
4029 fm.plain(b"%s\n" % b' '.join(output))
4036 fm.plain(b"%s\n" % b' '.join(output))
4030 fm.end()
4037 fm.end()
4031 finally:
4038 finally:
4032 if peer:
4039 if peer:
4033 peer.close()
4040 peer.close()
4034
4041
4035
4042
4036 @command(
4043 @command(
4037 b'import|patch',
4044 b'import|patch',
4038 [
4045 [
4039 (
4046 (
4040 b'p',
4047 b'p',
4041 b'strip',
4048 b'strip',
4042 1,
4049 1,
4043 _(
4050 _(
4044 b'directory strip option for patch. This has the same '
4051 b'directory strip option for patch. This has the same '
4045 b'meaning as the corresponding patch option'
4052 b'meaning as the corresponding patch option'
4046 ),
4053 ),
4047 _(b'NUM'),
4054 _(b'NUM'),
4048 ),
4055 ),
4049 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4056 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4050 (b'', b'secret', None, _(b'use the secret phase for committing')),
4057 (b'', b'secret', None, _(b'use the secret phase for committing')),
4051 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4058 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4052 (
4059 (
4053 b'f',
4060 b'f',
4054 b'force',
4061 b'force',
4055 None,
4062 None,
4056 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4063 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4057 ),
4064 ),
4058 (
4065 (
4059 b'',
4066 b'',
4060 b'no-commit',
4067 b'no-commit',
4061 None,
4068 None,
4062 _(b"don't commit, just update the working directory"),
4069 _(b"don't commit, just update the working directory"),
4063 ),
4070 ),
4064 (
4071 (
4065 b'',
4072 b'',
4066 b'bypass',
4073 b'bypass',
4067 None,
4074 None,
4068 _(b"apply patch without touching the working directory"),
4075 _(b"apply patch without touching the working directory"),
4069 ),
4076 ),
4070 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4077 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4071 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4078 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4072 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4079 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4073 (
4080 (
4074 b'',
4081 b'',
4075 b'import-branch',
4082 b'import-branch',
4076 None,
4083 None,
4077 _(b'use any branch information in patch (implied by --exact)'),
4084 _(b'use any branch information in patch (implied by --exact)'),
4078 ),
4085 ),
4079 ]
4086 ]
4080 + commitopts
4087 + commitopts
4081 + commitopts2
4088 + commitopts2
4082 + similarityopts,
4089 + similarityopts,
4083 _(b'[OPTION]... PATCH...'),
4090 _(b'[OPTION]... PATCH...'),
4084 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4091 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4085 )
4092 )
4086 def import_(ui, repo, patch1=None, *patches, **opts):
4093 def import_(ui, repo, patch1=None, *patches, **opts):
4087 """import an ordered set of patches
4094 """import an ordered set of patches
4088
4095
4089 Import a list of patches and commit them individually (unless
4096 Import a list of patches and commit them individually (unless
4090 --no-commit is specified).
4097 --no-commit is specified).
4091
4098
4092 To read a patch from standard input (stdin), use "-" as the patch
4099 To read a patch from standard input (stdin), use "-" as the patch
4093 name. If a URL is specified, the patch will be downloaded from
4100 name. If a URL is specified, the patch will be downloaded from
4094 there.
4101 there.
4095
4102
4096 Import first applies changes to the working directory (unless
4103 Import first applies changes to the working directory (unless
4097 --bypass is specified), import will abort if there are outstanding
4104 --bypass is specified), import will abort if there are outstanding
4098 changes.
4105 changes.
4099
4106
4100 Use --bypass to apply and commit patches directly to the
4107 Use --bypass to apply and commit patches directly to the
4101 repository, without affecting the working directory. Without
4108 repository, without affecting the working directory. Without
4102 --exact, patches will be applied on top of the working directory
4109 --exact, patches will be applied on top of the working directory
4103 parent revision.
4110 parent revision.
4104
4111
4105 You can import a patch straight from a mail message. Even patches
4112 You can import a patch straight from a mail message. Even patches
4106 as attachments work (to use the body part, it must have type
4113 as attachments work (to use the body part, it must have type
4107 text/plain or text/x-patch). From and Subject headers of email
4114 text/plain or text/x-patch). From and Subject headers of email
4108 message are used as default committer and commit message. All
4115 message are used as default committer and commit message. All
4109 text/plain body parts before first diff are added to the commit
4116 text/plain body parts before first diff are added to the commit
4110 message.
4117 message.
4111
4118
4112 If the imported patch was generated by :hg:`export`, user and
4119 If the imported patch was generated by :hg:`export`, user and
4113 description from patch override values from message headers and
4120 description from patch override values from message headers and
4114 body. Values given on command line with -m/--message and -u/--user
4121 body. Values given on command line with -m/--message and -u/--user
4115 override these.
4122 override these.
4116
4123
4117 If --exact is specified, import will set the working directory to
4124 If --exact is specified, import will set the working directory to
4118 the parent of each patch before applying it, and will abort if the
4125 the parent of each patch before applying it, and will abort if the
4119 resulting changeset has a different ID than the one recorded in
4126 resulting changeset has a different ID than the one recorded in
4120 the patch. This will guard against various ways that portable
4127 the patch. This will guard against various ways that portable
4121 patch formats and mail systems might fail to transfer Mercurial
4128 patch formats and mail systems might fail to transfer Mercurial
4122 data or metadata. See :hg:`bundle` for lossless transmission.
4129 data or metadata. See :hg:`bundle` for lossless transmission.
4123
4130
4124 Use --partial to ensure a changeset will be created from the patch
4131 Use --partial to ensure a changeset will be created from the patch
4125 even if some hunks fail to apply. Hunks that fail to apply will be
4132 even if some hunks fail to apply. Hunks that fail to apply will be
4126 written to a <target-file>.rej file. Conflicts can then be resolved
4133 written to a <target-file>.rej file. Conflicts can then be resolved
4127 by hand before :hg:`commit --amend` is run to update the created
4134 by hand before :hg:`commit --amend` is run to update the created
4128 changeset. This flag exists to let people import patches that
4135 changeset. This flag exists to let people import patches that
4129 partially apply without losing the associated metadata (author,
4136 partially apply without losing the associated metadata (author,
4130 date, description, ...).
4137 date, description, ...).
4131
4138
4132 .. note::
4139 .. note::
4133
4140
4134 When no hunks apply cleanly, :hg:`import --partial` will create
4141 When no hunks apply cleanly, :hg:`import --partial` will create
4135 an empty changeset, importing only the patch metadata.
4142 an empty changeset, importing only the patch metadata.
4136
4143
4137 With -s/--similarity, hg will attempt to discover renames and
4144 With -s/--similarity, hg will attempt to discover renames and
4138 copies in the patch in the same way as :hg:`addremove`.
4145 copies in the patch in the same way as :hg:`addremove`.
4139
4146
4140 It is possible to use external patch programs to perform the patch
4147 It is possible to use external patch programs to perform the patch
4141 by setting the ``ui.patch`` configuration option. For the default
4148 by setting the ``ui.patch`` configuration option. For the default
4142 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4149 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4143 See :hg:`help config` for more information about configuration
4150 See :hg:`help config` for more information about configuration
4144 files and how to use these options.
4151 files and how to use these options.
4145
4152
4146 See :hg:`help dates` for a list of formats valid for -d/--date.
4153 See :hg:`help dates` for a list of formats valid for -d/--date.
4147
4154
4148 .. container:: verbose
4155 .. container:: verbose
4149
4156
4150 Examples:
4157 Examples:
4151
4158
4152 - import a traditional patch from a website and detect renames::
4159 - import a traditional patch from a website and detect renames::
4153
4160
4154 hg import -s 80 http://example.com/bugfix.patch
4161 hg import -s 80 http://example.com/bugfix.patch
4155
4162
4156 - import a changeset from an hgweb server::
4163 - import a changeset from an hgweb server::
4157
4164
4158 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4165 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4159
4166
4160 - import all the patches in an Unix-style mbox::
4167 - import all the patches in an Unix-style mbox::
4161
4168
4162 hg import incoming-patches.mbox
4169 hg import incoming-patches.mbox
4163
4170
4164 - import patches from stdin::
4171 - import patches from stdin::
4165
4172
4166 hg import -
4173 hg import -
4167
4174
4168 - attempt to exactly restore an exported changeset (not always
4175 - attempt to exactly restore an exported changeset (not always
4169 possible)::
4176 possible)::
4170
4177
4171 hg import --exact proposed-fix.patch
4178 hg import --exact proposed-fix.patch
4172
4179
4173 - use an external tool to apply a patch which is too fuzzy for
4180 - use an external tool to apply a patch which is too fuzzy for
4174 the default internal tool.
4181 the default internal tool.
4175
4182
4176 hg import --config ui.patch="patch --merge" fuzzy.patch
4183 hg import --config ui.patch="patch --merge" fuzzy.patch
4177
4184
4178 - change the default fuzzing from 2 to a less strict 7
4185 - change the default fuzzing from 2 to a less strict 7
4179
4186
4180 hg import --config ui.fuzz=7 fuzz.patch
4187 hg import --config ui.fuzz=7 fuzz.patch
4181
4188
4182 Returns 0 on success, 1 on partial success (see --partial).
4189 Returns 0 on success, 1 on partial success (see --partial).
4183 """
4190 """
4184
4191
4185 cmdutil.check_incompatible_arguments(
4192 cmdutil.check_incompatible_arguments(
4186 opts, 'no_commit', ['bypass', 'secret']
4193 opts, 'no_commit', ['bypass', 'secret']
4187 )
4194 )
4188 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4195 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4189 opts = pycompat.byteskwargs(opts)
4196 opts = pycompat.byteskwargs(opts)
4190 if not patch1:
4197 if not patch1:
4191 raise error.InputError(_(b'need at least one patch to import'))
4198 raise error.InputError(_(b'need at least one patch to import'))
4192
4199
4193 patches = (patch1,) + patches
4200 patches = (patch1,) + patches
4194
4201
4195 date = opts.get(b'date')
4202 date = opts.get(b'date')
4196 if date:
4203 if date:
4197 opts[b'date'] = dateutil.parsedate(date)
4204 opts[b'date'] = dateutil.parsedate(date)
4198
4205
4199 exact = opts.get(b'exact')
4206 exact = opts.get(b'exact')
4200 update = not opts.get(b'bypass')
4207 update = not opts.get(b'bypass')
4201 try:
4208 try:
4202 sim = float(opts.get(b'similarity') or 0)
4209 sim = float(opts.get(b'similarity') or 0)
4203 except ValueError:
4210 except ValueError:
4204 raise error.InputError(_(b'similarity must be a number'))
4211 raise error.InputError(_(b'similarity must be a number'))
4205 if sim < 0 or sim > 100:
4212 if sim < 0 or sim > 100:
4206 raise error.InputError(_(b'similarity must be between 0 and 100'))
4213 raise error.InputError(_(b'similarity must be between 0 and 100'))
4207 if sim and not update:
4214 if sim and not update:
4208 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4215 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4209
4216
4210 base = opts[b"base"]
4217 base = opts[b"base"]
4211 msgs = []
4218 msgs = []
4212 ret = 0
4219 ret = 0
4213
4220
4214 with repo.wlock():
4221 with repo.wlock():
4215 if update:
4222 if update:
4216 cmdutil.checkunfinished(repo)
4223 cmdutil.checkunfinished(repo)
4217 if exact or not opts.get(b'force'):
4224 if exact or not opts.get(b'force'):
4218 cmdutil.bailifchanged(repo)
4225 cmdutil.bailifchanged(repo)
4219
4226
4220 if not opts.get(b'no_commit'):
4227 if not opts.get(b'no_commit'):
4221 lock = repo.lock
4228 lock = repo.lock
4222 tr = lambda: repo.transaction(b'import')
4229 tr = lambda: repo.transaction(b'import')
4223 dsguard = util.nullcontextmanager
4230 dsguard = util.nullcontextmanager
4224 else:
4231 else:
4225 lock = util.nullcontextmanager
4232 lock = util.nullcontextmanager
4226 tr = util.nullcontextmanager
4233 tr = util.nullcontextmanager
4227 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4234 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4228 with lock(), tr(), dsguard():
4235 with lock(), tr(), dsguard():
4229 parents = repo[None].parents()
4236 parents = repo[None].parents()
4230 for patchurl in patches:
4237 for patchurl in patches:
4231 if patchurl == b'-':
4238 if patchurl == b'-':
4232 ui.status(_(b'applying patch from stdin\n'))
4239 ui.status(_(b'applying patch from stdin\n'))
4233 patchfile = ui.fin
4240 patchfile = ui.fin
4234 patchurl = b'stdin' # for error message
4241 patchurl = b'stdin' # for error message
4235 else:
4242 else:
4236 patchurl = os.path.join(base, patchurl)
4243 patchurl = os.path.join(base, patchurl)
4237 ui.status(_(b'applying %s\n') % patchurl)
4244 ui.status(_(b'applying %s\n') % patchurl)
4238 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4245 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4239
4246
4240 haspatch = False
4247 haspatch = False
4241 for hunk in patch.split(patchfile):
4248 for hunk in patch.split(patchfile):
4242 with patch.extract(ui, hunk) as patchdata:
4249 with patch.extract(ui, hunk) as patchdata:
4243 msg, node, rej = cmdutil.tryimportone(
4250 msg, node, rej = cmdutil.tryimportone(
4244 ui, repo, patchdata, parents, opts, msgs, hg.clean
4251 ui, repo, patchdata, parents, opts, msgs, hg.clean
4245 )
4252 )
4246 if msg:
4253 if msg:
4247 haspatch = True
4254 haspatch = True
4248 ui.note(msg + b'\n')
4255 ui.note(msg + b'\n')
4249 if update or exact:
4256 if update or exact:
4250 parents = repo[None].parents()
4257 parents = repo[None].parents()
4251 else:
4258 else:
4252 parents = [repo[node]]
4259 parents = [repo[node]]
4253 if rej:
4260 if rej:
4254 ui.write_err(_(b"patch applied partially\n"))
4261 ui.write_err(_(b"patch applied partially\n"))
4255 ui.write_err(
4262 ui.write_err(
4256 _(
4263 _(
4257 b"(fix the .rej files and run "
4264 b"(fix the .rej files and run "
4258 b"`hg commit --amend`)\n"
4265 b"`hg commit --amend`)\n"
4259 )
4266 )
4260 )
4267 )
4261 ret = 1
4268 ret = 1
4262 break
4269 break
4263
4270
4264 if not haspatch:
4271 if not haspatch:
4265 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4272 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4266
4273
4267 if msgs:
4274 if msgs:
4268 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4275 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4269 return ret
4276 return ret
4270
4277
4271
4278
4272 @command(
4279 @command(
4273 b'incoming|in',
4280 b'incoming|in',
4274 [
4281 [
4275 (
4282 (
4276 b'f',
4283 b'f',
4277 b'force',
4284 b'force',
4278 None,
4285 None,
4279 _(b'run even if remote repository is unrelated'),
4286 _(b'run even if remote repository is unrelated'),
4280 ),
4287 ),
4281 (b'n', b'newest-first', None, _(b'show newest record first')),
4288 (b'n', b'newest-first', None, _(b'show newest record first')),
4282 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4289 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4283 (
4290 (
4284 b'r',
4291 b'r',
4285 b'rev',
4292 b'rev',
4286 [],
4293 [],
4287 _(b'a remote changeset intended to be added'),
4294 _(b'a remote changeset intended to be added'),
4288 _(b'REV'),
4295 _(b'REV'),
4289 ),
4296 ),
4290 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4297 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4291 (
4298 (
4292 b'b',
4299 b'b',
4293 b'branch',
4300 b'branch',
4294 [],
4301 [],
4295 _(b'a specific branch you would like to pull'),
4302 _(b'a specific branch you would like to pull'),
4296 _(b'BRANCH'),
4303 _(b'BRANCH'),
4297 ),
4304 ),
4298 ]
4305 ]
4299 + logopts
4306 + logopts
4300 + remoteopts
4307 + remoteopts
4301 + subrepoopts,
4308 + subrepoopts,
4302 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4309 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4303 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4310 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4304 )
4311 )
4305 def incoming(ui, repo, source=b"default", **opts):
4312 def incoming(ui, repo, source=b"default", **opts):
4306 """show new changesets found in source
4313 """show new changesets found in source
4307
4314
4308 Show new changesets found in the specified path/URL or the default
4315 Show new changesets found in the specified path/URL or the default
4309 pull location. These are the changesets that would have been pulled
4316 pull location. These are the changesets that would have been pulled
4310 by :hg:`pull` at the time you issued this command.
4317 by :hg:`pull` at the time you issued this command.
4311
4318
4312 See pull for valid source format details.
4319 See pull for valid source format details.
4313
4320
4314 .. container:: verbose
4321 .. container:: verbose
4315
4322
4316 With -B/--bookmarks, the result of bookmark comparison between
4323 With -B/--bookmarks, the result of bookmark comparison between
4317 local and remote repositories is displayed. With -v/--verbose,
4324 local and remote repositories is displayed. With -v/--verbose,
4318 status is also displayed for each bookmark like below::
4325 status is also displayed for each bookmark like below::
4319
4326
4320 BM1 01234567890a added
4327 BM1 01234567890a added
4321 BM2 1234567890ab advanced
4328 BM2 1234567890ab advanced
4322 BM3 234567890abc diverged
4329 BM3 234567890abc diverged
4323 BM4 34567890abcd changed
4330 BM4 34567890abcd changed
4324
4331
4325 The action taken locally when pulling depends on the
4332 The action taken locally when pulling depends on the
4326 status of each bookmark:
4333 status of each bookmark:
4327
4334
4328 :``added``: pull will create it
4335 :``added``: pull will create it
4329 :``advanced``: pull will update it
4336 :``advanced``: pull will update it
4330 :``diverged``: pull will create a divergent bookmark
4337 :``diverged``: pull will create a divergent bookmark
4331 :``changed``: result depends on remote changesets
4338 :``changed``: result depends on remote changesets
4332
4339
4333 From the point of view of pulling behavior, bookmark
4340 From the point of view of pulling behavior, bookmark
4334 existing only in the remote repository are treated as ``added``,
4341 existing only in the remote repository are treated as ``added``,
4335 even if it is in fact locally deleted.
4342 even if it is in fact locally deleted.
4336
4343
4337 .. container:: verbose
4344 .. container:: verbose
4338
4345
4339 For remote repository, using --bundle avoids downloading the
4346 For remote repository, using --bundle avoids downloading the
4340 changesets twice if the incoming is followed by a pull.
4347 changesets twice if the incoming is followed by a pull.
4341
4348
4342 Examples:
4349 Examples:
4343
4350
4344 - show incoming changes with patches and full description::
4351 - show incoming changes with patches and full description::
4345
4352
4346 hg incoming -vp
4353 hg incoming -vp
4347
4354
4348 - show incoming changes excluding merges, store a bundle::
4355 - show incoming changes excluding merges, store a bundle::
4349
4356
4350 hg in -vpM --bundle incoming.hg
4357 hg in -vpM --bundle incoming.hg
4351 hg pull incoming.hg
4358 hg pull incoming.hg
4352
4359
4353 - briefly list changes inside a bundle::
4360 - briefly list changes inside a bundle::
4354
4361
4355 hg in changes.hg -T "{desc|firstline}\\n"
4362 hg in changes.hg -T "{desc|firstline}\\n"
4356
4363
4357 Returns 0 if there are incoming changes, 1 otherwise.
4364 Returns 0 if there are incoming changes, 1 otherwise.
4358 """
4365 """
4359 opts = pycompat.byteskwargs(opts)
4366 opts = pycompat.byteskwargs(opts)
4360 if opts.get(b'graph'):
4367 if opts.get(b'graph'):
4361 logcmdutil.checkunsupportedgraphflags([], opts)
4368 logcmdutil.checkunsupportedgraphflags([], opts)
4362
4369
4363 def display(other, chlist, displayer):
4370 def display(other, chlist, displayer):
4364 revdag = logcmdutil.graphrevs(other, chlist, opts)
4371 revdag = logcmdutil.graphrevs(other, chlist, opts)
4365 logcmdutil.displaygraph(
4372 logcmdutil.displaygraph(
4366 ui, repo, revdag, displayer, graphmod.asciiedges
4373 ui, repo, revdag, displayer, graphmod.asciiedges
4367 )
4374 )
4368
4375
4369 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4376 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4370 return 0
4377 return 0
4371
4378
4372 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4379 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4373
4380
4374 if opts.get(b'bookmarks'):
4381 if opts.get(b'bookmarks'):
4375 srcs = urlutil.get_pull_paths(repo, ui, [source])
4382 srcs = urlutil.get_pull_paths(repo, ui, [source])
4376 for path in srcs:
4383 for path in srcs:
4377 source, branches = urlutil.parseurl(
4384 source, branches = urlutil.parseurl(
4378 path.rawloc, opts.get(b'branch')
4385 path.rawloc, opts.get(b'branch')
4379 )
4386 )
4380 other = hg.peer(repo, opts, source)
4387 other = hg.peer(repo, opts, source)
4381 try:
4388 try:
4382 if b'bookmarks' not in other.listkeys(b'namespaces'):
4389 if b'bookmarks' not in other.listkeys(b'namespaces'):
4383 ui.warn(_(b"remote doesn't support bookmarks\n"))
4390 ui.warn(_(b"remote doesn't support bookmarks\n"))
4384 return 0
4391 return 0
4385 ui.pager(b'incoming')
4392 ui.pager(b'incoming')
4386 ui.status(
4393 ui.status(
4387 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4394 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4388 )
4395 )
4389 return bookmarks.incoming(
4396 return bookmarks.incoming(
4390 ui, repo, other, mode=path.bookmarks_mode
4397 ui, repo, other, mode=path.bookmarks_mode
4391 )
4398 )
4392 finally:
4399 finally:
4393 other.close()
4400 other.close()
4394
4401
4395 return hg.incoming(ui, repo, source, opts)
4402 return hg.incoming(ui, repo, source, opts)
4396
4403
4397
4404
4398 @command(
4405 @command(
4399 b'init',
4406 b'init',
4400 remoteopts,
4407 remoteopts,
4401 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4408 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4402 helpcategory=command.CATEGORY_REPO_CREATION,
4409 helpcategory=command.CATEGORY_REPO_CREATION,
4403 helpbasic=True,
4410 helpbasic=True,
4404 norepo=True,
4411 norepo=True,
4405 )
4412 )
4406 def init(ui, dest=b".", **opts):
4413 def init(ui, dest=b".", **opts):
4407 """create a new repository in the given directory
4414 """create a new repository in the given directory
4408
4415
4409 Initialize a new repository in the given directory. If the given
4416 Initialize a new repository in the given directory. If the given
4410 directory does not exist, it will be created.
4417 directory does not exist, it will be created.
4411
4418
4412 If no directory is given, the current directory is used.
4419 If no directory is given, the current directory is used.
4413
4420
4414 It is possible to specify an ``ssh://`` URL as the destination.
4421 It is possible to specify an ``ssh://`` URL as the destination.
4415 See :hg:`help urls` for more information.
4422 See :hg:`help urls` for more information.
4416
4423
4417 Returns 0 on success.
4424 Returns 0 on success.
4418 """
4425 """
4419 opts = pycompat.byteskwargs(opts)
4426 opts = pycompat.byteskwargs(opts)
4420 path = urlutil.get_clone_path(ui, dest)[1]
4427 path = urlutil.get_clone_path(ui, dest)[1]
4421 peer = hg.peer(ui, opts, path, create=True)
4428 peer = hg.peer(ui, opts, path, create=True)
4422 peer.close()
4429 peer.close()
4423
4430
4424
4431
4425 @command(
4432 @command(
4426 b'locate',
4433 b'locate',
4427 [
4434 [
4428 (
4435 (
4429 b'r',
4436 b'r',
4430 b'rev',
4437 b'rev',
4431 b'',
4438 b'',
4432 _(b'search the repository as it is in REV'),
4439 _(b'search the repository as it is in REV'),
4433 _(b'REV'),
4440 _(b'REV'),
4434 ),
4441 ),
4435 (
4442 (
4436 b'0',
4443 b'0',
4437 b'print0',
4444 b'print0',
4438 None,
4445 None,
4439 _(b'end filenames with NUL, for use with xargs'),
4446 _(b'end filenames with NUL, for use with xargs'),
4440 ),
4447 ),
4441 (
4448 (
4442 b'f',
4449 b'f',
4443 b'fullpath',
4450 b'fullpath',
4444 None,
4451 None,
4445 _(b'print complete paths from the filesystem root'),
4452 _(b'print complete paths from the filesystem root'),
4446 ),
4453 ),
4447 ]
4454 ]
4448 + walkopts,
4455 + walkopts,
4449 _(b'[OPTION]... [PATTERN]...'),
4456 _(b'[OPTION]... [PATTERN]...'),
4450 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4457 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4451 )
4458 )
4452 def locate(ui, repo, *pats, **opts):
4459 def locate(ui, repo, *pats, **opts):
4453 """locate files matching specific patterns (DEPRECATED)
4460 """locate files matching specific patterns (DEPRECATED)
4454
4461
4455 Print files under Mercurial control in the working directory whose
4462 Print files under Mercurial control in the working directory whose
4456 names match the given patterns.
4463 names match the given patterns.
4457
4464
4458 By default, this command searches all directories in the working
4465 By default, this command searches all directories in the working
4459 directory. To search just the current directory and its
4466 directory. To search just the current directory and its
4460 subdirectories, use "--include .".
4467 subdirectories, use "--include .".
4461
4468
4462 If no patterns are given to match, this command prints the names
4469 If no patterns are given to match, this command prints the names
4463 of all files under Mercurial control in the working directory.
4470 of all files under Mercurial control in the working directory.
4464
4471
4465 If you want to feed the output of this command into the "xargs"
4472 If you want to feed the output of this command into the "xargs"
4466 command, use the -0 option to both this command and "xargs". This
4473 command, use the -0 option to both this command and "xargs". This
4467 will avoid the problem of "xargs" treating single filenames that
4474 will avoid the problem of "xargs" treating single filenames that
4468 contain whitespace as multiple filenames.
4475 contain whitespace as multiple filenames.
4469
4476
4470 See :hg:`help files` for a more versatile command.
4477 See :hg:`help files` for a more versatile command.
4471
4478
4472 Returns 0 if a match is found, 1 otherwise.
4479 Returns 0 if a match is found, 1 otherwise.
4473 """
4480 """
4474 opts = pycompat.byteskwargs(opts)
4481 opts = pycompat.byteskwargs(opts)
4475 if opts.get(b'print0'):
4482 if opts.get(b'print0'):
4476 end = b'\0'
4483 end = b'\0'
4477 else:
4484 else:
4478 end = b'\n'
4485 end = b'\n'
4479 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4486 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4480
4487
4481 ret = 1
4488 ret = 1
4482 m = scmutil.match(
4489 m = scmutil.match(
4483 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4490 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4484 )
4491 )
4485
4492
4486 ui.pager(b'locate')
4493 ui.pager(b'locate')
4487 if ctx.rev() is None:
4494 if ctx.rev() is None:
4488 # When run on the working copy, "locate" includes removed files, so
4495 # When run on the working copy, "locate" includes removed files, so
4489 # we get the list of files from the dirstate.
4496 # we get the list of files from the dirstate.
4490 filesgen = sorted(repo.dirstate.matches(m))
4497 filesgen = sorted(repo.dirstate.matches(m))
4491 else:
4498 else:
4492 filesgen = ctx.matches(m)
4499 filesgen = ctx.matches(m)
4493 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4500 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4494 for abs in filesgen:
4501 for abs in filesgen:
4495 if opts.get(b'fullpath'):
4502 if opts.get(b'fullpath'):
4496 ui.write(repo.wjoin(abs), end)
4503 ui.write(repo.wjoin(abs), end)
4497 else:
4504 else:
4498 ui.write(uipathfn(abs), end)
4505 ui.write(uipathfn(abs), end)
4499 ret = 0
4506 ret = 0
4500
4507
4501 return ret
4508 return ret
4502
4509
4503
4510
4504 @command(
4511 @command(
4505 b'log|history',
4512 b'log|history',
4506 [
4513 [
4507 (
4514 (
4508 b'f',
4515 b'f',
4509 b'follow',
4516 b'follow',
4510 None,
4517 None,
4511 _(
4518 _(
4512 b'follow changeset history, or file history across copies and renames'
4519 b'follow changeset history, or file history across copies and renames'
4513 ),
4520 ),
4514 ),
4521 ),
4515 (
4522 (
4516 b'',
4523 b'',
4517 b'follow-first',
4524 b'follow-first',
4518 None,
4525 None,
4519 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4526 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4520 ),
4527 ),
4521 (
4528 (
4522 b'd',
4529 b'd',
4523 b'date',
4530 b'date',
4524 b'',
4531 b'',
4525 _(b'show revisions matching date spec'),
4532 _(b'show revisions matching date spec'),
4526 _(b'DATE'),
4533 _(b'DATE'),
4527 ),
4534 ),
4528 (b'C', b'copies', None, _(b'show copied files')),
4535 (b'C', b'copies', None, _(b'show copied files')),
4529 (
4536 (
4530 b'k',
4537 b'k',
4531 b'keyword',
4538 b'keyword',
4532 [],
4539 [],
4533 _(b'do case-insensitive search for a given text'),
4540 _(b'do case-insensitive search for a given text'),
4534 _(b'TEXT'),
4541 _(b'TEXT'),
4535 ),
4542 ),
4536 (
4543 (
4537 b'r',
4544 b'r',
4538 b'rev',
4545 b'rev',
4539 [],
4546 [],
4540 _(b'revisions to select or follow from'),
4547 _(b'revisions to select or follow from'),
4541 _(b'REV'),
4548 _(b'REV'),
4542 ),
4549 ),
4543 (
4550 (
4544 b'L',
4551 b'L',
4545 b'line-range',
4552 b'line-range',
4546 [],
4553 [],
4547 _(b'follow line range of specified file (EXPERIMENTAL)'),
4554 _(b'follow line range of specified file (EXPERIMENTAL)'),
4548 _(b'FILE,RANGE'),
4555 _(b'FILE,RANGE'),
4549 ),
4556 ),
4550 (
4557 (
4551 b'',
4558 b'',
4552 b'removed',
4559 b'removed',
4553 None,
4560 None,
4554 _(b'include revisions where files were removed'),
4561 _(b'include revisions where files were removed'),
4555 ),
4562 ),
4556 (
4563 (
4557 b'm',
4564 b'm',
4558 b'only-merges',
4565 b'only-merges',
4559 None,
4566 None,
4560 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4567 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4561 ),
4568 ),
4562 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4569 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4563 (
4570 (
4564 b'',
4571 b'',
4565 b'only-branch',
4572 b'only-branch',
4566 [],
4573 [],
4567 _(
4574 _(
4568 b'show only changesets within the given named branch (DEPRECATED)'
4575 b'show only changesets within the given named branch (DEPRECATED)'
4569 ),
4576 ),
4570 _(b'BRANCH'),
4577 _(b'BRANCH'),
4571 ),
4578 ),
4572 (
4579 (
4573 b'b',
4580 b'b',
4574 b'branch',
4581 b'branch',
4575 [],
4582 [],
4576 _(b'show changesets within the given named branch'),
4583 _(b'show changesets within the given named branch'),
4577 _(b'BRANCH'),
4584 _(b'BRANCH'),
4578 ),
4585 ),
4579 (
4586 (
4580 b'B',
4587 b'B',
4581 b'bookmark',
4588 b'bookmark',
4582 [],
4589 [],
4583 _(b"show changesets within the given bookmark"),
4590 _(b"show changesets within the given bookmark"),
4584 _(b'BOOKMARK'),
4591 _(b'BOOKMARK'),
4585 ),
4592 ),
4586 (
4593 (
4587 b'P',
4594 b'P',
4588 b'prune',
4595 b'prune',
4589 [],
4596 [],
4590 _(b'do not display revision or any of its ancestors'),
4597 _(b'do not display revision or any of its ancestors'),
4591 _(b'REV'),
4598 _(b'REV'),
4592 ),
4599 ),
4593 ]
4600 ]
4594 + logopts
4601 + logopts
4595 + walkopts,
4602 + walkopts,
4596 _(b'[OPTION]... [FILE]'),
4603 _(b'[OPTION]... [FILE]'),
4597 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4604 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4598 helpbasic=True,
4605 helpbasic=True,
4599 inferrepo=True,
4606 inferrepo=True,
4600 intents={INTENT_READONLY},
4607 intents={INTENT_READONLY},
4601 )
4608 )
4602 def log(ui, repo, *pats, **opts):
4609 def log(ui, repo, *pats, **opts):
4603 """show revision history of entire repository or files
4610 """show revision history of entire repository or files
4604
4611
4605 Print the revision history of the specified files or the entire
4612 Print the revision history of the specified files or the entire
4606 project.
4613 project.
4607
4614
4608 If no revision range is specified, the default is ``tip:0`` unless
4615 If no revision range is specified, the default is ``tip:0`` unless
4609 --follow is set.
4616 --follow is set.
4610
4617
4611 File history is shown without following rename or copy history of
4618 File history is shown without following rename or copy history of
4612 files. Use -f/--follow with a filename to follow history across
4619 files. Use -f/--follow with a filename to follow history across
4613 renames and copies. --follow without a filename will only show
4620 renames and copies. --follow without a filename will only show
4614 ancestors of the starting revisions. The starting revisions can be
4621 ancestors of the starting revisions. The starting revisions can be
4615 specified by -r/--rev, which default to the working directory parent.
4622 specified by -r/--rev, which default to the working directory parent.
4616
4623
4617 By default this command prints revision number and changeset id,
4624 By default this command prints revision number and changeset id,
4618 tags, non-trivial parents, user, date and time, and a summary for
4625 tags, non-trivial parents, user, date and time, and a summary for
4619 each commit. When the -v/--verbose switch is used, the list of
4626 each commit. When the -v/--verbose switch is used, the list of
4620 changed files and full commit message are shown.
4627 changed files and full commit message are shown.
4621
4628
4622 With --graph the revisions are shown as an ASCII art DAG with the most
4629 With --graph the revisions are shown as an ASCII art DAG with the most
4623 recent changeset at the top.
4630 recent changeset at the top.
4624 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4631 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4625 involved in an unresolved merge conflict, '_' closes a branch,
4632 involved in an unresolved merge conflict, '_' closes a branch,
4626 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4633 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4627 changeset from the lines below is a parent of the 'o' merge on the same
4634 changeset from the lines below is a parent of the 'o' merge on the same
4628 line.
4635 line.
4629 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4636 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4630 of a '|' indicates one or more revisions in a path are omitted.
4637 of a '|' indicates one or more revisions in a path are omitted.
4631
4638
4632 .. container:: verbose
4639 .. container:: verbose
4633
4640
4634 Use -L/--line-range FILE,M:N options to follow the history of lines
4641 Use -L/--line-range FILE,M:N options to follow the history of lines
4635 from M to N in FILE. With -p/--patch only diff hunks affecting
4642 from M to N in FILE. With -p/--patch only diff hunks affecting
4636 specified line range will be shown. This option requires --follow;
4643 specified line range will be shown. This option requires --follow;
4637 it can be specified multiple times. Currently, this option is not
4644 it can be specified multiple times. Currently, this option is not
4638 compatible with --graph. This option is experimental.
4645 compatible with --graph. This option is experimental.
4639
4646
4640 .. note::
4647 .. note::
4641
4648
4642 :hg:`log --patch` may generate unexpected diff output for merge
4649 :hg:`log --patch` may generate unexpected diff output for merge
4643 changesets, as it will only compare the merge changeset against
4650 changesets, as it will only compare the merge changeset against
4644 its first parent. Also, only files different from BOTH parents
4651 its first parent. Also, only files different from BOTH parents
4645 will appear in files:.
4652 will appear in files:.
4646
4653
4647 .. note::
4654 .. note::
4648
4655
4649 For performance reasons, :hg:`log FILE` may omit duplicate changes
4656 For performance reasons, :hg:`log FILE` may omit duplicate changes
4650 made on branches and will not show removals or mode changes. To
4657 made on branches and will not show removals or mode changes. To
4651 see all such changes, use the --removed switch.
4658 see all such changes, use the --removed switch.
4652
4659
4653 .. container:: verbose
4660 .. container:: verbose
4654
4661
4655 .. note::
4662 .. note::
4656
4663
4657 The history resulting from -L/--line-range options depends on diff
4664 The history resulting from -L/--line-range options depends on diff
4658 options; for instance if white-spaces are ignored, respective changes
4665 options; for instance if white-spaces are ignored, respective changes
4659 with only white-spaces in specified line range will not be listed.
4666 with only white-spaces in specified line range will not be listed.
4660
4667
4661 .. container:: verbose
4668 .. container:: verbose
4662
4669
4663 Some examples:
4670 Some examples:
4664
4671
4665 - changesets with full descriptions and file lists::
4672 - changesets with full descriptions and file lists::
4666
4673
4667 hg log -v
4674 hg log -v
4668
4675
4669 - changesets ancestral to the working directory::
4676 - changesets ancestral to the working directory::
4670
4677
4671 hg log -f
4678 hg log -f
4672
4679
4673 - last 10 commits on the current branch::
4680 - last 10 commits on the current branch::
4674
4681
4675 hg log -l 10 -b .
4682 hg log -l 10 -b .
4676
4683
4677 - changesets showing all modifications of a file, including removals::
4684 - changesets showing all modifications of a file, including removals::
4678
4685
4679 hg log --removed file.c
4686 hg log --removed file.c
4680
4687
4681 - all changesets that touch a directory, with diffs, excluding merges::
4688 - all changesets that touch a directory, with diffs, excluding merges::
4682
4689
4683 hg log -Mp lib/
4690 hg log -Mp lib/
4684
4691
4685 - all revision numbers that match a keyword::
4692 - all revision numbers that match a keyword::
4686
4693
4687 hg log -k bug --template "{rev}\\n"
4694 hg log -k bug --template "{rev}\\n"
4688
4695
4689 - the full hash identifier of the working directory parent::
4696 - the full hash identifier of the working directory parent::
4690
4697
4691 hg log -r . --template "{node}\\n"
4698 hg log -r . --template "{node}\\n"
4692
4699
4693 - list available log templates::
4700 - list available log templates::
4694
4701
4695 hg log -T list
4702 hg log -T list
4696
4703
4697 - check if a given changeset is included in a tagged release::
4704 - check if a given changeset is included in a tagged release::
4698
4705
4699 hg log -r "a21ccf and ancestor(1.9)"
4706 hg log -r "a21ccf and ancestor(1.9)"
4700
4707
4701 - find all changesets by some user in a date range::
4708 - find all changesets by some user in a date range::
4702
4709
4703 hg log -k alice -d "may 2008 to jul 2008"
4710 hg log -k alice -d "may 2008 to jul 2008"
4704
4711
4705 - summary of all changesets after the last tag::
4712 - summary of all changesets after the last tag::
4706
4713
4707 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4714 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4708
4715
4709 - changesets touching lines 13 to 23 for file.c::
4716 - changesets touching lines 13 to 23 for file.c::
4710
4717
4711 hg log -L file.c,13:23
4718 hg log -L file.c,13:23
4712
4719
4713 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4720 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4714 main.c with patch::
4721 main.c with patch::
4715
4722
4716 hg log -L file.c,13:23 -L main.c,2:6 -p
4723 hg log -L file.c,13:23 -L main.c,2:6 -p
4717
4724
4718 See :hg:`help dates` for a list of formats valid for -d/--date.
4725 See :hg:`help dates` for a list of formats valid for -d/--date.
4719
4726
4720 See :hg:`help revisions` for more about specifying and ordering
4727 See :hg:`help revisions` for more about specifying and ordering
4721 revisions.
4728 revisions.
4722
4729
4723 See :hg:`help templates` for more about pre-packaged styles and
4730 See :hg:`help templates` for more about pre-packaged styles and
4724 specifying custom templates. The default template used by the log
4731 specifying custom templates. The default template used by the log
4725 command can be customized via the ``command-templates.log`` configuration
4732 command can be customized via the ``command-templates.log`` configuration
4726 setting.
4733 setting.
4727
4734
4728 Returns 0 on success.
4735 Returns 0 on success.
4729
4736
4730 """
4737 """
4731 opts = pycompat.byteskwargs(opts)
4738 opts = pycompat.byteskwargs(opts)
4732 linerange = opts.get(b'line_range')
4739 linerange = opts.get(b'line_range')
4733
4740
4734 if linerange and not opts.get(b'follow'):
4741 if linerange and not opts.get(b'follow'):
4735 raise error.InputError(_(b'--line-range requires --follow'))
4742 raise error.InputError(_(b'--line-range requires --follow'))
4736
4743
4737 if linerange and pats:
4744 if linerange and pats:
4738 # TODO: take pats as patterns with no line-range filter
4745 # TODO: take pats as patterns with no line-range filter
4739 raise error.InputError(
4746 raise error.InputError(
4740 _(b'FILE arguments are not compatible with --line-range option')
4747 _(b'FILE arguments are not compatible with --line-range option')
4741 )
4748 )
4742
4749
4743 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4750 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4744 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4751 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4745 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4752 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4746 if linerange:
4753 if linerange:
4747 # TODO: should follow file history from logcmdutil._initialrevs(),
4754 # TODO: should follow file history from logcmdutil._initialrevs(),
4748 # then filter the result by logcmdutil._makerevset() and --limit
4755 # then filter the result by logcmdutil._makerevset() and --limit
4749 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4756 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4750
4757
4751 getcopies = None
4758 getcopies = None
4752 if opts.get(b'copies'):
4759 if opts.get(b'copies'):
4753 endrev = None
4760 endrev = None
4754 if revs:
4761 if revs:
4755 endrev = revs.max() + 1
4762 endrev = revs.max() + 1
4756 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4763 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4757
4764
4758 ui.pager(b'log')
4765 ui.pager(b'log')
4759 displayer = logcmdutil.changesetdisplayer(
4766 displayer = logcmdutil.changesetdisplayer(
4760 ui, repo, opts, differ, buffered=True
4767 ui, repo, opts, differ, buffered=True
4761 )
4768 )
4762 if opts.get(b'graph'):
4769 if opts.get(b'graph'):
4763 displayfn = logcmdutil.displaygraphrevs
4770 displayfn = logcmdutil.displaygraphrevs
4764 else:
4771 else:
4765 displayfn = logcmdutil.displayrevs
4772 displayfn = logcmdutil.displayrevs
4766 displayfn(ui, repo, revs, displayer, getcopies)
4773 displayfn(ui, repo, revs, displayer, getcopies)
4767
4774
4768
4775
4769 @command(
4776 @command(
4770 b'manifest',
4777 b'manifest',
4771 [
4778 [
4772 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4779 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4773 (b'', b'all', False, _(b"list files from all revisions")),
4780 (b'', b'all', False, _(b"list files from all revisions")),
4774 ]
4781 ]
4775 + formatteropts,
4782 + formatteropts,
4776 _(b'[-r REV]'),
4783 _(b'[-r REV]'),
4777 helpcategory=command.CATEGORY_MAINTENANCE,
4784 helpcategory=command.CATEGORY_MAINTENANCE,
4778 intents={INTENT_READONLY},
4785 intents={INTENT_READONLY},
4779 )
4786 )
4780 def manifest(ui, repo, node=None, rev=None, **opts):
4787 def manifest(ui, repo, node=None, rev=None, **opts):
4781 """output the current or given revision of the project manifest
4788 """output the current or given revision of the project manifest
4782
4789
4783 Print a list of version controlled files for the given revision.
4790 Print a list of version controlled files for the given revision.
4784 If no revision is given, the first parent of the working directory
4791 If no revision is given, the first parent of the working directory
4785 is used, or the null revision if no revision is checked out.
4792 is used, or the null revision if no revision is checked out.
4786
4793
4787 With -v, print file permissions, symlink and executable bits.
4794 With -v, print file permissions, symlink and executable bits.
4788 With --debug, print file revision hashes.
4795 With --debug, print file revision hashes.
4789
4796
4790 If option --all is specified, the list of all files from all revisions
4797 If option --all is specified, the list of all files from all revisions
4791 is printed. This includes deleted and renamed files.
4798 is printed. This includes deleted and renamed files.
4792
4799
4793 Returns 0 on success.
4800 Returns 0 on success.
4794 """
4801 """
4795 opts = pycompat.byteskwargs(opts)
4802 opts = pycompat.byteskwargs(opts)
4796 fm = ui.formatter(b'manifest', opts)
4803 fm = ui.formatter(b'manifest', opts)
4797
4804
4798 if opts.get(b'all'):
4805 if opts.get(b'all'):
4799 if rev or node:
4806 if rev or node:
4800 raise error.InputError(_(b"can't specify a revision with --all"))
4807 raise error.InputError(_(b"can't specify a revision with --all"))
4801
4808
4802 res = set()
4809 res = set()
4803 for rev in repo:
4810 for rev in repo:
4804 ctx = repo[rev]
4811 ctx = repo[rev]
4805 res |= set(ctx.files())
4812 res |= set(ctx.files())
4806
4813
4807 ui.pager(b'manifest')
4814 ui.pager(b'manifest')
4808 for f in sorted(res):
4815 for f in sorted(res):
4809 fm.startitem()
4816 fm.startitem()
4810 fm.write(b"path", b'%s\n', f)
4817 fm.write(b"path", b'%s\n', f)
4811 fm.end()
4818 fm.end()
4812 return
4819 return
4813
4820
4814 if rev and node:
4821 if rev and node:
4815 raise error.InputError(_(b"please specify just one revision"))
4822 raise error.InputError(_(b"please specify just one revision"))
4816
4823
4817 if not node:
4824 if not node:
4818 node = rev
4825 node = rev
4819
4826
4820 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4827 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4821 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4828 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4822 if node:
4829 if node:
4823 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4830 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4824 ctx = logcmdutil.revsingle(repo, node)
4831 ctx = logcmdutil.revsingle(repo, node)
4825 mf = ctx.manifest()
4832 mf = ctx.manifest()
4826 ui.pager(b'manifest')
4833 ui.pager(b'manifest')
4827 for f in ctx:
4834 for f in ctx:
4828 fm.startitem()
4835 fm.startitem()
4829 fm.context(ctx=ctx)
4836 fm.context(ctx=ctx)
4830 fl = ctx[f].flags()
4837 fl = ctx[f].flags()
4831 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4838 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4832 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4839 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4833 fm.write(b'path', b'%s\n', f)
4840 fm.write(b'path', b'%s\n', f)
4834 fm.end()
4841 fm.end()
4835
4842
4836
4843
4837 @command(
4844 @command(
4838 b'merge',
4845 b'merge',
4839 [
4846 [
4840 (
4847 (
4841 b'f',
4848 b'f',
4842 b'force',
4849 b'force',
4843 None,
4850 None,
4844 _(b'force a merge including outstanding changes (DEPRECATED)'),
4851 _(b'force a merge including outstanding changes (DEPRECATED)'),
4845 ),
4852 ),
4846 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4853 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4847 (
4854 (
4848 b'P',
4855 b'P',
4849 b'preview',
4856 b'preview',
4850 None,
4857 None,
4851 _(b'review revisions to merge (no merge is performed)'),
4858 _(b'review revisions to merge (no merge is performed)'),
4852 ),
4859 ),
4853 (b'', b'abort', None, _(b'abort the ongoing merge')),
4860 (b'', b'abort', None, _(b'abort the ongoing merge')),
4854 ]
4861 ]
4855 + mergetoolopts,
4862 + mergetoolopts,
4856 _(b'[-P] [[-r] REV]'),
4863 _(b'[-P] [[-r] REV]'),
4857 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4864 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4858 helpbasic=True,
4865 helpbasic=True,
4859 )
4866 )
4860 def merge(ui, repo, node=None, **opts):
4867 def merge(ui, repo, node=None, **opts):
4861 """merge another revision into working directory
4868 """merge another revision into working directory
4862
4869
4863 The current working directory is updated with all changes made in
4870 The current working directory is updated with all changes made in
4864 the requested revision since the last common predecessor revision.
4871 the requested revision since the last common predecessor revision.
4865
4872
4866 Files that changed between either parent are marked as changed for
4873 Files that changed between either parent are marked as changed for
4867 the next commit and a commit must be performed before any further
4874 the next commit and a commit must be performed before any further
4868 updates to the repository are allowed. The next commit will have
4875 updates to the repository are allowed. The next commit will have
4869 two parents.
4876 two parents.
4870
4877
4871 ``--tool`` can be used to specify the merge tool used for file
4878 ``--tool`` can be used to specify the merge tool used for file
4872 merges. It overrides the HGMERGE environment variable and your
4879 merges. It overrides the HGMERGE environment variable and your
4873 configuration files. See :hg:`help merge-tools` for options.
4880 configuration files. See :hg:`help merge-tools` for options.
4874
4881
4875 If no revision is specified, the working directory's parent is a
4882 If no revision is specified, the working directory's parent is a
4876 head revision, and the current branch contains exactly one other
4883 head revision, and the current branch contains exactly one other
4877 head, the other head is merged with by default. Otherwise, an
4884 head, the other head is merged with by default. Otherwise, an
4878 explicit revision with which to merge must be provided.
4885 explicit revision with which to merge must be provided.
4879
4886
4880 See :hg:`help resolve` for information on handling file conflicts.
4887 See :hg:`help resolve` for information on handling file conflicts.
4881
4888
4882 To undo an uncommitted merge, use :hg:`merge --abort` which
4889 To undo an uncommitted merge, use :hg:`merge --abort` which
4883 will check out a clean copy of the original merge parent, losing
4890 will check out a clean copy of the original merge parent, losing
4884 all changes.
4891 all changes.
4885
4892
4886 Returns 0 on success, 1 if there are unresolved files.
4893 Returns 0 on success, 1 if there are unresolved files.
4887 """
4894 """
4888
4895
4889 opts = pycompat.byteskwargs(opts)
4896 opts = pycompat.byteskwargs(opts)
4890 abort = opts.get(b'abort')
4897 abort = opts.get(b'abort')
4891 if abort and repo.dirstate.p2() == repo.nullid:
4898 if abort and repo.dirstate.p2() == repo.nullid:
4892 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4899 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4893 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4900 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4894 if abort:
4901 if abort:
4895 state = cmdutil.getunfinishedstate(repo)
4902 state = cmdutil.getunfinishedstate(repo)
4896 if state and state._opname != b'merge':
4903 if state and state._opname != b'merge':
4897 raise error.StateError(
4904 raise error.StateError(
4898 _(b'cannot abort merge with %s in progress') % (state._opname),
4905 _(b'cannot abort merge with %s in progress') % (state._opname),
4899 hint=state.hint(),
4906 hint=state.hint(),
4900 )
4907 )
4901 if node:
4908 if node:
4902 raise error.InputError(_(b"cannot specify a node with --abort"))
4909 raise error.InputError(_(b"cannot specify a node with --abort"))
4903 return hg.abortmerge(repo.ui, repo)
4910 return hg.abortmerge(repo.ui, repo)
4904
4911
4905 if opts.get(b'rev') and node:
4912 if opts.get(b'rev') and node:
4906 raise error.InputError(_(b"please specify just one revision"))
4913 raise error.InputError(_(b"please specify just one revision"))
4907 if not node:
4914 if not node:
4908 node = opts.get(b'rev')
4915 node = opts.get(b'rev')
4909
4916
4910 if node:
4917 if node:
4911 ctx = logcmdutil.revsingle(repo, node)
4918 ctx = logcmdutil.revsingle(repo, node)
4912 else:
4919 else:
4913 if ui.configbool(b'commands', b'merge.require-rev'):
4920 if ui.configbool(b'commands', b'merge.require-rev'):
4914 raise error.InputError(
4921 raise error.InputError(
4915 _(
4922 _(
4916 b'configuration requires specifying revision to merge '
4923 b'configuration requires specifying revision to merge '
4917 b'with'
4924 b'with'
4918 )
4925 )
4919 )
4926 )
4920 ctx = repo[destutil.destmerge(repo)]
4927 ctx = repo[destutil.destmerge(repo)]
4921
4928
4922 if ctx.node() is None:
4929 if ctx.node() is None:
4923 raise error.InputError(
4930 raise error.InputError(
4924 _(b'merging with the working copy has no effect')
4931 _(b'merging with the working copy has no effect')
4925 )
4932 )
4926
4933
4927 if opts.get(b'preview'):
4934 if opts.get(b'preview'):
4928 # find nodes that are ancestors of p2 but not of p1
4935 # find nodes that are ancestors of p2 but not of p1
4929 p1 = repo[b'.'].node()
4936 p1 = repo[b'.'].node()
4930 p2 = ctx.node()
4937 p2 = ctx.node()
4931 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4938 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4932
4939
4933 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4940 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4934 for node in nodes:
4941 for node in nodes:
4935 displayer.show(repo[node])
4942 displayer.show(repo[node])
4936 displayer.close()
4943 displayer.close()
4937 return 0
4944 return 0
4938
4945
4939 # ui.forcemerge is an internal variable, do not document
4946 # ui.forcemerge is an internal variable, do not document
4940 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4947 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4941 with ui.configoverride(overrides, b'merge'):
4948 with ui.configoverride(overrides, b'merge'):
4942 force = opts.get(b'force')
4949 force = opts.get(b'force')
4943 labels = [b'working copy', b'merge rev', b'common ancestor']
4950 labels = [b'working copy', b'merge rev', b'common ancestor']
4944 return hg.merge(ctx, force=force, labels=labels)
4951 return hg.merge(ctx, force=force, labels=labels)
4945
4952
4946
4953
4947 statemod.addunfinished(
4954 statemod.addunfinished(
4948 b'merge',
4955 b'merge',
4949 fname=None,
4956 fname=None,
4950 clearable=True,
4957 clearable=True,
4951 allowcommit=True,
4958 allowcommit=True,
4952 cmdmsg=_(b'outstanding uncommitted merge'),
4959 cmdmsg=_(b'outstanding uncommitted merge'),
4953 abortfunc=hg.abortmerge,
4960 abortfunc=hg.abortmerge,
4954 statushint=_(
4961 statushint=_(
4955 b'To continue: hg commit\nTo abort: hg merge --abort'
4962 b'To continue: hg commit\nTo abort: hg merge --abort'
4956 ),
4963 ),
4957 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4964 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4958 )
4965 )
4959
4966
4960
4967
4961 @command(
4968 @command(
4962 b'outgoing|out',
4969 b'outgoing|out',
4963 [
4970 [
4964 (
4971 (
4965 b'f',
4972 b'f',
4966 b'force',
4973 b'force',
4967 None,
4974 None,
4968 _(b'run even when the destination is unrelated'),
4975 _(b'run even when the destination is unrelated'),
4969 ),
4976 ),
4970 (
4977 (
4971 b'r',
4978 b'r',
4972 b'rev',
4979 b'rev',
4973 [],
4980 [],
4974 _(b'a changeset intended to be included in the destination'),
4981 _(b'a changeset intended to be included in the destination'),
4975 _(b'REV'),
4982 _(b'REV'),
4976 ),
4983 ),
4977 (b'n', b'newest-first', None, _(b'show newest record first')),
4984 (b'n', b'newest-first', None, _(b'show newest record first')),
4978 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4985 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4979 (
4986 (
4980 b'b',
4987 b'b',
4981 b'branch',
4988 b'branch',
4982 [],
4989 [],
4983 _(b'a specific branch you would like to push'),
4990 _(b'a specific branch you would like to push'),
4984 _(b'BRANCH'),
4991 _(b'BRANCH'),
4985 ),
4992 ),
4986 ]
4993 ]
4987 + logopts
4994 + logopts
4988 + remoteopts
4995 + remoteopts
4989 + subrepoopts,
4996 + subrepoopts,
4990 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4997 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4991 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4998 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4992 )
4999 )
4993 def outgoing(ui, repo, *dests, **opts):
5000 def outgoing(ui, repo, *dests, **opts):
4994 """show changesets not found in the destination
5001 """show changesets not found in the destination
4995
5002
4996 Show changesets not found in the specified destination repository
5003 Show changesets not found in the specified destination repository
4997 or the default push location. These are the changesets that would
5004 or the default push location. These are the changesets that would
4998 be pushed if a push was requested.
5005 be pushed if a push was requested.
4999
5006
5000 See pull for details of valid destination formats.
5007 See pull for details of valid destination formats.
5001
5008
5002 .. container:: verbose
5009 .. container:: verbose
5003
5010
5004 With -B/--bookmarks, the result of bookmark comparison between
5011 With -B/--bookmarks, the result of bookmark comparison between
5005 local and remote repositories is displayed. With -v/--verbose,
5012 local and remote repositories is displayed. With -v/--verbose,
5006 status is also displayed for each bookmark like below::
5013 status is also displayed for each bookmark like below::
5007
5014
5008 BM1 01234567890a added
5015 BM1 01234567890a added
5009 BM2 deleted
5016 BM2 deleted
5010 BM3 234567890abc advanced
5017 BM3 234567890abc advanced
5011 BM4 34567890abcd diverged
5018 BM4 34567890abcd diverged
5012 BM5 4567890abcde changed
5019 BM5 4567890abcde changed
5013
5020
5014 The action taken when pushing depends on the
5021 The action taken when pushing depends on the
5015 status of each bookmark:
5022 status of each bookmark:
5016
5023
5017 :``added``: push with ``-B`` will create it
5024 :``added``: push with ``-B`` will create it
5018 :``deleted``: push with ``-B`` will delete it
5025 :``deleted``: push with ``-B`` will delete it
5019 :``advanced``: push will update it
5026 :``advanced``: push will update it
5020 :``diverged``: push with ``-B`` will update it
5027 :``diverged``: push with ``-B`` will update it
5021 :``changed``: push with ``-B`` will update it
5028 :``changed``: push with ``-B`` will update it
5022
5029
5023 From the point of view of pushing behavior, bookmarks
5030 From the point of view of pushing behavior, bookmarks
5024 existing only in the remote repository are treated as
5031 existing only in the remote repository are treated as
5025 ``deleted``, even if it is in fact added remotely.
5032 ``deleted``, even if it is in fact added remotely.
5026
5033
5027 Returns 0 if there are outgoing changes, 1 otherwise.
5034 Returns 0 if there are outgoing changes, 1 otherwise.
5028 """
5035 """
5029 opts = pycompat.byteskwargs(opts)
5036 opts = pycompat.byteskwargs(opts)
5030 if opts.get(b'bookmarks'):
5037 if opts.get(b'bookmarks'):
5031 for path in urlutil.get_push_paths(repo, ui, dests):
5038 for path in urlutil.get_push_paths(repo, ui, dests):
5032 dest = path.pushloc or path.loc
5039 dest = path.pushloc or path.loc
5033 other = hg.peer(repo, opts, dest)
5040 other = hg.peer(repo, opts, dest)
5034 try:
5041 try:
5035 if b'bookmarks' not in other.listkeys(b'namespaces'):
5042 if b'bookmarks' not in other.listkeys(b'namespaces'):
5036 ui.warn(_(b"remote doesn't support bookmarks\n"))
5043 ui.warn(_(b"remote doesn't support bookmarks\n"))
5037 return 0
5044 return 0
5038 ui.status(
5045 ui.status(
5039 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5046 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5040 )
5047 )
5041 ui.pager(b'outgoing')
5048 ui.pager(b'outgoing')
5042 return bookmarks.outgoing(ui, repo, other)
5049 return bookmarks.outgoing(ui, repo, other)
5043 finally:
5050 finally:
5044 other.close()
5051 other.close()
5045
5052
5046 return hg.outgoing(ui, repo, dests, opts)
5053 return hg.outgoing(ui, repo, dests, opts)
5047
5054
5048
5055
5049 @command(
5056 @command(
5050 b'parents',
5057 b'parents',
5051 [
5058 [
5052 (
5059 (
5053 b'r',
5060 b'r',
5054 b'rev',
5061 b'rev',
5055 b'',
5062 b'',
5056 _(b'show parents of the specified revision'),
5063 _(b'show parents of the specified revision'),
5057 _(b'REV'),
5064 _(b'REV'),
5058 ),
5065 ),
5059 ]
5066 ]
5060 + templateopts,
5067 + templateopts,
5061 _(b'[-r REV] [FILE]'),
5068 _(b'[-r REV] [FILE]'),
5062 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5069 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5063 inferrepo=True,
5070 inferrepo=True,
5064 )
5071 )
5065 def parents(ui, repo, file_=None, **opts):
5072 def parents(ui, repo, file_=None, **opts):
5066 """show the parents of the working directory or revision (DEPRECATED)
5073 """show the parents of the working directory or revision (DEPRECATED)
5067
5074
5068 Print the working directory's parent revisions. If a revision is
5075 Print the working directory's parent revisions. If a revision is
5069 given via -r/--rev, the parent of that revision will be printed.
5076 given via -r/--rev, the parent of that revision will be printed.
5070 If a file argument is given, the revision in which the file was
5077 If a file argument is given, the revision in which the file was
5071 last changed (before the working directory revision or the
5078 last changed (before the working directory revision or the
5072 argument to --rev if given) is printed.
5079 argument to --rev if given) is printed.
5073
5080
5074 This command is equivalent to::
5081 This command is equivalent to::
5075
5082
5076 hg log -r "p1()+p2()" or
5083 hg log -r "p1()+p2()" or
5077 hg log -r "p1(REV)+p2(REV)" or
5084 hg log -r "p1(REV)+p2(REV)" or
5078 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5085 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5079 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5086 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5080
5087
5081 See :hg:`summary` and :hg:`help revsets` for related information.
5088 See :hg:`summary` and :hg:`help revsets` for related information.
5082
5089
5083 Returns 0 on success.
5090 Returns 0 on success.
5084 """
5091 """
5085
5092
5086 opts = pycompat.byteskwargs(opts)
5093 opts = pycompat.byteskwargs(opts)
5087 rev = opts.get(b'rev')
5094 rev = opts.get(b'rev')
5088 if rev:
5095 if rev:
5089 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5096 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5090 ctx = logcmdutil.revsingle(repo, rev, None)
5097 ctx = logcmdutil.revsingle(repo, rev, None)
5091
5098
5092 if file_:
5099 if file_:
5093 m = scmutil.match(ctx, (file_,), opts)
5100 m = scmutil.match(ctx, (file_,), opts)
5094 if m.anypats() or len(m.files()) != 1:
5101 if m.anypats() or len(m.files()) != 1:
5095 raise error.InputError(_(b'can only specify an explicit filename'))
5102 raise error.InputError(_(b'can only specify an explicit filename'))
5096 file_ = m.files()[0]
5103 file_ = m.files()[0]
5097 filenodes = []
5104 filenodes = []
5098 for cp in ctx.parents():
5105 for cp in ctx.parents():
5099 if not cp:
5106 if not cp:
5100 continue
5107 continue
5101 try:
5108 try:
5102 filenodes.append(cp.filenode(file_))
5109 filenodes.append(cp.filenode(file_))
5103 except error.LookupError:
5110 except error.LookupError:
5104 pass
5111 pass
5105 if not filenodes:
5112 if not filenodes:
5106 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5113 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5107 p = []
5114 p = []
5108 for fn in filenodes:
5115 for fn in filenodes:
5109 fctx = repo.filectx(file_, fileid=fn)
5116 fctx = repo.filectx(file_, fileid=fn)
5110 p.append(fctx.node())
5117 p.append(fctx.node())
5111 else:
5118 else:
5112 p = [cp.node() for cp in ctx.parents()]
5119 p = [cp.node() for cp in ctx.parents()]
5113
5120
5114 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5121 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5115 for n in p:
5122 for n in p:
5116 if n != repo.nullid:
5123 if n != repo.nullid:
5117 displayer.show(repo[n])
5124 displayer.show(repo[n])
5118 displayer.close()
5125 displayer.close()
5119
5126
5120
5127
5121 @command(
5128 @command(
5122 b'paths',
5129 b'paths',
5123 formatteropts,
5130 formatteropts,
5124 _(b'[NAME]'),
5131 _(b'[NAME]'),
5125 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5132 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5126 optionalrepo=True,
5133 optionalrepo=True,
5127 intents={INTENT_READONLY},
5134 intents={INTENT_READONLY},
5128 )
5135 )
5129 def paths(ui, repo, search=None, **opts):
5136 def paths(ui, repo, search=None, **opts):
5130 """show aliases for remote repositories
5137 """show aliases for remote repositories
5131
5138
5132 Show definition of symbolic path name NAME. If no name is given,
5139 Show definition of symbolic path name NAME. If no name is given,
5133 show definition of all available names.
5140 show definition of all available names.
5134
5141
5135 Option -q/--quiet suppresses all output when searching for NAME
5142 Option -q/--quiet suppresses all output when searching for NAME
5136 and shows only the path names when listing all definitions.
5143 and shows only the path names when listing all definitions.
5137
5144
5138 Path names are defined in the [paths] section of your
5145 Path names are defined in the [paths] section of your
5139 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5146 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5140 repository, ``.hg/hgrc`` is used, too.
5147 repository, ``.hg/hgrc`` is used, too.
5141
5148
5142 The path names ``default`` and ``default-push`` have a special
5149 The path names ``default`` and ``default-push`` have a special
5143 meaning. When performing a push or pull operation, they are used
5150 meaning. When performing a push or pull operation, they are used
5144 as fallbacks if no location is specified on the command-line.
5151 as fallbacks if no location is specified on the command-line.
5145 When ``default-push`` is set, it will be used for push and
5152 When ``default-push`` is set, it will be used for push and
5146 ``default`` will be used for pull; otherwise ``default`` is used
5153 ``default`` will be used for pull; otherwise ``default`` is used
5147 as the fallback for both. When cloning a repository, the clone
5154 as the fallback for both. When cloning a repository, the clone
5148 source is written as ``default`` in ``.hg/hgrc``.
5155 source is written as ``default`` in ``.hg/hgrc``.
5149
5156
5150 .. note::
5157 .. note::
5151
5158
5152 ``default`` and ``default-push`` apply to all inbound (e.g.
5159 ``default`` and ``default-push`` apply to all inbound (e.g.
5153 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5160 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5154 and :hg:`bundle`) operations.
5161 and :hg:`bundle`) operations.
5155
5162
5156 See :hg:`help urls` for more information.
5163 See :hg:`help urls` for more information.
5157
5164
5158 .. container:: verbose
5165 .. container:: verbose
5159
5166
5160 Template:
5167 Template:
5161
5168
5162 The following keywords are supported. See also :hg:`help templates`.
5169 The following keywords are supported. See also :hg:`help templates`.
5163
5170
5164 :name: String. Symbolic name of the path alias.
5171 :name: String. Symbolic name of the path alias.
5165 :pushurl: String. URL for push operations.
5172 :pushurl: String. URL for push operations.
5166 :url: String. URL or directory path for the other operations.
5173 :url: String. URL or directory path for the other operations.
5167
5174
5168 Returns 0 on success.
5175 Returns 0 on success.
5169 """
5176 """
5170
5177
5171 opts = pycompat.byteskwargs(opts)
5178 opts = pycompat.byteskwargs(opts)
5172
5179
5173 pathitems = urlutil.list_paths(ui, search)
5180 pathitems = urlutil.list_paths(ui, search)
5174 ui.pager(b'paths')
5181 ui.pager(b'paths')
5175
5182
5176 fm = ui.formatter(b'paths', opts)
5183 fm = ui.formatter(b'paths', opts)
5177 if fm.isplain():
5184 if fm.isplain():
5178 hidepassword = urlutil.hidepassword
5185 hidepassword = urlutil.hidepassword
5179 else:
5186 else:
5180 hidepassword = bytes
5187 hidepassword = bytes
5181 if ui.quiet:
5188 if ui.quiet:
5182 namefmt = b'%s\n'
5189 namefmt = b'%s\n'
5183 else:
5190 else:
5184 namefmt = b'%s = '
5191 namefmt = b'%s = '
5185 showsubopts = not search and not ui.quiet
5192 showsubopts = not search and not ui.quiet
5186
5193
5187 for name, path in pathitems:
5194 for name, path in pathitems:
5188 fm.startitem()
5195 fm.startitem()
5189 fm.condwrite(not search, b'name', namefmt, name)
5196 fm.condwrite(not search, b'name', namefmt, name)
5190 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5197 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5191 for subopt, value in sorted(path.suboptions.items()):
5198 for subopt, value in sorted(path.suboptions.items()):
5192 assert subopt not in (b'name', b'url')
5199 assert subopt not in (b'name', b'url')
5193 if showsubopts:
5200 if showsubopts:
5194 fm.plain(b'%s:%s = ' % (name, subopt))
5201 fm.plain(b'%s:%s = ' % (name, subopt))
5195 if isinstance(value, bool):
5202 if isinstance(value, bool):
5196 if value:
5203 if value:
5197 value = b'yes'
5204 value = b'yes'
5198 else:
5205 else:
5199 value = b'no'
5206 value = b'no'
5200 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5207 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5201
5208
5202 fm.end()
5209 fm.end()
5203
5210
5204 if search and not pathitems:
5211 if search and not pathitems:
5205 if not ui.quiet:
5212 if not ui.quiet:
5206 ui.warn(_(b"not found!\n"))
5213 ui.warn(_(b"not found!\n"))
5207 return 1
5214 return 1
5208 else:
5215 else:
5209 return 0
5216 return 0
5210
5217
5211
5218
5212 @command(
5219 @command(
5213 b'phase',
5220 b'phase',
5214 [
5221 [
5215 (b'p', b'public', False, _(b'set changeset phase to public')),
5222 (b'p', b'public', False, _(b'set changeset phase to public')),
5216 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5223 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5217 (b's', b'secret', False, _(b'set changeset phase to secret')),
5224 (b's', b'secret', False, _(b'set changeset phase to secret')),
5218 (b'f', b'force', False, _(b'allow to move boundary backward')),
5225 (b'f', b'force', False, _(b'allow to move boundary backward')),
5219 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5226 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5220 ],
5227 ],
5221 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5228 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5222 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5229 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5223 )
5230 )
5224 def phase(ui, repo, *revs, **opts):
5231 def phase(ui, repo, *revs, **opts):
5225 """set or show the current phase name
5232 """set or show the current phase name
5226
5233
5227 With no argument, show the phase name of the current revision(s).
5234 With no argument, show the phase name of the current revision(s).
5228
5235
5229 With one of -p/--public, -d/--draft or -s/--secret, change the
5236 With one of -p/--public, -d/--draft or -s/--secret, change the
5230 phase value of the specified revisions.
5237 phase value of the specified revisions.
5231
5238
5232 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5239 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5233 lower phase to a higher phase. Phases are ordered as follows::
5240 lower phase to a higher phase. Phases are ordered as follows::
5234
5241
5235 public < draft < secret
5242 public < draft < secret
5236
5243
5237 Returns 0 on success, 1 if some phases could not be changed.
5244 Returns 0 on success, 1 if some phases could not be changed.
5238
5245
5239 (For more information about the phases concept, see :hg:`help phases`.)
5246 (For more information about the phases concept, see :hg:`help phases`.)
5240 """
5247 """
5241 opts = pycompat.byteskwargs(opts)
5248 opts = pycompat.byteskwargs(opts)
5242 # search for a unique phase argument
5249 # search for a unique phase argument
5243 targetphase = None
5250 targetphase = None
5244 for idx, name in enumerate(phases.cmdphasenames):
5251 for idx, name in enumerate(phases.cmdphasenames):
5245 if opts[name]:
5252 if opts[name]:
5246 if targetphase is not None:
5253 if targetphase is not None:
5247 raise error.InputError(_(b'only one phase can be specified'))
5254 raise error.InputError(_(b'only one phase can be specified'))
5248 targetphase = idx
5255 targetphase = idx
5249
5256
5250 # look for specified revision
5257 # look for specified revision
5251 revs = list(revs)
5258 revs = list(revs)
5252 revs.extend(opts[b'rev'])
5259 revs.extend(opts[b'rev'])
5253 if revs:
5260 if revs:
5254 revs = logcmdutil.revrange(repo, revs)
5261 revs = logcmdutil.revrange(repo, revs)
5255 else:
5262 else:
5256 # display both parents as the second parent phase can influence
5263 # display both parents as the second parent phase can influence
5257 # the phase of a merge commit
5264 # the phase of a merge commit
5258 revs = [c.rev() for c in repo[None].parents()]
5265 revs = [c.rev() for c in repo[None].parents()]
5259
5266
5260 ret = 0
5267 ret = 0
5261 if targetphase is None:
5268 if targetphase is None:
5262 # display
5269 # display
5263 for r in revs:
5270 for r in revs:
5264 ctx = repo[r]
5271 ctx = repo[r]
5265 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5272 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5266 else:
5273 else:
5267 with repo.lock(), repo.transaction(b"phase") as tr:
5274 with repo.lock(), repo.transaction(b"phase") as tr:
5268 # set phase
5275 # set phase
5269 if not revs:
5276 if not revs:
5270 raise error.InputError(_(b'empty revision set'))
5277 raise error.InputError(_(b'empty revision set'))
5271 nodes = [repo[r].node() for r in revs]
5278 nodes = [repo[r].node() for r in revs]
5272 # moving revision from public to draft may hide them
5279 # moving revision from public to draft may hide them
5273 # We have to check result on an unfiltered repository
5280 # We have to check result on an unfiltered repository
5274 unfi = repo.unfiltered()
5281 unfi = repo.unfiltered()
5275 getphase = unfi._phasecache.phase
5282 getphase = unfi._phasecache.phase
5276 olddata = [getphase(unfi, r) for r in unfi]
5283 olddata = [getphase(unfi, r) for r in unfi]
5277 phases.advanceboundary(repo, tr, targetphase, nodes)
5284 phases.advanceboundary(repo, tr, targetphase, nodes)
5278 if opts[b'force']:
5285 if opts[b'force']:
5279 phases.retractboundary(repo, tr, targetphase, nodes)
5286 phases.retractboundary(repo, tr, targetphase, nodes)
5280 getphase = unfi._phasecache.phase
5287 getphase = unfi._phasecache.phase
5281 newdata = [getphase(unfi, r) for r in unfi]
5288 newdata = [getphase(unfi, r) for r in unfi]
5282 changes = sum(newdata[r] != olddata[r] for r in unfi)
5289 changes = sum(newdata[r] != olddata[r] for r in unfi)
5283 cl = unfi.changelog
5290 cl = unfi.changelog
5284 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5291 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5285 if rejected:
5292 if rejected:
5286 ui.warn(
5293 ui.warn(
5287 _(
5294 _(
5288 b'cannot move %i changesets to a higher '
5295 b'cannot move %i changesets to a higher '
5289 b'phase, use --force\n'
5296 b'phase, use --force\n'
5290 )
5297 )
5291 % len(rejected)
5298 % len(rejected)
5292 )
5299 )
5293 ret = 1
5300 ret = 1
5294 if changes:
5301 if changes:
5295 msg = _(b'phase changed for %i changesets\n') % changes
5302 msg = _(b'phase changed for %i changesets\n') % changes
5296 if ret:
5303 if ret:
5297 ui.status(msg)
5304 ui.status(msg)
5298 else:
5305 else:
5299 ui.note(msg)
5306 ui.note(msg)
5300 else:
5307 else:
5301 ui.warn(_(b'no phases changed\n'))
5308 ui.warn(_(b'no phases changed\n'))
5302 return ret
5309 return ret
5303
5310
5304
5311
5305 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5312 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5306 """Run after a changegroup has been added via pull/unbundle
5313 """Run after a changegroup has been added via pull/unbundle
5307
5314
5308 This takes arguments below:
5315 This takes arguments below:
5309
5316
5310 :modheads: change of heads by pull/unbundle
5317 :modheads: change of heads by pull/unbundle
5311 :optupdate: updating working directory is needed or not
5318 :optupdate: updating working directory is needed or not
5312 :checkout: update destination revision (or None to default destination)
5319 :checkout: update destination revision (or None to default destination)
5313 :brev: a name, which might be a bookmark to be activated after updating
5320 :brev: a name, which might be a bookmark to be activated after updating
5314
5321
5315 return True if update raise any conflict, False otherwise.
5322 return True if update raise any conflict, False otherwise.
5316 """
5323 """
5317 if modheads == 0:
5324 if modheads == 0:
5318 return False
5325 return False
5319 if optupdate:
5326 if optupdate:
5320 try:
5327 try:
5321 return hg.updatetotally(ui, repo, checkout, brev)
5328 return hg.updatetotally(ui, repo, checkout, brev)
5322 except error.UpdateAbort as inst:
5329 except error.UpdateAbort as inst:
5323 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5330 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5324 hint = inst.hint
5331 hint = inst.hint
5325 raise error.UpdateAbort(msg, hint=hint)
5332 raise error.UpdateAbort(msg, hint=hint)
5326 if modheads is not None and modheads > 1:
5333 if modheads is not None and modheads > 1:
5327 currentbranchheads = len(repo.branchheads())
5334 currentbranchheads = len(repo.branchheads())
5328 if currentbranchheads == modheads:
5335 if currentbranchheads == modheads:
5329 ui.status(
5336 ui.status(
5330 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5337 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5331 )
5338 )
5332 elif currentbranchheads > 1:
5339 elif currentbranchheads > 1:
5333 ui.status(
5340 ui.status(
5334 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5341 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5335 )
5342 )
5336 else:
5343 else:
5337 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5344 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5338 elif not ui.configbool(b'commands', b'update.requiredest'):
5345 elif not ui.configbool(b'commands', b'update.requiredest'):
5339 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5346 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5340 return False
5347 return False
5341
5348
5342
5349
5343 @command(
5350 @command(
5344 b'pull',
5351 b'pull',
5345 [
5352 [
5346 (
5353 (
5347 b'u',
5354 b'u',
5348 b'update',
5355 b'update',
5349 None,
5356 None,
5350 _(b'update to new branch head if new descendants were pulled'),
5357 _(b'update to new branch head if new descendants were pulled'),
5351 ),
5358 ),
5352 (
5359 (
5353 b'f',
5360 b'f',
5354 b'force',
5361 b'force',
5355 None,
5362 None,
5356 _(b'run even when remote repository is unrelated'),
5363 _(b'run even when remote repository is unrelated'),
5357 ),
5364 ),
5358 (
5365 (
5359 b'',
5366 b'',
5360 b'confirm',
5367 b'confirm',
5361 None,
5368 None,
5362 _(b'confirm pull before applying changes'),
5369 _(b'confirm pull before applying changes'),
5363 ),
5370 ),
5364 (
5371 (
5365 b'r',
5372 b'r',
5366 b'rev',
5373 b'rev',
5367 [],
5374 [],
5368 _(b'a remote changeset intended to be added'),
5375 _(b'a remote changeset intended to be added'),
5369 _(b'REV'),
5376 _(b'REV'),
5370 ),
5377 ),
5371 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5378 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5372 (
5379 (
5373 b'b',
5380 b'b',
5374 b'branch',
5381 b'branch',
5375 [],
5382 [],
5376 _(b'a specific branch you would like to pull'),
5383 _(b'a specific branch you would like to pull'),
5377 _(b'BRANCH'),
5384 _(b'BRANCH'),
5378 ),
5385 ),
5379 ]
5386 ]
5380 + remoteopts,
5387 + remoteopts,
5381 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5388 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5382 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5389 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5383 helpbasic=True,
5390 helpbasic=True,
5384 )
5391 )
5385 def pull(ui, repo, *sources, **opts):
5392 def pull(ui, repo, *sources, **opts):
5386 """pull changes from the specified source
5393 """pull changes from the specified source
5387
5394
5388 Pull changes from a remote repository to a local one.
5395 Pull changes from a remote repository to a local one.
5389
5396
5390 This finds all changes from the repository at the specified path
5397 This finds all changes from the repository at the specified path
5391 or URL and adds them to a local repository (the current one unless
5398 or URL and adds them to a local repository (the current one unless
5392 -R is specified). By default, this does not update the copy of the
5399 -R is specified). By default, this does not update the copy of the
5393 project in the working directory.
5400 project in the working directory.
5394
5401
5395 When cloning from servers that support it, Mercurial may fetch
5402 When cloning from servers that support it, Mercurial may fetch
5396 pre-generated data. When this is done, hooks operating on incoming
5403 pre-generated data. When this is done, hooks operating on incoming
5397 changesets and changegroups may fire more than once, once for each
5404 changesets and changegroups may fire more than once, once for each
5398 pre-generated bundle and as well as for any additional remaining
5405 pre-generated bundle and as well as for any additional remaining
5399 data. See :hg:`help -e clonebundles` for more.
5406 data. See :hg:`help -e clonebundles` for more.
5400
5407
5401 Use :hg:`incoming` if you want to see what would have been added
5408 Use :hg:`incoming` if you want to see what would have been added
5402 by a pull at the time you issued this command. If you then decide
5409 by a pull at the time you issued this command. If you then decide
5403 to add those changes to the repository, you should use :hg:`pull
5410 to add those changes to the repository, you should use :hg:`pull
5404 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5411 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5405
5412
5406 If SOURCE is omitted, the 'default' path will be used.
5413 If SOURCE is omitted, the 'default' path will be used.
5407 See :hg:`help urls` for more information.
5414 See :hg:`help urls` for more information.
5408
5415
5409 If multiple sources are specified, they will be pulled sequentially as if
5416 If multiple sources are specified, they will be pulled sequentially as if
5410 the command was run multiple time. If --update is specify and the command
5417 the command was run multiple time. If --update is specify and the command
5411 will stop at the first failed --update.
5418 will stop at the first failed --update.
5412
5419
5413 Specifying bookmark as ``.`` is equivalent to specifying the active
5420 Specifying bookmark as ``.`` is equivalent to specifying the active
5414 bookmark's name.
5421 bookmark's name.
5415
5422
5416 Returns 0 on success, 1 if an update had unresolved files.
5423 Returns 0 on success, 1 if an update had unresolved files.
5417 """
5424 """
5418
5425
5419 opts = pycompat.byteskwargs(opts)
5426 opts = pycompat.byteskwargs(opts)
5420 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5427 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5421 b'update'
5428 b'update'
5422 ):
5429 ):
5423 msg = _(b'update destination required by configuration')
5430 msg = _(b'update destination required by configuration')
5424 hint = _(b'use hg pull followed by hg update DEST')
5431 hint = _(b'use hg pull followed by hg update DEST')
5425 raise error.InputError(msg, hint=hint)
5432 raise error.InputError(msg, hint=hint)
5426
5433
5427 for path in urlutil.get_pull_paths(repo, ui, sources):
5434 for path in urlutil.get_pull_paths(repo, ui, sources):
5428 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5435 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5429 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5436 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5430 ui.flush()
5437 ui.flush()
5431 other = hg.peer(repo, opts, source)
5438 other = hg.peer(repo, opts, source)
5432 update_conflict = None
5439 update_conflict = None
5433 try:
5440 try:
5434 revs, checkout = hg.addbranchrevs(
5441 revs, checkout = hg.addbranchrevs(
5435 repo, other, branches, opts.get(b'rev')
5442 repo, other, branches, opts.get(b'rev')
5436 )
5443 )
5437
5444
5438 pullopargs = {}
5445 pullopargs = {}
5439
5446
5440 nodes = None
5447 nodes = None
5441 if opts.get(b'bookmark') or revs:
5448 if opts.get(b'bookmark') or revs:
5442 # The list of bookmark used here is the same used to actually update
5449 # The list of bookmark used here is the same used to actually update
5443 # the bookmark names, to avoid the race from issue 4689 and we do
5450 # the bookmark names, to avoid the race from issue 4689 and we do
5444 # all lookup and bookmark queries in one go so they see the same
5451 # all lookup and bookmark queries in one go so they see the same
5445 # version of the server state (issue 4700).
5452 # version of the server state (issue 4700).
5446 nodes = []
5453 nodes = []
5447 fnodes = []
5454 fnodes = []
5448 revs = revs or []
5455 revs = revs or []
5449 if revs and not other.capable(b'lookup'):
5456 if revs and not other.capable(b'lookup'):
5450 err = _(
5457 err = _(
5451 b"other repository doesn't support revision lookup, "
5458 b"other repository doesn't support revision lookup, "
5452 b"so a rev cannot be specified."
5459 b"so a rev cannot be specified."
5453 )
5460 )
5454 raise error.Abort(err)
5461 raise error.Abort(err)
5455 with other.commandexecutor() as e:
5462 with other.commandexecutor() as e:
5456 fremotebookmarks = e.callcommand(
5463 fremotebookmarks = e.callcommand(
5457 b'listkeys', {b'namespace': b'bookmarks'}
5464 b'listkeys', {b'namespace': b'bookmarks'}
5458 )
5465 )
5459 for r in revs:
5466 for r in revs:
5460 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5467 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5461 remotebookmarks = fremotebookmarks.result()
5468 remotebookmarks = fremotebookmarks.result()
5462 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5469 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5463 pullopargs[b'remotebookmarks'] = remotebookmarks
5470 pullopargs[b'remotebookmarks'] = remotebookmarks
5464 for b in opts.get(b'bookmark', []):
5471 for b in opts.get(b'bookmark', []):
5465 b = repo._bookmarks.expandname(b)
5472 b = repo._bookmarks.expandname(b)
5466 if b not in remotebookmarks:
5473 if b not in remotebookmarks:
5467 raise error.InputError(
5474 raise error.InputError(
5468 _(b'remote bookmark %s not found!') % b
5475 _(b'remote bookmark %s not found!') % b
5469 )
5476 )
5470 nodes.append(remotebookmarks[b])
5477 nodes.append(remotebookmarks[b])
5471 for i, rev in enumerate(revs):
5478 for i, rev in enumerate(revs):
5472 node = fnodes[i].result()
5479 node = fnodes[i].result()
5473 nodes.append(node)
5480 nodes.append(node)
5474 if rev == checkout:
5481 if rev == checkout:
5475 checkout = node
5482 checkout = node
5476
5483
5477 wlock = util.nullcontextmanager()
5484 wlock = util.nullcontextmanager()
5478 if opts.get(b'update'):
5485 if opts.get(b'update'):
5479 wlock = repo.wlock()
5486 wlock = repo.wlock()
5480 with wlock:
5487 with wlock:
5481 pullopargs.update(opts.get(b'opargs', {}))
5488 pullopargs.update(opts.get(b'opargs', {}))
5482 modheads = exchange.pull(
5489 modheads = exchange.pull(
5483 repo,
5490 repo,
5484 other,
5491 other,
5485 path=path,
5492 path=path,
5486 heads=nodes,
5493 heads=nodes,
5487 force=opts.get(b'force'),
5494 force=opts.get(b'force'),
5488 bookmarks=opts.get(b'bookmark', ()),
5495 bookmarks=opts.get(b'bookmark', ()),
5489 opargs=pullopargs,
5496 opargs=pullopargs,
5490 confirm=opts.get(b'confirm'),
5497 confirm=opts.get(b'confirm'),
5491 ).cgresult
5498 ).cgresult
5492
5499
5493 # brev is a name, which might be a bookmark to be activated at
5500 # brev is a name, which might be a bookmark to be activated at
5494 # the end of the update. In other words, it is an explicit
5501 # the end of the update. In other words, it is an explicit
5495 # destination of the update
5502 # destination of the update
5496 brev = None
5503 brev = None
5497
5504
5498 if checkout:
5505 if checkout:
5499 checkout = repo.unfiltered().changelog.rev(checkout)
5506 checkout = repo.unfiltered().changelog.rev(checkout)
5500
5507
5501 # order below depends on implementation of
5508 # order below depends on implementation of
5502 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5509 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5503 # because 'checkout' is determined without it.
5510 # because 'checkout' is determined without it.
5504 if opts.get(b'rev'):
5511 if opts.get(b'rev'):
5505 brev = opts[b'rev'][0]
5512 brev = opts[b'rev'][0]
5506 elif opts.get(b'branch'):
5513 elif opts.get(b'branch'):
5507 brev = opts[b'branch'][0]
5514 brev = opts[b'branch'][0]
5508 else:
5515 else:
5509 brev = branches[0]
5516 brev = branches[0]
5510 repo._subtoppath = source
5517 repo._subtoppath = source
5511 try:
5518 try:
5512 update_conflict = postincoming(
5519 update_conflict = postincoming(
5513 ui, repo, modheads, opts.get(b'update'), checkout, brev
5520 ui, repo, modheads, opts.get(b'update'), checkout, brev
5514 )
5521 )
5515 except error.FilteredRepoLookupError as exc:
5522 except error.FilteredRepoLookupError as exc:
5516 msg = _(b'cannot update to target: %s') % exc.args[0]
5523 msg = _(b'cannot update to target: %s') % exc.args[0]
5517 exc.args = (msg,) + exc.args[1:]
5524 exc.args = (msg,) + exc.args[1:]
5518 raise
5525 raise
5519 finally:
5526 finally:
5520 del repo._subtoppath
5527 del repo._subtoppath
5521
5528
5522 finally:
5529 finally:
5523 other.close()
5530 other.close()
5524 # skip the remaining pull source if they are some conflict.
5531 # skip the remaining pull source if they are some conflict.
5525 if update_conflict:
5532 if update_conflict:
5526 break
5533 break
5527 if update_conflict:
5534 if update_conflict:
5528 return 1
5535 return 1
5529 else:
5536 else:
5530 return 0
5537 return 0
5531
5538
5532
5539
5533 @command(
5540 @command(
5534 b'purge|clean',
5541 b'purge|clean',
5535 [
5542 [
5536 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5543 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5537 (b'', b'all', None, _(b'purge ignored files too')),
5544 (b'', b'all', None, _(b'purge ignored files too')),
5538 (b'i', b'ignored', None, _(b'purge only ignored files')),
5545 (b'i', b'ignored', None, _(b'purge only ignored files')),
5539 (b'', b'dirs', None, _(b'purge empty directories')),
5546 (b'', b'dirs', None, _(b'purge empty directories')),
5540 (b'', b'files', None, _(b'purge files')),
5547 (b'', b'files', None, _(b'purge files')),
5541 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5548 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5542 (
5549 (
5543 b'0',
5550 b'0',
5544 b'print0',
5551 b'print0',
5545 None,
5552 None,
5546 _(
5553 _(
5547 b'end filenames with NUL, for use with xargs'
5554 b'end filenames with NUL, for use with xargs'
5548 b' (implies -p/--print)'
5555 b' (implies -p/--print)'
5549 ),
5556 ),
5550 ),
5557 ),
5551 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5558 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5552 ]
5559 ]
5553 + cmdutil.walkopts,
5560 + cmdutil.walkopts,
5554 _(b'hg purge [OPTION]... [DIR]...'),
5561 _(b'hg purge [OPTION]... [DIR]...'),
5555 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5562 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5556 )
5563 )
5557 def purge(ui, repo, *dirs, **opts):
5564 def purge(ui, repo, *dirs, **opts):
5558 """removes files not tracked by Mercurial
5565 """removes files not tracked by Mercurial
5559
5566
5560 Delete files not known to Mercurial. This is useful to test local
5567 Delete files not known to Mercurial. This is useful to test local
5561 and uncommitted changes in an otherwise-clean source tree.
5568 and uncommitted changes in an otherwise-clean source tree.
5562
5569
5563 This means that purge will delete the following by default:
5570 This means that purge will delete the following by default:
5564
5571
5565 - Unknown files: files marked with "?" by :hg:`status`
5572 - Unknown files: files marked with "?" by :hg:`status`
5566 - Empty directories: in fact Mercurial ignores directories unless
5573 - Empty directories: in fact Mercurial ignores directories unless
5567 they contain files under source control management
5574 they contain files under source control management
5568
5575
5569 But it will leave untouched:
5576 But it will leave untouched:
5570
5577
5571 - Modified and unmodified tracked files
5578 - Modified and unmodified tracked files
5572 - Ignored files (unless -i or --all is specified)
5579 - Ignored files (unless -i or --all is specified)
5573 - New files added to the repository (with :hg:`add`)
5580 - New files added to the repository (with :hg:`add`)
5574
5581
5575 The --files and --dirs options can be used to direct purge to delete
5582 The --files and --dirs options can be used to direct purge to delete
5576 only files, only directories, or both. If neither option is given,
5583 only files, only directories, or both. If neither option is given,
5577 both will be deleted.
5584 both will be deleted.
5578
5585
5579 If directories are given on the command line, only files in these
5586 If directories are given on the command line, only files in these
5580 directories are considered.
5587 directories are considered.
5581
5588
5582 Be careful with purge, as you could irreversibly delete some files
5589 Be careful with purge, as you could irreversibly delete some files
5583 you forgot to add to the repository. If you only want to print the
5590 you forgot to add to the repository. If you only want to print the
5584 list of files that this program would delete, use the --print
5591 list of files that this program would delete, use the --print
5585 option.
5592 option.
5586 """
5593 """
5587 opts = pycompat.byteskwargs(opts)
5594 opts = pycompat.byteskwargs(opts)
5588 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5595 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5589
5596
5590 act = not opts.get(b'print')
5597 act = not opts.get(b'print')
5591 eol = b'\n'
5598 eol = b'\n'
5592 if opts.get(b'print0'):
5599 if opts.get(b'print0'):
5593 eol = b'\0'
5600 eol = b'\0'
5594 act = False # --print0 implies --print
5601 act = False # --print0 implies --print
5595 if opts.get(b'all', False):
5602 if opts.get(b'all', False):
5596 ignored = True
5603 ignored = True
5597 unknown = True
5604 unknown = True
5598 else:
5605 else:
5599 ignored = opts.get(b'ignored', False)
5606 ignored = opts.get(b'ignored', False)
5600 unknown = not ignored
5607 unknown = not ignored
5601
5608
5602 removefiles = opts.get(b'files')
5609 removefiles = opts.get(b'files')
5603 removedirs = opts.get(b'dirs')
5610 removedirs = opts.get(b'dirs')
5604 confirm = opts.get(b'confirm')
5611 confirm = opts.get(b'confirm')
5605 if confirm is None:
5612 if confirm is None:
5606 try:
5613 try:
5607 extensions.find(b'purge')
5614 extensions.find(b'purge')
5608 confirm = False
5615 confirm = False
5609 except KeyError:
5616 except KeyError:
5610 confirm = True
5617 confirm = True
5611
5618
5612 if not removefiles and not removedirs:
5619 if not removefiles and not removedirs:
5613 removefiles = True
5620 removefiles = True
5614 removedirs = True
5621 removedirs = True
5615
5622
5616 match = scmutil.match(repo[None], dirs, opts)
5623 match = scmutil.match(repo[None], dirs, opts)
5617
5624
5618 paths = mergemod.purge(
5625 paths = mergemod.purge(
5619 repo,
5626 repo,
5620 match,
5627 match,
5621 unknown=unknown,
5628 unknown=unknown,
5622 ignored=ignored,
5629 ignored=ignored,
5623 removeemptydirs=removedirs,
5630 removeemptydirs=removedirs,
5624 removefiles=removefiles,
5631 removefiles=removefiles,
5625 abortonerror=opts.get(b'abort_on_err'),
5632 abortonerror=opts.get(b'abort_on_err'),
5626 noop=not act,
5633 noop=not act,
5627 confirm=confirm,
5634 confirm=confirm,
5628 )
5635 )
5629
5636
5630 for path in paths:
5637 for path in paths:
5631 if not act:
5638 if not act:
5632 ui.write(b'%s%s' % (path, eol))
5639 ui.write(b'%s%s' % (path, eol))
5633
5640
5634
5641
5635 @command(
5642 @command(
5636 b'push',
5643 b'push',
5637 [
5644 [
5638 (b'f', b'force', None, _(b'force push')),
5645 (b'f', b'force', None, _(b'force push')),
5639 (
5646 (
5640 b'r',
5647 b'r',
5641 b'rev',
5648 b'rev',
5642 [],
5649 [],
5643 _(b'a changeset intended to be included in the destination'),
5650 _(b'a changeset intended to be included in the destination'),
5644 _(b'REV'),
5651 _(b'REV'),
5645 ),
5652 ),
5646 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5653 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5647 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5654 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5648 (
5655 (
5649 b'b',
5656 b'b',
5650 b'branch',
5657 b'branch',
5651 [],
5658 [],
5652 _(b'a specific branch you would like to push'),
5659 _(b'a specific branch you would like to push'),
5653 _(b'BRANCH'),
5660 _(b'BRANCH'),
5654 ),
5661 ),
5655 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5662 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5656 (
5663 (
5657 b'',
5664 b'',
5658 b'pushvars',
5665 b'pushvars',
5659 [],
5666 [],
5660 _(b'variables that can be sent to server (ADVANCED)'),
5667 _(b'variables that can be sent to server (ADVANCED)'),
5661 ),
5668 ),
5662 (
5669 (
5663 b'',
5670 b'',
5664 b'publish',
5671 b'publish',
5665 False,
5672 False,
5666 _(b'push the changeset as public (EXPERIMENTAL)'),
5673 _(b'push the changeset as public (EXPERIMENTAL)'),
5667 ),
5674 ),
5668 ]
5675 ]
5669 + remoteopts,
5676 + remoteopts,
5670 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5677 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5671 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5678 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5672 helpbasic=True,
5679 helpbasic=True,
5673 )
5680 )
5674 def push(ui, repo, *dests, **opts):
5681 def push(ui, repo, *dests, **opts):
5675 """push changes to the specified destination
5682 """push changes to the specified destination
5676
5683
5677 Push changesets from the local repository to the specified
5684 Push changesets from the local repository to the specified
5678 destination.
5685 destination.
5679
5686
5680 This operation is symmetrical to pull: it is identical to a pull
5687 This operation is symmetrical to pull: it is identical to a pull
5681 in the destination repository from the current one.
5688 in the destination repository from the current one.
5682
5689
5683 By default, push will not allow creation of new heads at the
5690 By default, push will not allow creation of new heads at the
5684 destination, since multiple heads would make it unclear which head
5691 destination, since multiple heads would make it unclear which head
5685 to use. In this situation, it is recommended to pull and merge
5692 to use. In this situation, it is recommended to pull and merge
5686 before pushing.
5693 before pushing.
5687
5694
5688 Use --new-branch if you want to allow push to create a new named
5695 Use --new-branch if you want to allow push to create a new named
5689 branch that is not present at the destination. This allows you to
5696 branch that is not present at the destination. This allows you to
5690 only create a new branch without forcing other changes.
5697 only create a new branch without forcing other changes.
5691
5698
5692 .. note::
5699 .. note::
5693
5700
5694 Extra care should be taken with the -f/--force option,
5701 Extra care should be taken with the -f/--force option,
5695 which will push all new heads on all branches, an action which will
5702 which will push all new heads on all branches, an action which will
5696 almost always cause confusion for collaborators.
5703 almost always cause confusion for collaborators.
5697
5704
5698 If -r/--rev is used, the specified revision and all its ancestors
5705 If -r/--rev is used, the specified revision and all its ancestors
5699 will be pushed to the remote repository.
5706 will be pushed to the remote repository.
5700
5707
5701 If -B/--bookmark is used, the specified bookmarked revision, its
5708 If -B/--bookmark is used, the specified bookmarked revision, its
5702 ancestors, and the bookmark will be pushed to the remote
5709 ancestors, and the bookmark will be pushed to the remote
5703 repository. Specifying ``.`` is equivalent to specifying the active
5710 repository. Specifying ``.`` is equivalent to specifying the active
5704 bookmark's name. Use the --all-bookmarks option for pushing all
5711 bookmark's name. Use the --all-bookmarks option for pushing all
5705 current bookmarks.
5712 current bookmarks.
5706
5713
5707 Please see :hg:`help urls` for important details about ``ssh://``
5714 Please see :hg:`help urls` for important details about ``ssh://``
5708 URLs. If DESTINATION is omitted, a default path will be used.
5715 URLs. If DESTINATION is omitted, a default path will be used.
5709
5716
5710 When passed multiple destinations, push will process them one after the
5717 When passed multiple destinations, push will process them one after the
5711 other, but stop should an error occur.
5718 other, but stop should an error occur.
5712
5719
5713 .. container:: verbose
5720 .. container:: verbose
5714
5721
5715 The --pushvars option sends strings to the server that become
5722 The --pushvars option sends strings to the server that become
5716 environment variables prepended with ``HG_USERVAR_``. For example,
5723 environment variables prepended with ``HG_USERVAR_``. For example,
5717 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5724 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5718 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5725 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5719
5726
5720 pushvars can provide for user-overridable hooks as well as set debug
5727 pushvars can provide for user-overridable hooks as well as set debug
5721 levels. One example is having a hook that blocks commits containing
5728 levels. One example is having a hook that blocks commits containing
5722 conflict markers, but enables the user to override the hook if the file
5729 conflict markers, but enables the user to override the hook if the file
5723 is using conflict markers for testing purposes or the file format has
5730 is using conflict markers for testing purposes or the file format has
5724 strings that look like conflict markers.
5731 strings that look like conflict markers.
5725
5732
5726 By default, servers will ignore `--pushvars`. To enable it add the
5733 By default, servers will ignore `--pushvars`. To enable it add the
5727 following to your configuration file::
5734 following to your configuration file::
5728
5735
5729 [push]
5736 [push]
5730 pushvars.server = true
5737 pushvars.server = true
5731
5738
5732 Returns 0 if push was successful, 1 if nothing to push.
5739 Returns 0 if push was successful, 1 if nothing to push.
5733 """
5740 """
5734
5741
5735 opts = pycompat.byteskwargs(opts)
5742 opts = pycompat.byteskwargs(opts)
5736
5743
5737 if opts.get(b'all_bookmarks'):
5744 if opts.get(b'all_bookmarks'):
5738 cmdutil.check_incompatible_arguments(
5745 cmdutil.check_incompatible_arguments(
5739 opts,
5746 opts,
5740 b'all_bookmarks',
5747 b'all_bookmarks',
5741 [b'bookmark', b'rev'],
5748 [b'bookmark', b'rev'],
5742 )
5749 )
5743 opts[b'bookmark'] = list(repo._bookmarks)
5750 opts[b'bookmark'] = list(repo._bookmarks)
5744
5751
5745 if opts.get(b'bookmark'):
5752 if opts.get(b'bookmark'):
5746 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5753 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5747 for b in opts[b'bookmark']:
5754 for b in opts[b'bookmark']:
5748 # translate -B options to -r so changesets get pushed
5755 # translate -B options to -r so changesets get pushed
5749 b = repo._bookmarks.expandname(b)
5756 b = repo._bookmarks.expandname(b)
5750 if b in repo._bookmarks:
5757 if b in repo._bookmarks:
5751 opts.setdefault(b'rev', []).append(b)
5758 opts.setdefault(b'rev', []).append(b)
5752 else:
5759 else:
5753 # if we try to push a deleted bookmark, translate it to null
5760 # if we try to push a deleted bookmark, translate it to null
5754 # this lets simultaneous -r, -b options continue working
5761 # this lets simultaneous -r, -b options continue working
5755 opts.setdefault(b'rev', []).append(b"null")
5762 opts.setdefault(b'rev', []).append(b"null")
5756
5763
5757 some_pushed = False
5764 some_pushed = False
5758 result = 0
5765 result = 0
5759 for path in urlutil.get_push_paths(repo, ui, dests):
5766 for path in urlutil.get_push_paths(repo, ui, dests):
5760 dest = path.pushloc or path.loc
5767 dest = path.pushloc or path.loc
5761 branches = (path.branch, opts.get(b'branch') or [])
5768 branches = (path.branch, opts.get(b'branch') or [])
5762 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5769 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5763 revs, checkout = hg.addbranchrevs(
5770 revs, checkout = hg.addbranchrevs(
5764 repo, repo, branches, opts.get(b'rev')
5771 repo, repo, branches, opts.get(b'rev')
5765 )
5772 )
5766 other = hg.peer(repo, opts, dest)
5773 other = hg.peer(repo, opts, dest)
5767
5774
5768 try:
5775 try:
5769 if revs:
5776 if revs:
5770 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5777 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5771 if not revs:
5778 if not revs:
5772 raise error.InputError(
5779 raise error.InputError(
5773 _(b"specified revisions evaluate to an empty set"),
5780 _(b"specified revisions evaluate to an empty set"),
5774 hint=_(b"use different revision arguments"),
5781 hint=_(b"use different revision arguments"),
5775 )
5782 )
5776 elif path.pushrev:
5783 elif path.pushrev:
5777 # It doesn't make any sense to specify ancestor revisions. So limit
5784 # It doesn't make any sense to specify ancestor revisions. So limit
5778 # to DAG heads to make discovery simpler.
5785 # to DAG heads to make discovery simpler.
5779 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5786 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5780 revs = scmutil.revrange(repo, [expr])
5787 revs = scmutil.revrange(repo, [expr])
5781 revs = [repo[rev].node() for rev in revs]
5788 revs = [repo[rev].node() for rev in revs]
5782 if not revs:
5789 if not revs:
5783 raise error.InputError(
5790 raise error.InputError(
5784 _(
5791 _(
5785 b'default push revset for path evaluates to an empty set'
5792 b'default push revset for path evaluates to an empty set'
5786 )
5793 )
5787 )
5794 )
5788 elif ui.configbool(b'commands', b'push.require-revs'):
5795 elif ui.configbool(b'commands', b'push.require-revs'):
5789 raise error.InputError(
5796 raise error.InputError(
5790 _(b'no revisions specified to push'),
5797 _(b'no revisions specified to push'),
5791 hint=_(b'did you mean "hg push -r ."?'),
5798 hint=_(b'did you mean "hg push -r ."?'),
5792 )
5799 )
5793
5800
5794 repo._subtoppath = dest
5801 repo._subtoppath = dest
5795 try:
5802 try:
5796 # push subrepos depth-first for coherent ordering
5803 # push subrepos depth-first for coherent ordering
5797 c = repo[b'.']
5804 c = repo[b'.']
5798 subs = c.substate # only repos that are committed
5805 subs = c.substate # only repos that are committed
5799 for s in sorted(subs):
5806 for s in sorted(subs):
5800 sub_result = c.sub(s).push(opts)
5807 sub_result = c.sub(s).push(opts)
5801 if sub_result == 0:
5808 if sub_result == 0:
5802 return 1
5809 return 1
5803 finally:
5810 finally:
5804 del repo._subtoppath
5811 del repo._subtoppath
5805
5812
5806 opargs = dict(
5813 opargs = dict(
5807 opts.get(b'opargs', {})
5814 opts.get(b'opargs', {})
5808 ) # copy opargs since we may mutate it
5815 ) # copy opargs since we may mutate it
5809 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5816 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5810
5817
5811 pushop = exchange.push(
5818 pushop = exchange.push(
5812 repo,
5819 repo,
5813 other,
5820 other,
5814 opts.get(b'force'),
5821 opts.get(b'force'),
5815 revs=revs,
5822 revs=revs,
5816 newbranch=opts.get(b'new_branch'),
5823 newbranch=opts.get(b'new_branch'),
5817 bookmarks=opts.get(b'bookmark', ()),
5824 bookmarks=opts.get(b'bookmark', ()),
5818 publish=opts.get(b'publish'),
5825 publish=opts.get(b'publish'),
5819 opargs=opargs,
5826 opargs=opargs,
5820 )
5827 )
5821
5828
5822 if pushop.cgresult == 0:
5829 if pushop.cgresult == 0:
5823 result = 1
5830 result = 1
5824 elif pushop.cgresult is not None:
5831 elif pushop.cgresult is not None:
5825 some_pushed = True
5832 some_pushed = True
5826
5833
5827 if pushop.bkresult is not None:
5834 if pushop.bkresult is not None:
5828 if pushop.bkresult == 2:
5835 if pushop.bkresult == 2:
5829 result = 2
5836 result = 2
5830 elif not result and pushop.bkresult:
5837 elif not result and pushop.bkresult:
5831 result = 2
5838 result = 2
5832
5839
5833 if result:
5840 if result:
5834 break
5841 break
5835
5842
5836 finally:
5843 finally:
5837 other.close()
5844 other.close()
5838 if result == 0 and not some_pushed:
5845 if result == 0 and not some_pushed:
5839 result = 1
5846 result = 1
5840 return result
5847 return result
5841
5848
5842
5849
5843 @command(
5850 @command(
5844 b'recover',
5851 b'recover',
5845 [
5852 [
5846 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5853 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5847 ],
5854 ],
5848 helpcategory=command.CATEGORY_MAINTENANCE,
5855 helpcategory=command.CATEGORY_MAINTENANCE,
5849 )
5856 )
5850 def recover(ui, repo, **opts):
5857 def recover(ui, repo, **opts):
5851 """roll back an interrupted transaction
5858 """roll back an interrupted transaction
5852
5859
5853 Recover from an interrupted commit or pull.
5860 Recover from an interrupted commit or pull.
5854
5861
5855 This command tries to fix the repository status after an
5862 This command tries to fix the repository status after an
5856 interrupted operation. It should only be necessary when Mercurial
5863 interrupted operation. It should only be necessary when Mercurial
5857 suggests it.
5864 suggests it.
5858
5865
5859 Returns 0 if successful, 1 if nothing to recover or verify fails.
5866 Returns 0 if successful, 1 if nothing to recover or verify fails.
5860 """
5867 """
5861 ret = repo.recover()
5868 ret = repo.recover()
5862 if ret:
5869 if ret:
5863 if opts['verify']:
5870 if opts['verify']:
5864 return hg.verify(repo)
5871 return hg.verify(repo)
5865 else:
5872 else:
5866 msg = _(
5873 msg = _(
5867 b"(verify step skipped, run `hg verify` to check your "
5874 b"(verify step skipped, run `hg verify` to check your "
5868 b"repository content)\n"
5875 b"repository content)\n"
5869 )
5876 )
5870 ui.warn(msg)
5877 ui.warn(msg)
5871 return 0
5878 return 0
5872 return 1
5879 return 1
5873
5880
5874
5881
5875 @command(
5882 @command(
5876 b'remove|rm',
5883 b'remove|rm',
5877 [
5884 [
5878 (b'A', b'after', None, _(b'record delete for missing files')),
5885 (b'A', b'after', None, _(b'record delete for missing files')),
5879 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5886 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5880 ]
5887 ]
5881 + subrepoopts
5888 + subrepoopts
5882 + walkopts
5889 + walkopts
5883 + dryrunopts,
5890 + dryrunopts,
5884 _(b'[OPTION]... FILE...'),
5891 _(b'[OPTION]... FILE...'),
5885 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5892 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5886 helpbasic=True,
5893 helpbasic=True,
5887 inferrepo=True,
5894 inferrepo=True,
5888 )
5895 )
5889 def remove(ui, repo, *pats, **opts):
5896 def remove(ui, repo, *pats, **opts):
5890 """remove the specified files on the next commit
5897 """remove the specified files on the next commit
5891
5898
5892 Schedule the indicated files for removal from the current branch.
5899 Schedule the indicated files for removal from the current branch.
5893
5900
5894 This command schedules the files to be removed at the next commit.
5901 This command schedules the files to be removed at the next commit.
5895 To undo a remove before that, see :hg:`revert`. To undo added
5902 To undo a remove before that, see :hg:`revert`. To undo added
5896 files, see :hg:`forget`.
5903 files, see :hg:`forget`.
5897
5904
5898 .. container:: verbose
5905 .. container:: verbose
5899
5906
5900 -A/--after can be used to remove only files that have already
5907 -A/--after can be used to remove only files that have already
5901 been deleted, -f/--force can be used to force deletion, and -Af
5908 been deleted, -f/--force can be used to force deletion, and -Af
5902 can be used to remove files from the next revision without
5909 can be used to remove files from the next revision without
5903 deleting them from the working directory.
5910 deleting them from the working directory.
5904
5911
5905 The following table details the behavior of remove for different
5912 The following table details the behavior of remove for different
5906 file states (columns) and option combinations (rows). The file
5913 file states (columns) and option combinations (rows). The file
5907 states are Added [A], Clean [C], Modified [M] and Missing [!]
5914 states are Added [A], Clean [C], Modified [M] and Missing [!]
5908 (as reported by :hg:`status`). The actions are Warn, Remove
5915 (as reported by :hg:`status`). The actions are Warn, Remove
5909 (from branch) and Delete (from disk):
5916 (from branch) and Delete (from disk):
5910
5917
5911 ========= == == == ==
5918 ========= == == == ==
5912 opt/state A C M !
5919 opt/state A C M !
5913 ========= == == == ==
5920 ========= == == == ==
5914 none W RD W R
5921 none W RD W R
5915 -f R RD RD R
5922 -f R RD RD R
5916 -A W W W R
5923 -A W W W R
5917 -Af R R R R
5924 -Af R R R R
5918 ========= == == == ==
5925 ========= == == == ==
5919
5926
5920 .. note::
5927 .. note::
5921
5928
5922 :hg:`remove` never deletes files in Added [A] state from the
5929 :hg:`remove` never deletes files in Added [A] state from the
5923 working directory, not even if ``--force`` is specified.
5930 working directory, not even if ``--force`` is specified.
5924
5931
5925 Returns 0 on success, 1 if any warnings encountered.
5932 Returns 0 on success, 1 if any warnings encountered.
5926 """
5933 """
5927
5934
5928 opts = pycompat.byteskwargs(opts)
5935 opts = pycompat.byteskwargs(opts)
5929 after, force = opts.get(b'after'), opts.get(b'force')
5936 after, force = opts.get(b'after'), opts.get(b'force')
5930 dryrun = opts.get(b'dry_run')
5937 dryrun = opts.get(b'dry_run')
5931 if not pats and not after:
5938 if not pats and not after:
5932 raise error.InputError(_(b'no files specified'))
5939 raise error.InputError(_(b'no files specified'))
5933
5940
5934 m = scmutil.match(repo[None], pats, opts)
5941 m = scmutil.match(repo[None], pats, opts)
5935 subrepos = opts.get(b'subrepos')
5942 subrepos = opts.get(b'subrepos')
5936 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5943 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5937 return cmdutil.remove(
5944 return cmdutil.remove(
5938 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5945 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5939 )
5946 )
5940
5947
5941
5948
5942 @command(
5949 @command(
5943 b'rename|move|mv',
5950 b'rename|move|mv',
5944 [
5951 [
5945 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5952 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5946 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5953 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5947 (
5954 (
5948 b'',
5955 b'',
5949 b'at-rev',
5956 b'at-rev',
5950 b'',
5957 b'',
5951 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5958 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5952 _(b'REV'),
5959 _(b'REV'),
5953 ),
5960 ),
5954 (
5961 (
5955 b'f',
5962 b'f',
5956 b'force',
5963 b'force',
5957 None,
5964 None,
5958 _(b'forcibly move over an existing managed file'),
5965 _(b'forcibly move over an existing managed file'),
5959 ),
5966 ),
5960 ]
5967 ]
5961 + walkopts
5968 + walkopts
5962 + dryrunopts,
5969 + dryrunopts,
5963 _(b'[OPTION]... SOURCE... DEST'),
5970 _(b'[OPTION]... SOURCE... DEST'),
5964 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5971 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5965 )
5972 )
5966 def rename(ui, repo, *pats, **opts):
5973 def rename(ui, repo, *pats, **opts):
5967 """rename files; equivalent of copy + remove
5974 """rename files; equivalent of copy + remove
5968
5975
5969 Mark dest as copies of sources; mark sources for deletion. If dest
5976 Mark dest as copies of sources; mark sources for deletion. If dest
5970 is a directory, copies are put in that directory. If dest is a
5977 is a directory, copies are put in that directory. If dest is a
5971 file, there can only be one source.
5978 file, there can only be one source.
5972
5979
5973 By default, this command copies the contents of files as they
5980 By default, this command copies the contents of files as they
5974 exist in the working directory. If invoked with -A/--after, the
5981 exist in the working directory. If invoked with -A/--after, the
5975 operation is recorded, but no copying is performed.
5982 operation is recorded, but no copying is performed.
5976
5983
5977 To undo marking a destination file as renamed, use --forget. With that
5984 To undo marking a destination file as renamed, use --forget. With that
5978 option, all given (positional) arguments are unmarked as renames. The
5985 option, all given (positional) arguments are unmarked as renames. The
5979 destination file(s) will be left in place (still tracked). The source
5986 destination file(s) will be left in place (still tracked). The source
5980 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5987 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5981 the same way as :hg:`copy --forget`.
5988 the same way as :hg:`copy --forget`.
5982
5989
5983 This command takes effect with the next commit by default.
5990 This command takes effect with the next commit by default.
5984
5991
5985 Returns 0 on success, 1 if errors are encountered.
5992 Returns 0 on success, 1 if errors are encountered.
5986 """
5993 """
5987 opts = pycompat.byteskwargs(opts)
5994 opts = pycompat.byteskwargs(opts)
5988 with repo.wlock():
5995 with repo.wlock():
5989 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5996 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5990
5997
5991
5998
5992 @command(
5999 @command(
5993 b'resolve',
6000 b'resolve',
5994 [
6001 [
5995 (b'a', b'all', None, _(b'select all unresolved files')),
6002 (b'a', b'all', None, _(b'select all unresolved files')),
5996 (b'l', b'list', None, _(b'list state of files needing merge')),
6003 (b'l', b'list', None, _(b'list state of files needing merge')),
5997 (b'm', b'mark', None, _(b'mark files as resolved')),
6004 (b'm', b'mark', None, _(b'mark files as resolved')),
5998 (b'u', b'unmark', None, _(b'mark files as unresolved')),
6005 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5999 (b'n', b'no-status', None, _(b'hide status prefix')),
6006 (b'n', b'no-status', None, _(b'hide status prefix')),
6000 (b'', b're-merge', None, _(b're-merge files')),
6007 (b'', b're-merge', None, _(b're-merge files')),
6001 ]
6008 ]
6002 + mergetoolopts
6009 + mergetoolopts
6003 + walkopts
6010 + walkopts
6004 + formatteropts,
6011 + formatteropts,
6005 _(b'[OPTION]... [FILE]...'),
6012 _(b'[OPTION]... [FILE]...'),
6006 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6013 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6007 inferrepo=True,
6014 inferrepo=True,
6008 )
6015 )
6009 def resolve(ui, repo, *pats, **opts):
6016 def resolve(ui, repo, *pats, **opts):
6010 """redo merges or set/view the merge status of files
6017 """redo merges or set/view the merge status of files
6011
6018
6012 Merges with unresolved conflicts are often the result of
6019 Merges with unresolved conflicts are often the result of
6013 non-interactive merging using the ``internal:merge`` configuration
6020 non-interactive merging using the ``internal:merge`` configuration
6014 setting, or a command-line merge tool like ``diff3``. The resolve
6021 setting, or a command-line merge tool like ``diff3``. The resolve
6015 command is used to manage the files involved in a merge, after
6022 command is used to manage the files involved in a merge, after
6016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6023 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6017 working directory must have two parents). See :hg:`help
6024 working directory must have two parents). See :hg:`help
6018 merge-tools` for information on configuring merge tools.
6025 merge-tools` for information on configuring merge tools.
6019
6026
6020 The resolve command can be used in the following ways:
6027 The resolve command can be used in the following ways:
6021
6028
6022 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6029 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6023 the specified files, discarding any previous merge attempts. Re-merging
6030 the specified files, discarding any previous merge attempts. Re-merging
6024 is not performed for files already marked as resolved. Use ``--all/-a``
6031 is not performed for files already marked as resolved. Use ``--all/-a``
6025 to select all unresolved files. ``--tool`` can be used to specify
6032 to select all unresolved files. ``--tool`` can be used to specify
6026 the merge tool used for the given files. It overrides the HGMERGE
6033 the merge tool used for the given files. It overrides the HGMERGE
6027 environment variable and your configuration files. Previous file
6034 environment variable and your configuration files. Previous file
6028 contents are saved with a ``.orig`` suffix.
6035 contents are saved with a ``.orig`` suffix.
6029
6036
6030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6037 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6031 (e.g. after having manually fixed-up the files). The default is
6038 (e.g. after having manually fixed-up the files). The default is
6032 to mark all unresolved files.
6039 to mark all unresolved files.
6033
6040
6034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6041 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6035 default is to mark all resolved files.
6042 default is to mark all resolved files.
6036
6043
6037 - :hg:`resolve -l`: list files which had or still have conflicts.
6044 - :hg:`resolve -l`: list files which had or still have conflicts.
6038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6045 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6039 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6046 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6040 the list. See :hg:`help filesets` for details.
6047 the list. See :hg:`help filesets` for details.
6041
6048
6042 .. note::
6049 .. note::
6043
6050
6044 Mercurial will not let you commit files with unresolved merge
6051 Mercurial will not let you commit files with unresolved merge
6045 conflicts. You must use :hg:`resolve -m ...` before you can
6052 conflicts. You must use :hg:`resolve -m ...` before you can
6046 commit after a conflicting merge.
6053 commit after a conflicting merge.
6047
6054
6048 .. container:: verbose
6055 .. container:: verbose
6049
6056
6050 Template:
6057 Template:
6051
6058
6052 The following keywords are supported in addition to the common template
6059 The following keywords are supported in addition to the common template
6053 keywords and functions. See also :hg:`help templates`.
6060 keywords and functions. See also :hg:`help templates`.
6054
6061
6055 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6062 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6056 :path: String. Repository-absolute path of the file.
6063 :path: String. Repository-absolute path of the file.
6057
6064
6058 Returns 0 on success, 1 if any files fail a resolve attempt.
6065 Returns 0 on success, 1 if any files fail a resolve attempt.
6059 """
6066 """
6060
6067
6061 opts = pycompat.byteskwargs(opts)
6068 opts = pycompat.byteskwargs(opts)
6062 confirm = ui.configbool(b'commands', b'resolve.confirm')
6069 confirm = ui.configbool(b'commands', b'resolve.confirm')
6063 flaglist = b'all mark unmark list no_status re_merge'.split()
6070 flaglist = b'all mark unmark list no_status re_merge'.split()
6064 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6071 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6065
6072
6066 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6073 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6067 if actioncount > 1:
6074 if actioncount > 1:
6068 raise error.InputError(_(b"too many actions specified"))
6075 raise error.InputError(_(b"too many actions specified"))
6069 elif actioncount == 0 and ui.configbool(
6076 elif actioncount == 0 and ui.configbool(
6070 b'commands', b'resolve.explicit-re-merge'
6077 b'commands', b'resolve.explicit-re-merge'
6071 ):
6078 ):
6072 hint = _(b'use --mark, --unmark, --list or --re-merge')
6079 hint = _(b'use --mark, --unmark, --list or --re-merge')
6073 raise error.InputError(_(b'no action specified'), hint=hint)
6080 raise error.InputError(_(b'no action specified'), hint=hint)
6074 if pats and all:
6081 if pats and all:
6075 raise error.InputError(_(b"can't specify --all and patterns"))
6082 raise error.InputError(_(b"can't specify --all and patterns"))
6076 if not (all or pats or show or mark or unmark):
6083 if not (all or pats or show or mark or unmark):
6077 raise error.InputError(
6084 raise error.InputError(
6078 _(b'no files or directories specified'),
6085 _(b'no files or directories specified'),
6079 hint=b'use --all to re-merge all unresolved files',
6086 hint=b'use --all to re-merge all unresolved files',
6080 )
6087 )
6081
6088
6082 if confirm:
6089 if confirm:
6083 if all:
6090 if all:
6084 if ui.promptchoice(
6091 if ui.promptchoice(
6085 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6092 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6086 ):
6093 ):
6087 raise error.CanceledError(_(b'user quit'))
6094 raise error.CanceledError(_(b'user quit'))
6088 if mark and not pats:
6095 if mark and not pats:
6089 if ui.promptchoice(
6096 if ui.promptchoice(
6090 _(
6097 _(
6091 b'mark all unresolved files as resolved (yn)?'
6098 b'mark all unresolved files as resolved (yn)?'
6092 b'$$ &Yes $$ &No'
6099 b'$$ &Yes $$ &No'
6093 )
6100 )
6094 ):
6101 ):
6095 raise error.CanceledError(_(b'user quit'))
6102 raise error.CanceledError(_(b'user quit'))
6096 if unmark and not pats:
6103 if unmark and not pats:
6097 if ui.promptchoice(
6104 if ui.promptchoice(
6098 _(
6105 _(
6099 b'mark all resolved files as unresolved (yn)?'
6106 b'mark all resolved files as unresolved (yn)?'
6100 b'$$ &Yes $$ &No'
6107 b'$$ &Yes $$ &No'
6101 )
6108 )
6102 ):
6109 ):
6103 raise error.CanceledError(_(b'user quit'))
6110 raise error.CanceledError(_(b'user quit'))
6104
6111
6105 uipathfn = scmutil.getuipathfn(repo)
6112 uipathfn = scmutil.getuipathfn(repo)
6106
6113
6107 if show:
6114 if show:
6108 ui.pager(b'resolve')
6115 ui.pager(b'resolve')
6109 fm = ui.formatter(b'resolve', opts)
6116 fm = ui.formatter(b'resolve', opts)
6110 ms = mergestatemod.mergestate.read(repo)
6117 ms = mergestatemod.mergestate.read(repo)
6111 wctx = repo[None]
6118 wctx = repo[None]
6112 m = scmutil.match(wctx, pats, opts)
6119 m = scmutil.match(wctx, pats, opts)
6113
6120
6114 # Labels and keys based on merge state. Unresolved path conflicts show
6121 # Labels and keys based on merge state. Unresolved path conflicts show
6115 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6122 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6116 # resolved conflicts.
6123 # resolved conflicts.
6117 mergestateinfo = {
6124 mergestateinfo = {
6118 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6125 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6119 b'resolve.unresolved',
6126 b'resolve.unresolved',
6120 b'U',
6127 b'U',
6121 ),
6128 ),
6122 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6129 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6123 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6130 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6124 b'resolve.unresolved',
6131 b'resolve.unresolved',
6125 b'P',
6132 b'P',
6126 ),
6133 ),
6127 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6134 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6128 b'resolve.resolved',
6135 b'resolve.resolved',
6129 b'R',
6136 b'R',
6130 ),
6137 ),
6131 }
6138 }
6132
6139
6133 for f in ms:
6140 for f in ms:
6134 if not m(f):
6141 if not m(f):
6135 continue
6142 continue
6136
6143
6137 label, key = mergestateinfo[ms[f]]
6144 label, key = mergestateinfo[ms[f]]
6138 fm.startitem()
6145 fm.startitem()
6139 fm.context(ctx=wctx)
6146 fm.context(ctx=wctx)
6140 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6147 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6141 fm.data(path=f)
6148 fm.data(path=f)
6142 fm.plain(b'%s\n' % uipathfn(f), label=label)
6149 fm.plain(b'%s\n' % uipathfn(f), label=label)
6143 fm.end()
6150 fm.end()
6144 return 0
6151 return 0
6145
6152
6146 with repo.wlock():
6153 with repo.wlock():
6147 ms = mergestatemod.mergestate.read(repo)
6154 ms = mergestatemod.mergestate.read(repo)
6148
6155
6149 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6156 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6150 raise error.StateError(
6157 raise error.StateError(
6151 _(b'resolve command not applicable when not merging')
6158 _(b'resolve command not applicable when not merging')
6152 )
6159 )
6153
6160
6154 wctx = repo[None]
6161 wctx = repo[None]
6155 m = scmutil.match(wctx, pats, opts)
6162 m = scmutil.match(wctx, pats, opts)
6156 ret = 0
6163 ret = 0
6157 didwork = False
6164 didwork = False
6158
6165
6159 hasconflictmarkers = []
6166 hasconflictmarkers = []
6160 if mark:
6167 if mark:
6161 markcheck = ui.config(b'commands', b'resolve.mark-check')
6168 markcheck = ui.config(b'commands', b'resolve.mark-check')
6162 if markcheck not in [b'warn', b'abort']:
6169 if markcheck not in [b'warn', b'abort']:
6163 # Treat all invalid / unrecognized values as 'none'.
6170 # Treat all invalid / unrecognized values as 'none'.
6164 markcheck = False
6171 markcheck = False
6165 for f in ms:
6172 for f in ms:
6166 if not m(f):
6173 if not m(f):
6167 continue
6174 continue
6168
6175
6169 didwork = True
6176 didwork = True
6170
6177
6171 # path conflicts must be resolved manually
6178 # path conflicts must be resolved manually
6172 if ms[f] in (
6179 if ms[f] in (
6173 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6180 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6174 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6181 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6175 ):
6182 ):
6176 if mark:
6183 if mark:
6177 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6184 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6178 elif unmark:
6185 elif unmark:
6179 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6186 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6180 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6187 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6181 ui.warn(
6188 ui.warn(
6182 _(b'%s: path conflict must be resolved manually\n')
6189 _(b'%s: path conflict must be resolved manually\n')
6183 % uipathfn(f)
6190 % uipathfn(f)
6184 )
6191 )
6185 continue
6192 continue
6186
6193
6187 if mark:
6194 if mark:
6188 if markcheck:
6195 if markcheck:
6189 fdata = repo.wvfs.tryread(f)
6196 fdata = repo.wvfs.tryread(f)
6190 if (
6197 if (
6191 filemerge.hasconflictmarkers(fdata)
6198 filemerge.hasconflictmarkers(fdata)
6192 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6199 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6193 ):
6200 ):
6194 hasconflictmarkers.append(f)
6201 hasconflictmarkers.append(f)
6195 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6202 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6196 elif unmark:
6203 elif unmark:
6197 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6204 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6198 else:
6205 else:
6199 # backup pre-resolve (merge uses .orig for its own purposes)
6206 # backup pre-resolve (merge uses .orig for its own purposes)
6200 a = repo.wjoin(f)
6207 a = repo.wjoin(f)
6201 try:
6208 try:
6202 util.copyfile(a, a + b".resolve")
6209 util.copyfile(a, a + b".resolve")
6203 except FileNotFoundError:
6210 except FileNotFoundError:
6204 pass
6211 pass
6205
6212
6206 try:
6213 try:
6207 # preresolve file
6214 # preresolve file
6208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6215 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6209 with ui.configoverride(overrides, b'resolve'):
6216 with ui.configoverride(overrides, b'resolve'):
6210 r = ms.resolve(f, wctx)
6217 r = ms.resolve(f, wctx)
6211 if r:
6218 if r:
6212 ret = 1
6219 ret = 1
6213 finally:
6220 finally:
6214 ms.commit()
6221 ms.commit()
6215
6222
6216 # replace filemerge's .orig file with our resolve file
6223 # replace filemerge's .orig file with our resolve file
6217 try:
6224 try:
6218 util.rename(
6225 util.rename(
6219 a + b".resolve", scmutil.backuppath(ui, repo, f)
6226 a + b".resolve", scmutil.backuppath(ui, repo, f)
6220 )
6227 )
6221 except FileNotFoundError:
6228 except FileNotFoundError:
6222 pass
6229 pass
6223
6230
6224 if hasconflictmarkers:
6231 if hasconflictmarkers:
6225 ui.warn(
6232 ui.warn(
6226 _(
6233 _(
6227 b'warning: the following files still have conflict '
6234 b'warning: the following files still have conflict '
6228 b'markers:\n'
6235 b'markers:\n'
6229 )
6236 )
6230 + b''.join(
6237 + b''.join(
6231 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6238 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6232 )
6239 )
6233 )
6240 )
6234 if markcheck == b'abort' and not all and not pats:
6241 if markcheck == b'abort' and not all and not pats:
6235 raise error.StateError(
6242 raise error.StateError(
6236 _(b'conflict markers detected'),
6243 _(b'conflict markers detected'),
6237 hint=_(b'use --all to mark anyway'),
6244 hint=_(b'use --all to mark anyway'),
6238 )
6245 )
6239
6246
6240 ms.commit()
6247 ms.commit()
6241 branchmerge = repo.dirstate.p2() != repo.nullid
6248 branchmerge = repo.dirstate.p2() != repo.nullid
6242 # resolve is not doing a parent change here, however, `record updates`
6249 # resolve is not doing a parent change here, however, `record updates`
6243 # will call some dirstate API that at intended for parent changes call.
6250 # will call some dirstate API that at intended for parent changes call.
6244 # Ideally we would not need this and could implement a lighter version
6251 # Ideally we would not need this and could implement a lighter version
6245 # of the recordupdateslogic that will not have to deal with the part
6252 # of the recordupdateslogic that will not have to deal with the part
6246 # related to parent changes. However this would requires that:
6253 # related to parent changes. However this would requires that:
6247 # - we are sure we passed around enough information at update/merge
6254 # - we are sure we passed around enough information at update/merge
6248 # time to no longer needs it at `hg resolve time`
6255 # time to no longer needs it at `hg resolve time`
6249 # - we are sure we store that information well enough to be able to reuse it
6256 # - we are sure we store that information well enough to be able to reuse it
6250 # - we are the necessary logic to reuse it right.
6257 # - we are the necessary logic to reuse it right.
6251 #
6258 #
6252 # All this should eventually happens, but in the mean time, we use this
6259 # All this should eventually happens, but in the mean time, we use this
6253 # context manager slightly out of the context it should be.
6260 # context manager slightly out of the context it should be.
6254 with repo.dirstate.parentchange():
6261 with repo.dirstate.parentchange():
6255 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6262 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6256
6263
6257 if not didwork and pats:
6264 if not didwork and pats:
6258 hint = None
6265 hint = None
6259 if not any([p for p in pats if p.find(b':') >= 0]):
6266 if not any([p for p in pats if p.find(b':') >= 0]):
6260 pats = [b'path:%s' % p for p in pats]
6267 pats = [b'path:%s' % p for p in pats]
6261 m = scmutil.match(wctx, pats, opts)
6268 m = scmutil.match(wctx, pats, opts)
6262 for f in ms:
6269 for f in ms:
6263 if not m(f):
6270 if not m(f):
6264 continue
6271 continue
6265
6272
6266 def flag(o):
6273 def flag(o):
6267 if o == b're_merge':
6274 if o == b're_merge':
6268 return b'--re-merge '
6275 return b'--re-merge '
6269 return b'-%s ' % o[0:1]
6276 return b'-%s ' % o[0:1]
6270
6277
6271 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6278 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6272 hint = _(b"(try: hg resolve %s%s)\n") % (
6279 hint = _(b"(try: hg resolve %s%s)\n") % (
6273 flags,
6280 flags,
6274 b' '.join(pats),
6281 b' '.join(pats),
6275 )
6282 )
6276 break
6283 break
6277 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6284 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6278 if hint:
6285 if hint:
6279 ui.warn(hint)
6286 ui.warn(hint)
6280
6287
6281 unresolvedf = ms.unresolvedcount()
6288 unresolvedf = ms.unresolvedcount()
6282 if not unresolvedf:
6289 if not unresolvedf:
6283 ui.status(_(b'(no more unresolved files)\n'))
6290 ui.status(_(b'(no more unresolved files)\n'))
6284 cmdutil.checkafterresolved(repo)
6291 cmdutil.checkafterresolved(repo)
6285
6292
6286 return ret
6293 return ret
6287
6294
6288
6295
6289 @command(
6296 @command(
6290 b'revert',
6297 b'revert',
6291 [
6298 [
6292 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6299 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6293 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6300 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6294 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6301 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6295 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6302 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6296 (b'i', b'interactive', None, _(b'interactively select the changes')),
6303 (b'i', b'interactive', None, _(b'interactively select the changes')),
6297 ]
6304 ]
6298 + walkopts
6305 + walkopts
6299 + dryrunopts,
6306 + dryrunopts,
6300 _(b'[OPTION]... [-r REV] [NAME]...'),
6307 _(b'[OPTION]... [-r REV] [NAME]...'),
6301 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6308 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6302 )
6309 )
6303 def revert(ui, repo, *pats, **opts):
6310 def revert(ui, repo, *pats, **opts):
6304 """restore files to their checkout state
6311 """restore files to their checkout state
6305
6312
6306 .. note::
6313 .. note::
6307
6314
6308 To check out earlier revisions, you should use :hg:`update REV`.
6315 To check out earlier revisions, you should use :hg:`update REV`.
6309 To cancel an uncommitted merge (and lose your changes),
6316 To cancel an uncommitted merge (and lose your changes),
6310 use :hg:`merge --abort`.
6317 use :hg:`merge --abort`.
6311
6318
6312 With no revision specified, revert the specified files or directories
6319 With no revision specified, revert the specified files or directories
6313 to the contents they had in the parent of the working directory.
6320 to the contents they had in the parent of the working directory.
6314 This restores the contents of files to an unmodified
6321 This restores the contents of files to an unmodified
6315 state and unschedules adds, removes, copies, and renames. If the
6322 state and unschedules adds, removes, copies, and renames. If the
6316 working directory has two parents, you must explicitly specify a
6323 working directory has two parents, you must explicitly specify a
6317 revision.
6324 revision.
6318
6325
6319 Using the -r/--rev or -d/--date options, revert the given files or
6326 Using the -r/--rev or -d/--date options, revert the given files or
6320 directories to their states as of a specific revision. Because
6327 directories to their states as of a specific revision. Because
6321 revert does not change the working directory parents, this will
6328 revert does not change the working directory parents, this will
6322 cause these files to appear modified. This can be helpful to "back
6329 cause these files to appear modified. This can be helpful to "back
6323 out" some or all of an earlier change. See :hg:`backout` for a
6330 out" some or all of an earlier change. See :hg:`backout` for a
6324 related method.
6331 related method.
6325
6332
6326 Modified files are saved with a .orig suffix before reverting.
6333 Modified files are saved with a .orig suffix before reverting.
6327 To disable these backups, use --no-backup. It is possible to store
6334 To disable these backups, use --no-backup. It is possible to store
6328 the backup files in a custom directory relative to the root of the
6335 the backup files in a custom directory relative to the root of the
6329 repository by setting the ``ui.origbackuppath`` configuration
6336 repository by setting the ``ui.origbackuppath`` configuration
6330 option.
6337 option.
6331
6338
6332 See :hg:`help dates` for a list of formats valid for -d/--date.
6339 See :hg:`help dates` for a list of formats valid for -d/--date.
6333
6340
6334 See :hg:`help backout` for a way to reverse the effect of an
6341 See :hg:`help backout` for a way to reverse the effect of an
6335 earlier changeset.
6342 earlier changeset.
6336
6343
6337 Returns 0 on success.
6344 Returns 0 on success.
6338 """
6345 """
6339
6346
6340 opts = pycompat.byteskwargs(opts)
6347 opts = pycompat.byteskwargs(opts)
6341 if opts.get(b"date"):
6348 if opts.get(b"date"):
6342 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6349 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6343 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6350 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6344
6351
6345 parent, p2 = repo.dirstate.parents()
6352 parent, p2 = repo.dirstate.parents()
6346 if not opts.get(b'rev') and p2 != repo.nullid:
6353 if not opts.get(b'rev') and p2 != repo.nullid:
6347 # revert after merge is a trap for new users (issue2915)
6354 # revert after merge is a trap for new users (issue2915)
6348 raise error.InputError(
6355 raise error.InputError(
6349 _(b'uncommitted merge with no revision specified'),
6356 _(b'uncommitted merge with no revision specified'),
6350 hint=_(b"use 'hg update' or see 'hg help revert'"),
6357 hint=_(b"use 'hg update' or see 'hg help revert'"),
6351 )
6358 )
6352
6359
6353 rev = opts.get(b'rev')
6360 rev = opts.get(b'rev')
6354 if rev:
6361 if rev:
6355 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6362 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6356 ctx = logcmdutil.revsingle(repo, rev)
6363 ctx = logcmdutil.revsingle(repo, rev)
6357
6364
6358 if not (
6365 if not (
6359 pats
6366 pats
6360 or opts.get(b'include')
6367 or opts.get(b'include')
6361 or opts.get(b'exclude')
6368 or opts.get(b'exclude')
6362 or opts.get(b'all')
6369 or opts.get(b'all')
6363 or opts.get(b'interactive')
6370 or opts.get(b'interactive')
6364 ):
6371 ):
6365 msg = _(b"no files or directories specified")
6372 msg = _(b"no files or directories specified")
6366 if p2 != repo.nullid:
6373 if p2 != repo.nullid:
6367 hint = _(
6374 hint = _(
6368 b"uncommitted merge, use --all to discard all changes,"
6375 b"uncommitted merge, use --all to discard all changes,"
6369 b" or 'hg update -C .' to abort the merge"
6376 b" or 'hg update -C .' to abort the merge"
6370 )
6377 )
6371 raise error.InputError(msg, hint=hint)
6378 raise error.InputError(msg, hint=hint)
6372 dirty = any(repo.status())
6379 dirty = any(repo.status())
6373 node = ctx.node()
6380 node = ctx.node()
6374 if node != parent:
6381 if node != parent:
6375 if dirty:
6382 if dirty:
6376 hint = (
6383 hint = (
6377 _(
6384 _(
6378 b"uncommitted changes, use --all to discard all"
6385 b"uncommitted changes, use --all to discard all"
6379 b" changes, or 'hg update %d' to update"
6386 b" changes, or 'hg update %d' to update"
6380 )
6387 )
6381 % ctx.rev()
6388 % ctx.rev()
6382 )
6389 )
6383 else:
6390 else:
6384 hint = (
6391 hint = (
6385 _(
6392 _(
6386 b"use --all to revert all files,"
6393 b"use --all to revert all files,"
6387 b" or 'hg update %d' to update"
6394 b" or 'hg update %d' to update"
6388 )
6395 )
6389 % ctx.rev()
6396 % ctx.rev()
6390 )
6397 )
6391 elif dirty:
6398 elif dirty:
6392 hint = _(b"uncommitted changes, use --all to discard all changes")
6399 hint = _(b"uncommitted changes, use --all to discard all changes")
6393 else:
6400 else:
6394 hint = _(b"use --all to revert all files")
6401 hint = _(b"use --all to revert all files")
6395 raise error.InputError(msg, hint=hint)
6402 raise error.InputError(msg, hint=hint)
6396
6403
6397 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6404 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6398
6405
6399
6406
6400 @command(
6407 @command(
6401 b'rollback',
6408 b'rollback',
6402 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6409 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6403 helpcategory=command.CATEGORY_MAINTENANCE,
6410 helpcategory=command.CATEGORY_MAINTENANCE,
6404 )
6411 )
6405 def rollback(ui, repo, **opts):
6412 def rollback(ui, repo, **opts):
6406 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6413 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6407
6414
6408 Please use :hg:`commit --amend` instead of rollback to correct
6415 Please use :hg:`commit --amend` instead of rollback to correct
6409 mistakes in the last commit.
6416 mistakes in the last commit.
6410
6417
6411 This command should be used with care. There is only one level of
6418 This command should be used with care. There is only one level of
6412 rollback, and there is no way to undo a rollback. It will also
6419 rollback, and there is no way to undo a rollback. It will also
6413 restore the dirstate at the time of the last transaction, losing
6420 restore the dirstate at the time of the last transaction, losing
6414 any dirstate changes since that time. This command does not alter
6421 any dirstate changes since that time. This command does not alter
6415 the working directory.
6422 the working directory.
6416
6423
6417 Transactions are used to encapsulate the effects of all commands
6424 Transactions are used to encapsulate the effects of all commands
6418 that create new changesets or propagate existing changesets into a
6425 that create new changesets or propagate existing changesets into a
6419 repository.
6426 repository.
6420
6427
6421 .. container:: verbose
6428 .. container:: verbose
6422
6429
6423 For example, the following commands are transactional, and their
6430 For example, the following commands are transactional, and their
6424 effects can be rolled back:
6431 effects can be rolled back:
6425
6432
6426 - commit
6433 - commit
6427 - import
6434 - import
6428 - pull
6435 - pull
6429 - push (with this repository as the destination)
6436 - push (with this repository as the destination)
6430 - unbundle
6437 - unbundle
6431
6438
6432 To avoid permanent data loss, rollback will refuse to rollback a
6439 To avoid permanent data loss, rollback will refuse to rollback a
6433 commit transaction if it isn't checked out. Use --force to
6440 commit transaction if it isn't checked out. Use --force to
6434 override this protection.
6441 override this protection.
6435
6442
6436 The rollback command can be entirely disabled by setting the
6443 The rollback command can be entirely disabled by setting the
6437 ``ui.rollback`` configuration setting to false. If you're here
6444 ``ui.rollback`` configuration setting to false. If you're here
6438 because you want to use rollback and it's disabled, you can
6445 because you want to use rollback and it's disabled, you can
6439 re-enable the command by setting ``ui.rollback`` to true.
6446 re-enable the command by setting ``ui.rollback`` to true.
6440
6447
6441 This command is not intended for use on public repositories. Once
6448 This command is not intended for use on public repositories. Once
6442 changes are visible for pull by other users, rolling a transaction
6449 changes are visible for pull by other users, rolling a transaction
6443 back locally is ineffective (someone else may already have pulled
6450 back locally is ineffective (someone else may already have pulled
6444 the changes). Furthermore, a race is possible with readers of the
6451 the changes). Furthermore, a race is possible with readers of the
6445 repository; for example an in-progress pull from the repository
6452 repository; for example an in-progress pull from the repository
6446 may fail if a rollback is performed.
6453 may fail if a rollback is performed.
6447
6454
6448 Returns 0 on success, 1 if no rollback data is available.
6455 Returns 0 on success, 1 if no rollback data is available.
6449 """
6456 """
6450 if not ui.configbool(b'ui', b'rollback'):
6457 if not ui.configbool(b'ui', b'rollback'):
6451 raise error.Abort(
6458 raise error.Abort(
6452 _(b'rollback is disabled because it is unsafe'),
6459 _(b'rollback is disabled because it is unsafe'),
6453 hint=b'see `hg help -v rollback` for information',
6460 hint=b'see `hg help -v rollback` for information',
6454 )
6461 )
6455 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6462 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6456
6463
6457
6464
6458 @command(
6465 @command(
6459 b'root',
6466 b'root',
6460 [] + formatteropts,
6467 [] + formatteropts,
6461 intents={INTENT_READONLY},
6468 intents={INTENT_READONLY},
6462 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6469 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6463 )
6470 )
6464 def root(ui, repo, **opts):
6471 def root(ui, repo, **opts):
6465 """print the root (top) of the current working directory
6472 """print the root (top) of the current working directory
6466
6473
6467 Print the root directory of the current repository.
6474 Print the root directory of the current repository.
6468
6475
6469 .. container:: verbose
6476 .. container:: verbose
6470
6477
6471 Template:
6478 Template:
6472
6479
6473 The following keywords are supported in addition to the common template
6480 The following keywords are supported in addition to the common template
6474 keywords and functions. See also :hg:`help templates`.
6481 keywords and functions. See also :hg:`help templates`.
6475
6482
6476 :hgpath: String. Path to the .hg directory.
6483 :hgpath: String. Path to the .hg directory.
6477 :storepath: String. Path to the directory holding versioned data.
6484 :storepath: String. Path to the directory holding versioned data.
6478
6485
6479 Returns 0 on success.
6486 Returns 0 on success.
6480 """
6487 """
6481 opts = pycompat.byteskwargs(opts)
6488 opts = pycompat.byteskwargs(opts)
6482 with ui.formatter(b'root', opts) as fm:
6489 with ui.formatter(b'root', opts) as fm:
6483 fm.startitem()
6490 fm.startitem()
6484 fm.write(b'reporoot', b'%s\n', repo.root)
6491 fm.write(b'reporoot', b'%s\n', repo.root)
6485 fm.data(hgpath=repo.path, storepath=repo.spath)
6492 fm.data(hgpath=repo.path, storepath=repo.spath)
6486
6493
6487
6494
6488 @command(
6495 @command(
6489 b'serve',
6496 b'serve',
6490 [
6497 [
6491 (
6498 (
6492 b'A',
6499 b'A',
6493 b'accesslog',
6500 b'accesslog',
6494 b'',
6501 b'',
6495 _(b'name of access log file to write to'),
6502 _(b'name of access log file to write to'),
6496 _(b'FILE'),
6503 _(b'FILE'),
6497 ),
6504 ),
6498 (b'd', b'daemon', None, _(b'run server in background')),
6505 (b'd', b'daemon', None, _(b'run server in background')),
6499 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6506 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6500 (
6507 (
6501 b'E',
6508 b'E',
6502 b'errorlog',
6509 b'errorlog',
6503 b'',
6510 b'',
6504 _(b'name of error log file to write to'),
6511 _(b'name of error log file to write to'),
6505 _(b'FILE'),
6512 _(b'FILE'),
6506 ),
6513 ),
6507 # use string type, then we can check if something was passed
6514 # use string type, then we can check if something was passed
6508 (
6515 (
6509 b'p',
6516 b'p',
6510 b'port',
6517 b'port',
6511 b'',
6518 b'',
6512 _(b'port to listen on (default: 8000)'),
6519 _(b'port to listen on (default: 8000)'),
6513 _(b'PORT'),
6520 _(b'PORT'),
6514 ),
6521 ),
6515 (
6522 (
6516 b'a',
6523 b'a',
6517 b'address',
6524 b'address',
6518 b'',
6525 b'',
6519 _(b'address to listen on (default: all interfaces)'),
6526 _(b'address to listen on (default: all interfaces)'),
6520 _(b'ADDR'),
6527 _(b'ADDR'),
6521 ),
6528 ),
6522 (
6529 (
6523 b'',
6530 b'',
6524 b'prefix',
6531 b'prefix',
6525 b'',
6532 b'',
6526 _(b'prefix path to serve from (default: server root)'),
6533 _(b'prefix path to serve from (default: server root)'),
6527 _(b'PREFIX'),
6534 _(b'PREFIX'),
6528 ),
6535 ),
6529 (
6536 (
6530 b'n',
6537 b'n',
6531 b'name',
6538 b'name',
6532 b'',
6539 b'',
6533 _(b'name to show in web pages (default: working directory)'),
6540 _(b'name to show in web pages (default: working directory)'),
6534 _(b'NAME'),
6541 _(b'NAME'),
6535 ),
6542 ),
6536 (
6543 (
6537 b'',
6544 b'',
6538 b'web-conf',
6545 b'web-conf',
6539 b'',
6546 b'',
6540 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6547 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6541 _(b'FILE'),
6548 _(b'FILE'),
6542 ),
6549 ),
6543 (
6550 (
6544 b'',
6551 b'',
6545 b'webdir-conf',
6552 b'webdir-conf',
6546 b'',
6553 b'',
6547 _(b'name of the hgweb config file (DEPRECATED)'),
6554 _(b'name of the hgweb config file (DEPRECATED)'),
6548 _(b'FILE'),
6555 _(b'FILE'),
6549 ),
6556 ),
6550 (
6557 (
6551 b'',
6558 b'',
6552 b'pid-file',
6559 b'pid-file',
6553 b'',
6560 b'',
6554 _(b'name of file to write process ID to'),
6561 _(b'name of file to write process ID to'),
6555 _(b'FILE'),
6562 _(b'FILE'),
6556 ),
6563 ),
6557 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6564 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6558 (
6565 (
6559 b'',
6566 b'',
6560 b'cmdserver',
6567 b'cmdserver',
6561 b'',
6568 b'',
6562 _(b'for remote clients (ADVANCED)'),
6569 _(b'for remote clients (ADVANCED)'),
6563 _(b'MODE'),
6570 _(b'MODE'),
6564 ),
6571 ),
6565 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6572 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6566 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6573 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6567 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6574 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6568 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6575 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6569 (b'', b'print-url', None, _(b'start and print only the URL')),
6576 (b'', b'print-url', None, _(b'start and print only the URL')),
6570 ]
6577 ]
6571 + subrepoopts,
6578 + subrepoopts,
6572 _(b'[OPTION]...'),
6579 _(b'[OPTION]...'),
6573 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6580 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6574 helpbasic=True,
6581 helpbasic=True,
6575 optionalrepo=True,
6582 optionalrepo=True,
6576 )
6583 )
6577 def serve(ui, repo, **opts):
6584 def serve(ui, repo, **opts):
6578 """start stand-alone webserver
6585 """start stand-alone webserver
6579
6586
6580 Start a local HTTP repository browser and pull server. You can use
6587 Start a local HTTP repository browser and pull server. You can use
6581 this for ad-hoc sharing and browsing of repositories. It is
6588 this for ad-hoc sharing and browsing of repositories. It is
6582 recommended to use a real web server to serve a repository for
6589 recommended to use a real web server to serve a repository for
6583 longer periods of time.
6590 longer periods of time.
6584
6591
6585 Please note that the server does not implement access control.
6592 Please note that the server does not implement access control.
6586 This means that, by default, anybody can read from the server and
6593 This means that, by default, anybody can read from the server and
6587 nobody can write to it by default. Set the ``web.allow-push``
6594 nobody can write to it by default. Set the ``web.allow-push``
6588 option to ``*`` to allow everybody to push to the server. You
6595 option to ``*`` to allow everybody to push to the server. You
6589 should use a real web server if you need to authenticate users.
6596 should use a real web server if you need to authenticate users.
6590
6597
6591 By default, the server logs accesses to stdout and errors to
6598 By default, the server logs accesses to stdout and errors to
6592 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6599 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6593 files.
6600 files.
6594
6601
6595 To have the server choose a free port number to listen on, specify
6602 To have the server choose a free port number to listen on, specify
6596 a port number of 0; in this case, the server will print the port
6603 a port number of 0; in this case, the server will print the port
6597 number it uses.
6604 number it uses.
6598
6605
6599 Returns 0 on success.
6606 Returns 0 on success.
6600 """
6607 """
6601
6608
6602 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6609 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6603 opts = pycompat.byteskwargs(opts)
6610 opts = pycompat.byteskwargs(opts)
6604 if opts[b"print_url"] and ui.verbose:
6611 if opts[b"print_url"] and ui.verbose:
6605 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6612 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6606
6613
6607 if opts[b"stdio"]:
6614 if opts[b"stdio"]:
6608 if repo is None:
6615 if repo is None:
6609 raise error.RepoError(
6616 raise error.RepoError(
6610 _(b"there is no Mercurial repository here (.hg not found)")
6617 _(b"there is no Mercurial repository here (.hg not found)")
6611 )
6618 )
6612 s = wireprotoserver.sshserver(ui, repo)
6619 s = wireprotoserver.sshserver(ui, repo)
6613 s.serve_forever()
6620 s.serve_forever()
6614 return
6621 return
6615
6622
6616 service = server.createservice(ui, repo, opts)
6623 service = server.createservice(ui, repo, opts)
6617 return server.runservice(opts, initfn=service.init, runfn=service.run)
6624 return server.runservice(opts, initfn=service.init, runfn=service.run)
6618
6625
6619
6626
6620 @command(
6627 @command(
6621 b'shelve',
6628 b'shelve',
6622 [
6629 [
6623 (
6630 (
6624 b'A',
6631 b'A',
6625 b'addremove',
6632 b'addremove',
6626 None,
6633 None,
6627 _(b'mark new/missing files as added/removed before shelving'),
6634 _(b'mark new/missing files as added/removed before shelving'),
6628 ),
6635 ),
6629 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6636 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6630 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6637 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6631 (
6638 (
6632 b'',
6639 b'',
6633 b'date',
6640 b'date',
6634 b'',
6641 b'',
6635 _(b'shelve with the specified commit date'),
6642 _(b'shelve with the specified commit date'),
6636 _(b'DATE'),
6643 _(b'DATE'),
6637 ),
6644 ),
6638 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6645 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6639 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6646 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6640 (
6647 (
6641 b'k',
6648 b'k',
6642 b'keep',
6649 b'keep',
6643 False,
6650 False,
6644 _(b'shelve, but keep changes in the working directory'),
6651 _(b'shelve, but keep changes in the working directory'),
6645 ),
6652 ),
6646 (b'l', b'list', None, _(b'list current shelves')),
6653 (b'l', b'list', None, _(b'list current shelves')),
6647 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6654 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6648 (
6655 (
6649 b'n',
6656 b'n',
6650 b'name',
6657 b'name',
6651 b'',
6658 b'',
6652 _(b'use the given name for the shelved commit'),
6659 _(b'use the given name for the shelved commit'),
6653 _(b'NAME'),
6660 _(b'NAME'),
6654 ),
6661 ),
6655 (
6662 (
6656 b'p',
6663 b'p',
6657 b'patch',
6664 b'patch',
6658 None,
6665 None,
6659 _(
6666 _(
6660 b'output patches for changes (provide the names of the shelved '
6667 b'output patches for changes (provide the names of the shelved '
6661 b'changes as positional arguments)'
6668 b'changes as positional arguments)'
6662 ),
6669 ),
6663 ),
6670 ),
6664 (b'i', b'interactive', None, _(b'interactive mode')),
6671 (b'i', b'interactive', None, _(b'interactive mode')),
6665 (
6672 (
6666 b'',
6673 b'',
6667 b'stat',
6674 b'stat',
6668 None,
6675 None,
6669 _(
6676 _(
6670 b'output diffstat-style summary of changes (provide the names of '
6677 b'output diffstat-style summary of changes (provide the names of '
6671 b'the shelved changes as positional arguments)'
6678 b'the shelved changes as positional arguments)'
6672 ),
6679 ),
6673 ),
6680 ),
6674 ]
6681 ]
6675 + cmdutil.walkopts,
6682 + cmdutil.walkopts,
6676 _(b'hg shelve [OPTION]... [FILE]...'),
6683 _(b'hg shelve [OPTION]... [FILE]...'),
6677 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6684 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6678 )
6685 )
6679 def shelve(ui, repo, *pats, **opts):
6686 def shelve(ui, repo, *pats, **opts):
6680 """save and set aside changes from the working directory
6687 """save and set aside changes from the working directory
6681
6688
6682 Shelving takes files that "hg status" reports as not clean, saves
6689 Shelving takes files that "hg status" reports as not clean, saves
6683 the modifications to a bundle (a shelved change), and reverts the
6690 the modifications to a bundle (a shelved change), and reverts the
6684 files so that their state in the working directory becomes clean.
6691 files so that their state in the working directory becomes clean.
6685
6692
6686 To restore these changes to the working directory, using "hg
6693 To restore these changes to the working directory, using "hg
6687 unshelve"; this will work even if you switch to a different
6694 unshelve"; this will work even if you switch to a different
6688 commit.
6695 commit.
6689
6696
6690 When no files are specified, "hg shelve" saves all not-clean
6697 When no files are specified, "hg shelve" saves all not-clean
6691 files. If specific files or directories are named, only changes to
6698 files. If specific files or directories are named, only changes to
6692 those files are shelved.
6699 those files are shelved.
6693
6700
6694 In bare shelve (when no files are specified, without interactive,
6701 In bare shelve (when no files are specified, without interactive,
6695 include and exclude option), shelving remembers information if the
6702 include and exclude option), shelving remembers information if the
6696 working directory was on newly created branch, in other words working
6703 working directory was on newly created branch, in other words working
6697 directory was on different branch than its first parent. In this
6704 directory was on different branch than its first parent. In this
6698 situation unshelving restores branch information to the working directory.
6705 situation unshelving restores branch information to the working directory.
6699
6706
6700 Each shelved change has a name that makes it easier to find later.
6707 Each shelved change has a name that makes it easier to find later.
6701 The name of a shelved change defaults to being based on the active
6708 The name of a shelved change defaults to being based on the active
6702 bookmark, or if there is no active bookmark, the current named
6709 bookmark, or if there is no active bookmark, the current named
6703 branch. To specify a different name, use ``--name``.
6710 branch. To specify a different name, use ``--name``.
6704
6711
6705 To see a list of existing shelved changes, use the ``--list``
6712 To see a list of existing shelved changes, use the ``--list``
6706 option. For each shelved change, this will print its name, age,
6713 option. For each shelved change, this will print its name, age,
6707 and description; use ``--patch`` or ``--stat`` for more details.
6714 and description; use ``--patch`` or ``--stat`` for more details.
6708
6715
6709 To delete specific shelved changes, use ``--delete``. To delete
6716 To delete specific shelved changes, use ``--delete``. To delete
6710 all shelved changes, use ``--cleanup``.
6717 all shelved changes, use ``--cleanup``.
6711 """
6718 """
6712 opts = pycompat.byteskwargs(opts)
6719 opts = pycompat.byteskwargs(opts)
6713 allowables = [
6720 allowables = [
6714 (b'addremove', {b'create'}), # 'create' is pseudo action
6721 (b'addremove', {b'create'}), # 'create' is pseudo action
6715 (b'unknown', {b'create'}),
6722 (b'unknown', {b'create'}),
6716 (b'cleanup', {b'cleanup'}),
6723 (b'cleanup', {b'cleanup'}),
6717 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6724 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6718 (b'delete', {b'delete'}),
6725 (b'delete', {b'delete'}),
6719 (b'edit', {b'create'}),
6726 (b'edit', {b'create'}),
6720 (b'keep', {b'create'}),
6727 (b'keep', {b'create'}),
6721 (b'list', {b'list'}),
6728 (b'list', {b'list'}),
6722 (b'message', {b'create'}),
6729 (b'message', {b'create'}),
6723 (b'name', {b'create'}),
6730 (b'name', {b'create'}),
6724 (b'patch', {b'patch', b'list'}),
6731 (b'patch', {b'patch', b'list'}),
6725 (b'stat', {b'stat', b'list'}),
6732 (b'stat', {b'stat', b'list'}),
6726 ]
6733 ]
6727
6734
6728 def checkopt(opt):
6735 def checkopt(opt):
6729 if opts.get(opt):
6736 if opts.get(opt):
6730 for i, allowable in allowables:
6737 for i, allowable in allowables:
6731 if opts[i] and opt not in allowable:
6738 if opts[i] and opt not in allowable:
6732 raise error.InputError(
6739 raise error.InputError(
6733 _(
6740 _(
6734 b"options '--%s' and '--%s' may not be "
6741 b"options '--%s' and '--%s' may not be "
6735 b"used together"
6742 b"used together"
6736 )
6743 )
6737 % (opt, i)
6744 % (opt, i)
6738 )
6745 )
6739 return True
6746 return True
6740
6747
6741 if checkopt(b'cleanup'):
6748 if checkopt(b'cleanup'):
6742 if pats:
6749 if pats:
6743 raise error.InputError(
6750 raise error.InputError(
6744 _(b"cannot specify names when using '--cleanup'")
6751 _(b"cannot specify names when using '--cleanup'")
6745 )
6752 )
6746 return shelvemod.cleanupcmd(ui, repo)
6753 return shelvemod.cleanupcmd(ui, repo)
6747 elif checkopt(b'delete'):
6754 elif checkopt(b'delete'):
6748 return shelvemod.deletecmd(ui, repo, pats)
6755 return shelvemod.deletecmd(ui, repo, pats)
6749 elif checkopt(b'list'):
6756 elif checkopt(b'list'):
6750 return shelvemod.listcmd(ui, repo, pats, opts)
6757 return shelvemod.listcmd(ui, repo, pats, opts)
6751 elif checkopt(b'patch') or checkopt(b'stat'):
6758 elif checkopt(b'patch') or checkopt(b'stat'):
6752 return shelvemod.patchcmds(ui, repo, pats, opts)
6759 return shelvemod.patchcmds(ui, repo, pats, opts)
6753 else:
6760 else:
6754 return shelvemod.createcmd(ui, repo, pats, opts)
6761 return shelvemod.createcmd(ui, repo, pats, opts)
6755
6762
6756
6763
6757 _NOTTERSE = b'nothing'
6764 _NOTTERSE = b'nothing'
6758
6765
6759
6766
6760 @command(
6767 @command(
6761 b'status|st',
6768 b'status|st',
6762 [
6769 [
6763 (b'A', b'all', None, _(b'show status of all files')),
6770 (b'A', b'all', None, _(b'show status of all files')),
6764 (b'm', b'modified', None, _(b'show only modified files')),
6771 (b'm', b'modified', None, _(b'show only modified files')),
6765 (b'a', b'added', None, _(b'show only added files')),
6772 (b'a', b'added', None, _(b'show only added files')),
6766 (b'r', b'removed', None, _(b'show only removed files')),
6773 (b'r', b'removed', None, _(b'show only removed files')),
6767 (b'd', b'deleted', None, _(b'show only missing files')),
6774 (b'd', b'deleted', None, _(b'show only missing files')),
6768 (b'c', b'clean', None, _(b'show only files without changes')),
6775 (b'c', b'clean', None, _(b'show only files without changes')),
6769 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6776 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6770 (b'i', b'ignored', None, _(b'show only ignored files')),
6777 (b'i', b'ignored', None, _(b'show only ignored files')),
6771 (b'n', b'no-status', None, _(b'hide status prefix')),
6778 (b'n', b'no-status', None, _(b'hide status prefix')),
6772 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6779 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6773 (
6780 (
6774 b'C',
6781 b'C',
6775 b'copies',
6782 b'copies',
6776 None,
6783 None,
6777 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6784 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6778 ),
6785 ),
6779 (
6786 (
6780 b'0',
6787 b'0',
6781 b'print0',
6788 b'print0',
6782 None,
6789 None,
6783 _(b'end filenames with NUL, for use with xargs'),
6790 _(b'end filenames with NUL, for use with xargs'),
6784 ),
6791 ),
6785 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6792 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6786 (
6793 (
6787 b'',
6794 b'',
6788 b'change',
6795 b'change',
6789 b'',
6796 b'',
6790 _(b'list the changed files of a revision'),
6797 _(b'list the changed files of a revision'),
6791 _(b'REV'),
6798 _(b'REV'),
6792 ),
6799 ),
6793 ]
6800 ]
6794 + walkopts
6801 + walkopts
6795 + subrepoopts
6802 + subrepoopts
6796 + formatteropts,
6803 + formatteropts,
6797 _(b'[OPTION]... [FILE]...'),
6804 _(b'[OPTION]... [FILE]...'),
6798 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6805 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6799 helpbasic=True,
6806 helpbasic=True,
6800 inferrepo=True,
6807 inferrepo=True,
6801 intents={INTENT_READONLY},
6808 intents={INTENT_READONLY},
6802 )
6809 )
6803 def status(ui, repo, *pats, **opts):
6810 def status(ui, repo, *pats, **opts):
6804 """show changed files in the working directory
6811 """show changed files in the working directory
6805
6812
6806 Show status of files in the repository. If names are given, only
6813 Show status of files in the repository. If names are given, only
6807 files that match are shown. Files that are clean or ignored or
6814 files that match are shown. Files that are clean or ignored or
6808 the source of a copy/move operation, are not listed unless
6815 the source of a copy/move operation, are not listed unless
6809 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6816 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6810 Unless options described with "show only ..." are given, the
6817 Unless options described with "show only ..." are given, the
6811 options -mardu are used.
6818 options -mardu are used.
6812
6819
6813 Option -q/--quiet hides untracked (unknown and ignored) files
6820 Option -q/--quiet hides untracked (unknown and ignored) files
6814 unless explicitly requested with -u/--unknown or -i/--ignored.
6821 unless explicitly requested with -u/--unknown or -i/--ignored.
6815
6822
6816 .. note::
6823 .. note::
6817
6824
6818 :hg:`status` may appear to disagree with diff if permissions have
6825 :hg:`status` may appear to disagree with diff if permissions have
6819 changed or a merge has occurred. The standard diff format does
6826 changed or a merge has occurred. The standard diff format does
6820 not report permission changes and diff only reports changes
6827 not report permission changes and diff only reports changes
6821 relative to one merge parent.
6828 relative to one merge parent.
6822
6829
6823 If one revision is given, it is used as the base revision.
6830 If one revision is given, it is used as the base revision.
6824 If two revisions are given, the differences between them are
6831 If two revisions are given, the differences between them are
6825 shown. The --change option can also be used as a shortcut to list
6832 shown. The --change option can also be used as a shortcut to list
6826 the changed files of a revision from its first parent.
6833 the changed files of a revision from its first parent.
6827
6834
6828 The codes used to show the status of files are::
6835 The codes used to show the status of files are::
6829
6836
6830 M = modified
6837 M = modified
6831 A = added
6838 A = added
6832 R = removed
6839 R = removed
6833 C = clean
6840 C = clean
6834 ! = missing (deleted by non-hg command, but still tracked)
6841 ! = missing (deleted by non-hg command, but still tracked)
6835 ? = not tracked
6842 ? = not tracked
6836 I = ignored
6843 I = ignored
6837 = origin of the previous file (with --copies)
6844 = origin of the previous file (with --copies)
6838
6845
6839 .. container:: verbose
6846 .. container:: verbose
6840
6847
6841 The -t/--terse option abbreviates the output by showing only the directory
6848 The -t/--terse option abbreviates the output by showing only the directory
6842 name if all the files in it share the same status. The option takes an
6849 name if all the files in it share the same status. The option takes an
6843 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6850 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6844 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6851 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6845 for 'ignored' and 'c' for clean.
6852 for 'ignored' and 'c' for clean.
6846
6853
6847 It abbreviates only those statuses which are passed. Note that clean and
6854 It abbreviates only those statuses which are passed. Note that clean and
6848 ignored files are not displayed with '--terse ic' unless the -c/--clean
6855 ignored files are not displayed with '--terse ic' unless the -c/--clean
6849 and -i/--ignored options are also used.
6856 and -i/--ignored options are also used.
6850
6857
6851 The -v/--verbose option shows information when the repository is in an
6858 The -v/--verbose option shows information when the repository is in an
6852 unfinished merge, shelve, rebase state etc. You can have this behavior
6859 unfinished merge, shelve, rebase state etc. You can have this behavior
6853 turned on by default by enabling the ``commands.status.verbose`` option.
6860 turned on by default by enabling the ``commands.status.verbose`` option.
6854
6861
6855 You can skip displaying some of these states by setting
6862 You can skip displaying some of these states by setting
6856 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6863 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6857 'histedit', 'merge', 'rebase', or 'unshelve'.
6864 'histedit', 'merge', 'rebase', or 'unshelve'.
6858
6865
6859 Template:
6866 Template:
6860
6867
6861 The following keywords are supported in addition to the common template
6868 The following keywords are supported in addition to the common template
6862 keywords and functions. See also :hg:`help templates`.
6869 keywords and functions. See also :hg:`help templates`.
6863
6870
6864 :path: String. Repository-absolute path of the file.
6871 :path: String. Repository-absolute path of the file.
6865 :source: String. Repository-absolute path of the file originated from.
6872 :source: String. Repository-absolute path of the file originated from.
6866 Available if ``--copies`` is specified.
6873 Available if ``--copies`` is specified.
6867 :status: String. Character denoting file's status.
6874 :status: String. Character denoting file's status.
6868
6875
6869 Examples:
6876 Examples:
6870
6877
6871 - show changes in the working directory relative to a
6878 - show changes in the working directory relative to a
6872 changeset::
6879 changeset::
6873
6880
6874 hg status --rev 9353
6881 hg status --rev 9353
6875
6882
6876 - show changes in the working directory relative to the
6883 - show changes in the working directory relative to the
6877 current directory (see :hg:`help patterns` for more information)::
6884 current directory (see :hg:`help patterns` for more information)::
6878
6885
6879 hg status re:
6886 hg status re:
6880
6887
6881 - show all changes including copies in an existing changeset::
6888 - show all changes including copies in an existing changeset::
6882
6889
6883 hg status --copies --change 9353
6890 hg status --copies --change 9353
6884
6891
6885 - get a NUL separated list of added files, suitable for xargs::
6892 - get a NUL separated list of added files, suitable for xargs::
6886
6893
6887 hg status -an0
6894 hg status -an0
6888
6895
6889 - show more information about the repository status, abbreviating
6896 - show more information about the repository status, abbreviating
6890 added, removed, modified, deleted, and untracked paths::
6897 added, removed, modified, deleted, and untracked paths::
6891
6898
6892 hg status -v -t mardu
6899 hg status -v -t mardu
6893
6900
6894 Returns 0 on success.
6901 Returns 0 on success.
6895
6902
6896 """
6903 """
6897
6904
6898 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6905 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6899 opts = pycompat.byteskwargs(opts)
6906 opts = pycompat.byteskwargs(opts)
6900 revs = opts.get(b'rev', [])
6907 revs = opts.get(b'rev', [])
6901 change = opts.get(b'change', b'')
6908 change = opts.get(b'change', b'')
6902 terse = opts.get(b'terse', _NOTTERSE)
6909 terse = opts.get(b'terse', _NOTTERSE)
6903 if terse is _NOTTERSE:
6910 if terse is _NOTTERSE:
6904 if revs:
6911 if revs:
6905 terse = b''
6912 terse = b''
6906 else:
6913 else:
6907 terse = ui.config(b'commands', b'status.terse')
6914 terse = ui.config(b'commands', b'status.terse')
6908
6915
6909 if revs and terse:
6916 if revs and terse:
6910 msg = _(b'cannot use --terse with --rev')
6917 msg = _(b'cannot use --terse with --rev')
6911 raise error.InputError(msg)
6918 raise error.InputError(msg)
6912 elif change:
6919 elif change:
6913 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6920 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6914 ctx2 = logcmdutil.revsingle(repo, change, None)
6921 ctx2 = logcmdutil.revsingle(repo, change, None)
6915 ctx1 = ctx2.p1()
6922 ctx1 = ctx2.p1()
6916 else:
6923 else:
6917 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6924 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6918 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6925 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6919
6926
6920 forcerelativevalue = None
6927 forcerelativevalue = None
6921 if ui.hasconfig(b'commands', b'status.relative'):
6928 if ui.hasconfig(b'commands', b'status.relative'):
6922 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6929 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6923 uipathfn = scmutil.getuipathfn(
6930 uipathfn = scmutil.getuipathfn(
6924 repo,
6931 repo,
6925 legacyrelativevalue=bool(pats),
6932 legacyrelativevalue=bool(pats),
6926 forcerelativevalue=forcerelativevalue,
6933 forcerelativevalue=forcerelativevalue,
6927 )
6934 )
6928
6935
6929 if opts.get(b'print0'):
6936 if opts.get(b'print0'):
6930 end = b'\0'
6937 end = b'\0'
6931 else:
6938 else:
6932 end = b'\n'
6939 end = b'\n'
6933 states = b'modified added removed deleted unknown ignored clean'.split()
6940 states = b'modified added removed deleted unknown ignored clean'.split()
6934 show = [k for k in states if opts.get(k)]
6941 show = [k for k in states if opts.get(k)]
6935 if opts.get(b'all'):
6942 if opts.get(b'all'):
6936 show += ui.quiet and (states[:4] + [b'clean']) or states
6943 show += ui.quiet and (states[:4] + [b'clean']) or states
6937
6944
6938 if not show:
6945 if not show:
6939 if ui.quiet:
6946 if ui.quiet:
6940 show = states[:4]
6947 show = states[:4]
6941 else:
6948 else:
6942 show = states[:5]
6949 show = states[:5]
6943
6950
6944 m = scmutil.match(ctx2, pats, opts)
6951 m = scmutil.match(ctx2, pats, opts)
6945 if terse:
6952 if terse:
6946 # we need to compute clean and unknown to terse
6953 # we need to compute clean and unknown to terse
6947 stat = repo.status(
6954 stat = repo.status(
6948 ctx1.node(),
6955 ctx1.node(),
6949 ctx2.node(),
6956 ctx2.node(),
6950 m,
6957 m,
6951 b'ignored' in show or b'i' in terse,
6958 b'ignored' in show or b'i' in terse,
6952 clean=True,
6959 clean=True,
6953 unknown=True,
6960 unknown=True,
6954 listsubrepos=opts.get(b'subrepos'),
6961 listsubrepos=opts.get(b'subrepos'),
6955 )
6962 )
6956
6963
6957 stat = cmdutil.tersedir(stat, terse)
6964 stat = cmdutil.tersedir(stat, terse)
6958 else:
6965 else:
6959 stat = repo.status(
6966 stat = repo.status(
6960 ctx1.node(),
6967 ctx1.node(),
6961 ctx2.node(),
6968 ctx2.node(),
6962 m,
6969 m,
6963 b'ignored' in show,
6970 b'ignored' in show,
6964 b'clean' in show,
6971 b'clean' in show,
6965 b'unknown' in show,
6972 b'unknown' in show,
6966 opts.get(b'subrepos'),
6973 opts.get(b'subrepos'),
6967 )
6974 )
6968
6975
6969 changestates = zip(
6976 changestates = zip(
6970 states,
6977 states,
6971 pycompat.iterbytestr(b'MAR!?IC'),
6978 pycompat.iterbytestr(b'MAR!?IC'),
6972 [getattr(stat, s.decode('utf8')) for s in states],
6979 [getattr(stat, s.decode('utf8')) for s in states],
6973 )
6980 )
6974
6981
6975 copy = {}
6982 copy = {}
6976 if (
6983 if (
6977 opts.get(b'all')
6984 opts.get(b'all')
6978 or opts.get(b'copies')
6985 or opts.get(b'copies')
6979 or ui.configbool(b'ui', b'statuscopies')
6986 or ui.configbool(b'ui', b'statuscopies')
6980 ) and not opts.get(b'no_status'):
6987 ) and not opts.get(b'no_status'):
6981 copy = copies.pathcopies(ctx1, ctx2, m)
6988 copy = copies.pathcopies(ctx1, ctx2, m)
6982
6989
6983 morestatus = None
6990 morestatus = None
6984 if (
6991 if (
6985 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6992 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6986 and not ui.plain()
6993 and not ui.plain()
6987 and not opts.get(b'print0')
6994 and not opts.get(b'print0')
6988 ):
6995 ):
6989 morestatus = cmdutil.readmorestatus(repo)
6996 morestatus = cmdutil.readmorestatus(repo)
6990
6997
6991 ui.pager(b'status')
6998 ui.pager(b'status')
6992 fm = ui.formatter(b'status', opts)
6999 fm = ui.formatter(b'status', opts)
6993 fmt = b'%s' + end
7000 fmt = b'%s' + end
6994 showchar = not opts.get(b'no_status')
7001 showchar = not opts.get(b'no_status')
6995
7002
6996 for state, char, files in changestates:
7003 for state, char, files in changestates:
6997 if state in show:
7004 if state in show:
6998 label = b'status.' + state
7005 label = b'status.' + state
6999 for f in files:
7006 for f in files:
7000 fm.startitem()
7007 fm.startitem()
7001 fm.context(ctx=ctx2)
7008 fm.context(ctx=ctx2)
7002 fm.data(itemtype=b'file', path=f)
7009 fm.data(itemtype=b'file', path=f)
7003 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7010 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
7004 fm.plain(fmt % uipathfn(f), label=label)
7011 fm.plain(fmt % uipathfn(f), label=label)
7005 if f in copy:
7012 if f in copy:
7006 fm.data(source=copy[f])
7013 fm.data(source=copy[f])
7007 fm.plain(
7014 fm.plain(
7008 (b' %s' + end) % uipathfn(copy[f]),
7015 (b' %s' + end) % uipathfn(copy[f]),
7009 label=b'status.copied',
7016 label=b'status.copied',
7010 )
7017 )
7011 if morestatus:
7018 if morestatus:
7012 morestatus.formatfile(f, fm)
7019 morestatus.formatfile(f, fm)
7013
7020
7014 if morestatus:
7021 if morestatus:
7015 morestatus.formatfooter(fm)
7022 morestatus.formatfooter(fm)
7016 fm.end()
7023 fm.end()
7017
7024
7018
7025
7019 @command(
7026 @command(
7020 b'summary|sum',
7027 b'summary|sum',
7021 [(b'', b'remote', None, _(b'check for push and pull'))],
7028 [(b'', b'remote', None, _(b'check for push and pull'))],
7022 b'[--remote]',
7029 b'[--remote]',
7023 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7030 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7024 helpbasic=True,
7031 helpbasic=True,
7025 intents={INTENT_READONLY},
7032 intents={INTENT_READONLY},
7026 )
7033 )
7027 def summary(ui, repo, **opts):
7034 def summary(ui, repo, **opts):
7028 """summarize working directory state
7035 """summarize working directory state
7029
7036
7030 This generates a brief summary of the working directory state,
7037 This generates a brief summary of the working directory state,
7031 including parents, branch, commit status, phase and available updates.
7038 including parents, branch, commit status, phase and available updates.
7032
7039
7033 With the --remote option, this will check the default paths for
7040 With the --remote option, this will check the default paths for
7034 incoming and outgoing changes. This can be time-consuming.
7041 incoming and outgoing changes. This can be time-consuming.
7035
7042
7036 Returns 0 on success.
7043 Returns 0 on success.
7037 """
7044 """
7038
7045
7039 opts = pycompat.byteskwargs(opts)
7046 opts = pycompat.byteskwargs(opts)
7040 ui.pager(b'summary')
7047 ui.pager(b'summary')
7041 ctx = repo[None]
7048 ctx = repo[None]
7042 parents = ctx.parents()
7049 parents = ctx.parents()
7043 pnode = parents[0].node()
7050 pnode = parents[0].node()
7044 marks = []
7051 marks = []
7045
7052
7046 try:
7053 try:
7047 ms = mergestatemod.mergestate.read(repo)
7054 ms = mergestatemod.mergestate.read(repo)
7048 except error.UnsupportedMergeRecords as e:
7055 except error.UnsupportedMergeRecords as e:
7049 s = b' '.join(e.recordtypes)
7056 s = b' '.join(e.recordtypes)
7050 ui.warn(
7057 ui.warn(
7051 _(b'warning: merge state has unsupported record types: %s\n') % s
7058 _(b'warning: merge state has unsupported record types: %s\n') % s
7052 )
7059 )
7053 unresolved = []
7060 unresolved = []
7054 else:
7061 else:
7055 unresolved = list(ms.unresolved())
7062 unresolved = list(ms.unresolved())
7056
7063
7057 for p in parents:
7064 for p in parents:
7058 # label with log.changeset (instead of log.parent) since this
7065 # label with log.changeset (instead of log.parent) since this
7059 # shows a working directory parent *changeset*:
7066 # shows a working directory parent *changeset*:
7060 # i18n: column positioning for "hg summary"
7067 # i18n: column positioning for "hg summary"
7061 ui.write(
7068 ui.write(
7062 _(b'parent: %d:%s ') % (p.rev(), p),
7069 _(b'parent: %d:%s ') % (p.rev(), p),
7063 label=logcmdutil.changesetlabels(p),
7070 label=logcmdutil.changesetlabels(p),
7064 )
7071 )
7065 ui.write(b' '.join(p.tags()), label=b'log.tag')
7072 ui.write(b' '.join(p.tags()), label=b'log.tag')
7066 if p.bookmarks():
7073 if p.bookmarks():
7067 marks.extend(p.bookmarks())
7074 marks.extend(p.bookmarks())
7068 if p.rev() == -1:
7075 if p.rev() == -1:
7069 if not len(repo):
7076 if not len(repo):
7070 ui.write(_(b' (empty repository)'))
7077 ui.write(_(b' (empty repository)'))
7071 else:
7078 else:
7072 ui.write(_(b' (no revision checked out)'))
7079 ui.write(_(b' (no revision checked out)'))
7073 if p.obsolete():
7080 if p.obsolete():
7074 ui.write(_(b' (obsolete)'))
7081 ui.write(_(b' (obsolete)'))
7075 if p.isunstable():
7082 if p.isunstable():
7076 instabilities = (
7083 instabilities = (
7077 ui.label(instability, b'trouble.%s' % instability)
7084 ui.label(instability, b'trouble.%s' % instability)
7078 for instability in p.instabilities()
7085 for instability in p.instabilities()
7079 )
7086 )
7080 ui.write(b' (' + b', '.join(instabilities) + b')')
7087 ui.write(b' (' + b', '.join(instabilities) + b')')
7081 ui.write(b'\n')
7088 ui.write(b'\n')
7082 if p.description():
7089 if p.description():
7083 ui.status(
7090 ui.status(
7084 b' ' + p.description().splitlines()[0].strip() + b'\n',
7091 b' ' + p.description().splitlines()[0].strip() + b'\n',
7085 label=b'log.summary',
7092 label=b'log.summary',
7086 )
7093 )
7087
7094
7088 branch = ctx.branch()
7095 branch = ctx.branch()
7089 bheads = repo.branchheads(branch)
7096 bheads = repo.branchheads(branch)
7090 # i18n: column positioning for "hg summary"
7097 # i18n: column positioning for "hg summary"
7091 m = _(b'branch: %s\n') % branch
7098 m = _(b'branch: %s\n') % branch
7092 if branch != b'default':
7099 if branch != b'default':
7093 ui.write(m, label=b'log.branch')
7100 ui.write(m, label=b'log.branch')
7094 else:
7101 else:
7095 ui.status(m, label=b'log.branch')
7102 ui.status(m, label=b'log.branch')
7096
7103
7097 if marks:
7104 if marks:
7098 active = repo._activebookmark
7105 active = repo._activebookmark
7099 # i18n: column positioning for "hg summary"
7106 # i18n: column positioning for "hg summary"
7100 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7107 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7101 if active is not None:
7108 if active is not None:
7102 if active in marks:
7109 if active in marks:
7103 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7110 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7104 marks.remove(active)
7111 marks.remove(active)
7105 else:
7112 else:
7106 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7113 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7107 for m in marks:
7114 for m in marks:
7108 ui.write(b' ' + m, label=b'log.bookmark')
7115 ui.write(b' ' + m, label=b'log.bookmark')
7109 ui.write(b'\n', label=b'log.bookmark')
7116 ui.write(b'\n', label=b'log.bookmark')
7110
7117
7111 status = repo.status(unknown=True)
7118 status = repo.status(unknown=True)
7112
7119
7113 c = repo.dirstate.copies()
7120 c = repo.dirstate.copies()
7114 copied, renamed = [], []
7121 copied, renamed = [], []
7115 for d, s in c.items():
7122 for d, s in c.items():
7116 if s in status.removed:
7123 if s in status.removed:
7117 status.removed.remove(s)
7124 status.removed.remove(s)
7118 renamed.append(d)
7125 renamed.append(d)
7119 else:
7126 else:
7120 copied.append(d)
7127 copied.append(d)
7121 if d in status.added:
7128 if d in status.added:
7122 status.added.remove(d)
7129 status.added.remove(d)
7123
7130
7124 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7131 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7125
7132
7126 labels = [
7133 labels = [
7127 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7134 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7128 (ui.label(_(b'%d added'), b'status.added'), status.added),
7135 (ui.label(_(b'%d added'), b'status.added'), status.added),
7129 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7136 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7130 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7137 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7131 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7138 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7132 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7139 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7133 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7140 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7134 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7141 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7135 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7142 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7136 ]
7143 ]
7137 t = []
7144 t = []
7138 for l, s in labels:
7145 for l, s in labels:
7139 if s:
7146 if s:
7140 t.append(l % len(s))
7147 t.append(l % len(s))
7141
7148
7142 t = b', '.join(t)
7149 t = b', '.join(t)
7143 cleanworkdir = False
7150 cleanworkdir = False
7144
7151
7145 if repo.vfs.exists(b'graftstate'):
7152 if repo.vfs.exists(b'graftstate'):
7146 t += _(b' (graft in progress)')
7153 t += _(b' (graft in progress)')
7147 if repo.vfs.exists(b'updatestate'):
7154 if repo.vfs.exists(b'updatestate'):
7148 t += _(b' (interrupted update)')
7155 t += _(b' (interrupted update)')
7149 elif len(parents) > 1:
7156 elif len(parents) > 1:
7150 t += _(b' (merge)')
7157 t += _(b' (merge)')
7151 elif branch != parents[0].branch():
7158 elif branch != parents[0].branch():
7152 t += _(b' (new branch)')
7159 t += _(b' (new branch)')
7153 elif parents[0].closesbranch() and pnode in repo.branchheads(
7160 elif parents[0].closesbranch() and pnode in repo.branchheads(
7154 branch, closed=True
7161 branch, closed=True
7155 ):
7162 ):
7156 t += _(b' (head closed)')
7163 t += _(b' (head closed)')
7157 elif not (
7164 elif not (
7158 status.modified
7165 status.modified
7159 or status.added
7166 or status.added
7160 or status.removed
7167 or status.removed
7161 or renamed
7168 or renamed
7162 or copied
7169 or copied
7163 or subs
7170 or subs
7164 ):
7171 ):
7165 t += _(b' (clean)')
7172 t += _(b' (clean)')
7166 cleanworkdir = True
7173 cleanworkdir = True
7167 elif pnode not in bheads:
7174 elif pnode not in bheads:
7168 t += _(b' (new branch head)')
7175 t += _(b' (new branch head)')
7169
7176
7170 if parents:
7177 if parents:
7171 pendingphase = max(p.phase() for p in parents)
7178 pendingphase = max(p.phase() for p in parents)
7172 else:
7179 else:
7173 pendingphase = phases.public
7180 pendingphase = phases.public
7174
7181
7175 if pendingphase > phases.newcommitphase(ui):
7182 if pendingphase > phases.newcommitphase(ui):
7176 t += b' (%s)' % phases.phasenames[pendingphase]
7183 t += b' (%s)' % phases.phasenames[pendingphase]
7177
7184
7178 if cleanworkdir:
7185 if cleanworkdir:
7179 # i18n: column positioning for "hg summary"
7186 # i18n: column positioning for "hg summary"
7180 ui.status(_(b'commit: %s\n') % t.strip())
7187 ui.status(_(b'commit: %s\n') % t.strip())
7181 else:
7188 else:
7182 # i18n: column positioning for "hg summary"
7189 # i18n: column positioning for "hg summary"
7183 ui.write(_(b'commit: %s\n') % t.strip())
7190 ui.write(_(b'commit: %s\n') % t.strip())
7184
7191
7185 # all ancestors of branch heads - all ancestors of parent = new csets
7192 # all ancestors of branch heads - all ancestors of parent = new csets
7186 new = len(
7193 new = len(
7187 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7194 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7188 )
7195 )
7189
7196
7190 if new == 0:
7197 if new == 0:
7191 # i18n: column positioning for "hg summary"
7198 # i18n: column positioning for "hg summary"
7192 ui.status(_(b'update: (current)\n'))
7199 ui.status(_(b'update: (current)\n'))
7193 elif pnode not in bheads:
7200 elif pnode not in bheads:
7194 # i18n: column positioning for "hg summary"
7201 # i18n: column positioning for "hg summary"
7195 ui.write(_(b'update: %d new changesets (update)\n') % new)
7202 ui.write(_(b'update: %d new changesets (update)\n') % new)
7196 else:
7203 else:
7197 # i18n: column positioning for "hg summary"
7204 # i18n: column positioning for "hg summary"
7198 ui.write(
7205 ui.write(
7199 _(b'update: %d new changesets, %d branch heads (merge)\n')
7206 _(b'update: %d new changesets, %d branch heads (merge)\n')
7200 % (new, len(bheads))
7207 % (new, len(bheads))
7201 )
7208 )
7202
7209
7203 t = []
7210 t = []
7204 draft = len(repo.revs(b'draft()'))
7211 draft = len(repo.revs(b'draft()'))
7205 if draft:
7212 if draft:
7206 t.append(_(b'%d draft') % draft)
7213 t.append(_(b'%d draft') % draft)
7207 secret = len(repo.revs(b'secret()'))
7214 secret = len(repo.revs(b'secret()'))
7208 if secret:
7215 if secret:
7209 t.append(_(b'%d secret') % secret)
7216 t.append(_(b'%d secret') % secret)
7210
7217
7211 if draft or secret:
7218 if draft or secret:
7212 ui.status(_(b'phases: %s\n') % b', '.join(t))
7219 ui.status(_(b'phases: %s\n') % b', '.join(t))
7213
7220
7214 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7221 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7215 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7222 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7216 numtrouble = len(repo.revs(trouble + b"()"))
7223 numtrouble = len(repo.revs(trouble + b"()"))
7217 # We write all the possibilities to ease translation
7224 # We write all the possibilities to ease translation
7218 troublemsg = {
7225 troublemsg = {
7219 b"orphan": _(b"orphan: %d changesets"),
7226 b"orphan": _(b"orphan: %d changesets"),
7220 b"contentdivergent": _(b"content-divergent: %d changesets"),
7227 b"contentdivergent": _(b"content-divergent: %d changesets"),
7221 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7228 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7222 }
7229 }
7223 if numtrouble > 0:
7230 if numtrouble > 0:
7224 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7231 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7225
7232
7226 cmdutil.summaryhooks(ui, repo)
7233 cmdutil.summaryhooks(ui, repo)
7227
7234
7228 if opts.get(b'remote'):
7235 if opts.get(b'remote'):
7229 needsincoming, needsoutgoing = True, True
7236 needsincoming, needsoutgoing = True, True
7230 else:
7237 else:
7231 needsincoming, needsoutgoing = False, False
7238 needsincoming, needsoutgoing = False, False
7232 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7239 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7233 if i:
7240 if i:
7234 needsincoming = True
7241 needsincoming = True
7235 if o:
7242 if o:
7236 needsoutgoing = True
7243 needsoutgoing = True
7237 if not needsincoming and not needsoutgoing:
7244 if not needsincoming and not needsoutgoing:
7238 return
7245 return
7239
7246
7240 def getincoming():
7247 def getincoming():
7241 # XXX We should actually skip this if no default is specified, instead
7248 # XXX We should actually skip this if no default is specified, instead
7242 # of passing "default" which will resolve as "./default/" if no default
7249 # of passing "default" which will resolve as "./default/" if no default
7243 # path is defined.
7250 # path is defined.
7244 source, branches = urlutil.get_unique_pull_path(
7251 source, branches = urlutil.get_unique_pull_path(
7245 b'summary', repo, ui, b'default'
7252 b'summary', repo, ui, b'default'
7246 )
7253 )
7247 sbranch = branches[0]
7254 sbranch = branches[0]
7248 try:
7255 try:
7249 other = hg.peer(repo, {}, source)
7256 other = hg.peer(repo, {}, source)
7250 except error.RepoError:
7257 except error.RepoError:
7251 if opts.get(b'remote'):
7258 if opts.get(b'remote'):
7252 raise
7259 raise
7253 return source, sbranch, None, None, None
7260 return source, sbranch, None, None, None
7254 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7261 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7255 if revs:
7262 if revs:
7256 revs = [other.lookup(rev) for rev in revs]
7263 revs = [other.lookup(rev) for rev in revs]
7257 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7264 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7258 with repo.ui.silent():
7265 with repo.ui.silent():
7259 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7266 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7260 return source, sbranch, other, commoninc, commoninc[1]
7267 return source, sbranch, other, commoninc, commoninc[1]
7261
7268
7262 if needsincoming:
7269 if needsincoming:
7263 source, sbranch, sother, commoninc, incoming = getincoming()
7270 source, sbranch, sother, commoninc, incoming = getincoming()
7264 else:
7271 else:
7265 source = sbranch = sother = commoninc = incoming = None
7272 source = sbranch = sother = commoninc = incoming = None
7266
7273
7267 def getoutgoing():
7274 def getoutgoing():
7268 # XXX We should actually skip this if no default is specified, instead
7275 # XXX We should actually skip this if no default is specified, instead
7269 # of passing "default" which will resolve as "./default/" if no default
7276 # of passing "default" which will resolve as "./default/" if no default
7270 # path is defined.
7277 # path is defined.
7271 d = None
7278 d = None
7272 if b'default-push' in ui.paths:
7279 if b'default-push' in ui.paths:
7273 d = b'default-push'
7280 d = b'default-push'
7274 elif b'default' in ui.paths:
7281 elif b'default' in ui.paths:
7275 d = b'default'
7282 d = b'default'
7276 if d is not None:
7283 if d is not None:
7277 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7284 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7278 dest = path.pushloc or path.loc
7285 dest = path.pushloc or path.loc
7279 dbranch = path.branch
7286 dbranch = path.branch
7280 else:
7287 else:
7281 dest = b'default'
7288 dest = b'default'
7282 dbranch = None
7289 dbranch = None
7283 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7290 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7284 if source != dest:
7291 if source != dest:
7285 try:
7292 try:
7286 dother = hg.peer(repo, {}, dest)
7293 dother = hg.peer(repo, {}, dest)
7287 except error.RepoError:
7294 except error.RepoError:
7288 if opts.get(b'remote'):
7295 if opts.get(b'remote'):
7289 raise
7296 raise
7290 return dest, dbranch, None, None
7297 return dest, dbranch, None, None
7291 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7298 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7292 elif sother is None:
7299 elif sother is None:
7293 # there is no explicit destination peer, but source one is invalid
7300 # there is no explicit destination peer, but source one is invalid
7294 return dest, dbranch, None, None
7301 return dest, dbranch, None, None
7295 else:
7302 else:
7296 dother = sother
7303 dother = sother
7297 if source != dest or (sbranch is not None and sbranch != dbranch):
7304 if source != dest or (sbranch is not None and sbranch != dbranch):
7298 common = None
7305 common = None
7299 else:
7306 else:
7300 common = commoninc
7307 common = commoninc
7301 if revs:
7308 if revs:
7302 revs = [repo.lookup(rev) for rev in revs]
7309 revs = [repo.lookup(rev) for rev in revs]
7303 with repo.ui.silent():
7310 with repo.ui.silent():
7304 outgoing = discovery.findcommonoutgoing(
7311 outgoing = discovery.findcommonoutgoing(
7305 repo, dother, onlyheads=revs, commoninc=common
7312 repo, dother, onlyheads=revs, commoninc=common
7306 )
7313 )
7307 return dest, dbranch, dother, outgoing
7314 return dest, dbranch, dother, outgoing
7308
7315
7309 if needsoutgoing:
7316 if needsoutgoing:
7310 dest, dbranch, dother, outgoing = getoutgoing()
7317 dest, dbranch, dother, outgoing = getoutgoing()
7311 else:
7318 else:
7312 dest = dbranch = dother = outgoing = None
7319 dest = dbranch = dother = outgoing = None
7313
7320
7314 if opts.get(b'remote'):
7321 if opts.get(b'remote'):
7315 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7322 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7316 # The former always sets `sother` (or raises an exception if it can't);
7323 # The former always sets `sother` (or raises an exception if it can't);
7317 # the latter always sets `outgoing`.
7324 # the latter always sets `outgoing`.
7318 assert sother is not None
7325 assert sother is not None
7319 assert outgoing is not None
7326 assert outgoing is not None
7320
7327
7321 t = []
7328 t = []
7322 if incoming:
7329 if incoming:
7323 t.append(_(b'1 or more incoming'))
7330 t.append(_(b'1 or more incoming'))
7324 o = outgoing.missing
7331 o = outgoing.missing
7325 if o:
7332 if o:
7326 t.append(_(b'%d outgoing') % len(o))
7333 t.append(_(b'%d outgoing') % len(o))
7327 other = dother or sother
7334 other = dother or sother
7328 if b'bookmarks' in other.listkeys(b'namespaces'):
7335 if b'bookmarks' in other.listkeys(b'namespaces'):
7329 counts = bookmarks.summary(repo, other)
7336 counts = bookmarks.summary(repo, other)
7330 if counts[0] > 0:
7337 if counts[0] > 0:
7331 t.append(_(b'%d incoming bookmarks') % counts[0])
7338 t.append(_(b'%d incoming bookmarks') % counts[0])
7332 if counts[1] > 0:
7339 if counts[1] > 0:
7333 t.append(_(b'%d outgoing bookmarks') % counts[1])
7340 t.append(_(b'%d outgoing bookmarks') % counts[1])
7334
7341
7335 if t:
7342 if t:
7336 # i18n: column positioning for "hg summary"
7343 # i18n: column positioning for "hg summary"
7337 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7344 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7338 else:
7345 else:
7339 # i18n: column positioning for "hg summary"
7346 # i18n: column positioning for "hg summary"
7340 ui.status(_(b'remote: (synced)\n'))
7347 ui.status(_(b'remote: (synced)\n'))
7341
7348
7342 cmdutil.summaryremotehooks(
7349 cmdutil.summaryremotehooks(
7343 ui,
7350 ui,
7344 repo,
7351 repo,
7345 opts,
7352 opts,
7346 (
7353 (
7347 (source, sbranch, sother, commoninc),
7354 (source, sbranch, sother, commoninc),
7348 (dest, dbranch, dother, outgoing),
7355 (dest, dbranch, dother, outgoing),
7349 ),
7356 ),
7350 )
7357 )
7351
7358
7352
7359
7353 @command(
7360 @command(
7354 b'tag',
7361 b'tag',
7355 [
7362 [
7356 (b'f', b'force', None, _(b'force tag')),
7363 (b'f', b'force', None, _(b'force tag')),
7357 (b'l', b'local', None, _(b'make the tag local')),
7364 (b'l', b'local', None, _(b'make the tag local')),
7358 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7365 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7359 (b'', b'remove', None, _(b'remove a tag')),
7366 (b'', b'remove', None, _(b'remove a tag')),
7360 # -l/--local is already there, commitopts cannot be used
7367 # -l/--local is already there, commitopts cannot be used
7361 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7368 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7362 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7369 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7363 ]
7370 ]
7364 + commitopts2,
7371 + commitopts2,
7365 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7372 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7366 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7373 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7367 )
7374 )
7368 def tag(ui, repo, name1, *names, **opts):
7375 def tag(ui, repo, name1, *names, **opts):
7369 """add one or more tags for the current or given revision
7376 """add one or more tags for the current or given revision
7370
7377
7371 Name a particular revision using <name>.
7378 Name a particular revision using <name>.
7372
7379
7373 Tags are used to name particular revisions of the repository and are
7380 Tags are used to name particular revisions of the repository and are
7374 very useful to compare different revisions, to go back to significant
7381 very useful to compare different revisions, to go back to significant
7375 earlier versions or to mark branch points as releases, etc. Changing
7382 earlier versions or to mark branch points as releases, etc. Changing
7376 an existing tag is normally disallowed; use -f/--force to override.
7383 an existing tag is normally disallowed; use -f/--force to override.
7377
7384
7378 If no revision is given, the parent of the working directory is
7385 If no revision is given, the parent of the working directory is
7379 used.
7386 used.
7380
7387
7381 To facilitate version control, distribution, and merging of tags,
7388 To facilitate version control, distribution, and merging of tags,
7382 they are stored as a file named ".hgtags" which is managed similarly
7389 they are stored as a file named ".hgtags" which is managed similarly
7383 to other project files and can be hand-edited if necessary. This
7390 to other project files and can be hand-edited if necessary. This
7384 also means that tagging creates a new commit. The file
7391 also means that tagging creates a new commit. The file
7385 ".hg/localtags" is used for local tags (not shared among
7392 ".hg/localtags" is used for local tags (not shared among
7386 repositories).
7393 repositories).
7387
7394
7388 Tag commits are usually made at the head of a branch. If the parent
7395 Tag commits are usually made at the head of a branch. If the parent
7389 of the working directory is not a branch head, :hg:`tag` aborts; use
7396 of the working directory is not a branch head, :hg:`tag` aborts; use
7390 -f/--force to force the tag commit to be based on a non-head
7397 -f/--force to force the tag commit to be based on a non-head
7391 changeset.
7398 changeset.
7392
7399
7393 See :hg:`help dates` for a list of formats valid for -d/--date.
7400 See :hg:`help dates` for a list of formats valid for -d/--date.
7394
7401
7395 Since tag names have priority over branch names during revision
7402 Since tag names have priority over branch names during revision
7396 lookup, using an existing branch name as a tag name is discouraged.
7403 lookup, using an existing branch name as a tag name is discouraged.
7397
7404
7398 Returns 0 on success.
7405 Returns 0 on success.
7399 """
7406 """
7400 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7407 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7401 opts = pycompat.byteskwargs(opts)
7408 opts = pycompat.byteskwargs(opts)
7402 with repo.wlock(), repo.lock():
7409 with repo.wlock(), repo.lock():
7403 rev_ = b"."
7410 rev_ = b"."
7404 names = [t.strip() for t in (name1,) + names]
7411 names = [t.strip() for t in (name1,) + names]
7405 if len(names) != len(set(names)):
7412 if len(names) != len(set(names)):
7406 raise error.InputError(_(b'tag names must be unique'))
7413 raise error.InputError(_(b'tag names must be unique'))
7407 for n in names:
7414 for n in names:
7408 scmutil.checknewlabel(repo, n, b'tag')
7415 scmutil.checknewlabel(repo, n, b'tag')
7409 if not n:
7416 if not n:
7410 raise error.InputError(
7417 raise error.InputError(
7411 _(b'tag names cannot consist entirely of whitespace')
7418 _(b'tag names cannot consist entirely of whitespace')
7412 )
7419 )
7413 if opts.get(b'rev'):
7420 if opts.get(b'rev'):
7414 rev_ = opts[b'rev']
7421 rev_ = opts[b'rev']
7415 message = opts.get(b'message')
7422 message = opts.get(b'message')
7416 if opts.get(b'remove'):
7423 if opts.get(b'remove'):
7417 if opts.get(b'local'):
7424 if opts.get(b'local'):
7418 expectedtype = b'local'
7425 expectedtype = b'local'
7419 else:
7426 else:
7420 expectedtype = b'global'
7427 expectedtype = b'global'
7421
7428
7422 for n in names:
7429 for n in names:
7423 if repo.tagtype(n) == b'global':
7430 if repo.tagtype(n) == b'global':
7424 alltags = tagsmod.findglobaltags(ui, repo)
7431 alltags = tagsmod.findglobaltags(ui, repo)
7425 if alltags[n][0] == repo.nullid:
7432 if alltags[n][0] == repo.nullid:
7426 raise error.InputError(
7433 raise error.InputError(
7427 _(b"tag '%s' is already removed") % n
7434 _(b"tag '%s' is already removed") % n
7428 )
7435 )
7429 if not repo.tagtype(n):
7436 if not repo.tagtype(n):
7430 raise error.InputError(_(b"tag '%s' does not exist") % n)
7437 raise error.InputError(_(b"tag '%s' does not exist") % n)
7431 if repo.tagtype(n) != expectedtype:
7438 if repo.tagtype(n) != expectedtype:
7432 if expectedtype == b'global':
7439 if expectedtype == b'global':
7433 raise error.InputError(
7440 raise error.InputError(
7434 _(b"tag '%s' is not a global tag") % n
7441 _(b"tag '%s' is not a global tag") % n
7435 )
7442 )
7436 else:
7443 else:
7437 raise error.InputError(
7444 raise error.InputError(
7438 _(b"tag '%s' is not a local tag") % n
7445 _(b"tag '%s' is not a local tag") % n
7439 )
7446 )
7440 rev_ = b'null'
7447 rev_ = b'null'
7441 if not message:
7448 if not message:
7442 # we don't translate commit messages
7449 # we don't translate commit messages
7443 message = b'Removed tag %s' % b', '.join(names)
7450 message = b'Removed tag %s' % b', '.join(names)
7444 elif not opts.get(b'force'):
7451 elif not opts.get(b'force'):
7445 for n in names:
7452 for n in names:
7446 if n in repo.tags():
7453 if n in repo.tags():
7447 raise error.InputError(
7454 raise error.InputError(
7448 _(b"tag '%s' already exists (use -f to force)") % n
7455 _(b"tag '%s' already exists (use -f to force)") % n
7449 )
7456 )
7450 if not opts.get(b'local'):
7457 if not opts.get(b'local'):
7451 p1, p2 = repo.dirstate.parents()
7458 p1, p2 = repo.dirstate.parents()
7452 if p2 != repo.nullid:
7459 if p2 != repo.nullid:
7453 raise error.StateError(_(b'uncommitted merge'))
7460 raise error.StateError(_(b'uncommitted merge'))
7454 bheads = repo.branchheads()
7461 bheads = repo.branchheads()
7455 if not opts.get(b'force') and bheads and p1 not in bheads:
7462 if not opts.get(b'force') and bheads and p1 not in bheads:
7456 raise error.InputError(
7463 raise error.InputError(
7457 _(
7464 _(
7458 b'working directory is not at a branch head '
7465 b'working directory is not at a branch head '
7459 b'(use -f to force)'
7466 b'(use -f to force)'
7460 )
7467 )
7461 )
7468 )
7462 node = logcmdutil.revsingle(repo, rev_).node()
7469 node = logcmdutil.revsingle(repo, rev_).node()
7463
7470
7464 if not message:
7471 if not message:
7465 # we don't translate commit messages
7472 # we don't translate commit messages
7466 message = b'Added tag %s for changeset %s' % (
7473 message = b'Added tag %s for changeset %s' % (
7467 b', '.join(names),
7474 b', '.join(names),
7468 short(node),
7475 short(node),
7469 )
7476 )
7470
7477
7471 date = opts.get(b'date')
7478 date = opts.get(b'date')
7472 if date:
7479 if date:
7473 date = dateutil.parsedate(date)
7480 date = dateutil.parsedate(date)
7474
7481
7475 if opts.get(b'remove'):
7482 if opts.get(b'remove'):
7476 editform = b'tag.remove'
7483 editform = b'tag.remove'
7477 else:
7484 else:
7478 editform = b'tag.add'
7485 editform = b'tag.add'
7479 editor = cmdutil.getcommiteditor(
7486 editor = cmdutil.getcommiteditor(
7480 editform=editform, **pycompat.strkwargs(opts)
7487 editform=editform, **pycompat.strkwargs(opts)
7481 )
7488 )
7482
7489
7483 # don't allow tagging the null rev
7490 # don't allow tagging the null rev
7484 if (
7491 if (
7485 not opts.get(b'remove')
7492 not opts.get(b'remove')
7486 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7493 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7487 ):
7494 ):
7488 raise error.InputError(_(b"cannot tag null revision"))
7495 raise error.InputError(_(b"cannot tag null revision"))
7489
7496
7490 tagsmod.tag(
7497 tagsmod.tag(
7491 repo,
7498 repo,
7492 names,
7499 names,
7493 node,
7500 node,
7494 message,
7501 message,
7495 opts.get(b'local'),
7502 opts.get(b'local'),
7496 opts.get(b'user'),
7503 opts.get(b'user'),
7497 date,
7504 date,
7498 editor=editor,
7505 editor=editor,
7499 )
7506 )
7500
7507
7501
7508
7502 @command(
7509 @command(
7503 b'tags',
7510 b'tags',
7504 formatteropts,
7511 formatteropts,
7505 b'',
7512 b'',
7506 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7513 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7507 intents={INTENT_READONLY},
7514 intents={INTENT_READONLY},
7508 )
7515 )
7509 def tags(ui, repo, **opts):
7516 def tags(ui, repo, **opts):
7510 """list repository tags
7517 """list repository tags
7511
7518
7512 This lists both regular and local tags. When the -v/--verbose
7519 This lists both regular and local tags. When the -v/--verbose
7513 switch is used, a third column "local" is printed for local tags.
7520 switch is used, a third column "local" is printed for local tags.
7514 When the -q/--quiet switch is used, only the tag name is printed.
7521 When the -q/--quiet switch is used, only the tag name is printed.
7515
7522
7516 .. container:: verbose
7523 .. container:: verbose
7517
7524
7518 Template:
7525 Template:
7519
7526
7520 The following keywords are supported in addition to the common template
7527 The following keywords are supported in addition to the common template
7521 keywords and functions such as ``{tag}``. See also
7528 keywords and functions such as ``{tag}``. See also
7522 :hg:`help templates`.
7529 :hg:`help templates`.
7523
7530
7524 :type: String. ``local`` for local tags.
7531 :type: String. ``local`` for local tags.
7525
7532
7526 Returns 0 on success.
7533 Returns 0 on success.
7527 """
7534 """
7528
7535
7529 opts = pycompat.byteskwargs(opts)
7536 opts = pycompat.byteskwargs(opts)
7530 ui.pager(b'tags')
7537 ui.pager(b'tags')
7531 fm = ui.formatter(b'tags', opts)
7538 fm = ui.formatter(b'tags', opts)
7532 hexfunc = fm.hexfunc
7539 hexfunc = fm.hexfunc
7533
7540
7534 for t, n in reversed(repo.tagslist()):
7541 for t, n in reversed(repo.tagslist()):
7535 hn = hexfunc(n)
7542 hn = hexfunc(n)
7536 label = b'tags.normal'
7543 label = b'tags.normal'
7537 tagtype = repo.tagtype(t)
7544 tagtype = repo.tagtype(t)
7538 if not tagtype or tagtype == b'global':
7545 if not tagtype or tagtype == b'global':
7539 tagtype = b''
7546 tagtype = b''
7540 else:
7547 else:
7541 label = b'tags.' + tagtype
7548 label = b'tags.' + tagtype
7542
7549
7543 fm.startitem()
7550 fm.startitem()
7544 fm.context(repo=repo)
7551 fm.context(repo=repo)
7545 fm.write(b'tag', b'%s', t, label=label)
7552 fm.write(b'tag', b'%s', t, label=label)
7546 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7553 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7547 fm.condwrite(
7554 fm.condwrite(
7548 not ui.quiet,
7555 not ui.quiet,
7549 b'rev node',
7556 b'rev node',
7550 fmt,
7557 fmt,
7551 repo.changelog.rev(n),
7558 repo.changelog.rev(n),
7552 hn,
7559 hn,
7553 label=label,
7560 label=label,
7554 )
7561 )
7555 fm.condwrite(
7562 fm.condwrite(
7556 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7563 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7557 )
7564 )
7558 fm.plain(b'\n')
7565 fm.plain(b'\n')
7559 fm.end()
7566 fm.end()
7560
7567
7561
7568
7562 @command(
7569 @command(
7563 b'tip',
7570 b'tip',
7564 [
7571 [
7565 (b'p', b'patch', None, _(b'show patch')),
7572 (b'p', b'patch', None, _(b'show patch')),
7566 (b'g', b'git', None, _(b'use git extended diff format')),
7573 (b'g', b'git', None, _(b'use git extended diff format')),
7567 ]
7574 ]
7568 + templateopts,
7575 + templateopts,
7569 _(b'[-p] [-g]'),
7576 _(b'[-p] [-g]'),
7570 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7577 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7571 )
7578 )
7572 def tip(ui, repo, **opts):
7579 def tip(ui, repo, **opts):
7573 """show the tip revision (DEPRECATED)
7580 """show the tip revision (DEPRECATED)
7574
7581
7575 The tip revision (usually just called the tip) is the changeset
7582 The tip revision (usually just called the tip) is the changeset
7576 most recently added to the repository (and therefore the most
7583 most recently added to the repository (and therefore the most
7577 recently changed head).
7584 recently changed head).
7578
7585
7579 If you have just made a commit, that commit will be the tip. If
7586 If you have just made a commit, that commit will be the tip. If
7580 you have just pulled changes from another repository, the tip of
7587 you have just pulled changes from another repository, the tip of
7581 that repository becomes the current tip. The "tip" tag is special
7588 that repository becomes the current tip. The "tip" tag is special
7582 and cannot be renamed or assigned to a different changeset.
7589 and cannot be renamed or assigned to a different changeset.
7583
7590
7584 This command is deprecated, please use :hg:`heads` instead.
7591 This command is deprecated, please use :hg:`heads` instead.
7585
7592
7586 Returns 0 on success.
7593 Returns 0 on success.
7587 """
7594 """
7588 opts = pycompat.byteskwargs(opts)
7595 opts = pycompat.byteskwargs(opts)
7589 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7596 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7590 displayer.show(repo[b'tip'])
7597 displayer.show(repo[b'tip'])
7591 displayer.close()
7598 displayer.close()
7592
7599
7593
7600
7594 @command(
7601 @command(
7595 b'unbundle',
7602 b'unbundle',
7596 [
7603 [
7597 (
7604 (
7598 b'u',
7605 b'u',
7599 b'update',
7606 b'update',
7600 None,
7607 None,
7601 _(b'update to new branch head if changesets were unbundled'),
7608 _(b'update to new branch head if changesets were unbundled'),
7602 )
7609 )
7603 ],
7610 ],
7604 _(b'[-u] FILE...'),
7611 _(b'[-u] FILE...'),
7605 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7612 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7606 )
7613 )
7607 def unbundle(ui, repo, fname1, *fnames, **opts):
7614 def unbundle(ui, repo, fname1, *fnames, **opts):
7608 """apply one or more bundle files
7615 """apply one or more bundle files
7609
7616
7610 Apply one or more bundle files generated by :hg:`bundle`.
7617 Apply one or more bundle files generated by :hg:`bundle`.
7611
7618
7612 Returns 0 on success, 1 if an update has unresolved files.
7619 Returns 0 on success, 1 if an update has unresolved files.
7613 """
7620 """
7614 fnames = (fname1,) + fnames
7621 fnames = (fname1,) + fnames
7615
7622
7616 with repo.lock():
7623 with repo.lock():
7617 for fname in fnames:
7624 for fname in fnames:
7618 f = hg.openpath(ui, fname)
7625 f = hg.openpath(ui, fname)
7619 gen = exchange.readbundle(ui, f, fname)
7626 gen = exchange.readbundle(ui, f, fname)
7620 if isinstance(gen, streamclone.streamcloneapplier):
7627 if isinstance(gen, streamclone.streamcloneapplier):
7621 raise error.InputError(
7628 raise error.InputError(
7622 _(
7629 _(
7623 b'packed bundles cannot be applied with '
7630 b'packed bundles cannot be applied with '
7624 b'"hg unbundle"'
7631 b'"hg unbundle"'
7625 ),
7632 ),
7626 hint=_(b'use "hg debugapplystreamclonebundle"'),
7633 hint=_(b'use "hg debugapplystreamclonebundle"'),
7627 )
7634 )
7628 url = b'bundle:' + fname
7635 url = b'bundle:' + fname
7629 try:
7636 try:
7630 txnname = b'unbundle'
7637 txnname = b'unbundle'
7631 if not isinstance(gen, bundle2.unbundle20):
7638 if not isinstance(gen, bundle2.unbundle20):
7632 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7639 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7633 with repo.transaction(txnname) as tr:
7640 with repo.transaction(txnname) as tr:
7634 op = bundle2.applybundle(
7641 op = bundle2.applybundle(
7635 repo, gen, tr, source=b'unbundle', url=url
7642 repo, gen, tr, source=b'unbundle', url=url
7636 )
7643 )
7637 except error.BundleUnknownFeatureError as exc:
7644 except error.BundleUnknownFeatureError as exc:
7638 raise error.Abort(
7645 raise error.Abort(
7639 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7646 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7640 hint=_(
7647 hint=_(
7641 b"see https://mercurial-scm.org/"
7648 b"see https://mercurial-scm.org/"
7642 b"wiki/BundleFeature for more "
7649 b"wiki/BundleFeature for more "
7643 b"information"
7650 b"information"
7644 ),
7651 ),
7645 )
7652 )
7646 modheads = bundle2.combinechangegroupresults(op)
7653 modheads = bundle2.combinechangegroupresults(op)
7647
7654
7648 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7655 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7649 return 1
7656 return 1
7650 else:
7657 else:
7651 return 0
7658 return 0
7652
7659
7653
7660
7654 @command(
7661 @command(
7655 b'unshelve',
7662 b'unshelve',
7656 [
7663 [
7657 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7664 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7658 (
7665 (
7659 b'c',
7666 b'c',
7660 b'continue',
7667 b'continue',
7661 None,
7668 None,
7662 _(b'continue an incomplete unshelve operation'),
7669 _(b'continue an incomplete unshelve operation'),
7663 ),
7670 ),
7664 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7671 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7665 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7672 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7666 (
7673 (
7667 b'n',
7674 b'n',
7668 b'name',
7675 b'name',
7669 b'',
7676 b'',
7670 _(b'restore shelved change with given name'),
7677 _(b'restore shelved change with given name'),
7671 _(b'NAME'),
7678 _(b'NAME'),
7672 ),
7679 ),
7673 (b't', b'tool', b'', _(b'specify merge tool')),
7680 (b't', b'tool', b'', _(b'specify merge tool')),
7674 (
7681 (
7675 b'',
7682 b'',
7676 b'date',
7683 b'date',
7677 b'',
7684 b'',
7678 _(b'set date for temporary commits (DEPRECATED)'),
7685 _(b'set date for temporary commits (DEPRECATED)'),
7679 _(b'DATE'),
7686 _(b'DATE'),
7680 ),
7687 ),
7681 ],
7688 ],
7682 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7689 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7683 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7690 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7684 )
7691 )
7685 def unshelve(ui, repo, *shelved, **opts):
7692 def unshelve(ui, repo, *shelved, **opts):
7686 """restore a shelved change to the working directory
7693 """restore a shelved change to the working directory
7687
7694
7688 This command accepts an optional name of a shelved change to
7695 This command accepts an optional name of a shelved change to
7689 restore. If none is given, the most recent shelved change is used.
7696 restore. If none is given, the most recent shelved change is used.
7690
7697
7691 If a shelved change is applied successfully, the bundle that
7698 If a shelved change is applied successfully, the bundle that
7692 contains the shelved changes is moved to a backup location
7699 contains the shelved changes is moved to a backup location
7693 (.hg/shelve-backup).
7700 (.hg/shelve-backup).
7694
7701
7695 Since you can restore a shelved change on top of an arbitrary
7702 Since you can restore a shelved change on top of an arbitrary
7696 commit, it is possible that unshelving will result in a conflict
7703 commit, it is possible that unshelving will result in a conflict
7697 between your changes and the commits you are unshelving onto. If
7704 between your changes and the commits you are unshelving onto. If
7698 this occurs, you must resolve the conflict, then use
7705 this occurs, you must resolve the conflict, then use
7699 ``--continue`` to complete the unshelve operation. (The bundle
7706 ``--continue`` to complete the unshelve operation. (The bundle
7700 will not be moved until you successfully complete the unshelve.)
7707 will not be moved until you successfully complete the unshelve.)
7701
7708
7702 (Alternatively, you can use ``--abort`` to abandon an unshelve
7709 (Alternatively, you can use ``--abort`` to abandon an unshelve
7703 that causes a conflict. This reverts the unshelved changes, and
7710 that causes a conflict. This reverts the unshelved changes, and
7704 leaves the bundle in place.)
7711 leaves the bundle in place.)
7705
7712
7706 If bare shelved change (without interactive, include and exclude
7713 If bare shelved change (without interactive, include and exclude
7707 option) was done on newly created branch it would restore branch
7714 option) was done on newly created branch it would restore branch
7708 information to the working directory.
7715 information to the working directory.
7709
7716
7710 After a successful unshelve, the shelved changes are stored in a
7717 After a successful unshelve, the shelved changes are stored in a
7711 backup directory. Only the N most recent backups are kept. N
7718 backup directory. Only the N most recent backups are kept. N
7712 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7719 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7713 configuration option.
7720 configuration option.
7714
7721
7715 .. container:: verbose
7722 .. container:: verbose
7716
7723
7717 Timestamp in seconds is used to decide order of backups. More
7724 Timestamp in seconds is used to decide order of backups. More
7718 than ``maxbackups`` backups are kept, if same timestamp
7725 than ``maxbackups`` backups are kept, if same timestamp
7719 prevents from deciding exact order of them, for safety.
7726 prevents from deciding exact order of them, for safety.
7720
7727
7721 Selected changes can be unshelved with ``--interactive`` flag.
7728 Selected changes can be unshelved with ``--interactive`` flag.
7722 The working directory is updated with the selected changes, and
7729 The working directory is updated with the selected changes, and
7723 only the unselected changes remain shelved.
7730 only the unselected changes remain shelved.
7724 Note: The whole shelve is applied to working directory first before
7731 Note: The whole shelve is applied to working directory first before
7725 running interactively. So, this will bring up all the conflicts between
7732 running interactively. So, this will bring up all the conflicts between
7726 working directory and the shelve, irrespective of which changes will be
7733 working directory and the shelve, irrespective of which changes will be
7727 unshelved.
7734 unshelved.
7728 """
7735 """
7729 with repo.wlock():
7736 with repo.wlock():
7730 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7737 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7731
7738
7732
7739
7733 statemod.addunfinished(
7740 statemod.addunfinished(
7734 b'unshelve',
7741 b'unshelve',
7735 fname=b'shelvedstate',
7742 fname=b'shelvedstate',
7736 continueflag=True,
7743 continueflag=True,
7737 abortfunc=shelvemod.hgabortunshelve,
7744 abortfunc=shelvemod.hgabortunshelve,
7738 continuefunc=shelvemod.hgcontinueunshelve,
7745 continuefunc=shelvemod.hgcontinueunshelve,
7739 cmdmsg=_(b'unshelve already in progress'),
7746 cmdmsg=_(b'unshelve already in progress'),
7740 )
7747 )
7741
7748
7742
7749
7743 @command(
7750 @command(
7744 b'update|up|checkout|co',
7751 b'update|up|checkout|co',
7745 [
7752 [
7746 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7753 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7747 (b'c', b'check', None, _(b'require clean working directory')),
7754 (b'c', b'check', None, _(b'require clean working directory')),
7748 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7755 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7749 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7756 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7750 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7757 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7751 ]
7758 ]
7752 + mergetoolopts,
7759 + mergetoolopts,
7753 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7760 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7754 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7761 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7755 helpbasic=True,
7762 helpbasic=True,
7756 )
7763 )
7757 def update(ui, repo, node=None, **opts):
7764 def update(ui, repo, node=None, **opts):
7758 """update working directory (or switch revisions)
7765 """update working directory (or switch revisions)
7759
7766
7760 Update the repository's working directory to the specified
7767 Update the repository's working directory to the specified
7761 changeset. If no changeset is specified, update to the tip of the
7768 changeset. If no changeset is specified, update to the tip of the
7762 current named branch and move the active bookmark (see :hg:`help
7769 current named branch and move the active bookmark (see :hg:`help
7763 bookmarks`).
7770 bookmarks`).
7764
7771
7765 Update sets the working directory's parent revision to the specified
7772 Update sets the working directory's parent revision to the specified
7766 changeset (see :hg:`help parents`).
7773 changeset (see :hg:`help parents`).
7767
7774
7768 If the changeset is not a descendant or ancestor of the working
7775 If the changeset is not a descendant or ancestor of the working
7769 directory's parent and there are uncommitted changes, the update is
7776 directory's parent and there are uncommitted changes, the update is
7770 aborted. With the -c/--check option, the working directory is checked
7777 aborted. With the -c/--check option, the working directory is checked
7771 for uncommitted changes; if none are found, the working directory is
7778 for uncommitted changes; if none are found, the working directory is
7772 updated to the specified changeset.
7779 updated to the specified changeset.
7773
7780
7774 .. container:: verbose
7781 .. container:: verbose
7775
7782
7776 The -C/--clean, -c/--check, and -m/--merge options control what
7783 The -C/--clean, -c/--check, and -m/--merge options control what
7777 happens if the working directory contains uncommitted changes.
7784 happens if the working directory contains uncommitted changes.
7778 At most of one of them can be specified.
7785 At most of one of them can be specified.
7779
7786
7780 1. If no option is specified, and if
7787 1. If no option is specified, and if
7781 the requested changeset is an ancestor or descendant of
7788 the requested changeset is an ancestor or descendant of
7782 the working directory's parent, the uncommitted changes
7789 the working directory's parent, the uncommitted changes
7783 are merged into the requested changeset and the merged
7790 are merged into the requested changeset and the merged
7784 result is left uncommitted. If the requested changeset is
7791 result is left uncommitted. If the requested changeset is
7785 not an ancestor or descendant (that is, it is on another
7792 not an ancestor or descendant (that is, it is on another
7786 branch), the update is aborted and the uncommitted changes
7793 branch), the update is aborted and the uncommitted changes
7787 are preserved.
7794 are preserved.
7788
7795
7789 2. With the -m/--merge option, the update is allowed even if the
7796 2. With the -m/--merge option, the update is allowed even if the
7790 requested changeset is not an ancestor or descendant of
7797 requested changeset is not an ancestor or descendant of
7791 the working directory's parent.
7798 the working directory's parent.
7792
7799
7793 3. With the -c/--check option, the update is aborted and the
7800 3. With the -c/--check option, the update is aborted and the
7794 uncommitted changes are preserved.
7801 uncommitted changes are preserved.
7795
7802
7796 4. With the -C/--clean option, uncommitted changes are discarded and
7803 4. With the -C/--clean option, uncommitted changes are discarded and
7797 the working directory is updated to the requested changeset.
7804 the working directory is updated to the requested changeset.
7798
7805
7799 To cancel an uncommitted merge (and lose your changes), use
7806 To cancel an uncommitted merge (and lose your changes), use
7800 :hg:`merge --abort`.
7807 :hg:`merge --abort`.
7801
7808
7802 Use null as the changeset to remove the working directory (like
7809 Use null as the changeset to remove the working directory (like
7803 :hg:`clone -U`).
7810 :hg:`clone -U`).
7804
7811
7805 If you want to revert just one file to an older revision, use
7812 If you want to revert just one file to an older revision, use
7806 :hg:`revert [-r REV] NAME`.
7813 :hg:`revert [-r REV] NAME`.
7807
7814
7808 See :hg:`help dates` for a list of formats valid for -d/--date.
7815 See :hg:`help dates` for a list of formats valid for -d/--date.
7809
7816
7810 Returns 0 on success, 1 if there are unresolved files.
7817 Returns 0 on success, 1 if there are unresolved files.
7811 """
7818 """
7812 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7819 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7813 rev = opts.get('rev')
7820 rev = opts.get('rev')
7814 date = opts.get('date')
7821 date = opts.get('date')
7815 clean = opts.get('clean')
7822 clean = opts.get('clean')
7816 check = opts.get('check')
7823 check = opts.get('check')
7817 merge = opts.get('merge')
7824 merge = opts.get('merge')
7818 if rev and node:
7825 if rev and node:
7819 raise error.InputError(_(b"please specify just one revision"))
7826 raise error.InputError(_(b"please specify just one revision"))
7820
7827
7821 if ui.configbool(b'commands', b'update.requiredest'):
7828 if ui.configbool(b'commands', b'update.requiredest'):
7822 if not node and not rev and not date:
7829 if not node and not rev and not date:
7823 raise error.InputError(
7830 raise error.InputError(
7824 _(b'you must specify a destination'),
7831 _(b'you must specify a destination'),
7825 hint=_(b'for example: hg update ".::"'),
7832 hint=_(b'for example: hg update ".::"'),
7826 )
7833 )
7827
7834
7828 if rev is None or rev == b'':
7835 if rev is None or rev == b'':
7829 rev = node
7836 rev = node
7830
7837
7831 if date and rev is not None:
7838 if date and rev is not None:
7832 raise error.InputError(_(b"you can't specify a revision and a date"))
7839 raise error.InputError(_(b"you can't specify a revision and a date"))
7833
7840
7834 updatecheck = None
7841 updatecheck = None
7835 if check or merge is not None and not merge:
7842 if check or merge is not None and not merge:
7836 updatecheck = b'abort'
7843 updatecheck = b'abort'
7837 elif merge or check is not None and not check:
7844 elif merge or check is not None and not check:
7838 updatecheck = b'none'
7845 updatecheck = b'none'
7839
7846
7840 with repo.wlock():
7847 with repo.wlock():
7841 cmdutil.clearunfinished(repo)
7848 cmdutil.clearunfinished(repo)
7842 if date:
7849 if date:
7843 rev = cmdutil.finddate(ui, repo, date)
7850 rev = cmdutil.finddate(ui, repo, date)
7844
7851
7845 # if we defined a bookmark, we have to remember the original name
7852 # if we defined a bookmark, we have to remember the original name
7846 brev = rev
7853 brev = rev
7847 if rev:
7854 if rev:
7848 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7855 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7849 ctx = logcmdutil.revsingle(repo, rev, default=None)
7856 ctx = logcmdutil.revsingle(repo, rev, default=None)
7850 rev = ctx.rev()
7857 rev = ctx.rev()
7851 hidden = ctx.hidden()
7858 hidden = ctx.hidden()
7852 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7859 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7853 with ui.configoverride(overrides, b'update'):
7860 with ui.configoverride(overrides, b'update'):
7854 ret = hg.updatetotally(
7861 ret = hg.updatetotally(
7855 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7862 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7856 )
7863 )
7857 if hidden:
7864 if hidden:
7858 ctxstr = ctx.hex()[:12]
7865 ctxstr = ctx.hex()[:12]
7859 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7866 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7860
7867
7861 if ctx.obsolete():
7868 if ctx.obsolete():
7862 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7869 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7863 ui.warn(b"(%s)\n" % obsfatemsg)
7870 ui.warn(b"(%s)\n" % obsfatemsg)
7864 return ret
7871 return ret
7865
7872
7866
7873
7867 @command(
7874 @command(
7868 b'verify',
7875 b'verify',
7869 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7876 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7870 helpcategory=command.CATEGORY_MAINTENANCE,
7877 helpcategory=command.CATEGORY_MAINTENANCE,
7871 )
7878 )
7872 def verify(ui, repo, **opts):
7879 def verify(ui, repo, **opts):
7873 """verify the integrity of the repository
7880 """verify the integrity of the repository
7874
7881
7875 Verify the integrity of the current repository.
7882 Verify the integrity of the current repository.
7876
7883
7877 This will perform an extensive check of the repository's
7884 This will perform an extensive check of the repository's
7878 integrity, validating the hashes and checksums of each entry in
7885 integrity, validating the hashes and checksums of each entry in
7879 the changelog, manifest, and tracked files, as well as the
7886 the changelog, manifest, and tracked files, as well as the
7880 integrity of their crosslinks and indices.
7887 integrity of their crosslinks and indices.
7881
7888
7882 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7889 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7883 for more information about recovery from corruption of the
7890 for more information about recovery from corruption of the
7884 repository.
7891 repository.
7885
7892
7886 Returns 0 on success, 1 if errors are encountered.
7893 Returns 0 on success, 1 if errors are encountered.
7887 """
7894 """
7888 opts = pycompat.byteskwargs(opts)
7895 opts = pycompat.byteskwargs(opts)
7889
7896
7890 level = None
7897 level = None
7891 if opts[b'full']:
7898 if opts[b'full']:
7892 level = verifymod.VERIFY_FULL
7899 level = verifymod.VERIFY_FULL
7893 return hg.verify(repo, level)
7900 return hg.verify(repo, level)
7894
7901
7895
7902
7896 @command(
7903 @command(
7897 b'version',
7904 b'version',
7898 [] + formatteropts,
7905 [] + formatteropts,
7899 helpcategory=command.CATEGORY_HELP,
7906 helpcategory=command.CATEGORY_HELP,
7900 norepo=True,
7907 norepo=True,
7901 intents={INTENT_READONLY},
7908 intents={INTENT_READONLY},
7902 )
7909 )
7903 def version_(ui, **opts):
7910 def version_(ui, **opts):
7904 """output version and copyright information
7911 """output version and copyright information
7905
7912
7906 .. container:: verbose
7913 .. container:: verbose
7907
7914
7908 Template:
7915 Template:
7909
7916
7910 The following keywords are supported. See also :hg:`help templates`.
7917 The following keywords are supported. See also :hg:`help templates`.
7911
7918
7912 :extensions: List of extensions.
7919 :extensions: List of extensions.
7913 :ver: String. Version number.
7920 :ver: String. Version number.
7914
7921
7915 And each entry of ``{extensions}`` provides the following sub-keywords
7922 And each entry of ``{extensions}`` provides the following sub-keywords
7916 in addition to ``{ver}``.
7923 in addition to ``{ver}``.
7917
7924
7918 :bundled: Boolean. True if included in the release.
7925 :bundled: Boolean. True if included in the release.
7919 :name: String. Extension name.
7926 :name: String. Extension name.
7920 """
7927 """
7921 opts = pycompat.byteskwargs(opts)
7928 opts = pycompat.byteskwargs(opts)
7922 if ui.verbose:
7929 if ui.verbose:
7923 ui.pager(b'version')
7930 ui.pager(b'version')
7924 fm = ui.formatter(b"version", opts)
7931 fm = ui.formatter(b"version", opts)
7925 fm.startitem()
7932 fm.startitem()
7926 fm.write(
7933 fm.write(
7927 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7934 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7928 )
7935 )
7929 license = _(
7936 license = _(
7930 b"(see https://mercurial-scm.org for more information)\n"
7937 b"(see https://mercurial-scm.org for more information)\n"
7931 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7938 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7932 b"This is free software; see the source for copying conditions. "
7939 b"This is free software; see the source for copying conditions. "
7933 b"There is NO\nwarranty; "
7940 b"There is NO\nwarranty; "
7934 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7941 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7935 )
7942 )
7936 if not ui.quiet:
7943 if not ui.quiet:
7937 fm.plain(license)
7944 fm.plain(license)
7938
7945
7939 if ui.verbose:
7946 if ui.verbose:
7940 fm.plain(_(b"\nEnabled extensions:\n\n"))
7947 fm.plain(_(b"\nEnabled extensions:\n\n"))
7941 # format names and versions into columns
7948 # format names and versions into columns
7942 names = []
7949 names = []
7943 vers = []
7950 vers = []
7944 isinternals = []
7951 isinternals = []
7945 for name, module in sorted(extensions.extensions()):
7952 for name, module in sorted(extensions.extensions()):
7946 names.append(name)
7953 names.append(name)
7947 vers.append(extensions.moduleversion(module) or None)
7954 vers.append(extensions.moduleversion(module) or None)
7948 isinternals.append(extensions.ismoduleinternal(module))
7955 isinternals.append(extensions.ismoduleinternal(module))
7949 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7956 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7950 if names:
7957 if names:
7951 namefmt = b" %%-%ds " % max(len(n) for n in names)
7958 namefmt = b" %%-%ds " % max(len(n) for n in names)
7952 places = [_(b"external"), _(b"internal")]
7959 places = [_(b"external"), _(b"internal")]
7953 for n, v, p in zip(names, vers, isinternals):
7960 for n, v, p in zip(names, vers, isinternals):
7954 fn.startitem()
7961 fn.startitem()
7955 fn.condwrite(ui.verbose, b"name", namefmt, n)
7962 fn.condwrite(ui.verbose, b"name", namefmt, n)
7956 if ui.verbose:
7963 if ui.verbose:
7957 fn.plain(b"%s " % places[p])
7964 fn.plain(b"%s " % places[p])
7958 fn.data(bundled=p)
7965 fn.data(bundled=p)
7959 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7966 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7960 if ui.verbose:
7967 if ui.verbose:
7961 fn.plain(b"\n")
7968 fn.plain(b"\n")
7962 fn.end()
7969 fn.end()
7963 fm.end()
7970 fm.end()
7964
7971
7965
7972
7966 def loadcmdtable(ui, name, cmdtable):
7973 def loadcmdtable(ui, name, cmdtable):
7967 """Load command functions from specified cmdtable"""
7974 """Load command functions from specified cmdtable"""
7968 overrides = [cmd for cmd in cmdtable if cmd in table]
7975 overrides = [cmd for cmd in cmdtable if cmd in table]
7969 if overrides:
7976 if overrides:
7970 ui.warn(
7977 ui.warn(
7971 _(b"extension '%s' overrides commands: %s\n")
7978 _(b"extension '%s' overrides commands: %s\n")
7972 % (name, b" ".join(overrides))
7979 % (name, b" ".join(overrides))
7973 )
7980 )
7974 table.update(cmdtable)
7981 table.update(cmdtable)
@@ -1,797 +1,796
1 # The tests in test-bisect are done on a linear history. Here the
1 # The tests in test-bisect are done on a linear history. Here the
2 # following repository history is used for testing:
2 # following repository history is used for testing:
3 #
3 #
4 # 17
4 # 17
5 # |
5 # |
6 # 18 16
6 # 18 16
7 # \ /
7 # \ /
8 # 15
8 # 15
9 # / \
9 # / \
10 # / \
10 # / \
11 # 10 13
11 # 10 13
12 # / \ |
12 # / \ |
13 # / \ | 14
13 # / \ | 14
14 # 7 6 9 12 /
14 # 7 6 9 12 /
15 # \ / \ | |/
15 # \ / \ | |/
16 # 4 \ | 11
16 # 4 \ | 11
17 # \ \ | /
17 # \ \ | /
18 # 3 5 | /
18 # 3 5 | /
19 # \ / |/
19 # \ / |/
20 # 2 8
20 # 2 8
21 # \ /
21 # \ /
22 # 1
22 # 1
23 # |
23 # |
24 # 0
24 # 0
25
25
26 init
26 init
27
27
28 $ hg init
28 $ hg init
29
29
30 committing changes
30 committing changes
31
31
32 $ echo > a
32 $ echo > a
33 $ echo '0' >> a
33 $ echo '0' >> a
34 $ hg add a
34 $ hg add a
35 $ hg ci -m "0" -d "0 0"
35 $ hg ci -m "0" -d "0 0"
36 $ echo '1' >> a
36 $ echo '1' >> a
37 $ hg ci -m "1" -d "1 0"
37 $ hg ci -m "1" -d "1 0"
38 $ echo '2' >> a
38 $ echo '2' >> a
39 $ hg ci -m "2" -d "2 0"
39 $ hg ci -m "2" -d "2 0"
40 $ echo '3' >> a
40 $ echo '3' >> a
41 $ hg ci -m "3" -d "3 0"
41 $ hg ci -m "3" -d "3 0"
42 $ echo '4' >> a
42 $ echo '4' >> a
43 $ hg ci -m "4" -d "4 0"
43 $ hg ci -m "4" -d "4 0"
44
44
45 create branch
45 create branch
46
46
47 $ hg up -r 2
47 $ hg up -r 2
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 $ echo '5' >> b
49 $ echo '5' >> b
50 $ hg add b
50 $ hg add b
51 $ hg ci -m "5" -d "5 0"
51 $ hg ci -m "5" -d "5 0"
52 created new head
52 created new head
53
53
54 merge
54 merge
55
55
56 $ hg merge
56 $ hg merge
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 (branch merge, don't forget to commit)
58 (branch merge, don't forget to commit)
59 $ hg ci -m "merge 4,5" -d "6 0"
59 $ hg ci -m "merge 4,5" -d "6 0"
60
60
61 create branch
61 create branch
62
62
63 $ hg up -r 4
63 $ hg up -r 4
64 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
64 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
65 $ echo '7' > c
65 $ echo '7' > c
66 $ hg add c
66 $ hg add c
67 $ hg ci -m "7" -d "7 0"
67 $ hg ci -m "7" -d "7 0"
68 created new head
68 created new head
69
69
70 create branch
70 create branch
71
71
72 $ hg up -r 1
72 $ hg up -r 1
73 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
73 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
74 $ echo '8' > d
74 $ echo '8' > d
75 $ hg add d
75 $ hg add d
76 $ hg ci -m "8" -d "8 0"
76 $ hg ci -m "8" -d "8 0"
77 created new head
77 created new head
78 $ echo '9' >> d
78 $ echo '9' >> d
79 $ hg ci -m "9" -d "9 0"
79 $ hg ci -m "9" -d "9 0"
80
80
81 merge
81 merge
82
82
83 $ hg merge -r 6
83 $ hg merge -r 6
84 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 (branch merge, don't forget to commit)
85 (branch merge, don't forget to commit)
86 $ hg ci -m "merge 6,9" -d "10 0"
86 $ hg ci -m "merge 6,9" -d "10 0"
87
87
88 create branch
88 create branch
89
89
90 $ hg up -r 8
90 $ hg up -r 8
91 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
91 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
92 $ echo '11' > e
92 $ echo '11' > e
93 $ hg add e
93 $ hg add e
94 $ hg ci -m "11" -d "11 0"
94 $ hg ci -m "11" -d "11 0"
95 created new head
95 created new head
96 $ echo '12' >> e
96 $ echo '12' >> e
97 $ hg ci -m "12" -d "12 0"
97 $ hg ci -m "12" -d "12 0"
98 $ echo '13' >> e
98 $ echo '13' >> e
99 $ hg ci -m "13" -d "13 0"
99 $ hg ci -m "13" -d "13 0"
100
100
101 create branch
101 create branch
102
102
103 $ hg up -r 11
103 $ hg up -r 11
104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 $ echo '14' > f
105 $ echo '14' > f
106 $ hg add f
106 $ hg add f
107 $ hg ci -m "14" -d "14 0"
107 $ hg ci -m "14" -d "14 0"
108 created new head
108 created new head
109
109
110 merge
110 merge
111
111
112 $ hg up -r 13 -C
112 $ hg up -r 13 -C
113 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ hg merge -r 10
114 $ hg merge -r 10
115 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 (branch merge, don't forget to commit)
116 (branch merge, don't forget to commit)
117 $ hg ci -m "merge 10,13" -d "15 0"
117 $ hg ci -m "merge 10,13" -d "15 0"
118 $ echo '16' >> e
118 $ echo '16' >> e
119 $ hg ci -m "16" -d "16 0"
119 $ hg ci -m "16" -d "16 0"
120 $ echo '17' >> e
120 $ echo '17' >> e
121 $ hg ci -m "17" -d "17 0"
121 $ hg ci -m "17" -d "17 0"
122
122
123 create branch
123 create branch
124
124
125 $ hg up -r 15
125 $ hg up -r 15
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 $ echo '18' >> e
127 $ echo '18' >> e
128 $ hg ci -m "18" -d "18 0"
128 $ hg ci -m "18" -d "18 0"
129 created new head
129 created new head
130
130
131 log
131 log
132
132
133 $ hg log
133 $ hg log
134 changeset: 18:d42e18c7bc9b
134 changeset: 18:d42e18c7bc9b
135 tag: tip
135 tag: tip
136 parent: 15:857b178a7cf3
136 parent: 15:857b178a7cf3
137 user: test
137 user: test
138 date: Thu Jan 01 00:00:18 1970 +0000
138 date: Thu Jan 01 00:00:18 1970 +0000
139 summary: 18
139 summary: 18
140
140
141 changeset: 17:228c06deef46
141 changeset: 17:228c06deef46
142 user: test
142 user: test
143 date: Thu Jan 01 00:00:17 1970 +0000
143 date: Thu Jan 01 00:00:17 1970 +0000
144 summary: 17
144 summary: 17
145
145
146 changeset: 16:609d82a7ebae
146 changeset: 16:609d82a7ebae
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:16 1970 +0000
148 date: Thu Jan 01 00:00:16 1970 +0000
149 summary: 16
149 summary: 16
150
150
151 changeset: 15:857b178a7cf3
151 changeset: 15:857b178a7cf3
152 parent: 13:b0a32c86eb31
152 parent: 13:b0a32c86eb31
153 parent: 10:429fcd26f52d
153 parent: 10:429fcd26f52d
154 user: test
154 user: test
155 date: Thu Jan 01 00:00:15 1970 +0000
155 date: Thu Jan 01 00:00:15 1970 +0000
156 summary: merge 10,13
156 summary: merge 10,13
157
157
158 changeset: 14:faa450606157
158 changeset: 14:faa450606157
159 parent: 11:82ca6f06eccd
159 parent: 11:82ca6f06eccd
160 user: test
160 user: test
161 date: Thu Jan 01 00:00:14 1970 +0000
161 date: Thu Jan 01 00:00:14 1970 +0000
162 summary: 14
162 summary: 14
163
163
164 changeset: 13:b0a32c86eb31
164 changeset: 13:b0a32c86eb31
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:13 1970 +0000
166 date: Thu Jan 01 00:00:13 1970 +0000
167 summary: 13
167 summary: 13
168
168
169 changeset: 12:9f259202bbe7
169 changeset: 12:9f259202bbe7
170 user: test
170 user: test
171 date: Thu Jan 01 00:00:12 1970 +0000
171 date: Thu Jan 01 00:00:12 1970 +0000
172 summary: 12
172 summary: 12
173
173
174 changeset: 11:82ca6f06eccd
174 changeset: 11:82ca6f06eccd
175 parent: 8:dab8161ac8fc
175 parent: 8:dab8161ac8fc
176 user: test
176 user: test
177 date: Thu Jan 01 00:00:11 1970 +0000
177 date: Thu Jan 01 00:00:11 1970 +0000
178 summary: 11
178 summary: 11
179
179
180 changeset: 10:429fcd26f52d
180 changeset: 10:429fcd26f52d
181 parent: 9:3c77083deb4a
181 parent: 9:3c77083deb4a
182 parent: 6:a214d5d3811a
182 parent: 6:a214d5d3811a
183 user: test
183 user: test
184 date: Thu Jan 01 00:00:10 1970 +0000
184 date: Thu Jan 01 00:00:10 1970 +0000
185 summary: merge 6,9
185 summary: merge 6,9
186
186
187 changeset: 9:3c77083deb4a
187 changeset: 9:3c77083deb4a
188 user: test
188 user: test
189 date: Thu Jan 01 00:00:09 1970 +0000
189 date: Thu Jan 01 00:00:09 1970 +0000
190 summary: 9
190 summary: 9
191
191
192 changeset: 8:dab8161ac8fc
192 changeset: 8:dab8161ac8fc
193 parent: 1:4ca5088da217
193 parent: 1:4ca5088da217
194 user: test
194 user: test
195 date: Thu Jan 01 00:00:08 1970 +0000
195 date: Thu Jan 01 00:00:08 1970 +0000
196 summary: 8
196 summary: 8
197
197
198 changeset: 7:50c76098bbf2
198 changeset: 7:50c76098bbf2
199 parent: 4:5c668c22234f
199 parent: 4:5c668c22234f
200 user: test
200 user: test
201 date: Thu Jan 01 00:00:07 1970 +0000
201 date: Thu Jan 01 00:00:07 1970 +0000
202 summary: 7
202 summary: 7
203
203
204 changeset: 6:a214d5d3811a
204 changeset: 6:a214d5d3811a
205 parent: 5:385a529b6670
205 parent: 5:385a529b6670
206 parent: 4:5c668c22234f
206 parent: 4:5c668c22234f
207 user: test
207 user: test
208 date: Thu Jan 01 00:00:06 1970 +0000
208 date: Thu Jan 01 00:00:06 1970 +0000
209 summary: merge 4,5
209 summary: merge 4,5
210
210
211 changeset: 5:385a529b6670
211 changeset: 5:385a529b6670
212 parent: 2:051e12f87bf1
212 parent: 2:051e12f87bf1
213 user: test
213 user: test
214 date: Thu Jan 01 00:00:05 1970 +0000
214 date: Thu Jan 01 00:00:05 1970 +0000
215 summary: 5
215 summary: 5
216
216
217 changeset: 4:5c668c22234f
217 changeset: 4:5c668c22234f
218 user: test
218 user: test
219 date: Thu Jan 01 00:00:04 1970 +0000
219 date: Thu Jan 01 00:00:04 1970 +0000
220 summary: 4
220 summary: 4
221
221
222 changeset: 3:0950834f0a9c
222 changeset: 3:0950834f0a9c
223 user: test
223 user: test
224 date: Thu Jan 01 00:00:03 1970 +0000
224 date: Thu Jan 01 00:00:03 1970 +0000
225 summary: 3
225 summary: 3
226
226
227 changeset: 2:051e12f87bf1
227 changeset: 2:051e12f87bf1
228 user: test
228 user: test
229 date: Thu Jan 01 00:00:02 1970 +0000
229 date: Thu Jan 01 00:00:02 1970 +0000
230 summary: 2
230 summary: 2
231
231
232 changeset: 1:4ca5088da217
232 changeset: 1:4ca5088da217
233 user: test
233 user: test
234 date: Thu Jan 01 00:00:01 1970 +0000
234 date: Thu Jan 01 00:00:01 1970 +0000
235 summary: 1
235 summary: 1
236
236
237 changeset: 0:33b1f9bc8bc5
237 changeset: 0:33b1f9bc8bc5
238 user: test
238 user: test
239 date: Thu Jan 01 00:00:00 1970 +0000
239 date: Thu Jan 01 00:00:00 1970 +0000
240 summary: 0
240 summary: 0
241
241
242
242
243 hg up -C
243 hg up -C
244
244
245 $ hg up -C
245 $ hg up -C
246 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 updated to "d42e18c7bc9b: 18"
247 updated to "d42e18c7bc9b: 18"
248 3 other heads for branch "default"
248 3 other heads for branch "default"
249
249
250 complex bisect test 1 # first bad rev is 9
250 complex bisect test 1 # first bad rev is 9
251
251
252 $ hg bisect -r
252 $ hg bisect -r
253 $ hg bisect -g 0
253 $ hg bisect -g 0
254 $ hg bisect -b 17 # -> update to rev 6
254 $ hg bisect -b 17 # -> update to rev 6
255 Testing changeset 6:a214d5d3811a "merge 4,5" (15 changesets remaining, ~3 tests)
255 Testing changeset 6:a214d5d3811a "merge 4,5" (15 changesets remaining, ~3 tests)
256 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
256 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
257 $ hg log -q -r 'bisect(pruned)'
257 $ hg log -q -r 'bisect(pruned)'
258 0:33b1f9bc8bc5
258 0:33b1f9bc8bc5
259 17:228c06deef46
259 17:228c06deef46
260 $ hg log -q -r 'bisect(untested)'
260 $ hg log -q -r 'bisect(untested)'
261 1:4ca5088da217
261 1:4ca5088da217
262 2:051e12f87bf1
262 2:051e12f87bf1
263 3:0950834f0a9c
263 3:0950834f0a9c
264 4:5c668c22234f
264 4:5c668c22234f
265 5:385a529b6670
265 5:385a529b6670
266 6:a214d5d3811a
266 6:a214d5d3811a
267 8:dab8161ac8fc
267 8:dab8161ac8fc
268 9:3c77083deb4a
268 9:3c77083deb4a
269 10:429fcd26f52d
269 10:429fcd26f52d
270 11:82ca6f06eccd
270 11:82ca6f06eccd
271 12:9f259202bbe7
271 12:9f259202bbe7
272 13:b0a32c86eb31
272 13:b0a32c86eb31
273 15:857b178a7cf3
273 15:857b178a7cf3
274 16:609d82a7ebae
274 16:609d82a7ebae
275 $ hg log -q -r 'bisect(ignored)'
275 $ hg log -q -r 'bisect(ignored)'
276 $ hg bisect -g # -> update to rev 13
276 $ hg bisect -g # -> update to rev 13
277 Testing changeset 13:b0a32c86eb31 "13" (9 changesets remaining, ~3 tests)
277 Testing changeset 13:b0a32c86eb31 "13" (9 changesets remaining, ~3 tests)
278 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
278 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
279 $ hg bisect -s # -> update to rev 10
279 $ hg bisect -s # -> update to rev 10
280 Testing changeset 10:429fcd26f52d "merge 6,9" (9 changesets remaining, ~3 tests)
280 Testing changeset 10:429fcd26f52d "merge 6,9" (9 changesets remaining, ~3 tests)
281 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
281 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
282 $ hg bisect -b # -> update to rev 8
282 $ hg bisect -b # -> update to rev 8
283 Testing changeset 8:dab8161ac8fc "8" (3 changesets remaining, ~1 tests)
283 Testing changeset 8:dab8161ac8fc "8" (3 changesets remaining, ~1 tests)
284 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
284 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 $ hg bisect -g # -> update to rev 9
285 $ hg bisect -g # -> update to rev 9
286 Testing changeset 9:3c77083deb4a "9" (2 changesets remaining, ~1 tests)
286 Testing changeset 9:3c77083deb4a "9" (2 changesets remaining, ~1 tests)
287 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 $ hg bisect -b
288 $ hg bisect -b
289 The first bad revision is:
289 The first bad revision is:
290 changeset: 9:3c77083deb4a
290 changeset: 9:3c77083deb4a
291 user: test
291 user: test
292 date: Thu Jan 01 00:00:09 1970 +0000
292 date: Thu Jan 01 00:00:09 1970 +0000
293 summary: 9
293 summary: 9
294
294
295 $ hg log -q -r 'bisect(range)'
295 $ hg log -q -r 'bisect(range)'
296 0:33b1f9bc8bc5
296 0:33b1f9bc8bc5
297 1:4ca5088da217
297 1:4ca5088da217
298 2:051e12f87bf1
298 2:051e12f87bf1
299 3:0950834f0a9c
299 3:0950834f0a9c
300 4:5c668c22234f
300 4:5c668c22234f
301 5:385a529b6670
301 5:385a529b6670
302 6:a214d5d3811a
302 6:a214d5d3811a
303 8:dab8161ac8fc
303 8:dab8161ac8fc
304 9:3c77083deb4a
304 9:3c77083deb4a
305 10:429fcd26f52d
305 10:429fcd26f52d
306 11:82ca6f06eccd
306 11:82ca6f06eccd
307 12:9f259202bbe7
307 12:9f259202bbe7
308 13:b0a32c86eb31
308 13:b0a32c86eb31
309 15:857b178a7cf3
309 15:857b178a7cf3
310 16:609d82a7ebae
310 16:609d82a7ebae
311 17:228c06deef46
311 17:228c06deef46
312 $ hg log -q -r 'bisect(pruned)'
312 $ hg log -q -r 'bisect(pruned)'
313 0:33b1f9bc8bc5
313 0:33b1f9bc8bc5
314 1:4ca5088da217
314 1:4ca5088da217
315 2:051e12f87bf1
315 2:051e12f87bf1
316 3:0950834f0a9c
316 3:0950834f0a9c
317 4:5c668c22234f
317 4:5c668c22234f
318 5:385a529b6670
318 5:385a529b6670
319 6:a214d5d3811a
319 6:a214d5d3811a
320 8:dab8161ac8fc
320 8:dab8161ac8fc
321 9:3c77083deb4a
321 9:3c77083deb4a
322 10:429fcd26f52d
322 10:429fcd26f52d
323 13:b0a32c86eb31
323 13:b0a32c86eb31
324 15:857b178a7cf3
324 15:857b178a7cf3
325 16:609d82a7ebae
325 16:609d82a7ebae
326 17:228c06deef46
326 17:228c06deef46
327 18:d42e18c7bc9b
327 18:d42e18c7bc9b
328 $ hg log -q -r 'bisect(untested)'
328 $ hg log -q -r 'bisect(untested)'
329 11:82ca6f06eccd
329 11:82ca6f06eccd
330 12:9f259202bbe7
330 12:9f259202bbe7
331 $ hg log -q -r 'bisect(goods)'
331 $ hg log -q -r 'bisect(goods)'
332 0:33b1f9bc8bc5
332 0:33b1f9bc8bc5
333 1:4ca5088da217
333 1:4ca5088da217
334 2:051e12f87bf1
334 2:051e12f87bf1
335 3:0950834f0a9c
335 3:0950834f0a9c
336 4:5c668c22234f
336 4:5c668c22234f
337 5:385a529b6670
337 5:385a529b6670
338 6:a214d5d3811a
338 6:a214d5d3811a
339 8:dab8161ac8fc
339 8:dab8161ac8fc
340 $ hg log -q -r 'bisect(bads)'
340 $ hg log -q -r 'bisect(bads)'
341 9:3c77083deb4a
341 9:3c77083deb4a
342 10:429fcd26f52d
342 10:429fcd26f52d
343 15:857b178a7cf3
343 15:857b178a7cf3
344 16:609d82a7ebae
344 16:609d82a7ebae
345 17:228c06deef46
345 17:228c06deef46
346 18:d42e18c7bc9b
346 18:d42e18c7bc9b
347
347
348 complex bisect test 2 # first good rev is 13
348 complex bisect test 2 # first good rev is 13
349
349
350 $ hg bisect -r
350 $ hg bisect -r
351 $ hg bisect -g 18
351 $ hg bisect -g 18
352 $ hg bisect -b 1 # -> update to rev 6
352 $ hg bisect -b 1 # -> update to rev 6
353 Testing changeset 6:a214d5d3811a "merge 4,5" (13 changesets remaining, ~3 tests)
353 Testing changeset 6:a214d5d3811a "merge 4,5" (13 changesets remaining, ~3 tests)
354 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
354 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
355 $ hg bisect -s # -> update to rev 10
355 $ hg bisect -s # -> update to rev 10
356 Testing changeset 10:429fcd26f52d "merge 6,9" (13 changesets remaining, ~3 tests)
356 Testing changeset 10:429fcd26f52d "merge 6,9" (13 changesets remaining, ~3 tests)
357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 $ hg log -q -r 'bisect(pruned)'
358 $ hg log -q -r 'bisect(pruned)'
359 0:33b1f9bc8bc5
359 0:33b1f9bc8bc5
360 1:4ca5088da217
360 1:4ca5088da217
361 6:a214d5d3811a
361 6:a214d5d3811a
362 18:d42e18c7bc9b
362 18:d42e18c7bc9b
363 $ hg bisect -b # -> update to rev 12
363 $ hg bisect -b # -> update to rev 12
364 Testing changeset 12:9f259202bbe7 "12" (5 changesets remaining, ~2 tests)
364 Testing changeset 12:9f259202bbe7 "12" (5 changesets remaining, ~2 tests)
365 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
365 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
366 $ hg log -q -r 'bisect(pruned)'
366 $ hg log -q -r 'bisect(pruned)'
367 0:33b1f9bc8bc5
367 0:33b1f9bc8bc5
368 1:4ca5088da217
368 1:4ca5088da217
369 2:051e12f87bf1
369 2:051e12f87bf1
370 3:0950834f0a9c
370 3:0950834f0a9c
371 4:5c668c22234f
371 4:5c668c22234f
372 5:385a529b6670
372 5:385a529b6670
373 6:a214d5d3811a
373 6:a214d5d3811a
374 8:dab8161ac8fc
374 8:dab8161ac8fc
375 9:3c77083deb4a
375 9:3c77083deb4a
376 10:429fcd26f52d
376 10:429fcd26f52d
377 18:d42e18c7bc9b
377 18:d42e18c7bc9b
378 $ hg log -q -r 'bisect(untested)'
378 $ hg log -q -r 'bisect(untested)'
379 11:82ca6f06eccd
379 11:82ca6f06eccd
380 12:9f259202bbe7
380 12:9f259202bbe7
381 13:b0a32c86eb31
381 13:b0a32c86eb31
382 15:857b178a7cf3
382 15:857b178a7cf3
383 $ hg bisect -b # -> update to rev 13
383 $ hg bisect -b # -> update to rev 13
384 Testing changeset 13:b0a32c86eb31 "13" (3 changesets remaining, ~1 tests)
384 Testing changeset 13:b0a32c86eb31 "13" (3 changesets remaining, ~1 tests)
385 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
385 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
386 $ hg bisect -g
386 $ hg bisect -g
387 The first good revision is:
387 The first good revision is:
388 changeset: 13:b0a32c86eb31
388 changeset: 13:b0a32c86eb31
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:13 1970 +0000
390 date: Thu Jan 01 00:00:13 1970 +0000
391 summary: 13
391 summary: 13
392
392
393 $ hg log -q -r 'bisect(range)'
393 $ hg log -q -r 'bisect(range)'
394 1:4ca5088da217
394 1:4ca5088da217
395 2:051e12f87bf1
395 2:051e12f87bf1
396 3:0950834f0a9c
396 3:0950834f0a9c
397 4:5c668c22234f
397 4:5c668c22234f
398 5:385a529b6670
398 5:385a529b6670
399 6:a214d5d3811a
399 6:a214d5d3811a
400 8:dab8161ac8fc
400 8:dab8161ac8fc
401 9:3c77083deb4a
401 9:3c77083deb4a
402 10:429fcd26f52d
402 10:429fcd26f52d
403 11:82ca6f06eccd
403 11:82ca6f06eccd
404 12:9f259202bbe7
404 12:9f259202bbe7
405 13:b0a32c86eb31
405 13:b0a32c86eb31
406 15:857b178a7cf3
406 15:857b178a7cf3
407 18:d42e18c7bc9b
407 18:d42e18c7bc9b
408
408
409 complex bisect test 3
409 complex bisect test 3
410
410
411 first bad rev is 15
411 first bad rev is 15
412 10,9,13 are skipped an might be the first bad revisions as well
412 10,9,13 are skipped an might be the first bad revisions as well
413
413
414 $ hg bisect -r
414 $ hg bisect -r
415 $ hg bisect -g 1
415 $ hg bisect -g 1
416 $ hg bisect -b 16 # -> update to rev 6
416 $ hg bisect -b 16 # -> update to rev 6
417 Testing changeset 6:a214d5d3811a "merge 4,5" (13 changesets remaining, ~3 tests)
417 Testing changeset 6:a214d5d3811a "merge 4,5" (13 changesets remaining, ~3 tests)
418 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
418 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
419 $ hg log -q -r 'bisect(pruned)'
419 $ hg log -q -r 'bisect(pruned)'
420 0:33b1f9bc8bc5
420 0:33b1f9bc8bc5
421 1:4ca5088da217
421 1:4ca5088da217
422 16:609d82a7ebae
422 16:609d82a7ebae
423 17:228c06deef46
423 17:228c06deef46
424 $ hg bisect -g # -> update to rev 13
424 $ hg bisect -g # -> update to rev 13
425 Testing changeset 13:b0a32c86eb31 "13" (8 changesets remaining, ~3 tests)
425 Testing changeset 13:b0a32c86eb31 "13" (8 changesets remaining, ~3 tests)
426 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
426 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
427 $ hg bisect -s # -> update to rev 10
427 $ hg bisect -s # -> update to rev 10
428 Testing changeset 10:429fcd26f52d "merge 6,9" (8 changesets remaining, ~3 tests)
428 Testing changeset 10:429fcd26f52d "merge 6,9" (8 changesets remaining, ~3 tests)
429 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 $ hg bisect -s # -> update to rev 12
430 $ hg bisect -s # -> update to rev 12
431 Testing changeset 12:9f259202bbe7 "12" (8 changesets remaining, ~3 tests)
431 Testing changeset 12:9f259202bbe7 "12" (8 changesets remaining, ~3 tests)
432 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
432 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
433 $ hg log -q -r 'bisect(pruned)'
433 $ hg log -q -r 'bisect(pruned)'
434 0:33b1f9bc8bc5
434 0:33b1f9bc8bc5
435 1:4ca5088da217
435 1:4ca5088da217
436 2:051e12f87bf1
436 2:051e12f87bf1
437 3:0950834f0a9c
437 3:0950834f0a9c
438 4:5c668c22234f
438 4:5c668c22234f
439 5:385a529b6670
439 5:385a529b6670
440 6:a214d5d3811a
440 6:a214d5d3811a
441 10:429fcd26f52d
441 10:429fcd26f52d
442 13:b0a32c86eb31
442 13:b0a32c86eb31
443 16:609d82a7ebae
443 16:609d82a7ebae
444 17:228c06deef46
444 17:228c06deef46
445 $ hg bisect -g # -> update to rev 9
445 $ hg bisect -g # -> update to rev 9
446 Testing changeset 9:3c77083deb4a "9" (5 changesets remaining, ~2 tests)
446 Testing changeset 9:3c77083deb4a "9" (5 changesets remaining, ~2 tests)
447 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
448 $ hg bisect -s # -> update to rev 15
448 $ hg bisect -s # -> update to rev 15
449 Testing changeset 15:857b178a7cf3 "merge 10,13" (5 changesets remaining, ~2 tests)
449 Testing changeset 15:857b178a7cf3 "merge 10,13" (5 changesets remaining, ~2 tests)
450 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 $ hg log -q -r 'bisect(ignored)'
451 $ hg log -q -r 'bisect(ignored)'
452 $ hg bisect -b
452 $ hg bisect -b
453 Due to skipped revisions, the first bad revision could be any of:
453 Due to skipped revisions, the first bad revision could be any of:
454 changeset: 9:3c77083deb4a
454 changeset: 9:3c77083deb4a
455 user: test
455 user: test
456 date: Thu Jan 01 00:00:09 1970 +0000
456 date: Thu Jan 01 00:00:09 1970 +0000
457 summary: 9
457 summary: 9
458
458
459 changeset: 10:429fcd26f52d
459 changeset: 10:429fcd26f52d
460 parent: 9:3c77083deb4a
460 parent: 9:3c77083deb4a
461 parent: 6:a214d5d3811a
461 parent: 6:a214d5d3811a
462 user: test
462 user: test
463 date: Thu Jan 01 00:00:10 1970 +0000
463 date: Thu Jan 01 00:00:10 1970 +0000
464 summary: merge 6,9
464 summary: merge 6,9
465
465
466 changeset: 13:b0a32c86eb31
466 changeset: 13:b0a32c86eb31
467 user: test
467 user: test
468 date: Thu Jan 01 00:00:13 1970 +0000
468 date: Thu Jan 01 00:00:13 1970 +0000
469 summary: 13
469 summary: 13
470
470
471 changeset: 15:857b178a7cf3
471 changeset: 15:857b178a7cf3
472 parent: 13:b0a32c86eb31
472 parent: 13:b0a32c86eb31
473 parent: 10:429fcd26f52d
473 parent: 10:429fcd26f52d
474 user: test
474 user: test
475 date: Thu Jan 01 00:00:15 1970 +0000
475 date: Thu Jan 01 00:00:15 1970 +0000
476 summary: merge 10,13
476 summary: merge 10,13
477
477
478 $ hg log -q -r 'bisect(range)'
478 $ hg log -q -r 'bisect(range)'
479 1:4ca5088da217
479 1:4ca5088da217
480 2:051e12f87bf1
480 2:051e12f87bf1
481 3:0950834f0a9c
481 3:0950834f0a9c
482 4:5c668c22234f
482 4:5c668c22234f
483 5:385a529b6670
483 5:385a529b6670
484 6:a214d5d3811a
484 6:a214d5d3811a
485 8:dab8161ac8fc
485 8:dab8161ac8fc
486 9:3c77083deb4a
486 9:3c77083deb4a
487 10:429fcd26f52d
487 10:429fcd26f52d
488 11:82ca6f06eccd
488 11:82ca6f06eccd
489 12:9f259202bbe7
489 12:9f259202bbe7
490 13:b0a32c86eb31
490 13:b0a32c86eb31
491 15:857b178a7cf3
491 15:857b178a7cf3
492 16:609d82a7ebae
492 16:609d82a7ebae
493 $ hg log -q -r 'bisect(ignored)'
493 $ hg log -q -r 'bisect(ignored)'
494
494
495 complex bisect test 4
495 complex bisect test 4
496
496
497 first good revision is 17
497 first good revision is 17
498 15,16 are skipped an might be the first good revisions as well
498 15,16 are skipped an might be the first good revisions as well
499
499
500 $ hg bisect -r
500 $ hg bisect -r
501 $ hg bisect -g 17
501 $ hg bisect -g 17
502 $ hg bisect -b 8 # -> update to rev 10
502 $ hg bisect -b 8 # -> update to rev 10
503 Testing changeset 13:b0a32c86eb31 "13" (8 changesets remaining, ~3 tests)
503 Testing changeset 13:b0a32c86eb31 "13" (8 changesets remaining, ~3 tests)
504 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
504 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
505 $ hg bisect -b # -> update to rev 13
505 $ hg bisect -b # -> update to rev 13
506 Testing changeset 10:429fcd26f52d "merge 6,9" (5 changesets remaining, ~2 tests)
506 Testing changeset 10:429fcd26f52d "merge 6,9" (5 changesets remaining, ~2 tests)
507 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
507 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
508 $ hg bisect -b # -> update to rev 15
508 $ hg bisect -b # -> update to rev 15
509 Testing changeset 15:857b178a7cf3 "merge 10,13" (3 changesets remaining, ~1 tests)
509 Testing changeset 15:857b178a7cf3 "merge 10,13" (3 changesets remaining, ~1 tests)
510 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 $ hg log -q -r 'bisect(pruned)'
511 $ hg log -q -r 'bisect(pruned)'
512 0:33b1f9bc8bc5
512 0:33b1f9bc8bc5
513 1:4ca5088da217
513 1:4ca5088da217
514 2:051e12f87bf1
514 2:051e12f87bf1
515 3:0950834f0a9c
515 3:0950834f0a9c
516 4:5c668c22234f
516 4:5c668c22234f
517 5:385a529b6670
517 5:385a529b6670
518 6:a214d5d3811a
518 6:a214d5d3811a
519 8:dab8161ac8fc
519 8:dab8161ac8fc
520 9:3c77083deb4a
520 9:3c77083deb4a
521 10:429fcd26f52d
521 10:429fcd26f52d
522 11:82ca6f06eccd
522 11:82ca6f06eccd
523 12:9f259202bbe7
523 12:9f259202bbe7
524 13:b0a32c86eb31
524 13:b0a32c86eb31
525 17:228c06deef46
525 17:228c06deef46
526 $ hg bisect -s # -> update to rev 16
526 $ hg bisect -s # -> update to rev 16
527 Testing changeset 16:609d82a7ebae "16" (3 changesets remaining, ~1 tests)
527 Testing changeset 16:609d82a7ebae "16" (3 changesets remaining, ~1 tests)
528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
529 $ hg log -q -r 'bisect(pruned)'
529 $ hg log -q -r 'bisect(pruned)'
530 0:33b1f9bc8bc5
530 0:33b1f9bc8bc5
531 1:4ca5088da217
531 1:4ca5088da217
532 2:051e12f87bf1
532 2:051e12f87bf1
533 3:0950834f0a9c
533 3:0950834f0a9c
534 4:5c668c22234f
534 4:5c668c22234f
535 5:385a529b6670
535 5:385a529b6670
536 6:a214d5d3811a
536 6:a214d5d3811a
537 8:dab8161ac8fc
537 8:dab8161ac8fc
538 9:3c77083deb4a
538 9:3c77083deb4a
539 10:429fcd26f52d
539 10:429fcd26f52d
540 11:82ca6f06eccd
540 11:82ca6f06eccd
541 12:9f259202bbe7
541 12:9f259202bbe7
542 13:b0a32c86eb31
542 13:b0a32c86eb31
543 15:857b178a7cf3
543 15:857b178a7cf3
544 17:228c06deef46
544 17:228c06deef46
545 $ hg bisect -s
545 $ hg bisect -s
546 Due to skipped revisions, the first good revision could be any of:
546 Due to skipped revisions, the first good revision could be any of:
547 changeset: 15:857b178a7cf3
547 changeset: 15:857b178a7cf3
548 parent: 13:b0a32c86eb31
548 parent: 13:b0a32c86eb31
549 parent: 10:429fcd26f52d
549 parent: 10:429fcd26f52d
550 user: test
550 user: test
551 date: Thu Jan 01 00:00:15 1970 +0000
551 date: Thu Jan 01 00:00:15 1970 +0000
552 summary: merge 10,13
552 summary: merge 10,13
553
553
554 changeset: 16:609d82a7ebae
554 changeset: 16:609d82a7ebae
555 user: test
555 user: test
556 date: Thu Jan 01 00:00:16 1970 +0000
556 date: Thu Jan 01 00:00:16 1970 +0000
557 summary: 16
557 summary: 16
558
558
559 changeset: 17:228c06deef46
559 changeset: 17:228c06deef46
560 user: test
560 user: test
561 date: Thu Jan 01 00:00:17 1970 +0000
561 date: Thu Jan 01 00:00:17 1970 +0000
562 summary: 17
562 summary: 17
563
563
564 $ hg log -q -r 'bisect(range)'
564 $ hg log -q -r 'bisect(range)'
565 8:dab8161ac8fc
565 8:dab8161ac8fc
566 9:3c77083deb4a
566 9:3c77083deb4a
567 10:429fcd26f52d
567 10:429fcd26f52d
568 11:82ca6f06eccd
568 11:82ca6f06eccd
569 12:9f259202bbe7
569 12:9f259202bbe7
570 13:b0a32c86eb31
570 13:b0a32c86eb31
571 15:857b178a7cf3
571 15:857b178a7cf3
572 16:609d82a7ebae
572 16:609d82a7ebae
573 17:228c06deef46
573 17:228c06deef46
574 $ hg log -q -r 'bisect(pruned)'
574 $ hg log -q -r 'bisect(pruned)'
575 0:33b1f9bc8bc5
575 0:33b1f9bc8bc5
576 1:4ca5088da217
576 1:4ca5088da217
577 2:051e12f87bf1
577 2:051e12f87bf1
578 3:0950834f0a9c
578 3:0950834f0a9c
579 4:5c668c22234f
579 4:5c668c22234f
580 5:385a529b6670
580 5:385a529b6670
581 6:a214d5d3811a
581 6:a214d5d3811a
582 8:dab8161ac8fc
582 8:dab8161ac8fc
583 9:3c77083deb4a
583 9:3c77083deb4a
584 10:429fcd26f52d
584 10:429fcd26f52d
585 11:82ca6f06eccd
585 11:82ca6f06eccd
586 12:9f259202bbe7
586 12:9f259202bbe7
587 13:b0a32c86eb31
587 13:b0a32c86eb31
588 15:857b178a7cf3
588 15:857b178a7cf3
589 16:609d82a7ebae
589 16:609d82a7ebae
590 17:228c06deef46
590 17:228c06deef46
591
591
592 test unrelated revs:
592 test unrelated revs:
593
593
594 $ hg bisect --reset
594 $ hg bisect --reset
595 $ hg bisect -b 7
595 $ hg bisect -b 7
596 $ hg bisect -g 14
596 $ hg bisect -g 14
597 abort: starting revisions are not directly related
597 abort: starting revisions are not directly related
598 [255]
598 [255]
599 $ hg log -q -r 'bisect(range)'
599 $ hg log -q -r 'bisect(range)'
600 $ hg log -q -r 'bisect(pruned)'
600 $ hg log -q -r 'bisect(pruned)'
601 0:33b1f9bc8bc5
601 0:33b1f9bc8bc5
602 1:4ca5088da217
602 1:4ca5088da217
603 2:051e12f87bf1
603 2:051e12f87bf1
604 3:0950834f0a9c
604 3:0950834f0a9c
605 4:5c668c22234f
605 4:5c668c22234f
606 7:50c76098bbf2
606 7:50c76098bbf2
607 14:faa450606157
607 14:faa450606157
608 $ hg bisect --reset
608 $ hg bisect --reset
609
609
610 end at merge: 17 bad, 11 good (but 9 is first bad)
610 end at merge: 17 bad, 11 good (but 9 is first bad)
611
611
612 $ hg bisect -r
612 $ hg bisect -r
613 $ hg bisect -b 17
613 $ hg bisect -b 17
614 $ hg bisect -g 11
614 $ hg bisect -g 11
615 Testing changeset 13:b0a32c86eb31 "13" (5 changesets remaining, ~2 tests)
615 Testing changeset 13:b0a32c86eb31 "13" (5 changesets remaining, ~2 tests)
616 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
616 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
617 $ hg log -q -r 'bisect(ignored)'
617 $ hg log -q -r 'bisect(ignored)'
618 2:051e12f87bf1
618 2:051e12f87bf1
619 3:0950834f0a9c
619 3:0950834f0a9c
620 4:5c668c22234f
620 4:5c668c22234f
621 5:385a529b6670
621 5:385a529b6670
622 6:a214d5d3811a
622 6:a214d5d3811a
623 9:3c77083deb4a
623 9:3c77083deb4a
624 10:429fcd26f52d
624 10:429fcd26f52d
625 $ hg bisect -g
625 $ hg bisect -g
626 Testing changeset 15:857b178a7cf3 "merge 10,13" (3 changesets remaining, ~1 tests)
626 Testing changeset 15:857b178a7cf3 "merge 10,13" (3 changesets remaining, ~1 tests)
627 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
627 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
628 $ hg bisect -b
628 $ hg bisect -b
629 The first bad revision is:
629 The first bad revision is:
630 changeset: 15:857b178a7cf3
630 changeset: 15:857b178a7cf3
631 parent: 13:b0a32c86eb31
631 parent: 13:b0a32c86eb31
632 parent: 10:429fcd26f52d
632 parent: 10:429fcd26f52d
633 user: test
633 user: test
634 date: Thu Jan 01 00:00:15 1970 +0000
634 date: Thu Jan 01 00:00:15 1970 +0000
635 summary: merge 10,13
635 summary: merge 10,13
636
636
637 Not all ancestors of this changeset have been checked.
637 Not all ancestors of this changeset have been checked.
638 Use bisect --extend to continue the bisection from
638 Use bisect --extend to continue the bisection from
639 the common ancestor, dab8161ac8fc.
639 the common ancestor, dab8161ac8fc.
640 $ hg log -q -r 'bisect(range)'
640 $ hg log -q -r 'bisect(range)'
641 11:82ca6f06eccd
641 11:82ca6f06eccd
642 12:9f259202bbe7
642 12:9f259202bbe7
643 13:b0a32c86eb31
643 13:b0a32c86eb31
644 15:857b178a7cf3
644 15:857b178a7cf3
645 16:609d82a7ebae
645 16:609d82a7ebae
646 17:228c06deef46
646 17:228c06deef46
647 $ hg log -q -r 'bisect(pruned)'
647 $ hg log -q -r 'bisect(pruned)'
648 0:33b1f9bc8bc5
648 0:33b1f9bc8bc5
649 1:4ca5088da217
649 1:4ca5088da217
650 8:dab8161ac8fc
650 8:dab8161ac8fc
651 11:82ca6f06eccd
651 11:82ca6f06eccd
652 12:9f259202bbe7
652 12:9f259202bbe7
653 13:b0a32c86eb31
653 13:b0a32c86eb31
654 15:857b178a7cf3
654 15:857b178a7cf3
655 16:609d82a7ebae
655 16:609d82a7ebae
656 17:228c06deef46
656 17:228c06deef46
657 18:d42e18c7bc9b
657 18:d42e18c7bc9b
658 $ hg log -q -r 'bisect(untested)'
658 $ hg log -q -r 'bisect(untested)'
659 $ hg log -q -r 'bisect(ignored)'
659 $ hg log -q -r 'bisect(ignored)'
660 2:051e12f87bf1
660 2:051e12f87bf1
661 3:0950834f0a9c
661 3:0950834f0a9c
662 4:5c668c22234f
662 4:5c668c22234f
663 5:385a529b6670
663 5:385a529b6670
664 6:a214d5d3811a
664 6:a214d5d3811a
665 9:3c77083deb4a
665 9:3c77083deb4a
666 10:429fcd26f52d
666 10:429fcd26f52d
667 $ hg bisect --extend
667 $ hg bisect --extend
668 Extending search to changeset 8:dab8161ac8fc "8"
668 Extending search to changeset 8:dab8161ac8fc "8"
669 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
669 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
670 $ hg log -q -r 'bisect(untested)'
670 $ hg log -q -r 'bisect(untested)'
671 $ hg log -q -r 'bisect(ignored)'
671 $ hg log -q -r 'bisect(ignored)'
672 2:051e12f87bf1
672 2:051e12f87bf1
673 3:0950834f0a9c
673 3:0950834f0a9c
674 4:5c668c22234f
674 4:5c668c22234f
675 5:385a529b6670
675 5:385a529b6670
676 6:a214d5d3811a
676 6:a214d5d3811a
677 9:3c77083deb4a
677 9:3c77083deb4a
678 10:429fcd26f52d
678 10:429fcd26f52d
679 $ hg bisect -g # dab8161ac8fc
679 $ hg bisect -g # dab8161ac8fc
680 Testing changeset 9:3c77083deb4a "9" (3 changesets remaining, ~1 tests)
680 Testing changeset 9:3c77083deb4a "9" (3 changesets remaining, ~1 tests)
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
682 $ hg log -q -r 'bisect(untested)'
682 $ hg log -q -r 'bisect(untested)'
683 9:3c77083deb4a
683 9:3c77083deb4a
684 10:429fcd26f52d
684 10:429fcd26f52d
685 $ hg log -q -r 'bisect(ignored)'
685 $ hg log -q -r 'bisect(ignored)'
686 2:051e12f87bf1
686 2:051e12f87bf1
687 3:0950834f0a9c
687 3:0950834f0a9c
688 4:5c668c22234f
688 4:5c668c22234f
689 5:385a529b6670
689 5:385a529b6670
690 6:a214d5d3811a
690 6:a214d5d3811a
691 $ hg log -q -r 'bisect(goods)'
691 $ hg log -q -r 'bisect(goods)'
692 0:33b1f9bc8bc5
692 0:33b1f9bc8bc5
693 1:4ca5088da217
693 1:4ca5088da217
694 8:dab8161ac8fc
694 8:dab8161ac8fc
695 11:82ca6f06eccd
695 11:82ca6f06eccd
696 12:9f259202bbe7
696 12:9f259202bbe7
697 13:b0a32c86eb31
697 13:b0a32c86eb31
698 $ hg log -q -r 'bisect(bads)'
698 $ hg log -q -r 'bisect(bads)'
699 15:857b178a7cf3
699 15:857b178a7cf3
700 16:609d82a7ebae
700 16:609d82a7ebae
701 17:228c06deef46
701 17:228c06deef46
702 18:d42e18c7bc9b
702 18:d42e18c7bc9b
703 $ hg bisect -b
703 $ hg bisect -b
704 The first bad revision is:
704 The first bad revision is:
705 changeset: 9:3c77083deb4a
705 changeset: 9:3c77083deb4a
706 user: test
706 user: test
707 date: Thu Jan 01 00:00:09 1970 +0000
707 date: Thu Jan 01 00:00:09 1970 +0000
708 summary: 9
708 summary: 9
709
709
710 $ hg log -q -r 'bisect(range)'
710 $ hg log -q -r 'bisect(range)'
711 8:dab8161ac8fc
711 8:dab8161ac8fc
712 9:3c77083deb4a
712 9:3c77083deb4a
713 10:429fcd26f52d
713 10:429fcd26f52d
714 11:82ca6f06eccd
714 11:82ca6f06eccd
715 12:9f259202bbe7
715 12:9f259202bbe7
716 13:b0a32c86eb31
716 13:b0a32c86eb31
717 15:857b178a7cf3
717 15:857b178a7cf3
718 16:609d82a7ebae
718 16:609d82a7ebae
719 17:228c06deef46
719 17:228c06deef46
720 $ hg log -q -r 'bisect(pruned)'
720 $ hg log -q -r 'bisect(pruned)'
721 0:33b1f9bc8bc5
721 0:33b1f9bc8bc5
722 1:4ca5088da217
722 1:4ca5088da217
723 8:dab8161ac8fc
723 8:dab8161ac8fc
724 9:3c77083deb4a
724 9:3c77083deb4a
725 10:429fcd26f52d
725 10:429fcd26f52d
726 11:82ca6f06eccd
726 11:82ca6f06eccd
727 12:9f259202bbe7
727 12:9f259202bbe7
728 13:b0a32c86eb31
728 13:b0a32c86eb31
729 15:857b178a7cf3
729 15:857b178a7cf3
730 16:609d82a7ebae
730 16:609d82a7ebae
731 17:228c06deef46
731 17:228c06deef46
732 18:d42e18c7bc9b
732 18:d42e18c7bc9b
733 $ hg log -q -r 'bisect(untested)'
733 $ hg log -q -r 'bisect(untested)'
734 $ hg log -q -r 'bisect(ignored)'
734 $ hg log -q -r 'bisect(ignored)'
735 2:051e12f87bf1
735 2:051e12f87bf1
736 3:0950834f0a9c
736 3:0950834f0a9c
737 4:5c668c22234f
737 4:5c668c22234f
738 5:385a529b6670
738 5:385a529b6670
739 6:a214d5d3811a
739 6:a214d5d3811a
740 $ hg log -q -r 'bisect(goods)'
740 $ hg log -q -r 'bisect(goods)'
741 0:33b1f9bc8bc5
741 0:33b1f9bc8bc5
742 1:4ca5088da217
742 1:4ca5088da217
743 8:dab8161ac8fc
743 8:dab8161ac8fc
744 11:82ca6f06eccd
744 11:82ca6f06eccd
745 12:9f259202bbe7
745 12:9f259202bbe7
746 13:b0a32c86eb31
746 13:b0a32c86eb31
747 $ hg log -q -r 'bisect(bads)'
747 $ hg log -q -r 'bisect(bads)'
748 9:3c77083deb4a
748 9:3c77083deb4a
749 10:429fcd26f52d
749 10:429fcd26f52d
750 15:857b178a7cf3
750 15:857b178a7cf3
751 16:609d82a7ebae
751 16:609d82a7ebae
752 17:228c06deef46
752 17:228c06deef46
753 18:d42e18c7bc9b
753 18:d42e18c7bc9b
754
754
755 user adds irrelevant but consistent information (here: -g 2) to bisect state
755 user adds irrelevant but consistent information (here: -g 2) to bisect state
756
756
757 $ hg bisect -r
757 $ hg bisect -r
758 $ hg bisect -b 13
758 $ hg bisect -b 13
759 $ hg bisect -g 8
759 $ hg bisect -g 8
760 Testing changeset 11:82ca6f06eccd "11" (3 changesets remaining, ~1 tests)
760 Testing changeset 11:82ca6f06eccd "11" (3 changesets remaining, ~1 tests)
761 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
761 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 $ hg log -q -r 'bisect(untested)'
762 $ hg log -q -r 'bisect(untested)'
763 11:82ca6f06eccd
763 11:82ca6f06eccd
764 12:9f259202bbe7
764 12:9f259202bbe7
765 $ hg bisect -g 2
765 $ hg bisect -g 2
766 Testing changeset 11:82ca6f06eccd "11" (3 changesets remaining, ~1 tests)
766 Testing changeset 11:82ca6f06eccd "11" (3 changesets remaining, ~1 tests)
767 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
767 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
768 $ hg log -q -r 'bisect(untested)'
768 $ hg log -q -r 'bisect(untested)'
769 11:82ca6f06eccd
769 11:82ca6f06eccd
770 12:9f259202bbe7
770 12:9f259202bbe7
771 $ hg bisect -b
771 $ hg bisect -b
772 The first bad revision is:
772 The first bad revision is:
773 changeset: 11:82ca6f06eccd
773 changeset: 11:82ca6f06eccd
774 parent: 8:dab8161ac8fc
774 parent: 8:dab8161ac8fc
775 user: test
775 user: test
776 date: Thu Jan 01 00:00:11 1970 +0000
776 date: Thu Jan 01 00:00:11 1970 +0000
777 summary: 11
777 summary: 11
778
778
779 $ hg log -q -r 'bisect(range)'
779 $ hg log -q -r 'bisect(range)'
780 8:dab8161ac8fc
780 8:dab8161ac8fc
781 11:82ca6f06eccd
781 11:82ca6f06eccd
782 12:9f259202bbe7
782 12:9f259202bbe7
783 13:b0a32c86eb31
783 13:b0a32c86eb31
784 $ hg log -q -r 'bisect(pruned)'
784 $ hg log -q -r 'bisect(pruned)'
785 0:33b1f9bc8bc5
785 0:33b1f9bc8bc5
786 1:4ca5088da217
786 1:4ca5088da217
787 2:051e12f87bf1
788 8:dab8161ac8fc
787 8:dab8161ac8fc
789 11:82ca6f06eccd
788 11:82ca6f06eccd
790 12:9f259202bbe7
789 12:9f259202bbe7
791 13:b0a32c86eb31
790 13:b0a32c86eb31
792 14:faa450606157
791 14:faa450606157
793 15:857b178a7cf3
792 15:857b178a7cf3
794 16:609d82a7ebae
793 16:609d82a7ebae
795 17:228c06deef46
794 17:228c06deef46
796 18:d42e18c7bc9b
795 18:d42e18c7bc9b
797 $ hg log -q -r 'bisect(untested)'
796 $ hg log -q -r 'bisect(untested)'
General Comments 0
You need to be logged in to leave comments. Login now