##// END OF EJS Templates
help: update command synopsis to clarify "cp --forget" only takes destinations...
Yuya Nishihara -
r46378:4db5671d default
parent child Browse files
Show More
@@ -1,7666 +1,7666 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 bundlecaches,
29 bundlecaches,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 grep as grepmod,
44 grep as grepmod,
45 hbisect,
45 hbisect,
46 help,
46 help,
47 hg,
47 hg,
48 logcmdutil,
48 logcmdutil,
49 merge as mergemod,
49 merge as mergemod,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 narrowspec,
51 narrowspec,
52 obsolete,
52 obsolete,
53 obsutil,
53 obsutil,
54 patch,
54 patch,
55 phases,
55 phases,
56 pycompat,
56 pycompat,
57 rcutil,
57 rcutil,
58 registrar,
58 registrar,
59 requirements,
59 requirements,
60 revsetlang,
60 revsetlang,
61 rewriteutil,
61 rewriteutil,
62 scmutil,
62 scmutil,
63 server,
63 server,
64 shelve as shelvemod,
64 shelve as shelvemod,
65 state as statemod,
65 state as statemod,
66 streamclone,
66 streamclone,
67 tags as tagsmod,
67 tags as tagsmod,
68 ui as uimod,
68 ui as uimod,
69 util,
69 util,
70 verify as verifymod,
70 verify as verifymod,
71 vfs as vfsmod,
71 vfs as vfsmod,
72 wireprotoserver,
72 wireprotoserver,
73 )
73 )
74 from .utils import (
74 from .utils import (
75 dateutil,
75 dateutil,
76 stringutil,
76 stringutil,
77 )
77 )
78
78
79 table = {}
79 table = {}
80 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
81
81
82 command = registrar.command(table)
82 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
83 INTENT_READONLY = registrar.INTENT_READONLY
84
84
85 # common command options
85 # common command options
86
86
87 globalopts = [
87 globalopts = [
88 (
88 (
89 b'R',
89 b'R',
90 b'repository',
90 b'repository',
91 b'',
91 b'',
92 _(b'repository root directory or name of overlay bundle file'),
92 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
93 _(b'REPO'),
94 ),
94 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
96 (
97 b'y',
97 b'y',
98 b'noninteractive',
98 b'noninteractive',
99 None,
99 None,
100 _(
100 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
101 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
102 ),
103 ),
103 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
106 (
107 b'',
107 b'',
108 b'color',
108 b'color',
109 b'',
109 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
111 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
113 _(b'TYPE'),
114 ),
114 ),
115 (
115 (
116 b'',
116 b'',
117 b'config',
117 b'config',
118 [],
118 [],
119 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
120 _(b'CONFIG'),
121 ),
121 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
123 (b'', b'debugger', None, _(b'start debugger')),
124 (
124 (
125 b'',
125 b'',
126 b'encoding',
126 b'encoding',
127 encoding.encoding,
127 encoding.encoding,
128 _(b'set the charset encoding'),
128 _(b'set the charset encoding'),
129 _(b'ENCODE'),
129 _(b'ENCODE'),
130 ),
130 ),
131 (
131 (
132 b'',
132 b'',
133 b'encodingmode',
133 b'encodingmode',
134 encoding.encodingmode,
134 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
135 _(b'set the charset encoding mode'),
136 _(b'MODE'),
136 _(b'MODE'),
137 ),
137 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
141 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
144 (
145 b'',
145 b'',
146 b'pager',
146 b'pager',
147 b'auto',
147 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
149 _(b'TYPE'),
150 ),
150 ),
151 ]
151 ]
152
152
153 dryrunopts = cmdutil.dryrunopts
153 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
154 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
155 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
156 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
157 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
158 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
159 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
160 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
161 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
162 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
163 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
164 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
165 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
166 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
167 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
168 debugrevlogopts = cmdutil.debugrevlogopts
169
169
170 # Commands start here, listed alphabetically
170 # Commands start here, listed alphabetically
171
171
172
172
173 @command(
173 @command(
174 b'abort',
174 b'abort',
175 dryrunopts,
175 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
177 helpbasic=True,
178 )
178 )
179 def abort(ui, repo, **opts):
179 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
180 """abort an unfinished operation (EXPERIMENTAL)
181
181
182 Aborts a multistep operation like graft, histedit, rebase, merge,
182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
183 and unshelve if they are in an unfinished state.
184
184
185 use --dry-run/-n to dry run the command.
185 use --dry-run/-n to dry run the command.
186 """
186 """
187 dryrun = opts.get('dry_run')
187 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
188 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
189 if not abortstate:
190 raise error.Abort(_(b'no operation in progress'))
190 raise error.Abort(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
191 if not abortstate.abortfunc:
192 raise error.Abort(
192 raise error.Abort(
193 (
193 (
194 _(b"%s in progress but does not support 'hg abort'")
194 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
195 % (abortstate._opname)
196 ),
196 ),
197 hint=abortstate.hint(),
197 hint=abortstate.hint(),
198 )
198 )
199 if dryrun:
199 if dryrun:
200 ui.status(
200 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
202 )
203 return
203 return
204 return abortstate.abortfunc(ui, repo)
204 return abortstate.abortfunc(ui, repo)
205
205
206
206
207 @command(
207 @command(
208 b'add',
208 b'add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
210 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
212 helpbasic=True,
213 inferrepo=True,
213 inferrepo=True,
214 )
214 )
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 relative = scmutil.anypats(pats, opts)
337 relative = scmutil.anypats(pats, opts)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340
340
341
341
342 @command(
342 @command(
343 b'annotate|blame',
343 b'annotate|blame',
344 [
344 [
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (
346 (
347 b'',
347 b'',
348 b'follow',
348 b'follow',
349 None,
349 None,
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 ),
351 ),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'f', b'file', None, _(b'list the filename')),
355 (b'f', b'file', None, _(b'list the filename')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
359 (
359 (
360 b'l',
360 b'l',
361 b'line-number',
361 b'line-number',
362 None,
362 None,
363 _(b'show line number at the first appearance'),
363 _(b'show line number at the first appearance'),
364 ),
364 ),
365 (
365 (
366 b'',
366 b'',
367 b'skip',
367 b'skip',
368 [],
368 [],
369 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'REV'),
370 _(b'REV'),
371 ),
371 ),
372 ]
372 ]
373 + diffwsopts
373 + diffwsopts
374 + walkopts
374 + walkopts
375 + formatteropts,
375 + formatteropts,
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpbasic=True,
378 helpbasic=True,
379 inferrepo=True,
379 inferrepo=True,
380 )
380 )
381 def annotate(ui, repo, *pats, **opts):
381 def annotate(ui, repo, *pats, **opts):
382 """show changeset information by line for each file
382 """show changeset information by line for each file
383
383
384 List changes in files, showing the revision id responsible for
384 List changes in files, showing the revision id responsible for
385 each line.
385 each line.
386
386
387 This command is useful for discovering when a change was made and
387 This command is useful for discovering when a change was made and
388 by whom.
388 by whom.
389
389
390 If you include --file, --user, or --date, the revision number is
390 If you include --file, --user, or --date, the revision number is
391 suppressed unless you also include --number.
391 suppressed unless you also include --number.
392
392
393 Without the -a/--text option, annotate will avoid processing files
393 Without the -a/--text option, annotate will avoid processing files
394 it detects as binary. With -a, annotate will annotate the file
394 it detects as binary. With -a, annotate will annotate the file
395 anyway, although the results will probably be neither useful
395 anyway, although the results will probably be neither useful
396 nor desirable.
396 nor desirable.
397
397
398 .. container:: verbose
398 .. container:: verbose
399
399
400 Template:
400 Template:
401
401
402 The following keywords are supported in addition to the common template
402 The following keywords are supported in addition to the common template
403 keywords and functions. See also :hg:`help templates`.
403 keywords and functions. See also :hg:`help templates`.
404
404
405 :lines: List of lines with annotation data.
405 :lines: List of lines with annotation data.
406 :path: String. Repository-absolute path of the specified file.
406 :path: String. Repository-absolute path of the specified file.
407
407
408 And each entry of ``{lines}`` provides the following sub-keywords in
408 And each entry of ``{lines}`` provides the following sub-keywords in
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410
410
411 :line: String. Line content.
411 :line: String. Line content.
412 :lineno: Integer. Line number at that revision.
412 :lineno: Integer. Line number at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
414
414
415 See :hg:`help templates.operators` for the list expansion syntax.
415 See :hg:`help templates.operators` for the list expansion syntax.
416
416
417 Returns 0 on success.
417 Returns 0 on success.
418 """
418 """
419 opts = pycompat.byteskwargs(opts)
419 opts = pycompat.byteskwargs(opts)
420 if not pats:
420 if not pats:
421 raise error.Abort(_(b'at least one filename or pattern is required'))
421 raise error.Abort(_(b'at least one filename or pattern is required'))
422
422
423 if opts.get(b'follow'):
423 if opts.get(b'follow'):
424 # --follow is deprecated and now just an alias for -f/--file
424 # --follow is deprecated and now just an alias for -f/--file
425 # to mimic the behavior of Mercurial before version 1.5
425 # to mimic the behavior of Mercurial before version 1.5
426 opts[b'file'] = True
426 opts[b'file'] = True
427
427
428 if (
428 if (
429 not opts.get(b'user')
429 not opts.get(b'user')
430 and not opts.get(b'changeset')
430 and not opts.get(b'changeset')
431 and not opts.get(b'date')
431 and not opts.get(b'date')
432 and not opts.get(b'file')
432 and not opts.get(b'file')
433 ):
433 ):
434 opts[b'number'] = True
434 opts[b'number'] = True
435
435
436 linenumber = opts.get(b'line_number') is not None
436 linenumber = opts.get(b'line_number') is not None
437 if (
437 if (
438 linenumber
438 linenumber
439 and (not opts.get(b'changeset'))
439 and (not opts.get(b'changeset'))
440 and (not opts.get(b'number'))
440 and (not opts.get(b'number'))
441 ):
441 ):
442 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
442 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
443
443
444 rev = opts.get(b'rev')
444 rev = opts.get(b'rev')
445 if rev:
445 if rev:
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 ctx = scmutil.revsingle(repo, rev)
447 ctx = scmutil.revsingle(repo, rev)
448
448
449 ui.pager(b'annotate')
449 ui.pager(b'annotate')
450 rootfm = ui.formatter(b'annotate', opts)
450 rootfm = ui.formatter(b'annotate', opts)
451 if ui.debugflag:
451 if ui.debugflag:
452 shorthex = pycompat.identity
452 shorthex = pycompat.identity
453 else:
453 else:
454
454
455 def shorthex(h):
455 def shorthex(h):
456 return h[:12]
456 return h[:12]
457
457
458 if ui.quiet:
458 if ui.quiet:
459 datefunc = dateutil.shortdate
459 datefunc = dateutil.shortdate
460 else:
460 else:
461 datefunc = dateutil.datestr
461 datefunc = dateutil.datestr
462 if ctx.rev() is None:
462 if ctx.rev() is None:
463 if opts.get(b'changeset'):
463 if opts.get(b'changeset'):
464 # omit "+" suffix which is appended to node hex
464 # omit "+" suffix which is appended to node hex
465 def formatrev(rev):
465 def formatrev(rev):
466 if rev == wdirrev:
466 if rev == wdirrev:
467 return b'%d' % ctx.p1().rev()
467 return b'%d' % ctx.p1().rev()
468 else:
468 else:
469 return b'%d' % rev
469 return b'%d' % rev
470
470
471 else:
471 else:
472
472
473 def formatrev(rev):
473 def formatrev(rev):
474 if rev == wdirrev:
474 if rev == wdirrev:
475 return b'%d+' % ctx.p1().rev()
475 return b'%d+' % ctx.p1().rev()
476 else:
476 else:
477 return b'%d ' % rev
477 return b'%d ' % rev
478
478
479 def formathex(h):
479 def formathex(h):
480 if h == wdirhex:
480 if h == wdirhex:
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 else:
482 else:
483 return b'%s ' % shorthex(h)
483 return b'%s ' % shorthex(h)
484
484
485 else:
485 else:
486 formatrev = b'%d'.__mod__
486 formatrev = b'%d'.__mod__
487 formathex = shorthex
487 formathex = shorthex
488
488
489 opmap = [
489 opmap = [
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 ]
496 ]
497 opnamemap = {
497 opnamemap = {
498 b'rev': b'number',
498 b'rev': b'number',
499 b'node': b'changeset',
499 b'node': b'changeset',
500 b'path': b'file',
500 b'path': b'file',
501 b'lineno': b'line_number',
501 b'lineno': b'line_number',
502 }
502 }
503
503
504 if rootfm.isplain():
504 if rootfm.isplain():
505
505
506 def makefunc(get, fmt):
506 def makefunc(get, fmt):
507 return lambda x: fmt(get(x))
507 return lambda x: fmt(get(x))
508
508
509 else:
509 else:
510
510
511 def makefunc(get, fmt):
511 def makefunc(get, fmt):
512 return get
512 return get
513
513
514 datahint = rootfm.datahint()
514 datahint = rootfm.datahint()
515 funcmap = [
515 funcmap = [
516 (makefunc(get, fmt), sep)
516 (makefunc(get, fmt), sep)
517 for fn, sep, get, fmt in opmap
517 for fn, sep, get, fmt in opmap
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 ]
519 ]
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 fields = b' '.join(
521 fields = b' '.join(
522 fn
522 fn
523 for fn, sep, get, fmt in opmap
523 for fn, sep, get, fmt in opmap
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 )
525 )
526
526
527 def bad(x, y):
527 def bad(x, y):
528 raise error.Abort(b"%s: %s" % (x, y))
528 raise error.Abort(b"%s: %s" % (x, y))
529
529
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
531
531
532 follow = not opts.get(b'no_follow')
532 follow = not opts.get(b'no_follow')
533 diffopts = patch.difffeatureopts(
533 diffopts = patch.difffeatureopts(
534 ui, opts, section=b'annotate', whitespace=True
534 ui, opts, section=b'annotate', whitespace=True
535 )
535 )
536 skiprevs = opts.get(b'skip')
536 skiprevs = opts.get(b'skip')
537 if skiprevs:
537 if skiprevs:
538 skiprevs = scmutil.revrange(repo, skiprevs)
538 skiprevs = scmutil.revrange(repo, skiprevs)
539
539
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 for abs in ctx.walk(m):
541 for abs in ctx.walk(m):
542 fctx = ctx[abs]
542 fctx = ctx[abs]
543 rootfm.startitem()
543 rootfm.startitem()
544 rootfm.data(path=abs)
544 rootfm.data(path=abs)
545 if not opts.get(b'text') and fctx.isbinary():
545 if not opts.get(b'text') and fctx.isbinary():
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 continue
547 continue
548
548
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 lines = fctx.annotate(
550 lines = fctx.annotate(
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 )
552 )
553 if not lines:
553 if not lines:
554 fm.end()
554 fm.end()
555 continue
555 continue
556 formats = []
556 formats = []
557 pieces = []
557 pieces = []
558
558
559 for f, sep in funcmap:
559 for f, sep in funcmap:
560 l = [f(n) for n in lines]
560 l = [f(n) for n in lines]
561 if fm.isplain():
561 if fm.isplain():
562 sizes = [encoding.colwidth(x) for x in l]
562 sizes = [encoding.colwidth(x) for x in l]
563 ml = max(sizes)
563 ml = max(sizes)
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 else:
565 else:
566 formats.append([b'%s'] * len(l))
566 formats.append([b'%s'] * len(l))
567 pieces.append(l)
567 pieces.append(l)
568
568
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 fm.startitem()
570 fm.startitem()
571 fm.context(fctx=n.fctx)
571 fm.context(fctx=n.fctx)
572 fm.write(fields, b"".join(f), *p)
572 fm.write(fields, b"".join(f), *p)
573 if n.skip:
573 if n.skip:
574 fmt = b"* %s"
574 fmt = b"* %s"
575 else:
575 else:
576 fmt = b": %s"
576 fmt = b": %s"
577 fm.write(b'line', fmt, n.text)
577 fm.write(b'line', fmt, n.text)
578
578
579 if not lines[-1].text.endswith(b'\n'):
579 if not lines[-1].text.endswith(b'\n'):
580 fm.plain(b'\n')
580 fm.plain(b'\n')
581 fm.end()
581 fm.end()
582
582
583 rootfm.end()
583 rootfm.end()
584
584
585
585
586 @command(
586 @command(
587 b'archive',
587 b'archive',
588 [
588 [
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (
590 (
591 b'p',
591 b'p',
592 b'prefix',
592 b'prefix',
593 b'',
593 b'',
594 _(b'directory prefix for files in archive'),
594 _(b'directory prefix for files in archive'),
595 _(b'PREFIX'),
595 _(b'PREFIX'),
596 ),
596 ),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
599 ]
599 ]
600 + subrepoopts
600 + subrepoopts
601 + walkopts,
601 + walkopts,
602 _(b'[OPTION]... DEST'),
602 _(b'[OPTION]... DEST'),
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 )
604 )
605 def archive(ui, repo, dest, **opts):
605 def archive(ui, repo, dest, **opts):
606 '''create an unversioned archive of a repository revision
606 '''create an unversioned archive of a repository revision
607
607
608 By default, the revision used is the parent of the working
608 By default, the revision used is the parent of the working
609 directory; use -r/--rev to specify a different revision.
609 directory; use -r/--rev to specify a different revision.
610
610
611 The archive type is automatically detected based on file
611 The archive type is automatically detected based on file
612 extension (to override, use -t/--type).
612 extension (to override, use -t/--type).
613
613
614 .. container:: verbose
614 .. container:: verbose
615
615
616 Examples:
616 Examples:
617
617
618 - create a zip file containing the 1.0 release::
618 - create a zip file containing the 1.0 release::
619
619
620 hg archive -r 1.0 project-1.0.zip
620 hg archive -r 1.0 project-1.0.zip
621
621
622 - create a tarball excluding .hg files::
622 - create a tarball excluding .hg files::
623
623
624 hg archive project.tar.gz -X ".hg*"
624 hg archive project.tar.gz -X ".hg*"
625
625
626 Valid types are:
626 Valid types are:
627
627
628 :``files``: a directory full of files (default)
628 :``files``: a directory full of files (default)
629 :``tar``: tar archive, uncompressed
629 :``tar``: tar archive, uncompressed
630 :``tbz2``: tar archive, compressed using bzip2
630 :``tbz2``: tar archive, compressed using bzip2
631 :``tgz``: tar archive, compressed using gzip
631 :``tgz``: tar archive, compressed using gzip
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``uzip``: zip archive, uncompressed
633 :``uzip``: zip archive, uncompressed
634 :``zip``: zip archive, compressed using deflate
634 :``zip``: zip archive, compressed using deflate
635
635
636 The exact name of the destination archive or directory is given
636 The exact name of the destination archive or directory is given
637 using a format string; see :hg:`help export` for details.
637 using a format string; see :hg:`help export` for details.
638
638
639 Each member added to an archive file has a directory prefix
639 Each member added to an archive file has a directory prefix
640 prepended. Use -p/--prefix to specify a format string for the
640 prepended. Use -p/--prefix to specify a format string for the
641 prefix. The default is the basename of the archive, with suffixes
641 prefix. The default is the basename of the archive, with suffixes
642 removed.
642 removed.
643
643
644 Returns 0 on success.
644 Returns 0 on success.
645 '''
645 '''
646
646
647 opts = pycompat.byteskwargs(opts)
647 opts = pycompat.byteskwargs(opts)
648 rev = opts.get(b'rev')
648 rev = opts.get(b'rev')
649 if rev:
649 if rev:
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 ctx = scmutil.revsingle(repo, rev)
651 ctx = scmutil.revsingle(repo, rev)
652 if not ctx:
652 if not ctx:
653 raise error.Abort(_(b'no working directory: please specify a revision'))
653 raise error.Abort(_(b'no working directory: please specify a revision'))
654 node = ctx.node()
654 node = ctx.node()
655 dest = cmdutil.makefilename(ctx, dest)
655 dest = cmdutil.makefilename(ctx, dest)
656 if os.path.realpath(dest) == repo.root:
656 if os.path.realpath(dest) == repo.root:
657 raise error.Abort(_(b'repository root cannot be destination'))
657 raise error.Abort(_(b'repository root cannot be destination'))
658
658
659 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
659 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
660 prefix = opts.get(b'prefix')
660 prefix = opts.get(b'prefix')
661
661
662 if dest == b'-':
662 if dest == b'-':
663 if kind == b'files':
663 if kind == b'files':
664 raise error.Abort(_(b'cannot archive plain files to stdout'))
664 raise error.Abort(_(b'cannot archive plain files to stdout'))
665 dest = cmdutil.makefileobj(ctx, dest)
665 dest = cmdutil.makefileobj(ctx, dest)
666 if not prefix:
666 if not prefix:
667 prefix = os.path.basename(repo.root) + b'-%h'
667 prefix = os.path.basename(repo.root) + b'-%h'
668
668
669 prefix = cmdutil.makefilename(ctx, prefix)
669 prefix = cmdutil.makefilename(ctx, prefix)
670 match = scmutil.match(ctx, [], opts)
670 match = scmutil.match(ctx, [], opts)
671 archival.archive(
671 archival.archive(
672 repo,
672 repo,
673 dest,
673 dest,
674 node,
674 node,
675 kind,
675 kind,
676 not opts.get(b'no_decode'),
676 not opts.get(b'no_decode'),
677 match,
677 match,
678 prefix,
678 prefix,
679 subrepos=opts.get(b'subrepos'),
679 subrepos=opts.get(b'subrepos'),
680 )
680 )
681
681
682
682
683 @command(
683 @command(
684 b'backout',
684 b'backout',
685 [
685 [
686 (
686 (
687 b'',
687 b'',
688 b'merge',
688 b'merge',
689 None,
689 None,
690 _(b'merge with old dirstate parent after backout'),
690 _(b'merge with old dirstate parent after backout'),
691 ),
691 ),
692 (
692 (
693 b'',
693 b'',
694 b'commit',
694 b'commit',
695 None,
695 None,
696 _(b'commit if no conflicts were encountered (DEPRECATED)'),
696 _(b'commit if no conflicts were encountered (DEPRECATED)'),
697 ),
697 ),
698 (b'', b'no-commit', None, _(b'do not commit')),
698 (b'', b'no-commit', None, _(b'do not commit')),
699 (
699 (
700 b'',
700 b'',
701 b'parent',
701 b'parent',
702 b'',
702 b'',
703 _(b'parent to choose when backing out merge (DEPRECATED)'),
703 _(b'parent to choose when backing out merge (DEPRECATED)'),
704 _(b'REV'),
704 _(b'REV'),
705 ),
705 ),
706 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
706 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
707 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
707 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
708 ]
708 ]
709 + mergetoolopts
709 + mergetoolopts
710 + walkopts
710 + walkopts
711 + commitopts
711 + commitopts
712 + commitopts2,
712 + commitopts2,
713 _(b'[OPTION]... [-r] REV'),
713 _(b'[OPTION]... [-r] REV'),
714 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
714 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
715 )
715 )
716 def backout(ui, repo, node=None, rev=None, **opts):
716 def backout(ui, repo, node=None, rev=None, **opts):
717 '''reverse effect of earlier changeset
717 '''reverse effect of earlier changeset
718
718
719 Prepare a new changeset with the effect of REV undone in the
719 Prepare a new changeset with the effect of REV undone in the
720 current working directory. If no conflicts were encountered,
720 current working directory. If no conflicts were encountered,
721 it will be committed immediately.
721 it will be committed immediately.
722
722
723 If REV is the parent of the working directory, then this new changeset
723 If REV is the parent of the working directory, then this new changeset
724 is committed automatically (unless --no-commit is specified).
724 is committed automatically (unless --no-commit is specified).
725
725
726 .. note::
726 .. note::
727
727
728 :hg:`backout` cannot be used to fix either an unwanted or
728 :hg:`backout` cannot be used to fix either an unwanted or
729 incorrect merge.
729 incorrect merge.
730
730
731 .. container:: verbose
731 .. container:: verbose
732
732
733 Examples:
733 Examples:
734
734
735 - Reverse the effect of the parent of the working directory.
735 - Reverse the effect of the parent of the working directory.
736 This backout will be committed immediately::
736 This backout will be committed immediately::
737
737
738 hg backout -r .
738 hg backout -r .
739
739
740 - Reverse the effect of previous bad revision 23::
740 - Reverse the effect of previous bad revision 23::
741
741
742 hg backout -r 23
742 hg backout -r 23
743
743
744 - Reverse the effect of previous bad revision 23 and
744 - Reverse the effect of previous bad revision 23 and
745 leave changes uncommitted::
745 leave changes uncommitted::
746
746
747 hg backout -r 23 --no-commit
747 hg backout -r 23 --no-commit
748 hg commit -m "Backout revision 23"
748 hg commit -m "Backout revision 23"
749
749
750 By default, the pending changeset will have one parent,
750 By default, the pending changeset will have one parent,
751 maintaining a linear history. With --merge, the pending
751 maintaining a linear history. With --merge, the pending
752 changeset will instead have two parents: the old parent of the
752 changeset will instead have two parents: the old parent of the
753 working directory and a new child of REV that simply undoes REV.
753 working directory and a new child of REV that simply undoes REV.
754
754
755 Before version 1.7, the behavior without --merge was equivalent
755 Before version 1.7, the behavior without --merge was equivalent
756 to specifying --merge followed by :hg:`update --clean .` to
756 to specifying --merge followed by :hg:`update --clean .` to
757 cancel the merge and leave the child of REV as a head to be
757 cancel the merge and leave the child of REV as a head to be
758 merged separately.
758 merged separately.
759
759
760 See :hg:`help dates` for a list of formats valid for -d/--date.
760 See :hg:`help dates` for a list of formats valid for -d/--date.
761
761
762 See :hg:`help revert` for a way to restore files to the state
762 See :hg:`help revert` for a way to restore files to the state
763 of another revision.
763 of another revision.
764
764
765 Returns 0 on success, 1 if nothing to backout or there are unresolved
765 Returns 0 on success, 1 if nothing to backout or there are unresolved
766 files.
766 files.
767 '''
767 '''
768 with repo.wlock(), repo.lock():
768 with repo.wlock(), repo.lock():
769 return _dobackout(ui, repo, node, rev, **opts)
769 return _dobackout(ui, repo, node, rev, **opts)
770
770
771
771
772 def _dobackout(ui, repo, node=None, rev=None, **opts):
772 def _dobackout(ui, repo, node=None, rev=None, **opts):
773 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
773 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
774 opts = pycompat.byteskwargs(opts)
774 opts = pycompat.byteskwargs(opts)
775
775
776 if rev and node:
776 if rev and node:
777 raise error.Abort(_(b"please specify just one revision"))
777 raise error.Abort(_(b"please specify just one revision"))
778
778
779 if not rev:
779 if not rev:
780 rev = node
780 rev = node
781
781
782 if not rev:
782 if not rev:
783 raise error.Abort(_(b"please specify a revision to backout"))
783 raise error.Abort(_(b"please specify a revision to backout"))
784
784
785 date = opts.get(b'date')
785 date = opts.get(b'date')
786 if date:
786 if date:
787 opts[b'date'] = dateutil.parsedate(date)
787 opts[b'date'] = dateutil.parsedate(date)
788
788
789 cmdutil.checkunfinished(repo)
789 cmdutil.checkunfinished(repo)
790 cmdutil.bailifchanged(repo)
790 cmdutil.bailifchanged(repo)
791 ctx = scmutil.revsingle(repo, rev)
791 ctx = scmutil.revsingle(repo, rev)
792 node = ctx.node()
792 node = ctx.node()
793
793
794 op1, op2 = repo.dirstate.parents()
794 op1, op2 = repo.dirstate.parents()
795 if not repo.changelog.isancestor(node, op1):
795 if not repo.changelog.isancestor(node, op1):
796 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
796 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
797
797
798 p1, p2 = repo.changelog.parents(node)
798 p1, p2 = repo.changelog.parents(node)
799 if p1 == nullid:
799 if p1 == nullid:
800 raise error.Abort(_(b'cannot backout a change with no parents'))
800 raise error.Abort(_(b'cannot backout a change with no parents'))
801 if p2 != nullid:
801 if p2 != nullid:
802 if not opts.get(b'parent'):
802 if not opts.get(b'parent'):
803 raise error.Abort(_(b'cannot backout a merge changeset'))
803 raise error.Abort(_(b'cannot backout a merge changeset'))
804 p = repo.lookup(opts[b'parent'])
804 p = repo.lookup(opts[b'parent'])
805 if p not in (p1, p2):
805 if p not in (p1, p2):
806 raise error.Abort(
806 raise error.Abort(
807 _(b'%s is not a parent of %s') % (short(p), short(node))
807 _(b'%s is not a parent of %s') % (short(p), short(node))
808 )
808 )
809 parent = p
809 parent = p
810 else:
810 else:
811 if opts.get(b'parent'):
811 if opts.get(b'parent'):
812 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
812 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
813 parent = p1
813 parent = p1
814
814
815 # the backout should appear on the same branch
815 # the backout should appear on the same branch
816 branch = repo.dirstate.branch()
816 branch = repo.dirstate.branch()
817 bheads = repo.branchheads(branch)
817 bheads = repo.branchheads(branch)
818 rctx = scmutil.revsingle(repo, hex(parent))
818 rctx = scmutil.revsingle(repo, hex(parent))
819 if not opts.get(b'merge') and op1 != node:
819 if not opts.get(b'merge') and op1 != node:
820 with dirstateguard.dirstateguard(repo, b'backout'):
820 with dirstateguard.dirstateguard(repo, b'backout'):
821 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
821 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
822 with ui.configoverride(overrides, b'backout'):
822 with ui.configoverride(overrides, b'backout'):
823 stats = mergemod.back_out(ctx, parent=repo[parent])
823 stats = mergemod.back_out(ctx, parent=repo[parent])
824 repo.setparents(op1, op2)
824 repo.setparents(op1, op2)
825 hg._showstats(repo, stats)
825 hg._showstats(repo, stats)
826 if stats.unresolvedcount:
826 if stats.unresolvedcount:
827 repo.ui.status(
827 repo.ui.status(
828 _(b"use 'hg resolve' to retry unresolved file merges\n")
828 _(b"use 'hg resolve' to retry unresolved file merges\n")
829 )
829 )
830 return 1
830 return 1
831 else:
831 else:
832 hg.clean(repo, node, show_stats=False)
832 hg.clean(repo, node, show_stats=False)
833 repo.dirstate.setbranch(branch)
833 repo.dirstate.setbranch(branch)
834 cmdutil.revert(ui, repo, rctx)
834 cmdutil.revert(ui, repo, rctx)
835
835
836 if opts.get(b'no_commit'):
836 if opts.get(b'no_commit'):
837 msg = _(b"changeset %s backed out, don't forget to commit.\n")
837 msg = _(b"changeset %s backed out, don't forget to commit.\n")
838 ui.status(msg % short(node))
838 ui.status(msg % short(node))
839 return 0
839 return 0
840
840
841 def commitfunc(ui, repo, message, match, opts):
841 def commitfunc(ui, repo, message, match, opts):
842 editform = b'backout'
842 editform = b'backout'
843 e = cmdutil.getcommiteditor(
843 e = cmdutil.getcommiteditor(
844 editform=editform, **pycompat.strkwargs(opts)
844 editform=editform, **pycompat.strkwargs(opts)
845 )
845 )
846 if not message:
846 if not message:
847 # we don't translate commit messages
847 # we don't translate commit messages
848 message = b"Backed out changeset %s" % short(node)
848 message = b"Backed out changeset %s" % short(node)
849 e = cmdutil.getcommiteditor(edit=True, editform=editform)
849 e = cmdutil.getcommiteditor(edit=True, editform=editform)
850 return repo.commit(
850 return repo.commit(
851 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
851 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
852 )
852 )
853
853
854 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
854 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
855 if not newnode:
855 if not newnode:
856 ui.status(_(b"nothing changed\n"))
856 ui.status(_(b"nothing changed\n"))
857 return 1
857 return 1
858 cmdutil.commitstatus(repo, newnode, branch, bheads)
858 cmdutil.commitstatus(repo, newnode, branch, bheads)
859
859
860 def nice(node):
860 def nice(node):
861 return b'%d:%s' % (repo.changelog.rev(node), short(node))
861 return b'%d:%s' % (repo.changelog.rev(node), short(node))
862
862
863 ui.status(
863 ui.status(
864 _(b'changeset %s backs out changeset %s\n')
864 _(b'changeset %s backs out changeset %s\n')
865 % (nice(repo.changelog.tip()), nice(node))
865 % (nice(repo.changelog.tip()), nice(node))
866 )
866 )
867 if opts.get(b'merge') and op1 != node:
867 if opts.get(b'merge') and op1 != node:
868 hg.clean(repo, op1, show_stats=False)
868 hg.clean(repo, op1, show_stats=False)
869 ui.status(
869 ui.status(
870 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
870 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
871 )
871 )
872 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
872 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
873 with ui.configoverride(overrides, b'backout'):
873 with ui.configoverride(overrides, b'backout'):
874 return hg.merge(repo[b'tip'])
874 return hg.merge(repo[b'tip'])
875 return 0
875 return 0
876
876
877
877
878 @command(
878 @command(
879 b'bisect',
879 b'bisect',
880 [
880 [
881 (b'r', b'reset', False, _(b'reset bisect state')),
881 (b'r', b'reset', False, _(b'reset bisect state')),
882 (b'g', b'good', False, _(b'mark changeset good')),
882 (b'g', b'good', False, _(b'mark changeset good')),
883 (b'b', b'bad', False, _(b'mark changeset bad')),
883 (b'b', b'bad', False, _(b'mark changeset bad')),
884 (b's', b'skip', False, _(b'skip testing changeset')),
884 (b's', b'skip', False, _(b'skip testing changeset')),
885 (b'e', b'extend', False, _(b'extend the bisect range')),
885 (b'e', b'extend', False, _(b'extend the bisect range')),
886 (
886 (
887 b'c',
887 b'c',
888 b'command',
888 b'command',
889 b'',
889 b'',
890 _(b'use command to check changeset state'),
890 _(b'use command to check changeset state'),
891 _(b'CMD'),
891 _(b'CMD'),
892 ),
892 ),
893 (b'U', b'noupdate', False, _(b'do not update to target')),
893 (b'U', b'noupdate', False, _(b'do not update to target')),
894 ],
894 ],
895 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
895 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
896 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
896 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
897 )
897 )
898 def bisect(
898 def bisect(
899 ui,
899 ui,
900 repo,
900 repo,
901 rev=None,
901 rev=None,
902 extra=None,
902 extra=None,
903 command=None,
903 command=None,
904 reset=None,
904 reset=None,
905 good=None,
905 good=None,
906 bad=None,
906 bad=None,
907 skip=None,
907 skip=None,
908 extend=None,
908 extend=None,
909 noupdate=None,
909 noupdate=None,
910 ):
910 ):
911 """subdivision search of changesets
911 """subdivision search of changesets
912
912
913 This command helps to find changesets which introduce problems. To
913 This command helps to find changesets which introduce problems. To
914 use, mark the earliest changeset you know exhibits the problem as
914 use, mark the earliest changeset you know exhibits the problem as
915 bad, then mark the latest changeset which is free from the problem
915 bad, then mark the latest changeset which is free from the problem
916 as good. Bisect will update your working directory to a revision
916 as good. Bisect will update your working directory to a revision
917 for testing (unless the -U/--noupdate option is specified). Once
917 for testing (unless the -U/--noupdate option is specified). Once
918 you have performed tests, mark the working directory as good or
918 you have performed tests, mark the working directory as good or
919 bad, and bisect will either update to another candidate changeset
919 bad, and bisect will either update to another candidate changeset
920 or announce that it has found the bad revision.
920 or announce that it has found the bad revision.
921
921
922 As a shortcut, you can also use the revision argument to mark a
922 As a shortcut, you can also use the revision argument to mark a
923 revision as good or bad without checking it out first.
923 revision as good or bad without checking it out first.
924
924
925 If you supply a command, it will be used for automatic bisection.
925 If you supply a command, it will be used for automatic bisection.
926 The environment variable HG_NODE will contain the ID of the
926 The environment variable HG_NODE will contain the ID of the
927 changeset being tested. The exit status of the command will be
927 changeset being tested. The exit status of the command will be
928 used to mark revisions as good or bad: status 0 means good, 125
928 used to mark revisions as good or bad: status 0 means good, 125
929 means to skip the revision, 127 (command not found) will abort the
929 means to skip the revision, 127 (command not found) will abort the
930 bisection, and any other non-zero exit status means the revision
930 bisection, and any other non-zero exit status means the revision
931 is bad.
931 is bad.
932
932
933 .. container:: verbose
933 .. container:: verbose
934
934
935 Some examples:
935 Some examples:
936
936
937 - start a bisection with known bad revision 34, and good revision 12::
937 - start a bisection with known bad revision 34, and good revision 12::
938
938
939 hg bisect --bad 34
939 hg bisect --bad 34
940 hg bisect --good 12
940 hg bisect --good 12
941
941
942 - advance the current bisection by marking current revision as good or
942 - advance the current bisection by marking current revision as good or
943 bad::
943 bad::
944
944
945 hg bisect --good
945 hg bisect --good
946 hg bisect --bad
946 hg bisect --bad
947
947
948 - mark the current revision, or a known revision, to be skipped (e.g. if
948 - mark the current revision, or a known revision, to be skipped (e.g. if
949 that revision is not usable because of another issue)::
949 that revision is not usable because of another issue)::
950
950
951 hg bisect --skip
951 hg bisect --skip
952 hg bisect --skip 23
952 hg bisect --skip 23
953
953
954 - skip all revisions that do not touch directories ``foo`` or ``bar``::
954 - skip all revisions that do not touch directories ``foo`` or ``bar``::
955
955
956 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
956 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
957
957
958 - forget the current bisection::
958 - forget the current bisection::
959
959
960 hg bisect --reset
960 hg bisect --reset
961
961
962 - use 'make && make tests' to automatically find the first broken
962 - use 'make && make tests' to automatically find the first broken
963 revision::
963 revision::
964
964
965 hg bisect --reset
965 hg bisect --reset
966 hg bisect --bad 34
966 hg bisect --bad 34
967 hg bisect --good 12
967 hg bisect --good 12
968 hg bisect --command "make && make tests"
968 hg bisect --command "make && make tests"
969
969
970 - see all changesets whose states are already known in the current
970 - see all changesets whose states are already known in the current
971 bisection::
971 bisection::
972
972
973 hg log -r "bisect(pruned)"
973 hg log -r "bisect(pruned)"
974
974
975 - see the changeset currently being bisected (especially useful
975 - see the changeset currently being bisected (especially useful
976 if running with -U/--noupdate)::
976 if running with -U/--noupdate)::
977
977
978 hg log -r "bisect(current)"
978 hg log -r "bisect(current)"
979
979
980 - see all changesets that took part in the current bisection::
980 - see all changesets that took part in the current bisection::
981
981
982 hg log -r "bisect(range)"
982 hg log -r "bisect(range)"
983
983
984 - you can even get a nice graph::
984 - you can even get a nice graph::
985
985
986 hg log --graph -r "bisect(range)"
986 hg log --graph -r "bisect(range)"
987
987
988 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
988 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
989
989
990 Returns 0 on success.
990 Returns 0 on success.
991 """
991 """
992 # backward compatibility
992 # backward compatibility
993 if rev in b"good bad reset init".split():
993 if rev in b"good bad reset init".split():
994 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
994 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
995 cmd, rev, extra = rev, extra, None
995 cmd, rev, extra = rev, extra, None
996 if cmd == b"good":
996 if cmd == b"good":
997 good = True
997 good = True
998 elif cmd == b"bad":
998 elif cmd == b"bad":
999 bad = True
999 bad = True
1000 else:
1000 else:
1001 reset = True
1001 reset = True
1002 elif extra:
1002 elif extra:
1003 raise error.Abort(_(b'incompatible arguments'))
1003 raise error.Abort(_(b'incompatible arguments'))
1004
1004
1005 incompatibles = {
1005 incompatibles = {
1006 b'--bad': bad,
1006 b'--bad': bad,
1007 b'--command': bool(command),
1007 b'--command': bool(command),
1008 b'--extend': extend,
1008 b'--extend': extend,
1009 b'--good': good,
1009 b'--good': good,
1010 b'--reset': reset,
1010 b'--reset': reset,
1011 b'--skip': skip,
1011 b'--skip': skip,
1012 }
1012 }
1013
1013
1014 enabled = [x for x in incompatibles if incompatibles[x]]
1014 enabled = [x for x in incompatibles if incompatibles[x]]
1015
1015
1016 if len(enabled) > 1:
1016 if len(enabled) > 1:
1017 raise error.Abort(
1017 raise error.Abort(
1018 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1018 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1019 )
1019 )
1020
1020
1021 if reset:
1021 if reset:
1022 hbisect.resetstate(repo)
1022 hbisect.resetstate(repo)
1023 return
1023 return
1024
1024
1025 state = hbisect.load_state(repo)
1025 state = hbisect.load_state(repo)
1026
1026
1027 # update state
1027 # update state
1028 if good or bad or skip:
1028 if good or bad or skip:
1029 if rev:
1029 if rev:
1030 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1030 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1031 else:
1031 else:
1032 nodes = [repo.lookup(b'.')]
1032 nodes = [repo.lookup(b'.')]
1033 if good:
1033 if good:
1034 state[b'good'] += nodes
1034 state[b'good'] += nodes
1035 elif bad:
1035 elif bad:
1036 state[b'bad'] += nodes
1036 state[b'bad'] += nodes
1037 elif skip:
1037 elif skip:
1038 state[b'skip'] += nodes
1038 state[b'skip'] += nodes
1039 hbisect.save_state(repo, state)
1039 hbisect.save_state(repo, state)
1040 if not (state[b'good'] and state[b'bad']):
1040 if not (state[b'good'] and state[b'bad']):
1041 return
1041 return
1042
1042
1043 def mayupdate(repo, node, show_stats=True):
1043 def mayupdate(repo, node, show_stats=True):
1044 """common used update sequence"""
1044 """common used update sequence"""
1045 if noupdate:
1045 if noupdate:
1046 return
1046 return
1047 cmdutil.checkunfinished(repo)
1047 cmdutil.checkunfinished(repo)
1048 cmdutil.bailifchanged(repo)
1048 cmdutil.bailifchanged(repo)
1049 return hg.clean(repo, node, show_stats=show_stats)
1049 return hg.clean(repo, node, show_stats=show_stats)
1050
1050
1051 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1051 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1052
1052
1053 if command:
1053 if command:
1054 changesets = 1
1054 changesets = 1
1055 if noupdate:
1055 if noupdate:
1056 try:
1056 try:
1057 node = state[b'current'][0]
1057 node = state[b'current'][0]
1058 except LookupError:
1058 except LookupError:
1059 raise error.Abort(
1059 raise error.Abort(
1060 _(
1060 _(
1061 b'current bisect revision is unknown - '
1061 b'current bisect revision is unknown - '
1062 b'start a new bisect to fix'
1062 b'start a new bisect to fix'
1063 )
1063 )
1064 )
1064 )
1065 else:
1065 else:
1066 node, p2 = repo.dirstate.parents()
1066 node, p2 = repo.dirstate.parents()
1067 if p2 != nullid:
1067 if p2 != nullid:
1068 raise error.Abort(_(b'current bisect revision is a merge'))
1068 raise error.Abort(_(b'current bisect revision is a merge'))
1069 if rev:
1069 if rev:
1070 node = repo[scmutil.revsingle(repo, rev, node)].node()
1070 node = repo[scmutil.revsingle(repo, rev, node)].node()
1071 with hbisect.restore_state(repo, state, node):
1071 with hbisect.restore_state(repo, state, node):
1072 while changesets:
1072 while changesets:
1073 # update state
1073 # update state
1074 state[b'current'] = [node]
1074 state[b'current'] = [node]
1075 hbisect.save_state(repo, state)
1075 hbisect.save_state(repo, state)
1076 status = ui.system(
1076 status = ui.system(
1077 command,
1077 command,
1078 environ={b'HG_NODE': hex(node)},
1078 environ={b'HG_NODE': hex(node)},
1079 blockedtag=b'bisect_check',
1079 blockedtag=b'bisect_check',
1080 )
1080 )
1081 if status == 125:
1081 if status == 125:
1082 transition = b"skip"
1082 transition = b"skip"
1083 elif status == 0:
1083 elif status == 0:
1084 transition = b"good"
1084 transition = b"good"
1085 # status < 0 means process was killed
1085 # status < 0 means process was killed
1086 elif status == 127:
1086 elif status == 127:
1087 raise error.Abort(_(b"failed to execute %s") % command)
1087 raise error.Abort(_(b"failed to execute %s") % command)
1088 elif status < 0:
1088 elif status < 0:
1089 raise error.Abort(_(b"%s killed") % command)
1089 raise error.Abort(_(b"%s killed") % command)
1090 else:
1090 else:
1091 transition = b"bad"
1091 transition = b"bad"
1092 state[transition].append(node)
1092 state[transition].append(node)
1093 ctx = repo[node]
1093 ctx = repo[node]
1094 ui.status(
1094 ui.status(
1095 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1095 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1096 )
1096 )
1097 hbisect.checkstate(state)
1097 hbisect.checkstate(state)
1098 # bisect
1098 # bisect
1099 nodes, changesets, bgood = hbisect.bisect(repo, state)
1099 nodes, changesets, bgood = hbisect.bisect(repo, state)
1100 # update to next check
1100 # update to next check
1101 node = nodes[0]
1101 node = nodes[0]
1102 mayupdate(repo, node, show_stats=False)
1102 mayupdate(repo, node, show_stats=False)
1103 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1103 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1104 return
1104 return
1105
1105
1106 hbisect.checkstate(state)
1106 hbisect.checkstate(state)
1107
1107
1108 # actually bisect
1108 # actually bisect
1109 nodes, changesets, good = hbisect.bisect(repo, state)
1109 nodes, changesets, good = hbisect.bisect(repo, state)
1110 if extend:
1110 if extend:
1111 if not changesets:
1111 if not changesets:
1112 extendnode = hbisect.extendrange(repo, state, nodes, good)
1112 extendnode = hbisect.extendrange(repo, state, nodes, good)
1113 if extendnode is not None:
1113 if extendnode is not None:
1114 ui.write(
1114 ui.write(
1115 _(b"Extending search to changeset %d:%s\n")
1115 _(b"Extending search to changeset %d:%s\n")
1116 % (extendnode.rev(), extendnode)
1116 % (extendnode.rev(), extendnode)
1117 )
1117 )
1118 state[b'current'] = [extendnode.node()]
1118 state[b'current'] = [extendnode.node()]
1119 hbisect.save_state(repo, state)
1119 hbisect.save_state(repo, state)
1120 return mayupdate(repo, extendnode.node())
1120 return mayupdate(repo, extendnode.node())
1121 raise error.Abort(_(b"nothing to extend"))
1121 raise error.Abort(_(b"nothing to extend"))
1122
1122
1123 if changesets == 0:
1123 if changesets == 0:
1124 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1124 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1125 else:
1125 else:
1126 assert len(nodes) == 1 # only a single node can be tested next
1126 assert len(nodes) == 1 # only a single node can be tested next
1127 node = nodes[0]
1127 node = nodes[0]
1128 # compute the approximate number of remaining tests
1128 # compute the approximate number of remaining tests
1129 tests, size = 0, 2
1129 tests, size = 0, 2
1130 while size <= changesets:
1130 while size <= changesets:
1131 tests, size = tests + 1, size * 2
1131 tests, size = tests + 1, size * 2
1132 rev = repo.changelog.rev(node)
1132 rev = repo.changelog.rev(node)
1133 ui.write(
1133 ui.write(
1134 _(
1134 _(
1135 b"Testing changeset %d:%s "
1135 b"Testing changeset %d:%s "
1136 b"(%d changesets remaining, ~%d tests)\n"
1136 b"(%d changesets remaining, ~%d tests)\n"
1137 )
1137 )
1138 % (rev, short(node), changesets, tests)
1138 % (rev, short(node), changesets, tests)
1139 )
1139 )
1140 state[b'current'] = [node]
1140 state[b'current'] = [node]
1141 hbisect.save_state(repo, state)
1141 hbisect.save_state(repo, state)
1142 return mayupdate(repo, node)
1142 return mayupdate(repo, node)
1143
1143
1144
1144
1145 @command(
1145 @command(
1146 b'bookmarks|bookmark',
1146 b'bookmarks|bookmark',
1147 [
1147 [
1148 (b'f', b'force', False, _(b'force')),
1148 (b'f', b'force', False, _(b'force')),
1149 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1149 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1150 (b'd', b'delete', False, _(b'delete a given bookmark')),
1150 (b'd', b'delete', False, _(b'delete a given bookmark')),
1151 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1151 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1152 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1152 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1153 (b'l', b'list', False, _(b'list existing bookmarks')),
1153 (b'l', b'list', False, _(b'list existing bookmarks')),
1154 ]
1154 ]
1155 + formatteropts,
1155 + formatteropts,
1156 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1156 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1157 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1157 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1158 )
1158 )
1159 def bookmark(ui, repo, *names, **opts):
1159 def bookmark(ui, repo, *names, **opts):
1160 '''create a new bookmark or list existing bookmarks
1160 '''create a new bookmark or list existing bookmarks
1161
1161
1162 Bookmarks are labels on changesets to help track lines of development.
1162 Bookmarks are labels on changesets to help track lines of development.
1163 Bookmarks are unversioned and can be moved, renamed and deleted.
1163 Bookmarks are unversioned and can be moved, renamed and deleted.
1164 Deleting or moving a bookmark has no effect on the associated changesets.
1164 Deleting or moving a bookmark has no effect on the associated changesets.
1165
1165
1166 Creating or updating to a bookmark causes it to be marked as 'active'.
1166 Creating or updating to a bookmark causes it to be marked as 'active'.
1167 The active bookmark is indicated with a '*'.
1167 The active bookmark is indicated with a '*'.
1168 When a commit is made, the active bookmark will advance to the new commit.
1168 When a commit is made, the active bookmark will advance to the new commit.
1169 A plain :hg:`update` will also advance an active bookmark, if possible.
1169 A plain :hg:`update` will also advance an active bookmark, if possible.
1170 Updating away from a bookmark will cause it to be deactivated.
1170 Updating away from a bookmark will cause it to be deactivated.
1171
1171
1172 Bookmarks can be pushed and pulled between repositories (see
1172 Bookmarks can be pushed and pulled between repositories (see
1173 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1173 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1174 diverged, a new 'divergent bookmark' of the form 'name@path' will
1174 diverged, a new 'divergent bookmark' of the form 'name@path' will
1175 be created. Using :hg:`merge` will resolve the divergence.
1175 be created. Using :hg:`merge` will resolve the divergence.
1176
1176
1177 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1177 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1178 the active bookmark's name.
1178 the active bookmark's name.
1179
1179
1180 A bookmark named '@' has the special property that :hg:`clone` will
1180 A bookmark named '@' has the special property that :hg:`clone` will
1181 check it out by default if it exists.
1181 check it out by default if it exists.
1182
1182
1183 .. container:: verbose
1183 .. container:: verbose
1184
1184
1185 Template:
1185 Template:
1186
1186
1187 The following keywords are supported in addition to the common template
1187 The following keywords are supported in addition to the common template
1188 keywords and functions such as ``{bookmark}``. See also
1188 keywords and functions such as ``{bookmark}``. See also
1189 :hg:`help templates`.
1189 :hg:`help templates`.
1190
1190
1191 :active: Boolean. True if the bookmark is active.
1191 :active: Boolean. True if the bookmark is active.
1192
1192
1193 Examples:
1193 Examples:
1194
1194
1195 - create an active bookmark for a new line of development::
1195 - create an active bookmark for a new line of development::
1196
1196
1197 hg book new-feature
1197 hg book new-feature
1198
1198
1199 - create an inactive bookmark as a place marker::
1199 - create an inactive bookmark as a place marker::
1200
1200
1201 hg book -i reviewed
1201 hg book -i reviewed
1202
1202
1203 - create an inactive bookmark on another changeset::
1203 - create an inactive bookmark on another changeset::
1204
1204
1205 hg book -r .^ tested
1205 hg book -r .^ tested
1206
1206
1207 - rename bookmark turkey to dinner::
1207 - rename bookmark turkey to dinner::
1208
1208
1209 hg book -m turkey dinner
1209 hg book -m turkey dinner
1210
1210
1211 - move the '@' bookmark from another branch::
1211 - move the '@' bookmark from another branch::
1212
1212
1213 hg book -f @
1213 hg book -f @
1214
1214
1215 - print only the active bookmark name::
1215 - print only the active bookmark name::
1216
1216
1217 hg book -ql .
1217 hg book -ql .
1218 '''
1218 '''
1219 opts = pycompat.byteskwargs(opts)
1219 opts = pycompat.byteskwargs(opts)
1220 force = opts.get(b'force')
1220 force = opts.get(b'force')
1221 rev = opts.get(b'rev')
1221 rev = opts.get(b'rev')
1222 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1222 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1223
1223
1224 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1224 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1225 if action:
1225 if action:
1226 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1226 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1227 elif names or rev:
1227 elif names or rev:
1228 action = b'add'
1228 action = b'add'
1229 elif inactive:
1229 elif inactive:
1230 action = b'inactive' # meaning deactivate
1230 action = b'inactive' # meaning deactivate
1231 else:
1231 else:
1232 action = b'list'
1232 action = b'list'
1233
1233
1234 cmdutil.check_incompatible_arguments(
1234 cmdutil.check_incompatible_arguments(
1235 opts, b'inactive', [b'delete', b'list']
1235 opts, b'inactive', [b'delete', b'list']
1236 )
1236 )
1237 if not names and action in {b'add', b'delete'}:
1237 if not names and action in {b'add', b'delete'}:
1238 raise error.Abort(_(b"bookmark name required"))
1238 raise error.Abort(_(b"bookmark name required"))
1239
1239
1240 if action in {b'add', b'delete', b'rename', b'inactive'}:
1240 if action in {b'add', b'delete', b'rename', b'inactive'}:
1241 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1241 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1242 if action == b'delete':
1242 if action == b'delete':
1243 names = pycompat.maplist(repo._bookmarks.expandname, names)
1243 names = pycompat.maplist(repo._bookmarks.expandname, names)
1244 bookmarks.delete(repo, tr, names)
1244 bookmarks.delete(repo, tr, names)
1245 elif action == b'rename':
1245 elif action == b'rename':
1246 if not names:
1246 if not names:
1247 raise error.Abort(_(b"new bookmark name required"))
1247 raise error.Abort(_(b"new bookmark name required"))
1248 elif len(names) > 1:
1248 elif len(names) > 1:
1249 raise error.Abort(_(b"only one new bookmark name allowed"))
1249 raise error.Abort(_(b"only one new bookmark name allowed"))
1250 oldname = repo._bookmarks.expandname(opts[b'rename'])
1250 oldname = repo._bookmarks.expandname(opts[b'rename'])
1251 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1251 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1252 elif action == b'add':
1252 elif action == b'add':
1253 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1253 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1254 elif action == b'inactive':
1254 elif action == b'inactive':
1255 if len(repo._bookmarks) == 0:
1255 if len(repo._bookmarks) == 0:
1256 ui.status(_(b"no bookmarks set\n"))
1256 ui.status(_(b"no bookmarks set\n"))
1257 elif not repo._activebookmark:
1257 elif not repo._activebookmark:
1258 ui.status(_(b"no active bookmark\n"))
1258 ui.status(_(b"no active bookmark\n"))
1259 else:
1259 else:
1260 bookmarks.deactivate(repo)
1260 bookmarks.deactivate(repo)
1261 elif action == b'list':
1261 elif action == b'list':
1262 names = pycompat.maplist(repo._bookmarks.expandname, names)
1262 names = pycompat.maplist(repo._bookmarks.expandname, names)
1263 with ui.formatter(b'bookmarks', opts) as fm:
1263 with ui.formatter(b'bookmarks', opts) as fm:
1264 bookmarks.printbookmarks(ui, repo, fm, names)
1264 bookmarks.printbookmarks(ui, repo, fm, names)
1265 else:
1265 else:
1266 raise error.ProgrammingError(b'invalid action: %s' % action)
1266 raise error.ProgrammingError(b'invalid action: %s' % action)
1267
1267
1268
1268
1269 @command(
1269 @command(
1270 b'branch',
1270 b'branch',
1271 [
1271 [
1272 (
1272 (
1273 b'f',
1273 b'f',
1274 b'force',
1274 b'force',
1275 None,
1275 None,
1276 _(b'set branch name even if it shadows an existing branch'),
1276 _(b'set branch name even if it shadows an existing branch'),
1277 ),
1277 ),
1278 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1278 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1279 (
1279 (
1280 b'r',
1280 b'r',
1281 b'rev',
1281 b'rev',
1282 [],
1282 [],
1283 _(b'change branches of the given revs (EXPERIMENTAL)'),
1283 _(b'change branches of the given revs (EXPERIMENTAL)'),
1284 ),
1284 ),
1285 ],
1285 ],
1286 _(b'[-fC] [NAME]'),
1286 _(b'[-fC] [NAME]'),
1287 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1287 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1288 )
1288 )
1289 def branch(ui, repo, label=None, **opts):
1289 def branch(ui, repo, label=None, **opts):
1290 """set or show the current branch name
1290 """set or show the current branch name
1291
1291
1292 .. note::
1292 .. note::
1293
1293
1294 Branch names are permanent and global. Use :hg:`bookmark` to create a
1294 Branch names are permanent and global. Use :hg:`bookmark` to create a
1295 light-weight bookmark instead. See :hg:`help glossary` for more
1295 light-weight bookmark instead. See :hg:`help glossary` for more
1296 information about named branches and bookmarks.
1296 information about named branches and bookmarks.
1297
1297
1298 With no argument, show the current branch name. With one argument,
1298 With no argument, show the current branch name. With one argument,
1299 set the working directory branch name (the branch will not exist
1299 set the working directory branch name (the branch will not exist
1300 in the repository until the next commit). Standard practice
1300 in the repository until the next commit). Standard practice
1301 recommends that primary development take place on the 'default'
1301 recommends that primary development take place on the 'default'
1302 branch.
1302 branch.
1303
1303
1304 Unless -f/--force is specified, branch will not let you set a
1304 Unless -f/--force is specified, branch will not let you set a
1305 branch name that already exists.
1305 branch name that already exists.
1306
1306
1307 Use -C/--clean to reset the working directory branch to that of
1307 Use -C/--clean to reset the working directory branch to that of
1308 the parent of the working directory, negating a previous branch
1308 the parent of the working directory, negating a previous branch
1309 change.
1309 change.
1310
1310
1311 Use the command :hg:`update` to switch to an existing branch. Use
1311 Use the command :hg:`update` to switch to an existing branch. Use
1312 :hg:`commit --close-branch` to mark this branch head as closed.
1312 :hg:`commit --close-branch` to mark this branch head as closed.
1313 When all heads of a branch are closed, the branch will be
1313 When all heads of a branch are closed, the branch will be
1314 considered closed.
1314 considered closed.
1315
1315
1316 Returns 0 on success.
1316 Returns 0 on success.
1317 """
1317 """
1318 opts = pycompat.byteskwargs(opts)
1318 opts = pycompat.byteskwargs(opts)
1319 revs = opts.get(b'rev')
1319 revs = opts.get(b'rev')
1320 if label:
1320 if label:
1321 label = label.strip()
1321 label = label.strip()
1322
1322
1323 if not opts.get(b'clean') and not label:
1323 if not opts.get(b'clean') and not label:
1324 if revs:
1324 if revs:
1325 raise error.Abort(_(b"no branch name specified for the revisions"))
1325 raise error.Abort(_(b"no branch name specified for the revisions"))
1326 ui.write(b"%s\n" % repo.dirstate.branch())
1326 ui.write(b"%s\n" % repo.dirstate.branch())
1327 return
1327 return
1328
1328
1329 with repo.wlock():
1329 with repo.wlock():
1330 if opts.get(b'clean'):
1330 if opts.get(b'clean'):
1331 label = repo[b'.'].branch()
1331 label = repo[b'.'].branch()
1332 repo.dirstate.setbranch(label)
1332 repo.dirstate.setbranch(label)
1333 ui.status(_(b'reset working directory to branch %s\n') % label)
1333 ui.status(_(b'reset working directory to branch %s\n') % label)
1334 elif label:
1334 elif label:
1335
1335
1336 scmutil.checknewlabel(repo, label, b'branch')
1336 scmutil.checknewlabel(repo, label, b'branch')
1337 if revs:
1337 if revs:
1338 return cmdutil.changebranch(ui, repo, revs, label, opts)
1338 return cmdutil.changebranch(ui, repo, revs, label, opts)
1339
1339
1340 if not opts.get(b'force') and label in repo.branchmap():
1340 if not opts.get(b'force') and label in repo.branchmap():
1341 if label not in [p.branch() for p in repo[None].parents()]:
1341 if label not in [p.branch() for p in repo[None].parents()]:
1342 raise error.Abort(
1342 raise error.Abort(
1343 _(b'a branch of the same name already exists'),
1343 _(b'a branch of the same name already exists'),
1344 # i18n: "it" refers to an existing branch
1344 # i18n: "it" refers to an existing branch
1345 hint=_(b"use 'hg update' to switch to it"),
1345 hint=_(b"use 'hg update' to switch to it"),
1346 )
1346 )
1347
1347
1348 repo.dirstate.setbranch(label)
1348 repo.dirstate.setbranch(label)
1349 ui.status(_(b'marked working directory as branch %s\n') % label)
1349 ui.status(_(b'marked working directory as branch %s\n') % label)
1350
1350
1351 # find any open named branches aside from default
1351 # find any open named branches aside from default
1352 for n, h, t, c in repo.branchmap().iterbranches():
1352 for n, h, t, c in repo.branchmap().iterbranches():
1353 if n != b"default" and not c:
1353 if n != b"default" and not c:
1354 return 0
1354 return 0
1355 ui.status(
1355 ui.status(
1356 _(
1356 _(
1357 b'(branches are permanent and global, '
1357 b'(branches are permanent and global, '
1358 b'did you want a bookmark?)\n'
1358 b'did you want a bookmark?)\n'
1359 )
1359 )
1360 )
1360 )
1361
1361
1362
1362
1363 @command(
1363 @command(
1364 b'branches',
1364 b'branches',
1365 [
1365 [
1366 (
1366 (
1367 b'a',
1367 b'a',
1368 b'active',
1368 b'active',
1369 False,
1369 False,
1370 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1370 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1371 ),
1371 ),
1372 (b'c', b'closed', False, _(b'show normal and closed branches')),
1372 (b'c', b'closed', False, _(b'show normal and closed branches')),
1373 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1373 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1374 ]
1374 ]
1375 + formatteropts,
1375 + formatteropts,
1376 _(b'[-c]'),
1376 _(b'[-c]'),
1377 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1377 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1378 intents={INTENT_READONLY},
1378 intents={INTENT_READONLY},
1379 )
1379 )
1380 def branches(ui, repo, active=False, closed=False, **opts):
1380 def branches(ui, repo, active=False, closed=False, **opts):
1381 """list repository named branches
1381 """list repository named branches
1382
1382
1383 List the repository's named branches, indicating which ones are
1383 List the repository's named branches, indicating which ones are
1384 inactive. If -c/--closed is specified, also list branches which have
1384 inactive. If -c/--closed is specified, also list branches which have
1385 been marked closed (see :hg:`commit --close-branch`).
1385 been marked closed (see :hg:`commit --close-branch`).
1386
1386
1387 Use the command :hg:`update` to switch to an existing branch.
1387 Use the command :hg:`update` to switch to an existing branch.
1388
1388
1389 .. container:: verbose
1389 .. container:: verbose
1390
1390
1391 Template:
1391 Template:
1392
1392
1393 The following keywords are supported in addition to the common template
1393 The following keywords are supported in addition to the common template
1394 keywords and functions such as ``{branch}``. See also
1394 keywords and functions such as ``{branch}``. See also
1395 :hg:`help templates`.
1395 :hg:`help templates`.
1396
1396
1397 :active: Boolean. True if the branch is active.
1397 :active: Boolean. True if the branch is active.
1398 :closed: Boolean. True if the branch is closed.
1398 :closed: Boolean. True if the branch is closed.
1399 :current: Boolean. True if it is the current branch.
1399 :current: Boolean. True if it is the current branch.
1400
1400
1401 Returns 0.
1401 Returns 0.
1402 """
1402 """
1403
1403
1404 opts = pycompat.byteskwargs(opts)
1404 opts = pycompat.byteskwargs(opts)
1405 revs = opts.get(b'rev')
1405 revs = opts.get(b'rev')
1406 selectedbranches = None
1406 selectedbranches = None
1407 if revs:
1407 if revs:
1408 revs = scmutil.revrange(repo, revs)
1408 revs = scmutil.revrange(repo, revs)
1409 getbi = repo.revbranchcache().branchinfo
1409 getbi = repo.revbranchcache().branchinfo
1410 selectedbranches = {getbi(r)[0] for r in revs}
1410 selectedbranches = {getbi(r)[0] for r in revs}
1411
1411
1412 ui.pager(b'branches')
1412 ui.pager(b'branches')
1413 fm = ui.formatter(b'branches', opts)
1413 fm = ui.formatter(b'branches', opts)
1414 hexfunc = fm.hexfunc
1414 hexfunc = fm.hexfunc
1415
1415
1416 allheads = set(repo.heads())
1416 allheads = set(repo.heads())
1417 branches = []
1417 branches = []
1418 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1418 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1419 if selectedbranches is not None and tag not in selectedbranches:
1419 if selectedbranches is not None and tag not in selectedbranches:
1420 continue
1420 continue
1421 isactive = False
1421 isactive = False
1422 if not isclosed:
1422 if not isclosed:
1423 openheads = set(repo.branchmap().iteropen(heads))
1423 openheads = set(repo.branchmap().iteropen(heads))
1424 isactive = bool(openheads & allheads)
1424 isactive = bool(openheads & allheads)
1425 branches.append((tag, repo[tip], isactive, not isclosed))
1425 branches.append((tag, repo[tip], isactive, not isclosed))
1426 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1426 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1427
1427
1428 for tag, ctx, isactive, isopen in branches:
1428 for tag, ctx, isactive, isopen in branches:
1429 if active and not isactive:
1429 if active and not isactive:
1430 continue
1430 continue
1431 if isactive:
1431 if isactive:
1432 label = b'branches.active'
1432 label = b'branches.active'
1433 notice = b''
1433 notice = b''
1434 elif not isopen:
1434 elif not isopen:
1435 if not closed:
1435 if not closed:
1436 continue
1436 continue
1437 label = b'branches.closed'
1437 label = b'branches.closed'
1438 notice = _(b' (closed)')
1438 notice = _(b' (closed)')
1439 else:
1439 else:
1440 label = b'branches.inactive'
1440 label = b'branches.inactive'
1441 notice = _(b' (inactive)')
1441 notice = _(b' (inactive)')
1442 current = tag == repo.dirstate.branch()
1442 current = tag == repo.dirstate.branch()
1443 if current:
1443 if current:
1444 label = b'branches.current'
1444 label = b'branches.current'
1445
1445
1446 fm.startitem()
1446 fm.startitem()
1447 fm.write(b'branch', b'%s', tag, label=label)
1447 fm.write(b'branch', b'%s', tag, label=label)
1448 rev = ctx.rev()
1448 rev = ctx.rev()
1449 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1449 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1450 fmt = b' ' * padsize + b' %d:%s'
1450 fmt = b' ' * padsize + b' %d:%s'
1451 fm.condwrite(
1451 fm.condwrite(
1452 not ui.quiet,
1452 not ui.quiet,
1453 b'rev node',
1453 b'rev node',
1454 fmt,
1454 fmt,
1455 rev,
1455 rev,
1456 hexfunc(ctx.node()),
1456 hexfunc(ctx.node()),
1457 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1457 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1458 )
1458 )
1459 fm.context(ctx=ctx)
1459 fm.context(ctx=ctx)
1460 fm.data(active=isactive, closed=not isopen, current=current)
1460 fm.data(active=isactive, closed=not isopen, current=current)
1461 if not ui.quiet:
1461 if not ui.quiet:
1462 fm.plain(notice)
1462 fm.plain(notice)
1463 fm.plain(b'\n')
1463 fm.plain(b'\n')
1464 fm.end()
1464 fm.end()
1465
1465
1466
1466
1467 @command(
1467 @command(
1468 b'bundle',
1468 b'bundle',
1469 [
1469 [
1470 (
1470 (
1471 b'f',
1471 b'f',
1472 b'force',
1472 b'force',
1473 None,
1473 None,
1474 _(b'run even when the destination is unrelated'),
1474 _(b'run even when the destination is unrelated'),
1475 ),
1475 ),
1476 (
1476 (
1477 b'r',
1477 b'r',
1478 b'rev',
1478 b'rev',
1479 [],
1479 [],
1480 _(b'a changeset intended to be added to the destination'),
1480 _(b'a changeset intended to be added to the destination'),
1481 _(b'REV'),
1481 _(b'REV'),
1482 ),
1482 ),
1483 (
1483 (
1484 b'b',
1484 b'b',
1485 b'branch',
1485 b'branch',
1486 [],
1486 [],
1487 _(b'a specific branch you would like to bundle'),
1487 _(b'a specific branch you would like to bundle'),
1488 _(b'BRANCH'),
1488 _(b'BRANCH'),
1489 ),
1489 ),
1490 (
1490 (
1491 b'',
1491 b'',
1492 b'base',
1492 b'base',
1493 [],
1493 [],
1494 _(b'a base changeset assumed to be available at the destination'),
1494 _(b'a base changeset assumed to be available at the destination'),
1495 _(b'REV'),
1495 _(b'REV'),
1496 ),
1496 ),
1497 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1497 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1498 (
1498 (
1499 b't',
1499 b't',
1500 b'type',
1500 b'type',
1501 b'bzip2',
1501 b'bzip2',
1502 _(b'bundle compression type to use'),
1502 _(b'bundle compression type to use'),
1503 _(b'TYPE'),
1503 _(b'TYPE'),
1504 ),
1504 ),
1505 ]
1505 ]
1506 + remoteopts,
1506 + remoteopts,
1507 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1507 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1508 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1508 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1509 )
1509 )
1510 def bundle(ui, repo, fname, dest=None, **opts):
1510 def bundle(ui, repo, fname, dest=None, **opts):
1511 """create a bundle file
1511 """create a bundle file
1512
1512
1513 Generate a bundle file containing data to be transferred to another
1513 Generate a bundle file containing data to be transferred to another
1514 repository.
1514 repository.
1515
1515
1516 To create a bundle containing all changesets, use -a/--all
1516 To create a bundle containing all changesets, use -a/--all
1517 (or --base null). Otherwise, hg assumes the destination will have
1517 (or --base null). Otherwise, hg assumes the destination will have
1518 all the nodes you specify with --base parameters. Otherwise, hg
1518 all the nodes you specify with --base parameters. Otherwise, hg
1519 will assume the repository has all the nodes in destination, or
1519 will assume the repository has all the nodes in destination, or
1520 default-push/default if no destination is specified, where destination
1520 default-push/default if no destination is specified, where destination
1521 is the repository you provide through DEST option.
1521 is the repository you provide through DEST option.
1522
1522
1523 You can change bundle format with the -t/--type option. See
1523 You can change bundle format with the -t/--type option. See
1524 :hg:`help bundlespec` for documentation on this format. By default,
1524 :hg:`help bundlespec` for documentation on this format. By default,
1525 the most appropriate format is used and compression defaults to
1525 the most appropriate format is used and compression defaults to
1526 bzip2.
1526 bzip2.
1527
1527
1528 The bundle file can then be transferred using conventional means
1528 The bundle file can then be transferred using conventional means
1529 and applied to another repository with the unbundle or pull
1529 and applied to another repository with the unbundle or pull
1530 command. This is useful when direct push and pull are not
1530 command. This is useful when direct push and pull are not
1531 available or when exporting an entire repository is undesirable.
1531 available or when exporting an entire repository is undesirable.
1532
1532
1533 Applying bundles preserves all changeset contents including
1533 Applying bundles preserves all changeset contents including
1534 permissions, copy/rename information, and revision history.
1534 permissions, copy/rename information, and revision history.
1535
1535
1536 Returns 0 on success, 1 if no changes found.
1536 Returns 0 on success, 1 if no changes found.
1537 """
1537 """
1538 opts = pycompat.byteskwargs(opts)
1538 opts = pycompat.byteskwargs(opts)
1539 revs = None
1539 revs = None
1540 if b'rev' in opts:
1540 if b'rev' in opts:
1541 revstrings = opts[b'rev']
1541 revstrings = opts[b'rev']
1542 revs = scmutil.revrange(repo, revstrings)
1542 revs = scmutil.revrange(repo, revstrings)
1543 if revstrings and not revs:
1543 if revstrings and not revs:
1544 raise error.Abort(_(b'no commits to bundle'))
1544 raise error.Abort(_(b'no commits to bundle'))
1545
1545
1546 bundletype = opts.get(b'type', b'bzip2').lower()
1546 bundletype = opts.get(b'type', b'bzip2').lower()
1547 try:
1547 try:
1548 bundlespec = bundlecaches.parsebundlespec(
1548 bundlespec = bundlecaches.parsebundlespec(
1549 repo, bundletype, strict=False
1549 repo, bundletype, strict=False
1550 )
1550 )
1551 except error.UnsupportedBundleSpecification as e:
1551 except error.UnsupportedBundleSpecification as e:
1552 raise error.Abort(
1552 raise error.Abort(
1553 pycompat.bytestr(e),
1553 pycompat.bytestr(e),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1555 )
1555 )
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1557
1557
1558 # Packed bundles are a pseudo bundle format for now.
1558 # Packed bundles are a pseudo bundle format for now.
1559 if cgversion == b's1':
1559 if cgversion == b's1':
1560 raise error.Abort(
1560 raise error.Abort(
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1563 )
1563 )
1564
1564
1565 if opts.get(b'all'):
1565 if opts.get(b'all'):
1566 if dest:
1566 if dest:
1567 raise error.Abort(
1567 raise error.Abort(
1568 _(b"--all is incompatible with specifying a destination")
1568 _(b"--all is incompatible with specifying a destination")
1569 )
1569 )
1570 if opts.get(b'base'):
1570 if opts.get(b'base'):
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1572 base = [nullrev]
1572 base = [nullrev]
1573 else:
1573 else:
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1576 raise error.Abort(
1576 raise error.Abort(
1577 _(b"repository does not support bundle version %s") % cgversion
1577 _(b"repository does not support bundle version %s") % cgversion
1578 )
1578 )
1579
1579
1580 if base:
1580 if base:
1581 if dest:
1581 if dest:
1582 raise error.Abort(
1582 raise error.Abort(
1583 _(b"--base is incompatible with specifying a destination")
1583 _(b"--base is incompatible with specifying a destination")
1584 )
1584 )
1585 common = [repo[rev].node() for rev in base]
1585 common = [repo[rev].node() for rev in base]
1586 heads = [repo[r].node() for r in revs] if revs else None
1586 heads = [repo[r].node() for r in revs] if revs else None
1587 outgoing = discovery.outgoing(repo, common, heads)
1587 outgoing = discovery.outgoing(repo, common, heads)
1588 else:
1588 else:
1589 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1589 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1591 other = hg.peer(repo, opts, dest)
1591 other = hg.peer(repo, opts, dest)
1592 revs = [repo[r].hex() for r in revs]
1592 revs = [repo[r].hex() for r in revs]
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1595 outgoing = discovery.findcommonoutgoing(
1595 outgoing = discovery.findcommonoutgoing(
1596 repo,
1596 repo,
1597 other,
1597 other,
1598 onlyheads=heads,
1598 onlyheads=heads,
1599 force=opts.get(b'force'),
1599 force=opts.get(b'force'),
1600 portable=True,
1600 portable=True,
1601 )
1601 )
1602
1602
1603 if not outgoing.missing:
1603 if not outgoing.missing:
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1605 return 1
1605 return 1
1606
1606
1607 if cgversion == b'01': # bundle1
1607 if cgversion == b'01': # bundle1
1608 bversion = b'HG10' + bundlespec.wirecompression
1608 bversion = b'HG10' + bundlespec.wirecompression
1609 bcompression = None
1609 bcompression = None
1610 elif cgversion in (b'02', b'03'):
1610 elif cgversion in (b'02', b'03'):
1611 bversion = b'HG20'
1611 bversion = b'HG20'
1612 bcompression = bundlespec.wirecompression
1612 bcompression = bundlespec.wirecompression
1613 else:
1613 else:
1614 raise error.ProgrammingError(
1614 raise error.ProgrammingError(
1615 b'bundle: unexpected changegroup version %s' % cgversion
1615 b'bundle: unexpected changegroup version %s' % cgversion
1616 )
1616 )
1617
1617
1618 # TODO compression options should be derived from bundlespec parsing.
1618 # TODO compression options should be derived from bundlespec parsing.
1619 # This is a temporary hack to allow adjusting bundle compression
1619 # This is a temporary hack to allow adjusting bundle compression
1620 # level without a) formalizing the bundlespec changes to declare it
1620 # level without a) formalizing the bundlespec changes to declare it
1621 # b) introducing a command flag.
1621 # b) introducing a command flag.
1622 compopts = {}
1622 compopts = {}
1623 complevel = ui.configint(
1623 complevel = ui.configint(
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1625 )
1625 )
1626 if complevel is None:
1626 if complevel is None:
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1628 if complevel is not None:
1628 if complevel is not None:
1629 compopts[b'level'] = complevel
1629 compopts[b'level'] = complevel
1630
1630
1631 # Allow overriding the bundling of obsmarker in phases through
1631 # Allow overriding the bundling of obsmarker in phases through
1632 # configuration while we don't have a bundle version that include them
1632 # configuration while we don't have a bundle version that include them
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1634 bundlespec.contentopts[b'obsolescence'] = True
1634 bundlespec.contentopts[b'obsolescence'] = True
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1636 bundlespec.contentopts[b'phases'] = True
1636 bundlespec.contentopts[b'phases'] = True
1637
1637
1638 bundle2.writenewbundle(
1638 bundle2.writenewbundle(
1639 ui,
1639 ui,
1640 repo,
1640 repo,
1641 b'bundle',
1641 b'bundle',
1642 fname,
1642 fname,
1643 bversion,
1643 bversion,
1644 outgoing,
1644 outgoing,
1645 bundlespec.contentopts,
1645 bundlespec.contentopts,
1646 compression=bcompression,
1646 compression=bcompression,
1647 compopts=compopts,
1647 compopts=compopts,
1648 )
1648 )
1649
1649
1650
1650
1651 @command(
1651 @command(
1652 b'cat',
1652 b'cat',
1653 [
1653 [
1654 (
1654 (
1655 b'o',
1655 b'o',
1656 b'output',
1656 b'output',
1657 b'',
1657 b'',
1658 _(b'print output to file with formatted name'),
1658 _(b'print output to file with formatted name'),
1659 _(b'FORMAT'),
1659 _(b'FORMAT'),
1660 ),
1660 ),
1661 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1661 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1663 ]
1663 ]
1664 + walkopts
1664 + walkopts
1665 + formatteropts,
1665 + formatteropts,
1666 _(b'[OPTION]... FILE...'),
1666 _(b'[OPTION]... FILE...'),
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1668 inferrepo=True,
1668 inferrepo=True,
1669 intents={INTENT_READONLY},
1669 intents={INTENT_READONLY},
1670 )
1670 )
1671 def cat(ui, repo, file1, *pats, **opts):
1671 def cat(ui, repo, file1, *pats, **opts):
1672 """output the current or given revision of files
1672 """output the current or given revision of files
1673
1673
1674 Print the specified files as they were at the given revision. If
1674 Print the specified files as they were at the given revision. If
1675 no revision is given, the parent of the working directory is used.
1675 no revision is given, the parent of the working directory is used.
1676
1676
1677 Output may be to a file, in which case the name of the file is
1677 Output may be to a file, in which case the name of the file is
1678 given using a template string. See :hg:`help templates`. In addition
1678 given using a template string. See :hg:`help templates`. In addition
1679 to the common template keywords, the following formatting rules are
1679 to the common template keywords, the following formatting rules are
1680 supported:
1680 supported:
1681
1681
1682 :``%%``: literal "%" character
1682 :``%%``: literal "%" character
1683 :``%s``: basename of file being printed
1683 :``%s``: basename of file being printed
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1685 :``%p``: root-relative path name of file being printed
1685 :``%p``: root-relative path name of file being printed
1686 :``%H``: changeset hash (40 hexadecimal digits)
1686 :``%H``: changeset hash (40 hexadecimal digits)
1687 :``%R``: changeset revision number
1687 :``%R``: changeset revision number
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1689 :``%r``: zero-padded changeset revision number
1689 :``%r``: zero-padded changeset revision number
1690 :``%b``: basename of the exporting repository
1690 :``%b``: basename of the exporting repository
1691 :``\\``: literal "\\" character
1691 :``\\``: literal "\\" character
1692
1692
1693 .. container:: verbose
1693 .. container:: verbose
1694
1694
1695 Template:
1695 Template:
1696
1696
1697 The following keywords are supported in addition to the common template
1697 The following keywords are supported in addition to the common template
1698 keywords and functions. See also :hg:`help templates`.
1698 keywords and functions. See also :hg:`help templates`.
1699
1699
1700 :data: String. File content.
1700 :data: String. File content.
1701 :path: String. Repository-absolute path of the file.
1701 :path: String. Repository-absolute path of the file.
1702
1702
1703 Returns 0 on success.
1703 Returns 0 on success.
1704 """
1704 """
1705 opts = pycompat.byteskwargs(opts)
1705 opts = pycompat.byteskwargs(opts)
1706 rev = opts.get(b'rev')
1706 rev = opts.get(b'rev')
1707 if rev:
1707 if rev:
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1709 ctx = scmutil.revsingle(repo, rev)
1709 ctx = scmutil.revsingle(repo, rev)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1711 fntemplate = opts.pop(b'output', b'')
1711 fntemplate = opts.pop(b'output', b'')
1712 if cmdutil.isstdiofilename(fntemplate):
1712 if cmdutil.isstdiofilename(fntemplate):
1713 fntemplate = b''
1713 fntemplate = b''
1714
1714
1715 if fntemplate:
1715 if fntemplate:
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1717 else:
1717 else:
1718 ui.pager(b'cat')
1718 ui.pager(b'cat')
1719 fm = ui.formatter(b'cat', opts)
1719 fm = ui.formatter(b'cat', opts)
1720 with fm:
1720 with fm:
1721 return cmdutil.cat(
1721 return cmdutil.cat(
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1723 )
1723 )
1724
1724
1725
1725
1726 @command(
1726 @command(
1727 b'clone',
1727 b'clone',
1728 [
1728 [
1729 (
1729 (
1730 b'U',
1730 b'U',
1731 b'noupdate',
1731 b'noupdate',
1732 None,
1732 None,
1733 _(
1733 _(
1734 b'the clone will include an empty working '
1734 b'the clone will include an empty working '
1735 b'directory (only a repository)'
1735 b'directory (only a repository)'
1736 ),
1736 ),
1737 ),
1737 ),
1738 (
1738 (
1739 b'u',
1739 b'u',
1740 b'updaterev',
1740 b'updaterev',
1741 b'',
1741 b'',
1742 _(b'revision, tag, or branch to check out'),
1742 _(b'revision, tag, or branch to check out'),
1743 _(b'REV'),
1743 _(b'REV'),
1744 ),
1744 ),
1745 (
1745 (
1746 b'r',
1746 b'r',
1747 b'rev',
1747 b'rev',
1748 [],
1748 [],
1749 _(
1749 _(
1750 b'do not clone everything, but include this changeset'
1750 b'do not clone everything, but include this changeset'
1751 b' and its ancestors'
1751 b' and its ancestors'
1752 ),
1752 ),
1753 _(b'REV'),
1753 _(b'REV'),
1754 ),
1754 ),
1755 (
1755 (
1756 b'b',
1756 b'b',
1757 b'branch',
1757 b'branch',
1758 [],
1758 [],
1759 _(
1759 _(
1760 b'do not clone everything, but include this branch\'s'
1760 b'do not clone everything, but include this branch\'s'
1761 b' changesets and their ancestors'
1761 b' changesets and their ancestors'
1762 ),
1762 ),
1763 _(b'BRANCH'),
1763 _(b'BRANCH'),
1764 ),
1764 ),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1768 ]
1768 ]
1769 + remoteopts,
1769 + remoteopts,
1770 _(b'[OPTION]... SOURCE [DEST]'),
1770 _(b'[OPTION]... SOURCE [DEST]'),
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1772 helpbasic=True,
1772 helpbasic=True,
1773 norepo=True,
1773 norepo=True,
1774 )
1774 )
1775 def clone(ui, source, dest=None, **opts):
1775 def clone(ui, source, dest=None, **opts):
1776 """make a copy of an existing repository
1776 """make a copy of an existing repository
1777
1777
1778 Create a copy of an existing repository in a new directory.
1778 Create a copy of an existing repository in a new directory.
1779
1779
1780 If no destination directory name is specified, it defaults to the
1780 If no destination directory name is specified, it defaults to the
1781 basename of the source.
1781 basename of the source.
1782
1782
1783 The location of the source is added to the new repository's
1783 The location of the source is added to the new repository's
1784 ``.hg/hgrc`` file, as the default to be used for future pulls.
1784 ``.hg/hgrc`` file, as the default to be used for future pulls.
1785
1785
1786 Only local paths and ``ssh://`` URLs are supported as
1786 Only local paths and ``ssh://`` URLs are supported as
1787 destinations. For ``ssh://`` destinations, no working directory or
1787 destinations. For ``ssh://`` destinations, no working directory or
1788 ``.hg/hgrc`` will be created on the remote side.
1788 ``.hg/hgrc`` will be created on the remote side.
1789
1789
1790 If the source repository has a bookmark called '@' set, that
1790 If the source repository has a bookmark called '@' set, that
1791 revision will be checked out in the new repository by default.
1791 revision will be checked out in the new repository by default.
1792
1792
1793 To check out a particular version, use -u/--update, or
1793 To check out a particular version, use -u/--update, or
1794 -U/--noupdate to create a clone with no working directory.
1794 -U/--noupdate to create a clone with no working directory.
1795
1795
1796 To pull only a subset of changesets, specify one or more revisions
1796 To pull only a subset of changesets, specify one or more revisions
1797 identifiers with -r/--rev or branches with -b/--branch. The
1797 identifiers with -r/--rev or branches with -b/--branch. The
1798 resulting clone will contain only the specified changesets and
1798 resulting clone will contain only the specified changesets and
1799 their ancestors. These options (or 'clone src#rev dest') imply
1799 their ancestors. These options (or 'clone src#rev dest') imply
1800 --pull, even for local source repositories.
1800 --pull, even for local source repositories.
1801
1801
1802 In normal clone mode, the remote normalizes repository data into a common
1802 In normal clone mode, the remote normalizes repository data into a common
1803 exchange format and the receiving end translates this data into its local
1803 exchange format and the receiving end translates this data into its local
1804 storage format. --stream activates a different clone mode that essentially
1804 storage format. --stream activates a different clone mode that essentially
1805 copies repository files from the remote with minimal data processing. This
1805 copies repository files from the remote with minimal data processing. This
1806 significantly reduces the CPU cost of a clone both remotely and locally.
1806 significantly reduces the CPU cost of a clone both remotely and locally.
1807 However, it often increases the transferred data size by 30-40%. This can
1807 However, it often increases the transferred data size by 30-40%. This can
1808 result in substantially faster clones where I/O throughput is plentiful,
1808 result in substantially faster clones where I/O throughput is plentiful,
1809 especially for larger repositories. A side-effect of --stream clones is
1809 especially for larger repositories. A side-effect of --stream clones is
1810 that storage settings and requirements on the remote are applied locally:
1810 that storage settings and requirements on the remote are applied locally:
1811 a modern client may inherit legacy or inefficient storage used by the
1811 a modern client may inherit legacy or inefficient storage used by the
1812 remote or a legacy Mercurial client may not be able to clone from a
1812 remote or a legacy Mercurial client may not be able to clone from a
1813 modern Mercurial remote.
1813 modern Mercurial remote.
1814
1814
1815 .. note::
1815 .. note::
1816
1816
1817 Specifying a tag will include the tagged changeset but not the
1817 Specifying a tag will include the tagged changeset but not the
1818 changeset containing the tag.
1818 changeset containing the tag.
1819
1819
1820 .. container:: verbose
1820 .. container:: verbose
1821
1821
1822 For efficiency, hardlinks are used for cloning whenever the
1822 For efficiency, hardlinks are used for cloning whenever the
1823 source and destination are on the same filesystem (note this
1823 source and destination are on the same filesystem (note this
1824 applies only to the repository data, not to the working
1824 applies only to the repository data, not to the working
1825 directory). Some filesystems, such as AFS, implement hardlinking
1825 directory). Some filesystems, such as AFS, implement hardlinking
1826 incorrectly, but do not report errors. In these cases, use the
1826 incorrectly, but do not report errors. In these cases, use the
1827 --pull option to avoid hardlinking.
1827 --pull option to avoid hardlinking.
1828
1828
1829 Mercurial will update the working directory to the first applicable
1829 Mercurial will update the working directory to the first applicable
1830 revision from this list:
1830 revision from this list:
1831
1831
1832 a) null if -U or the source repository has no changesets
1832 a) null if -U or the source repository has no changesets
1833 b) if -u . and the source repository is local, the first parent of
1833 b) if -u . and the source repository is local, the first parent of
1834 the source repository's working directory
1834 the source repository's working directory
1835 c) the changeset specified with -u (if a branch name, this means the
1835 c) the changeset specified with -u (if a branch name, this means the
1836 latest head of that branch)
1836 latest head of that branch)
1837 d) the changeset specified with -r
1837 d) the changeset specified with -r
1838 e) the tipmost head specified with -b
1838 e) the tipmost head specified with -b
1839 f) the tipmost head specified with the url#branch source syntax
1839 f) the tipmost head specified with the url#branch source syntax
1840 g) the revision marked with the '@' bookmark, if present
1840 g) the revision marked with the '@' bookmark, if present
1841 h) the tipmost head of the default branch
1841 h) the tipmost head of the default branch
1842 i) tip
1842 i) tip
1843
1843
1844 When cloning from servers that support it, Mercurial may fetch
1844 When cloning from servers that support it, Mercurial may fetch
1845 pre-generated data from a server-advertised URL or inline from the
1845 pre-generated data from a server-advertised URL or inline from the
1846 same stream. When this is done, hooks operating on incoming changesets
1846 same stream. When this is done, hooks operating on incoming changesets
1847 and changegroups may fire more than once, once for each pre-generated
1847 and changegroups may fire more than once, once for each pre-generated
1848 bundle and as well as for any additional remaining data. In addition,
1848 bundle and as well as for any additional remaining data. In addition,
1849 if an error occurs, the repository may be rolled back to a partial
1849 if an error occurs, the repository may be rolled back to a partial
1850 clone. This behavior may change in future releases.
1850 clone. This behavior may change in future releases.
1851 See :hg:`help -e clonebundles` for more.
1851 See :hg:`help -e clonebundles` for more.
1852
1852
1853 Examples:
1853 Examples:
1854
1854
1855 - clone a remote repository to a new directory named hg/::
1855 - clone a remote repository to a new directory named hg/::
1856
1856
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1858
1858
1859 - create a lightweight local clone::
1859 - create a lightweight local clone::
1860
1860
1861 hg clone project/ project-feature/
1861 hg clone project/ project-feature/
1862
1862
1863 - clone from an absolute path on an ssh server (note double-slash)::
1863 - clone from an absolute path on an ssh server (note double-slash)::
1864
1864
1865 hg clone ssh://user@server//home/projects/alpha/
1865 hg clone ssh://user@server//home/projects/alpha/
1866
1866
1867 - do a streaming clone while checking out a specified version::
1867 - do a streaming clone while checking out a specified version::
1868
1868
1869 hg clone --stream http://server/repo -u 1.5
1869 hg clone --stream http://server/repo -u 1.5
1870
1870
1871 - create a repository without changesets after a particular revision::
1871 - create a repository without changesets after a particular revision::
1872
1872
1873 hg clone -r 04e544 experimental/ good/
1873 hg clone -r 04e544 experimental/ good/
1874
1874
1875 - clone (and track) a particular named branch::
1875 - clone (and track) a particular named branch::
1876
1876
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1878
1878
1879 See :hg:`help urls` for details on specifying URLs.
1879 See :hg:`help urls` for details on specifying URLs.
1880
1880
1881 Returns 0 on success.
1881 Returns 0 on success.
1882 """
1882 """
1883 opts = pycompat.byteskwargs(opts)
1883 opts = pycompat.byteskwargs(opts)
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1885
1885
1886 # --include/--exclude can come from narrow or sparse.
1886 # --include/--exclude can come from narrow or sparse.
1887 includepats, excludepats = None, None
1887 includepats, excludepats = None, None
1888
1888
1889 # hg.clone() differentiates between None and an empty set. So make sure
1889 # hg.clone() differentiates between None and an empty set. So make sure
1890 # patterns are sets if narrow is requested without patterns.
1890 # patterns are sets if narrow is requested without patterns.
1891 if opts.get(b'narrow'):
1891 if opts.get(b'narrow'):
1892 includepats = set()
1892 includepats = set()
1893 excludepats = set()
1893 excludepats = set()
1894
1894
1895 if opts.get(b'include'):
1895 if opts.get(b'include'):
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1897 if opts.get(b'exclude'):
1897 if opts.get(b'exclude'):
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1899
1899
1900 r = hg.clone(
1900 r = hg.clone(
1901 ui,
1901 ui,
1902 opts,
1902 opts,
1903 source,
1903 source,
1904 dest,
1904 dest,
1905 pull=opts.get(b'pull'),
1905 pull=opts.get(b'pull'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1907 revs=opts.get(b'rev'),
1907 revs=opts.get(b'rev'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1909 branch=opts.get(b'branch'),
1909 branch=opts.get(b'branch'),
1910 shareopts=opts.get(b'shareopts'),
1910 shareopts=opts.get(b'shareopts'),
1911 storeincludepats=includepats,
1911 storeincludepats=includepats,
1912 storeexcludepats=excludepats,
1912 storeexcludepats=excludepats,
1913 depth=opts.get(b'depth') or None,
1913 depth=opts.get(b'depth') or None,
1914 )
1914 )
1915
1915
1916 return r is None
1916 return r is None
1917
1917
1918
1918
1919 @command(
1919 @command(
1920 b'commit|ci',
1920 b'commit|ci',
1921 [
1921 [
1922 (
1922 (
1923 b'A',
1923 b'A',
1924 b'addremove',
1924 b'addremove',
1925 None,
1925 None,
1926 _(b'mark new/missing files as added/removed before committing'),
1926 _(b'mark new/missing files as added/removed before committing'),
1927 ),
1927 ),
1928 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1928 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1929 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1929 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1930 (b's', b'secret', None, _(b'use the secret phase for committing')),
1930 (b's', b'secret', None, _(b'use the secret phase for committing')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1932 (
1932 (
1933 b'',
1933 b'',
1934 b'force-close-branch',
1934 b'force-close-branch',
1935 None,
1935 None,
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1937 ),
1937 ),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1939 ]
1939 ]
1940 + walkopts
1940 + walkopts
1941 + commitopts
1941 + commitopts
1942 + commitopts2
1942 + commitopts2
1943 + subrepoopts,
1943 + subrepoopts,
1944 _(b'[OPTION]... [FILE]...'),
1944 _(b'[OPTION]... [FILE]...'),
1945 helpcategory=command.CATEGORY_COMMITTING,
1945 helpcategory=command.CATEGORY_COMMITTING,
1946 helpbasic=True,
1946 helpbasic=True,
1947 inferrepo=True,
1947 inferrepo=True,
1948 )
1948 )
1949 def commit(ui, repo, *pats, **opts):
1949 def commit(ui, repo, *pats, **opts):
1950 """commit the specified files or all outstanding changes
1950 """commit the specified files or all outstanding changes
1951
1951
1952 Commit changes to the given files into the repository. Unlike a
1952 Commit changes to the given files into the repository. Unlike a
1953 centralized SCM, this operation is a local operation. See
1953 centralized SCM, this operation is a local operation. See
1954 :hg:`push` for a way to actively distribute your changes.
1954 :hg:`push` for a way to actively distribute your changes.
1955
1955
1956 If a list of files is omitted, all changes reported by :hg:`status`
1956 If a list of files is omitted, all changes reported by :hg:`status`
1957 will be committed.
1957 will be committed.
1958
1958
1959 If you are committing the result of a merge, do not provide any
1959 If you are committing the result of a merge, do not provide any
1960 filenames or -I/-X filters.
1960 filenames or -I/-X filters.
1961
1961
1962 If no commit message is specified, Mercurial starts your
1962 If no commit message is specified, Mercurial starts your
1963 configured editor where you can enter a message. In case your
1963 configured editor where you can enter a message. In case your
1964 commit fails, you will find a backup of your message in
1964 commit fails, you will find a backup of your message in
1965 ``.hg/last-message.txt``.
1965 ``.hg/last-message.txt``.
1966
1966
1967 The --close-branch flag can be used to mark the current branch
1967 The --close-branch flag can be used to mark the current branch
1968 head closed. When all heads of a branch are closed, the branch
1968 head closed. When all heads of a branch are closed, the branch
1969 will be considered closed and no longer listed.
1969 will be considered closed and no longer listed.
1970
1970
1971 The --amend flag can be used to amend the parent of the
1971 The --amend flag can be used to amend the parent of the
1972 working directory with a new commit that contains the changes
1972 working directory with a new commit that contains the changes
1973 in the parent in addition to those currently reported by :hg:`status`,
1973 in the parent in addition to those currently reported by :hg:`status`,
1974 if there are any. The old commit is stored in a backup bundle in
1974 if there are any. The old commit is stored in a backup bundle in
1975 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1975 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1976 on how to restore it).
1976 on how to restore it).
1977
1977
1978 Message, user and date are taken from the amended commit unless
1978 Message, user and date are taken from the amended commit unless
1979 specified. When a message isn't specified on the command line,
1979 specified. When a message isn't specified on the command line,
1980 the editor will open with the message of the amended commit.
1980 the editor will open with the message of the amended commit.
1981
1981
1982 It is not possible to amend public changesets (see :hg:`help phases`)
1982 It is not possible to amend public changesets (see :hg:`help phases`)
1983 or changesets that have children.
1983 or changesets that have children.
1984
1984
1985 See :hg:`help dates` for a list of formats valid for -d/--date.
1985 See :hg:`help dates` for a list of formats valid for -d/--date.
1986
1986
1987 Returns 0 on success, 1 if nothing changed.
1987 Returns 0 on success, 1 if nothing changed.
1988
1988
1989 .. container:: verbose
1989 .. container:: verbose
1990
1990
1991 Examples:
1991 Examples:
1992
1992
1993 - commit all files ending in .py::
1993 - commit all files ending in .py::
1994
1994
1995 hg commit --include "set:**.py"
1995 hg commit --include "set:**.py"
1996
1996
1997 - commit all non-binary files::
1997 - commit all non-binary files::
1998
1998
1999 hg commit --exclude "set:binary()"
1999 hg commit --exclude "set:binary()"
2000
2000
2001 - amend the current commit and set the date to now::
2001 - amend the current commit and set the date to now::
2002
2002
2003 hg commit --amend --date now
2003 hg commit --amend --date now
2004 """
2004 """
2005 with repo.wlock(), repo.lock():
2005 with repo.wlock(), repo.lock():
2006 return _docommit(ui, repo, *pats, **opts)
2006 return _docommit(ui, repo, *pats, **opts)
2007
2007
2008
2008
2009 def _docommit(ui, repo, *pats, **opts):
2009 def _docommit(ui, repo, *pats, **opts):
2010 if opts.get('interactive'):
2010 if opts.get('interactive'):
2011 opts.pop('interactive')
2011 opts.pop('interactive')
2012 ret = cmdutil.dorecord(
2012 ret = cmdutil.dorecord(
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2014 )
2014 )
2015 # ret can be 0 (no changes to record) or the value returned by
2015 # ret can be 0 (no changes to record) or the value returned by
2016 # commit(), 1 if nothing changed or None on success.
2016 # commit(), 1 if nothing changed or None on success.
2017 return 1 if ret == 0 else ret
2017 return 1 if ret == 0 else ret
2018
2018
2019 opts = pycompat.byteskwargs(opts)
2019 opts = pycompat.byteskwargs(opts)
2020 if opts.get(b'subrepos'):
2020 if opts.get(b'subrepos'):
2021 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2021 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2022 # Let --subrepos on the command line override config setting.
2022 # Let --subrepos on the command line override config setting.
2023 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2023 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2024
2024
2025 cmdutil.checkunfinished(repo, commit=True)
2025 cmdutil.checkunfinished(repo, commit=True)
2026
2026
2027 branch = repo[None].branch()
2027 branch = repo[None].branch()
2028 bheads = repo.branchheads(branch)
2028 bheads = repo.branchheads(branch)
2029
2029
2030 extra = {}
2030 extra = {}
2031 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2031 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2032 extra[b'close'] = b'1'
2032 extra[b'close'] = b'1'
2033
2033
2034 if repo[b'.'].closesbranch():
2034 if repo[b'.'].closesbranch():
2035 raise error.Abort(
2035 raise error.Abort(
2036 _(b'current revision is already a branch closing head')
2036 _(b'current revision is already a branch closing head')
2037 )
2037 )
2038 elif not bheads:
2038 elif not bheads:
2039 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2039 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2040 elif (
2040 elif (
2041 branch == repo[b'.'].branch()
2041 branch == repo[b'.'].branch()
2042 and repo[b'.'].node() not in bheads
2042 and repo[b'.'].node() not in bheads
2043 and not opts.get(b'force_close_branch')
2043 and not opts.get(b'force_close_branch')
2044 ):
2044 ):
2045 hint = _(
2045 hint = _(
2046 b'use --force-close-branch to close branch from a non-head'
2046 b'use --force-close-branch to close branch from a non-head'
2047 b' changeset'
2047 b' changeset'
2048 )
2048 )
2049 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2049 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2050 elif opts.get(b'amend'):
2050 elif opts.get(b'amend'):
2051 if (
2051 if (
2052 repo[b'.'].p1().branch() != branch
2052 repo[b'.'].p1().branch() != branch
2053 and repo[b'.'].p2().branch() != branch
2053 and repo[b'.'].p2().branch() != branch
2054 ):
2054 ):
2055 raise error.Abort(_(b'can only close branch heads'))
2055 raise error.Abort(_(b'can only close branch heads'))
2056
2056
2057 if opts.get(b'amend'):
2057 if opts.get(b'amend'):
2058 if ui.configbool(b'ui', b'commitsubrepos'):
2058 if ui.configbool(b'ui', b'commitsubrepos'):
2059 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2059 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2060
2060
2061 old = repo[b'.']
2061 old = repo[b'.']
2062 rewriteutil.precheck(repo, [old.rev()], b'amend')
2062 rewriteutil.precheck(repo, [old.rev()], b'amend')
2063
2063
2064 # Currently histedit gets confused if an amend happens while histedit
2064 # Currently histedit gets confused if an amend happens while histedit
2065 # is in progress. Since we have a checkunfinished command, we are
2065 # is in progress. Since we have a checkunfinished command, we are
2066 # temporarily honoring it.
2066 # temporarily honoring it.
2067 #
2067 #
2068 # Note: eventually this guard will be removed. Please do not expect
2068 # Note: eventually this guard will be removed. Please do not expect
2069 # this behavior to remain.
2069 # this behavior to remain.
2070 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2070 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2071 cmdutil.checkunfinished(repo)
2071 cmdutil.checkunfinished(repo)
2072
2072
2073 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2073 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2074 if node == old.node():
2074 if node == old.node():
2075 ui.status(_(b"nothing changed\n"))
2075 ui.status(_(b"nothing changed\n"))
2076 return 1
2076 return 1
2077 else:
2077 else:
2078
2078
2079 def commitfunc(ui, repo, message, match, opts):
2079 def commitfunc(ui, repo, message, match, opts):
2080 overrides = {}
2080 overrides = {}
2081 if opts.get(b'secret'):
2081 if opts.get(b'secret'):
2082 overrides[(b'phases', b'new-commit')] = b'secret'
2082 overrides[(b'phases', b'new-commit')] = b'secret'
2083
2083
2084 baseui = repo.baseui
2084 baseui = repo.baseui
2085 with baseui.configoverride(overrides, b'commit'):
2085 with baseui.configoverride(overrides, b'commit'):
2086 with ui.configoverride(overrides, b'commit'):
2086 with ui.configoverride(overrides, b'commit'):
2087 editform = cmdutil.mergeeditform(
2087 editform = cmdutil.mergeeditform(
2088 repo[None], b'commit.normal'
2088 repo[None], b'commit.normal'
2089 )
2089 )
2090 editor = cmdutil.getcommiteditor(
2090 editor = cmdutil.getcommiteditor(
2091 editform=editform, **pycompat.strkwargs(opts)
2091 editform=editform, **pycompat.strkwargs(opts)
2092 )
2092 )
2093 return repo.commit(
2093 return repo.commit(
2094 message,
2094 message,
2095 opts.get(b'user'),
2095 opts.get(b'user'),
2096 opts.get(b'date'),
2096 opts.get(b'date'),
2097 match,
2097 match,
2098 editor=editor,
2098 editor=editor,
2099 extra=extra,
2099 extra=extra,
2100 )
2100 )
2101
2101
2102 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2102 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2103
2103
2104 if not node:
2104 if not node:
2105 stat = cmdutil.postcommitstatus(repo, pats, opts)
2105 stat = cmdutil.postcommitstatus(repo, pats, opts)
2106 if stat.deleted:
2106 if stat.deleted:
2107 ui.status(
2107 ui.status(
2108 _(
2108 _(
2109 b"nothing changed (%d missing files, see "
2109 b"nothing changed (%d missing files, see "
2110 b"'hg status')\n"
2110 b"'hg status')\n"
2111 )
2111 )
2112 % len(stat.deleted)
2112 % len(stat.deleted)
2113 )
2113 )
2114 else:
2114 else:
2115 ui.status(_(b"nothing changed\n"))
2115 ui.status(_(b"nothing changed\n"))
2116 return 1
2116 return 1
2117
2117
2118 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2118 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2119
2119
2120 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2120 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2121 status(
2121 status(
2122 ui,
2122 ui,
2123 repo,
2123 repo,
2124 modified=True,
2124 modified=True,
2125 added=True,
2125 added=True,
2126 removed=True,
2126 removed=True,
2127 deleted=True,
2127 deleted=True,
2128 unknown=True,
2128 unknown=True,
2129 subrepos=opts.get(b'subrepos'),
2129 subrepos=opts.get(b'subrepos'),
2130 )
2130 )
2131
2131
2132
2132
2133 @command(
2133 @command(
2134 b'config|showconfig|debugconfig',
2134 b'config|showconfig|debugconfig',
2135 [
2135 [
2136 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2136 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2137 (b'e', b'edit', None, _(b'edit user config')),
2137 (b'e', b'edit', None, _(b'edit user config')),
2138 (b'l', b'local', None, _(b'edit repository config')),
2138 (b'l', b'local', None, _(b'edit repository config')),
2139 (
2139 (
2140 b'',
2140 b'',
2141 b'shared',
2141 b'shared',
2142 None,
2142 None,
2143 _(b'edit shared source repository config (EXPERIMENTAL)'),
2143 _(b'edit shared source repository config (EXPERIMENTAL)'),
2144 ),
2144 ),
2145 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2145 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2146 (b'g', b'global', None, _(b'edit global config')),
2146 (b'g', b'global', None, _(b'edit global config')),
2147 ]
2147 ]
2148 + formatteropts,
2148 + formatteropts,
2149 _(b'[-u] [NAME]...'),
2149 _(b'[-u] [NAME]...'),
2150 helpcategory=command.CATEGORY_HELP,
2150 helpcategory=command.CATEGORY_HELP,
2151 optionalrepo=True,
2151 optionalrepo=True,
2152 intents={INTENT_READONLY},
2152 intents={INTENT_READONLY},
2153 )
2153 )
2154 def config(ui, repo, *values, **opts):
2154 def config(ui, repo, *values, **opts):
2155 """show combined config settings from all hgrc files
2155 """show combined config settings from all hgrc files
2156
2156
2157 With no arguments, print names and values of all config items.
2157 With no arguments, print names and values of all config items.
2158
2158
2159 With one argument of the form section.name, print just the value
2159 With one argument of the form section.name, print just the value
2160 of that config item.
2160 of that config item.
2161
2161
2162 With multiple arguments, print names and values of all config
2162 With multiple arguments, print names and values of all config
2163 items with matching section names or section.names.
2163 items with matching section names or section.names.
2164
2164
2165 With --edit, start an editor on the user-level config file. With
2165 With --edit, start an editor on the user-level config file. With
2166 --global, edit the system-wide config file. With --local, edit the
2166 --global, edit the system-wide config file. With --local, edit the
2167 repository-level config file.
2167 repository-level config file.
2168
2168
2169 With --debug, the source (filename and line number) is printed
2169 With --debug, the source (filename and line number) is printed
2170 for each config item.
2170 for each config item.
2171
2171
2172 See :hg:`help config` for more information about config files.
2172 See :hg:`help config` for more information about config files.
2173
2173
2174 .. container:: verbose
2174 .. container:: verbose
2175
2175
2176 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2176 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2177 This file is not shared across shares when in share-safe mode.
2177 This file is not shared across shares when in share-safe mode.
2178
2178
2179 Template:
2179 Template:
2180
2180
2181 The following keywords are supported. See also :hg:`help templates`.
2181 The following keywords are supported. See also :hg:`help templates`.
2182
2182
2183 :name: String. Config name.
2183 :name: String. Config name.
2184 :source: String. Filename and line number where the item is defined.
2184 :source: String. Filename and line number where the item is defined.
2185 :value: String. Config value.
2185 :value: String. Config value.
2186
2186
2187 The --shared flag can be used to edit the config file of shared source
2187 The --shared flag can be used to edit the config file of shared source
2188 repository. It only works when you have shared using the experimental
2188 repository. It only works when you have shared using the experimental
2189 share safe feature.
2189 share safe feature.
2190
2190
2191 Returns 0 on success, 1 if NAME does not exist.
2191 Returns 0 on success, 1 if NAME does not exist.
2192
2192
2193 """
2193 """
2194
2194
2195 opts = pycompat.byteskwargs(opts)
2195 opts = pycompat.byteskwargs(opts)
2196 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2196 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2197 if any(opts.get(o) for o in editopts):
2197 if any(opts.get(o) for o in editopts):
2198 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2198 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2199 if opts.get(b'local'):
2199 if opts.get(b'local'):
2200 if not repo:
2200 if not repo:
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2201 raise error.Abort(_(b"can't use --local outside a repository"))
2202 paths = [repo.vfs.join(b'hgrc')]
2202 paths = [repo.vfs.join(b'hgrc')]
2203 elif opts.get(b'global'):
2203 elif opts.get(b'global'):
2204 paths = rcutil.systemrcpath()
2204 paths = rcutil.systemrcpath()
2205 elif opts.get(b'shared'):
2205 elif opts.get(b'shared'):
2206 if not repo.shared():
2206 if not repo.shared():
2207 raise error.Abort(
2207 raise error.Abort(
2208 _(b"repository is not shared; can't use --shared")
2208 _(b"repository is not shared; can't use --shared")
2209 )
2209 )
2210 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2210 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2211 raise error.Abort(
2211 raise error.Abort(
2212 _(
2212 _(
2213 b"share safe feature not unabled; "
2213 b"share safe feature not unabled; "
2214 b"unable to edit shared source repository config"
2214 b"unable to edit shared source repository config"
2215 )
2215 )
2216 )
2216 )
2217 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2217 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2218 elif opts.get(b'non_shared'):
2218 elif opts.get(b'non_shared'):
2219 paths = [repo.vfs.join(b'hgrc-not-shared')]
2219 paths = [repo.vfs.join(b'hgrc-not-shared')]
2220 else:
2220 else:
2221 paths = rcutil.userrcpath()
2221 paths = rcutil.userrcpath()
2222
2222
2223 for f in paths:
2223 for f in paths:
2224 if os.path.exists(f):
2224 if os.path.exists(f):
2225 break
2225 break
2226 else:
2226 else:
2227 if opts.get(b'global'):
2227 if opts.get(b'global'):
2228 samplehgrc = uimod.samplehgrcs[b'global']
2228 samplehgrc = uimod.samplehgrcs[b'global']
2229 elif opts.get(b'local'):
2229 elif opts.get(b'local'):
2230 samplehgrc = uimod.samplehgrcs[b'local']
2230 samplehgrc = uimod.samplehgrcs[b'local']
2231 else:
2231 else:
2232 samplehgrc = uimod.samplehgrcs[b'user']
2232 samplehgrc = uimod.samplehgrcs[b'user']
2233
2233
2234 f = paths[0]
2234 f = paths[0]
2235 fp = open(f, b"wb")
2235 fp = open(f, b"wb")
2236 fp.write(util.tonativeeol(samplehgrc))
2236 fp.write(util.tonativeeol(samplehgrc))
2237 fp.close()
2237 fp.close()
2238
2238
2239 editor = ui.geteditor()
2239 editor = ui.geteditor()
2240 ui.system(
2240 ui.system(
2241 b"%s \"%s\"" % (editor, f),
2241 b"%s \"%s\"" % (editor, f),
2242 onerr=error.Abort,
2242 onerr=error.Abort,
2243 errprefix=_(b"edit failed"),
2243 errprefix=_(b"edit failed"),
2244 blockedtag=b'config_edit',
2244 blockedtag=b'config_edit',
2245 )
2245 )
2246 return
2246 return
2247 ui.pager(b'config')
2247 ui.pager(b'config')
2248 fm = ui.formatter(b'config', opts)
2248 fm = ui.formatter(b'config', opts)
2249 for t, f in rcutil.rccomponents():
2249 for t, f in rcutil.rccomponents():
2250 if t == b'path':
2250 if t == b'path':
2251 ui.debug(b'read config from: %s\n' % f)
2251 ui.debug(b'read config from: %s\n' % f)
2252 elif t == b'resource':
2252 elif t == b'resource':
2253 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2253 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2254 elif t == b'items':
2254 elif t == b'items':
2255 # Don't print anything for 'items'.
2255 # Don't print anything for 'items'.
2256 pass
2256 pass
2257 else:
2257 else:
2258 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2258 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2259 untrusted = bool(opts.get(b'untrusted'))
2259 untrusted = bool(opts.get(b'untrusted'))
2260
2260
2261 selsections = selentries = []
2261 selsections = selentries = []
2262 if values:
2262 if values:
2263 selsections = [v for v in values if b'.' not in v]
2263 selsections = [v for v in values if b'.' not in v]
2264 selentries = [v for v in values if b'.' in v]
2264 selentries = [v for v in values if b'.' in v]
2265 uniquesel = len(selentries) == 1 and not selsections
2265 uniquesel = len(selentries) == 1 and not selsections
2266 selsections = set(selsections)
2266 selsections = set(selsections)
2267 selentries = set(selentries)
2267 selentries = set(selentries)
2268
2268
2269 matched = False
2269 matched = False
2270 for section, name, value in ui.walkconfig(untrusted=untrusted):
2270 for section, name, value in ui.walkconfig(untrusted=untrusted):
2271 source = ui.configsource(section, name, untrusted)
2271 source = ui.configsource(section, name, untrusted)
2272 value = pycompat.bytestr(value)
2272 value = pycompat.bytestr(value)
2273 defaultvalue = ui.configdefault(section, name)
2273 defaultvalue = ui.configdefault(section, name)
2274 if fm.isplain():
2274 if fm.isplain():
2275 source = source or b'none'
2275 source = source or b'none'
2276 value = value.replace(b'\n', b'\\n')
2276 value = value.replace(b'\n', b'\\n')
2277 entryname = section + b'.' + name
2277 entryname = section + b'.' + name
2278 if values and not (section in selsections or entryname in selentries):
2278 if values and not (section in selsections or entryname in selentries):
2279 continue
2279 continue
2280 fm.startitem()
2280 fm.startitem()
2281 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2281 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2282 if uniquesel:
2282 if uniquesel:
2283 fm.data(name=entryname)
2283 fm.data(name=entryname)
2284 fm.write(b'value', b'%s\n', value)
2284 fm.write(b'value', b'%s\n', value)
2285 else:
2285 else:
2286 fm.write(b'name value', b'%s=%s\n', entryname, value)
2286 fm.write(b'name value', b'%s=%s\n', entryname, value)
2287 if formatter.isprintable(defaultvalue):
2287 if formatter.isprintable(defaultvalue):
2288 fm.data(defaultvalue=defaultvalue)
2288 fm.data(defaultvalue=defaultvalue)
2289 elif isinstance(defaultvalue, list) and all(
2289 elif isinstance(defaultvalue, list) and all(
2290 formatter.isprintable(e) for e in defaultvalue
2290 formatter.isprintable(e) for e in defaultvalue
2291 ):
2291 ):
2292 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2292 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2293 # TODO: no idea how to process unsupported defaultvalue types
2293 # TODO: no idea how to process unsupported defaultvalue types
2294 matched = True
2294 matched = True
2295 fm.end()
2295 fm.end()
2296 if matched:
2296 if matched:
2297 return 0
2297 return 0
2298 return 1
2298 return 1
2299
2299
2300
2300
2301 @command(
2301 @command(
2302 b'continue',
2302 b'continue',
2303 dryrunopts,
2303 dryrunopts,
2304 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2304 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2305 helpbasic=True,
2305 helpbasic=True,
2306 )
2306 )
2307 def continuecmd(ui, repo, **opts):
2307 def continuecmd(ui, repo, **opts):
2308 """resumes an interrupted operation (EXPERIMENTAL)
2308 """resumes an interrupted operation (EXPERIMENTAL)
2309
2309
2310 Finishes a multistep operation like graft, histedit, rebase, merge,
2310 Finishes a multistep operation like graft, histedit, rebase, merge,
2311 and unshelve if they are in an interrupted state.
2311 and unshelve if they are in an interrupted state.
2312
2312
2313 use --dry-run/-n to dry run the command.
2313 use --dry-run/-n to dry run the command.
2314 """
2314 """
2315 dryrun = opts.get('dry_run')
2315 dryrun = opts.get('dry_run')
2316 contstate = cmdutil.getunfinishedstate(repo)
2316 contstate = cmdutil.getunfinishedstate(repo)
2317 if not contstate:
2317 if not contstate:
2318 raise error.Abort(_(b'no operation in progress'))
2318 raise error.Abort(_(b'no operation in progress'))
2319 if not contstate.continuefunc:
2319 if not contstate.continuefunc:
2320 raise error.Abort(
2320 raise error.Abort(
2321 (
2321 (
2322 _(b"%s in progress but does not support 'hg continue'")
2322 _(b"%s in progress but does not support 'hg continue'")
2323 % (contstate._opname)
2323 % (contstate._opname)
2324 ),
2324 ),
2325 hint=contstate.continuemsg(),
2325 hint=contstate.continuemsg(),
2326 )
2326 )
2327 if dryrun:
2327 if dryrun:
2328 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2328 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2329 return
2329 return
2330 return contstate.continuefunc(ui, repo)
2330 return contstate.continuefunc(ui, repo)
2331
2331
2332
2332
2333 @command(
2333 @command(
2334 b'copy|cp',
2334 b'copy|cp',
2335 [
2335 [
2336 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2336 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2337 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2337 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2338 (
2338 (
2339 b'',
2339 b'',
2340 b'at-rev',
2340 b'at-rev',
2341 b'',
2341 b'',
2342 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2342 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2343 _(b'REV'),
2343 _(b'REV'),
2344 ),
2344 ),
2345 (
2345 (
2346 b'f',
2346 b'f',
2347 b'force',
2347 b'force',
2348 None,
2348 None,
2349 _(b'forcibly copy over an existing managed file'),
2349 _(b'forcibly copy over an existing managed file'),
2350 ),
2350 ),
2351 ]
2351 ]
2352 + walkopts
2352 + walkopts
2353 + dryrunopts,
2353 + dryrunopts,
2354 _(b'[OPTION]... SOURCE... DEST'),
2354 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2355 helpcategory=command.CATEGORY_FILE_CONTENTS,
2355 helpcategory=command.CATEGORY_FILE_CONTENTS,
2356 )
2356 )
2357 def copy(ui, repo, *pats, **opts):
2357 def copy(ui, repo, *pats, **opts):
2358 """mark files as copied for the next commit
2358 """mark files as copied for the next commit
2359
2359
2360 Mark dest as having copies of source files. If dest is a
2360 Mark dest as having copies of source files. If dest is a
2361 directory, copies are put in that directory. If dest is a file,
2361 directory, copies are put in that directory. If dest is a file,
2362 the source must be a single file.
2362 the source must be a single file.
2363
2363
2364 By default, this command copies the contents of files as they
2364 By default, this command copies the contents of files as they
2365 exist in the working directory. If invoked with -A/--after, the
2365 exist in the working directory. If invoked with -A/--after, the
2366 operation is recorded, but no copying is performed.
2366 operation is recorded, but no copying is performed.
2367
2367
2368 To undo marking a destination file as copied, use --forget. With that
2368 To undo marking a destination file as copied, use --forget. With that
2369 option, all given (positional) arguments are unmarked as copies. The
2369 option, all given (positional) arguments are unmarked as copies. The
2370 destination file(s) will be left in place (still tracked).
2370 destination file(s) will be left in place (still tracked).
2371
2371
2372 This command takes effect with the next commit by default.
2372 This command takes effect with the next commit by default.
2373
2373
2374 Returns 0 on success, 1 if errors are encountered.
2374 Returns 0 on success, 1 if errors are encountered.
2375 """
2375 """
2376 opts = pycompat.byteskwargs(opts)
2376 opts = pycompat.byteskwargs(opts)
2377 with repo.wlock():
2377 with repo.wlock():
2378 return cmdutil.copy(ui, repo, pats, opts)
2378 return cmdutil.copy(ui, repo, pats, opts)
2379
2379
2380
2380
2381 @command(
2381 @command(
2382 b'debugcommands',
2382 b'debugcommands',
2383 [],
2383 [],
2384 _(b'[COMMAND]'),
2384 _(b'[COMMAND]'),
2385 helpcategory=command.CATEGORY_HELP,
2385 helpcategory=command.CATEGORY_HELP,
2386 norepo=True,
2386 norepo=True,
2387 )
2387 )
2388 def debugcommands(ui, cmd=b'', *args):
2388 def debugcommands(ui, cmd=b'', *args):
2389 """list all available commands and options"""
2389 """list all available commands and options"""
2390 for cmd, vals in sorted(pycompat.iteritems(table)):
2390 for cmd, vals in sorted(pycompat.iteritems(table)):
2391 cmd = cmd.split(b'|')[0]
2391 cmd = cmd.split(b'|')[0]
2392 opts = b', '.join([i[1] for i in vals[1]])
2392 opts = b', '.join([i[1] for i in vals[1]])
2393 ui.write(b'%s: %s\n' % (cmd, opts))
2393 ui.write(b'%s: %s\n' % (cmd, opts))
2394
2394
2395
2395
2396 @command(
2396 @command(
2397 b'debugcomplete',
2397 b'debugcomplete',
2398 [(b'o', b'options', None, _(b'show the command options'))],
2398 [(b'o', b'options', None, _(b'show the command options'))],
2399 _(b'[-o] CMD'),
2399 _(b'[-o] CMD'),
2400 helpcategory=command.CATEGORY_HELP,
2400 helpcategory=command.CATEGORY_HELP,
2401 norepo=True,
2401 norepo=True,
2402 )
2402 )
2403 def debugcomplete(ui, cmd=b'', **opts):
2403 def debugcomplete(ui, cmd=b'', **opts):
2404 """returns the completion list associated with the given command"""
2404 """returns the completion list associated with the given command"""
2405
2405
2406 if opts.get('options'):
2406 if opts.get('options'):
2407 options = []
2407 options = []
2408 otables = [globalopts]
2408 otables = [globalopts]
2409 if cmd:
2409 if cmd:
2410 aliases, entry = cmdutil.findcmd(cmd, table, False)
2410 aliases, entry = cmdutil.findcmd(cmd, table, False)
2411 otables.append(entry[1])
2411 otables.append(entry[1])
2412 for t in otables:
2412 for t in otables:
2413 for o in t:
2413 for o in t:
2414 if b"(DEPRECATED)" in o[3]:
2414 if b"(DEPRECATED)" in o[3]:
2415 continue
2415 continue
2416 if o[0]:
2416 if o[0]:
2417 options.append(b'-%s' % o[0])
2417 options.append(b'-%s' % o[0])
2418 options.append(b'--%s' % o[1])
2418 options.append(b'--%s' % o[1])
2419 ui.write(b"%s\n" % b"\n".join(options))
2419 ui.write(b"%s\n" % b"\n".join(options))
2420 return
2420 return
2421
2421
2422 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2422 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2423 if ui.verbose:
2423 if ui.verbose:
2424 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2424 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2425 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2425 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2426
2426
2427
2427
2428 @command(
2428 @command(
2429 b'diff',
2429 b'diff',
2430 [
2430 [
2431 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2431 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2432 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2432 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2433 ]
2433 ]
2434 + diffopts
2434 + diffopts
2435 + diffopts2
2435 + diffopts2
2436 + walkopts
2436 + walkopts
2437 + subrepoopts,
2437 + subrepoopts,
2438 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2438 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2439 helpcategory=command.CATEGORY_FILE_CONTENTS,
2439 helpcategory=command.CATEGORY_FILE_CONTENTS,
2440 helpbasic=True,
2440 helpbasic=True,
2441 inferrepo=True,
2441 inferrepo=True,
2442 intents={INTENT_READONLY},
2442 intents={INTENT_READONLY},
2443 )
2443 )
2444 def diff(ui, repo, *pats, **opts):
2444 def diff(ui, repo, *pats, **opts):
2445 """diff repository (or selected files)
2445 """diff repository (or selected files)
2446
2446
2447 Show differences between revisions for the specified files.
2447 Show differences between revisions for the specified files.
2448
2448
2449 Differences between files are shown using the unified diff format.
2449 Differences between files are shown using the unified diff format.
2450
2450
2451 .. note::
2451 .. note::
2452
2452
2453 :hg:`diff` may generate unexpected results for merges, as it will
2453 :hg:`diff` may generate unexpected results for merges, as it will
2454 default to comparing against the working directory's first
2454 default to comparing against the working directory's first
2455 parent changeset if no revisions are specified.
2455 parent changeset if no revisions are specified.
2456
2456
2457 When two revision arguments are given, then changes are shown
2457 When two revision arguments are given, then changes are shown
2458 between those revisions. If only one revision is specified then
2458 between those revisions. If only one revision is specified then
2459 that revision is compared to the working directory, and, when no
2459 that revision is compared to the working directory, and, when no
2460 revisions are specified, the working directory files are compared
2460 revisions are specified, the working directory files are compared
2461 to its first parent.
2461 to its first parent.
2462
2462
2463 Alternatively you can specify -c/--change with a revision to see
2463 Alternatively you can specify -c/--change with a revision to see
2464 the changes in that changeset relative to its first parent.
2464 the changes in that changeset relative to its first parent.
2465
2465
2466 Without the -a/--text option, diff will avoid generating diffs of
2466 Without the -a/--text option, diff will avoid generating diffs of
2467 files it detects as binary. With -a, diff will generate a diff
2467 files it detects as binary. With -a, diff will generate a diff
2468 anyway, probably with undesirable results.
2468 anyway, probably with undesirable results.
2469
2469
2470 Use the -g/--git option to generate diffs in the git extended diff
2470 Use the -g/--git option to generate diffs in the git extended diff
2471 format. For more information, read :hg:`help diffs`.
2471 format. For more information, read :hg:`help diffs`.
2472
2472
2473 .. container:: verbose
2473 .. container:: verbose
2474
2474
2475 Examples:
2475 Examples:
2476
2476
2477 - compare a file in the current working directory to its parent::
2477 - compare a file in the current working directory to its parent::
2478
2478
2479 hg diff foo.c
2479 hg diff foo.c
2480
2480
2481 - compare two historical versions of a directory, with rename info::
2481 - compare two historical versions of a directory, with rename info::
2482
2482
2483 hg diff --git -r 1.0:1.2 lib/
2483 hg diff --git -r 1.0:1.2 lib/
2484
2484
2485 - get change stats relative to the last change on some date::
2485 - get change stats relative to the last change on some date::
2486
2486
2487 hg diff --stat -r "date('may 2')"
2487 hg diff --stat -r "date('may 2')"
2488
2488
2489 - diff all newly-added files that contain a keyword::
2489 - diff all newly-added files that contain a keyword::
2490
2490
2491 hg diff "set:added() and grep(GNU)"
2491 hg diff "set:added() and grep(GNU)"
2492
2492
2493 - compare a revision and its parents::
2493 - compare a revision and its parents::
2494
2494
2495 hg diff -c 9353 # compare against first parent
2495 hg diff -c 9353 # compare against first parent
2496 hg diff -r 9353^:9353 # same using revset syntax
2496 hg diff -r 9353^:9353 # same using revset syntax
2497 hg diff -r 9353^2:9353 # compare against the second parent
2497 hg diff -r 9353^2:9353 # compare against the second parent
2498
2498
2499 Returns 0 on success.
2499 Returns 0 on success.
2500 """
2500 """
2501
2501
2502 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2502 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2503 opts = pycompat.byteskwargs(opts)
2503 opts = pycompat.byteskwargs(opts)
2504 revs = opts.get(b'rev')
2504 revs = opts.get(b'rev')
2505 change = opts.get(b'change')
2505 change = opts.get(b'change')
2506 stat = opts.get(b'stat')
2506 stat = opts.get(b'stat')
2507 reverse = opts.get(b'reverse')
2507 reverse = opts.get(b'reverse')
2508
2508
2509 if change:
2509 if change:
2510 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2510 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2511 ctx2 = scmutil.revsingle(repo, change, None)
2511 ctx2 = scmutil.revsingle(repo, change, None)
2512 ctx1 = ctx2.p1()
2512 ctx1 = ctx2.p1()
2513 else:
2513 else:
2514 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2514 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2515 ctx1, ctx2 = scmutil.revpair(repo, revs)
2515 ctx1, ctx2 = scmutil.revpair(repo, revs)
2516
2516
2517 if reverse:
2517 if reverse:
2518 ctxleft = ctx2
2518 ctxleft = ctx2
2519 ctxright = ctx1
2519 ctxright = ctx1
2520 else:
2520 else:
2521 ctxleft = ctx1
2521 ctxleft = ctx1
2522 ctxright = ctx2
2522 ctxright = ctx2
2523
2523
2524 diffopts = patch.diffallopts(ui, opts)
2524 diffopts = patch.diffallopts(ui, opts)
2525 m = scmutil.match(ctx2, pats, opts)
2525 m = scmutil.match(ctx2, pats, opts)
2526 m = repo.narrowmatch(m)
2526 m = repo.narrowmatch(m)
2527 ui.pager(b'diff')
2527 ui.pager(b'diff')
2528 logcmdutil.diffordiffstat(
2528 logcmdutil.diffordiffstat(
2529 ui,
2529 ui,
2530 repo,
2530 repo,
2531 diffopts,
2531 diffopts,
2532 ctxleft,
2532 ctxleft,
2533 ctxright,
2533 ctxright,
2534 m,
2534 m,
2535 stat=stat,
2535 stat=stat,
2536 listsubrepos=opts.get(b'subrepos'),
2536 listsubrepos=opts.get(b'subrepos'),
2537 root=opts.get(b'root'),
2537 root=opts.get(b'root'),
2538 )
2538 )
2539
2539
2540
2540
2541 @command(
2541 @command(
2542 b'export',
2542 b'export',
2543 [
2543 [
2544 (
2544 (
2545 b'B',
2545 b'B',
2546 b'bookmark',
2546 b'bookmark',
2547 b'',
2547 b'',
2548 _(b'export changes only reachable by given bookmark'),
2548 _(b'export changes only reachable by given bookmark'),
2549 _(b'BOOKMARK'),
2549 _(b'BOOKMARK'),
2550 ),
2550 ),
2551 (
2551 (
2552 b'o',
2552 b'o',
2553 b'output',
2553 b'output',
2554 b'',
2554 b'',
2555 _(b'print output to file with formatted name'),
2555 _(b'print output to file with formatted name'),
2556 _(b'FORMAT'),
2556 _(b'FORMAT'),
2557 ),
2557 ),
2558 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2558 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2559 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2559 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2560 ]
2560 ]
2561 + diffopts
2561 + diffopts
2562 + formatteropts,
2562 + formatteropts,
2563 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2563 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2564 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2564 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2565 helpbasic=True,
2565 helpbasic=True,
2566 intents={INTENT_READONLY},
2566 intents={INTENT_READONLY},
2567 )
2567 )
2568 def export(ui, repo, *changesets, **opts):
2568 def export(ui, repo, *changesets, **opts):
2569 """dump the header and diffs for one or more changesets
2569 """dump the header and diffs for one or more changesets
2570
2570
2571 Print the changeset header and diffs for one or more revisions.
2571 Print the changeset header and diffs for one or more revisions.
2572 If no revision is given, the parent of the working directory is used.
2572 If no revision is given, the parent of the working directory is used.
2573
2573
2574 The information shown in the changeset header is: author, date,
2574 The information shown in the changeset header is: author, date,
2575 branch name (if non-default), changeset hash, parent(s) and commit
2575 branch name (if non-default), changeset hash, parent(s) and commit
2576 comment.
2576 comment.
2577
2577
2578 .. note::
2578 .. note::
2579
2579
2580 :hg:`export` may generate unexpected diff output for merge
2580 :hg:`export` may generate unexpected diff output for merge
2581 changesets, as it will compare the merge changeset against its
2581 changesets, as it will compare the merge changeset against its
2582 first parent only.
2582 first parent only.
2583
2583
2584 Output may be to a file, in which case the name of the file is
2584 Output may be to a file, in which case the name of the file is
2585 given using a template string. See :hg:`help templates`. In addition
2585 given using a template string. See :hg:`help templates`. In addition
2586 to the common template keywords, the following formatting rules are
2586 to the common template keywords, the following formatting rules are
2587 supported:
2587 supported:
2588
2588
2589 :``%%``: literal "%" character
2589 :``%%``: literal "%" character
2590 :``%H``: changeset hash (40 hexadecimal digits)
2590 :``%H``: changeset hash (40 hexadecimal digits)
2591 :``%N``: number of patches being generated
2591 :``%N``: number of patches being generated
2592 :``%R``: changeset revision number
2592 :``%R``: changeset revision number
2593 :``%b``: basename of the exporting repository
2593 :``%b``: basename of the exporting repository
2594 :``%h``: short-form changeset hash (12 hexadecimal digits)
2594 :``%h``: short-form changeset hash (12 hexadecimal digits)
2595 :``%m``: first line of the commit message (only alphanumeric characters)
2595 :``%m``: first line of the commit message (only alphanumeric characters)
2596 :``%n``: zero-padded sequence number, starting at 1
2596 :``%n``: zero-padded sequence number, starting at 1
2597 :``%r``: zero-padded changeset revision number
2597 :``%r``: zero-padded changeset revision number
2598 :``\\``: literal "\\" character
2598 :``\\``: literal "\\" character
2599
2599
2600 Without the -a/--text option, export will avoid generating diffs
2600 Without the -a/--text option, export will avoid generating diffs
2601 of files it detects as binary. With -a, export will generate a
2601 of files it detects as binary. With -a, export will generate a
2602 diff anyway, probably with undesirable results.
2602 diff anyway, probably with undesirable results.
2603
2603
2604 With -B/--bookmark changesets reachable by the given bookmark are
2604 With -B/--bookmark changesets reachable by the given bookmark are
2605 selected.
2605 selected.
2606
2606
2607 Use the -g/--git option to generate diffs in the git extended diff
2607 Use the -g/--git option to generate diffs in the git extended diff
2608 format. See :hg:`help diffs` for more information.
2608 format. See :hg:`help diffs` for more information.
2609
2609
2610 With the --switch-parent option, the diff will be against the
2610 With the --switch-parent option, the diff will be against the
2611 second parent. It can be useful to review a merge.
2611 second parent. It can be useful to review a merge.
2612
2612
2613 .. container:: verbose
2613 .. container:: verbose
2614
2614
2615 Template:
2615 Template:
2616
2616
2617 The following keywords are supported in addition to the common template
2617 The following keywords are supported in addition to the common template
2618 keywords and functions. See also :hg:`help templates`.
2618 keywords and functions. See also :hg:`help templates`.
2619
2619
2620 :diff: String. Diff content.
2620 :diff: String. Diff content.
2621 :parents: List of strings. Parent nodes of the changeset.
2621 :parents: List of strings. Parent nodes of the changeset.
2622
2622
2623 Examples:
2623 Examples:
2624
2624
2625 - use export and import to transplant a bugfix to the current
2625 - use export and import to transplant a bugfix to the current
2626 branch::
2626 branch::
2627
2627
2628 hg export -r 9353 | hg import -
2628 hg export -r 9353 | hg import -
2629
2629
2630 - export all the changesets between two revisions to a file with
2630 - export all the changesets between two revisions to a file with
2631 rename information::
2631 rename information::
2632
2632
2633 hg export --git -r 123:150 > changes.txt
2633 hg export --git -r 123:150 > changes.txt
2634
2634
2635 - split outgoing changes into a series of patches with
2635 - split outgoing changes into a series of patches with
2636 descriptive names::
2636 descriptive names::
2637
2637
2638 hg export -r "outgoing()" -o "%n-%m.patch"
2638 hg export -r "outgoing()" -o "%n-%m.patch"
2639
2639
2640 Returns 0 on success.
2640 Returns 0 on success.
2641 """
2641 """
2642 opts = pycompat.byteskwargs(opts)
2642 opts = pycompat.byteskwargs(opts)
2643 bookmark = opts.get(b'bookmark')
2643 bookmark = opts.get(b'bookmark')
2644 changesets += tuple(opts.get(b'rev', []))
2644 changesets += tuple(opts.get(b'rev', []))
2645
2645
2646 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2646 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2647
2647
2648 if bookmark:
2648 if bookmark:
2649 if bookmark not in repo._bookmarks:
2649 if bookmark not in repo._bookmarks:
2650 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2650 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2651
2651
2652 revs = scmutil.bookmarkrevs(repo, bookmark)
2652 revs = scmutil.bookmarkrevs(repo, bookmark)
2653 else:
2653 else:
2654 if not changesets:
2654 if not changesets:
2655 changesets = [b'.']
2655 changesets = [b'.']
2656
2656
2657 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2657 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2658 revs = scmutil.revrange(repo, changesets)
2658 revs = scmutil.revrange(repo, changesets)
2659
2659
2660 if not revs:
2660 if not revs:
2661 raise error.Abort(_(b"export requires at least one changeset"))
2661 raise error.Abort(_(b"export requires at least one changeset"))
2662 if len(revs) > 1:
2662 if len(revs) > 1:
2663 ui.note(_(b'exporting patches:\n'))
2663 ui.note(_(b'exporting patches:\n'))
2664 else:
2664 else:
2665 ui.note(_(b'exporting patch:\n'))
2665 ui.note(_(b'exporting patch:\n'))
2666
2666
2667 fntemplate = opts.get(b'output')
2667 fntemplate = opts.get(b'output')
2668 if cmdutil.isstdiofilename(fntemplate):
2668 if cmdutil.isstdiofilename(fntemplate):
2669 fntemplate = b''
2669 fntemplate = b''
2670
2670
2671 if fntemplate:
2671 if fntemplate:
2672 fm = formatter.nullformatter(ui, b'export', opts)
2672 fm = formatter.nullformatter(ui, b'export', opts)
2673 else:
2673 else:
2674 ui.pager(b'export')
2674 ui.pager(b'export')
2675 fm = ui.formatter(b'export', opts)
2675 fm = ui.formatter(b'export', opts)
2676 with fm:
2676 with fm:
2677 cmdutil.export(
2677 cmdutil.export(
2678 repo,
2678 repo,
2679 revs,
2679 revs,
2680 fm,
2680 fm,
2681 fntemplate=fntemplate,
2681 fntemplate=fntemplate,
2682 switch_parent=opts.get(b'switch_parent'),
2682 switch_parent=opts.get(b'switch_parent'),
2683 opts=patch.diffallopts(ui, opts),
2683 opts=patch.diffallopts(ui, opts),
2684 )
2684 )
2685
2685
2686
2686
2687 @command(
2687 @command(
2688 b'files',
2688 b'files',
2689 [
2689 [
2690 (
2690 (
2691 b'r',
2691 b'r',
2692 b'rev',
2692 b'rev',
2693 b'',
2693 b'',
2694 _(b'search the repository as it is in REV'),
2694 _(b'search the repository as it is in REV'),
2695 _(b'REV'),
2695 _(b'REV'),
2696 ),
2696 ),
2697 (
2697 (
2698 b'0',
2698 b'0',
2699 b'print0',
2699 b'print0',
2700 None,
2700 None,
2701 _(b'end filenames with NUL, for use with xargs'),
2701 _(b'end filenames with NUL, for use with xargs'),
2702 ),
2702 ),
2703 ]
2703 ]
2704 + walkopts
2704 + walkopts
2705 + formatteropts
2705 + formatteropts
2706 + subrepoopts,
2706 + subrepoopts,
2707 _(b'[OPTION]... [FILE]...'),
2707 _(b'[OPTION]... [FILE]...'),
2708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2709 intents={INTENT_READONLY},
2709 intents={INTENT_READONLY},
2710 )
2710 )
2711 def files(ui, repo, *pats, **opts):
2711 def files(ui, repo, *pats, **opts):
2712 """list tracked files
2712 """list tracked files
2713
2713
2714 Print files under Mercurial control in the working directory or
2714 Print files under Mercurial control in the working directory or
2715 specified revision for given files (excluding removed files).
2715 specified revision for given files (excluding removed files).
2716 Files can be specified as filenames or filesets.
2716 Files can be specified as filenames or filesets.
2717
2717
2718 If no files are given to match, this command prints the names
2718 If no files are given to match, this command prints the names
2719 of all files under Mercurial control.
2719 of all files under Mercurial control.
2720
2720
2721 .. container:: verbose
2721 .. container:: verbose
2722
2722
2723 Template:
2723 Template:
2724
2724
2725 The following keywords are supported in addition to the common template
2725 The following keywords are supported in addition to the common template
2726 keywords and functions. See also :hg:`help templates`.
2726 keywords and functions. See also :hg:`help templates`.
2727
2727
2728 :flags: String. Character denoting file's symlink and executable bits.
2728 :flags: String. Character denoting file's symlink and executable bits.
2729 :path: String. Repository-absolute path of the file.
2729 :path: String. Repository-absolute path of the file.
2730 :size: Integer. Size of the file in bytes.
2730 :size: Integer. Size of the file in bytes.
2731
2731
2732 Examples:
2732 Examples:
2733
2733
2734 - list all files under the current directory::
2734 - list all files under the current directory::
2735
2735
2736 hg files .
2736 hg files .
2737
2737
2738 - shows sizes and flags for current revision::
2738 - shows sizes and flags for current revision::
2739
2739
2740 hg files -vr .
2740 hg files -vr .
2741
2741
2742 - list all files named README::
2742 - list all files named README::
2743
2743
2744 hg files -I "**/README"
2744 hg files -I "**/README"
2745
2745
2746 - list all binary files::
2746 - list all binary files::
2747
2747
2748 hg files "set:binary()"
2748 hg files "set:binary()"
2749
2749
2750 - find files containing a regular expression::
2750 - find files containing a regular expression::
2751
2751
2752 hg files "set:grep('bob')"
2752 hg files "set:grep('bob')"
2753
2753
2754 - search tracked file contents with xargs and grep::
2754 - search tracked file contents with xargs and grep::
2755
2755
2756 hg files -0 | xargs -0 grep foo
2756 hg files -0 | xargs -0 grep foo
2757
2757
2758 See :hg:`help patterns` and :hg:`help filesets` for more information
2758 See :hg:`help patterns` and :hg:`help filesets` for more information
2759 on specifying file patterns.
2759 on specifying file patterns.
2760
2760
2761 Returns 0 if a match is found, 1 otherwise.
2761 Returns 0 if a match is found, 1 otherwise.
2762
2762
2763 """
2763 """
2764
2764
2765 opts = pycompat.byteskwargs(opts)
2765 opts = pycompat.byteskwargs(opts)
2766 rev = opts.get(b'rev')
2766 rev = opts.get(b'rev')
2767 if rev:
2767 if rev:
2768 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2768 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2769 ctx = scmutil.revsingle(repo, rev, None)
2769 ctx = scmutil.revsingle(repo, rev, None)
2770
2770
2771 end = b'\n'
2771 end = b'\n'
2772 if opts.get(b'print0'):
2772 if opts.get(b'print0'):
2773 end = b'\0'
2773 end = b'\0'
2774 fmt = b'%s' + end
2774 fmt = b'%s' + end
2775
2775
2776 m = scmutil.match(ctx, pats, opts)
2776 m = scmutil.match(ctx, pats, opts)
2777 ui.pager(b'files')
2777 ui.pager(b'files')
2778 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2778 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2779 with ui.formatter(b'files', opts) as fm:
2779 with ui.formatter(b'files', opts) as fm:
2780 return cmdutil.files(
2780 return cmdutil.files(
2781 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2781 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2782 )
2782 )
2783
2783
2784
2784
2785 @command(
2785 @command(
2786 b'forget',
2786 b'forget',
2787 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2787 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2788 + walkopts
2788 + walkopts
2789 + dryrunopts,
2789 + dryrunopts,
2790 _(b'[OPTION]... FILE...'),
2790 _(b'[OPTION]... FILE...'),
2791 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2791 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2792 helpbasic=True,
2792 helpbasic=True,
2793 inferrepo=True,
2793 inferrepo=True,
2794 )
2794 )
2795 def forget(ui, repo, *pats, **opts):
2795 def forget(ui, repo, *pats, **opts):
2796 """forget the specified files on the next commit
2796 """forget the specified files on the next commit
2797
2797
2798 Mark the specified files so they will no longer be tracked
2798 Mark the specified files so they will no longer be tracked
2799 after the next commit.
2799 after the next commit.
2800
2800
2801 This only removes files from the current branch, not from the
2801 This only removes files from the current branch, not from the
2802 entire project history, and it does not delete them from the
2802 entire project history, and it does not delete them from the
2803 working directory.
2803 working directory.
2804
2804
2805 To delete the file from the working directory, see :hg:`remove`.
2805 To delete the file from the working directory, see :hg:`remove`.
2806
2806
2807 To undo a forget before the next commit, see :hg:`add`.
2807 To undo a forget before the next commit, see :hg:`add`.
2808
2808
2809 .. container:: verbose
2809 .. container:: verbose
2810
2810
2811 Examples:
2811 Examples:
2812
2812
2813 - forget newly-added binary files::
2813 - forget newly-added binary files::
2814
2814
2815 hg forget "set:added() and binary()"
2815 hg forget "set:added() and binary()"
2816
2816
2817 - forget files that would be excluded by .hgignore::
2817 - forget files that would be excluded by .hgignore::
2818
2818
2819 hg forget "set:hgignore()"
2819 hg forget "set:hgignore()"
2820
2820
2821 Returns 0 on success.
2821 Returns 0 on success.
2822 """
2822 """
2823
2823
2824 opts = pycompat.byteskwargs(opts)
2824 opts = pycompat.byteskwargs(opts)
2825 if not pats:
2825 if not pats:
2826 raise error.Abort(_(b'no files specified'))
2826 raise error.Abort(_(b'no files specified'))
2827
2827
2828 m = scmutil.match(repo[None], pats, opts)
2828 m = scmutil.match(repo[None], pats, opts)
2829 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2829 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2830 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2830 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2831 rejected = cmdutil.forget(
2831 rejected = cmdutil.forget(
2832 ui,
2832 ui,
2833 repo,
2833 repo,
2834 m,
2834 m,
2835 prefix=b"",
2835 prefix=b"",
2836 uipathfn=uipathfn,
2836 uipathfn=uipathfn,
2837 explicitonly=False,
2837 explicitonly=False,
2838 dryrun=dryrun,
2838 dryrun=dryrun,
2839 interactive=interactive,
2839 interactive=interactive,
2840 )[0]
2840 )[0]
2841 return rejected and 1 or 0
2841 return rejected and 1 or 0
2842
2842
2843
2843
2844 @command(
2844 @command(
2845 b'graft',
2845 b'graft',
2846 [
2846 [
2847 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2847 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2848 (
2848 (
2849 b'',
2849 b'',
2850 b'base',
2850 b'base',
2851 b'',
2851 b'',
2852 _(b'base revision when doing the graft merge (ADVANCED)'),
2852 _(b'base revision when doing the graft merge (ADVANCED)'),
2853 _(b'REV'),
2853 _(b'REV'),
2854 ),
2854 ),
2855 (b'c', b'continue', False, _(b'resume interrupted graft')),
2855 (b'c', b'continue', False, _(b'resume interrupted graft')),
2856 (b'', b'stop', False, _(b'stop interrupted graft')),
2856 (b'', b'stop', False, _(b'stop interrupted graft')),
2857 (b'', b'abort', False, _(b'abort interrupted graft')),
2857 (b'', b'abort', False, _(b'abort interrupted graft')),
2858 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2858 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2859 (b'', b'log', None, _(b'append graft info to log message')),
2859 (b'', b'log', None, _(b'append graft info to log message')),
2860 (
2860 (
2861 b'',
2861 b'',
2862 b'no-commit',
2862 b'no-commit',
2863 None,
2863 None,
2864 _(b"don't commit, just apply the changes in working directory"),
2864 _(b"don't commit, just apply the changes in working directory"),
2865 ),
2865 ),
2866 (b'f', b'force', False, _(b'force graft')),
2866 (b'f', b'force', False, _(b'force graft')),
2867 (
2867 (
2868 b'D',
2868 b'D',
2869 b'currentdate',
2869 b'currentdate',
2870 False,
2870 False,
2871 _(b'record the current date as commit date'),
2871 _(b'record the current date as commit date'),
2872 ),
2872 ),
2873 (
2873 (
2874 b'U',
2874 b'U',
2875 b'currentuser',
2875 b'currentuser',
2876 False,
2876 False,
2877 _(b'record the current user as committer'),
2877 _(b'record the current user as committer'),
2878 ),
2878 ),
2879 ]
2879 ]
2880 + commitopts2
2880 + commitopts2
2881 + mergetoolopts
2881 + mergetoolopts
2882 + dryrunopts,
2882 + dryrunopts,
2883 _(b'[OPTION]... [-r REV]... REV...'),
2883 _(b'[OPTION]... [-r REV]... REV...'),
2884 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2884 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2885 )
2885 )
2886 def graft(ui, repo, *revs, **opts):
2886 def graft(ui, repo, *revs, **opts):
2887 '''copy changes from other branches onto the current branch
2887 '''copy changes from other branches onto the current branch
2888
2888
2889 This command uses Mercurial's merge logic to copy individual
2889 This command uses Mercurial's merge logic to copy individual
2890 changes from other branches without merging branches in the
2890 changes from other branches without merging branches in the
2891 history graph. This is sometimes known as 'backporting' or
2891 history graph. This is sometimes known as 'backporting' or
2892 'cherry-picking'. By default, graft will copy user, date, and
2892 'cherry-picking'. By default, graft will copy user, date, and
2893 description from the source changesets.
2893 description from the source changesets.
2894
2894
2895 Changesets that are ancestors of the current revision, that have
2895 Changesets that are ancestors of the current revision, that have
2896 already been grafted, or that are merges will be skipped.
2896 already been grafted, or that are merges will be skipped.
2897
2897
2898 If --log is specified, log messages will have a comment appended
2898 If --log is specified, log messages will have a comment appended
2899 of the form::
2899 of the form::
2900
2900
2901 (grafted from CHANGESETHASH)
2901 (grafted from CHANGESETHASH)
2902
2902
2903 If --force is specified, revisions will be grafted even if they
2903 If --force is specified, revisions will be grafted even if they
2904 are already ancestors of, or have been grafted to, the destination.
2904 are already ancestors of, or have been grafted to, the destination.
2905 This is useful when the revisions have since been backed out.
2905 This is useful when the revisions have since been backed out.
2906
2906
2907 If a graft merge results in conflicts, the graft process is
2907 If a graft merge results in conflicts, the graft process is
2908 interrupted so that the current merge can be manually resolved.
2908 interrupted so that the current merge can be manually resolved.
2909 Once all conflicts are addressed, the graft process can be
2909 Once all conflicts are addressed, the graft process can be
2910 continued with the -c/--continue option.
2910 continued with the -c/--continue option.
2911
2911
2912 The -c/--continue option reapplies all the earlier options.
2912 The -c/--continue option reapplies all the earlier options.
2913
2913
2914 .. container:: verbose
2914 .. container:: verbose
2915
2915
2916 The --base option exposes more of how graft internally uses merge with a
2916 The --base option exposes more of how graft internally uses merge with a
2917 custom base revision. --base can be used to specify another ancestor than
2917 custom base revision. --base can be used to specify another ancestor than
2918 the first and only parent.
2918 the first and only parent.
2919
2919
2920 The command::
2920 The command::
2921
2921
2922 hg graft -r 345 --base 234
2922 hg graft -r 345 --base 234
2923
2923
2924 is thus pretty much the same as::
2924 is thus pretty much the same as::
2925
2925
2926 hg diff -r 234 -r 345 | hg import
2926 hg diff -r 234 -r 345 | hg import
2927
2927
2928 but using merge to resolve conflicts and track moved files.
2928 but using merge to resolve conflicts and track moved files.
2929
2929
2930 The result of a merge can thus be backported as a single commit by
2930 The result of a merge can thus be backported as a single commit by
2931 specifying one of the merge parents as base, and thus effectively
2931 specifying one of the merge parents as base, and thus effectively
2932 grafting the changes from the other side.
2932 grafting the changes from the other side.
2933
2933
2934 It is also possible to collapse multiple changesets and clean up history
2934 It is also possible to collapse multiple changesets and clean up history
2935 by specifying another ancestor as base, much like rebase --collapse
2935 by specifying another ancestor as base, much like rebase --collapse
2936 --keep.
2936 --keep.
2937
2937
2938 The commit message can be tweaked after the fact using commit --amend .
2938 The commit message can be tweaked after the fact using commit --amend .
2939
2939
2940 For using non-ancestors as the base to backout changes, see the backout
2940 For using non-ancestors as the base to backout changes, see the backout
2941 command and the hidden --parent option.
2941 command and the hidden --parent option.
2942
2942
2943 .. container:: verbose
2943 .. container:: verbose
2944
2944
2945 Examples:
2945 Examples:
2946
2946
2947 - copy a single change to the stable branch and edit its description::
2947 - copy a single change to the stable branch and edit its description::
2948
2948
2949 hg update stable
2949 hg update stable
2950 hg graft --edit 9393
2950 hg graft --edit 9393
2951
2951
2952 - graft a range of changesets with one exception, updating dates::
2952 - graft a range of changesets with one exception, updating dates::
2953
2953
2954 hg graft -D "2085::2093 and not 2091"
2954 hg graft -D "2085::2093 and not 2091"
2955
2955
2956 - continue a graft after resolving conflicts::
2956 - continue a graft after resolving conflicts::
2957
2957
2958 hg graft -c
2958 hg graft -c
2959
2959
2960 - show the source of a grafted changeset::
2960 - show the source of a grafted changeset::
2961
2961
2962 hg log --debug -r .
2962 hg log --debug -r .
2963
2963
2964 - show revisions sorted by date::
2964 - show revisions sorted by date::
2965
2965
2966 hg log -r "sort(all(), date)"
2966 hg log -r "sort(all(), date)"
2967
2967
2968 - backport the result of a merge as a single commit::
2968 - backport the result of a merge as a single commit::
2969
2969
2970 hg graft -r 123 --base 123^
2970 hg graft -r 123 --base 123^
2971
2971
2972 - land a feature branch as one changeset::
2972 - land a feature branch as one changeset::
2973
2973
2974 hg up -cr default
2974 hg up -cr default
2975 hg graft -r featureX --base "ancestor('featureX', 'default')"
2975 hg graft -r featureX --base "ancestor('featureX', 'default')"
2976
2976
2977 See :hg:`help revisions` for more about specifying revisions.
2977 See :hg:`help revisions` for more about specifying revisions.
2978
2978
2979 Returns 0 on successful completion, 1 if there are unresolved files.
2979 Returns 0 on successful completion, 1 if there are unresolved files.
2980 '''
2980 '''
2981 with repo.wlock():
2981 with repo.wlock():
2982 return _dograft(ui, repo, *revs, **opts)
2982 return _dograft(ui, repo, *revs, **opts)
2983
2983
2984
2984
2985 def _dograft(ui, repo, *revs, **opts):
2985 def _dograft(ui, repo, *revs, **opts):
2986 opts = pycompat.byteskwargs(opts)
2986 opts = pycompat.byteskwargs(opts)
2987 if revs and opts.get(b'rev'):
2987 if revs and opts.get(b'rev'):
2988 ui.warn(
2988 ui.warn(
2989 _(
2989 _(
2990 b'warning: inconsistent use of --rev might give unexpected '
2990 b'warning: inconsistent use of --rev might give unexpected '
2991 b'revision ordering!\n'
2991 b'revision ordering!\n'
2992 )
2992 )
2993 )
2993 )
2994
2994
2995 revs = list(revs)
2995 revs = list(revs)
2996 revs.extend(opts.get(b'rev'))
2996 revs.extend(opts.get(b'rev'))
2997 # a dict of data to be stored in state file
2997 # a dict of data to be stored in state file
2998 statedata = {}
2998 statedata = {}
2999 # list of new nodes created by ongoing graft
2999 # list of new nodes created by ongoing graft
3000 statedata[b'newnodes'] = []
3000 statedata[b'newnodes'] = []
3001
3001
3002 cmdutil.resolvecommitoptions(ui, opts)
3002 cmdutil.resolvecommitoptions(ui, opts)
3003
3003
3004 editor = cmdutil.getcommiteditor(
3004 editor = cmdutil.getcommiteditor(
3005 editform=b'graft', **pycompat.strkwargs(opts)
3005 editform=b'graft', **pycompat.strkwargs(opts)
3006 )
3006 )
3007
3007
3008 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3008 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3009
3009
3010 cont = False
3010 cont = False
3011 if opts.get(b'no_commit'):
3011 if opts.get(b'no_commit'):
3012 cmdutil.check_incompatible_arguments(
3012 cmdutil.check_incompatible_arguments(
3013 opts,
3013 opts,
3014 b'no_commit',
3014 b'no_commit',
3015 [b'edit', b'currentuser', b'currentdate', b'log'],
3015 [b'edit', b'currentuser', b'currentdate', b'log'],
3016 )
3016 )
3017
3017
3018 graftstate = statemod.cmdstate(repo, b'graftstate')
3018 graftstate = statemod.cmdstate(repo, b'graftstate')
3019
3019
3020 if opts.get(b'stop'):
3020 if opts.get(b'stop'):
3021 cmdutil.check_incompatible_arguments(
3021 cmdutil.check_incompatible_arguments(
3022 opts,
3022 opts,
3023 b'stop',
3023 b'stop',
3024 [
3024 [
3025 b'edit',
3025 b'edit',
3026 b'log',
3026 b'log',
3027 b'user',
3027 b'user',
3028 b'date',
3028 b'date',
3029 b'currentdate',
3029 b'currentdate',
3030 b'currentuser',
3030 b'currentuser',
3031 b'rev',
3031 b'rev',
3032 ],
3032 ],
3033 )
3033 )
3034 return _stopgraft(ui, repo, graftstate)
3034 return _stopgraft(ui, repo, graftstate)
3035 elif opts.get(b'abort'):
3035 elif opts.get(b'abort'):
3036 cmdutil.check_incompatible_arguments(
3036 cmdutil.check_incompatible_arguments(
3037 opts,
3037 opts,
3038 b'abort',
3038 b'abort',
3039 [
3039 [
3040 b'edit',
3040 b'edit',
3041 b'log',
3041 b'log',
3042 b'user',
3042 b'user',
3043 b'date',
3043 b'date',
3044 b'currentdate',
3044 b'currentdate',
3045 b'currentuser',
3045 b'currentuser',
3046 b'rev',
3046 b'rev',
3047 ],
3047 ],
3048 )
3048 )
3049 return cmdutil.abortgraft(ui, repo, graftstate)
3049 return cmdutil.abortgraft(ui, repo, graftstate)
3050 elif opts.get(b'continue'):
3050 elif opts.get(b'continue'):
3051 cont = True
3051 cont = True
3052 if revs:
3052 if revs:
3053 raise error.Abort(_(b"can't specify --continue and revisions"))
3053 raise error.Abort(_(b"can't specify --continue and revisions"))
3054 # read in unfinished revisions
3054 # read in unfinished revisions
3055 if graftstate.exists():
3055 if graftstate.exists():
3056 statedata = cmdutil.readgraftstate(repo, graftstate)
3056 statedata = cmdutil.readgraftstate(repo, graftstate)
3057 if statedata.get(b'date'):
3057 if statedata.get(b'date'):
3058 opts[b'date'] = statedata[b'date']
3058 opts[b'date'] = statedata[b'date']
3059 if statedata.get(b'user'):
3059 if statedata.get(b'user'):
3060 opts[b'user'] = statedata[b'user']
3060 opts[b'user'] = statedata[b'user']
3061 if statedata.get(b'log'):
3061 if statedata.get(b'log'):
3062 opts[b'log'] = True
3062 opts[b'log'] = True
3063 if statedata.get(b'no_commit'):
3063 if statedata.get(b'no_commit'):
3064 opts[b'no_commit'] = statedata.get(b'no_commit')
3064 opts[b'no_commit'] = statedata.get(b'no_commit')
3065 if statedata.get(b'base'):
3065 if statedata.get(b'base'):
3066 opts[b'base'] = statedata.get(b'base')
3066 opts[b'base'] = statedata.get(b'base')
3067 nodes = statedata[b'nodes']
3067 nodes = statedata[b'nodes']
3068 revs = [repo[node].rev() for node in nodes]
3068 revs = [repo[node].rev() for node in nodes]
3069 else:
3069 else:
3070 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3070 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3071 else:
3071 else:
3072 if not revs:
3072 if not revs:
3073 raise error.Abort(_(b'no revisions specified'))
3073 raise error.Abort(_(b'no revisions specified'))
3074 cmdutil.checkunfinished(repo)
3074 cmdutil.checkunfinished(repo)
3075 cmdutil.bailifchanged(repo)
3075 cmdutil.bailifchanged(repo)
3076 revs = scmutil.revrange(repo, revs)
3076 revs = scmutil.revrange(repo, revs)
3077
3077
3078 skipped = set()
3078 skipped = set()
3079 basectx = None
3079 basectx = None
3080 if opts.get(b'base'):
3080 if opts.get(b'base'):
3081 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3081 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3082 if basectx is None:
3082 if basectx is None:
3083 # check for merges
3083 # check for merges
3084 for rev in repo.revs(b'%ld and merge()', revs):
3084 for rev in repo.revs(b'%ld and merge()', revs):
3085 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3085 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3086 skipped.add(rev)
3086 skipped.add(rev)
3087 revs = [r for r in revs if r not in skipped]
3087 revs = [r for r in revs if r not in skipped]
3088 if not revs:
3088 if not revs:
3089 return -1
3089 return -1
3090 if basectx is not None and len(revs) != 1:
3090 if basectx is not None and len(revs) != 1:
3091 raise error.Abort(_(b'only one revision allowed with --base '))
3091 raise error.Abort(_(b'only one revision allowed with --base '))
3092
3092
3093 # Don't check in the --continue case, in effect retaining --force across
3093 # Don't check in the --continue case, in effect retaining --force across
3094 # --continues. That's because without --force, any revisions we decided to
3094 # --continues. That's because without --force, any revisions we decided to
3095 # skip would have been filtered out here, so they wouldn't have made their
3095 # skip would have been filtered out here, so they wouldn't have made their
3096 # way to the graftstate. With --force, any revisions we would have otherwise
3096 # way to the graftstate. With --force, any revisions we would have otherwise
3097 # skipped would not have been filtered out, and if they hadn't been applied
3097 # skipped would not have been filtered out, and if they hadn't been applied
3098 # already, they'd have been in the graftstate.
3098 # already, they'd have been in the graftstate.
3099 if not (cont or opts.get(b'force')) and basectx is None:
3099 if not (cont or opts.get(b'force')) and basectx is None:
3100 # check for ancestors of dest branch
3100 # check for ancestors of dest branch
3101 ancestors = repo.revs(b'%ld & (::.)', revs)
3101 ancestors = repo.revs(b'%ld & (::.)', revs)
3102 for rev in ancestors:
3102 for rev in ancestors:
3103 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3103 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3104
3104
3105 revs = [r for r in revs if r not in ancestors]
3105 revs = [r for r in revs if r not in ancestors]
3106
3106
3107 if not revs:
3107 if not revs:
3108 return -1
3108 return -1
3109
3109
3110 # analyze revs for earlier grafts
3110 # analyze revs for earlier grafts
3111 ids = {}
3111 ids = {}
3112 for ctx in repo.set(b"%ld", revs):
3112 for ctx in repo.set(b"%ld", revs):
3113 ids[ctx.hex()] = ctx.rev()
3113 ids[ctx.hex()] = ctx.rev()
3114 n = ctx.extra().get(b'source')
3114 n = ctx.extra().get(b'source')
3115 if n:
3115 if n:
3116 ids[n] = ctx.rev()
3116 ids[n] = ctx.rev()
3117
3117
3118 # check ancestors for earlier grafts
3118 # check ancestors for earlier grafts
3119 ui.debug(b'scanning for duplicate grafts\n')
3119 ui.debug(b'scanning for duplicate grafts\n')
3120
3120
3121 # The only changesets we can be sure doesn't contain grafts of any
3121 # The only changesets we can be sure doesn't contain grafts of any
3122 # revs, are the ones that are common ancestors of *all* revs:
3122 # revs, are the ones that are common ancestors of *all* revs:
3123 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3123 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3124 ctx = repo[rev]
3124 ctx = repo[rev]
3125 n = ctx.extra().get(b'source')
3125 n = ctx.extra().get(b'source')
3126 if n in ids:
3126 if n in ids:
3127 try:
3127 try:
3128 r = repo[n].rev()
3128 r = repo[n].rev()
3129 except error.RepoLookupError:
3129 except error.RepoLookupError:
3130 r = None
3130 r = None
3131 if r in revs:
3131 if r in revs:
3132 ui.warn(
3132 ui.warn(
3133 _(
3133 _(
3134 b'skipping revision %d:%s '
3134 b'skipping revision %d:%s '
3135 b'(already grafted to %d:%s)\n'
3135 b'(already grafted to %d:%s)\n'
3136 )
3136 )
3137 % (r, repo[r], rev, ctx)
3137 % (r, repo[r], rev, ctx)
3138 )
3138 )
3139 revs.remove(r)
3139 revs.remove(r)
3140 elif ids[n] in revs:
3140 elif ids[n] in revs:
3141 if r is None:
3141 if r is None:
3142 ui.warn(
3142 ui.warn(
3143 _(
3143 _(
3144 b'skipping already grafted revision %d:%s '
3144 b'skipping already grafted revision %d:%s '
3145 b'(%d:%s also has unknown origin %s)\n'
3145 b'(%d:%s also has unknown origin %s)\n'
3146 )
3146 )
3147 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3147 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3148 )
3148 )
3149 else:
3149 else:
3150 ui.warn(
3150 ui.warn(
3151 _(
3151 _(
3152 b'skipping already grafted revision %d:%s '
3152 b'skipping already grafted revision %d:%s '
3153 b'(%d:%s also has origin %d:%s)\n'
3153 b'(%d:%s also has origin %d:%s)\n'
3154 )
3154 )
3155 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3155 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3156 )
3156 )
3157 revs.remove(ids[n])
3157 revs.remove(ids[n])
3158 elif ctx.hex() in ids:
3158 elif ctx.hex() in ids:
3159 r = ids[ctx.hex()]
3159 r = ids[ctx.hex()]
3160 if r in revs:
3160 if r in revs:
3161 ui.warn(
3161 ui.warn(
3162 _(
3162 _(
3163 b'skipping already grafted revision %d:%s '
3163 b'skipping already grafted revision %d:%s '
3164 b'(was grafted from %d:%s)\n'
3164 b'(was grafted from %d:%s)\n'
3165 )
3165 )
3166 % (r, repo[r], rev, ctx)
3166 % (r, repo[r], rev, ctx)
3167 )
3167 )
3168 revs.remove(r)
3168 revs.remove(r)
3169 if not revs:
3169 if not revs:
3170 return -1
3170 return -1
3171
3171
3172 if opts.get(b'no_commit'):
3172 if opts.get(b'no_commit'):
3173 statedata[b'no_commit'] = True
3173 statedata[b'no_commit'] = True
3174 if opts.get(b'base'):
3174 if opts.get(b'base'):
3175 statedata[b'base'] = opts[b'base']
3175 statedata[b'base'] = opts[b'base']
3176 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3176 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3177 desc = b'%d:%s "%s"' % (
3177 desc = b'%d:%s "%s"' % (
3178 ctx.rev(),
3178 ctx.rev(),
3179 ctx,
3179 ctx,
3180 ctx.description().split(b'\n', 1)[0],
3180 ctx.description().split(b'\n', 1)[0],
3181 )
3181 )
3182 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3182 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3183 if names:
3183 if names:
3184 desc += b' (%s)' % b' '.join(names)
3184 desc += b' (%s)' % b' '.join(names)
3185 ui.status(_(b'grafting %s\n') % desc)
3185 ui.status(_(b'grafting %s\n') % desc)
3186 if opts.get(b'dry_run'):
3186 if opts.get(b'dry_run'):
3187 continue
3187 continue
3188
3188
3189 source = ctx.extra().get(b'source')
3189 source = ctx.extra().get(b'source')
3190 extra = {}
3190 extra = {}
3191 if source:
3191 if source:
3192 extra[b'source'] = source
3192 extra[b'source'] = source
3193 extra[b'intermediate-source'] = ctx.hex()
3193 extra[b'intermediate-source'] = ctx.hex()
3194 else:
3194 else:
3195 extra[b'source'] = ctx.hex()
3195 extra[b'source'] = ctx.hex()
3196 user = ctx.user()
3196 user = ctx.user()
3197 if opts.get(b'user'):
3197 if opts.get(b'user'):
3198 user = opts[b'user']
3198 user = opts[b'user']
3199 statedata[b'user'] = user
3199 statedata[b'user'] = user
3200 date = ctx.date()
3200 date = ctx.date()
3201 if opts.get(b'date'):
3201 if opts.get(b'date'):
3202 date = opts[b'date']
3202 date = opts[b'date']
3203 statedata[b'date'] = date
3203 statedata[b'date'] = date
3204 message = ctx.description()
3204 message = ctx.description()
3205 if opts.get(b'log'):
3205 if opts.get(b'log'):
3206 message += b'\n(grafted from %s)' % ctx.hex()
3206 message += b'\n(grafted from %s)' % ctx.hex()
3207 statedata[b'log'] = True
3207 statedata[b'log'] = True
3208
3208
3209 # we don't merge the first commit when continuing
3209 # we don't merge the first commit when continuing
3210 if not cont:
3210 if not cont:
3211 # perform the graft merge with p1(rev) as 'ancestor'
3211 # perform the graft merge with p1(rev) as 'ancestor'
3212 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3212 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3213 base = ctx.p1() if basectx is None else basectx
3213 base = ctx.p1() if basectx is None else basectx
3214 with ui.configoverride(overrides, b'graft'):
3214 with ui.configoverride(overrides, b'graft'):
3215 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3215 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3216 # report any conflicts
3216 # report any conflicts
3217 if stats.unresolvedcount > 0:
3217 if stats.unresolvedcount > 0:
3218 # write out state for --continue
3218 # write out state for --continue
3219 nodes = [repo[rev].hex() for rev in revs[pos:]]
3219 nodes = [repo[rev].hex() for rev in revs[pos:]]
3220 statedata[b'nodes'] = nodes
3220 statedata[b'nodes'] = nodes
3221 stateversion = 1
3221 stateversion = 1
3222 graftstate.save(stateversion, statedata)
3222 graftstate.save(stateversion, statedata)
3223 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3223 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3224 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3224 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3225 return 1
3225 return 1
3226 else:
3226 else:
3227 cont = False
3227 cont = False
3228
3228
3229 # commit if --no-commit is false
3229 # commit if --no-commit is false
3230 if not opts.get(b'no_commit'):
3230 if not opts.get(b'no_commit'):
3231 node = repo.commit(
3231 node = repo.commit(
3232 text=message, user=user, date=date, extra=extra, editor=editor
3232 text=message, user=user, date=date, extra=extra, editor=editor
3233 )
3233 )
3234 if node is None:
3234 if node is None:
3235 ui.warn(
3235 ui.warn(
3236 _(b'note: graft of %d:%s created no changes to commit\n')
3236 _(b'note: graft of %d:%s created no changes to commit\n')
3237 % (ctx.rev(), ctx)
3237 % (ctx.rev(), ctx)
3238 )
3238 )
3239 # checking that newnodes exist because old state files won't have it
3239 # checking that newnodes exist because old state files won't have it
3240 elif statedata.get(b'newnodes') is not None:
3240 elif statedata.get(b'newnodes') is not None:
3241 statedata[b'newnodes'].append(node)
3241 statedata[b'newnodes'].append(node)
3242
3242
3243 # remove state when we complete successfully
3243 # remove state when we complete successfully
3244 if not opts.get(b'dry_run'):
3244 if not opts.get(b'dry_run'):
3245 graftstate.delete()
3245 graftstate.delete()
3246
3246
3247 return 0
3247 return 0
3248
3248
3249
3249
3250 def _stopgraft(ui, repo, graftstate):
3250 def _stopgraft(ui, repo, graftstate):
3251 """stop the interrupted graft"""
3251 """stop the interrupted graft"""
3252 if not graftstate.exists():
3252 if not graftstate.exists():
3253 raise error.Abort(_(b"no interrupted graft found"))
3253 raise error.Abort(_(b"no interrupted graft found"))
3254 pctx = repo[b'.']
3254 pctx = repo[b'.']
3255 mergemod.clean_update(pctx)
3255 mergemod.clean_update(pctx)
3256 graftstate.delete()
3256 graftstate.delete()
3257 ui.status(_(b"stopped the interrupted graft\n"))
3257 ui.status(_(b"stopped the interrupted graft\n"))
3258 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3258 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3259 return 0
3259 return 0
3260
3260
3261
3261
3262 statemod.addunfinished(
3262 statemod.addunfinished(
3263 b'graft',
3263 b'graft',
3264 fname=b'graftstate',
3264 fname=b'graftstate',
3265 clearable=True,
3265 clearable=True,
3266 stopflag=True,
3266 stopflag=True,
3267 continueflag=True,
3267 continueflag=True,
3268 abortfunc=cmdutil.hgabortgraft,
3268 abortfunc=cmdutil.hgabortgraft,
3269 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3269 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3270 )
3270 )
3271
3271
3272
3272
3273 @command(
3273 @command(
3274 b'grep',
3274 b'grep',
3275 [
3275 [
3276 (b'0', b'print0', None, _(b'end fields with NUL')),
3276 (b'0', b'print0', None, _(b'end fields with NUL')),
3277 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3277 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3278 (
3278 (
3279 b'',
3279 b'',
3280 b'diff',
3280 b'diff',
3281 None,
3281 None,
3282 _(
3282 _(
3283 b'search revision differences for when the pattern was added '
3283 b'search revision differences for when the pattern was added '
3284 b'or removed'
3284 b'or removed'
3285 ),
3285 ),
3286 ),
3286 ),
3287 (b'a', b'text', None, _(b'treat all files as text')),
3287 (b'a', b'text', None, _(b'treat all files as text')),
3288 (
3288 (
3289 b'f',
3289 b'f',
3290 b'follow',
3290 b'follow',
3291 None,
3291 None,
3292 _(
3292 _(
3293 b'follow changeset history,'
3293 b'follow changeset history,'
3294 b' or file history across copies and renames'
3294 b' or file history across copies and renames'
3295 ),
3295 ),
3296 ),
3296 ),
3297 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3297 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3298 (
3298 (
3299 b'l',
3299 b'l',
3300 b'files-with-matches',
3300 b'files-with-matches',
3301 None,
3301 None,
3302 _(b'print only filenames and revisions that match'),
3302 _(b'print only filenames and revisions that match'),
3303 ),
3303 ),
3304 (b'n', b'line-number', None, _(b'print matching line numbers')),
3304 (b'n', b'line-number', None, _(b'print matching line numbers')),
3305 (
3305 (
3306 b'r',
3306 b'r',
3307 b'rev',
3307 b'rev',
3308 [],
3308 [],
3309 _(b'search files changed within revision range'),
3309 _(b'search files changed within revision range'),
3310 _(b'REV'),
3310 _(b'REV'),
3311 ),
3311 ),
3312 (
3312 (
3313 b'',
3313 b'',
3314 b'all-files',
3314 b'all-files',
3315 None,
3315 None,
3316 _(
3316 _(
3317 b'include all files in the changeset while grepping (DEPRECATED)'
3317 b'include all files in the changeset while grepping (DEPRECATED)'
3318 ),
3318 ),
3319 ),
3319 ),
3320 (b'u', b'user', None, _(b'list the author (long with -v)')),
3320 (b'u', b'user', None, _(b'list the author (long with -v)')),
3321 (b'd', b'date', None, _(b'list the date (short with -q)')),
3321 (b'd', b'date', None, _(b'list the date (short with -q)')),
3322 ]
3322 ]
3323 + formatteropts
3323 + formatteropts
3324 + walkopts,
3324 + walkopts,
3325 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3325 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3326 helpcategory=command.CATEGORY_FILE_CONTENTS,
3326 helpcategory=command.CATEGORY_FILE_CONTENTS,
3327 inferrepo=True,
3327 inferrepo=True,
3328 intents={INTENT_READONLY},
3328 intents={INTENT_READONLY},
3329 )
3329 )
3330 def grep(ui, repo, pattern, *pats, **opts):
3330 def grep(ui, repo, pattern, *pats, **opts):
3331 """search for a pattern in specified files
3331 """search for a pattern in specified files
3332
3332
3333 Search the working directory or revision history for a regular
3333 Search the working directory or revision history for a regular
3334 expression in the specified files for the entire repository.
3334 expression in the specified files for the entire repository.
3335
3335
3336 By default, grep searches the repository files in the working
3336 By default, grep searches the repository files in the working
3337 directory and prints the files where it finds a match. To specify
3337 directory and prints the files where it finds a match. To specify
3338 historical revisions instead of the working directory, use the
3338 historical revisions instead of the working directory, use the
3339 --rev flag.
3339 --rev flag.
3340
3340
3341 To search instead historical revision differences that contains a
3341 To search instead historical revision differences that contains a
3342 change in match status ("-" for a match that becomes a non-match,
3342 change in match status ("-" for a match that becomes a non-match,
3343 or "+" for a non-match that becomes a match), use the --diff flag.
3343 or "+" for a non-match that becomes a match), use the --diff flag.
3344
3344
3345 PATTERN can be any Python (roughly Perl-compatible) regular
3345 PATTERN can be any Python (roughly Perl-compatible) regular
3346 expression.
3346 expression.
3347
3347
3348 If no FILEs are specified and the --rev flag isn't supplied, all
3348 If no FILEs are specified and the --rev flag isn't supplied, all
3349 files in the working directory are searched. When using the --rev
3349 files in the working directory are searched. When using the --rev
3350 flag and specifying FILEs, use the --follow argument to also
3350 flag and specifying FILEs, use the --follow argument to also
3351 follow the specified FILEs across renames and copies.
3351 follow the specified FILEs across renames and copies.
3352
3352
3353 .. container:: verbose
3353 .. container:: verbose
3354
3354
3355 Template:
3355 Template:
3356
3356
3357 The following keywords are supported in addition to the common template
3357 The following keywords are supported in addition to the common template
3358 keywords and functions. See also :hg:`help templates`.
3358 keywords and functions. See also :hg:`help templates`.
3359
3359
3360 :change: String. Character denoting insertion ``+`` or removal ``-``.
3360 :change: String. Character denoting insertion ``+`` or removal ``-``.
3361 Available if ``--diff`` is specified.
3361 Available if ``--diff`` is specified.
3362 :lineno: Integer. Line number of the match.
3362 :lineno: Integer. Line number of the match.
3363 :path: String. Repository-absolute path of the file.
3363 :path: String. Repository-absolute path of the file.
3364 :texts: List of text chunks.
3364 :texts: List of text chunks.
3365
3365
3366 And each entry of ``{texts}`` provides the following sub-keywords.
3366 And each entry of ``{texts}`` provides the following sub-keywords.
3367
3367
3368 :matched: Boolean. True if the chunk matches the specified pattern.
3368 :matched: Boolean. True if the chunk matches the specified pattern.
3369 :text: String. Chunk content.
3369 :text: String. Chunk content.
3370
3370
3371 See :hg:`help templates.operators` for the list expansion syntax.
3371 See :hg:`help templates.operators` for the list expansion syntax.
3372
3372
3373 Returns 0 if a match is found, 1 otherwise.
3373 Returns 0 if a match is found, 1 otherwise.
3374
3374
3375 """
3375 """
3376 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3376 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3377 opts = pycompat.byteskwargs(opts)
3377 opts = pycompat.byteskwargs(opts)
3378 diff = opts.get(b'all') or opts.get(b'diff')
3378 diff = opts.get(b'all') or opts.get(b'diff')
3379 follow = opts.get(b'follow')
3379 follow = opts.get(b'follow')
3380 if opts.get(b'all_files') is None and not diff:
3380 if opts.get(b'all_files') is None and not diff:
3381 opts[b'all_files'] = True
3381 opts[b'all_files'] = True
3382 plaingrep = (
3382 plaingrep = (
3383 opts.get(b'all_files')
3383 opts.get(b'all_files')
3384 and not opts.get(b'rev')
3384 and not opts.get(b'rev')
3385 and not opts.get(b'follow')
3385 and not opts.get(b'follow')
3386 )
3386 )
3387 all_files = opts.get(b'all_files')
3387 all_files = opts.get(b'all_files')
3388 if plaingrep:
3388 if plaingrep:
3389 opts[b'rev'] = [b'wdir()']
3389 opts[b'rev'] = [b'wdir()']
3390
3390
3391 reflags = re.M
3391 reflags = re.M
3392 if opts.get(b'ignore_case'):
3392 if opts.get(b'ignore_case'):
3393 reflags |= re.I
3393 reflags |= re.I
3394 try:
3394 try:
3395 regexp = util.re.compile(pattern, reflags)
3395 regexp = util.re.compile(pattern, reflags)
3396 except re.error as inst:
3396 except re.error as inst:
3397 ui.warn(
3397 ui.warn(
3398 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3398 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3399 )
3399 )
3400 return 1
3400 return 1
3401 sep, eol = b':', b'\n'
3401 sep, eol = b':', b'\n'
3402 if opts.get(b'print0'):
3402 if opts.get(b'print0'):
3403 sep = eol = b'\0'
3403 sep = eol = b'\0'
3404
3404
3405 searcher = grepmod.grepsearcher(
3405 searcher = grepmod.grepsearcher(
3406 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3406 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3407 )
3407 )
3408
3408
3409 getfile = searcher._getfile
3409 getfile = searcher._getfile
3410
3410
3411 uipathfn = scmutil.getuipathfn(repo)
3411 uipathfn = scmutil.getuipathfn(repo)
3412
3412
3413 def display(fm, fn, ctx, pstates, states):
3413 def display(fm, fn, ctx, pstates, states):
3414 rev = scmutil.intrev(ctx)
3414 rev = scmutil.intrev(ctx)
3415 if fm.isplain():
3415 if fm.isplain():
3416 formatuser = ui.shortuser
3416 formatuser = ui.shortuser
3417 else:
3417 else:
3418 formatuser = pycompat.bytestr
3418 formatuser = pycompat.bytestr
3419 if ui.quiet:
3419 if ui.quiet:
3420 datefmt = b'%Y-%m-%d'
3420 datefmt = b'%Y-%m-%d'
3421 else:
3421 else:
3422 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3422 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3423 found = False
3423 found = False
3424
3424
3425 @util.cachefunc
3425 @util.cachefunc
3426 def binary():
3426 def binary():
3427 flog = getfile(fn)
3427 flog = getfile(fn)
3428 try:
3428 try:
3429 return stringutil.binary(flog.read(ctx.filenode(fn)))
3429 return stringutil.binary(flog.read(ctx.filenode(fn)))
3430 except error.WdirUnsupported:
3430 except error.WdirUnsupported:
3431 return ctx[fn].isbinary()
3431 return ctx[fn].isbinary()
3432
3432
3433 fieldnamemap = {b'linenumber': b'lineno'}
3433 fieldnamemap = {b'linenumber': b'lineno'}
3434 if diff:
3434 if diff:
3435 iter = grepmod.difflinestates(pstates, states)
3435 iter = grepmod.difflinestates(pstates, states)
3436 else:
3436 else:
3437 iter = [(b'', l) for l in states]
3437 iter = [(b'', l) for l in states]
3438 for change, l in iter:
3438 for change, l in iter:
3439 fm.startitem()
3439 fm.startitem()
3440 fm.context(ctx=ctx)
3440 fm.context(ctx=ctx)
3441 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3441 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3442 fm.plain(uipathfn(fn), label=b'grep.filename')
3442 fm.plain(uipathfn(fn), label=b'grep.filename')
3443
3443
3444 cols = [
3444 cols = [
3445 (b'rev', b'%d', rev, not plaingrep, b''),
3445 (b'rev', b'%d', rev, not plaingrep, b''),
3446 (
3446 (
3447 b'linenumber',
3447 b'linenumber',
3448 b'%d',
3448 b'%d',
3449 l.linenum,
3449 l.linenum,
3450 opts.get(b'line_number'),
3450 opts.get(b'line_number'),
3451 b'',
3451 b'',
3452 ),
3452 ),
3453 ]
3453 ]
3454 if diff:
3454 if diff:
3455 cols.append(
3455 cols.append(
3456 (
3456 (
3457 b'change',
3457 b'change',
3458 b'%s',
3458 b'%s',
3459 change,
3459 change,
3460 True,
3460 True,
3461 b'grep.inserted '
3461 b'grep.inserted '
3462 if change == b'+'
3462 if change == b'+'
3463 else b'grep.deleted ',
3463 else b'grep.deleted ',
3464 )
3464 )
3465 )
3465 )
3466 cols.extend(
3466 cols.extend(
3467 [
3467 [
3468 (
3468 (
3469 b'user',
3469 b'user',
3470 b'%s',
3470 b'%s',
3471 formatuser(ctx.user()),
3471 formatuser(ctx.user()),
3472 opts.get(b'user'),
3472 opts.get(b'user'),
3473 b'',
3473 b'',
3474 ),
3474 ),
3475 (
3475 (
3476 b'date',
3476 b'date',
3477 b'%s',
3477 b'%s',
3478 fm.formatdate(ctx.date(), datefmt),
3478 fm.formatdate(ctx.date(), datefmt),
3479 opts.get(b'date'),
3479 opts.get(b'date'),
3480 b'',
3480 b'',
3481 ),
3481 ),
3482 ]
3482 ]
3483 )
3483 )
3484 for name, fmt, data, cond, extra_label in cols:
3484 for name, fmt, data, cond, extra_label in cols:
3485 if cond:
3485 if cond:
3486 fm.plain(sep, label=b'grep.sep')
3486 fm.plain(sep, label=b'grep.sep')
3487 field = fieldnamemap.get(name, name)
3487 field = fieldnamemap.get(name, name)
3488 label = extra_label + (b'grep.%s' % name)
3488 label = extra_label + (b'grep.%s' % name)
3489 fm.condwrite(cond, field, fmt, data, label=label)
3489 fm.condwrite(cond, field, fmt, data, label=label)
3490 if not opts.get(b'files_with_matches'):
3490 if not opts.get(b'files_with_matches'):
3491 fm.plain(sep, label=b'grep.sep')
3491 fm.plain(sep, label=b'grep.sep')
3492 if not opts.get(b'text') and binary():
3492 if not opts.get(b'text') and binary():
3493 fm.plain(_(b" Binary file matches"))
3493 fm.plain(_(b" Binary file matches"))
3494 else:
3494 else:
3495 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3495 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3496 fm.plain(eol)
3496 fm.plain(eol)
3497 found = True
3497 found = True
3498 if opts.get(b'files_with_matches'):
3498 if opts.get(b'files_with_matches'):
3499 break
3499 break
3500 return found
3500 return found
3501
3501
3502 def displaymatches(fm, l):
3502 def displaymatches(fm, l):
3503 p = 0
3503 p = 0
3504 for s, e in l.findpos(regexp):
3504 for s, e in l.findpos(regexp):
3505 if p < s:
3505 if p < s:
3506 fm.startitem()
3506 fm.startitem()
3507 fm.write(b'text', b'%s', l.line[p:s])
3507 fm.write(b'text', b'%s', l.line[p:s])
3508 fm.data(matched=False)
3508 fm.data(matched=False)
3509 fm.startitem()
3509 fm.startitem()
3510 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3510 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3511 fm.data(matched=True)
3511 fm.data(matched=True)
3512 p = e
3512 p = e
3513 if p < len(l.line):
3513 if p < len(l.line):
3514 fm.startitem()
3514 fm.startitem()
3515 fm.write(b'text', b'%s', l.line[p:])
3515 fm.write(b'text', b'%s', l.line[p:])
3516 fm.data(matched=False)
3516 fm.data(matched=False)
3517 fm.end()
3517 fm.end()
3518
3518
3519 found = False
3519 found = False
3520
3520
3521 wopts = logcmdutil.walkopts(
3521 wopts = logcmdutil.walkopts(
3522 pats=pats,
3522 pats=pats,
3523 opts=opts,
3523 opts=opts,
3524 revspec=opts[b'rev'],
3524 revspec=opts[b'rev'],
3525 include_pats=opts[b'include'],
3525 include_pats=opts[b'include'],
3526 exclude_pats=opts[b'exclude'],
3526 exclude_pats=opts[b'exclude'],
3527 follow=follow,
3527 follow=follow,
3528 force_changelog_traversal=all_files,
3528 force_changelog_traversal=all_files,
3529 filter_revisions_by_pats=not all_files,
3529 filter_revisions_by_pats=not all_files,
3530 )
3530 )
3531 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3531 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3532
3532
3533 ui.pager(b'grep')
3533 ui.pager(b'grep')
3534 fm = ui.formatter(b'grep', opts)
3534 fm = ui.formatter(b'grep', opts)
3535 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3535 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3536 r = display(fm, fn, ctx, pstates, states)
3536 r = display(fm, fn, ctx, pstates, states)
3537 found = found or r
3537 found = found or r
3538 if r and not diff and not all_files:
3538 if r and not diff and not all_files:
3539 searcher.skipfile(fn, ctx.rev())
3539 searcher.skipfile(fn, ctx.rev())
3540 fm.end()
3540 fm.end()
3541
3541
3542 return not found
3542 return not found
3543
3543
3544
3544
3545 @command(
3545 @command(
3546 b'heads',
3546 b'heads',
3547 [
3547 [
3548 (
3548 (
3549 b'r',
3549 b'r',
3550 b'rev',
3550 b'rev',
3551 b'',
3551 b'',
3552 _(b'show only heads which are descendants of STARTREV'),
3552 _(b'show only heads which are descendants of STARTREV'),
3553 _(b'STARTREV'),
3553 _(b'STARTREV'),
3554 ),
3554 ),
3555 (b't', b'topo', False, _(b'show topological heads only')),
3555 (b't', b'topo', False, _(b'show topological heads only')),
3556 (
3556 (
3557 b'a',
3557 b'a',
3558 b'active',
3558 b'active',
3559 False,
3559 False,
3560 _(b'show active branchheads only (DEPRECATED)'),
3560 _(b'show active branchheads only (DEPRECATED)'),
3561 ),
3561 ),
3562 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3562 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3563 ]
3563 ]
3564 + templateopts,
3564 + templateopts,
3565 _(b'[-ct] [-r STARTREV] [REV]...'),
3565 _(b'[-ct] [-r STARTREV] [REV]...'),
3566 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3566 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3567 intents={INTENT_READONLY},
3567 intents={INTENT_READONLY},
3568 )
3568 )
3569 def heads(ui, repo, *branchrevs, **opts):
3569 def heads(ui, repo, *branchrevs, **opts):
3570 """show branch heads
3570 """show branch heads
3571
3571
3572 With no arguments, show all open branch heads in the repository.
3572 With no arguments, show all open branch heads in the repository.
3573 Branch heads are changesets that have no descendants on the
3573 Branch heads are changesets that have no descendants on the
3574 same branch. They are where development generally takes place and
3574 same branch. They are where development generally takes place and
3575 are the usual targets for update and merge operations.
3575 are the usual targets for update and merge operations.
3576
3576
3577 If one or more REVs are given, only open branch heads on the
3577 If one or more REVs are given, only open branch heads on the
3578 branches associated with the specified changesets are shown. This
3578 branches associated with the specified changesets are shown. This
3579 means that you can use :hg:`heads .` to see the heads on the
3579 means that you can use :hg:`heads .` to see the heads on the
3580 currently checked-out branch.
3580 currently checked-out branch.
3581
3581
3582 If -c/--closed is specified, also show branch heads marked closed
3582 If -c/--closed is specified, also show branch heads marked closed
3583 (see :hg:`commit --close-branch`).
3583 (see :hg:`commit --close-branch`).
3584
3584
3585 If STARTREV is specified, only those heads that are descendants of
3585 If STARTREV is specified, only those heads that are descendants of
3586 STARTREV will be displayed.
3586 STARTREV will be displayed.
3587
3587
3588 If -t/--topo is specified, named branch mechanics will be ignored and only
3588 If -t/--topo is specified, named branch mechanics will be ignored and only
3589 topological heads (changesets with no children) will be shown.
3589 topological heads (changesets with no children) will be shown.
3590
3590
3591 Returns 0 if matching heads are found, 1 if not.
3591 Returns 0 if matching heads are found, 1 if not.
3592 """
3592 """
3593
3593
3594 opts = pycompat.byteskwargs(opts)
3594 opts = pycompat.byteskwargs(opts)
3595 start = None
3595 start = None
3596 rev = opts.get(b'rev')
3596 rev = opts.get(b'rev')
3597 if rev:
3597 if rev:
3598 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3598 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3599 start = scmutil.revsingle(repo, rev, None).node()
3599 start = scmutil.revsingle(repo, rev, None).node()
3600
3600
3601 if opts.get(b'topo'):
3601 if opts.get(b'topo'):
3602 heads = [repo[h] for h in repo.heads(start)]
3602 heads = [repo[h] for h in repo.heads(start)]
3603 else:
3603 else:
3604 heads = []
3604 heads = []
3605 for branch in repo.branchmap():
3605 for branch in repo.branchmap():
3606 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3606 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3607 heads = [repo[h] for h in heads]
3607 heads = [repo[h] for h in heads]
3608
3608
3609 if branchrevs:
3609 if branchrevs:
3610 branches = {
3610 branches = {
3611 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3611 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3612 }
3612 }
3613 heads = [h for h in heads if h.branch() in branches]
3613 heads = [h for h in heads if h.branch() in branches]
3614
3614
3615 if opts.get(b'active') and branchrevs:
3615 if opts.get(b'active') and branchrevs:
3616 dagheads = repo.heads(start)
3616 dagheads = repo.heads(start)
3617 heads = [h for h in heads if h.node() in dagheads]
3617 heads = [h for h in heads if h.node() in dagheads]
3618
3618
3619 if branchrevs:
3619 if branchrevs:
3620 haveheads = {h.branch() for h in heads}
3620 haveheads = {h.branch() for h in heads}
3621 if branches - haveheads:
3621 if branches - haveheads:
3622 headless = b', '.join(b for b in branches - haveheads)
3622 headless = b', '.join(b for b in branches - haveheads)
3623 msg = _(b'no open branch heads found on branches %s')
3623 msg = _(b'no open branch heads found on branches %s')
3624 if opts.get(b'rev'):
3624 if opts.get(b'rev'):
3625 msg += _(b' (started at %s)') % opts[b'rev']
3625 msg += _(b' (started at %s)') % opts[b'rev']
3626 ui.warn((msg + b'\n') % headless)
3626 ui.warn((msg + b'\n') % headless)
3627
3627
3628 if not heads:
3628 if not heads:
3629 return 1
3629 return 1
3630
3630
3631 ui.pager(b'heads')
3631 ui.pager(b'heads')
3632 heads = sorted(heads, key=lambda x: -(x.rev()))
3632 heads = sorted(heads, key=lambda x: -(x.rev()))
3633 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3633 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3634 for ctx in heads:
3634 for ctx in heads:
3635 displayer.show(ctx)
3635 displayer.show(ctx)
3636 displayer.close()
3636 displayer.close()
3637
3637
3638
3638
3639 @command(
3639 @command(
3640 b'help',
3640 b'help',
3641 [
3641 [
3642 (b'e', b'extension', None, _(b'show only help for extensions')),
3642 (b'e', b'extension', None, _(b'show only help for extensions')),
3643 (b'c', b'command', None, _(b'show only help for commands')),
3643 (b'c', b'command', None, _(b'show only help for commands')),
3644 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3644 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3645 (
3645 (
3646 b's',
3646 b's',
3647 b'system',
3647 b'system',
3648 [],
3648 [],
3649 _(b'show help for specific platform(s)'),
3649 _(b'show help for specific platform(s)'),
3650 _(b'PLATFORM'),
3650 _(b'PLATFORM'),
3651 ),
3651 ),
3652 ],
3652 ],
3653 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3653 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3654 helpcategory=command.CATEGORY_HELP,
3654 helpcategory=command.CATEGORY_HELP,
3655 norepo=True,
3655 norepo=True,
3656 intents={INTENT_READONLY},
3656 intents={INTENT_READONLY},
3657 )
3657 )
3658 def help_(ui, name=None, **opts):
3658 def help_(ui, name=None, **opts):
3659 """show help for a given topic or a help overview
3659 """show help for a given topic or a help overview
3660
3660
3661 With no arguments, print a list of commands with short help messages.
3661 With no arguments, print a list of commands with short help messages.
3662
3662
3663 Given a topic, extension, or command name, print help for that
3663 Given a topic, extension, or command name, print help for that
3664 topic.
3664 topic.
3665
3665
3666 Returns 0 if successful.
3666 Returns 0 if successful.
3667 """
3667 """
3668
3668
3669 keep = opts.get('system') or []
3669 keep = opts.get('system') or []
3670 if len(keep) == 0:
3670 if len(keep) == 0:
3671 if pycompat.sysplatform.startswith(b'win'):
3671 if pycompat.sysplatform.startswith(b'win'):
3672 keep.append(b'windows')
3672 keep.append(b'windows')
3673 elif pycompat.sysplatform == b'OpenVMS':
3673 elif pycompat.sysplatform == b'OpenVMS':
3674 keep.append(b'vms')
3674 keep.append(b'vms')
3675 elif pycompat.sysplatform == b'plan9':
3675 elif pycompat.sysplatform == b'plan9':
3676 keep.append(b'plan9')
3676 keep.append(b'plan9')
3677 else:
3677 else:
3678 keep.append(b'unix')
3678 keep.append(b'unix')
3679 keep.append(pycompat.sysplatform.lower())
3679 keep.append(pycompat.sysplatform.lower())
3680 if ui.verbose:
3680 if ui.verbose:
3681 keep.append(b'verbose')
3681 keep.append(b'verbose')
3682
3682
3683 commands = sys.modules[__name__]
3683 commands = sys.modules[__name__]
3684 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3684 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3685 ui.pager(b'help')
3685 ui.pager(b'help')
3686 ui.write(formatted)
3686 ui.write(formatted)
3687
3687
3688
3688
3689 @command(
3689 @command(
3690 b'identify|id',
3690 b'identify|id',
3691 [
3691 [
3692 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3692 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3693 (b'n', b'num', None, _(b'show local revision number')),
3693 (b'n', b'num', None, _(b'show local revision number')),
3694 (b'i', b'id', None, _(b'show global revision id')),
3694 (b'i', b'id', None, _(b'show global revision id')),
3695 (b'b', b'branch', None, _(b'show branch')),
3695 (b'b', b'branch', None, _(b'show branch')),
3696 (b't', b'tags', None, _(b'show tags')),
3696 (b't', b'tags', None, _(b'show tags')),
3697 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3697 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3698 ]
3698 ]
3699 + remoteopts
3699 + remoteopts
3700 + formatteropts,
3700 + formatteropts,
3701 _(b'[-nibtB] [-r REV] [SOURCE]'),
3701 _(b'[-nibtB] [-r REV] [SOURCE]'),
3702 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3702 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3703 optionalrepo=True,
3703 optionalrepo=True,
3704 intents={INTENT_READONLY},
3704 intents={INTENT_READONLY},
3705 )
3705 )
3706 def identify(
3706 def identify(
3707 ui,
3707 ui,
3708 repo,
3708 repo,
3709 source=None,
3709 source=None,
3710 rev=None,
3710 rev=None,
3711 num=None,
3711 num=None,
3712 id=None,
3712 id=None,
3713 branch=None,
3713 branch=None,
3714 tags=None,
3714 tags=None,
3715 bookmarks=None,
3715 bookmarks=None,
3716 **opts
3716 **opts
3717 ):
3717 ):
3718 """identify the working directory or specified revision
3718 """identify the working directory or specified revision
3719
3719
3720 Print a summary identifying the repository state at REV using one or
3720 Print a summary identifying the repository state at REV using one or
3721 two parent hash identifiers, followed by a "+" if the working
3721 two parent hash identifiers, followed by a "+" if the working
3722 directory has uncommitted changes, the branch name (if not default),
3722 directory has uncommitted changes, the branch name (if not default),
3723 a list of tags, and a list of bookmarks.
3723 a list of tags, and a list of bookmarks.
3724
3724
3725 When REV is not given, print a summary of the current state of the
3725 When REV is not given, print a summary of the current state of the
3726 repository including the working directory. Specify -r. to get information
3726 repository including the working directory. Specify -r. to get information
3727 of the working directory parent without scanning uncommitted changes.
3727 of the working directory parent without scanning uncommitted changes.
3728
3728
3729 Specifying a path to a repository root or Mercurial bundle will
3729 Specifying a path to a repository root or Mercurial bundle will
3730 cause lookup to operate on that repository/bundle.
3730 cause lookup to operate on that repository/bundle.
3731
3731
3732 .. container:: verbose
3732 .. container:: verbose
3733
3733
3734 Template:
3734 Template:
3735
3735
3736 The following keywords are supported in addition to the common template
3736 The following keywords are supported in addition to the common template
3737 keywords and functions. See also :hg:`help templates`.
3737 keywords and functions. See also :hg:`help templates`.
3738
3738
3739 :dirty: String. Character ``+`` denoting if the working directory has
3739 :dirty: String. Character ``+`` denoting if the working directory has
3740 uncommitted changes.
3740 uncommitted changes.
3741 :id: String. One or two nodes, optionally followed by ``+``.
3741 :id: String. One or two nodes, optionally followed by ``+``.
3742 :parents: List of strings. Parent nodes of the changeset.
3742 :parents: List of strings. Parent nodes of the changeset.
3743
3743
3744 Examples:
3744 Examples:
3745
3745
3746 - generate a build identifier for the working directory::
3746 - generate a build identifier for the working directory::
3747
3747
3748 hg id --id > build-id.dat
3748 hg id --id > build-id.dat
3749
3749
3750 - find the revision corresponding to a tag::
3750 - find the revision corresponding to a tag::
3751
3751
3752 hg id -n -r 1.3
3752 hg id -n -r 1.3
3753
3753
3754 - check the most recent revision of a remote repository::
3754 - check the most recent revision of a remote repository::
3755
3755
3756 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3756 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3757
3757
3758 See :hg:`log` for generating more information about specific revisions,
3758 See :hg:`log` for generating more information about specific revisions,
3759 including full hash identifiers.
3759 including full hash identifiers.
3760
3760
3761 Returns 0 if successful.
3761 Returns 0 if successful.
3762 """
3762 """
3763
3763
3764 opts = pycompat.byteskwargs(opts)
3764 opts = pycompat.byteskwargs(opts)
3765 if not repo and not source:
3765 if not repo and not source:
3766 raise error.Abort(
3766 raise error.Abort(
3767 _(b"there is no Mercurial repository here (.hg not found)")
3767 _(b"there is no Mercurial repository here (.hg not found)")
3768 )
3768 )
3769
3769
3770 default = not (num or id or branch or tags or bookmarks)
3770 default = not (num or id or branch or tags or bookmarks)
3771 output = []
3771 output = []
3772 revs = []
3772 revs = []
3773
3773
3774 if source:
3774 if source:
3775 source, branches = hg.parseurl(ui.expandpath(source))
3775 source, branches = hg.parseurl(ui.expandpath(source))
3776 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3776 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3777 repo = peer.local()
3777 repo = peer.local()
3778 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3778 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3779
3779
3780 fm = ui.formatter(b'identify', opts)
3780 fm = ui.formatter(b'identify', opts)
3781 fm.startitem()
3781 fm.startitem()
3782
3782
3783 if not repo:
3783 if not repo:
3784 if num or branch or tags:
3784 if num or branch or tags:
3785 raise error.Abort(
3785 raise error.Abort(
3786 _(b"can't query remote revision number, branch, or tags")
3786 _(b"can't query remote revision number, branch, or tags")
3787 )
3787 )
3788 if not rev and revs:
3788 if not rev and revs:
3789 rev = revs[0]
3789 rev = revs[0]
3790 if not rev:
3790 if not rev:
3791 rev = b"tip"
3791 rev = b"tip"
3792
3792
3793 remoterev = peer.lookup(rev)
3793 remoterev = peer.lookup(rev)
3794 hexrev = fm.hexfunc(remoterev)
3794 hexrev = fm.hexfunc(remoterev)
3795 if default or id:
3795 if default or id:
3796 output = [hexrev]
3796 output = [hexrev]
3797 fm.data(id=hexrev)
3797 fm.data(id=hexrev)
3798
3798
3799 @util.cachefunc
3799 @util.cachefunc
3800 def getbms():
3800 def getbms():
3801 bms = []
3801 bms = []
3802
3802
3803 if b'bookmarks' in peer.listkeys(b'namespaces'):
3803 if b'bookmarks' in peer.listkeys(b'namespaces'):
3804 hexremoterev = hex(remoterev)
3804 hexremoterev = hex(remoterev)
3805 bms = [
3805 bms = [
3806 bm
3806 bm
3807 for bm, bmr in pycompat.iteritems(
3807 for bm, bmr in pycompat.iteritems(
3808 peer.listkeys(b'bookmarks')
3808 peer.listkeys(b'bookmarks')
3809 )
3809 )
3810 if bmr == hexremoterev
3810 if bmr == hexremoterev
3811 ]
3811 ]
3812
3812
3813 return sorted(bms)
3813 return sorted(bms)
3814
3814
3815 if fm.isplain():
3815 if fm.isplain():
3816 if bookmarks:
3816 if bookmarks:
3817 output.extend(getbms())
3817 output.extend(getbms())
3818 elif default and not ui.quiet:
3818 elif default and not ui.quiet:
3819 # multiple bookmarks for a single parent separated by '/'
3819 # multiple bookmarks for a single parent separated by '/'
3820 bm = b'/'.join(getbms())
3820 bm = b'/'.join(getbms())
3821 if bm:
3821 if bm:
3822 output.append(bm)
3822 output.append(bm)
3823 else:
3823 else:
3824 fm.data(node=hex(remoterev))
3824 fm.data(node=hex(remoterev))
3825 if bookmarks or b'bookmarks' in fm.datahint():
3825 if bookmarks or b'bookmarks' in fm.datahint():
3826 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3826 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3827 else:
3827 else:
3828 if rev:
3828 if rev:
3829 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3829 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3830 ctx = scmutil.revsingle(repo, rev, None)
3830 ctx = scmutil.revsingle(repo, rev, None)
3831
3831
3832 if ctx.rev() is None:
3832 if ctx.rev() is None:
3833 ctx = repo[None]
3833 ctx = repo[None]
3834 parents = ctx.parents()
3834 parents = ctx.parents()
3835 taglist = []
3835 taglist = []
3836 for p in parents:
3836 for p in parents:
3837 taglist.extend(p.tags())
3837 taglist.extend(p.tags())
3838
3838
3839 dirty = b""
3839 dirty = b""
3840 if ctx.dirty(missing=True, merge=False, branch=False):
3840 if ctx.dirty(missing=True, merge=False, branch=False):
3841 dirty = b'+'
3841 dirty = b'+'
3842 fm.data(dirty=dirty)
3842 fm.data(dirty=dirty)
3843
3843
3844 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3844 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3845 if default or id:
3845 if default or id:
3846 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3846 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3847 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3847 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3848
3848
3849 if num:
3849 if num:
3850 numoutput = [b"%d" % p.rev() for p in parents]
3850 numoutput = [b"%d" % p.rev() for p in parents]
3851 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3851 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3852
3852
3853 fm.data(
3853 fm.data(
3854 parents=fm.formatlist(
3854 parents=fm.formatlist(
3855 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3855 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3856 )
3856 )
3857 )
3857 )
3858 else:
3858 else:
3859 hexoutput = fm.hexfunc(ctx.node())
3859 hexoutput = fm.hexfunc(ctx.node())
3860 if default or id:
3860 if default or id:
3861 output = [hexoutput]
3861 output = [hexoutput]
3862 fm.data(id=hexoutput)
3862 fm.data(id=hexoutput)
3863
3863
3864 if num:
3864 if num:
3865 output.append(pycompat.bytestr(ctx.rev()))
3865 output.append(pycompat.bytestr(ctx.rev()))
3866 taglist = ctx.tags()
3866 taglist = ctx.tags()
3867
3867
3868 if default and not ui.quiet:
3868 if default and not ui.quiet:
3869 b = ctx.branch()
3869 b = ctx.branch()
3870 if b != b'default':
3870 if b != b'default':
3871 output.append(b"(%s)" % b)
3871 output.append(b"(%s)" % b)
3872
3872
3873 # multiple tags for a single parent separated by '/'
3873 # multiple tags for a single parent separated by '/'
3874 t = b'/'.join(taglist)
3874 t = b'/'.join(taglist)
3875 if t:
3875 if t:
3876 output.append(t)
3876 output.append(t)
3877
3877
3878 # multiple bookmarks for a single parent separated by '/'
3878 # multiple bookmarks for a single parent separated by '/'
3879 bm = b'/'.join(ctx.bookmarks())
3879 bm = b'/'.join(ctx.bookmarks())
3880 if bm:
3880 if bm:
3881 output.append(bm)
3881 output.append(bm)
3882 else:
3882 else:
3883 if branch:
3883 if branch:
3884 output.append(ctx.branch())
3884 output.append(ctx.branch())
3885
3885
3886 if tags:
3886 if tags:
3887 output.extend(taglist)
3887 output.extend(taglist)
3888
3888
3889 if bookmarks:
3889 if bookmarks:
3890 output.extend(ctx.bookmarks())
3890 output.extend(ctx.bookmarks())
3891
3891
3892 fm.data(node=ctx.hex())
3892 fm.data(node=ctx.hex())
3893 fm.data(branch=ctx.branch())
3893 fm.data(branch=ctx.branch())
3894 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3894 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3895 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3895 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3896 fm.context(ctx=ctx)
3896 fm.context(ctx=ctx)
3897
3897
3898 fm.plain(b"%s\n" % b' '.join(output))
3898 fm.plain(b"%s\n" % b' '.join(output))
3899 fm.end()
3899 fm.end()
3900
3900
3901
3901
3902 @command(
3902 @command(
3903 b'import|patch',
3903 b'import|patch',
3904 [
3904 [
3905 (
3905 (
3906 b'p',
3906 b'p',
3907 b'strip',
3907 b'strip',
3908 1,
3908 1,
3909 _(
3909 _(
3910 b'directory strip option for patch. This has the same '
3910 b'directory strip option for patch. This has the same '
3911 b'meaning as the corresponding patch option'
3911 b'meaning as the corresponding patch option'
3912 ),
3912 ),
3913 _(b'NUM'),
3913 _(b'NUM'),
3914 ),
3914 ),
3915 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3915 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3916 (b'', b'secret', None, _(b'use the secret phase for committing')),
3916 (b'', b'secret', None, _(b'use the secret phase for committing')),
3917 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3917 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3918 (
3918 (
3919 b'f',
3919 b'f',
3920 b'force',
3920 b'force',
3921 None,
3921 None,
3922 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3922 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3923 ),
3923 ),
3924 (
3924 (
3925 b'',
3925 b'',
3926 b'no-commit',
3926 b'no-commit',
3927 None,
3927 None,
3928 _(b"don't commit, just update the working directory"),
3928 _(b"don't commit, just update the working directory"),
3929 ),
3929 ),
3930 (
3930 (
3931 b'',
3931 b'',
3932 b'bypass',
3932 b'bypass',
3933 None,
3933 None,
3934 _(b"apply patch without touching the working directory"),
3934 _(b"apply patch without touching the working directory"),
3935 ),
3935 ),
3936 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3936 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3937 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3937 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3938 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3938 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3939 (
3939 (
3940 b'',
3940 b'',
3941 b'import-branch',
3941 b'import-branch',
3942 None,
3942 None,
3943 _(b'use any branch information in patch (implied by --exact)'),
3943 _(b'use any branch information in patch (implied by --exact)'),
3944 ),
3944 ),
3945 ]
3945 ]
3946 + commitopts
3946 + commitopts
3947 + commitopts2
3947 + commitopts2
3948 + similarityopts,
3948 + similarityopts,
3949 _(b'[OPTION]... PATCH...'),
3949 _(b'[OPTION]... PATCH...'),
3950 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3950 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3951 )
3951 )
3952 def import_(ui, repo, patch1=None, *patches, **opts):
3952 def import_(ui, repo, patch1=None, *patches, **opts):
3953 """import an ordered set of patches
3953 """import an ordered set of patches
3954
3954
3955 Import a list of patches and commit them individually (unless
3955 Import a list of patches and commit them individually (unless
3956 --no-commit is specified).
3956 --no-commit is specified).
3957
3957
3958 To read a patch from standard input (stdin), use "-" as the patch
3958 To read a patch from standard input (stdin), use "-" as the patch
3959 name. If a URL is specified, the patch will be downloaded from
3959 name. If a URL is specified, the patch will be downloaded from
3960 there.
3960 there.
3961
3961
3962 Import first applies changes to the working directory (unless
3962 Import first applies changes to the working directory (unless
3963 --bypass is specified), import will abort if there are outstanding
3963 --bypass is specified), import will abort if there are outstanding
3964 changes.
3964 changes.
3965
3965
3966 Use --bypass to apply and commit patches directly to the
3966 Use --bypass to apply and commit patches directly to the
3967 repository, without affecting the working directory. Without
3967 repository, without affecting the working directory. Without
3968 --exact, patches will be applied on top of the working directory
3968 --exact, patches will be applied on top of the working directory
3969 parent revision.
3969 parent revision.
3970
3970
3971 You can import a patch straight from a mail message. Even patches
3971 You can import a patch straight from a mail message. Even patches
3972 as attachments work (to use the body part, it must have type
3972 as attachments work (to use the body part, it must have type
3973 text/plain or text/x-patch). From and Subject headers of email
3973 text/plain or text/x-patch). From and Subject headers of email
3974 message are used as default committer and commit message. All
3974 message are used as default committer and commit message. All
3975 text/plain body parts before first diff are added to the commit
3975 text/plain body parts before first diff are added to the commit
3976 message.
3976 message.
3977
3977
3978 If the imported patch was generated by :hg:`export`, user and
3978 If the imported patch was generated by :hg:`export`, user and
3979 description from patch override values from message headers and
3979 description from patch override values from message headers and
3980 body. Values given on command line with -m/--message and -u/--user
3980 body. Values given on command line with -m/--message and -u/--user
3981 override these.
3981 override these.
3982
3982
3983 If --exact is specified, import will set the working directory to
3983 If --exact is specified, import will set the working directory to
3984 the parent of each patch before applying it, and will abort if the
3984 the parent of each patch before applying it, and will abort if the
3985 resulting changeset has a different ID than the one recorded in
3985 resulting changeset has a different ID than the one recorded in
3986 the patch. This will guard against various ways that portable
3986 the patch. This will guard against various ways that portable
3987 patch formats and mail systems might fail to transfer Mercurial
3987 patch formats and mail systems might fail to transfer Mercurial
3988 data or metadata. See :hg:`bundle` for lossless transmission.
3988 data or metadata. See :hg:`bundle` for lossless transmission.
3989
3989
3990 Use --partial to ensure a changeset will be created from the patch
3990 Use --partial to ensure a changeset will be created from the patch
3991 even if some hunks fail to apply. Hunks that fail to apply will be
3991 even if some hunks fail to apply. Hunks that fail to apply will be
3992 written to a <target-file>.rej file. Conflicts can then be resolved
3992 written to a <target-file>.rej file. Conflicts can then be resolved
3993 by hand before :hg:`commit --amend` is run to update the created
3993 by hand before :hg:`commit --amend` is run to update the created
3994 changeset. This flag exists to let people import patches that
3994 changeset. This flag exists to let people import patches that
3995 partially apply without losing the associated metadata (author,
3995 partially apply without losing the associated metadata (author,
3996 date, description, ...).
3996 date, description, ...).
3997
3997
3998 .. note::
3998 .. note::
3999
3999
4000 When no hunks apply cleanly, :hg:`import --partial` will create
4000 When no hunks apply cleanly, :hg:`import --partial` will create
4001 an empty changeset, importing only the patch metadata.
4001 an empty changeset, importing only the patch metadata.
4002
4002
4003 With -s/--similarity, hg will attempt to discover renames and
4003 With -s/--similarity, hg will attempt to discover renames and
4004 copies in the patch in the same way as :hg:`addremove`.
4004 copies in the patch in the same way as :hg:`addremove`.
4005
4005
4006 It is possible to use external patch programs to perform the patch
4006 It is possible to use external patch programs to perform the patch
4007 by setting the ``ui.patch`` configuration option. For the default
4007 by setting the ``ui.patch`` configuration option. For the default
4008 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4008 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4009 See :hg:`help config` for more information about configuration
4009 See :hg:`help config` for more information about configuration
4010 files and how to use these options.
4010 files and how to use these options.
4011
4011
4012 See :hg:`help dates` for a list of formats valid for -d/--date.
4012 See :hg:`help dates` for a list of formats valid for -d/--date.
4013
4013
4014 .. container:: verbose
4014 .. container:: verbose
4015
4015
4016 Examples:
4016 Examples:
4017
4017
4018 - import a traditional patch from a website and detect renames::
4018 - import a traditional patch from a website and detect renames::
4019
4019
4020 hg import -s 80 http://example.com/bugfix.patch
4020 hg import -s 80 http://example.com/bugfix.patch
4021
4021
4022 - import a changeset from an hgweb server::
4022 - import a changeset from an hgweb server::
4023
4023
4024 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4024 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4025
4025
4026 - import all the patches in an Unix-style mbox::
4026 - import all the patches in an Unix-style mbox::
4027
4027
4028 hg import incoming-patches.mbox
4028 hg import incoming-patches.mbox
4029
4029
4030 - import patches from stdin::
4030 - import patches from stdin::
4031
4031
4032 hg import -
4032 hg import -
4033
4033
4034 - attempt to exactly restore an exported changeset (not always
4034 - attempt to exactly restore an exported changeset (not always
4035 possible)::
4035 possible)::
4036
4036
4037 hg import --exact proposed-fix.patch
4037 hg import --exact proposed-fix.patch
4038
4038
4039 - use an external tool to apply a patch which is too fuzzy for
4039 - use an external tool to apply a patch which is too fuzzy for
4040 the default internal tool.
4040 the default internal tool.
4041
4041
4042 hg import --config ui.patch="patch --merge" fuzzy.patch
4042 hg import --config ui.patch="patch --merge" fuzzy.patch
4043
4043
4044 - change the default fuzzing from 2 to a less strict 7
4044 - change the default fuzzing from 2 to a less strict 7
4045
4045
4046 hg import --config ui.fuzz=7 fuzz.patch
4046 hg import --config ui.fuzz=7 fuzz.patch
4047
4047
4048 Returns 0 on success, 1 on partial success (see --partial).
4048 Returns 0 on success, 1 on partial success (see --partial).
4049 """
4049 """
4050
4050
4051 cmdutil.check_incompatible_arguments(
4051 cmdutil.check_incompatible_arguments(
4052 opts, 'no_commit', ['bypass', 'secret']
4052 opts, 'no_commit', ['bypass', 'secret']
4053 )
4053 )
4054 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4054 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4055 opts = pycompat.byteskwargs(opts)
4055 opts = pycompat.byteskwargs(opts)
4056 if not patch1:
4056 if not patch1:
4057 raise error.Abort(_(b'need at least one patch to import'))
4057 raise error.Abort(_(b'need at least one patch to import'))
4058
4058
4059 patches = (patch1,) + patches
4059 patches = (patch1,) + patches
4060
4060
4061 date = opts.get(b'date')
4061 date = opts.get(b'date')
4062 if date:
4062 if date:
4063 opts[b'date'] = dateutil.parsedate(date)
4063 opts[b'date'] = dateutil.parsedate(date)
4064
4064
4065 exact = opts.get(b'exact')
4065 exact = opts.get(b'exact')
4066 update = not opts.get(b'bypass')
4066 update = not opts.get(b'bypass')
4067 try:
4067 try:
4068 sim = float(opts.get(b'similarity') or 0)
4068 sim = float(opts.get(b'similarity') or 0)
4069 except ValueError:
4069 except ValueError:
4070 raise error.Abort(_(b'similarity must be a number'))
4070 raise error.Abort(_(b'similarity must be a number'))
4071 if sim < 0 or sim > 100:
4071 if sim < 0 or sim > 100:
4072 raise error.Abort(_(b'similarity must be between 0 and 100'))
4072 raise error.Abort(_(b'similarity must be between 0 and 100'))
4073 if sim and not update:
4073 if sim and not update:
4074 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4074 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4075
4075
4076 base = opts[b"base"]
4076 base = opts[b"base"]
4077 msgs = []
4077 msgs = []
4078 ret = 0
4078 ret = 0
4079
4079
4080 with repo.wlock():
4080 with repo.wlock():
4081 if update:
4081 if update:
4082 cmdutil.checkunfinished(repo)
4082 cmdutil.checkunfinished(repo)
4083 if exact or not opts.get(b'force'):
4083 if exact or not opts.get(b'force'):
4084 cmdutil.bailifchanged(repo)
4084 cmdutil.bailifchanged(repo)
4085
4085
4086 if not opts.get(b'no_commit'):
4086 if not opts.get(b'no_commit'):
4087 lock = repo.lock
4087 lock = repo.lock
4088 tr = lambda: repo.transaction(b'import')
4088 tr = lambda: repo.transaction(b'import')
4089 dsguard = util.nullcontextmanager
4089 dsguard = util.nullcontextmanager
4090 else:
4090 else:
4091 lock = util.nullcontextmanager
4091 lock = util.nullcontextmanager
4092 tr = util.nullcontextmanager
4092 tr = util.nullcontextmanager
4093 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4093 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4094 with lock(), tr(), dsguard():
4094 with lock(), tr(), dsguard():
4095 parents = repo[None].parents()
4095 parents = repo[None].parents()
4096 for patchurl in patches:
4096 for patchurl in patches:
4097 if patchurl == b'-':
4097 if patchurl == b'-':
4098 ui.status(_(b'applying patch from stdin\n'))
4098 ui.status(_(b'applying patch from stdin\n'))
4099 patchfile = ui.fin
4099 patchfile = ui.fin
4100 patchurl = b'stdin' # for error message
4100 patchurl = b'stdin' # for error message
4101 else:
4101 else:
4102 patchurl = os.path.join(base, patchurl)
4102 patchurl = os.path.join(base, patchurl)
4103 ui.status(_(b'applying %s\n') % patchurl)
4103 ui.status(_(b'applying %s\n') % patchurl)
4104 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4104 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4105
4105
4106 haspatch = False
4106 haspatch = False
4107 for hunk in patch.split(patchfile):
4107 for hunk in patch.split(patchfile):
4108 with patch.extract(ui, hunk) as patchdata:
4108 with patch.extract(ui, hunk) as patchdata:
4109 msg, node, rej = cmdutil.tryimportone(
4109 msg, node, rej = cmdutil.tryimportone(
4110 ui, repo, patchdata, parents, opts, msgs, hg.clean
4110 ui, repo, patchdata, parents, opts, msgs, hg.clean
4111 )
4111 )
4112 if msg:
4112 if msg:
4113 haspatch = True
4113 haspatch = True
4114 ui.note(msg + b'\n')
4114 ui.note(msg + b'\n')
4115 if update or exact:
4115 if update or exact:
4116 parents = repo[None].parents()
4116 parents = repo[None].parents()
4117 else:
4117 else:
4118 parents = [repo[node]]
4118 parents = [repo[node]]
4119 if rej:
4119 if rej:
4120 ui.write_err(_(b"patch applied partially\n"))
4120 ui.write_err(_(b"patch applied partially\n"))
4121 ui.write_err(
4121 ui.write_err(
4122 _(
4122 _(
4123 b"(fix the .rej files and run "
4123 b"(fix the .rej files and run "
4124 b"`hg commit --amend`)\n"
4124 b"`hg commit --amend`)\n"
4125 )
4125 )
4126 )
4126 )
4127 ret = 1
4127 ret = 1
4128 break
4128 break
4129
4129
4130 if not haspatch:
4130 if not haspatch:
4131 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4131 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4132
4132
4133 if msgs:
4133 if msgs:
4134 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4134 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4135 return ret
4135 return ret
4136
4136
4137
4137
4138 @command(
4138 @command(
4139 b'incoming|in',
4139 b'incoming|in',
4140 [
4140 [
4141 (
4141 (
4142 b'f',
4142 b'f',
4143 b'force',
4143 b'force',
4144 None,
4144 None,
4145 _(b'run even if remote repository is unrelated'),
4145 _(b'run even if remote repository is unrelated'),
4146 ),
4146 ),
4147 (b'n', b'newest-first', None, _(b'show newest record first')),
4147 (b'n', b'newest-first', None, _(b'show newest record first')),
4148 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4148 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4149 (
4149 (
4150 b'r',
4150 b'r',
4151 b'rev',
4151 b'rev',
4152 [],
4152 [],
4153 _(b'a remote changeset intended to be added'),
4153 _(b'a remote changeset intended to be added'),
4154 _(b'REV'),
4154 _(b'REV'),
4155 ),
4155 ),
4156 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4156 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4157 (
4157 (
4158 b'b',
4158 b'b',
4159 b'branch',
4159 b'branch',
4160 [],
4160 [],
4161 _(b'a specific branch you would like to pull'),
4161 _(b'a specific branch you would like to pull'),
4162 _(b'BRANCH'),
4162 _(b'BRANCH'),
4163 ),
4163 ),
4164 ]
4164 ]
4165 + logopts
4165 + logopts
4166 + remoteopts
4166 + remoteopts
4167 + subrepoopts,
4167 + subrepoopts,
4168 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4168 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4169 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4169 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4170 )
4170 )
4171 def incoming(ui, repo, source=b"default", **opts):
4171 def incoming(ui, repo, source=b"default", **opts):
4172 """show new changesets found in source
4172 """show new changesets found in source
4173
4173
4174 Show new changesets found in the specified path/URL or the default
4174 Show new changesets found in the specified path/URL or the default
4175 pull location. These are the changesets that would have been pulled
4175 pull location. These are the changesets that would have been pulled
4176 by :hg:`pull` at the time you issued this command.
4176 by :hg:`pull` at the time you issued this command.
4177
4177
4178 See pull for valid source format details.
4178 See pull for valid source format details.
4179
4179
4180 .. container:: verbose
4180 .. container:: verbose
4181
4181
4182 With -B/--bookmarks, the result of bookmark comparison between
4182 With -B/--bookmarks, the result of bookmark comparison between
4183 local and remote repositories is displayed. With -v/--verbose,
4183 local and remote repositories is displayed. With -v/--verbose,
4184 status is also displayed for each bookmark like below::
4184 status is also displayed for each bookmark like below::
4185
4185
4186 BM1 01234567890a added
4186 BM1 01234567890a added
4187 BM2 1234567890ab advanced
4187 BM2 1234567890ab advanced
4188 BM3 234567890abc diverged
4188 BM3 234567890abc diverged
4189 BM4 34567890abcd changed
4189 BM4 34567890abcd changed
4190
4190
4191 The action taken locally when pulling depends on the
4191 The action taken locally when pulling depends on the
4192 status of each bookmark:
4192 status of each bookmark:
4193
4193
4194 :``added``: pull will create it
4194 :``added``: pull will create it
4195 :``advanced``: pull will update it
4195 :``advanced``: pull will update it
4196 :``diverged``: pull will create a divergent bookmark
4196 :``diverged``: pull will create a divergent bookmark
4197 :``changed``: result depends on remote changesets
4197 :``changed``: result depends on remote changesets
4198
4198
4199 From the point of view of pulling behavior, bookmark
4199 From the point of view of pulling behavior, bookmark
4200 existing only in the remote repository are treated as ``added``,
4200 existing only in the remote repository are treated as ``added``,
4201 even if it is in fact locally deleted.
4201 even if it is in fact locally deleted.
4202
4202
4203 .. container:: verbose
4203 .. container:: verbose
4204
4204
4205 For remote repository, using --bundle avoids downloading the
4205 For remote repository, using --bundle avoids downloading the
4206 changesets twice if the incoming is followed by a pull.
4206 changesets twice if the incoming is followed by a pull.
4207
4207
4208 Examples:
4208 Examples:
4209
4209
4210 - show incoming changes with patches and full description::
4210 - show incoming changes with patches and full description::
4211
4211
4212 hg incoming -vp
4212 hg incoming -vp
4213
4213
4214 - show incoming changes excluding merges, store a bundle::
4214 - show incoming changes excluding merges, store a bundle::
4215
4215
4216 hg in -vpM --bundle incoming.hg
4216 hg in -vpM --bundle incoming.hg
4217 hg pull incoming.hg
4217 hg pull incoming.hg
4218
4218
4219 - briefly list changes inside a bundle::
4219 - briefly list changes inside a bundle::
4220
4220
4221 hg in changes.hg -T "{desc|firstline}\\n"
4221 hg in changes.hg -T "{desc|firstline}\\n"
4222
4222
4223 Returns 0 if there are incoming changes, 1 otherwise.
4223 Returns 0 if there are incoming changes, 1 otherwise.
4224 """
4224 """
4225 opts = pycompat.byteskwargs(opts)
4225 opts = pycompat.byteskwargs(opts)
4226 if opts.get(b'graph'):
4226 if opts.get(b'graph'):
4227 logcmdutil.checkunsupportedgraphflags([], opts)
4227 logcmdutil.checkunsupportedgraphflags([], opts)
4228
4228
4229 def display(other, chlist, displayer):
4229 def display(other, chlist, displayer):
4230 revdag = logcmdutil.graphrevs(other, chlist, opts)
4230 revdag = logcmdutil.graphrevs(other, chlist, opts)
4231 logcmdutil.displaygraph(
4231 logcmdutil.displaygraph(
4232 ui, repo, revdag, displayer, graphmod.asciiedges
4232 ui, repo, revdag, displayer, graphmod.asciiedges
4233 )
4233 )
4234
4234
4235 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4235 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4236 return 0
4236 return 0
4237
4237
4238 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4238 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4239
4239
4240 if opts.get(b'bookmarks'):
4240 if opts.get(b'bookmarks'):
4241 source, branches = hg.parseurl(
4241 source, branches = hg.parseurl(
4242 ui.expandpath(source), opts.get(b'branch')
4242 ui.expandpath(source), opts.get(b'branch')
4243 )
4243 )
4244 other = hg.peer(repo, opts, source)
4244 other = hg.peer(repo, opts, source)
4245 if b'bookmarks' not in other.listkeys(b'namespaces'):
4245 if b'bookmarks' not in other.listkeys(b'namespaces'):
4246 ui.warn(_(b"remote doesn't support bookmarks\n"))
4246 ui.warn(_(b"remote doesn't support bookmarks\n"))
4247 return 0
4247 return 0
4248 ui.pager(b'incoming')
4248 ui.pager(b'incoming')
4249 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4249 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4250 return bookmarks.incoming(ui, repo, other)
4250 return bookmarks.incoming(ui, repo, other)
4251
4251
4252 repo._subtoppath = ui.expandpath(source)
4252 repo._subtoppath = ui.expandpath(source)
4253 try:
4253 try:
4254 return hg.incoming(ui, repo, source, opts)
4254 return hg.incoming(ui, repo, source, opts)
4255 finally:
4255 finally:
4256 del repo._subtoppath
4256 del repo._subtoppath
4257
4257
4258
4258
4259 @command(
4259 @command(
4260 b'init',
4260 b'init',
4261 remoteopts,
4261 remoteopts,
4262 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4262 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4263 helpcategory=command.CATEGORY_REPO_CREATION,
4263 helpcategory=command.CATEGORY_REPO_CREATION,
4264 helpbasic=True,
4264 helpbasic=True,
4265 norepo=True,
4265 norepo=True,
4266 )
4266 )
4267 def init(ui, dest=b".", **opts):
4267 def init(ui, dest=b".", **opts):
4268 """create a new repository in the given directory
4268 """create a new repository in the given directory
4269
4269
4270 Initialize a new repository in the given directory. If the given
4270 Initialize a new repository in the given directory. If the given
4271 directory does not exist, it will be created.
4271 directory does not exist, it will be created.
4272
4272
4273 If no directory is given, the current directory is used.
4273 If no directory is given, the current directory is used.
4274
4274
4275 It is possible to specify an ``ssh://`` URL as the destination.
4275 It is possible to specify an ``ssh://`` URL as the destination.
4276 See :hg:`help urls` for more information.
4276 See :hg:`help urls` for more information.
4277
4277
4278 Returns 0 on success.
4278 Returns 0 on success.
4279 """
4279 """
4280 opts = pycompat.byteskwargs(opts)
4280 opts = pycompat.byteskwargs(opts)
4281 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4281 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4282
4282
4283
4283
4284 @command(
4284 @command(
4285 b'locate',
4285 b'locate',
4286 [
4286 [
4287 (
4287 (
4288 b'r',
4288 b'r',
4289 b'rev',
4289 b'rev',
4290 b'',
4290 b'',
4291 _(b'search the repository as it is in REV'),
4291 _(b'search the repository as it is in REV'),
4292 _(b'REV'),
4292 _(b'REV'),
4293 ),
4293 ),
4294 (
4294 (
4295 b'0',
4295 b'0',
4296 b'print0',
4296 b'print0',
4297 None,
4297 None,
4298 _(b'end filenames with NUL, for use with xargs'),
4298 _(b'end filenames with NUL, for use with xargs'),
4299 ),
4299 ),
4300 (
4300 (
4301 b'f',
4301 b'f',
4302 b'fullpath',
4302 b'fullpath',
4303 None,
4303 None,
4304 _(b'print complete paths from the filesystem root'),
4304 _(b'print complete paths from the filesystem root'),
4305 ),
4305 ),
4306 ]
4306 ]
4307 + walkopts,
4307 + walkopts,
4308 _(b'[OPTION]... [PATTERN]...'),
4308 _(b'[OPTION]... [PATTERN]...'),
4309 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4309 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4310 )
4310 )
4311 def locate(ui, repo, *pats, **opts):
4311 def locate(ui, repo, *pats, **opts):
4312 """locate files matching specific patterns (DEPRECATED)
4312 """locate files matching specific patterns (DEPRECATED)
4313
4313
4314 Print files under Mercurial control in the working directory whose
4314 Print files under Mercurial control in the working directory whose
4315 names match the given patterns.
4315 names match the given patterns.
4316
4316
4317 By default, this command searches all directories in the working
4317 By default, this command searches all directories in the working
4318 directory. To search just the current directory and its
4318 directory. To search just the current directory and its
4319 subdirectories, use "--include .".
4319 subdirectories, use "--include .".
4320
4320
4321 If no patterns are given to match, this command prints the names
4321 If no patterns are given to match, this command prints the names
4322 of all files under Mercurial control in the working directory.
4322 of all files under Mercurial control in the working directory.
4323
4323
4324 If you want to feed the output of this command into the "xargs"
4324 If you want to feed the output of this command into the "xargs"
4325 command, use the -0 option to both this command and "xargs". This
4325 command, use the -0 option to both this command and "xargs". This
4326 will avoid the problem of "xargs" treating single filenames that
4326 will avoid the problem of "xargs" treating single filenames that
4327 contain whitespace as multiple filenames.
4327 contain whitespace as multiple filenames.
4328
4328
4329 See :hg:`help files` for a more versatile command.
4329 See :hg:`help files` for a more versatile command.
4330
4330
4331 Returns 0 if a match is found, 1 otherwise.
4331 Returns 0 if a match is found, 1 otherwise.
4332 """
4332 """
4333 opts = pycompat.byteskwargs(opts)
4333 opts = pycompat.byteskwargs(opts)
4334 if opts.get(b'print0'):
4334 if opts.get(b'print0'):
4335 end = b'\0'
4335 end = b'\0'
4336 else:
4336 else:
4337 end = b'\n'
4337 end = b'\n'
4338 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4338 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4339
4339
4340 ret = 1
4340 ret = 1
4341 m = scmutil.match(
4341 m = scmutil.match(
4342 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4342 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4343 )
4343 )
4344
4344
4345 ui.pager(b'locate')
4345 ui.pager(b'locate')
4346 if ctx.rev() is None:
4346 if ctx.rev() is None:
4347 # When run on the working copy, "locate" includes removed files, so
4347 # When run on the working copy, "locate" includes removed files, so
4348 # we get the list of files from the dirstate.
4348 # we get the list of files from the dirstate.
4349 filesgen = sorted(repo.dirstate.matches(m))
4349 filesgen = sorted(repo.dirstate.matches(m))
4350 else:
4350 else:
4351 filesgen = ctx.matches(m)
4351 filesgen = ctx.matches(m)
4352 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4352 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4353 for abs in filesgen:
4353 for abs in filesgen:
4354 if opts.get(b'fullpath'):
4354 if opts.get(b'fullpath'):
4355 ui.write(repo.wjoin(abs), end)
4355 ui.write(repo.wjoin(abs), end)
4356 else:
4356 else:
4357 ui.write(uipathfn(abs), end)
4357 ui.write(uipathfn(abs), end)
4358 ret = 0
4358 ret = 0
4359
4359
4360 return ret
4360 return ret
4361
4361
4362
4362
4363 @command(
4363 @command(
4364 b'log|history',
4364 b'log|history',
4365 [
4365 [
4366 (
4366 (
4367 b'f',
4367 b'f',
4368 b'follow',
4368 b'follow',
4369 None,
4369 None,
4370 _(
4370 _(
4371 b'follow changeset history, or file history across copies and renames'
4371 b'follow changeset history, or file history across copies and renames'
4372 ),
4372 ),
4373 ),
4373 ),
4374 (
4374 (
4375 b'',
4375 b'',
4376 b'follow-first',
4376 b'follow-first',
4377 None,
4377 None,
4378 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4378 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4379 ),
4379 ),
4380 (
4380 (
4381 b'd',
4381 b'd',
4382 b'date',
4382 b'date',
4383 b'',
4383 b'',
4384 _(b'show revisions matching date spec'),
4384 _(b'show revisions matching date spec'),
4385 _(b'DATE'),
4385 _(b'DATE'),
4386 ),
4386 ),
4387 (b'C', b'copies', None, _(b'show copied files')),
4387 (b'C', b'copies', None, _(b'show copied files')),
4388 (
4388 (
4389 b'k',
4389 b'k',
4390 b'keyword',
4390 b'keyword',
4391 [],
4391 [],
4392 _(b'do case-insensitive search for a given text'),
4392 _(b'do case-insensitive search for a given text'),
4393 _(b'TEXT'),
4393 _(b'TEXT'),
4394 ),
4394 ),
4395 (
4395 (
4396 b'r',
4396 b'r',
4397 b'rev',
4397 b'rev',
4398 [],
4398 [],
4399 _(b'show the specified revision or revset'),
4399 _(b'show the specified revision or revset'),
4400 _(b'REV'),
4400 _(b'REV'),
4401 ),
4401 ),
4402 (
4402 (
4403 b'L',
4403 b'L',
4404 b'line-range',
4404 b'line-range',
4405 [],
4405 [],
4406 _(b'follow line range of specified file (EXPERIMENTAL)'),
4406 _(b'follow line range of specified file (EXPERIMENTAL)'),
4407 _(b'FILE,RANGE'),
4407 _(b'FILE,RANGE'),
4408 ),
4408 ),
4409 (
4409 (
4410 b'',
4410 b'',
4411 b'removed',
4411 b'removed',
4412 None,
4412 None,
4413 _(b'include revisions where files were removed'),
4413 _(b'include revisions where files were removed'),
4414 ),
4414 ),
4415 (
4415 (
4416 b'm',
4416 b'm',
4417 b'only-merges',
4417 b'only-merges',
4418 None,
4418 None,
4419 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4419 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4420 ),
4420 ),
4421 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4421 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4422 (
4422 (
4423 b'',
4423 b'',
4424 b'only-branch',
4424 b'only-branch',
4425 [],
4425 [],
4426 _(
4426 _(
4427 b'show only changesets within the given named branch (DEPRECATED)'
4427 b'show only changesets within the given named branch (DEPRECATED)'
4428 ),
4428 ),
4429 _(b'BRANCH'),
4429 _(b'BRANCH'),
4430 ),
4430 ),
4431 (
4431 (
4432 b'b',
4432 b'b',
4433 b'branch',
4433 b'branch',
4434 [],
4434 [],
4435 _(b'show changesets within the given named branch'),
4435 _(b'show changesets within the given named branch'),
4436 _(b'BRANCH'),
4436 _(b'BRANCH'),
4437 ),
4437 ),
4438 (
4438 (
4439 b'P',
4439 b'P',
4440 b'prune',
4440 b'prune',
4441 [],
4441 [],
4442 _(b'do not display revision or any of its ancestors'),
4442 _(b'do not display revision or any of its ancestors'),
4443 _(b'REV'),
4443 _(b'REV'),
4444 ),
4444 ),
4445 ]
4445 ]
4446 + logopts
4446 + logopts
4447 + walkopts,
4447 + walkopts,
4448 _(b'[OPTION]... [FILE]'),
4448 _(b'[OPTION]... [FILE]'),
4449 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4449 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4450 helpbasic=True,
4450 helpbasic=True,
4451 inferrepo=True,
4451 inferrepo=True,
4452 intents={INTENT_READONLY},
4452 intents={INTENT_READONLY},
4453 )
4453 )
4454 def log(ui, repo, *pats, **opts):
4454 def log(ui, repo, *pats, **opts):
4455 """show revision history of entire repository or files
4455 """show revision history of entire repository or files
4456
4456
4457 Print the revision history of the specified files or the entire
4457 Print the revision history of the specified files or the entire
4458 project.
4458 project.
4459
4459
4460 If no revision range is specified, the default is ``tip:0`` unless
4460 If no revision range is specified, the default is ``tip:0`` unless
4461 --follow is set, in which case the working directory parent is
4461 --follow is set, in which case the working directory parent is
4462 used as the starting revision.
4462 used as the starting revision.
4463
4463
4464 File history is shown without following rename or copy history of
4464 File history is shown without following rename or copy history of
4465 files. Use -f/--follow with a filename to follow history across
4465 files. Use -f/--follow with a filename to follow history across
4466 renames and copies. --follow without a filename will only show
4466 renames and copies. --follow without a filename will only show
4467 ancestors of the starting revision.
4467 ancestors of the starting revision.
4468
4468
4469 By default this command prints revision number and changeset id,
4469 By default this command prints revision number and changeset id,
4470 tags, non-trivial parents, user, date and time, and a summary for
4470 tags, non-trivial parents, user, date and time, and a summary for
4471 each commit. When the -v/--verbose switch is used, the list of
4471 each commit. When the -v/--verbose switch is used, the list of
4472 changed files and full commit message are shown.
4472 changed files and full commit message are shown.
4473
4473
4474 With --graph the revisions are shown as an ASCII art DAG with the most
4474 With --graph the revisions are shown as an ASCII art DAG with the most
4475 recent changeset at the top.
4475 recent changeset at the top.
4476 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4476 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4477 involved in an unresolved merge conflict, '_' closes a branch,
4477 involved in an unresolved merge conflict, '_' closes a branch,
4478 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4478 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4479 changeset from the lines below is a parent of the 'o' merge on the same
4479 changeset from the lines below is a parent of the 'o' merge on the same
4480 line.
4480 line.
4481 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4481 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4482 of a '|' indicates one or more revisions in a path are omitted.
4482 of a '|' indicates one or more revisions in a path are omitted.
4483
4483
4484 .. container:: verbose
4484 .. container:: verbose
4485
4485
4486 Use -L/--line-range FILE,M:N options to follow the history of lines
4486 Use -L/--line-range FILE,M:N options to follow the history of lines
4487 from M to N in FILE. With -p/--patch only diff hunks affecting
4487 from M to N in FILE. With -p/--patch only diff hunks affecting
4488 specified line range will be shown. This option requires --follow;
4488 specified line range will be shown. This option requires --follow;
4489 it can be specified multiple times. Currently, this option is not
4489 it can be specified multiple times. Currently, this option is not
4490 compatible with --graph. This option is experimental.
4490 compatible with --graph. This option is experimental.
4491
4491
4492 .. note::
4492 .. note::
4493
4493
4494 :hg:`log --patch` may generate unexpected diff output for merge
4494 :hg:`log --patch` may generate unexpected diff output for merge
4495 changesets, as it will only compare the merge changeset against
4495 changesets, as it will only compare the merge changeset against
4496 its first parent. Also, only files different from BOTH parents
4496 its first parent. Also, only files different from BOTH parents
4497 will appear in files:.
4497 will appear in files:.
4498
4498
4499 .. note::
4499 .. note::
4500
4500
4501 For performance reasons, :hg:`log FILE` may omit duplicate changes
4501 For performance reasons, :hg:`log FILE` may omit duplicate changes
4502 made on branches and will not show removals or mode changes. To
4502 made on branches and will not show removals or mode changes. To
4503 see all such changes, use the --removed switch.
4503 see all such changes, use the --removed switch.
4504
4504
4505 .. container:: verbose
4505 .. container:: verbose
4506
4506
4507 .. note::
4507 .. note::
4508
4508
4509 The history resulting from -L/--line-range options depends on diff
4509 The history resulting from -L/--line-range options depends on diff
4510 options; for instance if white-spaces are ignored, respective changes
4510 options; for instance if white-spaces are ignored, respective changes
4511 with only white-spaces in specified line range will not be listed.
4511 with only white-spaces in specified line range will not be listed.
4512
4512
4513 .. container:: verbose
4513 .. container:: verbose
4514
4514
4515 Some examples:
4515 Some examples:
4516
4516
4517 - changesets with full descriptions and file lists::
4517 - changesets with full descriptions and file lists::
4518
4518
4519 hg log -v
4519 hg log -v
4520
4520
4521 - changesets ancestral to the working directory::
4521 - changesets ancestral to the working directory::
4522
4522
4523 hg log -f
4523 hg log -f
4524
4524
4525 - last 10 commits on the current branch::
4525 - last 10 commits on the current branch::
4526
4526
4527 hg log -l 10 -b .
4527 hg log -l 10 -b .
4528
4528
4529 - changesets showing all modifications of a file, including removals::
4529 - changesets showing all modifications of a file, including removals::
4530
4530
4531 hg log --removed file.c
4531 hg log --removed file.c
4532
4532
4533 - all changesets that touch a directory, with diffs, excluding merges::
4533 - all changesets that touch a directory, with diffs, excluding merges::
4534
4534
4535 hg log -Mp lib/
4535 hg log -Mp lib/
4536
4536
4537 - all revision numbers that match a keyword::
4537 - all revision numbers that match a keyword::
4538
4538
4539 hg log -k bug --template "{rev}\\n"
4539 hg log -k bug --template "{rev}\\n"
4540
4540
4541 - the full hash identifier of the working directory parent::
4541 - the full hash identifier of the working directory parent::
4542
4542
4543 hg log -r . --template "{node}\\n"
4543 hg log -r . --template "{node}\\n"
4544
4544
4545 - list available log templates::
4545 - list available log templates::
4546
4546
4547 hg log -T list
4547 hg log -T list
4548
4548
4549 - check if a given changeset is included in a tagged release::
4549 - check if a given changeset is included in a tagged release::
4550
4550
4551 hg log -r "a21ccf and ancestor(1.9)"
4551 hg log -r "a21ccf and ancestor(1.9)"
4552
4552
4553 - find all changesets by some user in a date range::
4553 - find all changesets by some user in a date range::
4554
4554
4555 hg log -k alice -d "may 2008 to jul 2008"
4555 hg log -k alice -d "may 2008 to jul 2008"
4556
4556
4557 - summary of all changesets after the last tag::
4557 - summary of all changesets after the last tag::
4558
4558
4559 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4559 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4560
4560
4561 - changesets touching lines 13 to 23 for file.c::
4561 - changesets touching lines 13 to 23 for file.c::
4562
4562
4563 hg log -L file.c,13:23
4563 hg log -L file.c,13:23
4564
4564
4565 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4565 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4566 main.c with patch::
4566 main.c with patch::
4567
4567
4568 hg log -L file.c,13:23 -L main.c,2:6 -p
4568 hg log -L file.c,13:23 -L main.c,2:6 -p
4569
4569
4570 See :hg:`help dates` for a list of formats valid for -d/--date.
4570 See :hg:`help dates` for a list of formats valid for -d/--date.
4571
4571
4572 See :hg:`help revisions` for more about specifying and ordering
4572 See :hg:`help revisions` for more about specifying and ordering
4573 revisions.
4573 revisions.
4574
4574
4575 See :hg:`help templates` for more about pre-packaged styles and
4575 See :hg:`help templates` for more about pre-packaged styles and
4576 specifying custom templates. The default template used by the log
4576 specifying custom templates. The default template used by the log
4577 command can be customized via the ``command-templates.log`` configuration
4577 command can be customized via the ``command-templates.log`` configuration
4578 setting.
4578 setting.
4579
4579
4580 Returns 0 on success.
4580 Returns 0 on success.
4581
4581
4582 """
4582 """
4583 opts = pycompat.byteskwargs(opts)
4583 opts = pycompat.byteskwargs(opts)
4584 linerange = opts.get(b'line_range')
4584 linerange = opts.get(b'line_range')
4585
4585
4586 if linerange and not opts.get(b'follow'):
4586 if linerange and not opts.get(b'follow'):
4587 raise error.Abort(_(b'--line-range requires --follow'))
4587 raise error.Abort(_(b'--line-range requires --follow'))
4588
4588
4589 if linerange and pats:
4589 if linerange and pats:
4590 # TODO: take pats as patterns with no line-range filter
4590 # TODO: take pats as patterns with no line-range filter
4591 raise error.Abort(
4591 raise error.Abort(
4592 _(b'FILE arguments are not compatible with --line-range option')
4592 _(b'FILE arguments are not compatible with --line-range option')
4593 )
4593 )
4594
4594
4595 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4595 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4596 revs, differ = logcmdutil.getrevs(
4596 revs, differ = logcmdutil.getrevs(
4597 repo, logcmdutil.parseopts(ui, pats, opts)
4597 repo, logcmdutil.parseopts(ui, pats, opts)
4598 )
4598 )
4599 if linerange:
4599 if linerange:
4600 # TODO: should follow file history from logcmdutil._initialrevs(),
4600 # TODO: should follow file history from logcmdutil._initialrevs(),
4601 # then filter the result by logcmdutil._makerevset() and --limit
4601 # then filter the result by logcmdutil._makerevset() and --limit
4602 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4602 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4603
4603
4604 getcopies = None
4604 getcopies = None
4605 if opts.get(b'copies'):
4605 if opts.get(b'copies'):
4606 endrev = None
4606 endrev = None
4607 if revs:
4607 if revs:
4608 endrev = revs.max() + 1
4608 endrev = revs.max() + 1
4609 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4609 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4610
4610
4611 ui.pager(b'log')
4611 ui.pager(b'log')
4612 displayer = logcmdutil.changesetdisplayer(
4612 displayer = logcmdutil.changesetdisplayer(
4613 ui, repo, opts, differ, buffered=True
4613 ui, repo, opts, differ, buffered=True
4614 )
4614 )
4615 if opts.get(b'graph'):
4615 if opts.get(b'graph'):
4616 displayfn = logcmdutil.displaygraphrevs
4616 displayfn = logcmdutil.displaygraphrevs
4617 else:
4617 else:
4618 displayfn = logcmdutil.displayrevs
4618 displayfn = logcmdutil.displayrevs
4619 displayfn(ui, repo, revs, displayer, getcopies)
4619 displayfn(ui, repo, revs, displayer, getcopies)
4620
4620
4621
4621
4622 @command(
4622 @command(
4623 b'manifest',
4623 b'manifest',
4624 [
4624 [
4625 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4625 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4626 (b'', b'all', False, _(b"list files from all revisions")),
4626 (b'', b'all', False, _(b"list files from all revisions")),
4627 ]
4627 ]
4628 + formatteropts,
4628 + formatteropts,
4629 _(b'[-r REV]'),
4629 _(b'[-r REV]'),
4630 helpcategory=command.CATEGORY_MAINTENANCE,
4630 helpcategory=command.CATEGORY_MAINTENANCE,
4631 intents={INTENT_READONLY},
4631 intents={INTENT_READONLY},
4632 )
4632 )
4633 def manifest(ui, repo, node=None, rev=None, **opts):
4633 def manifest(ui, repo, node=None, rev=None, **opts):
4634 """output the current or given revision of the project manifest
4634 """output the current or given revision of the project manifest
4635
4635
4636 Print a list of version controlled files for the given revision.
4636 Print a list of version controlled files for the given revision.
4637 If no revision is given, the first parent of the working directory
4637 If no revision is given, the first parent of the working directory
4638 is used, or the null revision if no revision is checked out.
4638 is used, or the null revision if no revision is checked out.
4639
4639
4640 With -v, print file permissions, symlink and executable bits.
4640 With -v, print file permissions, symlink and executable bits.
4641 With --debug, print file revision hashes.
4641 With --debug, print file revision hashes.
4642
4642
4643 If option --all is specified, the list of all files from all revisions
4643 If option --all is specified, the list of all files from all revisions
4644 is printed. This includes deleted and renamed files.
4644 is printed. This includes deleted and renamed files.
4645
4645
4646 Returns 0 on success.
4646 Returns 0 on success.
4647 """
4647 """
4648 opts = pycompat.byteskwargs(opts)
4648 opts = pycompat.byteskwargs(opts)
4649 fm = ui.formatter(b'manifest', opts)
4649 fm = ui.formatter(b'manifest', opts)
4650
4650
4651 if opts.get(b'all'):
4651 if opts.get(b'all'):
4652 if rev or node:
4652 if rev or node:
4653 raise error.Abort(_(b"can't specify a revision with --all"))
4653 raise error.Abort(_(b"can't specify a revision with --all"))
4654
4654
4655 res = set()
4655 res = set()
4656 for rev in repo:
4656 for rev in repo:
4657 ctx = repo[rev]
4657 ctx = repo[rev]
4658 res |= set(ctx.files())
4658 res |= set(ctx.files())
4659
4659
4660 ui.pager(b'manifest')
4660 ui.pager(b'manifest')
4661 for f in sorted(res):
4661 for f in sorted(res):
4662 fm.startitem()
4662 fm.startitem()
4663 fm.write(b"path", b'%s\n', f)
4663 fm.write(b"path", b'%s\n', f)
4664 fm.end()
4664 fm.end()
4665 return
4665 return
4666
4666
4667 if rev and node:
4667 if rev and node:
4668 raise error.Abort(_(b"please specify just one revision"))
4668 raise error.Abort(_(b"please specify just one revision"))
4669
4669
4670 if not node:
4670 if not node:
4671 node = rev
4671 node = rev
4672
4672
4673 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4673 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4674 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4674 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4675 if node:
4675 if node:
4676 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4676 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4677 ctx = scmutil.revsingle(repo, node)
4677 ctx = scmutil.revsingle(repo, node)
4678 mf = ctx.manifest()
4678 mf = ctx.manifest()
4679 ui.pager(b'manifest')
4679 ui.pager(b'manifest')
4680 for f in ctx:
4680 for f in ctx:
4681 fm.startitem()
4681 fm.startitem()
4682 fm.context(ctx=ctx)
4682 fm.context(ctx=ctx)
4683 fl = ctx[f].flags()
4683 fl = ctx[f].flags()
4684 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4684 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4685 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4685 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4686 fm.write(b'path', b'%s\n', f)
4686 fm.write(b'path', b'%s\n', f)
4687 fm.end()
4687 fm.end()
4688
4688
4689
4689
4690 @command(
4690 @command(
4691 b'merge',
4691 b'merge',
4692 [
4692 [
4693 (
4693 (
4694 b'f',
4694 b'f',
4695 b'force',
4695 b'force',
4696 None,
4696 None,
4697 _(b'force a merge including outstanding changes (DEPRECATED)'),
4697 _(b'force a merge including outstanding changes (DEPRECATED)'),
4698 ),
4698 ),
4699 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4699 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4700 (
4700 (
4701 b'P',
4701 b'P',
4702 b'preview',
4702 b'preview',
4703 None,
4703 None,
4704 _(b'review revisions to merge (no merge is performed)'),
4704 _(b'review revisions to merge (no merge is performed)'),
4705 ),
4705 ),
4706 (b'', b'abort', None, _(b'abort the ongoing merge')),
4706 (b'', b'abort', None, _(b'abort the ongoing merge')),
4707 ]
4707 ]
4708 + mergetoolopts,
4708 + mergetoolopts,
4709 _(b'[-P] [[-r] REV]'),
4709 _(b'[-P] [[-r] REV]'),
4710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4711 helpbasic=True,
4711 helpbasic=True,
4712 )
4712 )
4713 def merge(ui, repo, node=None, **opts):
4713 def merge(ui, repo, node=None, **opts):
4714 """merge another revision into working directory
4714 """merge another revision into working directory
4715
4715
4716 The current working directory is updated with all changes made in
4716 The current working directory is updated with all changes made in
4717 the requested revision since the last common predecessor revision.
4717 the requested revision since the last common predecessor revision.
4718
4718
4719 Files that changed between either parent are marked as changed for
4719 Files that changed between either parent are marked as changed for
4720 the next commit and a commit must be performed before any further
4720 the next commit and a commit must be performed before any further
4721 updates to the repository are allowed. The next commit will have
4721 updates to the repository are allowed. The next commit will have
4722 two parents.
4722 two parents.
4723
4723
4724 ``--tool`` can be used to specify the merge tool used for file
4724 ``--tool`` can be used to specify the merge tool used for file
4725 merges. It overrides the HGMERGE environment variable and your
4725 merges. It overrides the HGMERGE environment variable and your
4726 configuration files. See :hg:`help merge-tools` for options.
4726 configuration files. See :hg:`help merge-tools` for options.
4727
4727
4728 If no revision is specified, the working directory's parent is a
4728 If no revision is specified, the working directory's parent is a
4729 head revision, and the current branch contains exactly one other
4729 head revision, and the current branch contains exactly one other
4730 head, the other head is merged with by default. Otherwise, an
4730 head, the other head is merged with by default. Otherwise, an
4731 explicit revision with which to merge must be provided.
4731 explicit revision with which to merge must be provided.
4732
4732
4733 See :hg:`help resolve` for information on handling file conflicts.
4733 See :hg:`help resolve` for information on handling file conflicts.
4734
4734
4735 To undo an uncommitted merge, use :hg:`merge --abort` which
4735 To undo an uncommitted merge, use :hg:`merge --abort` which
4736 will check out a clean copy of the original merge parent, losing
4736 will check out a clean copy of the original merge parent, losing
4737 all changes.
4737 all changes.
4738
4738
4739 Returns 0 on success, 1 if there are unresolved files.
4739 Returns 0 on success, 1 if there are unresolved files.
4740 """
4740 """
4741
4741
4742 opts = pycompat.byteskwargs(opts)
4742 opts = pycompat.byteskwargs(opts)
4743 abort = opts.get(b'abort')
4743 abort = opts.get(b'abort')
4744 if abort and repo.dirstate.p2() == nullid:
4744 if abort and repo.dirstate.p2() == nullid:
4745 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4745 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4746 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4746 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4747 if abort:
4747 if abort:
4748 state = cmdutil.getunfinishedstate(repo)
4748 state = cmdutil.getunfinishedstate(repo)
4749 if state and state._opname != b'merge':
4749 if state and state._opname != b'merge':
4750 raise error.Abort(
4750 raise error.Abort(
4751 _(b'cannot abort merge with %s in progress') % (state._opname),
4751 _(b'cannot abort merge with %s in progress') % (state._opname),
4752 hint=state.hint(),
4752 hint=state.hint(),
4753 )
4753 )
4754 if node:
4754 if node:
4755 raise error.Abort(_(b"cannot specify a node with --abort"))
4755 raise error.Abort(_(b"cannot specify a node with --abort"))
4756 return hg.abortmerge(repo.ui, repo)
4756 return hg.abortmerge(repo.ui, repo)
4757
4757
4758 if opts.get(b'rev') and node:
4758 if opts.get(b'rev') and node:
4759 raise error.Abort(_(b"please specify just one revision"))
4759 raise error.Abort(_(b"please specify just one revision"))
4760 if not node:
4760 if not node:
4761 node = opts.get(b'rev')
4761 node = opts.get(b'rev')
4762
4762
4763 if node:
4763 if node:
4764 ctx = scmutil.revsingle(repo, node)
4764 ctx = scmutil.revsingle(repo, node)
4765 else:
4765 else:
4766 if ui.configbool(b'commands', b'merge.require-rev'):
4766 if ui.configbool(b'commands', b'merge.require-rev'):
4767 raise error.Abort(
4767 raise error.Abort(
4768 _(
4768 _(
4769 b'configuration requires specifying revision to merge '
4769 b'configuration requires specifying revision to merge '
4770 b'with'
4770 b'with'
4771 )
4771 )
4772 )
4772 )
4773 ctx = repo[destutil.destmerge(repo)]
4773 ctx = repo[destutil.destmerge(repo)]
4774
4774
4775 if ctx.node() is None:
4775 if ctx.node() is None:
4776 raise error.Abort(_(b'merging with the working copy has no effect'))
4776 raise error.Abort(_(b'merging with the working copy has no effect'))
4777
4777
4778 if opts.get(b'preview'):
4778 if opts.get(b'preview'):
4779 # find nodes that are ancestors of p2 but not of p1
4779 # find nodes that are ancestors of p2 but not of p1
4780 p1 = repo[b'.'].node()
4780 p1 = repo[b'.'].node()
4781 p2 = ctx.node()
4781 p2 = ctx.node()
4782 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4782 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4783
4783
4784 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4784 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4785 for node in nodes:
4785 for node in nodes:
4786 displayer.show(repo[node])
4786 displayer.show(repo[node])
4787 displayer.close()
4787 displayer.close()
4788 return 0
4788 return 0
4789
4789
4790 # ui.forcemerge is an internal variable, do not document
4790 # ui.forcemerge is an internal variable, do not document
4791 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4791 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4792 with ui.configoverride(overrides, b'merge'):
4792 with ui.configoverride(overrides, b'merge'):
4793 force = opts.get(b'force')
4793 force = opts.get(b'force')
4794 labels = [b'working copy', b'merge rev']
4794 labels = [b'working copy', b'merge rev']
4795 return hg.merge(ctx, force=force, labels=labels)
4795 return hg.merge(ctx, force=force, labels=labels)
4796
4796
4797
4797
4798 statemod.addunfinished(
4798 statemod.addunfinished(
4799 b'merge',
4799 b'merge',
4800 fname=None,
4800 fname=None,
4801 clearable=True,
4801 clearable=True,
4802 allowcommit=True,
4802 allowcommit=True,
4803 cmdmsg=_(b'outstanding uncommitted merge'),
4803 cmdmsg=_(b'outstanding uncommitted merge'),
4804 abortfunc=hg.abortmerge,
4804 abortfunc=hg.abortmerge,
4805 statushint=_(
4805 statushint=_(
4806 b'To continue: hg commit\nTo abort: hg merge --abort'
4806 b'To continue: hg commit\nTo abort: hg merge --abort'
4807 ),
4807 ),
4808 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4808 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4809 )
4809 )
4810
4810
4811
4811
4812 @command(
4812 @command(
4813 b'outgoing|out',
4813 b'outgoing|out',
4814 [
4814 [
4815 (
4815 (
4816 b'f',
4816 b'f',
4817 b'force',
4817 b'force',
4818 None,
4818 None,
4819 _(b'run even when the destination is unrelated'),
4819 _(b'run even when the destination is unrelated'),
4820 ),
4820 ),
4821 (
4821 (
4822 b'r',
4822 b'r',
4823 b'rev',
4823 b'rev',
4824 [],
4824 [],
4825 _(b'a changeset intended to be included in the destination'),
4825 _(b'a changeset intended to be included in the destination'),
4826 _(b'REV'),
4826 _(b'REV'),
4827 ),
4827 ),
4828 (b'n', b'newest-first', None, _(b'show newest record first')),
4828 (b'n', b'newest-first', None, _(b'show newest record first')),
4829 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4829 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4830 (
4830 (
4831 b'b',
4831 b'b',
4832 b'branch',
4832 b'branch',
4833 [],
4833 [],
4834 _(b'a specific branch you would like to push'),
4834 _(b'a specific branch you would like to push'),
4835 _(b'BRANCH'),
4835 _(b'BRANCH'),
4836 ),
4836 ),
4837 ]
4837 ]
4838 + logopts
4838 + logopts
4839 + remoteopts
4839 + remoteopts
4840 + subrepoopts,
4840 + subrepoopts,
4841 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4841 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4842 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4842 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4843 )
4843 )
4844 def outgoing(ui, repo, dest=None, **opts):
4844 def outgoing(ui, repo, dest=None, **opts):
4845 """show changesets not found in the destination
4845 """show changesets not found in the destination
4846
4846
4847 Show changesets not found in the specified destination repository
4847 Show changesets not found in the specified destination repository
4848 or the default push location. These are the changesets that would
4848 or the default push location. These are the changesets that would
4849 be pushed if a push was requested.
4849 be pushed if a push was requested.
4850
4850
4851 See pull for details of valid destination formats.
4851 See pull for details of valid destination formats.
4852
4852
4853 .. container:: verbose
4853 .. container:: verbose
4854
4854
4855 With -B/--bookmarks, the result of bookmark comparison between
4855 With -B/--bookmarks, the result of bookmark comparison between
4856 local and remote repositories is displayed. With -v/--verbose,
4856 local and remote repositories is displayed. With -v/--verbose,
4857 status is also displayed for each bookmark like below::
4857 status is also displayed for each bookmark like below::
4858
4858
4859 BM1 01234567890a added
4859 BM1 01234567890a added
4860 BM2 deleted
4860 BM2 deleted
4861 BM3 234567890abc advanced
4861 BM3 234567890abc advanced
4862 BM4 34567890abcd diverged
4862 BM4 34567890abcd diverged
4863 BM5 4567890abcde changed
4863 BM5 4567890abcde changed
4864
4864
4865 The action taken when pushing depends on the
4865 The action taken when pushing depends on the
4866 status of each bookmark:
4866 status of each bookmark:
4867
4867
4868 :``added``: push with ``-B`` will create it
4868 :``added``: push with ``-B`` will create it
4869 :``deleted``: push with ``-B`` will delete it
4869 :``deleted``: push with ``-B`` will delete it
4870 :``advanced``: push will update it
4870 :``advanced``: push will update it
4871 :``diverged``: push with ``-B`` will update it
4871 :``diverged``: push with ``-B`` will update it
4872 :``changed``: push with ``-B`` will update it
4872 :``changed``: push with ``-B`` will update it
4873
4873
4874 From the point of view of pushing behavior, bookmarks
4874 From the point of view of pushing behavior, bookmarks
4875 existing only in the remote repository are treated as
4875 existing only in the remote repository are treated as
4876 ``deleted``, even if it is in fact added remotely.
4876 ``deleted``, even if it is in fact added remotely.
4877
4877
4878 Returns 0 if there are outgoing changes, 1 otherwise.
4878 Returns 0 if there are outgoing changes, 1 otherwise.
4879 """
4879 """
4880 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4880 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4881 # style URLs, so don't overwrite dest.
4881 # style URLs, so don't overwrite dest.
4882 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4882 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4883 if not path:
4883 if not path:
4884 raise error.Abort(
4884 raise error.Abort(
4885 _(b'default repository not configured!'),
4885 _(b'default repository not configured!'),
4886 hint=_(b"see 'hg help config.paths'"),
4886 hint=_(b"see 'hg help config.paths'"),
4887 )
4887 )
4888
4888
4889 opts = pycompat.byteskwargs(opts)
4889 opts = pycompat.byteskwargs(opts)
4890 if opts.get(b'graph'):
4890 if opts.get(b'graph'):
4891 logcmdutil.checkunsupportedgraphflags([], opts)
4891 logcmdutil.checkunsupportedgraphflags([], opts)
4892 o, other = hg._outgoing(ui, repo, dest, opts)
4892 o, other = hg._outgoing(ui, repo, dest, opts)
4893 if not o:
4893 if not o:
4894 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4894 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4895 return
4895 return
4896
4896
4897 revdag = logcmdutil.graphrevs(repo, o, opts)
4897 revdag = logcmdutil.graphrevs(repo, o, opts)
4898 ui.pager(b'outgoing')
4898 ui.pager(b'outgoing')
4899 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4899 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4900 logcmdutil.displaygraph(
4900 logcmdutil.displaygraph(
4901 ui, repo, revdag, displayer, graphmod.asciiedges
4901 ui, repo, revdag, displayer, graphmod.asciiedges
4902 )
4902 )
4903 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4903 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4904 return 0
4904 return 0
4905
4905
4906 if opts.get(b'bookmarks'):
4906 if opts.get(b'bookmarks'):
4907 dest = path.pushloc or path.loc
4907 dest = path.pushloc or path.loc
4908 other = hg.peer(repo, opts, dest)
4908 other = hg.peer(repo, opts, dest)
4909 if b'bookmarks' not in other.listkeys(b'namespaces'):
4909 if b'bookmarks' not in other.listkeys(b'namespaces'):
4910 ui.warn(_(b"remote doesn't support bookmarks\n"))
4910 ui.warn(_(b"remote doesn't support bookmarks\n"))
4911 return 0
4911 return 0
4912 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4912 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4913 ui.pager(b'outgoing')
4913 ui.pager(b'outgoing')
4914 return bookmarks.outgoing(ui, repo, other)
4914 return bookmarks.outgoing(ui, repo, other)
4915
4915
4916 repo._subtoppath = path.pushloc or path.loc
4916 repo._subtoppath = path.pushloc or path.loc
4917 try:
4917 try:
4918 return hg.outgoing(ui, repo, dest, opts)
4918 return hg.outgoing(ui, repo, dest, opts)
4919 finally:
4919 finally:
4920 del repo._subtoppath
4920 del repo._subtoppath
4921
4921
4922
4922
4923 @command(
4923 @command(
4924 b'parents',
4924 b'parents',
4925 [
4925 [
4926 (
4926 (
4927 b'r',
4927 b'r',
4928 b'rev',
4928 b'rev',
4929 b'',
4929 b'',
4930 _(b'show parents of the specified revision'),
4930 _(b'show parents of the specified revision'),
4931 _(b'REV'),
4931 _(b'REV'),
4932 ),
4932 ),
4933 ]
4933 ]
4934 + templateopts,
4934 + templateopts,
4935 _(b'[-r REV] [FILE]'),
4935 _(b'[-r REV] [FILE]'),
4936 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4936 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4937 inferrepo=True,
4937 inferrepo=True,
4938 )
4938 )
4939 def parents(ui, repo, file_=None, **opts):
4939 def parents(ui, repo, file_=None, **opts):
4940 """show the parents of the working directory or revision (DEPRECATED)
4940 """show the parents of the working directory or revision (DEPRECATED)
4941
4941
4942 Print the working directory's parent revisions. If a revision is
4942 Print the working directory's parent revisions. If a revision is
4943 given via -r/--rev, the parent of that revision will be printed.
4943 given via -r/--rev, the parent of that revision will be printed.
4944 If a file argument is given, the revision in which the file was
4944 If a file argument is given, the revision in which the file was
4945 last changed (before the working directory revision or the
4945 last changed (before the working directory revision or the
4946 argument to --rev if given) is printed.
4946 argument to --rev if given) is printed.
4947
4947
4948 This command is equivalent to::
4948 This command is equivalent to::
4949
4949
4950 hg log -r "p1()+p2()" or
4950 hg log -r "p1()+p2()" or
4951 hg log -r "p1(REV)+p2(REV)" or
4951 hg log -r "p1(REV)+p2(REV)" or
4952 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4952 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4953 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4953 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4954
4954
4955 See :hg:`summary` and :hg:`help revsets` for related information.
4955 See :hg:`summary` and :hg:`help revsets` for related information.
4956
4956
4957 Returns 0 on success.
4957 Returns 0 on success.
4958 """
4958 """
4959
4959
4960 opts = pycompat.byteskwargs(opts)
4960 opts = pycompat.byteskwargs(opts)
4961 rev = opts.get(b'rev')
4961 rev = opts.get(b'rev')
4962 if rev:
4962 if rev:
4963 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4963 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4964 ctx = scmutil.revsingle(repo, rev, None)
4964 ctx = scmutil.revsingle(repo, rev, None)
4965
4965
4966 if file_:
4966 if file_:
4967 m = scmutil.match(ctx, (file_,), opts)
4967 m = scmutil.match(ctx, (file_,), opts)
4968 if m.anypats() or len(m.files()) != 1:
4968 if m.anypats() or len(m.files()) != 1:
4969 raise error.Abort(_(b'can only specify an explicit filename'))
4969 raise error.Abort(_(b'can only specify an explicit filename'))
4970 file_ = m.files()[0]
4970 file_ = m.files()[0]
4971 filenodes = []
4971 filenodes = []
4972 for cp in ctx.parents():
4972 for cp in ctx.parents():
4973 if not cp:
4973 if not cp:
4974 continue
4974 continue
4975 try:
4975 try:
4976 filenodes.append(cp.filenode(file_))
4976 filenodes.append(cp.filenode(file_))
4977 except error.LookupError:
4977 except error.LookupError:
4978 pass
4978 pass
4979 if not filenodes:
4979 if not filenodes:
4980 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
4980 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
4981 p = []
4981 p = []
4982 for fn in filenodes:
4982 for fn in filenodes:
4983 fctx = repo.filectx(file_, fileid=fn)
4983 fctx = repo.filectx(file_, fileid=fn)
4984 p.append(fctx.node())
4984 p.append(fctx.node())
4985 else:
4985 else:
4986 p = [cp.node() for cp in ctx.parents()]
4986 p = [cp.node() for cp in ctx.parents()]
4987
4987
4988 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4988 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4989 for n in p:
4989 for n in p:
4990 if n != nullid:
4990 if n != nullid:
4991 displayer.show(repo[n])
4991 displayer.show(repo[n])
4992 displayer.close()
4992 displayer.close()
4993
4993
4994
4994
4995 @command(
4995 @command(
4996 b'paths',
4996 b'paths',
4997 formatteropts,
4997 formatteropts,
4998 _(b'[NAME]'),
4998 _(b'[NAME]'),
4999 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4999 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5000 optionalrepo=True,
5000 optionalrepo=True,
5001 intents={INTENT_READONLY},
5001 intents={INTENT_READONLY},
5002 )
5002 )
5003 def paths(ui, repo, search=None, **opts):
5003 def paths(ui, repo, search=None, **opts):
5004 """show aliases for remote repositories
5004 """show aliases for remote repositories
5005
5005
5006 Show definition of symbolic path name NAME. If no name is given,
5006 Show definition of symbolic path name NAME. If no name is given,
5007 show definition of all available names.
5007 show definition of all available names.
5008
5008
5009 Option -q/--quiet suppresses all output when searching for NAME
5009 Option -q/--quiet suppresses all output when searching for NAME
5010 and shows only the path names when listing all definitions.
5010 and shows only the path names when listing all definitions.
5011
5011
5012 Path names are defined in the [paths] section of your
5012 Path names are defined in the [paths] section of your
5013 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5013 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5014 repository, ``.hg/hgrc`` is used, too.
5014 repository, ``.hg/hgrc`` is used, too.
5015
5015
5016 The path names ``default`` and ``default-push`` have a special
5016 The path names ``default`` and ``default-push`` have a special
5017 meaning. When performing a push or pull operation, they are used
5017 meaning. When performing a push or pull operation, they are used
5018 as fallbacks if no location is specified on the command-line.
5018 as fallbacks if no location is specified on the command-line.
5019 When ``default-push`` is set, it will be used for push and
5019 When ``default-push`` is set, it will be used for push and
5020 ``default`` will be used for pull; otherwise ``default`` is used
5020 ``default`` will be used for pull; otherwise ``default`` is used
5021 as the fallback for both. When cloning a repository, the clone
5021 as the fallback for both. When cloning a repository, the clone
5022 source is written as ``default`` in ``.hg/hgrc``.
5022 source is written as ``default`` in ``.hg/hgrc``.
5023
5023
5024 .. note::
5024 .. note::
5025
5025
5026 ``default`` and ``default-push`` apply to all inbound (e.g.
5026 ``default`` and ``default-push`` apply to all inbound (e.g.
5027 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5027 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5028 and :hg:`bundle`) operations.
5028 and :hg:`bundle`) operations.
5029
5029
5030 See :hg:`help urls` for more information.
5030 See :hg:`help urls` for more information.
5031
5031
5032 .. container:: verbose
5032 .. container:: verbose
5033
5033
5034 Template:
5034 Template:
5035
5035
5036 The following keywords are supported. See also :hg:`help templates`.
5036 The following keywords are supported. See also :hg:`help templates`.
5037
5037
5038 :name: String. Symbolic name of the path alias.
5038 :name: String. Symbolic name of the path alias.
5039 :pushurl: String. URL for push operations.
5039 :pushurl: String. URL for push operations.
5040 :url: String. URL or directory path for the other operations.
5040 :url: String. URL or directory path for the other operations.
5041
5041
5042 Returns 0 on success.
5042 Returns 0 on success.
5043 """
5043 """
5044
5044
5045 opts = pycompat.byteskwargs(opts)
5045 opts = pycompat.byteskwargs(opts)
5046 ui.pager(b'paths')
5046 ui.pager(b'paths')
5047 if search:
5047 if search:
5048 pathitems = [
5048 pathitems = [
5049 (name, path)
5049 (name, path)
5050 for name, path in pycompat.iteritems(ui.paths)
5050 for name, path in pycompat.iteritems(ui.paths)
5051 if name == search
5051 if name == search
5052 ]
5052 ]
5053 else:
5053 else:
5054 pathitems = sorted(pycompat.iteritems(ui.paths))
5054 pathitems = sorted(pycompat.iteritems(ui.paths))
5055
5055
5056 fm = ui.formatter(b'paths', opts)
5056 fm = ui.formatter(b'paths', opts)
5057 if fm.isplain():
5057 if fm.isplain():
5058 hidepassword = util.hidepassword
5058 hidepassword = util.hidepassword
5059 else:
5059 else:
5060 hidepassword = bytes
5060 hidepassword = bytes
5061 if ui.quiet:
5061 if ui.quiet:
5062 namefmt = b'%s\n'
5062 namefmt = b'%s\n'
5063 else:
5063 else:
5064 namefmt = b'%s = '
5064 namefmt = b'%s = '
5065 showsubopts = not search and not ui.quiet
5065 showsubopts = not search and not ui.quiet
5066
5066
5067 for name, path in pathitems:
5067 for name, path in pathitems:
5068 fm.startitem()
5068 fm.startitem()
5069 fm.condwrite(not search, b'name', namefmt, name)
5069 fm.condwrite(not search, b'name', namefmt, name)
5070 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5070 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5071 for subopt, value in sorted(path.suboptions.items()):
5071 for subopt, value in sorted(path.suboptions.items()):
5072 assert subopt not in (b'name', b'url')
5072 assert subopt not in (b'name', b'url')
5073 if showsubopts:
5073 if showsubopts:
5074 fm.plain(b'%s:%s = ' % (name, subopt))
5074 fm.plain(b'%s:%s = ' % (name, subopt))
5075 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5075 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5076
5076
5077 fm.end()
5077 fm.end()
5078
5078
5079 if search and not pathitems:
5079 if search and not pathitems:
5080 if not ui.quiet:
5080 if not ui.quiet:
5081 ui.warn(_(b"not found!\n"))
5081 ui.warn(_(b"not found!\n"))
5082 return 1
5082 return 1
5083 else:
5083 else:
5084 return 0
5084 return 0
5085
5085
5086
5086
5087 @command(
5087 @command(
5088 b'phase',
5088 b'phase',
5089 [
5089 [
5090 (b'p', b'public', False, _(b'set changeset phase to public')),
5090 (b'p', b'public', False, _(b'set changeset phase to public')),
5091 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5091 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5092 (b's', b'secret', False, _(b'set changeset phase to secret')),
5092 (b's', b'secret', False, _(b'set changeset phase to secret')),
5093 (b'f', b'force', False, _(b'allow to move boundary backward')),
5093 (b'f', b'force', False, _(b'allow to move boundary backward')),
5094 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5094 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5095 ],
5095 ],
5096 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5096 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5097 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5097 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5098 )
5098 )
5099 def phase(ui, repo, *revs, **opts):
5099 def phase(ui, repo, *revs, **opts):
5100 """set or show the current phase name
5100 """set or show the current phase name
5101
5101
5102 With no argument, show the phase name of the current revision(s).
5102 With no argument, show the phase name of the current revision(s).
5103
5103
5104 With one of -p/--public, -d/--draft or -s/--secret, change the
5104 With one of -p/--public, -d/--draft or -s/--secret, change the
5105 phase value of the specified revisions.
5105 phase value of the specified revisions.
5106
5106
5107 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5107 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5108 lower phase to a higher phase. Phases are ordered as follows::
5108 lower phase to a higher phase. Phases are ordered as follows::
5109
5109
5110 public < draft < secret
5110 public < draft < secret
5111
5111
5112 Returns 0 on success, 1 if some phases could not be changed.
5112 Returns 0 on success, 1 if some phases could not be changed.
5113
5113
5114 (For more information about the phases concept, see :hg:`help phases`.)
5114 (For more information about the phases concept, see :hg:`help phases`.)
5115 """
5115 """
5116 opts = pycompat.byteskwargs(opts)
5116 opts = pycompat.byteskwargs(opts)
5117 # search for a unique phase argument
5117 # search for a unique phase argument
5118 targetphase = None
5118 targetphase = None
5119 for idx, name in enumerate(phases.cmdphasenames):
5119 for idx, name in enumerate(phases.cmdphasenames):
5120 if opts[name]:
5120 if opts[name]:
5121 if targetphase is not None:
5121 if targetphase is not None:
5122 raise error.Abort(_(b'only one phase can be specified'))
5122 raise error.Abort(_(b'only one phase can be specified'))
5123 targetphase = idx
5123 targetphase = idx
5124
5124
5125 # look for specified revision
5125 # look for specified revision
5126 revs = list(revs)
5126 revs = list(revs)
5127 revs.extend(opts[b'rev'])
5127 revs.extend(opts[b'rev'])
5128 if not revs:
5128 if not revs:
5129 # display both parents as the second parent phase can influence
5129 # display both parents as the second parent phase can influence
5130 # the phase of a merge commit
5130 # the phase of a merge commit
5131 revs = [c.rev() for c in repo[None].parents()]
5131 revs = [c.rev() for c in repo[None].parents()]
5132
5132
5133 revs = scmutil.revrange(repo, revs)
5133 revs = scmutil.revrange(repo, revs)
5134
5134
5135 ret = 0
5135 ret = 0
5136 if targetphase is None:
5136 if targetphase is None:
5137 # display
5137 # display
5138 for r in revs:
5138 for r in revs:
5139 ctx = repo[r]
5139 ctx = repo[r]
5140 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5140 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5141 else:
5141 else:
5142 with repo.lock(), repo.transaction(b"phase") as tr:
5142 with repo.lock(), repo.transaction(b"phase") as tr:
5143 # set phase
5143 # set phase
5144 if not revs:
5144 if not revs:
5145 raise error.Abort(_(b'empty revision set'))
5145 raise error.Abort(_(b'empty revision set'))
5146 nodes = [repo[r].node() for r in revs]
5146 nodes = [repo[r].node() for r in revs]
5147 # moving revision from public to draft may hide them
5147 # moving revision from public to draft may hide them
5148 # We have to check result on an unfiltered repository
5148 # We have to check result on an unfiltered repository
5149 unfi = repo.unfiltered()
5149 unfi = repo.unfiltered()
5150 getphase = unfi._phasecache.phase
5150 getphase = unfi._phasecache.phase
5151 olddata = [getphase(unfi, r) for r in unfi]
5151 olddata = [getphase(unfi, r) for r in unfi]
5152 phases.advanceboundary(repo, tr, targetphase, nodes)
5152 phases.advanceboundary(repo, tr, targetphase, nodes)
5153 if opts[b'force']:
5153 if opts[b'force']:
5154 phases.retractboundary(repo, tr, targetphase, nodes)
5154 phases.retractboundary(repo, tr, targetphase, nodes)
5155 getphase = unfi._phasecache.phase
5155 getphase = unfi._phasecache.phase
5156 newdata = [getphase(unfi, r) for r in unfi]
5156 newdata = [getphase(unfi, r) for r in unfi]
5157 changes = sum(newdata[r] != olddata[r] for r in unfi)
5157 changes = sum(newdata[r] != olddata[r] for r in unfi)
5158 cl = unfi.changelog
5158 cl = unfi.changelog
5159 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5159 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5160 if rejected:
5160 if rejected:
5161 ui.warn(
5161 ui.warn(
5162 _(
5162 _(
5163 b'cannot move %i changesets to a higher '
5163 b'cannot move %i changesets to a higher '
5164 b'phase, use --force\n'
5164 b'phase, use --force\n'
5165 )
5165 )
5166 % len(rejected)
5166 % len(rejected)
5167 )
5167 )
5168 ret = 1
5168 ret = 1
5169 if changes:
5169 if changes:
5170 msg = _(b'phase changed for %i changesets\n') % changes
5170 msg = _(b'phase changed for %i changesets\n') % changes
5171 if ret:
5171 if ret:
5172 ui.status(msg)
5172 ui.status(msg)
5173 else:
5173 else:
5174 ui.note(msg)
5174 ui.note(msg)
5175 else:
5175 else:
5176 ui.warn(_(b'no phases changed\n'))
5176 ui.warn(_(b'no phases changed\n'))
5177 return ret
5177 return ret
5178
5178
5179
5179
5180 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5180 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5181 """Run after a changegroup has been added via pull/unbundle
5181 """Run after a changegroup has been added via pull/unbundle
5182
5182
5183 This takes arguments below:
5183 This takes arguments below:
5184
5184
5185 :modheads: change of heads by pull/unbundle
5185 :modheads: change of heads by pull/unbundle
5186 :optupdate: updating working directory is needed or not
5186 :optupdate: updating working directory is needed or not
5187 :checkout: update destination revision (or None to default destination)
5187 :checkout: update destination revision (or None to default destination)
5188 :brev: a name, which might be a bookmark to be activated after updating
5188 :brev: a name, which might be a bookmark to be activated after updating
5189 """
5189 """
5190 if modheads == 0:
5190 if modheads == 0:
5191 return
5191 return
5192 if optupdate:
5192 if optupdate:
5193 try:
5193 try:
5194 return hg.updatetotally(ui, repo, checkout, brev)
5194 return hg.updatetotally(ui, repo, checkout, brev)
5195 except error.UpdateAbort as inst:
5195 except error.UpdateAbort as inst:
5196 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5196 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5197 hint = inst.hint
5197 hint = inst.hint
5198 raise error.UpdateAbort(msg, hint=hint)
5198 raise error.UpdateAbort(msg, hint=hint)
5199 if modheads is not None and modheads > 1:
5199 if modheads is not None and modheads > 1:
5200 currentbranchheads = len(repo.branchheads())
5200 currentbranchheads = len(repo.branchheads())
5201 if currentbranchheads == modheads:
5201 if currentbranchheads == modheads:
5202 ui.status(
5202 ui.status(
5203 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5203 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5204 )
5204 )
5205 elif currentbranchheads > 1:
5205 elif currentbranchheads > 1:
5206 ui.status(
5206 ui.status(
5207 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5207 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5208 )
5208 )
5209 else:
5209 else:
5210 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5210 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5211 elif not ui.configbool(b'commands', b'update.requiredest'):
5211 elif not ui.configbool(b'commands', b'update.requiredest'):
5212 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5212 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5213
5213
5214
5214
5215 @command(
5215 @command(
5216 b'pull',
5216 b'pull',
5217 [
5217 [
5218 (
5218 (
5219 b'u',
5219 b'u',
5220 b'update',
5220 b'update',
5221 None,
5221 None,
5222 _(b'update to new branch head if new descendants were pulled'),
5222 _(b'update to new branch head if new descendants were pulled'),
5223 ),
5223 ),
5224 (
5224 (
5225 b'f',
5225 b'f',
5226 b'force',
5226 b'force',
5227 None,
5227 None,
5228 _(b'run even when remote repository is unrelated'),
5228 _(b'run even when remote repository is unrelated'),
5229 ),
5229 ),
5230 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5230 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5231 (
5231 (
5232 b'r',
5232 b'r',
5233 b'rev',
5233 b'rev',
5234 [],
5234 [],
5235 _(b'a remote changeset intended to be added'),
5235 _(b'a remote changeset intended to be added'),
5236 _(b'REV'),
5236 _(b'REV'),
5237 ),
5237 ),
5238 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5238 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5239 (
5239 (
5240 b'b',
5240 b'b',
5241 b'branch',
5241 b'branch',
5242 [],
5242 [],
5243 _(b'a specific branch you would like to pull'),
5243 _(b'a specific branch you would like to pull'),
5244 _(b'BRANCH'),
5244 _(b'BRANCH'),
5245 ),
5245 ),
5246 ]
5246 ]
5247 + remoteopts,
5247 + remoteopts,
5248 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5248 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5249 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5249 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5250 helpbasic=True,
5250 helpbasic=True,
5251 )
5251 )
5252 def pull(ui, repo, source=b"default", **opts):
5252 def pull(ui, repo, source=b"default", **opts):
5253 """pull changes from the specified source
5253 """pull changes from the specified source
5254
5254
5255 Pull changes from a remote repository to a local one.
5255 Pull changes from a remote repository to a local one.
5256
5256
5257 This finds all changes from the repository at the specified path
5257 This finds all changes from the repository at the specified path
5258 or URL and adds them to a local repository (the current one unless
5258 or URL and adds them to a local repository (the current one unless
5259 -R is specified). By default, this does not update the copy of the
5259 -R is specified). By default, this does not update the copy of the
5260 project in the working directory.
5260 project in the working directory.
5261
5261
5262 When cloning from servers that support it, Mercurial may fetch
5262 When cloning from servers that support it, Mercurial may fetch
5263 pre-generated data. When this is done, hooks operating on incoming
5263 pre-generated data. When this is done, hooks operating on incoming
5264 changesets and changegroups may fire more than once, once for each
5264 changesets and changegroups may fire more than once, once for each
5265 pre-generated bundle and as well as for any additional remaining
5265 pre-generated bundle and as well as for any additional remaining
5266 data. See :hg:`help -e clonebundles` for more.
5266 data. See :hg:`help -e clonebundles` for more.
5267
5267
5268 Use :hg:`incoming` if you want to see what would have been added
5268 Use :hg:`incoming` if you want to see what would have been added
5269 by a pull at the time you issued this command. If you then decide
5269 by a pull at the time you issued this command. If you then decide
5270 to add those changes to the repository, you should use :hg:`pull
5270 to add those changes to the repository, you should use :hg:`pull
5271 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5271 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5272
5272
5273 If SOURCE is omitted, the 'default' path will be used.
5273 If SOURCE is omitted, the 'default' path will be used.
5274 See :hg:`help urls` for more information.
5274 See :hg:`help urls` for more information.
5275
5275
5276 Specifying bookmark as ``.`` is equivalent to specifying the active
5276 Specifying bookmark as ``.`` is equivalent to specifying the active
5277 bookmark's name.
5277 bookmark's name.
5278
5278
5279 Returns 0 on success, 1 if an update had unresolved files.
5279 Returns 0 on success, 1 if an update had unresolved files.
5280 """
5280 """
5281
5281
5282 opts = pycompat.byteskwargs(opts)
5282 opts = pycompat.byteskwargs(opts)
5283 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5283 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5284 b'update'
5284 b'update'
5285 ):
5285 ):
5286 msg = _(b'update destination required by configuration')
5286 msg = _(b'update destination required by configuration')
5287 hint = _(b'use hg pull followed by hg update DEST')
5287 hint = _(b'use hg pull followed by hg update DEST')
5288 raise error.Abort(msg, hint=hint)
5288 raise error.Abort(msg, hint=hint)
5289
5289
5290 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5290 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5291 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5291 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5292 other = hg.peer(repo, opts, source)
5292 other = hg.peer(repo, opts, source)
5293 try:
5293 try:
5294 revs, checkout = hg.addbranchrevs(
5294 revs, checkout = hg.addbranchrevs(
5295 repo, other, branches, opts.get(b'rev')
5295 repo, other, branches, opts.get(b'rev')
5296 )
5296 )
5297
5297
5298 pullopargs = {}
5298 pullopargs = {}
5299
5299
5300 nodes = None
5300 nodes = None
5301 if opts.get(b'bookmark') or revs:
5301 if opts.get(b'bookmark') or revs:
5302 # The list of bookmark used here is the same used to actually update
5302 # The list of bookmark used here is the same used to actually update
5303 # the bookmark names, to avoid the race from issue 4689 and we do
5303 # the bookmark names, to avoid the race from issue 4689 and we do
5304 # all lookup and bookmark queries in one go so they see the same
5304 # all lookup and bookmark queries in one go so they see the same
5305 # version of the server state (issue 4700).
5305 # version of the server state (issue 4700).
5306 nodes = []
5306 nodes = []
5307 fnodes = []
5307 fnodes = []
5308 revs = revs or []
5308 revs = revs or []
5309 if revs and not other.capable(b'lookup'):
5309 if revs and not other.capable(b'lookup'):
5310 err = _(
5310 err = _(
5311 b"other repository doesn't support revision lookup, "
5311 b"other repository doesn't support revision lookup, "
5312 b"so a rev cannot be specified."
5312 b"so a rev cannot be specified."
5313 )
5313 )
5314 raise error.Abort(err)
5314 raise error.Abort(err)
5315 with other.commandexecutor() as e:
5315 with other.commandexecutor() as e:
5316 fremotebookmarks = e.callcommand(
5316 fremotebookmarks = e.callcommand(
5317 b'listkeys', {b'namespace': b'bookmarks'}
5317 b'listkeys', {b'namespace': b'bookmarks'}
5318 )
5318 )
5319 for r in revs:
5319 for r in revs:
5320 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5320 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5321 remotebookmarks = fremotebookmarks.result()
5321 remotebookmarks = fremotebookmarks.result()
5322 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5322 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5323 pullopargs[b'remotebookmarks'] = remotebookmarks
5323 pullopargs[b'remotebookmarks'] = remotebookmarks
5324 for b in opts.get(b'bookmark', []):
5324 for b in opts.get(b'bookmark', []):
5325 b = repo._bookmarks.expandname(b)
5325 b = repo._bookmarks.expandname(b)
5326 if b not in remotebookmarks:
5326 if b not in remotebookmarks:
5327 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5327 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5328 nodes.append(remotebookmarks[b])
5328 nodes.append(remotebookmarks[b])
5329 for i, rev in enumerate(revs):
5329 for i, rev in enumerate(revs):
5330 node = fnodes[i].result()
5330 node = fnodes[i].result()
5331 nodes.append(node)
5331 nodes.append(node)
5332 if rev == checkout:
5332 if rev == checkout:
5333 checkout = node
5333 checkout = node
5334
5334
5335 wlock = util.nullcontextmanager()
5335 wlock = util.nullcontextmanager()
5336 if opts.get(b'update'):
5336 if opts.get(b'update'):
5337 wlock = repo.wlock()
5337 wlock = repo.wlock()
5338 with wlock:
5338 with wlock:
5339 pullopargs.update(opts.get(b'opargs', {}))
5339 pullopargs.update(opts.get(b'opargs', {}))
5340 modheads = exchange.pull(
5340 modheads = exchange.pull(
5341 repo,
5341 repo,
5342 other,
5342 other,
5343 heads=nodes,
5343 heads=nodes,
5344 force=opts.get(b'force'),
5344 force=opts.get(b'force'),
5345 bookmarks=opts.get(b'bookmark', ()),
5345 bookmarks=opts.get(b'bookmark', ()),
5346 opargs=pullopargs,
5346 opargs=pullopargs,
5347 confirm=opts.get(b'confirm'),
5347 confirm=opts.get(b'confirm'),
5348 ).cgresult
5348 ).cgresult
5349
5349
5350 # brev is a name, which might be a bookmark to be activated at
5350 # brev is a name, which might be a bookmark to be activated at
5351 # the end of the update. In other words, it is an explicit
5351 # the end of the update. In other words, it is an explicit
5352 # destination of the update
5352 # destination of the update
5353 brev = None
5353 brev = None
5354
5354
5355 if checkout:
5355 if checkout:
5356 checkout = repo.unfiltered().changelog.rev(checkout)
5356 checkout = repo.unfiltered().changelog.rev(checkout)
5357
5357
5358 # order below depends on implementation of
5358 # order below depends on implementation of
5359 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5359 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5360 # because 'checkout' is determined without it.
5360 # because 'checkout' is determined without it.
5361 if opts.get(b'rev'):
5361 if opts.get(b'rev'):
5362 brev = opts[b'rev'][0]
5362 brev = opts[b'rev'][0]
5363 elif opts.get(b'branch'):
5363 elif opts.get(b'branch'):
5364 brev = opts[b'branch'][0]
5364 brev = opts[b'branch'][0]
5365 else:
5365 else:
5366 brev = branches[0]
5366 brev = branches[0]
5367 repo._subtoppath = source
5367 repo._subtoppath = source
5368 try:
5368 try:
5369 ret = postincoming(
5369 ret = postincoming(
5370 ui, repo, modheads, opts.get(b'update'), checkout, brev
5370 ui, repo, modheads, opts.get(b'update'), checkout, brev
5371 )
5371 )
5372 except error.FilteredRepoLookupError as exc:
5372 except error.FilteredRepoLookupError as exc:
5373 msg = _(b'cannot update to target: %s') % exc.args[0]
5373 msg = _(b'cannot update to target: %s') % exc.args[0]
5374 exc.args = (msg,) + exc.args[1:]
5374 exc.args = (msg,) + exc.args[1:]
5375 raise
5375 raise
5376 finally:
5376 finally:
5377 del repo._subtoppath
5377 del repo._subtoppath
5378
5378
5379 finally:
5379 finally:
5380 other.close()
5380 other.close()
5381 return ret
5381 return ret
5382
5382
5383
5383
5384 @command(
5384 @command(
5385 b'push',
5385 b'push',
5386 [
5386 [
5387 (b'f', b'force', None, _(b'force push')),
5387 (b'f', b'force', None, _(b'force push')),
5388 (
5388 (
5389 b'r',
5389 b'r',
5390 b'rev',
5390 b'rev',
5391 [],
5391 [],
5392 _(b'a changeset intended to be included in the destination'),
5392 _(b'a changeset intended to be included in the destination'),
5393 _(b'REV'),
5393 _(b'REV'),
5394 ),
5394 ),
5395 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5395 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5396 (
5396 (
5397 b'b',
5397 b'b',
5398 b'branch',
5398 b'branch',
5399 [],
5399 [],
5400 _(b'a specific branch you would like to push'),
5400 _(b'a specific branch you would like to push'),
5401 _(b'BRANCH'),
5401 _(b'BRANCH'),
5402 ),
5402 ),
5403 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5403 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5404 (
5404 (
5405 b'',
5405 b'',
5406 b'pushvars',
5406 b'pushvars',
5407 [],
5407 [],
5408 _(b'variables that can be sent to server (ADVANCED)'),
5408 _(b'variables that can be sent to server (ADVANCED)'),
5409 ),
5409 ),
5410 (
5410 (
5411 b'',
5411 b'',
5412 b'publish',
5412 b'publish',
5413 False,
5413 False,
5414 _(b'push the changeset as public (EXPERIMENTAL)'),
5414 _(b'push the changeset as public (EXPERIMENTAL)'),
5415 ),
5415 ),
5416 ]
5416 ]
5417 + remoteopts,
5417 + remoteopts,
5418 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5418 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5419 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5419 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5420 helpbasic=True,
5420 helpbasic=True,
5421 )
5421 )
5422 def push(ui, repo, dest=None, **opts):
5422 def push(ui, repo, dest=None, **opts):
5423 """push changes to the specified destination
5423 """push changes to the specified destination
5424
5424
5425 Push changesets from the local repository to the specified
5425 Push changesets from the local repository to the specified
5426 destination.
5426 destination.
5427
5427
5428 This operation is symmetrical to pull: it is identical to a pull
5428 This operation is symmetrical to pull: it is identical to a pull
5429 in the destination repository from the current one.
5429 in the destination repository from the current one.
5430
5430
5431 By default, push will not allow creation of new heads at the
5431 By default, push will not allow creation of new heads at the
5432 destination, since multiple heads would make it unclear which head
5432 destination, since multiple heads would make it unclear which head
5433 to use. In this situation, it is recommended to pull and merge
5433 to use. In this situation, it is recommended to pull and merge
5434 before pushing.
5434 before pushing.
5435
5435
5436 Use --new-branch if you want to allow push to create a new named
5436 Use --new-branch if you want to allow push to create a new named
5437 branch that is not present at the destination. This allows you to
5437 branch that is not present at the destination. This allows you to
5438 only create a new branch without forcing other changes.
5438 only create a new branch without forcing other changes.
5439
5439
5440 .. note::
5440 .. note::
5441
5441
5442 Extra care should be taken with the -f/--force option,
5442 Extra care should be taken with the -f/--force option,
5443 which will push all new heads on all branches, an action which will
5443 which will push all new heads on all branches, an action which will
5444 almost always cause confusion for collaborators.
5444 almost always cause confusion for collaborators.
5445
5445
5446 If -r/--rev is used, the specified revision and all its ancestors
5446 If -r/--rev is used, the specified revision and all its ancestors
5447 will be pushed to the remote repository.
5447 will be pushed to the remote repository.
5448
5448
5449 If -B/--bookmark is used, the specified bookmarked revision, its
5449 If -B/--bookmark is used, the specified bookmarked revision, its
5450 ancestors, and the bookmark will be pushed to the remote
5450 ancestors, and the bookmark will be pushed to the remote
5451 repository. Specifying ``.`` is equivalent to specifying the active
5451 repository. Specifying ``.`` is equivalent to specifying the active
5452 bookmark's name.
5452 bookmark's name.
5453
5453
5454 Please see :hg:`help urls` for important details about ``ssh://``
5454 Please see :hg:`help urls` for important details about ``ssh://``
5455 URLs. If DESTINATION is omitted, a default path will be used.
5455 URLs. If DESTINATION is omitted, a default path will be used.
5456
5456
5457 .. container:: verbose
5457 .. container:: verbose
5458
5458
5459 The --pushvars option sends strings to the server that become
5459 The --pushvars option sends strings to the server that become
5460 environment variables prepended with ``HG_USERVAR_``. For example,
5460 environment variables prepended with ``HG_USERVAR_``. For example,
5461 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5461 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5462 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5462 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5463
5463
5464 pushvars can provide for user-overridable hooks as well as set debug
5464 pushvars can provide for user-overridable hooks as well as set debug
5465 levels. One example is having a hook that blocks commits containing
5465 levels. One example is having a hook that blocks commits containing
5466 conflict markers, but enables the user to override the hook if the file
5466 conflict markers, but enables the user to override the hook if the file
5467 is using conflict markers for testing purposes or the file format has
5467 is using conflict markers for testing purposes or the file format has
5468 strings that look like conflict markers.
5468 strings that look like conflict markers.
5469
5469
5470 By default, servers will ignore `--pushvars`. To enable it add the
5470 By default, servers will ignore `--pushvars`. To enable it add the
5471 following to your configuration file::
5471 following to your configuration file::
5472
5472
5473 [push]
5473 [push]
5474 pushvars.server = true
5474 pushvars.server = true
5475
5475
5476 Returns 0 if push was successful, 1 if nothing to push.
5476 Returns 0 if push was successful, 1 if nothing to push.
5477 """
5477 """
5478
5478
5479 opts = pycompat.byteskwargs(opts)
5479 opts = pycompat.byteskwargs(opts)
5480 if opts.get(b'bookmark'):
5480 if opts.get(b'bookmark'):
5481 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5481 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5482 for b in opts[b'bookmark']:
5482 for b in opts[b'bookmark']:
5483 # translate -B options to -r so changesets get pushed
5483 # translate -B options to -r so changesets get pushed
5484 b = repo._bookmarks.expandname(b)
5484 b = repo._bookmarks.expandname(b)
5485 if b in repo._bookmarks:
5485 if b in repo._bookmarks:
5486 opts.setdefault(b'rev', []).append(b)
5486 opts.setdefault(b'rev', []).append(b)
5487 else:
5487 else:
5488 # if we try to push a deleted bookmark, translate it to null
5488 # if we try to push a deleted bookmark, translate it to null
5489 # this lets simultaneous -r, -b options continue working
5489 # this lets simultaneous -r, -b options continue working
5490 opts.setdefault(b'rev', []).append(b"null")
5490 opts.setdefault(b'rev', []).append(b"null")
5491
5491
5492 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5492 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5493 if not path:
5493 if not path:
5494 raise error.Abort(
5494 raise error.Abort(
5495 _(b'default repository not configured!'),
5495 _(b'default repository not configured!'),
5496 hint=_(b"see 'hg help config.paths'"),
5496 hint=_(b"see 'hg help config.paths'"),
5497 )
5497 )
5498 dest = path.pushloc or path.loc
5498 dest = path.pushloc or path.loc
5499 branches = (path.branch, opts.get(b'branch') or [])
5499 branches = (path.branch, opts.get(b'branch') or [])
5500 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5500 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5501 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5501 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5502 other = hg.peer(repo, opts, dest)
5502 other = hg.peer(repo, opts, dest)
5503
5503
5504 if revs:
5504 if revs:
5505 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5505 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5506 if not revs:
5506 if not revs:
5507 raise error.Abort(
5507 raise error.Abort(
5508 _(b"specified revisions evaluate to an empty set"),
5508 _(b"specified revisions evaluate to an empty set"),
5509 hint=_(b"use different revision arguments"),
5509 hint=_(b"use different revision arguments"),
5510 )
5510 )
5511 elif path.pushrev:
5511 elif path.pushrev:
5512 # It doesn't make any sense to specify ancestor revisions. So limit
5512 # It doesn't make any sense to specify ancestor revisions. So limit
5513 # to DAG heads to make discovery simpler.
5513 # to DAG heads to make discovery simpler.
5514 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5514 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5515 revs = scmutil.revrange(repo, [expr])
5515 revs = scmutil.revrange(repo, [expr])
5516 revs = [repo[rev].node() for rev in revs]
5516 revs = [repo[rev].node() for rev in revs]
5517 if not revs:
5517 if not revs:
5518 raise error.Abort(
5518 raise error.Abort(
5519 _(b'default push revset for path evaluates to an empty set')
5519 _(b'default push revset for path evaluates to an empty set')
5520 )
5520 )
5521 elif ui.configbool(b'commands', b'push.require-revs'):
5521 elif ui.configbool(b'commands', b'push.require-revs'):
5522 raise error.Abort(
5522 raise error.Abort(
5523 _(b'no revisions specified to push'),
5523 _(b'no revisions specified to push'),
5524 hint=_(b'did you mean "hg push -r ."?'),
5524 hint=_(b'did you mean "hg push -r ."?'),
5525 )
5525 )
5526
5526
5527 repo._subtoppath = dest
5527 repo._subtoppath = dest
5528 try:
5528 try:
5529 # push subrepos depth-first for coherent ordering
5529 # push subrepos depth-first for coherent ordering
5530 c = repo[b'.']
5530 c = repo[b'.']
5531 subs = c.substate # only repos that are committed
5531 subs = c.substate # only repos that are committed
5532 for s in sorted(subs):
5532 for s in sorted(subs):
5533 result = c.sub(s).push(opts)
5533 result = c.sub(s).push(opts)
5534 if result == 0:
5534 if result == 0:
5535 return not result
5535 return not result
5536 finally:
5536 finally:
5537 del repo._subtoppath
5537 del repo._subtoppath
5538
5538
5539 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5539 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5540 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5540 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5541
5541
5542 pushop = exchange.push(
5542 pushop = exchange.push(
5543 repo,
5543 repo,
5544 other,
5544 other,
5545 opts.get(b'force'),
5545 opts.get(b'force'),
5546 revs=revs,
5546 revs=revs,
5547 newbranch=opts.get(b'new_branch'),
5547 newbranch=opts.get(b'new_branch'),
5548 bookmarks=opts.get(b'bookmark', ()),
5548 bookmarks=opts.get(b'bookmark', ()),
5549 publish=opts.get(b'publish'),
5549 publish=opts.get(b'publish'),
5550 opargs=opargs,
5550 opargs=opargs,
5551 )
5551 )
5552
5552
5553 result = not pushop.cgresult
5553 result = not pushop.cgresult
5554
5554
5555 if pushop.bkresult is not None:
5555 if pushop.bkresult is not None:
5556 if pushop.bkresult == 2:
5556 if pushop.bkresult == 2:
5557 result = 2
5557 result = 2
5558 elif not result and pushop.bkresult:
5558 elif not result and pushop.bkresult:
5559 result = 2
5559 result = 2
5560
5560
5561 return result
5561 return result
5562
5562
5563
5563
5564 @command(
5564 @command(
5565 b'recover',
5565 b'recover',
5566 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5566 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5567 helpcategory=command.CATEGORY_MAINTENANCE,
5567 helpcategory=command.CATEGORY_MAINTENANCE,
5568 )
5568 )
5569 def recover(ui, repo, **opts):
5569 def recover(ui, repo, **opts):
5570 """roll back an interrupted transaction
5570 """roll back an interrupted transaction
5571
5571
5572 Recover from an interrupted commit or pull.
5572 Recover from an interrupted commit or pull.
5573
5573
5574 This command tries to fix the repository status after an
5574 This command tries to fix the repository status after an
5575 interrupted operation. It should only be necessary when Mercurial
5575 interrupted operation. It should only be necessary when Mercurial
5576 suggests it.
5576 suggests it.
5577
5577
5578 Returns 0 if successful, 1 if nothing to recover or verify fails.
5578 Returns 0 if successful, 1 if nothing to recover or verify fails.
5579 """
5579 """
5580 ret = repo.recover()
5580 ret = repo.recover()
5581 if ret:
5581 if ret:
5582 if opts['verify']:
5582 if opts['verify']:
5583 return hg.verify(repo)
5583 return hg.verify(repo)
5584 else:
5584 else:
5585 msg = _(
5585 msg = _(
5586 b"(verify step skipped, run `hg verify` to check your "
5586 b"(verify step skipped, run `hg verify` to check your "
5587 b"repository content)\n"
5587 b"repository content)\n"
5588 )
5588 )
5589 ui.warn(msg)
5589 ui.warn(msg)
5590 return 0
5590 return 0
5591 return 1
5591 return 1
5592
5592
5593
5593
5594 @command(
5594 @command(
5595 b'remove|rm',
5595 b'remove|rm',
5596 [
5596 [
5597 (b'A', b'after', None, _(b'record delete for missing files')),
5597 (b'A', b'after', None, _(b'record delete for missing files')),
5598 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5598 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5599 ]
5599 ]
5600 + subrepoopts
5600 + subrepoopts
5601 + walkopts
5601 + walkopts
5602 + dryrunopts,
5602 + dryrunopts,
5603 _(b'[OPTION]... FILE...'),
5603 _(b'[OPTION]... FILE...'),
5604 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5604 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5605 helpbasic=True,
5605 helpbasic=True,
5606 inferrepo=True,
5606 inferrepo=True,
5607 )
5607 )
5608 def remove(ui, repo, *pats, **opts):
5608 def remove(ui, repo, *pats, **opts):
5609 """remove the specified files on the next commit
5609 """remove the specified files on the next commit
5610
5610
5611 Schedule the indicated files for removal from the current branch.
5611 Schedule the indicated files for removal from the current branch.
5612
5612
5613 This command schedules the files to be removed at the next commit.
5613 This command schedules the files to be removed at the next commit.
5614 To undo a remove before that, see :hg:`revert`. To undo added
5614 To undo a remove before that, see :hg:`revert`. To undo added
5615 files, see :hg:`forget`.
5615 files, see :hg:`forget`.
5616
5616
5617 .. container:: verbose
5617 .. container:: verbose
5618
5618
5619 -A/--after can be used to remove only files that have already
5619 -A/--after can be used to remove only files that have already
5620 been deleted, -f/--force can be used to force deletion, and -Af
5620 been deleted, -f/--force can be used to force deletion, and -Af
5621 can be used to remove files from the next revision without
5621 can be used to remove files from the next revision without
5622 deleting them from the working directory.
5622 deleting them from the working directory.
5623
5623
5624 The following table details the behavior of remove for different
5624 The following table details the behavior of remove for different
5625 file states (columns) and option combinations (rows). The file
5625 file states (columns) and option combinations (rows). The file
5626 states are Added [A], Clean [C], Modified [M] and Missing [!]
5626 states are Added [A], Clean [C], Modified [M] and Missing [!]
5627 (as reported by :hg:`status`). The actions are Warn, Remove
5627 (as reported by :hg:`status`). The actions are Warn, Remove
5628 (from branch) and Delete (from disk):
5628 (from branch) and Delete (from disk):
5629
5629
5630 ========= == == == ==
5630 ========= == == == ==
5631 opt/state A C M !
5631 opt/state A C M !
5632 ========= == == == ==
5632 ========= == == == ==
5633 none W RD W R
5633 none W RD W R
5634 -f R RD RD R
5634 -f R RD RD R
5635 -A W W W R
5635 -A W W W R
5636 -Af R R R R
5636 -Af R R R R
5637 ========= == == == ==
5637 ========= == == == ==
5638
5638
5639 .. note::
5639 .. note::
5640
5640
5641 :hg:`remove` never deletes files in Added [A] state from the
5641 :hg:`remove` never deletes files in Added [A] state from the
5642 working directory, not even if ``--force`` is specified.
5642 working directory, not even if ``--force`` is specified.
5643
5643
5644 Returns 0 on success, 1 if any warnings encountered.
5644 Returns 0 on success, 1 if any warnings encountered.
5645 """
5645 """
5646
5646
5647 opts = pycompat.byteskwargs(opts)
5647 opts = pycompat.byteskwargs(opts)
5648 after, force = opts.get(b'after'), opts.get(b'force')
5648 after, force = opts.get(b'after'), opts.get(b'force')
5649 dryrun = opts.get(b'dry_run')
5649 dryrun = opts.get(b'dry_run')
5650 if not pats and not after:
5650 if not pats and not after:
5651 raise error.Abort(_(b'no files specified'))
5651 raise error.Abort(_(b'no files specified'))
5652
5652
5653 m = scmutil.match(repo[None], pats, opts)
5653 m = scmutil.match(repo[None], pats, opts)
5654 subrepos = opts.get(b'subrepos')
5654 subrepos = opts.get(b'subrepos')
5655 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5655 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5656 return cmdutil.remove(
5656 return cmdutil.remove(
5657 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5657 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5658 )
5658 )
5659
5659
5660
5660
5661 @command(
5661 @command(
5662 b'rename|move|mv',
5662 b'rename|move|mv',
5663 [
5663 [
5664 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5664 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5665 (
5665 (
5666 b'',
5666 b'',
5667 b'at-rev',
5667 b'at-rev',
5668 b'',
5668 b'',
5669 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5669 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5670 _(b'REV'),
5670 _(b'REV'),
5671 ),
5671 ),
5672 (
5672 (
5673 b'f',
5673 b'f',
5674 b'force',
5674 b'force',
5675 None,
5675 None,
5676 _(b'forcibly move over an existing managed file'),
5676 _(b'forcibly move over an existing managed file'),
5677 ),
5677 ),
5678 ]
5678 ]
5679 + walkopts
5679 + walkopts
5680 + dryrunopts,
5680 + dryrunopts,
5681 _(b'[OPTION]... SOURCE... DEST'),
5681 _(b'[OPTION]... SOURCE... DEST'),
5682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5683 )
5683 )
5684 def rename(ui, repo, *pats, **opts):
5684 def rename(ui, repo, *pats, **opts):
5685 """rename files; equivalent of copy + remove
5685 """rename files; equivalent of copy + remove
5686
5686
5687 Mark dest as copies of sources; mark sources for deletion. If dest
5687 Mark dest as copies of sources; mark sources for deletion. If dest
5688 is a directory, copies are put in that directory. If dest is a
5688 is a directory, copies are put in that directory. If dest is a
5689 file, there can only be one source.
5689 file, there can only be one source.
5690
5690
5691 By default, this command copies the contents of files as they
5691 By default, this command copies the contents of files as they
5692 exist in the working directory. If invoked with -A/--after, the
5692 exist in the working directory. If invoked with -A/--after, the
5693 operation is recorded, but no copying is performed.
5693 operation is recorded, but no copying is performed.
5694
5694
5695 This command takes effect at the next commit. To undo a rename
5695 This command takes effect at the next commit. To undo a rename
5696 before that, see :hg:`revert`.
5696 before that, see :hg:`revert`.
5697
5697
5698 Returns 0 on success, 1 if errors are encountered.
5698 Returns 0 on success, 1 if errors are encountered.
5699 """
5699 """
5700 opts = pycompat.byteskwargs(opts)
5700 opts = pycompat.byteskwargs(opts)
5701 with repo.wlock():
5701 with repo.wlock():
5702 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5702 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5703
5703
5704
5704
5705 @command(
5705 @command(
5706 b'resolve',
5706 b'resolve',
5707 [
5707 [
5708 (b'a', b'all', None, _(b'select all unresolved files')),
5708 (b'a', b'all', None, _(b'select all unresolved files')),
5709 (b'l', b'list', None, _(b'list state of files needing merge')),
5709 (b'l', b'list', None, _(b'list state of files needing merge')),
5710 (b'm', b'mark', None, _(b'mark files as resolved')),
5710 (b'm', b'mark', None, _(b'mark files as resolved')),
5711 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5711 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5712 (b'n', b'no-status', None, _(b'hide status prefix')),
5712 (b'n', b'no-status', None, _(b'hide status prefix')),
5713 (b'', b're-merge', None, _(b're-merge files')),
5713 (b'', b're-merge', None, _(b're-merge files')),
5714 ]
5714 ]
5715 + mergetoolopts
5715 + mergetoolopts
5716 + walkopts
5716 + walkopts
5717 + formatteropts,
5717 + formatteropts,
5718 _(b'[OPTION]... [FILE]...'),
5718 _(b'[OPTION]... [FILE]...'),
5719 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5719 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5720 inferrepo=True,
5720 inferrepo=True,
5721 )
5721 )
5722 def resolve(ui, repo, *pats, **opts):
5722 def resolve(ui, repo, *pats, **opts):
5723 """redo merges or set/view the merge status of files
5723 """redo merges or set/view the merge status of files
5724
5724
5725 Merges with unresolved conflicts are often the result of
5725 Merges with unresolved conflicts are often the result of
5726 non-interactive merging using the ``internal:merge`` configuration
5726 non-interactive merging using the ``internal:merge`` configuration
5727 setting, or a command-line merge tool like ``diff3``. The resolve
5727 setting, or a command-line merge tool like ``diff3``. The resolve
5728 command is used to manage the files involved in a merge, after
5728 command is used to manage the files involved in a merge, after
5729 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5729 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5730 working directory must have two parents). See :hg:`help
5730 working directory must have two parents). See :hg:`help
5731 merge-tools` for information on configuring merge tools.
5731 merge-tools` for information on configuring merge tools.
5732
5732
5733 The resolve command can be used in the following ways:
5733 The resolve command can be used in the following ways:
5734
5734
5735 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5735 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5736 the specified files, discarding any previous merge attempts. Re-merging
5736 the specified files, discarding any previous merge attempts. Re-merging
5737 is not performed for files already marked as resolved. Use ``--all/-a``
5737 is not performed for files already marked as resolved. Use ``--all/-a``
5738 to select all unresolved files. ``--tool`` can be used to specify
5738 to select all unresolved files. ``--tool`` can be used to specify
5739 the merge tool used for the given files. It overrides the HGMERGE
5739 the merge tool used for the given files. It overrides the HGMERGE
5740 environment variable and your configuration files. Previous file
5740 environment variable and your configuration files. Previous file
5741 contents are saved with a ``.orig`` suffix.
5741 contents are saved with a ``.orig`` suffix.
5742
5742
5743 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5743 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5744 (e.g. after having manually fixed-up the files). The default is
5744 (e.g. after having manually fixed-up the files). The default is
5745 to mark all unresolved files.
5745 to mark all unresolved files.
5746
5746
5747 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5747 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5748 default is to mark all resolved files.
5748 default is to mark all resolved files.
5749
5749
5750 - :hg:`resolve -l`: list files which had or still have conflicts.
5750 - :hg:`resolve -l`: list files which had or still have conflicts.
5751 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5751 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5752 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5752 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5753 the list. See :hg:`help filesets` for details.
5753 the list. See :hg:`help filesets` for details.
5754
5754
5755 .. note::
5755 .. note::
5756
5756
5757 Mercurial will not let you commit files with unresolved merge
5757 Mercurial will not let you commit files with unresolved merge
5758 conflicts. You must use :hg:`resolve -m ...` before you can
5758 conflicts. You must use :hg:`resolve -m ...` before you can
5759 commit after a conflicting merge.
5759 commit after a conflicting merge.
5760
5760
5761 .. container:: verbose
5761 .. container:: verbose
5762
5762
5763 Template:
5763 Template:
5764
5764
5765 The following keywords are supported in addition to the common template
5765 The following keywords are supported in addition to the common template
5766 keywords and functions. See also :hg:`help templates`.
5766 keywords and functions. See also :hg:`help templates`.
5767
5767
5768 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5768 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5769 :path: String. Repository-absolute path of the file.
5769 :path: String. Repository-absolute path of the file.
5770
5770
5771 Returns 0 on success, 1 if any files fail a resolve attempt.
5771 Returns 0 on success, 1 if any files fail a resolve attempt.
5772 """
5772 """
5773
5773
5774 opts = pycompat.byteskwargs(opts)
5774 opts = pycompat.byteskwargs(opts)
5775 confirm = ui.configbool(b'commands', b'resolve.confirm')
5775 confirm = ui.configbool(b'commands', b'resolve.confirm')
5776 flaglist = b'all mark unmark list no_status re_merge'.split()
5776 flaglist = b'all mark unmark list no_status re_merge'.split()
5777 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5777 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5778
5778
5779 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5779 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5780 if actioncount > 1:
5780 if actioncount > 1:
5781 raise error.Abort(_(b"too many actions specified"))
5781 raise error.Abort(_(b"too many actions specified"))
5782 elif actioncount == 0 and ui.configbool(
5782 elif actioncount == 0 and ui.configbool(
5783 b'commands', b'resolve.explicit-re-merge'
5783 b'commands', b'resolve.explicit-re-merge'
5784 ):
5784 ):
5785 hint = _(b'use --mark, --unmark, --list or --re-merge')
5785 hint = _(b'use --mark, --unmark, --list or --re-merge')
5786 raise error.Abort(_(b'no action specified'), hint=hint)
5786 raise error.Abort(_(b'no action specified'), hint=hint)
5787 if pats and all:
5787 if pats and all:
5788 raise error.Abort(_(b"can't specify --all and patterns"))
5788 raise error.Abort(_(b"can't specify --all and patterns"))
5789 if not (all or pats or show or mark or unmark):
5789 if not (all or pats or show or mark or unmark):
5790 raise error.Abort(
5790 raise error.Abort(
5791 _(b'no files or directories specified'),
5791 _(b'no files or directories specified'),
5792 hint=b'use --all to re-merge all unresolved files',
5792 hint=b'use --all to re-merge all unresolved files',
5793 )
5793 )
5794
5794
5795 if confirm:
5795 if confirm:
5796 if all:
5796 if all:
5797 if ui.promptchoice(
5797 if ui.promptchoice(
5798 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5798 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5799 ):
5799 ):
5800 raise error.Abort(_(b'user quit'))
5800 raise error.Abort(_(b'user quit'))
5801 if mark and not pats:
5801 if mark and not pats:
5802 if ui.promptchoice(
5802 if ui.promptchoice(
5803 _(
5803 _(
5804 b'mark all unresolved files as resolved (yn)?'
5804 b'mark all unresolved files as resolved (yn)?'
5805 b'$$ &Yes $$ &No'
5805 b'$$ &Yes $$ &No'
5806 )
5806 )
5807 ):
5807 ):
5808 raise error.Abort(_(b'user quit'))
5808 raise error.Abort(_(b'user quit'))
5809 if unmark and not pats:
5809 if unmark and not pats:
5810 if ui.promptchoice(
5810 if ui.promptchoice(
5811 _(
5811 _(
5812 b'mark all resolved files as unresolved (yn)?'
5812 b'mark all resolved files as unresolved (yn)?'
5813 b'$$ &Yes $$ &No'
5813 b'$$ &Yes $$ &No'
5814 )
5814 )
5815 ):
5815 ):
5816 raise error.Abort(_(b'user quit'))
5816 raise error.Abort(_(b'user quit'))
5817
5817
5818 uipathfn = scmutil.getuipathfn(repo)
5818 uipathfn = scmutil.getuipathfn(repo)
5819
5819
5820 if show:
5820 if show:
5821 ui.pager(b'resolve')
5821 ui.pager(b'resolve')
5822 fm = ui.formatter(b'resolve', opts)
5822 fm = ui.formatter(b'resolve', opts)
5823 ms = mergestatemod.mergestate.read(repo)
5823 ms = mergestatemod.mergestate.read(repo)
5824 wctx = repo[None]
5824 wctx = repo[None]
5825 m = scmutil.match(wctx, pats, opts)
5825 m = scmutil.match(wctx, pats, opts)
5826
5826
5827 # Labels and keys based on merge state. Unresolved path conflicts show
5827 # Labels and keys based on merge state. Unresolved path conflicts show
5828 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5828 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5829 # resolved conflicts.
5829 # resolved conflicts.
5830 mergestateinfo = {
5830 mergestateinfo = {
5831 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5831 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5832 b'resolve.unresolved',
5832 b'resolve.unresolved',
5833 b'U',
5833 b'U',
5834 ),
5834 ),
5835 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5835 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5836 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5836 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5837 b'resolve.unresolved',
5837 b'resolve.unresolved',
5838 b'P',
5838 b'P',
5839 ),
5839 ),
5840 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5840 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5841 b'resolve.resolved',
5841 b'resolve.resolved',
5842 b'R',
5842 b'R',
5843 ),
5843 ),
5844 }
5844 }
5845
5845
5846 for f in ms:
5846 for f in ms:
5847 if not m(f):
5847 if not m(f):
5848 continue
5848 continue
5849
5849
5850 label, key = mergestateinfo[ms[f]]
5850 label, key = mergestateinfo[ms[f]]
5851 fm.startitem()
5851 fm.startitem()
5852 fm.context(ctx=wctx)
5852 fm.context(ctx=wctx)
5853 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5853 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5854 fm.data(path=f)
5854 fm.data(path=f)
5855 fm.plain(b'%s\n' % uipathfn(f), label=label)
5855 fm.plain(b'%s\n' % uipathfn(f), label=label)
5856 fm.end()
5856 fm.end()
5857 return 0
5857 return 0
5858
5858
5859 with repo.wlock():
5859 with repo.wlock():
5860 ms = mergestatemod.mergestate.read(repo)
5860 ms = mergestatemod.mergestate.read(repo)
5861
5861
5862 if not (ms.active() or repo.dirstate.p2() != nullid):
5862 if not (ms.active() or repo.dirstate.p2() != nullid):
5863 raise error.Abort(
5863 raise error.Abort(
5864 _(b'resolve command not applicable when not merging')
5864 _(b'resolve command not applicable when not merging')
5865 )
5865 )
5866
5866
5867 wctx = repo[None]
5867 wctx = repo[None]
5868 m = scmutil.match(wctx, pats, opts)
5868 m = scmutil.match(wctx, pats, opts)
5869 ret = 0
5869 ret = 0
5870 didwork = False
5870 didwork = False
5871
5871
5872 tocomplete = []
5872 tocomplete = []
5873 hasconflictmarkers = []
5873 hasconflictmarkers = []
5874 if mark:
5874 if mark:
5875 markcheck = ui.config(b'commands', b'resolve.mark-check')
5875 markcheck = ui.config(b'commands', b'resolve.mark-check')
5876 if markcheck not in [b'warn', b'abort']:
5876 if markcheck not in [b'warn', b'abort']:
5877 # Treat all invalid / unrecognized values as 'none'.
5877 # Treat all invalid / unrecognized values as 'none'.
5878 markcheck = False
5878 markcheck = False
5879 for f in ms:
5879 for f in ms:
5880 if not m(f):
5880 if not m(f):
5881 continue
5881 continue
5882
5882
5883 didwork = True
5883 didwork = True
5884
5884
5885 # path conflicts must be resolved manually
5885 # path conflicts must be resolved manually
5886 if ms[f] in (
5886 if ms[f] in (
5887 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5887 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5888 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5888 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5889 ):
5889 ):
5890 if mark:
5890 if mark:
5891 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5891 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5892 elif unmark:
5892 elif unmark:
5893 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5893 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5894 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5894 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5895 ui.warn(
5895 ui.warn(
5896 _(b'%s: path conflict must be resolved manually\n')
5896 _(b'%s: path conflict must be resolved manually\n')
5897 % uipathfn(f)
5897 % uipathfn(f)
5898 )
5898 )
5899 continue
5899 continue
5900
5900
5901 if mark:
5901 if mark:
5902 if markcheck:
5902 if markcheck:
5903 fdata = repo.wvfs.tryread(f)
5903 fdata = repo.wvfs.tryread(f)
5904 if (
5904 if (
5905 filemerge.hasconflictmarkers(fdata)
5905 filemerge.hasconflictmarkers(fdata)
5906 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5906 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5907 ):
5907 ):
5908 hasconflictmarkers.append(f)
5908 hasconflictmarkers.append(f)
5909 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5909 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5910 elif unmark:
5910 elif unmark:
5911 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5911 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5912 else:
5912 else:
5913 # backup pre-resolve (merge uses .orig for its own purposes)
5913 # backup pre-resolve (merge uses .orig for its own purposes)
5914 a = repo.wjoin(f)
5914 a = repo.wjoin(f)
5915 try:
5915 try:
5916 util.copyfile(a, a + b".resolve")
5916 util.copyfile(a, a + b".resolve")
5917 except (IOError, OSError) as inst:
5917 except (IOError, OSError) as inst:
5918 if inst.errno != errno.ENOENT:
5918 if inst.errno != errno.ENOENT:
5919 raise
5919 raise
5920
5920
5921 try:
5921 try:
5922 # preresolve file
5922 # preresolve file
5923 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5923 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5924 with ui.configoverride(overrides, b'resolve'):
5924 with ui.configoverride(overrides, b'resolve'):
5925 complete, r = ms.preresolve(f, wctx)
5925 complete, r = ms.preresolve(f, wctx)
5926 if not complete:
5926 if not complete:
5927 tocomplete.append(f)
5927 tocomplete.append(f)
5928 elif r:
5928 elif r:
5929 ret = 1
5929 ret = 1
5930 finally:
5930 finally:
5931 ms.commit()
5931 ms.commit()
5932
5932
5933 # replace filemerge's .orig file with our resolve file, but only
5933 # replace filemerge's .orig file with our resolve file, but only
5934 # for merges that are complete
5934 # for merges that are complete
5935 if complete:
5935 if complete:
5936 try:
5936 try:
5937 util.rename(
5937 util.rename(
5938 a + b".resolve", scmutil.backuppath(ui, repo, f)
5938 a + b".resolve", scmutil.backuppath(ui, repo, f)
5939 )
5939 )
5940 except OSError as inst:
5940 except OSError as inst:
5941 if inst.errno != errno.ENOENT:
5941 if inst.errno != errno.ENOENT:
5942 raise
5942 raise
5943
5943
5944 if hasconflictmarkers:
5944 if hasconflictmarkers:
5945 ui.warn(
5945 ui.warn(
5946 _(
5946 _(
5947 b'warning: the following files still have conflict '
5947 b'warning: the following files still have conflict '
5948 b'markers:\n'
5948 b'markers:\n'
5949 )
5949 )
5950 + b''.join(
5950 + b''.join(
5951 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5951 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5952 )
5952 )
5953 )
5953 )
5954 if markcheck == b'abort' and not all and not pats:
5954 if markcheck == b'abort' and not all and not pats:
5955 raise error.Abort(
5955 raise error.Abort(
5956 _(b'conflict markers detected'),
5956 _(b'conflict markers detected'),
5957 hint=_(b'use --all to mark anyway'),
5957 hint=_(b'use --all to mark anyway'),
5958 )
5958 )
5959
5959
5960 for f in tocomplete:
5960 for f in tocomplete:
5961 try:
5961 try:
5962 # resolve file
5962 # resolve file
5963 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5963 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5964 with ui.configoverride(overrides, b'resolve'):
5964 with ui.configoverride(overrides, b'resolve'):
5965 r = ms.resolve(f, wctx)
5965 r = ms.resolve(f, wctx)
5966 if r:
5966 if r:
5967 ret = 1
5967 ret = 1
5968 finally:
5968 finally:
5969 ms.commit()
5969 ms.commit()
5970
5970
5971 # replace filemerge's .orig file with our resolve file
5971 # replace filemerge's .orig file with our resolve file
5972 a = repo.wjoin(f)
5972 a = repo.wjoin(f)
5973 try:
5973 try:
5974 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5974 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5975 except OSError as inst:
5975 except OSError as inst:
5976 if inst.errno != errno.ENOENT:
5976 if inst.errno != errno.ENOENT:
5977 raise
5977 raise
5978
5978
5979 ms.commit()
5979 ms.commit()
5980 branchmerge = repo.dirstate.p2() != nullid
5980 branchmerge = repo.dirstate.p2() != nullid
5981 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5981 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5982
5982
5983 if not didwork and pats:
5983 if not didwork and pats:
5984 hint = None
5984 hint = None
5985 if not any([p for p in pats if p.find(b':') >= 0]):
5985 if not any([p for p in pats if p.find(b':') >= 0]):
5986 pats = [b'path:%s' % p for p in pats]
5986 pats = [b'path:%s' % p for p in pats]
5987 m = scmutil.match(wctx, pats, opts)
5987 m = scmutil.match(wctx, pats, opts)
5988 for f in ms:
5988 for f in ms:
5989 if not m(f):
5989 if not m(f):
5990 continue
5990 continue
5991
5991
5992 def flag(o):
5992 def flag(o):
5993 if o == b're_merge':
5993 if o == b're_merge':
5994 return b'--re-merge '
5994 return b'--re-merge '
5995 return b'-%s ' % o[0:1]
5995 return b'-%s ' % o[0:1]
5996
5996
5997 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5997 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5998 hint = _(b"(try: hg resolve %s%s)\n") % (
5998 hint = _(b"(try: hg resolve %s%s)\n") % (
5999 flags,
5999 flags,
6000 b' '.join(pats),
6000 b' '.join(pats),
6001 )
6001 )
6002 break
6002 break
6003 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6003 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6004 if hint:
6004 if hint:
6005 ui.warn(hint)
6005 ui.warn(hint)
6006
6006
6007 unresolvedf = list(ms.unresolved())
6007 unresolvedf = list(ms.unresolved())
6008 if not unresolvedf:
6008 if not unresolvedf:
6009 ui.status(_(b'(no more unresolved files)\n'))
6009 ui.status(_(b'(no more unresolved files)\n'))
6010 cmdutil.checkafterresolved(repo)
6010 cmdutil.checkafterresolved(repo)
6011
6011
6012 return ret
6012 return ret
6013
6013
6014
6014
6015 @command(
6015 @command(
6016 b'revert',
6016 b'revert',
6017 [
6017 [
6018 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6018 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6019 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6019 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6020 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6020 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6021 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6021 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6022 (b'i', b'interactive', None, _(b'interactively select the changes')),
6022 (b'i', b'interactive', None, _(b'interactively select the changes')),
6023 ]
6023 ]
6024 + walkopts
6024 + walkopts
6025 + dryrunopts,
6025 + dryrunopts,
6026 _(b'[OPTION]... [-r REV] [NAME]...'),
6026 _(b'[OPTION]... [-r REV] [NAME]...'),
6027 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6027 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6028 )
6028 )
6029 def revert(ui, repo, *pats, **opts):
6029 def revert(ui, repo, *pats, **opts):
6030 """restore files to their checkout state
6030 """restore files to their checkout state
6031
6031
6032 .. note::
6032 .. note::
6033
6033
6034 To check out earlier revisions, you should use :hg:`update REV`.
6034 To check out earlier revisions, you should use :hg:`update REV`.
6035 To cancel an uncommitted merge (and lose your changes),
6035 To cancel an uncommitted merge (and lose your changes),
6036 use :hg:`merge --abort`.
6036 use :hg:`merge --abort`.
6037
6037
6038 With no revision specified, revert the specified files or directories
6038 With no revision specified, revert the specified files or directories
6039 to the contents they had in the parent of the working directory.
6039 to the contents they had in the parent of the working directory.
6040 This restores the contents of files to an unmodified
6040 This restores the contents of files to an unmodified
6041 state and unschedules adds, removes, copies, and renames. If the
6041 state and unschedules adds, removes, copies, and renames. If the
6042 working directory has two parents, you must explicitly specify a
6042 working directory has two parents, you must explicitly specify a
6043 revision.
6043 revision.
6044
6044
6045 Using the -r/--rev or -d/--date options, revert the given files or
6045 Using the -r/--rev or -d/--date options, revert the given files or
6046 directories to their states as of a specific revision. Because
6046 directories to their states as of a specific revision. Because
6047 revert does not change the working directory parents, this will
6047 revert does not change the working directory parents, this will
6048 cause these files to appear modified. This can be helpful to "back
6048 cause these files to appear modified. This can be helpful to "back
6049 out" some or all of an earlier change. See :hg:`backout` for a
6049 out" some or all of an earlier change. See :hg:`backout` for a
6050 related method.
6050 related method.
6051
6051
6052 Modified files are saved with a .orig suffix before reverting.
6052 Modified files are saved with a .orig suffix before reverting.
6053 To disable these backups, use --no-backup. It is possible to store
6053 To disable these backups, use --no-backup. It is possible to store
6054 the backup files in a custom directory relative to the root of the
6054 the backup files in a custom directory relative to the root of the
6055 repository by setting the ``ui.origbackuppath`` configuration
6055 repository by setting the ``ui.origbackuppath`` configuration
6056 option.
6056 option.
6057
6057
6058 See :hg:`help dates` for a list of formats valid for -d/--date.
6058 See :hg:`help dates` for a list of formats valid for -d/--date.
6059
6059
6060 See :hg:`help backout` for a way to reverse the effect of an
6060 See :hg:`help backout` for a way to reverse the effect of an
6061 earlier changeset.
6061 earlier changeset.
6062
6062
6063 Returns 0 on success.
6063 Returns 0 on success.
6064 """
6064 """
6065
6065
6066 opts = pycompat.byteskwargs(opts)
6066 opts = pycompat.byteskwargs(opts)
6067 if opts.get(b"date"):
6067 if opts.get(b"date"):
6068 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6068 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6069 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6069 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6070
6070
6071 parent, p2 = repo.dirstate.parents()
6071 parent, p2 = repo.dirstate.parents()
6072 if not opts.get(b'rev') and p2 != nullid:
6072 if not opts.get(b'rev') and p2 != nullid:
6073 # revert after merge is a trap for new users (issue2915)
6073 # revert after merge is a trap for new users (issue2915)
6074 raise error.Abort(
6074 raise error.Abort(
6075 _(b'uncommitted merge with no revision specified'),
6075 _(b'uncommitted merge with no revision specified'),
6076 hint=_(b"use 'hg update' or see 'hg help revert'"),
6076 hint=_(b"use 'hg update' or see 'hg help revert'"),
6077 )
6077 )
6078
6078
6079 rev = opts.get(b'rev')
6079 rev = opts.get(b'rev')
6080 if rev:
6080 if rev:
6081 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6081 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6082 ctx = scmutil.revsingle(repo, rev)
6082 ctx = scmutil.revsingle(repo, rev)
6083
6083
6084 if not (
6084 if not (
6085 pats
6085 pats
6086 or opts.get(b'include')
6086 or opts.get(b'include')
6087 or opts.get(b'exclude')
6087 or opts.get(b'exclude')
6088 or opts.get(b'all')
6088 or opts.get(b'all')
6089 or opts.get(b'interactive')
6089 or opts.get(b'interactive')
6090 ):
6090 ):
6091 msg = _(b"no files or directories specified")
6091 msg = _(b"no files or directories specified")
6092 if p2 != nullid:
6092 if p2 != nullid:
6093 hint = _(
6093 hint = _(
6094 b"uncommitted merge, use --all to discard all changes,"
6094 b"uncommitted merge, use --all to discard all changes,"
6095 b" or 'hg update -C .' to abort the merge"
6095 b" or 'hg update -C .' to abort the merge"
6096 )
6096 )
6097 raise error.Abort(msg, hint=hint)
6097 raise error.Abort(msg, hint=hint)
6098 dirty = any(repo.status())
6098 dirty = any(repo.status())
6099 node = ctx.node()
6099 node = ctx.node()
6100 if node != parent:
6100 if node != parent:
6101 if dirty:
6101 if dirty:
6102 hint = (
6102 hint = (
6103 _(
6103 _(
6104 b"uncommitted changes, use --all to discard all"
6104 b"uncommitted changes, use --all to discard all"
6105 b" changes, or 'hg update %d' to update"
6105 b" changes, or 'hg update %d' to update"
6106 )
6106 )
6107 % ctx.rev()
6107 % ctx.rev()
6108 )
6108 )
6109 else:
6109 else:
6110 hint = (
6110 hint = (
6111 _(
6111 _(
6112 b"use --all to revert all files,"
6112 b"use --all to revert all files,"
6113 b" or 'hg update %d' to update"
6113 b" or 'hg update %d' to update"
6114 )
6114 )
6115 % ctx.rev()
6115 % ctx.rev()
6116 )
6116 )
6117 elif dirty:
6117 elif dirty:
6118 hint = _(b"uncommitted changes, use --all to discard all changes")
6118 hint = _(b"uncommitted changes, use --all to discard all changes")
6119 else:
6119 else:
6120 hint = _(b"use --all to revert all files")
6120 hint = _(b"use --all to revert all files")
6121 raise error.Abort(msg, hint=hint)
6121 raise error.Abort(msg, hint=hint)
6122
6122
6123 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6123 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6124
6124
6125
6125
6126 @command(
6126 @command(
6127 b'rollback',
6127 b'rollback',
6128 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6128 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6129 helpcategory=command.CATEGORY_MAINTENANCE,
6129 helpcategory=command.CATEGORY_MAINTENANCE,
6130 )
6130 )
6131 def rollback(ui, repo, **opts):
6131 def rollback(ui, repo, **opts):
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6133
6133
6134 Please use :hg:`commit --amend` instead of rollback to correct
6134 Please use :hg:`commit --amend` instead of rollback to correct
6135 mistakes in the last commit.
6135 mistakes in the last commit.
6136
6136
6137 This command should be used with care. There is only one level of
6137 This command should be used with care. There is only one level of
6138 rollback, and there is no way to undo a rollback. It will also
6138 rollback, and there is no way to undo a rollback. It will also
6139 restore the dirstate at the time of the last transaction, losing
6139 restore the dirstate at the time of the last transaction, losing
6140 any dirstate changes since that time. This command does not alter
6140 any dirstate changes since that time. This command does not alter
6141 the working directory.
6141 the working directory.
6142
6142
6143 Transactions are used to encapsulate the effects of all commands
6143 Transactions are used to encapsulate the effects of all commands
6144 that create new changesets or propagate existing changesets into a
6144 that create new changesets or propagate existing changesets into a
6145 repository.
6145 repository.
6146
6146
6147 .. container:: verbose
6147 .. container:: verbose
6148
6148
6149 For example, the following commands are transactional, and their
6149 For example, the following commands are transactional, and their
6150 effects can be rolled back:
6150 effects can be rolled back:
6151
6151
6152 - commit
6152 - commit
6153 - import
6153 - import
6154 - pull
6154 - pull
6155 - push (with this repository as the destination)
6155 - push (with this repository as the destination)
6156 - unbundle
6156 - unbundle
6157
6157
6158 To avoid permanent data loss, rollback will refuse to rollback a
6158 To avoid permanent data loss, rollback will refuse to rollback a
6159 commit transaction if it isn't checked out. Use --force to
6159 commit transaction if it isn't checked out. Use --force to
6160 override this protection.
6160 override this protection.
6161
6161
6162 The rollback command can be entirely disabled by setting the
6162 The rollback command can be entirely disabled by setting the
6163 ``ui.rollback`` configuration setting to false. If you're here
6163 ``ui.rollback`` configuration setting to false. If you're here
6164 because you want to use rollback and it's disabled, you can
6164 because you want to use rollback and it's disabled, you can
6165 re-enable the command by setting ``ui.rollback`` to true.
6165 re-enable the command by setting ``ui.rollback`` to true.
6166
6166
6167 This command is not intended for use on public repositories. Once
6167 This command is not intended for use on public repositories. Once
6168 changes are visible for pull by other users, rolling a transaction
6168 changes are visible for pull by other users, rolling a transaction
6169 back locally is ineffective (someone else may already have pulled
6169 back locally is ineffective (someone else may already have pulled
6170 the changes). Furthermore, a race is possible with readers of the
6170 the changes). Furthermore, a race is possible with readers of the
6171 repository; for example an in-progress pull from the repository
6171 repository; for example an in-progress pull from the repository
6172 may fail if a rollback is performed.
6172 may fail if a rollback is performed.
6173
6173
6174 Returns 0 on success, 1 if no rollback data is available.
6174 Returns 0 on success, 1 if no rollback data is available.
6175 """
6175 """
6176 if not ui.configbool(b'ui', b'rollback'):
6176 if not ui.configbool(b'ui', b'rollback'):
6177 raise error.Abort(
6177 raise error.Abort(
6178 _(b'rollback is disabled because it is unsafe'),
6178 _(b'rollback is disabled because it is unsafe'),
6179 hint=b'see `hg help -v rollback` for information',
6179 hint=b'see `hg help -v rollback` for information',
6180 )
6180 )
6181 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6181 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6182
6182
6183
6183
6184 @command(
6184 @command(
6185 b'root',
6185 b'root',
6186 [] + formatteropts,
6186 [] + formatteropts,
6187 intents={INTENT_READONLY},
6187 intents={INTENT_READONLY},
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6189 )
6189 )
6190 def root(ui, repo, **opts):
6190 def root(ui, repo, **opts):
6191 """print the root (top) of the current working directory
6191 """print the root (top) of the current working directory
6192
6192
6193 Print the root directory of the current repository.
6193 Print the root directory of the current repository.
6194
6194
6195 .. container:: verbose
6195 .. container:: verbose
6196
6196
6197 Template:
6197 Template:
6198
6198
6199 The following keywords are supported in addition to the common template
6199 The following keywords are supported in addition to the common template
6200 keywords and functions. See also :hg:`help templates`.
6200 keywords and functions. See also :hg:`help templates`.
6201
6201
6202 :hgpath: String. Path to the .hg directory.
6202 :hgpath: String. Path to the .hg directory.
6203 :storepath: String. Path to the directory holding versioned data.
6203 :storepath: String. Path to the directory holding versioned data.
6204
6204
6205 Returns 0 on success.
6205 Returns 0 on success.
6206 """
6206 """
6207 opts = pycompat.byteskwargs(opts)
6207 opts = pycompat.byteskwargs(opts)
6208 with ui.formatter(b'root', opts) as fm:
6208 with ui.formatter(b'root', opts) as fm:
6209 fm.startitem()
6209 fm.startitem()
6210 fm.write(b'reporoot', b'%s\n', repo.root)
6210 fm.write(b'reporoot', b'%s\n', repo.root)
6211 fm.data(hgpath=repo.path, storepath=repo.spath)
6211 fm.data(hgpath=repo.path, storepath=repo.spath)
6212
6212
6213
6213
6214 @command(
6214 @command(
6215 b'serve',
6215 b'serve',
6216 [
6216 [
6217 (
6217 (
6218 b'A',
6218 b'A',
6219 b'accesslog',
6219 b'accesslog',
6220 b'',
6220 b'',
6221 _(b'name of access log file to write to'),
6221 _(b'name of access log file to write to'),
6222 _(b'FILE'),
6222 _(b'FILE'),
6223 ),
6223 ),
6224 (b'd', b'daemon', None, _(b'run server in background')),
6224 (b'd', b'daemon', None, _(b'run server in background')),
6225 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6225 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6226 (
6226 (
6227 b'E',
6227 b'E',
6228 b'errorlog',
6228 b'errorlog',
6229 b'',
6229 b'',
6230 _(b'name of error log file to write to'),
6230 _(b'name of error log file to write to'),
6231 _(b'FILE'),
6231 _(b'FILE'),
6232 ),
6232 ),
6233 # use string type, then we can check if something was passed
6233 # use string type, then we can check if something was passed
6234 (
6234 (
6235 b'p',
6235 b'p',
6236 b'port',
6236 b'port',
6237 b'',
6237 b'',
6238 _(b'port to listen on (default: 8000)'),
6238 _(b'port to listen on (default: 8000)'),
6239 _(b'PORT'),
6239 _(b'PORT'),
6240 ),
6240 ),
6241 (
6241 (
6242 b'a',
6242 b'a',
6243 b'address',
6243 b'address',
6244 b'',
6244 b'',
6245 _(b'address to listen on (default: all interfaces)'),
6245 _(b'address to listen on (default: all interfaces)'),
6246 _(b'ADDR'),
6246 _(b'ADDR'),
6247 ),
6247 ),
6248 (
6248 (
6249 b'',
6249 b'',
6250 b'prefix',
6250 b'prefix',
6251 b'',
6251 b'',
6252 _(b'prefix path to serve from (default: server root)'),
6252 _(b'prefix path to serve from (default: server root)'),
6253 _(b'PREFIX'),
6253 _(b'PREFIX'),
6254 ),
6254 ),
6255 (
6255 (
6256 b'n',
6256 b'n',
6257 b'name',
6257 b'name',
6258 b'',
6258 b'',
6259 _(b'name to show in web pages (default: working directory)'),
6259 _(b'name to show in web pages (default: working directory)'),
6260 _(b'NAME'),
6260 _(b'NAME'),
6261 ),
6261 ),
6262 (
6262 (
6263 b'',
6263 b'',
6264 b'web-conf',
6264 b'web-conf',
6265 b'',
6265 b'',
6266 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6266 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6267 _(b'FILE'),
6267 _(b'FILE'),
6268 ),
6268 ),
6269 (
6269 (
6270 b'',
6270 b'',
6271 b'webdir-conf',
6271 b'webdir-conf',
6272 b'',
6272 b'',
6273 _(b'name of the hgweb config file (DEPRECATED)'),
6273 _(b'name of the hgweb config file (DEPRECATED)'),
6274 _(b'FILE'),
6274 _(b'FILE'),
6275 ),
6275 ),
6276 (
6276 (
6277 b'',
6277 b'',
6278 b'pid-file',
6278 b'pid-file',
6279 b'',
6279 b'',
6280 _(b'name of file to write process ID to'),
6280 _(b'name of file to write process ID to'),
6281 _(b'FILE'),
6281 _(b'FILE'),
6282 ),
6282 ),
6283 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6283 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6284 (
6284 (
6285 b'',
6285 b'',
6286 b'cmdserver',
6286 b'cmdserver',
6287 b'',
6287 b'',
6288 _(b'for remote clients (ADVANCED)'),
6288 _(b'for remote clients (ADVANCED)'),
6289 _(b'MODE'),
6289 _(b'MODE'),
6290 ),
6290 ),
6291 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6291 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6292 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6292 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6293 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6293 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6294 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6294 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6295 (b'', b'print-url', None, _(b'start and print only the URL')),
6295 (b'', b'print-url', None, _(b'start and print only the URL')),
6296 ]
6296 ]
6297 + subrepoopts,
6297 + subrepoopts,
6298 _(b'[OPTION]...'),
6298 _(b'[OPTION]...'),
6299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6300 helpbasic=True,
6300 helpbasic=True,
6301 optionalrepo=True,
6301 optionalrepo=True,
6302 )
6302 )
6303 def serve(ui, repo, **opts):
6303 def serve(ui, repo, **opts):
6304 """start stand-alone webserver
6304 """start stand-alone webserver
6305
6305
6306 Start a local HTTP repository browser and pull server. You can use
6306 Start a local HTTP repository browser and pull server. You can use
6307 this for ad-hoc sharing and browsing of repositories. It is
6307 this for ad-hoc sharing and browsing of repositories. It is
6308 recommended to use a real web server to serve a repository for
6308 recommended to use a real web server to serve a repository for
6309 longer periods of time.
6309 longer periods of time.
6310
6310
6311 Please note that the server does not implement access control.
6311 Please note that the server does not implement access control.
6312 This means that, by default, anybody can read from the server and
6312 This means that, by default, anybody can read from the server and
6313 nobody can write to it by default. Set the ``web.allow-push``
6313 nobody can write to it by default. Set the ``web.allow-push``
6314 option to ``*`` to allow everybody to push to the server. You
6314 option to ``*`` to allow everybody to push to the server. You
6315 should use a real web server if you need to authenticate users.
6315 should use a real web server if you need to authenticate users.
6316
6316
6317 By default, the server logs accesses to stdout and errors to
6317 By default, the server logs accesses to stdout and errors to
6318 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6318 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6319 files.
6319 files.
6320
6320
6321 To have the server choose a free port number to listen on, specify
6321 To have the server choose a free port number to listen on, specify
6322 a port number of 0; in this case, the server will print the port
6322 a port number of 0; in this case, the server will print the port
6323 number it uses.
6323 number it uses.
6324
6324
6325 Returns 0 on success.
6325 Returns 0 on success.
6326 """
6326 """
6327
6327
6328 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6328 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6329 opts = pycompat.byteskwargs(opts)
6329 opts = pycompat.byteskwargs(opts)
6330 if opts[b"print_url"] and ui.verbose:
6330 if opts[b"print_url"] and ui.verbose:
6331 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6331 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6332
6332
6333 if opts[b"stdio"]:
6333 if opts[b"stdio"]:
6334 if repo is None:
6334 if repo is None:
6335 raise error.RepoError(
6335 raise error.RepoError(
6336 _(b"there is no Mercurial repository here (.hg not found)")
6336 _(b"there is no Mercurial repository here (.hg not found)")
6337 )
6337 )
6338 s = wireprotoserver.sshserver(ui, repo)
6338 s = wireprotoserver.sshserver(ui, repo)
6339 s.serve_forever()
6339 s.serve_forever()
6340
6340
6341 service = server.createservice(ui, repo, opts)
6341 service = server.createservice(ui, repo, opts)
6342 return server.runservice(opts, initfn=service.init, runfn=service.run)
6342 return server.runservice(opts, initfn=service.init, runfn=service.run)
6343
6343
6344
6344
6345 @command(
6345 @command(
6346 b'shelve',
6346 b'shelve',
6347 [
6347 [
6348 (
6348 (
6349 b'A',
6349 b'A',
6350 b'addremove',
6350 b'addremove',
6351 None,
6351 None,
6352 _(b'mark new/missing files as added/removed before shelving'),
6352 _(b'mark new/missing files as added/removed before shelving'),
6353 ),
6353 ),
6354 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6354 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6355 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6355 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6356 (
6356 (
6357 b'',
6357 b'',
6358 b'date',
6358 b'date',
6359 b'',
6359 b'',
6360 _(b'shelve with the specified commit date'),
6360 _(b'shelve with the specified commit date'),
6361 _(b'DATE'),
6361 _(b'DATE'),
6362 ),
6362 ),
6363 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6363 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6364 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6364 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6365 (
6365 (
6366 b'k',
6366 b'k',
6367 b'keep',
6367 b'keep',
6368 False,
6368 False,
6369 _(b'shelve, but keep changes in the working directory'),
6369 _(b'shelve, but keep changes in the working directory'),
6370 ),
6370 ),
6371 (b'l', b'list', None, _(b'list current shelves')),
6371 (b'l', b'list', None, _(b'list current shelves')),
6372 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6372 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6373 (
6373 (
6374 b'n',
6374 b'n',
6375 b'name',
6375 b'name',
6376 b'',
6376 b'',
6377 _(b'use the given name for the shelved commit'),
6377 _(b'use the given name for the shelved commit'),
6378 _(b'NAME'),
6378 _(b'NAME'),
6379 ),
6379 ),
6380 (
6380 (
6381 b'p',
6381 b'p',
6382 b'patch',
6382 b'patch',
6383 None,
6383 None,
6384 _(
6384 _(
6385 b'output patches for changes (provide the names of the shelved '
6385 b'output patches for changes (provide the names of the shelved '
6386 b'changes as positional arguments)'
6386 b'changes as positional arguments)'
6387 ),
6387 ),
6388 ),
6388 ),
6389 (b'i', b'interactive', None, _(b'interactive mode')),
6389 (b'i', b'interactive', None, _(b'interactive mode')),
6390 (
6390 (
6391 b'',
6391 b'',
6392 b'stat',
6392 b'stat',
6393 None,
6393 None,
6394 _(
6394 _(
6395 b'output diffstat-style summary of changes (provide the names of '
6395 b'output diffstat-style summary of changes (provide the names of '
6396 b'the shelved changes as positional arguments)'
6396 b'the shelved changes as positional arguments)'
6397 ),
6397 ),
6398 ),
6398 ),
6399 ]
6399 ]
6400 + cmdutil.walkopts,
6400 + cmdutil.walkopts,
6401 _(b'hg shelve [OPTION]... [FILE]...'),
6401 _(b'hg shelve [OPTION]... [FILE]...'),
6402 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6402 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6403 )
6403 )
6404 def shelve(ui, repo, *pats, **opts):
6404 def shelve(ui, repo, *pats, **opts):
6405 '''save and set aside changes from the working directory
6405 '''save and set aside changes from the working directory
6406
6406
6407 Shelving takes files that "hg status" reports as not clean, saves
6407 Shelving takes files that "hg status" reports as not clean, saves
6408 the modifications to a bundle (a shelved change), and reverts the
6408 the modifications to a bundle (a shelved change), and reverts the
6409 files so that their state in the working directory becomes clean.
6409 files so that their state in the working directory becomes clean.
6410
6410
6411 To restore these changes to the working directory, using "hg
6411 To restore these changes to the working directory, using "hg
6412 unshelve"; this will work even if you switch to a different
6412 unshelve"; this will work even if you switch to a different
6413 commit.
6413 commit.
6414
6414
6415 When no files are specified, "hg shelve" saves all not-clean
6415 When no files are specified, "hg shelve" saves all not-clean
6416 files. If specific files or directories are named, only changes to
6416 files. If specific files or directories are named, only changes to
6417 those files are shelved.
6417 those files are shelved.
6418
6418
6419 In bare shelve (when no files are specified, without interactive,
6419 In bare shelve (when no files are specified, without interactive,
6420 include and exclude option), shelving remembers information if the
6420 include and exclude option), shelving remembers information if the
6421 working directory was on newly created branch, in other words working
6421 working directory was on newly created branch, in other words working
6422 directory was on different branch than its first parent. In this
6422 directory was on different branch than its first parent. In this
6423 situation unshelving restores branch information to the working directory.
6423 situation unshelving restores branch information to the working directory.
6424
6424
6425 Each shelved change has a name that makes it easier to find later.
6425 Each shelved change has a name that makes it easier to find later.
6426 The name of a shelved change defaults to being based on the active
6426 The name of a shelved change defaults to being based on the active
6427 bookmark, or if there is no active bookmark, the current named
6427 bookmark, or if there is no active bookmark, the current named
6428 branch. To specify a different name, use ``--name``.
6428 branch. To specify a different name, use ``--name``.
6429
6429
6430 To see a list of existing shelved changes, use the ``--list``
6430 To see a list of existing shelved changes, use the ``--list``
6431 option. For each shelved change, this will print its name, age,
6431 option. For each shelved change, this will print its name, age,
6432 and description; use ``--patch`` or ``--stat`` for more details.
6432 and description; use ``--patch`` or ``--stat`` for more details.
6433
6433
6434 To delete specific shelved changes, use ``--delete``. To delete
6434 To delete specific shelved changes, use ``--delete``. To delete
6435 all shelved changes, use ``--cleanup``.
6435 all shelved changes, use ``--cleanup``.
6436 '''
6436 '''
6437 opts = pycompat.byteskwargs(opts)
6437 opts = pycompat.byteskwargs(opts)
6438 allowables = [
6438 allowables = [
6439 (b'addremove', {b'create'}), # 'create' is pseudo action
6439 (b'addremove', {b'create'}), # 'create' is pseudo action
6440 (b'unknown', {b'create'}),
6440 (b'unknown', {b'create'}),
6441 (b'cleanup', {b'cleanup'}),
6441 (b'cleanup', {b'cleanup'}),
6442 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6442 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6443 (b'delete', {b'delete'}),
6443 (b'delete', {b'delete'}),
6444 (b'edit', {b'create'}),
6444 (b'edit', {b'create'}),
6445 (b'keep', {b'create'}),
6445 (b'keep', {b'create'}),
6446 (b'list', {b'list'}),
6446 (b'list', {b'list'}),
6447 (b'message', {b'create'}),
6447 (b'message', {b'create'}),
6448 (b'name', {b'create'}),
6448 (b'name', {b'create'}),
6449 (b'patch', {b'patch', b'list'}),
6449 (b'patch', {b'patch', b'list'}),
6450 (b'stat', {b'stat', b'list'}),
6450 (b'stat', {b'stat', b'list'}),
6451 ]
6451 ]
6452
6452
6453 def checkopt(opt):
6453 def checkopt(opt):
6454 if opts.get(opt):
6454 if opts.get(opt):
6455 for i, allowable in allowables:
6455 for i, allowable in allowables:
6456 if opts[i] and opt not in allowable:
6456 if opts[i] and opt not in allowable:
6457 raise error.Abort(
6457 raise error.Abort(
6458 _(
6458 _(
6459 b"options '--%s' and '--%s' may not be "
6459 b"options '--%s' and '--%s' may not be "
6460 b"used together"
6460 b"used together"
6461 )
6461 )
6462 % (opt, i)
6462 % (opt, i)
6463 )
6463 )
6464 return True
6464 return True
6465
6465
6466 if checkopt(b'cleanup'):
6466 if checkopt(b'cleanup'):
6467 if pats:
6467 if pats:
6468 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6468 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6469 return shelvemod.cleanupcmd(ui, repo)
6469 return shelvemod.cleanupcmd(ui, repo)
6470 elif checkopt(b'delete'):
6470 elif checkopt(b'delete'):
6471 return shelvemod.deletecmd(ui, repo, pats)
6471 return shelvemod.deletecmd(ui, repo, pats)
6472 elif checkopt(b'list'):
6472 elif checkopt(b'list'):
6473 return shelvemod.listcmd(ui, repo, pats, opts)
6473 return shelvemod.listcmd(ui, repo, pats, opts)
6474 elif checkopt(b'patch') or checkopt(b'stat'):
6474 elif checkopt(b'patch') or checkopt(b'stat'):
6475 return shelvemod.patchcmds(ui, repo, pats, opts)
6475 return shelvemod.patchcmds(ui, repo, pats, opts)
6476 else:
6476 else:
6477 return shelvemod.createcmd(ui, repo, pats, opts)
6477 return shelvemod.createcmd(ui, repo, pats, opts)
6478
6478
6479
6479
6480 _NOTTERSE = b'nothing'
6480 _NOTTERSE = b'nothing'
6481
6481
6482
6482
6483 @command(
6483 @command(
6484 b'status|st',
6484 b'status|st',
6485 [
6485 [
6486 (b'A', b'all', None, _(b'show status of all files')),
6486 (b'A', b'all', None, _(b'show status of all files')),
6487 (b'm', b'modified', None, _(b'show only modified files')),
6487 (b'm', b'modified', None, _(b'show only modified files')),
6488 (b'a', b'added', None, _(b'show only added files')),
6488 (b'a', b'added', None, _(b'show only added files')),
6489 (b'r', b'removed', None, _(b'show only removed files')),
6489 (b'r', b'removed', None, _(b'show only removed files')),
6490 (b'd', b'deleted', None, _(b'show only missing files')),
6490 (b'd', b'deleted', None, _(b'show only missing files')),
6491 (b'c', b'clean', None, _(b'show only files without changes')),
6491 (b'c', b'clean', None, _(b'show only files without changes')),
6492 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6492 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6493 (b'i', b'ignored', None, _(b'show only ignored files')),
6493 (b'i', b'ignored', None, _(b'show only ignored files')),
6494 (b'n', b'no-status', None, _(b'hide status prefix')),
6494 (b'n', b'no-status', None, _(b'hide status prefix')),
6495 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6495 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6496 (
6496 (
6497 b'C',
6497 b'C',
6498 b'copies',
6498 b'copies',
6499 None,
6499 None,
6500 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6500 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6501 ),
6501 ),
6502 (
6502 (
6503 b'0',
6503 b'0',
6504 b'print0',
6504 b'print0',
6505 None,
6505 None,
6506 _(b'end filenames with NUL, for use with xargs'),
6506 _(b'end filenames with NUL, for use with xargs'),
6507 ),
6507 ),
6508 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6508 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6509 (
6509 (
6510 b'',
6510 b'',
6511 b'change',
6511 b'change',
6512 b'',
6512 b'',
6513 _(b'list the changed files of a revision'),
6513 _(b'list the changed files of a revision'),
6514 _(b'REV'),
6514 _(b'REV'),
6515 ),
6515 ),
6516 ]
6516 ]
6517 + walkopts
6517 + walkopts
6518 + subrepoopts
6518 + subrepoopts
6519 + formatteropts,
6519 + formatteropts,
6520 _(b'[OPTION]... [FILE]...'),
6520 _(b'[OPTION]... [FILE]...'),
6521 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6521 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6522 helpbasic=True,
6522 helpbasic=True,
6523 inferrepo=True,
6523 inferrepo=True,
6524 intents={INTENT_READONLY},
6524 intents={INTENT_READONLY},
6525 )
6525 )
6526 def status(ui, repo, *pats, **opts):
6526 def status(ui, repo, *pats, **opts):
6527 """show changed files in the working directory
6527 """show changed files in the working directory
6528
6528
6529 Show status of files in the repository. If names are given, only
6529 Show status of files in the repository. If names are given, only
6530 files that match are shown. Files that are clean or ignored or
6530 files that match are shown. Files that are clean or ignored or
6531 the source of a copy/move operation, are not listed unless
6531 the source of a copy/move operation, are not listed unless
6532 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6532 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6533 Unless options described with "show only ..." are given, the
6533 Unless options described with "show only ..." are given, the
6534 options -mardu are used.
6534 options -mardu are used.
6535
6535
6536 Option -q/--quiet hides untracked (unknown and ignored) files
6536 Option -q/--quiet hides untracked (unknown and ignored) files
6537 unless explicitly requested with -u/--unknown or -i/--ignored.
6537 unless explicitly requested with -u/--unknown or -i/--ignored.
6538
6538
6539 .. note::
6539 .. note::
6540
6540
6541 :hg:`status` may appear to disagree with diff if permissions have
6541 :hg:`status` may appear to disagree with diff if permissions have
6542 changed or a merge has occurred. The standard diff format does
6542 changed or a merge has occurred. The standard diff format does
6543 not report permission changes and diff only reports changes
6543 not report permission changes and diff only reports changes
6544 relative to one merge parent.
6544 relative to one merge parent.
6545
6545
6546 If one revision is given, it is used as the base revision.
6546 If one revision is given, it is used as the base revision.
6547 If two revisions are given, the differences between them are
6547 If two revisions are given, the differences between them are
6548 shown. The --change option can also be used as a shortcut to list
6548 shown. The --change option can also be used as a shortcut to list
6549 the changed files of a revision from its first parent.
6549 the changed files of a revision from its first parent.
6550
6550
6551 The codes used to show the status of files are::
6551 The codes used to show the status of files are::
6552
6552
6553 M = modified
6553 M = modified
6554 A = added
6554 A = added
6555 R = removed
6555 R = removed
6556 C = clean
6556 C = clean
6557 ! = missing (deleted by non-hg command, but still tracked)
6557 ! = missing (deleted by non-hg command, but still tracked)
6558 ? = not tracked
6558 ? = not tracked
6559 I = ignored
6559 I = ignored
6560 = origin of the previous file (with --copies)
6560 = origin of the previous file (with --copies)
6561
6561
6562 .. container:: verbose
6562 .. container:: verbose
6563
6563
6564 The -t/--terse option abbreviates the output by showing only the directory
6564 The -t/--terse option abbreviates the output by showing only the directory
6565 name if all the files in it share the same status. The option takes an
6565 name if all the files in it share the same status. The option takes an
6566 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6566 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6567 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6567 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6568 for 'ignored' and 'c' for clean.
6568 for 'ignored' and 'c' for clean.
6569
6569
6570 It abbreviates only those statuses which are passed. Note that clean and
6570 It abbreviates only those statuses which are passed. Note that clean and
6571 ignored files are not displayed with '--terse ic' unless the -c/--clean
6571 ignored files are not displayed with '--terse ic' unless the -c/--clean
6572 and -i/--ignored options are also used.
6572 and -i/--ignored options are also used.
6573
6573
6574 The -v/--verbose option shows information when the repository is in an
6574 The -v/--verbose option shows information when the repository is in an
6575 unfinished merge, shelve, rebase state etc. You can have this behavior
6575 unfinished merge, shelve, rebase state etc. You can have this behavior
6576 turned on by default by enabling the ``commands.status.verbose`` option.
6576 turned on by default by enabling the ``commands.status.verbose`` option.
6577
6577
6578 You can skip displaying some of these states by setting
6578 You can skip displaying some of these states by setting
6579 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6579 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6580 'histedit', 'merge', 'rebase', or 'unshelve'.
6580 'histedit', 'merge', 'rebase', or 'unshelve'.
6581
6581
6582 Template:
6582 Template:
6583
6583
6584 The following keywords are supported in addition to the common template
6584 The following keywords are supported in addition to the common template
6585 keywords and functions. See also :hg:`help templates`.
6585 keywords and functions. See also :hg:`help templates`.
6586
6586
6587 :path: String. Repository-absolute path of the file.
6587 :path: String. Repository-absolute path of the file.
6588 :source: String. Repository-absolute path of the file originated from.
6588 :source: String. Repository-absolute path of the file originated from.
6589 Available if ``--copies`` is specified.
6589 Available if ``--copies`` is specified.
6590 :status: String. Character denoting file's status.
6590 :status: String. Character denoting file's status.
6591
6591
6592 Examples:
6592 Examples:
6593
6593
6594 - show changes in the working directory relative to a
6594 - show changes in the working directory relative to a
6595 changeset::
6595 changeset::
6596
6596
6597 hg status --rev 9353
6597 hg status --rev 9353
6598
6598
6599 - show changes in the working directory relative to the
6599 - show changes in the working directory relative to the
6600 current directory (see :hg:`help patterns` for more information)::
6600 current directory (see :hg:`help patterns` for more information)::
6601
6601
6602 hg status re:
6602 hg status re:
6603
6603
6604 - show all changes including copies in an existing changeset::
6604 - show all changes including copies in an existing changeset::
6605
6605
6606 hg status --copies --change 9353
6606 hg status --copies --change 9353
6607
6607
6608 - get a NUL separated list of added files, suitable for xargs::
6608 - get a NUL separated list of added files, suitable for xargs::
6609
6609
6610 hg status -an0
6610 hg status -an0
6611
6611
6612 - show more information about the repository status, abbreviating
6612 - show more information about the repository status, abbreviating
6613 added, removed, modified, deleted, and untracked paths::
6613 added, removed, modified, deleted, and untracked paths::
6614
6614
6615 hg status -v -t mardu
6615 hg status -v -t mardu
6616
6616
6617 Returns 0 on success.
6617 Returns 0 on success.
6618
6618
6619 """
6619 """
6620
6620
6621 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6621 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6622 opts = pycompat.byteskwargs(opts)
6622 opts = pycompat.byteskwargs(opts)
6623 revs = opts.get(b'rev')
6623 revs = opts.get(b'rev')
6624 change = opts.get(b'change')
6624 change = opts.get(b'change')
6625 terse = opts.get(b'terse')
6625 terse = opts.get(b'terse')
6626 if terse is _NOTTERSE:
6626 if terse is _NOTTERSE:
6627 if revs:
6627 if revs:
6628 terse = b''
6628 terse = b''
6629 else:
6629 else:
6630 terse = ui.config(b'commands', b'status.terse')
6630 terse = ui.config(b'commands', b'status.terse')
6631
6631
6632 if revs and terse:
6632 if revs and terse:
6633 msg = _(b'cannot use --terse with --rev')
6633 msg = _(b'cannot use --terse with --rev')
6634 raise error.Abort(msg)
6634 raise error.Abort(msg)
6635 elif change:
6635 elif change:
6636 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6636 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6637 ctx2 = scmutil.revsingle(repo, change, None)
6637 ctx2 = scmutil.revsingle(repo, change, None)
6638 ctx1 = ctx2.p1()
6638 ctx1 = ctx2.p1()
6639 else:
6639 else:
6640 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6640 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6641 ctx1, ctx2 = scmutil.revpair(repo, revs)
6641 ctx1, ctx2 = scmutil.revpair(repo, revs)
6642
6642
6643 forcerelativevalue = None
6643 forcerelativevalue = None
6644 if ui.hasconfig(b'commands', b'status.relative'):
6644 if ui.hasconfig(b'commands', b'status.relative'):
6645 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6645 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6646 uipathfn = scmutil.getuipathfn(
6646 uipathfn = scmutil.getuipathfn(
6647 repo,
6647 repo,
6648 legacyrelativevalue=bool(pats),
6648 legacyrelativevalue=bool(pats),
6649 forcerelativevalue=forcerelativevalue,
6649 forcerelativevalue=forcerelativevalue,
6650 )
6650 )
6651
6651
6652 if opts.get(b'print0'):
6652 if opts.get(b'print0'):
6653 end = b'\0'
6653 end = b'\0'
6654 else:
6654 else:
6655 end = b'\n'
6655 end = b'\n'
6656 states = b'modified added removed deleted unknown ignored clean'.split()
6656 states = b'modified added removed deleted unknown ignored clean'.split()
6657 show = [k for k in states if opts.get(k)]
6657 show = [k for k in states if opts.get(k)]
6658 if opts.get(b'all'):
6658 if opts.get(b'all'):
6659 show += ui.quiet and (states[:4] + [b'clean']) or states
6659 show += ui.quiet and (states[:4] + [b'clean']) or states
6660
6660
6661 if not show:
6661 if not show:
6662 if ui.quiet:
6662 if ui.quiet:
6663 show = states[:4]
6663 show = states[:4]
6664 else:
6664 else:
6665 show = states[:5]
6665 show = states[:5]
6666
6666
6667 m = scmutil.match(ctx2, pats, opts)
6667 m = scmutil.match(ctx2, pats, opts)
6668 if terse:
6668 if terse:
6669 # we need to compute clean and unknown to terse
6669 # we need to compute clean and unknown to terse
6670 stat = repo.status(
6670 stat = repo.status(
6671 ctx1.node(),
6671 ctx1.node(),
6672 ctx2.node(),
6672 ctx2.node(),
6673 m,
6673 m,
6674 b'ignored' in show or b'i' in terse,
6674 b'ignored' in show or b'i' in terse,
6675 clean=True,
6675 clean=True,
6676 unknown=True,
6676 unknown=True,
6677 listsubrepos=opts.get(b'subrepos'),
6677 listsubrepos=opts.get(b'subrepos'),
6678 )
6678 )
6679
6679
6680 stat = cmdutil.tersedir(stat, terse)
6680 stat = cmdutil.tersedir(stat, terse)
6681 else:
6681 else:
6682 stat = repo.status(
6682 stat = repo.status(
6683 ctx1.node(),
6683 ctx1.node(),
6684 ctx2.node(),
6684 ctx2.node(),
6685 m,
6685 m,
6686 b'ignored' in show,
6686 b'ignored' in show,
6687 b'clean' in show,
6687 b'clean' in show,
6688 b'unknown' in show,
6688 b'unknown' in show,
6689 opts.get(b'subrepos'),
6689 opts.get(b'subrepos'),
6690 )
6690 )
6691
6691
6692 changestates = zip(
6692 changestates = zip(
6693 states,
6693 states,
6694 pycompat.iterbytestr(b'MAR!?IC'),
6694 pycompat.iterbytestr(b'MAR!?IC'),
6695 [getattr(stat, s.decode('utf8')) for s in states],
6695 [getattr(stat, s.decode('utf8')) for s in states],
6696 )
6696 )
6697
6697
6698 copy = {}
6698 copy = {}
6699 if (
6699 if (
6700 opts.get(b'all')
6700 opts.get(b'all')
6701 or opts.get(b'copies')
6701 or opts.get(b'copies')
6702 or ui.configbool(b'ui', b'statuscopies')
6702 or ui.configbool(b'ui', b'statuscopies')
6703 ) and not opts.get(b'no_status'):
6703 ) and not opts.get(b'no_status'):
6704 copy = copies.pathcopies(ctx1, ctx2, m)
6704 copy = copies.pathcopies(ctx1, ctx2, m)
6705
6705
6706 morestatus = None
6706 morestatus = None
6707 if (
6707 if (
6708 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6708 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6709 ) and not ui.plain():
6709 ) and not ui.plain():
6710 morestatus = cmdutil.readmorestatus(repo)
6710 morestatus = cmdutil.readmorestatus(repo)
6711
6711
6712 ui.pager(b'status')
6712 ui.pager(b'status')
6713 fm = ui.formatter(b'status', opts)
6713 fm = ui.formatter(b'status', opts)
6714 fmt = b'%s' + end
6714 fmt = b'%s' + end
6715 showchar = not opts.get(b'no_status')
6715 showchar = not opts.get(b'no_status')
6716
6716
6717 for state, char, files in changestates:
6717 for state, char, files in changestates:
6718 if state in show:
6718 if state in show:
6719 label = b'status.' + state
6719 label = b'status.' + state
6720 for f in files:
6720 for f in files:
6721 fm.startitem()
6721 fm.startitem()
6722 fm.context(ctx=ctx2)
6722 fm.context(ctx=ctx2)
6723 fm.data(itemtype=b'file', path=f)
6723 fm.data(itemtype=b'file', path=f)
6724 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6724 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6725 fm.plain(fmt % uipathfn(f), label=label)
6725 fm.plain(fmt % uipathfn(f), label=label)
6726 if f in copy:
6726 if f in copy:
6727 fm.data(source=copy[f])
6727 fm.data(source=copy[f])
6728 fm.plain(
6728 fm.plain(
6729 (b' %s' + end) % uipathfn(copy[f]),
6729 (b' %s' + end) % uipathfn(copy[f]),
6730 label=b'status.copied',
6730 label=b'status.copied',
6731 )
6731 )
6732 if morestatus:
6732 if morestatus:
6733 morestatus.formatfile(f, fm)
6733 morestatus.formatfile(f, fm)
6734
6734
6735 if morestatus:
6735 if morestatus:
6736 morestatus.formatfooter(fm)
6736 morestatus.formatfooter(fm)
6737 fm.end()
6737 fm.end()
6738
6738
6739
6739
6740 @command(
6740 @command(
6741 b'summary|sum',
6741 b'summary|sum',
6742 [(b'', b'remote', None, _(b'check for push and pull'))],
6742 [(b'', b'remote', None, _(b'check for push and pull'))],
6743 b'[--remote]',
6743 b'[--remote]',
6744 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6744 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6745 helpbasic=True,
6745 helpbasic=True,
6746 intents={INTENT_READONLY},
6746 intents={INTENT_READONLY},
6747 )
6747 )
6748 def summary(ui, repo, **opts):
6748 def summary(ui, repo, **opts):
6749 """summarize working directory state
6749 """summarize working directory state
6750
6750
6751 This generates a brief summary of the working directory state,
6751 This generates a brief summary of the working directory state,
6752 including parents, branch, commit status, phase and available updates.
6752 including parents, branch, commit status, phase and available updates.
6753
6753
6754 With the --remote option, this will check the default paths for
6754 With the --remote option, this will check the default paths for
6755 incoming and outgoing changes. This can be time-consuming.
6755 incoming and outgoing changes. This can be time-consuming.
6756
6756
6757 Returns 0 on success.
6757 Returns 0 on success.
6758 """
6758 """
6759
6759
6760 opts = pycompat.byteskwargs(opts)
6760 opts = pycompat.byteskwargs(opts)
6761 ui.pager(b'summary')
6761 ui.pager(b'summary')
6762 ctx = repo[None]
6762 ctx = repo[None]
6763 parents = ctx.parents()
6763 parents = ctx.parents()
6764 pnode = parents[0].node()
6764 pnode = parents[0].node()
6765 marks = []
6765 marks = []
6766
6766
6767 try:
6767 try:
6768 ms = mergestatemod.mergestate.read(repo)
6768 ms = mergestatemod.mergestate.read(repo)
6769 except error.UnsupportedMergeRecords as e:
6769 except error.UnsupportedMergeRecords as e:
6770 s = b' '.join(e.recordtypes)
6770 s = b' '.join(e.recordtypes)
6771 ui.warn(
6771 ui.warn(
6772 _(b'warning: merge state has unsupported record types: %s\n') % s
6772 _(b'warning: merge state has unsupported record types: %s\n') % s
6773 )
6773 )
6774 unresolved = []
6774 unresolved = []
6775 else:
6775 else:
6776 unresolved = list(ms.unresolved())
6776 unresolved = list(ms.unresolved())
6777
6777
6778 for p in parents:
6778 for p in parents:
6779 # label with log.changeset (instead of log.parent) since this
6779 # label with log.changeset (instead of log.parent) since this
6780 # shows a working directory parent *changeset*:
6780 # shows a working directory parent *changeset*:
6781 # i18n: column positioning for "hg summary"
6781 # i18n: column positioning for "hg summary"
6782 ui.write(
6782 ui.write(
6783 _(b'parent: %d:%s ') % (p.rev(), p),
6783 _(b'parent: %d:%s ') % (p.rev(), p),
6784 label=logcmdutil.changesetlabels(p),
6784 label=logcmdutil.changesetlabels(p),
6785 )
6785 )
6786 ui.write(b' '.join(p.tags()), label=b'log.tag')
6786 ui.write(b' '.join(p.tags()), label=b'log.tag')
6787 if p.bookmarks():
6787 if p.bookmarks():
6788 marks.extend(p.bookmarks())
6788 marks.extend(p.bookmarks())
6789 if p.rev() == -1:
6789 if p.rev() == -1:
6790 if not len(repo):
6790 if not len(repo):
6791 ui.write(_(b' (empty repository)'))
6791 ui.write(_(b' (empty repository)'))
6792 else:
6792 else:
6793 ui.write(_(b' (no revision checked out)'))
6793 ui.write(_(b' (no revision checked out)'))
6794 if p.obsolete():
6794 if p.obsolete():
6795 ui.write(_(b' (obsolete)'))
6795 ui.write(_(b' (obsolete)'))
6796 if p.isunstable():
6796 if p.isunstable():
6797 instabilities = (
6797 instabilities = (
6798 ui.label(instability, b'trouble.%s' % instability)
6798 ui.label(instability, b'trouble.%s' % instability)
6799 for instability in p.instabilities()
6799 for instability in p.instabilities()
6800 )
6800 )
6801 ui.write(b' (' + b', '.join(instabilities) + b')')
6801 ui.write(b' (' + b', '.join(instabilities) + b')')
6802 ui.write(b'\n')
6802 ui.write(b'\n')
6803 if p.description():
6803 if p.description():
6804 ui.status(
6804 ui.status(
6805 b' ' + p.description().splitlines()[0].strip() + b'\n',
6805 b' ' + p.description().splitlines()[0].strip() + b'\n',
6806 label=b'log.summary',
6806 label=b'log.summary',
6807 )
6807 )
6808
6808
6809 branch = ctx.branch()
6809 branch = ctx.branch()
6810 bheads = repo.branchheads(branch)
6810 bheads = repo.branchheads(branch)
6811 # i18n: column positioning for "hg summary"
6811 # i18n: column positioning for "hg summary"
6812 m = _(b'branch: %s\n') % branch
6812 m = _(b'branch: %s\n') % branch
6813 if branch != b'default':
6813 if branch != b'default':
6814 ui.write(m, label=b'log.branch')
6814 ui.write(m, label=b'log.branch')
6815 else:
6815 else:
6816 ui.status(m, label=b'log.branch')
6816 ui.status(m, label=b'log.branch')
6817
6817
6818 if marks:
6818 if marks:
6819 active = repo._activebookmark
6819 active = repo._activebookmark
6820 # i18n: column positioning for "hg summary"
6820 # i18n: column positioning for "hg summary"
6821 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6821 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6822 if active is not None:
6822 if active is not None:
6823 if active in marks:
6823 if active in marks:
6824 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6824 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6825 marks.remove(active)
6825 marks.remove(active)
6826 else:
6826 else:
6827 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6827 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6828 for m in marks:
6828 for m in marks:
6829 ui.write(b' ' + m, label=b'log.bookmark')
6829 ui.write(b' ' + m, label=b'log.bookmark')
6830 ui.write(b'\n', label=b'log.bookmark')
6830 ui.write(b'\n', label=b'log.bookmark')
6831
6831
6832 status = repo.status(unknown=True)
6832 status = repo.status(unknown=True)
6833
6833
6834 c = repo.dirstate.copies()
6834 c = repo.dirstate.copies()
6835 copied, renamed = [], []
6835 copied, renamed = [], []
6836 for d, s in pycompat.iteritems(c):
6836 for d, s in pycompat.iteritems(c):
6837 if s in status.removed:
6837 if s in status.removed:
6838 status.removed.remove(s)
6838 status.removed.remove(s)
6839 renamed.append(d)
6839 renamed.append(d)
6840 else:
6840 else:
6841 copied.append(d)
6841 copied.append(d)
6842 if d in status.added:
6842 if d in status.added:
6843 status.added.remove(d)
6843 status.added.remove(d)
6844
6844
6845 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6845 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6846
6846
6847 labels = [
6847 labels = [
6848 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6848 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6849 (ui.label(_(b'%d added'), b'status.added'), status.added),
6849 (ui.label(_(b'%d added'), b'status.added'), status.added),
6850 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6850 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6851 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6851 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6852 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6852 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6853 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6853 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6854 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6854 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6855 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6855 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6856 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6856 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6857 ]
6857 ]
6858 t = []
6858 t = []
6859 for l, s in labels:
6859 for l, s in labels:
6860 if s:
6860 if s:
6861 t.append(l % len(s))
6861 t.append(l % len(s))
6862
6862
6863 t = b', '.join(t)
6863 t = b', '.join(t)
6864 cleanworkdir = False
6864 cleanworkdir = False
6865
6865
6866 if repo.vfs.exists(b'graftstate'):
6866 if repo.vfs.exists(b'graftstate'):
6867 t += _(b' (graft in progress)')
6867 t += _(b' (graft in progress)')
6868 if repo.vfs.exists(b'updatestate'):
6868 if repo.vfs.exists(b'updatestate'):
6869 t += _(b' (interrupted update)')
6869 t += _(b' (interrupted update)')
6870 elif len(parents) > 1:
6870 elif len(parents) > 1:
6871 t += _(b' (merge)')
6871 t += _(b' (merge)')
6872 elif branch != parents[0].branch():
6872 elif branch != parents[0].branch():
6873 t += _(b' (new branch)')
6873 t += _(b' (new branch)')
6874 elif parents[0].closesbranch() and pnode in repo.branchheads(
6874 elif parents[0].closesbranch() and pnode in repo.branchheads(
6875 branch, closed=True
6875 branch, closed=True
6876 ):
6876 ):
6877 t += _(b' (head closed)')
6877 t += _(b' (head closed)')
6878 elif not (
6878 elif not (
6879 status.modified
6879 status.modified
6880 or status.added
6880 or status.added
6881 or status.removed
6881 or status.removed
6882 or renamed
6882 or renamed
6883 or copied
6883 or copied
6884 or subs
6884 or subs
6885 ):
6885 ):
6886 t += _(b' (clean)')
6886 t += _(b' (clean)')
6887 cleanworkdir = True
6887 cleanworkdir = True
6888 elif pnode not in bheads:
6888 elif pnode not in bheads:
6889 t += _(b' (new branch head)')
6889 t += _(b' (new branch head)')
6890
6890
6891 if parents:
6891 if parents:
6892 pendingphase = max(p.phase() for p in parents)
6892 pendingphase = max(p.phase() for p in parents)
6893 else:
6893 else:
6894 pendingphase = phases.public
6894 pendingphase = phases.public
6895
6895
6896 if pendingphase > phases.newcommitphase(ui):
6896 if pendingphase > phases.newcommitphase(ui):
6897 t += b' (%s)' % phases.phasenames[pendingphase]
6897 t += b' (%s)' % phases.phasenames[pendingphase]
6898
6898
6899 if cleanworkdir:
6899 if cleanworkdir:
6900 # i18n: column positioning for "hg summary"
6900 # i18n: column positioning for "hg summary"
6901 ui.status(_(b'commit: %s\n') % t.strip())
6901 ui.status(_(b'commit: %s\n') % t.strip())
6902 else:
6902 else:
6903 # i18n: column positioning for "hg summary"
6903 # i18n: column positioning for "hg summary"
6904 ui.write(_(b'commit: %s\n') % t.strip())
6904 ui.write(_(b'commit: %s\n') % t.strip())
6905
6905
6906 # all ancestors of branch heads - all ancestors of parent = new csets
6906 # all ancestors of branch heads - all ancestors of parent = new csets
6907 new = len(
6907 new = len(
6908 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6908 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6909 )
6909 )
6910
6910
6911 if new == 0:
6911 if new == 0:
6912 # i18n: column positioning for "hg summary"
6912 # i18n: column positioning for "hg summary"
6913 ui.status(_(b'update: (current)\n'))
6913 ui.status(_(b'update: (current)\n'))
6914 elif pnode not in bheads:
6914 elif pnode not in bheads:
6915 # i18n: column positioning for "hg summary"
6915 # i18n: column positioning for "hg summary"
6916 ui.write(_(b'update: %d new changesets (update)\n') % new)
6916 ui.write(_(b'update: %d new changesets (update)\n') % new)
6917 else:
6917 else:
6918 # i18n: column positioning for "hg summary"
6918 # i18n: column positioning for "hg summary"
6919 ui.write(
6919 ui.write(
6920 _(b'update: %d new changesets, %d branch heads (merge)\n')
6920 _(b'update: %d new changesets, %d branch heads (merge)\n')
6921 % (new, len(bheads))
6921 % (new, len(bheads))
6922 )
6922 )
6923
6923
6924 t = []
6924 t = []
6925 draft = len(repo.revs(b'draft()'))
6925 draft = len(repo.revs(b'draft()'))
6926 if draft:
6926 if draft:
6927 t.append(_(b'%d draft') % draft)
6927 t.append(_(b'%d draft') % draft)
6928 secret = len(repo.revs(b'secret()'))
6928 secret = len(repo.revs(b'secret()'))
6929 if secret:
6929 if secret:
6930 t.append(_(b'%d secret') % secret)
6930 t.append(_(b'%d secret') % secret)
6931
6931
6932 if draft or secret:
6932 if draft or secret:
6933 ui.status(_(b'phases: %s\n') % b', '.join(t))
6933 ui.status(_(b'phases: %s\n') % b', '.join(t))
6934
6934
6935 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6935 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6936 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6936 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6937 numtrouble = len(repo.revs(trouble + b"()"))
6937 numtrouble = len(repo.revs(trouble + b"()"))
6938 # We write all the possibilities to ease translation
6938 # We write all the possibilities to ease translation
6939 troublemsg = {
6939 troublemsg = {
6940 b"orphan": _(b"orphan: %d changesets"),
6940 b"orphan": _(b"orphan: %d changesets"),
6941 b"contentdivergent": _(b"content-divergent: %d changesets"),
6941 b"contentdivergent": _(b"content-divergent: %d changesets"),
6942 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6942 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6943 }
6943 }
6944 if numtrouble > 0:
6944 if numtrouble > 0:
6945 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6945 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6946
6946
6947 cmdutil.summaryhooks(ui, repo)
6947 cmdutil.summaryhooks(ui, repo)
6948
6948
6949 if opts.get(b'remote'):
6949 if opts.get(b'remote'):
6950 needsincoming, needsoutgoing = True, True
6950 needsincoming, needsoutgoing = True, True
6951 else:
6951 else:
6952 needsincoming, needsoutgoing = False, False
6952 needsincoming, needsoutgoing = False, False
6953 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6953 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6954 if i:
6954 if i:
6955 needsincoming = True
6955 needsincoming = True
6956 if o:
6956 if o:
6957 needsoutgoing = True
6957 needsoutgoing = True
6958 if not needsincoming and not needsoutgoing:
6958 if not needsincoming and not needsoutgoing:
6959 return
6959 return
6960
6960
6961 def getincoming():
6961 def getincoming():
6962 source, branches = hg.parseurl(ui.expandpath(b'default'))
6962 source, branches = hg.parseurl(ui.expandpath(b'default'))
6963 sbranch = branches[0]
6963 sbranch = branches[0]
6964 try:
6964 try:
6965 other = hg.peer(repo, {}, source)
6965 other = hg.peer(repo, {}, source)
6966 except error.RepoError:
6966 except error.RepoError:
6967 if opts.get(b'remote'):
6967 if opts.get(b'remote'):
6968 raise
6968 raise
6969 return source, sbranch, None, None, None
6969 return source, sbranch, None, None, None
6970 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6970 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6971 if revs:
6971 if revs:
6972 revs = [other.lookup(rev) for rev in revs]
6972 revs = [other.lookup(rev) for rev in revs]
6973 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
6973 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
6974 repo.ui.pushbuffer()
6974 repo.ui.pushbuffer()
6975 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6975 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6976 repo.ui.popbuffer()
6976 repo.ui.popbuffer()
6977 return source, sbranch, other, commoninc, commoninc[1]
6977 return source, sbranch, other, commoninc, commoninc[1]
6978
6978
6979 if needsincoming:
6979 if needsincoming:
6980 source, sbranch, sother, commoninc, incoming = getincoming()
6980 source, sbranch, sother, commoninc, incoming = getincoming()
6981 else:
6981 else:
6982 source = sbranch = sother = commoninc = incoming = None
6982 source = sbranch = sother = commoninc = incoming = None
6983
6983
6984 def getoutgoing():
6984 def getoutgoing():
6985 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
6985 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
6986 dbranch = branches[0]
6986 dbranch = branches[0]
6987 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6987 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6988 if source != dest:
6988 if source != dest:
6989 try:
6989 try:
6990 dother = hg.peer(repo, {}, dest)
6990 dother = hg.peer(repo, {}, dest)
6991 except error.RepoError:
6991 except error.RepoError:
6992 if opts.get(b'remote'):
6992 if opts.get(b'remote'):
6993 raise
6993 raise
6994 return dest, dbranch, None, None
6994 return dest, dbranch, None, None
6995 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
6995 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
6996 elif sother is None:
6996 elif sother is None:
6997 # there is no explicit destination peer, but source one is invalid
6997 # there is no explicit destination peer, but source one is invalid
6998 return dest, dbranch, None, None
6998 return dest, dbranch, None, None
6999 else:
6999 else:
7000 dother = sother
7000 dother = sother
7001 if source != dest or (sbranch is not None and sbranch != dbranch):
7001 if source != dest or (sbranch is not None and sbranch != dbranch):
7002 common = None
7002 common = None
7003 else:
7003 else:
7004 common = commoninc
7004 common = commoninc
7005 if revs:
7005 if revs:
7006 revs = [repo.lookup(rev) for rev in revs]
7006 revs = [repo.lookup(rev) for rev in revs]
7007 repo.ui.pushbuffer()
7007 repo.ui.pushbuffer()
7008 outgoing = discovery.findcommonoutgoing(
7008 outgoing = discovery.findcommonoutgoing(
7009 repo, dother, onlyheads=revs, commoninc=common
7009 repo, dother, onlyheads=revs, commoninc=common
7010 )
7010 )
7011 repo.ui.popbuffer()
7011 repo.ui.popbuffer()
7012 return dest, dbranch, dother, outgoing
7012 return dest, dbranch, dother, outgoing
7013
7013
7014 if needsoutgoing:
7014 if needsoutgoing:
7015 dest, dbranch, dother, outgoing = getoutgoing()
7015 dest, dbranch, dother, outgoing = getoutgoing()
7016 else:
7016 else:
7017 dest = dbranch = dother = outgoing = None
7017 dest = dbranch = dother = outgoing = None
7018
7018
7019 if opts.get(b'remote'):
7019 if opts.get(b'remote'):
7020 t = []
7020 t = []
7021 if incoming:
7021 if incoming:
7022 t.append(_(b'1 or more incoming'))
7022 t.append(_(b'1 or more incoming'))
7023 o = outgoing.missing
7023 o = outgoing.missing
7024 if o:
7024 if o:
7025 t.append(_(b'%d outgoing') % len(o))
7025 t.append(_(b'%d outgoing') % len(o))
7026 other = dother or sother
7026 other = dother or sother
7027 if b'bookmarks' in other.listkeys(b'namespaces'):
7027 if b'bookmarks' in other.listkeys(b'namespaces'):
7028 counts = bookmarks.summary(repo, other)
7028 counts = bookmarks.summary(repo, other)
7029 if counts[0] > 0:
7029 if counts[0] > 0:
7030 t.append(_(b'%d incoming bookmarks') % counts[0])
7030 t.append(_(b'%d incoming bookmarks') % counts[0])
7031 if counts[1] > 0:
7031 if counts[1] > 0:
7032 t.append(_(b'%d outgoing bookmarks') % counts[1])
7032 t.append(_(b'%d outgoing bookmarks') % counts[1])
7033
7033
7034 if t:
7034 if t:
7035 # i18n: column positioning for "hg summary"
7035 # i18n: column positioning for "hg summary"
7036 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7036 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7037 else:
7037 else:
7038 # i18n: column positioning for "hg summary"
7038 # i18n: column positioning for "hg summary"
7039 ui.status(_(b'remote: (synced)\n'))
7039 ui.status(_(b'remote: (synced)\n'))
7040
7040
7041 cmdutil.summaryremotehooks(
7041 cmdutil.summaryremotehooks(
7042 ui,
7042 ui,
7043 repo,
7043 repo,
7044 opts,
7044 opts,
7045 (
7045 (
7046 (source, sbranch, sother, commoninc),
7046 (source, sbranch, sother, commoninc),
7047 (dest, dbranch, dother, outgoing),
7047 (dest, dbranch, dother, outgoing),
7048 ),
7048 ),
7049 )
7049 )
7050
7050
7051
7051
7052 @command(
7052 @command(
7053 b'tag',
7053 b'tag',
7054 [
7054 [
7055 (b'f', b'force', None, _(b'force tag')),
7055 (b'f', b'force', None, _(b'force tag')),
7056 (b'l', b'local', None, _(b'make the tag local')),
7056 (b'l', b'local', None, _(b'make the tag local')),
7057 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7057 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7058 (b'', b'remove', None, _(b'remove a tag')),
7058 (b'', b'remove', None, _(b'remove a tag')),
7059 # -l/--local is already there, commitopts cannot be used
7059 # -l/--local is already there, commitopts cannot be used
7060 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7060 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7061 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7061 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7062 ]
7062 ]
7063 + commitopts2,
7063 + commitopts2,
7064 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7064 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7065 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7065 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7066 )
7066 )
7067 def tag(ui, repo, name1, *names, **opts):
7067 def tag(ui, repo, name1, *names, **opts):
7068 """add one or more tags for the current or given revision
7068 """add one or more tags for the current or given revision
7069
7069
7070 Name a particular revision using <name>.
7070 Name a particular revision using <name>.
7071
7071
7072 Tags are used to name particular revisions of the repository and are
7072 Tags are used to name particular revisions of the repository and are
7073 very useful to compare different revisions, to go back to significant
7073 very useful to compare different revisions, to go back to significant
7074 earlier versions or to mark branch points as releases, etc. Changing
7074 earlier versions or to mark branch points as releases, etc. Changing
7075 an existing tag is normally disallowed; use -f/--force to override.
7075 an existing tag is normally disallowed; use -f/--force to override.
7076
7076
7077 If no revision is given, the parent of the working directory is
7077 If no revision is given, the parent of the working directory is
7078 used.
7078 used.
7079
7079
7080 To facilitate version control, distribution, and merging of tags,
7080 To facilitate version control, distribution, and merging of tags,
7081 they are stored as a file named ".hgtags" which is managed similarly
7081 they are stored as a file named ".hgtags" which is managed similarly
7082 to other project files and can be hand-edited if necessary. This
7082 to other project files and can be hand-edited if necessary. This
7083 also means that tagging creates a new commit. The file
7083 also means that tagging creates a new commit. The file
7084 ".hg/localtags" is used for local tags (not shared among
7084 ".hg/localtags" is used for local tags (not shared among
7085 repositories).
7085 repositories).
7086
7086
7087 Tag commits are usually made at the head of a branch. If the parent
7087 Tag commits are usually made at the head of a branch. If the parent
7088 of the working directory is not a branch head, :hg:`tag` aborts; use
7088 of the working directory is not a branch head, :hg:`tag` aborts; use
7089 -f/--force to force the tag commit to be based on a non-head
7089 -f/--force to force the tag commit to be based on a non-head
7090 changeset.
7090 changeset.
7091
7091
7092 See :hg:`help dates` for a list of formats valid for -d/--date.
7092 See :hg:`help dates` for a list of formats valid for -d/--date.
7093
7093
7094 Since tag names have priority over branch names during revision
7094 Since tag names have priority over branch names during revision
7095 lookup, using an existing branch name as a tag name is discouraged.
7095 lookup, using an existing branch name as a tag name is discouraged.
7096
7096
7097 Returns 0 on success.
7097 Returns 0 on success.
7098 """
7098 """
7099 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7099 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7100 opts = pycompat.byteskwargs(opts)
7100 opts = pycompat.byteskwargs(opts)
7101 with repo.wlock(), repo.lock():
7101 with repo.wlock(), repo.lock():
7102 rev_ = b"."
7102 rev_ = b"."
7103 names = [t.strip() for t in (name1,) + names]
7103 names = [t.strip() for t in (name1,) + names]
7104 if len(names) != len(set(names)):
7104 if len(names) != len(set(names)):
7105 raise error.Abort(_(b'tag names must be unique'))
7105 raise error.Abort(_(b'tag names must be unique'))
7106 for n in names:
7106 for n in names:
7107 scmutil.checknewlabel(repo, n, b'tag')
7107 scmutil.checknewlabel(repo, n, b'tag')
7108 if not n:
7108 if not n:
7109 raise error.Abort(
7109 raise error.Abort(
7110 _(b'tag names cannot consist entirely of whitespace')
7110 _(b'tag names cannot consist entirely of whitespace')
7111 )
7111 )
7112 if opts.get(b'rev'):
7112 if opts.get(b'rev'):
7113 rev_ = opts[b'rev']
7113 rev_ = opts[b'rev']
7114 message = opts.get(b'message')
7114 message = opts.get(b'message')
7115 if opts.get(b'remove'):
7115 if opts.get(b'remove'):
7116 if opts.get(b'local'):
7116 if opts.get(b'local'):
7117 expectedtype = b'local'
7117 expectedtype = b'local'
7118 else:
7118 else:
7119 expectedtype = b'global'
7119 expectedtype = b'global'
7120
7120
7121 for n in names:
7121 for n in names:
7122 if repo.tagtype(n) == b'global':
7122 if repo.tagtype(n) == b'global':
7123 alltags = tagsmod.findglobaltags(ui, repo)
7123 alltags = tagsmod.findglobaltags(ui, repo)
7124 if alltags[n][0] == nullid:
7124 if alltags[n][0] == nullid:
7125 raise error.Abort(_(b"tag '%s' is already removed") % n)
7125 raise error.Abort(_(b"tag '%s' is already removed") % n)
7126 if not repo.tagtype(n):
7126 if not repo.tagtype(n):
7127 raise error.Abort(_(b"tag '%s' does not exist") % n)
7127 raise error.Abort(_(b"tag '%s' does not exist") % n)
7128 if repo.tagtype(n) != expectedtype:
7128 if repo.tagtype(n) != expectedtype:
7129 if expectedtype == b'global':
7129 if expectedtype == b'global':
7130 raise error.Abort(
7130 raise error.Abort(
7131 _(b"tag '%s' is not a global tag") % n
7131 _(b"tag '%s' is not a global tag") % n
7132 )
7132 )
7133 else:
7133 else:
7134 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7134 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7135 rev_ = b'null'
7135 rev_ = b'null'
7136 if not message:
7136 if not message:
7137 # we don't translate commit messages
7137 # we don't translate commit messages
7138 message = b'Removed tag %s' % b', '.join(names)
7138 message = b'Removed tag %s' % b', '.join(names)
7139 elif not opts.get(b'force'):
7139 elif not opts.get(b'force'):
7140 for n in names:
7140 for n in names:
7141 if n in repo.tags():
7141 if n in repo.tags():
7142 raise error.Abort(
7142 raise error.Abort(
7143 _(b"tag '%s' already exists (use -f to force)") % n
7143 _(b"tag '%s' already exists (use -f to force)") % n
7144 )
7144 )
7145 if not opts.get(b'local'):
7145 if not opts.get(b'local'):
7146 p1, p2 = repo.dirstate.parents()
7146 p1, p2 = repo.dirstate.parents()
7147 if p2 != nullid:
7147 if p2 != nullid:
7148 raise error.Abort(_(b'uncommitted merge'))
7148 raise error.Abort(_(b'uncommitted merge'))
7149 bheads = repo.branchheads()
7149 bheads = repo.branchheads()
7150 if not opts.get(b'force') and bheads and p1 not in bheads:
7150 if not opts.get(b'force') and bheads and p1 not in bheads:
7151 raise error.Abort(
7151 raise error.Abort(
7152 _(
7152 _(
7153 b'working directory is not at a branch head '
7153 b'working directory is not at a branch head '
7154 b'(use -f to force)'
7154 b'(use -f to force)'
7155 )
7155 )
7156 )
7156 )
7157 node = scmutil.revsingle(repo, rev_).node()
7157 node = scmutil.revsingle(repo, rev_).node()
7158
7158
7159 if not message:
7159 if not message:
7160 # we don't translate commit messages
7160 # we don't translate commit messages
7161 message = b'Added tag %s for changeset %s' % (
7161 message = b'Added tag %s for changeset %s' % (
7162 b', '.join(names),
7162 b', '.join(names),
7163 short(node),
7163 short(node),
7164 )
7164 )
7165
7165
7166 date = opts.get(b'date')
7166 date = opts.get(b'date')
7167 if date:
7167 if date:
7168 date = dateutil.parsedate(date)
7168 date = dateutil.parsedate(date)
7169
7169
7170 if opts.get(b'remove'):
7170 if opts.get(b'remove'):
7171 editform = b'tag.remove'
7171 editform = b'tag.remove'
7172 else:
7172 else:
7173 editform = b'tag.add'
7173 editform = b'tag.add'
7174 editor = cmdutil.getcommiteditor(
7174 editor = cmdutil.getcommiteditor(
7175 editform=editform, **pycompat.strkwargs(opts)
7175 editform=editform, **pycompat.strkwargs(opts)
7176 )
7176 )
7177
7177
7178 # don't allow tagging the null rev
7178 # don't allow tagging the null rev
7179 if (
7179 if (
7180 not opts.get(b'remove')
7180 not opts.get(b'remove')
7181 and scmutil.revsingle(repo, rev_).rev() == nullrev
7181 and scmutil.revsingle(repo, rev_).rev() == nullrev
7182 ):
7182 ):
7183 raise error.Abort(_(b"cannot tag null revision"))
7183 raise error.Abort(_(b"cannot tag null revision"))
7184
7184
7185 tagsmod.tag(
7185 tagsmod.tag(
7186 repo,
7186 repo,
7187 names,
7187 names,
7188 node,
7188 node,
7189 message,
7189 message,
7190 opts.get(b'local'),
7190 opts.get(b'local'),
7191 opts.get(b'user'),
7191 opts.get(b'user'),
7192 date,
7192 date,
7193 editor=editor,
7193 editor=editor,
7194 )
7194 )
7195
7195
7196
7196
7197 @command(
7197 @command(
7198 b'tags',
7198 b'tags',
7199 formatteropts,
7199 formatteropts,
7200 b'',
7200 b'',
7201 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7201 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7202 intents={INTENT_READONLY},
7202 intents={INTENT_READONLY},
7203 )
7203 )
7204 def tags(ui, repo, **opts):
7204 def tags(ui, repo, **opts):
7205 """list repository tags
7205 """list repository tags
7206
7206
7207 This lists both regular and local tags. When the -v/--verbose
7207 This lists both regular and local tags. When the -v/--verbose
7208 switch is used, a third column "local" is printed for local tags.
7208 switch is used, a third column "local" is printed for local tags.
7209 When the -q/--quiet switch is used, only the tag name is printed.
7209 When the -q/--quiet switch is used, only the tag name is printed.
7210
7210
7211 .. container:: verbose
7211 .. container:: verbose
7212
7212
7213 Template:
7213 Template:
7214
7214
7215 The following keywords are supported in addition to the common template
7215 The following keywords are supported in addition to the common template
7216 keywords and functions such as ``{tag}``. See also
7216 keywords and functions such as ``{tag}``. See also
7217 :hg:`help templates`.
7217 :hg:`help templates`.
7218
7218
7219 :type: String. ``local`` for local tags.
7219 :type: String. ``local`` for local tags.
7220
7220
7221 Returns 0 on success.
7221 Returns 0 on success.
7222 """
7222 """
7223
7223
7224 opts = pycompat.byteskwargs(opts)
7224 opts = pycompat.byteskwargs(opts)
7225 ui.pager(b'tags')
7225 ui.pager(b'tags')
7226 fm = ui.formatter(b'tags', opts)
7226 fm = ui.formatter(b'tags', opts)
7227 hexfunc = fm.hexfunc
7227 hexfunc = fm.hexfunc
7228
7228
7229 for t, n in reversed(repo.tagslist()):
7229 for t, n in reversed(repo.tagslist()):
7230 hn = hexfunc(n)
7230 hn = hexfunc(n)
7231 label = b'tags.normal'
7231 label = b'tags.normal'
7232 tagtype = b''
7232 tagtype = b''
7233 if repo.tagtype(t) == b'local':
7233 if repo.tagtype(t) == b'local':
7234 label = b'tags.local'
7234 label = b'tags.local'
7235 tagtype = b'local'
7235 tagtype = b'local'
7236
7236
7237 fm.startitem()
7237 fm.startitem()
7238 fm.context(repo=repo)
7238 fm.context(repo=repo)
7239 fm.write(b'tag', b'%s', t, label=label)
7239 fm.write(b'tag', b'%s', t, label=label)
7240 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7240 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7241 fm.condwrite(
7241 fm.condwrite(
7242 not ui.quiet,
7242 not ui.quiet,
7243 b'rev node',
7243 b'rev node',
7244 fmt,
7244 fmt,
7245 repo.changelog.rev(n),
7245 repo.changelog.rev(n),
7246 hn,
7246 hn,
7247 label=label,
7247 label=label,
7248 )
7248 )
7249 fm.condwrite(
7249 fm.condwrite(
7250 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7250 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7251 )
7251 )
7252 fm.plain(b'\n')
7252 fm.plain(b'\n')
7253 fm.end()
7253 fm.end()
7254
7254
7255
7255
7256 @command(
7256 @command(
7257 b'tip',
7257 b'tip',
7258 [
7258 [
7259 (b'p', b'patch', None, _(b'show patch')),
7259 (b'p', b'patch', None, _(b'show patch')),
7260 (b'g', b'git', None, _(b'use git extended diff format')),
7260 (b'g', b'git', None, _(b'use git extended diff format')),
7261 ]
7261 ]
7262 + templateopts,
7262 + templateopts,
7263 _(b'[-p] [-g]'),
7263 _(b'[-p] [-g]'),
7264 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7264 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7265 )
7265 )
7266 def tip(ui, repo, **opts):
7266 def tip(ui, repo, **opts):
7267 """show the tip revision (DEPRECATED)
7267 """show the tip revision (DEPRECATED)
7268
7268
7269 The tip revision (usually just called the tip) is the changeset
7269 The tip revision (usually just called the tip) is the changeset
7270 most recently added to the repository (and therefore the most
7270 most recently added to the repository (and therefore the most
7271 recently changed head).
7271 recently changed head).
7272
7272
7273 If you have just made a commit, that commit will be the tip. If
7273 If you have just made a commit, that commit will be the tip. If
7274 you have just pulled changes from another repository, the tip of
7274 you have just pulled changes from another repository, the tip of
7275 that repository becomes the current tip. The "tip" tag is special
7275 that repository becomes the current tip. The "tip" tag is special
7276 and cannot be renamed or assigned to a different changeset.
7276 and cannot be renamed or assigned to a different changeset.
7277
7277
7278 This command is deprecated, please use :hg:`heads` instead.
7278 This command is deprecated, please use :hg:`heads` instead.
7279
7279
7280 Returns 0 on success.
7280 Returns 0 on success.
7281 """
7281 """
7282 opts = pycompat.byteskwargs(opts)
7282 opts = pycompat.byteskwargs(opts)
7283 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7283 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7284 displayer.show(repo[b'tip'])
7284 displayer.show(repo[b'tip'])
7285 displayer.close()
7285 displayer.close()
7286
7286
7287
7287
7288 @command(
7288 @command(
7289 b'unbundle',
7289 b'unbundle',
7290 [
7290 [
7291 (
7291 (
7292 b'u',
7292 b'u',
7293 b'update',
7293 b'update',
7294 None,
7294 None,
7295 _(b'update to new branch head if changesets were unbundled'),
7295 _(b'update to new branch head if changesets were unbundled'),
7296 )
7296 )
7297 ],
7297 ],
7298 _(b'[-u] FILE...'),
7298 _(b'[-u] FILE...'),
7299 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7299 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7300 )
7300 )
7301 def unbundle(ui, repo, fname1, *fnames, **opts):
7301 def unbundle(ui, repo, fname1, *fnames, **opts):
7302 """apply one or more bundle files
7302 """apply one or more bundle files
7303
7303
7304 Apply one or more bundle files generated by :hg:`bundle`.
7304 Apply one or more bundle files generated by :hg:`bundle`.
7305
7305
7306 Returns 0 on success, 1 if an update has unresolved files.
7306 Returns 0 on success, 1 if an update has unresolved files.
7307 """
7307 """
7308 fnames = (fname1,) + fnames
7308 fnames = (fname1,) + fnames
7309
7309
7310 with repo.lock():
7310 with repo.lock():
7311 for fname in fnames:
7311 for fname in fnames:
7312 f = hg.openpath(ui, fname)
7312 f = hg.openpath(ui, fname)
7313 gen = exchange.readbundle(ui, f, fname)
7313 gen = exchange.readbundle(ui, f, fname)
7314 if isinstance(gen, streamclone.streamcloneapplier):
7314 if isinstance(gen, streamclone.streamcloneapplier):
7315 raise error.Abort(
7315 raise error.Abort(
7316 _(
7316 _(
7317 b'packed bundles cannot be applied with '
7317 b'packed bundles cannot be applied with '
7318 b'"hg unbundle"'
7318 b'"hg unbundle"'
7319 ),
7319 ),
7320 hint=_(b'use "hg debugapplystreamclonebundle"'),
7320 hint=_(b'use "hg debugapplystreamclonebundle"'),
7321 )
7321 )
7322 url = b'bundle:' + fname
7322 url = b'bundle:' + fname
7323 try:
7323 try:
7324 txnname = b'unbundle'
7324 txnname = b'unbundle'
7325 if not isinstance(gen, bundle2.unbundle20):
7325 if not isinstance(gen, bundle2.unbundle20):
7326 txnname = b'unbundle\n%s' % util.hidepassword(url)
7326 txnname = b'unbundle\n%s' % util.hidepassword(url)
7327 with repo.transaction(txnname) as tr:
7327 with repo.transaction(txnname) as tr:
7328 op = bundle2.applybundle(
7328 op = bundle2.applybundle(
7329 repo, gen, tr, source=b'unbundle', url=url
7329 repo, gen, tr, source=b'unbundle', url=url
7330 )
7330 )
7331 except error.BundleUnknownFeatureError as exc:
7331 except error.BundleUnknownFeatureError as exc:
7332 raise error.Abort(
7332 raise error.Abort(
7333 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7333 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7334 hint=_(
7334 hint=_(
7335 b"see https://mercurial-scm.org/"
7335 b"see https://mercurial-scm.org/"
7336 b"wiki/BundleFeature for more "
7336 b"wiki/BundleFeature for more "
7337 b"information"
7337 b"information"
7338 ),
7338 ),
7339 )
7339 )
7340 modheads = bundle2.combinechangegroupresults(op)
7340 modheads = bundle2.combinechangegroupresults(op)
7341
7341
7342 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7342 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7343
7343
7344
7344
7345 @command(
7345 @command(
7346 b'unshelve',
7346 b'unshelve',
7347 [
7347 [
7348 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7348 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7349 (
7349 (
7350 b'c',
7350 b'c',
7351 b'continue',
7351 b'continue',
7352 None,
7352 None,
7353 _(b'continue an incomplete unshelve operation'),
7353 _(b'continue an incomplete unshelve operation'),
7354 ),
7354 ),
7355 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7355 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7356 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7356 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7357 (
7357 (
7358 b'n',
7358 b'n',
7359 b'name',
7359 b'name',
7360 b'',
7360 b'',
7361 _(b'restore shelved change with given name'),
7361 _(b'restore shelved change with given name'),
7362 _(b'NAME'),
7362 _(b'NAME'),
7363 ),
7363 ),
7364 (b't', b'tool', b'', _(b'specify merge tool')),
7364 (b't', b'tool', b'', _(b'specify merge tool')),
7365 (
7365 (
7366 b'',
7366 b'',
7367 b'date',
7367 b'date',
7368 b'',
7368 b'',
7369 _(b'set date for temporary commits (DEPRECATED)'),
7369 _(b'set date for temporary commits (DEPRECATED)'),
7370 _(b'DATE'),
7370 _(b'DATE'),
7371 ),
7371 ),
7372 ],
7372 ],
7373 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7373 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7374 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7374 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7375 )
7375 )
7376 def unshelve(ui, repo, *shelved, **opts):
7376 def unshelve(ui, repo, *shelved, **opts):
7377 """restore a shelved change to the working directory
7377 """restore a shelved change to the working directory
7378
7378
7379 This command accepts an optional name of a shelved change to
7379 This command accepts an optional name of a shelved change to
7380 restore. If none is given, the most recent shelved change is used.
7380 restore. If none is given, the most recent shelved change is used.
7381
7381
7382 If a shelved change is applied successfully, the bundle that
7382 If a shelved change is applied successfully, the bundle that
7383 contains the shelved changes is moved to a backup location
7383 contains the shelved changes is moved to a backup location
7384 (.hg/shelve-backup).
7384 (.hg/shelve-backup).
7385
7385
7386 Since you can restore a shelved change on top of an arbitrary
7386 Since you can restore a shelved change on top of an arbitrary
7387 commit, it is possible that unshelving will result in a conflict
7387 commit, it is possible that unshelving will result in a conflict
7388 between your changes and the commits you are unshelving onto. If
7388 between your changes and the commits you are unshelving onto. If
7389 this occurs, you must resolve the conflict, then use
7389 this occurs, you must resolve the conflict, then use
7390 ``--continue`` to complete the unshelve operation. (The bundle
7390 ``--continue`` to complete the unshelve operation. (The bundle
7391 will not be moved until you successfully complete the unshelve.)
7391 will not be moved until you successfully complete the unshelve.)
7392
7392
7393 (Alternatively, you can use ``--abort`` to abandon an unshelve
7393 (Alternatively, you can use ``--abort`` to abandon an unshelve
7394 that causes a conflict. This reverts the unshelved changes, and
7394 that causes a conflict. This reverts the unshelved changes, and
7395 leaves the bundle in place.)
7395 leaves the bundle in place.)
7396
7396
7397 If bare shelved change (without interactive, include and exclude
7397 If bare shelved change (without interactive, include and exclude
7398 option) was done on newly created branch it would restore branch
7398 option) was done on newly created branch it would restore branch
7399 information to the working directory.
7399 information to the working directory.
7400
7400
7401 After a successful unshelve, the shelved changes are stored in a
7401 After a successful unshelve, the shelved changes are stored in a
7402 backup directory. Only the N most recent backups are kept. N
7402 backup directory. Only the N most recent backups are kept. N
7403 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7403 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7404 configuration option.
7404 configuration option.
7405
7405
7406 .. container:: verbose
7406 .. container:: verbose
7407
7407
7408 Timestamp in seconds is used to decide order of backups. More
7408 Timestamp in seconds is used to decide order of backups. More
7409 than ``maxbackups`` backups are kept, if same timestamp
7409 than ``maxbackups`` backups are kept, if same timestamp
7410 prevents from deciding exact order of them, for safety.
7410 prevents from deciding exact order of them, for safety.
7411
7411
7412 Selected changes can be unshelved with ``--interactive`` flag.
7412 Selected changes can be unshelved with ``--interactive`` flag.
7413 The working directory is updated with the selected changes, and
7413 The working directory is updated with the selected changes, and
7414 only the unselected changes remain shelved.
7414 only the unselected changes remain shelved.
7415 Note: The whole shelve is applied to working directory first before
7415 Note: The whole shelve is applied to working directory first before
7416 running interactively. So, this will bring up all the conflicts between
7416 running interactively. So, this will bring up all the conflicts between
7417 working directory and the shelve, irrespective of which changes will be
7417 working directory and the shelve, irrespective of which changes will be
7418 unshelved.
7418 unshelved.
7419 """
7419 """
7420 with repo.wlock():
7420 with repo.wlock():
7421 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7421 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7422
7422
7423
7423
7424 statemod.addunfinished(
7424 statemod.addunfinished(
7425 b'unshelve',
7425 b'unshelve',
7426 fname=b'shelvedstate',
7426 fname=b'shelvedstate',
7427 continueflag=True,
7427 continueflag=True,
7428 abortfunc=shelvemod.hgabortunshelve,
7428 abortfunc=shelvemod.hgabortunshelve,
7429 continuefunc=shelvemod.hgcontinueunshelve,
7429 continuefunc=shelvemod.hgcontinueunshelve,
7430 cmdmsg=_(b'unshelve already in progress'),
7430 cmdmsg=_(b'unshelve already in progress'),
7431 )
7431 )
7432
7432
7433
7433
7434 @command(
7434 @command(
7435 b'update|up|checkout|co',
7435 b'update|up|checkout|co',
7436 [
7436 [
7437 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7437 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7438 (b'c', b'check', None, _(b'require clean working directory')),
7438 (b'c', b'check', None, _(b'require clean working directory')),
7439 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7439 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7440 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7440 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7441 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7441 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7442 ]
7442 ]
7443 + mergetoolopts,
7443 + mergetoolopts,
7444 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7444 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7445 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7445 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7446 helpbasic=True,
7446 helpbasic=True,
7447 )
7447 )
7448 def update(ui, repo, node=None, **opts):
7448 def update(ui, repo, node=None, **opts):
7449 """update working directory (or switch revisions)
7449 """update working directory (or switch revisions)
7450
7450
7451 Update the repository's working directory to the specified
7451 Update the repository's working directory to the specified
7452 changeset. If no changeset is specified, update to the tip of the
7452 changeset. If no changeset is specified, update to the tip of the
7453 current named branch and move the active bookmark (see :hg:`help
7453 current named branch and move the active bookmark (see :hg:`help
7454 bookmarks`).
7454 bookmarks`).
7455
7455
7456 Update sets the working directory's parent revision to the specified
7456 Update sets the working directory's parent revision to the specified
7457 changeset (see :hg:`help parents`).
7457 changeset (see :hg:`help parents`).
7458
7458
7459 If the changeset is not a descendant or ancestor of the working
7459 If the changeset is not a descendant or ancestor of the working
7460 directory's parent and there are uncommitted changes, the update is
7460 directory's parent and there are uncommitted changes, the update is
7461 aborted. With the -c/--check option, the working directory is checked
7461 aborted. With the -c/--check option, the working directory is checked
7462 for uncommitted changes; if none are found, the working directory is
7462 for uncommitted changes; if none are found, the working directory is
7463 updated to the specified changeset.
7463 updated to the specified changeset.
7464
7464
7465 .. container:: verbose
7465 .. container:: verbose
7466
7466
7467 The -C/--clean, -c/--check, and -m/--merge options control what
7467 The -C/--clean, -c/--check, and -m/--merge options control what
7468 happens if the working directory contains uncommitted changes.
7468 happens if the working directory contains uncommitted changes.
7469 At most of one of them can be specified.
7469 At most of one of them can be specified.
7470
7470
7471 1. If no option is specified, and if
7471 1. If no option is specified, and if
7472 the requested changeset is an ancestor or descendant of
7472 the requested changeset is an ancestor or descendant of
7473 the working directory's parent, the uncommitted changes
7473 the working directory's parent, the uncommitted changes
7474 are merged into the requested changeset and the merged
7474 are merged into the requested changeset and the merged
7475 result is left uncommitted. If the requested changeset is
7475 result is left uncommitted. If the requested changeset is
7476 not an ancestor or descendant (that is, it is on another
7476 not an ancestor or descendant (that is, it is on another
7477 branch), the update is aborted and the uncommitted changes
7477 branch), the update is aborted and the uncommitted changes
7478 are preserved.
7478 are preserved.
7479
7479
7480 2. With the -m/--merge option, the update is allowed even if the
7480 2. With the -m/--merge option, the update is allowed even if the
7481 requested changeset is not an ancestor or descendant of
7481 requested changeset is not an ancestor or descendant of
7482 the working directory's parent.
7482 the working directory's parent.
7483
7483
7484 3. With the -c/--check option, the update is aborted and the
7484 3. With the -c/--check option, the update is aborted and the
7485 uncommitted changes are preserved.
7485 uncommitted changes are preserved.
7486
7486
7487 4. With the -C/--clean option, uncommitted changes are discarded and
7487 4. With the -C/--clean option, uncommitted changes are discarded and
7488 the working directory is updated to the requested changeset.
7488 the working directory is updated to the requested changeset.
7489
7489
7490 To cancel an uncommitted merge (and lose your changes), use
7490 To cancel an uncommitted merge (and lose your changes), use
7491 :hg:`merge --abort`.
7491 :hg:`merge --abort`.
7492
7492
7493 Use null as the changeset to remove the working directory (like
7493 Use null as the changeset to remove the working directory (like
7494 :hg:`clone -U`).
7494 :hg:`clone -U`).
7495
7495
7496 If you want to revert just one file to an older revision, use
7496 If you want to revert just one file to an older revision, use
7497 :hg:`revert [-r REV] NAME`.
7497 :hg:`revert [-r REV] NAME`.
7498
7498
7499 See :hg:`help dates` for a list of formats valid for -d/--date.
7499 See :hg:`help dates` for a list of formats valid for -d/--date.
7500
7500
7501 Returns 0 on success, 1 if there are unresolved files.
7501 Returns 0 on success, 1 if there are unresolved files.
7502 """
7502 """
7503 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7503 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7504 rev = opts.get('rev')
7504 rev = opts.get('rev')
7505 date = opts.get('date')
7505 date = opts.get('date')
7506 clean = opts.get('clean')
7506 clean = opts.get('clean')
7507 check = opts.get('check')
7507 check = opts.get('check')
7508 merge = opts.get('merge')
7508 merge = opts.get('merge')
7509 if rev and node:
7509 if rev and node:
7510 raise error.Abort(_(b"please specify just one revision"))
7510 raise error.Abort(_(b"please specify just one revision"))
7511
7511
7512 if ui.configbool(b'commands', b'update.requiredest'):
7512 if ui.configbool(b'commands', b'update.requiredest'):
7513 if not node and not rev and not date:
7513 if not node and not rev and not date:
7514 raise error.Abort(
7514 raise error.Abort(
7515 _(b'you must specify a destination'),
7515 _(b'you must specify a destination'),
7516 hint=_(b'for example: hg update ".::"'),
7516 hint=_(b'for example: hg update ".::"'),
7517 )
7517 )
7518
7518
7519 if rev is None or rev == b'':
7519 if rev is None or rev == b'':
7520 rev = node
7520 rev = node
7521
7521
7522 if date and rev is not None:
7522 if date and rev is not None:
7523 raise error.Abort(_(b"you can't specify a revision and a date"))
7523 raise error.Abort(_(b"you can't specify a revision and a date"))
7524
7524
7525 updatecheck = None
7525 updatecheck = None
7526 if check:
7526 if check:
7527 updatecheck = b'abort'
7527 updatecheck = b'abort'
7528 elif merge:
7528 elif merge:
7529 updatecheck = b'none'
7529 updatecheck = b'none'
7530
7530
7531 with repo.wlock():
7531 with repo.wlock():
7532 cmdutil.clearunfinished(repo)
7532 cmdutil.clearunfinished(repo)
7533 if date:
7533 if date:
7534 rev = cmdutil.finddate(ui, repo, date)
7534 rev = cmdutil.finddate(ui, repo, date)
7535
7535
7536 # if we defined a bookmark, we have to remember the original name
7536 # if we defined a bookmark, we have to remember the original name
7537 brev = rev
7537 brev = rev
7538 if rev:
7538 if rev:
7539 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7539 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7540 ctx = scmutil.revsingle(repo, rev, default=None)
7540 ctx = scmutil.revsingle(repo, rev, default=None)
7541 rev = ctx.rev()
7541 rev = ctx.rev()
7542 hidden = ctx.hidden()
7542 hidden = ctx.hidden()
7543 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7543 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7544 with ui.configoverride(overrides, b'update'):
7544 with ui.configoverride(overrides, b'update'):
7545 ret = hg.updatetotally(
7545 ret = hg.updatetotally(
7546 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7546 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7547 )
7547 )
7548 if hidden:
7548 if hidden:
7549 ctxstr = ctx.hex()[:12]
7549 ctxstr = ctx.hex()[:12]
7550 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7550 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7551
7551
7552 if ctx.obsolete():
7552 if ctx.obsolete():
7553 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7553 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7554 ui.warn(b"(%s)\n" % obsfatemsg)
7554 ui.warn(b"(%s)\n" % obsfatemsg)
7555 return ret
7555 return ret
7556
7556
7557
7557
7558 @command(
7558 @command(
7559 b'verify',
7559 b'verify',
7560 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7560 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7561 helpcategory=command.CATEGORY_MAINTENANCE,
7561 helpcategory=command.CATEGORY_MAINTENANCE,
7562 )
7562 )
7563 def verify(ui, repo, **opts):
7563 def verify(ui, repo, **opts):
7564 """verify the integrity of the repository
7564 """verify the integrity of the repository
7565
7565
7566 Verify the integrity of the current repository.
7566 Verify the integrity of the current repository.
7567
7567
7568 This will perform an extensive check of the repository's
7568 This will perform an extensive check of the repository's
7569 integrity, validating the hashes and checksums of each entry in
7569 integrity, validating the hashes and checksums of each entry in
7570 the changelog, manifest, and tracked files, as well as the
7570 the changelog, manifest, and tracked files, as well as the
7571 integrity of their crosslinks and indices.
7571 integrity of their crosslinks and indices.
7572
7572
7573 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7573 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7574 for more information about recovery from corruption of the
7574 for more information about recovery from corruption of the
7575 repository.
7575 repository.
7576
7576
7577 Returns 0 on success, 1 if errors are encountered.
7577 Returns 0 on success, 1 if errors are encountered.
7578 """
7578 """
7579 opts = pycompat.byteskwargs(opts)
7579 opts = pycompat.byteskwargs(opts)
7580
7580
7581 level = None
7581 level = None
7582 if opts[b'full']:
7582 if opts[b'full']:
7583 level = verifymod.VERIFY_FULL
7583 level = verifymod.VERIFY_FULL
7584 return hg.verify(repo, level)
7584 return hg.verify(repo, level)
7585
7585
7586
7586
7587 @command(
7587 @command(
7588 b'version',
7588 b'version',
7589 [] + formatteropts,
7589 [] + formatteropts,
7590 helpcategory=command.CATEGORY_HELP,
7590 helpcategory=command.CATEGORY_HELP,
7591 norepo=True,
7591 norepo=True,
7592 intents={INTENT_READONLY},
7592 intents={INTENT_READONLY},
7593 )
7593 )
7594 def version_(ui, **opts):
7594 def version_(ui, **opts):
7595 """output version and copyright information
7595 """output version and copyright information
7596
7596
7597 .. container:: verbose
7597 .. container:: verbose
7598
7598
7599 Template:
7599 Template:
7600
7600
7601 The following keywords are supported. See also :hg:`help templates`.
7601 The following keywords are supported. See also :hg:`help templates`.
7602
7602
7603 :extensions: List of extensions.
7603 :extensions: List of extensions.
7604 :ver: String. Version number.
7604 :ver: String. Version number.
7605
7605
7606 And each entry of ``{extensions}`` provides the following sub-keywords
7606 And each entry of ``{extensions}`` provides the following sub-keywords
7607 in addition to ``{ver}``.
7607 in addition to ``{ver}``.
7608
7608
7609 :bundled: Boolean. True if included in the release.
7609 :bundled: Boolean. True if included in the release.
7610 :name: String. Extension name.
7610 :name: String. Extension name.
7611 """
7611 """
7612 opts = pycompat.byteskwargs(opts)
7612 opts = pycompat.byteskwargs(opts)
7613 if ui.verbose:
7613 if ui.verbose:
7614 ui.pager(b'version')
7614 ui.pager(b'version')
7615 fm = ui.formatter(b"version", opts)
7615 fm = ui.formatter(b"version", opts)
7616 fm.startitem()
7616 fm.startitem()
7617 fm.write(
7617 fm.write(
7618 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7618 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7619 )
7619 )
7620 license = _(
7620 license = _(
7621 b"(see https://mercurial-scm.org for more information)\n"
7621 b"(see https://mercurial-scm.org for more information)\n"
7622 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7622 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7623 b"This is free software; see the source for copying conditions. "
7623 b"This is free software; see the source for copying conditions. "
7624 b"There is NO\nwarranty; "
7624 b"There is NO\nwarranty; "
7625 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7625 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7626 )
7626 )
7627 if not ui.quiet:
7627 if not ui.quiet:
7628 fm.plain(license)
7628 fm.plain(license)
7629
7629
7630 if ui.verbose:
7630 if ui.verbose:
7631 fm.plain(_(b"\nEnabled extensions:\n\n"))
7631 fm.plain(_(b"\nEnabled extensions:\n\n"))
7632 # format names and versions into columns
7632 # format names and versions into columns
7633 names = []
7633 names = []
7634 vers = []
7634 vers = []
7635 isinternals = []
7635 isinternals = []
7636 for name, module in sorted(extensions.extensions()):
7636 for name, module in sorted(extensions.extensions()):
7637 names.append(name)
7637 names.append(name)
7638 vers.append(extensions.moduleversion(module) or None)
7638 vers.append(extensions.moduleversion(module) or None)
7639 isinternals.append(extensions.ismoduleinternal(module))
7639 isinternals.append(extensions.ismoduleinternal(module))
7640 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7640 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7641 if names:
7641 if names:
7642 namefmt = b" %%-%ds " % max(len(n) for n in names)
7642 namefmt = b" %%-%ds " % max(len(n) for n in names)
7643 places = [_(b"external"), _(b"internal")]
7643 places = [_(b"external"), _(b"internal")]
7644 for n, v, p in zip(names, vers, isinternals):
7644 for n, v, p in zip(names, vers, isinternals):
7645 fn.startitem()
7645 fn.startitem()
7646 fn.condwrite(ui.verbose, b"name", namefmt, n)
7646 fn.condwrite(ui.verbose, b"name", namefmt, n)
7647 if ui.verbose:
7647 if ui.verbose:
7648 fn.plain(b"%s " % places[p])
7648 fn.plain(b"%s " % places[p])
7649 fn.data(bundled=p)
7649 fn.data(bundled=p)
7650 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7650 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7651 if ui.verbose:
7651 if ui.verbose:
7652 fn.plain(b"\n")
7652 fn.plain(b"\n")
7653 fn.end()
7653 fn.end()
7654 fm.end()
7654 fm.end()
7655
7655
7656
7656
7657 def loadcmdtable(ui, name, cmdtable):
7657 def loadcmdtable(ui, name, cmdtable):
7658 """Load command functions from specified cmdtable
7658 """Load command functions from specified cmdtable
7659 """
7659 """
7660 overrides = [cmd for cmd in cmdtable if cmd in table]
7660 overrides = [cmd for cmd in cmdtable if cmd in table]
7661 if overrides:
7661 if overrides:
7662 ui.warn(
7662 ui.warn(
7663 _(b"extension '%s' overrides commands: %s\n")
7663 _(b"extension '%s' overrides commands: %s\n")
7664 % (name, b" ".join(overrides))
7664 % (name, b" ".join(overrides))
7665 )
7665 )
7666 table.update(cmdtable)
7666 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now