##// END OF EJS Templates
grep: explicitly pass regexp to closure functions...
Yuya Nishihara -
r46287:760bb4d7 default
parent child Browse files
Show More
@@ -1,7828 +1,7828 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 difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
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 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 match as matchmod,
48 match as matchmod,
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 opts = pycompat.byteskwargs(opts)
773 opts = pycompat.byteskwargs(opts)
774 if opts.get(b'commit') and opts.get(b'no_commit'):
774 if opts.get(b'commit') and opts.get(b'no_commit'):
775 raise error.Abort(_(b"cannot use --commit with --no-commit"))
775 raise error.Abort(_(b"cannot use --commit with --no-commit"))
776 if opts.get(b'merge') and opts.get(b'no_commit'):
776 if opts.get(b'merge') and opts.get(b'no_commit'):
777 raise error.Abort(_(b"cannot use --merge with --no-commit"))
777 raise error.Abort(_(b"cannot use --merge with --no-commit"))
778
778
779 if rev and node:
779 if rev and node:
780 raise error.Abort(_(b"please specify just one revision"))
780 raise error.Abort(_(b"please specify just one revision"))
781
781
782 if not rev:
782 if not rev:
783 rev = node
783 rev = node
784
784
785 if not rev:
785 if not rev:
786 raise error.Abort(_(b"please specify a revision to backout"))
786 raise error.Abort(_(b"please specify a revision to backout"))
787
787
788 date = opts.get(b'date')
788 date = opts.get(b'date')
789 if date:
789 if date:
790 opts[b'date'] = dateutil.parsedate(date)
790 opts[b'date'] = dateutil.parsedate(date)
791
791
792 cmdutil.checkunfinished(repo)
792 cmdutil.checkunfinished(repo)
793 cmdutil.bailifchanged(repo)
793 cmdutil.bailifchanged(repo)
794 ctx = scmutil.revsingle(repo, rev)
794 ctx = scmutil.revsingle(repo, rev)
795 node = ctx.node()
795 node = ctx.node()
796
796
797 op1, op2 = repo.dirstate.parents()
797 op1, op2 = repo.dirstate.parents()
798 if not repo.changelog.isancestor(node, op1):
798 if not repo.changelog.isancestor(node, op1):
799 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
799 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
800
800
801 p1, p2 = repo.changelog.parents(node)
801 p1, p2 = repo.changelog.parents(node)
802 if p1 == nullid:
802 if p1 == nullid:
803 raise error.Abort(_(b'cannot backout a change with no parents'))
803 raise error.Abort(_(b'cannot backout a change with no parents'))
804 if p2 != nullid:
804 if p2 != nullid:
805 if not opts.get(b'parent'):
805 if not opts.get(b'parent'):
806 raise error.Abort(_(b'cannot backout a merge changeset'))
806 raise error.Abort(_(b'cannot backout a merge changeset'))
807 p = repo.lookup(opts[b'parent'])
807 p = repo.lookup(opts[b'parent'])
808 if p not in (p1, p2):
808 if p not in (p1, p2):
809 raise error.Abort(
809 raise error.Abort(
810 _(b'%s is not a parent of %s') % (short(p), short(node))
810 _(b'%s is not a parent of %s') % (short(p), short(node))
811 )
811 )
812 parent = p
812 parent = p
813 else:
813 else:
814 if opts.get(b'parent'):
814 if opts.get(b'parent'):
815 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
815 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
816 parent = p1
816 parent = p1
817
817
818 # the backout should appear on the same branch
818 # the backout should appear on the same branch
819 branch = repo.dirstate.branch()
819 branch = repo.dirstate.branch()
820 bheads = repo.branchheads(branch)
820 bheads = repo.branchheads(branch)
821 rctx = scmutil.revsingle(repo, hex(parent))
821 rctx = scmutil.revsingle(repo, hex(parent))
822 if not opts.get(b'merge') and op1 != node:
822 if not opts.get(b'merge') and op1 != node:
823 with dirstateguard.dirstateguard(repo, b'backout'):
823 with dirstateguard.dirstateguard(repo, b'backout'):
824 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
824 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
825 with ui.configoverride(overrides, b'backout'):
825 with ui.configoverride(overrides, b'backout'):
826 stats = mergemod.back_out(ctx, parent=repo[parent])
826 stats = mergemod.back_out(ctx, parent=repo[parent])
827 repo.setparents(op1, op2)
827 repo.setparents(op1, op2)
828 hg._showstats(repo, stats)
828 hg._showstats(repo, stats)
829 if stats.unresolvedcount:
829 if stats.unresolvedcount:
830 repo.ui.status(
830 repo.ui.status(
831 _(b"use 'hg resolve' to retry unresolved file merges\n")
831 _(b"use 'hg resolve' to retry unresolved file merges\n")
832 )
832 )
833 return 1
833 return 1
834 else:
834 else:
835 hg.clean(repo, node, show_stats=False)
835 hg.clean(repo, node, show_stats=False)
836 repo.dirstate.setbranch(branch)
836 repo.dirstate.setbranch(branch)
837 cmdutil.revert(ui, repo, rctx)
837 cmdutil.revert(ui, repo, rctx)
838
838
839 if opts.get(b'no_commit'):
839 if opts.get(b'no_commit'):
840 msg = _(b"changeset %s backed out, don't forget to commit.\n")
840 msg = _(b"changeset %s backed out, don't forget to commit.\n")
841 ui.status(msg % short(node))
841 ui.status(msg % short(node))
842 return 0
842 return 0
843
843
844 def commitfunc(ui, repo, message, match, opts):
844 def commitfunc(ui, repo, message, match, opts):
845 editform = b'backout'
845 editform = b'backout'
846 e = cmdutil.getcommiteditor(
846 e = cmdutil.getcommiteditor(
847 editform=editform, **pycompat.strkwargs(opts)
847 editform=editform, **pycompat.strkwargs(opts)
848 )
848 )
849 if not message:
849 if not message:
850 # we don't translate commit messages
850 # we don't translate commit messages
851 message = b"Backed out changeset %s" % short(node)
851 message = b"Backed out changeset %s" % short(node)
852 e = cmdutil.getcommiteditor(edit=True, editform=editform)
852 e = cmdutil.getcommiteditor(edit=True, editform=editform)
853 return repo.commit(
853 return repo.commit(
854 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
854 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
855 )
855 )
856
856
857 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
857 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
858 if not newnode:
858 if not newnode:
859 ui.status(_(b"nothing changed\n"))
859 ui.status(_(b"nothing changed\n"))
860 return 1
860 return 1
861 cmdutil.commitstatus(repo, newnode, branch, bheads)
861 cmdutil.commitstatus(repo, newnode, branch, bheads)
862
862
863 def nice(node):
863 def nice(node):
864 return b'%d:%s' % (repo.changelog.rev(node), short(node))
864 return b'%d:%s' % (repo.changelog.rev(node), short(node))
865
865
866 ui.status(
866 ui.status(
867 _(b'changeset %s backs out changeset %s\n')
867 _(b'changeset %s backs out changeset %s\n')
868 % (nice(repo.changelog.tip()), nice(node))
868 % (nice(repo.changelog.tip()), nice(node))
869 )
869 )
870 if opts.get(b'merge') and op1 != node:
870 if opts.get(b'merge') and op1 != node:
871 hg.clean(repo, op1, show_stats=False)
871 hg.clean(repo, op1, show_stats=False)
872 ui.status(
872 ui.status(
873 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
873 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
874 )
874 )
875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
876 with ui.configoverride(overrides, b'backout'):
876 with ui.configoverride(overrides, b'backout'):
877 return hg.merge(repo[b'tip'])
877 return hg.merge(repo[b'tip'])
878 return 0
878 return 0
879
879
880
880
881 @command(
881 @command(
882 b'bisect',
882 b'bisect',
883 [
883 [
884 (b'r', b'reset', False, _(b'reset bisect state')),
884 (b'r', b'reset', False, _(b'reset bisect state')),
885 (b'g', b'good', False, _(b'mark changeset good')),
885 (b'g', b'good', False, _(b'mark changeset good')),
886 (b'b', b'bad', False, _(b'mark changeset bad')),
886 (b'b', b'bad', False, _(b'mark changeset bad')),
887 (b's', b'skip', False, _(b'skip testing changeset')),
887 (b's', b'skip', False, _(b'skip testing changeset')),
888 (b'e', b'extend', False, _(b'extend the bisect range')),
888 (b'e', b'extend', False, _(b'extend the bisect range')),
889 (
889 (
890 b'c',
890 b'c',
891 b'command',
891 b'command',
892 b'',
892 b'',
893 _(b'use command to check changeset state'),
893 _(b'use command to check changeset state'),
894 _(b'CMD'),
894 _(b'CMD'),
895 ),
895 ),
896 (b'U', b'noupdate', False, _(b'do not update to target')),
896 (b'U', b'noupdate', False, _(b'do not update to target')),
897 ],
897 ],
898 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
898 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
899 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
899 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
900 )
900 )
901 def bisect(
901 def bisect(
902 ui,
902 ui,
903 repo,
903 repo,
904 rev=None,
904 rev=None,
905 extra=None,
905 extra=None,
906 command=None,
906 command=None,
907 reset=None,
907 reset=None,
908 good=None,
908 good=None,
909 bad=None,
909 bad=None,
910 skip=None,
910 skip=None,
911 extend=None,
911 extend=None,
912 noupdate=None,
912 noupdate=None,
913 ):
913 ):
914 """subdivision search of changesets
914 """subdivision search of changesets
915
915
916 This command helps to find changesets which introduce problems. To
916 This command helps to find changesets which introduce problems. To
917 use, mark the earliest changeset you know exhibits the problem as
917 use, mark the earliest changeset you know exhibits the problem as
918 bad, then mark the latest changeset which is free from the problem
918 bad, then mark the latest changeset which is free from the problem
919 as good. Bisect will update your working directory to a revision
919 as good. Bisect will update your working directory to a revision
920 for testing (unless the -U/--noupdate option is specified). Once
920 for testing (unless the -U/--noupdate option is specified). Once
921 you have performed tests, mark the working directory as good or
921 you have performed tests, mark the working directory as good or
922 bad, and bisect will either update to another candidate changeset
922 bad, and bisect will either update to another candidate changeset
923 or announce that it has found the bad revision.
923 or announce that it has found the bad revision.
924
924
925 As a shortcut, you can also use the revision argument to mark a
925 As a shortcut, you can also use the revision argument to mark a
926 revision as good or bad without checking it out first.
926 revision as good or bad without checking it out first.
927
927
928 If you supply a command, it will be used for automatic bisection.
928 If you supply a command, it will be used for automatic bisection.
929 The environment variable HG_NODE will contain the ID of the
929 The environment variable HG_NODE will contain the ID of the
930 changeset being tested. The exit status of the command will be
930 changeset being tested. The exit status of the command will be
931 used to mark revisions as good or bad: status 0 means good, 125
931 used to mark revisions as good or bad: status 0 means good, 125
932 means to skip the revision, 127 (command not found) will abort the
932 means to skip the revision, 127 (command not found) will abort the
933 bisection, and any other non-zero exit status means the revision
933 bisection, and any other non-zero exit status means the revision
934 is bad.
934 is bad.
935
935
936 .. container:: verbose
936 .. container:: verbose
937
937
938 Some examples:
938 Some examples:
939
939
940 - start a bisection with known bad revision 34, and good revision 12::
940 - start a bisection with known bad revision 34, and good revision 12::
941
941
942 hg bisect --bad 34
942 hg bisect --bad 34
943 hg bisect --good 12
943 hg bisect --good 12
944
944
945 - advance the current bisection by marking current revision as good or
945 - advance the current bisection by marking current revision as good or
946 bad::
946 bad::
947
947
948 hg bisect --good
948 hg bisect --good
949 hg bisect --bad
949 hg bisect --bad
950
950
951 - mark the current revision, or a known revision, to be skipped (e.g. if
951 - mark the current revision, or a known revision, to be skipped (e.g. if
952 that revision is not usable because of another issue)::
952 that revision is not usable because of another issue)::
953
953
954 hg bisect --skip
954 hg bisect --skip
955 hg bisect --skip 23
955 hg bisect --skip 23
956
956
957 - skip all revisions that do not touch directories ``foo`` or ``bar``::
957 - skip all revisions that do not touch directories ``foo`` or ``bar``::
958
958
959 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
959 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
960
960
961 - forget the current bisection::
961 - forget the current bisection::
962
962
963 hg bisect --reset
963 hg bisect --reset
964
964
965 - use 'make && make tests' to automatically find the first broken
965 - use 'make && make tests' to automatically find the first broken
966 revision::
966 revision::
967
967
968 hg bisect --reset
968 hg bisect --reset
969 hg bisect --bad 34
969 hg bisect --bad 34
970 hg bisect --good 12
970 hg bisect --good 12
971 hg bisect --command "make && make tests"
971 hg bisect --command "make && make tests"
972
972
973 - see all changesets whose states are already known in the current
973 - see all changesets whose states are already known in the current
974 bisection::
974 bisection::
975
975
976 hg log -r "bisect(pruned)"
976 hg log -r "bisect(pruned)"
977
977
978 - see the changeset currently being bisected (especially useful
978 - see the changeset currently being bisected (especially useful
979 if running with -U/--noupdate)::
979 if running with -U/--noupdate)::
980
980
981 hg log -r "bisect(current)"
981 hg log -r "bisect(current)"
982
982
983 - see all changesets that took part in the current bisection::
983 - see all changesets that took part in the current bisection::
984
984
985 hg log -r "bisect(range)"
985 hg log -r "bisect(range)"
986
986
987 - you can even get a nice graph::
987 - you can even get a nice graph::
988
988
989 hg log --graph -r "bisect(range)"
989 hg log --graph -r "bisect(range)"
990
990
991 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
991 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
992
992
993 Returns 0 on success.
993 Returns 0 on success.
994 """
994 """
995 # backward compatibility
995 # backward compatibility
996 if rev in b"good bad reset init".split():
996 if rev in b"good bad reset init".split():
997 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
997 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
998 cmd, rev, extra = rev, extra, None
998 cmd, rev, extra = rev, extra, None
999 if cmd == b"good":
999 if cmd == b"good":
1000 good = True
1000 good = True
1001 elif cmd == b"bad":
1001 elif cmd == b"bad":
1002 bad = True
1002 bad = True
1003 else:
1003 else:
1004 reset = True
1004 reset = True
1005 elif extra:
1005 elif extra:
1006 raise error.Abort(_(b'incompatible arguments'))
1006 raise error.Abort(_(b'incompatible arguments'))
1007
1007
1008 incompatibles = {
1008 incompatibles = {
1009 b'--bad': bad,
1009 b'--bad': bad,
1010 b'--command': bool(command),
1010 b'--command': bool(command),
1011 b'--extend': extend,
1011 b'--extend': extend,
1012 b'--good': good,
1012 b'--good': good,
1013 b'--reset': reset,
1013 b'--reset': reset,
1014 b'--skip': skip,
1014 b'--skip': skip,
1015 }
1015 }
1016
1016
1017 enabled = [x for x in incompatibles if incompatibles[x]]
1017 enabled = [x for x in incompatibles if incompatibles[x]]
1018
1018
1019 if len(enabled) > 1:
1019 if len(enabled) > 1:
1020 raise error.Abort(
1020 raise error.Abort(
1021 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1021 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1022 )
1022 )
1023
1023
1024 if reset:
1024 if reset:
1025 hbisect.resetstate(repo)
1025 hbisect.resetstate(repo)
1026 return
1026 return
1027
1027
1028 state = hbisect.load_state(repo)
1028 state = hbisect.load_state(repo)
1029
1029
1030 # update state
1030 # update state
1031 if good or bad or skip:
1031 if good or bad or skip:
1032 if rev:
1032 if rev:
1033 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1033 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1034 else:
1034 else:
1035 nodes = [repo.lookup(b'.')]
1035 nodes = [repo.lookup(b'.')]
1036 if good:
1036 if good:
1037 state[b'good'] += nodes
1037 state[b'good'] += nodes
1038 elif bad:
1038 elif bad:
1039 state[b'bad'] += nodes
1039 state[b'bad'] += nodes
1040 elif skip:
1040 elif skip:
1041 state[b'skip'] += nodes
1041 state[b'skip'] += nodes
1042 hbisect.save_state(repo, state)
1042 hbisect.save_state(repo, state)
1043 if not (state[b'good'] and state[b'bad']):
1043 if not (state[b'good'] and state[b'bad']):
1044 return
1044 return
1045
1045
1046 def mayupdate(repo, node, show_stats=True):
1046 def mayupdate(repo, node, show_stats=True):
1047 """common used update sequence"""
1047 """common used update sequence"""
1048 if noupdate:
1048 if noupdate:
1049 return
1049 return
1050 cmdutil.checkunfinished(repo)
1050 cmdutil.checkunfinished(repo)
1051 cmdutil.bailifchanged(repo)
1051 cmdutil.bailifchanged(repo)
1052 return hg.clean(repo, node, show_stats=show_stats)
1052 return hg.clean(repo, node, show_stats=show_stats)
1053
1053
1054 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1054 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1055
1055
1056 if command:
1056 if command:
1057 changesets = 1
1057 changesets = 1
1058 if noupdate:
1058 if noupdate:
1059 try:
1059 try:
1060 node = state[b'current'][0]
1060 node = state[b'current'][0]
1061 except LookupError:
1061 except LookupError:
1062 raise error.Abort(
1062 raise error.Abort(
1063 _(
1063 _(
1064 b'current bisect revision is unknown - '
1064 b'current bisect revision is unknown - '
1065 b'start a new bisect to fix'
1065 b'start a new bisect to fix'
1066 )
1066 )
1067 )
1067 )
1068 else:
1068 else:
1069 node, p2 = repo.dirstate.parents()
1069 node, p2 = repo.dirstate.parents()
1070 if p2 != nullid:
1070 if p2 != nullid:
1071 raise error.Abort(_(b'current bisect revision is a merge'))
1071 raise error.Abort(_(b'current bisect revision is a merge'))
1072 if rev:
1072 if rev:
1073 node = repo[scmutil.revsingle(repo, rev, node)].node()
1073 node = repo[scmutil.revsingle(repo, rev, node)].node()
1074 with hbisect.restore_state(repo, state, node):
1074 with hbisect.restore_state(repo, state, node):
1075 while changesets:
1075 while changesets:
1076 # update state
1076 # update state
1077 state[b'current'] = [node]
1077 state[b'current'] = [node]
1078 hbisect.save_state(repo, state)
1078 hbisect.save_state(repo, state)
1079 status = ui.system(
1079 status = ui.system(
1080 command,
1080 command,
1081 environ={b'HG_NODE': hex(node)},
1081 environ={b'HG_NODE': hex(node)},
1082 blockedtag=b'bisect_check',
1082 blockedtag=b'bisect_check',
1083 )
1083 )
1084 if status == 125:
1084 if status == 125:
1085 transition = b"skip"
1085 transition = b"skip"
1086 elif status == 0:
1086 elif status == 0:
1087 transition = b"good"
1087 transition = b"good"
1088 # status < 0 means process was killed
1088 # status < 0 means process was killed
1089 elif status == 127:
1089 elif status == 127:
1090 raise error.Abort(_(b"failed to execute %s") % command)
1090 raise error.Abort(_(b"failed to execute %s") % command)
1091 elif status < 0:
1091 elif status < 0:
1092 raise error.Abort(_(b"%s killed") % command)
1092 raise error.Abort(_(b"%s killed") % command)
1093 else:
1093 else:
1094 transition = b"bad"
1094 transition = b"bad"
1095 state[transition].append(node)
1095 state[transition].append(node)
1096 ctx = repo[node]
1096 ctx = repo[node]
1097 ui.status(
1097 ui.status(
1098 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1098 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1099 )
1099 )
1100 hbisect.checkstate(state)
1100 hbisect.checkstate(state)
1101 # bisect
1101 # bisect
1102 nodes, changesets, bgood = hbisect.bisect(repo, state)
1102 nodes, changesets, bgood = hbisect.bisect(repo, state)
1103 # update to next check
1103 # update to next check
1104 node = nodes[0]
1104 node = nodes[0]
1105 mayupdate(repo, node, show_stats=False)
1105 mayupdate(repo, node, show_stats=False)
1106 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1106 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1107 return
1107 return
1108
1108
1109 hbisect.checkstate(state)
1109 hbisect.checkstate(state)
1110
1110
1111 # actually bisect
1111 # actually bisect
1112 nodes, changesets, good = hbisect.bisect(repo, state)
1112 nodes, changesets, good = hbisect.bisect(repo, state)
1113 if extend:
1113 if extend:
1114 if not changesets:
1114 if not changesets:
1115 extendnode = hbisect.extendrange(repo, state, nodes, good)
1115 extendnode = hbisect.extendrange(repo, state, nodes, good)
1116 if extendnode is not None:
1116 if extendnode is not None:
1117 ui.write(
1117 ui.write(
1118 _(b"Extending search to changeset %d:%s\n")
1118 _(b"Extending search to changeset %d:%s\n")
1119 % (extendnode.rev(), extendnode)
1119 % (extendnode.rev(), extendnode)
1120 )
1120 )
1121 state[b'current'] = [extendnode.node()]
1121 state[b'current'] = [extendnode.node()]
1122 hbisect.save_state(repo, state)
1122 hbisect.save_state(repo, state)
1123 return mayupdate(repo, extendnode.node())
1123 return mayupdate(repo, extendnode.node())
1124 raise error.Abort(_(b"nothing to extend"))
1124 raise error.Abort(_(b"nothing to extend"))
1125
1125
1126 if changesets == 0:
1126 if changesets == 0:
1127 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1127 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1128 else:
1128 else:
1129 assert len(nodes) == 1 # only a single node can be tested next
1129 assert len(nodes) == 1 # only a single node can be tested next
1130 node = nodes[0]
1130 node = nodes[0]
1131 # compute the approximate number of remaining tests
1131 # compute the approximate number of remaining tests
1132 tests, size = 0, 2
1132 tests, size = 0, 2
1133 while size <= changesets:
1133 while size <= changesets:
1134 tests, size = tests + 1, size * 2
1134 tests, size = tests + 1, size * 2
1135 rev = repo.changelog.rev(node)
1135 rev = repo.changelog.rev(node)
1136 ui.write(
1136 ui.write(
1137 _(
1137 _(
1138 b"Testing changeset %d:%s "
1138 b"Testing changeset %d:%s "
1139 b"(%d changesets remaining, ~%d tests)\n"
1139 b"(%d changesets remaining, ~%d tests)\n"
1140 )
1140 )
1141 % (rev, short(node), changesets, tests)
1141 % (rev, short(node), changesets, tests)
1142 )
1142 )
1143 state[b'current'] = [node]
1143 state[b'current'] = [node]
1144 hbisect.save_state(repo, state)
1144 hbisect.save_state(repo, state)
1145 return mayupdate(repo, node)
1145 return mayupdate(repo, node)
1146
1146
1147
1147
1148 @command(
1148 @command(
1149 b'bookmarks|bookmark',
1149 b'bookmarks|bookmark',
1150 [
1150 [
1151 (b'f', b'force', False, _(b'force')),
1151 (b'f', b'force', False, _(b'force')),
1152 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1152 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1153 (b'd', b'delete', False, _(b'delete a given bookmark')),
1153 (b'd', b'delete', False, _(b'delete a given bookmark')),
1154 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1154 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1155 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1155 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1156 (b'l', b'list', False, _(b'list existing bookmarks')),
1156 (b'l', b'list', False, _(b'list existing bookmarks')),
1157 ]
1157 ]
1158 + formatteropts,
1158 + formatteropts,
1159 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1159 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1160 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1160 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1161 )
1161 )
1162 def bookmark(ui, repo, *names, **opts):
1162 def bookmark(ui, repo, *names, **opts):
1163 '''create a new bookmark or list existing bookmarks
1163 '''create a new bookmark or list existing bookmarks
1164
1164
1165 Bookmarks are labels on changesets to help track lines of development.
1165 Bookmarks are labels on changesets to help track lines of development.
1166 Bookmarks are unversioned and can be moved, renamed and deleted.
1166 Bookmarks are unversioned and can be moved, renamed and deleted.
1167 Deleting or moving a bookmark has no effect on the associated changesets.
1167 Deleting or moving a bookmark has no effect on the associated changesets.
1168
1168
1169 Creating or updating to a bookmark causes it to be marked as 'active'.
1169 Creating or updating to a bookmark causes it to be marked as 'active'.
1170 The active bookmark is indicated with a '*'.
1170 The active bookmark is indicated with a '*'.
1171 When a commit is made, the active bookmark will advance to the new commit.
1171 When a commit is made, the active bookmark will advance to the new commit.
1172 A plain :hg:`update` will also advance an active bookmark, if possible.
1172 A plain :hg:`update` will also advance an active bookmark, if possible.
1173 Updating away from a bookmark will cause it to be deactivated.
1173 Updating away from a bookmark will cause it to be deactivated.
1174
1174
1175 Bookmarks can be pushed and pulled between repositories (see
1175 Bookmarks can be pushed and pulled between repositories (see
1176 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1176 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1177 diverged, a new 'divergent bookmark' of the form 'name@path' will
1177 diverged, a new 'divergent bookmark' of the form 'name@path' will
1178 be created. Using :hg:`merge` will resolve the divergence.
1178 be created. Using :hg:`merge` will resolve the divergence.
1179
1179
1180 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1180 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1181 the active bookmark's name.
1181 the active bookmark's name.
1182
1182
1183 A bookmark named '@' has the special property that :hg:`clone` will
1183 A bookmark named '@' has the special property that :hg:`clone` will
1184 check it out by default if it exists.
1184 check it out by default if it exists.
1185
1185
1186 .. container:: verbose
1186 .. container:: verbose
1187
1187
1188 Template:
1188 Template:
1189
1189
1190 The following keywords are supported in addition to the common template
1190 The following keywords are supported in addition to the common template
1191 keywords and functions such as ``{bookmark}``. See also
1191 keywords and functions such as ``{bookmark}``. See also
1192 :hg:`help templates`.
1192 :hg:`help templates`.
1193
1193
1194 :active: Boolean. True if the bookmark is active.
1194 :active: Boolean. True if the bookmark is active.
1195
1195
1196 Examples:
1196 Examples:
1197
1197
1198 - create an active bookmark for a new line of development::
1198 - create an active bookmark for a new line of development::
1199
1199
1200 hg book new-feature
1200 hg book new-feature
1201
1201
1202 - create an inactive bookmark as a place marker::
1202 - create an inactive bookmark as a place marker::
1203
1203
1204 hg book -i reviewed
1204 hg book -i reviewed
1205
1205
1206 - create an inactive bookmark on another changeset::
1206 - create an inactive bookmark on another changeset::
1207
1207
1208 hg book -r .^ tested
1208 hg book -r .^ tested
1209
1209
1210 - rename bookmark turkey to dinner::
1210 - rename bookmark turkey to dinner::
1211
1211
1212 hg book -m turkey dinner
1212 hg book -m turkey dinner
1213
1213
1214 - move the '@' bookmark from another branch::
1214 - move the '@' bookmark from another branch::
1215
1215
1216 hg book -f @
1216 hg book -f @
1217
1217
1218 - print only the active bookmark name::
1218 - print only the active bookmark name::
1219
1219
1220 hg book -ql .
1220 hg book -ql .
1221 '''
1221 '''
1222 opts = pycompat.byteskwargs(opts)
1222 opts = pycompat.byteskwargs(opts)
1223 force = opts.get(b'force')
1223 force = opts.get(b'force')
1224 rev = opts.get(b'rev')
1224 rev = opts.get(b'rev')
1225 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1225 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1226
1226
1227 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1227 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1228 if action:
1228 if action:
1229 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1229 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1230 elif names or rev:
1230 elif names or rev:
1231 action = b'add'
1231 action = b'add'
1232 elif inactive:
1232 elif inactive:
1233 action = b'inactive' # meaning deactivate
1233 action = b'inactive' # meaning deactivate
1234 else:
1234 else:
1235 action = b'list'
1235 action = b'list'
1236
1236
1237 cmdutil.check_incompatible_arguments(
1237 cmdutil.check_incompatible_arguments(
1238 opts, b'inactive', [b'delete', b'list']
1238 opts, b'inactive', [b'delete', b'list']
1239 )
1239 )
1240 if not names and action in {b'add', b'delete'}:
1240 if not names and action in {b'add', b'delete'}:
1241 raise error.Abort(_(b"bookmark name required"))
1241 raise error.Abort(_(b"bookmark name required"))
1242
1242
1243 if action in {b'add', b'delete', b'rename', b'inactive'}:
1243 if action in {b'add', b'delete', b'rename', b'inactive'}:
1244 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1244 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1245 if action == b'delete':
1245 if action == b'delete':
1246 names = pycompat.maplist(repo._bookmarks.expandname, names)
1246 names = pycompat.maplist(repo._bookmarks.expandname, names)
1247 bookmarks.delete(repo, tr, names)
1247 bookmarks.delete(repo, tr, names)
1248 elif action == b'rename':
1248 elif action == b'rename':
1249 if not names:
1249 if not names:
1250 raise error.Abort(_(b"new bookmark name required"))
1250 raise error.Abort(_(b"new bookmark name required"))
1251 elif len(names) > 1:
1251 elif len(names) > 1:
1252 raise error.Abort(_(b"only one new bookmark name allowed"))
1252 raise error.Abort(_(b"only one new bookmark name allowed"))
1253 oldname = repo._bookmarks.expandname(opts[b'rename'])
1253 oldname = repo._bookmarks.expandname(opts[b'rename'])
1254 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1254 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1255 elif action == b'add':
1255 elif action == b'add':
1256 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1256 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1257 elif action == b'inactive':
1257 elif action == b'inactive':
1258 if len(repo._bookmarks) == 0:
1258 if len(repo._bookmarks) == 0:
1259 ui.status(_(b"no bookmarks set\n"))
1259 ui.status(_(b"no bookmarks set\n"))
1260 elif not repo._activebookmark:
1260 elif not repo._activebookmark:
1261 ui.status(_(b"no active bookmark\n"))
1261 ui.status(_(b"no active bookmark\n"))
1262 else:
1262 else:
1263 bookmarks.deactivate(repo)
1263 bookmarks.deactivate(repo)
1264 elif action == b'list':
1264 elif action == b'list':
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1266 with ui.formatter(b'bookmarks', opts) as fm:
1266 with ui.formatter(b'bookmarks', opts) as fm:
1267 bookmarks.printbookmarks(ui, repo, fm, names)
1267 bookmarks.printbookmarks(ui, repo, fm, names)
1268 else:
1268 else:
1269 raise error.ProgrammingError(b'invalid action: %s' % action)
1269 raise error.ProgrammingError(b'invalid action: %s' % action)
1270
1270
1271
1271
1272 @command(
1272 @command(
1273 b'branch',
1273 b'branch',
1274 [
1274 [
1275 (
1275 (
1276 b'f',
1276 b'f',
1277 b'force',
1277 b'force',
1278 None,
1278 None,
1279 _(b'set branch name even if it shadows an existing branch'),
1279 _(b'set branch name even if it shadows an existing branch'),
1280 ),
1280 ),
1281 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1281 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1282 (
1282 (
1283 b'r',
1283 b'r',
1284 b'rev',
1284 b'rev',
1285 [],
1285 [],
1286 _(b'change branches of the given revs (EXPERIMENTAL)'),
1286 _(b'change branches of the given revs (EXPERIMENTAL)'),
1287 ),
1287 ),
1288 ],
1288 ],
1289 _(b'[-fC] [NAME]'),
1289 _(b'[-fC] [NAME]'),
1290 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1290 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1291 )
1291 )
1292 def branch(ui, repo, label=None, **opts):
1292 def branch(ui, repo, label=None, **opts):
1293 """set or show the current branch name
1293 """set or show the current branch name
1294
1294
1295 .. note::
1295 .. note::
1296
1296
1297 Branch names are permanent and global. Use :hg:`bookmark` to create a
1297 Branch names are permanent and global. Use :hg:`bookmark` to create a
1298 light-weight bookmark instead. See :hg:`help glossary` for more
1298 light-weight bookmark instead. See :hg:`help glossary` for more
1299 information about named branches and bookmarks.
1299 information about named branches and bookmarks.
1300
1300
1301 With no argument, show the current branch name. With one argument,
1301 With no argument, show the current branch name. With one argument,
1302 set the working directory branch name (the branch will not exist
1302 set the working directory branch name (the branch will not exist
1303 in the repository until the next commit). Standard practice
1303 in the repository until the next commit). Standard practice
1304 recommends that primary development take place on the 'default'
1304 recommends that primary development take place on the 'default'
1305 branch.
1305 branch.
1306
1306
1307 Unless -f/--force is specified, branch will not let you set a
1307 Unless -f/--force is specified, branch will not let you set a
1308 branch name that already exists.
1308 branch name that already exists.
1309
1309
1310 Use -C/--clean to reset the working directory branch to that of
1310 Use -C/--clean to reset the working directory branch to that of
1311 the parent of the working directory, negating a previous branch
1311 the parent of the working directory, negating a previous branch
1312 change.
1312 change.
1313
1313
1314 Use the command :hg:`update` to switch to an existing branch. Use
1314 Use the command :hg:`update` to switch to an existing branch. Use
1315 :hg:`commit --close-branch` to mark this branch head as closed.
1315 :hg:`commit --close-branch` to mark this branch head as closed.
1316 When all heads of a branch are closed, the branch will be
1316 When all heads of a branch are closed, the branch will be
1317 considered closed.
1317 considered closed.
1318
1318
1319 Returns 0 on success.
1319 Returns 0 on success.
1320 """
1320 """
1321 opts = pycompat.byteskwargs(opts)
1321 opts = pycompat.byteskwargs(opts)
1322 revs = opts.get(b'rev')
1322 revs = opts.get(b'rev')
1323 if label:
1323 if label:
1324 label = label.strip()
1324 label = label.strip()
1325
1325
1326 if not opts.get(b'clean') and not label:
1326 if not opts.get(b'clean') and not label:
1327 if revs:
1327 if revs:
1328 raise error.Abort(_(b"no branch name specified for the revisions"))
1328 raise error.Abort(_(b"no branch name specified for the revisions"))
1329 ui.write(b"%s\n" % repo.dirstate.branch())
1329 ui.write(b"%s\n" % repo.dirstate.branch())
1330 return
1330 return
1331
1331
1332 with repo.wlock():
1332 with repo.wlock():
1333 if opts.get(b'clean'):
1333 if opts.get(b'clean'):
1334 label = repo[b'.'].branch()
1334 label = repo[b'.'].branch()
1335 repo.dirstate.setbranch(label)
1335 repo.dirstate.setbranch(label)
1336 ui.status(_(b'reset working directory to branch %s\n') % label)
1336 ui.status(_(b'reset working directory to branch %s\n') % label)
1337 elif label:
1337 elif label:
1338
1338
1339 scmutil.checknewlabel(repo, label, b'branch')
1339 scmutil.checknewlabel(repo, label, b'branch')
1340 if revs:
1340 if revs:
1341 return cmdutil.changebranch(ui, repo, revs, label, opts)
1341 return cmdutil.changebranch(ui, repo, revs, label, opts)
1342
1342
1343 if not opts.get(b'force') and label in repo.branchmap():
1343 if not opts.get(b'force') and label in repo.branchmap():
1344 if label not in [p.branch() for p in repo[None].parents()]:
1344 if label not in [p.branch() for p in repo[None].parents()]:
1345 raise error.Abort(
1345 raise error.Abort(
1346 _(b'a branch of the same name already exists'),
1346 _(b'a branch of the same name already exists'),
1347 # i18n: "it" refers to an existing branch
1347 # i18n: "it" refers to an existing branch
1348 hint=_(b"use 'hg update' to switch to it"),
1348 hint=_(b"use 'hg update' to switch to it"),
1349 )
1349 )
1350
1350
1351 repo.dirstate.setbranch(label)
1351 repo.dirstate.setbranch(label)
1352 ui.status(_(b'marked working directory as branch %s\n') % label)
1352 ui.status(_(b'marked working directory as branch %s\n') % label)
1353
1353
1354 # find any open named branches aside from default
1354 # find any open named branches aside from default
1355 for n, h, t, c in repo.branchmap().iterbranches():
1355 for n, h, t, c in repo.branchmap().iterbranches():
1356 if n != b"default" and not c:
1356 if n != b"default" and not c:
1357 return 0
1357 return 0
1358 ui.status(
1358 ui.status(
1359 _(
1359 _(
1360 b'(branches are permanent and global, '
1360 b'(branches are permanent and global, '
1361 b'did you want a bookmark?)\n'
1361 b'did you want a bookmark?)\n'
1362 )
1362 )
1363 )
1363 )
1364
1364
1365
1365
1366 @command(
1366 @command(
1367 b'branches',
1367 b'branches',
1368 [
1368 [
1369 (
1369 (
1370 b'a',
1370 b'a',
1371 b'active',
1371 b'active',
1372 False,
1372 False,
1373 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1373 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1374 ),
1374 ),
1375 (b'c', b'closed', False, _(b'show normal and closed branches')),
1375 (b'c', b'closed', False, _(b'show normal and closed branches')),
1376 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1376 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1377 ]
1377 ]
1378 + formatteropts,
1378 + formatteropts,
1379 _(b'[-c]'),
1379 _(b'[-c]'),
1380 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1380 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1381 intents={INTENT_READONLY},
1381 intents={INTENT_READONLY},
1382 )
1382 )
1383 def branches(ui, repo, active=False, closed=False, **opts):
1383 def branches(ui, repo, active=False, closed=False, **opts):
1384 """list repository named branches
1384 """list repository named branches
1385
1385
1386 List the repository's named branches, indicating which ones are
1386 List the repository's named branches, indicating which ones are
1387 inactive. If -c/--closed is specified, also list branches which have
1387 inactive. If -c/--closed is specified, also list branches which have
1388 been marked closed (see :hg:`commit --close-branch`).
1388 been marked closed (see :hg:`commit --close-branch`).
1389
1389
1390 Use the command :hg:`update` to switch to an existing branch.
1390 Use the command :hg:`update` to switch to an existing branch.
1391
1391
1392 .. container:: verbose
1392 .. container:: verbose
1393
1393
1394 Template:
1394 Template:
1395
1395
1396 The following keywords are supported in addition to the common template
1396 The following keywords are supported in addition to the common template
1397 keywords and functions such as ``{branch}``. See also
1397 keywords and functions such as ``{branch}``. See also
1398 :hg:`help templates`.
1398 :hg:`help templates`.
1399
1399
1400 :active: Boolean. True if the branch is active.
1400 :active: Boolean. True if the branch is active.
1401 :closed: Boolean. True if the branch is closed.
1401 :closed: Boolean. True if the branch is closed.
1402 :current: Boolean. True if it is the current branch.
1402 :current: Boolean. True if it is the current branch.
1403
1403
1404 Returns 0.
1404 Returns 0.
1405 """
1405 """
1406
1406
1407 opts = pycompat.byteskwargs(opts)
1407 opts = pycompat.byteskwargs(opts)
1408 revs = opts.get(b'rev')
1408 revs = opts.get(b'rev')
1409 selectedbranches = None
1409 selectedbranches = None
1410 if revs:
1410 if revs:
1411 revs = scmutil.revrange(repo, revs)
1411 revs = scmutil.revrange(repo, revs)
1412 getbi = repo.revbranchcache().branchinfo
1412 getbi = repo.revbranchcache().branchinfo
1413 selectedbranches = {getbi(r)[0] for r in revs}
1413 selectedbranches = {getbi(r)[0] for r in revs}
1414
1414
1415 ui.pager(b'branches')
1415 ui.pager(b'branches')
1416 fm = ui.formatter(b'branches', opts)
1416 fm = ui.formatter(b'branches', opts)
1417 hexfunc = fm.hexfunc
1417 hexfunc = fm.hexfunc
1418
1418
1419 allheads = set(repo.heads())
1419 allheads = set(repo.heads())
1420 branches = []
1420 branches = []
1421 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1421 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1422 if selectedbranches is not None and tag not in selectedbranches:
1422 if selectedbranches is not None and tag not in selectedbranches:
1423 continue
1423 continue
1424 isactive = False
1424 isactive = False
1425 if not isclosed:
1425 if not isclosed:
1426 openheads = set(repo.branchmap().iteropen(heads))
1426 openheads = set(repo.branchmap().iteropen(heads))
1427 isactive = bool(openheads & allheads)
1427 isactive = bool(openheads & allheads)
1428 branches.append((tag, repo[tip], isactive, not isclosed))
1428 branches.append((tag, repo[tip], isactive, not isclosed))
1429 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1429 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1430
1430
1431 for tag, ctx, isactive, isopen in branches:
1431 for tag, ctx, isactive, isopen in branches:
1432 if active and not isactive:
1432 if active and not isactive:
1433 continue
1433 continue
1434 if isactive:
1434 if isactive:
1435 label = b'branches.active'
1435 label = b'branches.active'
1436 notice = b''
1436 notice = b''
1437 elif not isopen:
1437 elif not isopen:
1438 if not closed:
1438 if not closed:
1439 continue
1439 continue
1440 label = b'branches.closed'
1440 label = b'branches.closed'
1441 notice = _(b' (closed)')
1441 notice = _(b' (closed)')
1442 else:
1442 else:
1443 label = b'branches.inactive'
1443 label = b'branches.inactive'
1444 notice = _(b' (inactive)')
1444 notice = _(b' (inactive)')
1445 current = tag == repo.dirstate.branch()
1445 current = tag == repo.dirstate.branch()
1446 if current:
1446 if current:
1447 label = b'branches.current'
1447 label = b'branches.current'
1448
1448
1449 fm.startitem()
1449 fm.startitem()
1450 fm.write(b'branch', b'%s', tag, label=label)
1450 fm.write(b'branch', b'%s', tag, label=label)
1451 rev = ctx.rev()
1451 rev = ctx.rev()
1452 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1452 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1453 fmt = b' ' * padsize + b' %d:%s'
1453 fmt = b' ' * padsize + b' %d:%s'
1454 fm.condwrite(
1454 fm.condwrite(
1455 not ui.quiet,
1455 not ui.quiet,
1456 b'rev node',
1456 b'rev node',
1457 fmt,
1457 fmt,
1458 rev,
1458 rev,
1459 hexfunc(ctx.node()),
1459 hexfunc(ctx.node()),
1460 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1460 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1461 )
1461 )
1462 fm.context(ctx=ctx)
1462 fm.context(ctx=ctx)
1463 fm.data(active=isactive, closed=not isopen, current=current)
1463 fm.data(active=isactive, closed=not isopen, current=current)
1464 if not ui.quiet:
1464 if not ui.quiet:
1465 fm.plain(notice)
1465 fm.plain(notice)
1466 fm.plain(b'\n')
1466 fm.plain(b'\n')
1467 fm.end()
1467 fm.end()
1468
1468
1469
1469
1470 @command(
1470 @command(
1471 b'bundle',
1471 b'bundle',
1472 [
1472 [
1473 (
1473 (
1474 b'f',
1474 b'f',
1475 b'force',
1475 b'force',
1476 None,
1476 None,
1477 _(b'run even when the destination is unrelated'),
1477 _(b'run even when the destination is unrelated'),
1478 ),
1478 ),
1479 (
1479 (
1480 b'r',
1480 b'r',
1481 b'rev',
1481 b'rev',
1482 [],
1482 [],
1483 _(b'a changeset intended to be added to the destination'),
1483 _(b'a changeset intended to be added to the destination'),
1484 _(b'REV'),
1484 _(b'REV'),
1485 ),
1485 ),
1486 (
1486 (
1487 b'b',
1487 b'b',
1488 b'branch',
1488 b'branch',
1489 [],
1489 [],
1490 _(b'a specific branch you would like to bundle'),
1490 _(b'a specific branch you would like to bundle'),
1491 _(b'BRANCH'),
1491 _(b'BRANCH'),
1492 ),
1492 ),
1493 (
1493 (
1494 b'',
1494 b'',
1495 b'base',
1495 b'base',
1496 [],
1496 [],
1497 _(b'a base changeset assumed to be available at the destination'),
1497 _(b'a base changeset assumed to be available at the destination'),
1498 _(b'REV'),
1498 _(b'REV'),
1499 ),
1499 ),
1500 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1500 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1501 (
1501 (
1502 b't',
1502 b't',
1503 b'type',
1503 b'type',
1504 b'bzip2',
1504 b'bzip2',
1505 _(b'bundle compression type to use'),
1505 _(b'bundle compression type to use'),
1506 _(b'TYPE'),
1506 _(b'TYPE'),
1507 ),
1507 ),
1508 ]
1508 ]
1509 + remoteopts,
1509 + remoteopts,
1510 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1510 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1511 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1511 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1512 )
1512 )
1513 def bundle(ui, repo, fname, dest=None, **opts):
1513 def bundle(ui, repo, fname, dest=None, **opts):
1514 """create a bundle file
1514 """create a bundle file
1515
1515
1516 Generate a bundle file containing data to be transferred to another
1516 Generate a bundle file containing data to be transferred to another
1517 repository.
1517 repository.
1518
1518
1519 To create a bundle containing all changesets, use -a/--all
1519 To create a bundle containing all changesets, use -a/--all
1520 (or --base null). Otherwise, hg assumes the destination will have
1520 (or --base null). Otherwise, hg assumes the destination will have
1521 all the nodes you specify with --base parameters. Otherwise, hg
1521 all the nodes you specify with --base parameters. Otherwise, hg
1522 will assume the repository has all the nodes in destination, or
1522 will assume the repository has all the nodes in destination, or
1523 default-push/default if no destination is specified, where destination
1523 default-push/default if no destination is specified, where destination
1524 is the repository you provide through DEST option.
1524 is the repository you provide through DEST option.
1525
1525
1526 You can change bundle format with the -t/--type option. See
1526 You can change bundle format with the -t/--type option. See
1527 :hg:`help bundlespec` for documentation on this format. By default,
1527 :hg:`help bundlespec` for documentation on this format. By default,
1528 the most appropriate format is used and compression defaults to
1528 the most appropriate format is used and compression defaults to
1529 bzip2.
1529 bzip2.
1530
1530
1531 The bundle file can then be transferred using conventional means
1531 The bundle file can then be transferred using conventional means
1532 and applied to another repository with the unbundle or pull
1532 and applied to another repository with the unbundle or pull
1533 command. This is useful when direct push and pull are not
1533 command. This is useful when direct push and pull are not
1534 available or when exporting an entire repository is undesirable.
1534 available or when exporting an entire repository is undesirable.
1535
1535
1536 Applying bundles preserves all changeset contents including
1536 Applying bundles preserves all changeset contents including
1537 permissions, copy/rename information, and revision history.
1537 permissions, copy/rename information, and revision history.
1538
1538
1539 Returns 0 on success, 1 if no changes found.
1539 Returns 0 on success, 1 if no changes found.
1540 """
1540 """
1541 opts = pycompat.byteskwargs(opts)
1541 opts = pycompat.byteskwargs(opts)
1542 revs = None
1542 revs = None
1543 if b'rev' in opts:
1543 if b'rev' in opts:
1544 revstrings = opts[b'rev']
1544 revstrings = opts[b'rev']
1545 revs = scmutil.revrange(repo, revstrings)
1545 revs = scmutil.revrange(repo, revstrings)
1546 if revstrings and not revs:
1546 if revstrings and not revs:
1547 raise error.Abort(_(b'no commits to bundle'))
1547 raise error.Abort(_(b'no commits to bundle'))
1548
1548
1549 bundletype = opts.get(b'type', b'bzip2').lower()
1549 bundletype = opts.get(b'type', b'bzip2').lower()
1550 try:
1550 try:
1551 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1551 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1552 except error.UnsupportedBundleSpecification as e:
1552 except error.UnsupportedBundleSpecification as e:
1553 raise error.Abort(
1553 raise error.Abort(
1554 pycompat.bytestr(e),
1554 pycompat.bytestr(e),
1555 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1555 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1556 )
1556 )
1557 cgversion = bundlespec.contentopts[b"cg.version"]
1557 cgversion = bundlespec.contentopts[b"cg.version"]
1558
1558
1559 # Packed bundles are a pseudo bundle format for now.
1559 # Packed bundles are a pseudo bundle format for now.
1560 if cgversion == b's1':
1560 if cgversion == b's1':
1561 raise error.Abort(
1561 raise error.Abort(
1562 _(b'packed bundles cannot be produced by "hg bundle"'),
1562 _(b'packed bundles cannot be produced by "hg bundle"'),
1563 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1563 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1564 )
1564 )
1565
1565
1566 if opts.get(b'all'):
1566 if opts.get(b'all'):
1567 if dest:
1567 if dest:
1568 raise error.Abort(
1568 raise error.Abort(
1569 _(b"--all is incompatible with specifying a destination")
1569 _(b"--all is incompatible with specifying a destination")
1570 )
1570 )
1571 if opts.get(b'base'):
1571 if opts.get(b'base'):
1572 ui.warn(_(b"ignoring --base because --all was specified\n"))
1572 ui.warn(_(b"ignoring --base because --all was specified\n"))
1573 base = [nullrev]
1573 base = [nullrev]
1574 else:
1574 else:
1575 base = scmutil.revrange(repo, opts.get(b'base'))
1575 base = scmutil.revrange(repo, opts.get(b'base'))
1576 if cgversion not in changegroup.supportedoutgoingversions(repo):
1576 if cgversion not in changegroup.supportedoutgoingversions(repo):
1577 raise error.Abort(
1577 raise error.Abort(
1578 _(b"repository does not support bundle version %s") % cgversion
1578 _(b"repository does not support bundle version %s") % cgversion
1579 )
1579 )
1580
1580
1581 if base:
1581 if base:
1582 if dest:
1582 if dest:
1583 raise error.Abort(
1583 raise error.Abort(
1584 _(b"--base is incompatible with specifying a destination")
1584 _(b"--base is incompatible with specifying a destination")
1585 )
1585 )
1586 common = [repo[rev].node() for rev in base]
1586 common = [repo[rev].node() for rev in base]
1587 heads = [repo[r].node() for r in revs] if revs else None
1587 heads = [repo[r].node() for r in revs] if revs else None
1588 outgoing = discovery.outgoing(repo, common, heads)
1588 outgoing = discovery.outgoing(repo, common, heads)
1589 else:
1589 else:
1590 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1590 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1591 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1591 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1592 other = hg.peer(repo, opts, dest)
1592 other = hg.peer(repo, opts, dest)
1593 revs = [repo[r].hex() for r in revs]
1593 revs = [repo[r].hex() for r in revs]
1594 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1594 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1595 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1595 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1596 outgoing = discovery.findcommonoutgoing(
1596 outgoing = discovery.findcommonoutgoing(
1597 repo,
1597 repo,
1598 other,
1598 other,
1599 onlyheads=heads,
1599 onlyheads=heads,
1600 force=opts.get(b'force'),
1600 force=opts.get(b'force'),
1601 portable=True,
1601 portable=True,
1602 )
1602 )
1603
1603
1604 if not outgoing.missing:
1604 if not outgoing.missing:
1605 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1605 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1606 return 1
1606 return 1
1607
1607
1608 if cgversion == b'01': # bundle1
1608 if cgversion == b'01': # bundle1
1609 bversion = b'HG10' + bundlespec.wirecompression
1609 bversion = b'HG10' + bundlespec.wirecompression
1610 bcompression = None
1610 bcompression = None
1611 elif cgversion in (b'02', b'03'):
1611 elif cgversion in (b'02', b'03'):
1612 bversion = b'HG20'
1612 bversion = b'HG20'
1613 bcompression = bundlespec.wirecompression
1613 bcompression = bundlespec.wirecompression
1614 else:
1614 else:
1615 raise error.ProgrammingError(
1615 raise error.ProgrammingError(
1616 b'bundle: unexpected changegroup version %s' % cgversion
1616 b'bundle: unexpected changegroup version %s' % cgversion
1617 )
1617 )
1618
1618
1619 # TODO compression options should be derived from bundlespec parsing.
1619 # TODO compression options should be derived from bundlespec parsing.
1620 # This is a temporary hack to allow adjusting bundle compression
1620 # This is a temporary hack to allow adjusting bundle compression
1621 # level without a) formalizing the bundlespec changes to declare it
1621 # level without a) formalizing the bundlespec changes to declare it
1622 # b) introducing a command flag.
1622 # b) introducing a command flag.
1623 compopts = {}
1623 compopts = {}
1624 complevel = ui.configint(
1624 complevel = ui.configint(
1625 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1625 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1626 )
1626 )
1627 if complevel is None:
1627 if complevel is None:
1628 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1628 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1629 if complevel is not None:
1629 if complevel is not None:
1630 compopts[b'level'] = complevel
1630 compopts[b'level'] = complevel
1631
1631
1632 # Allow overriding the bundling of obsmarker in phases through
1632 # Allow overriding the bundling of obsmarker in phases through
1633 # configuration while we don't have a bundle version that include them
1633 # configuration while we don't have a bundle version that include them
1634 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1634 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1635 bundlespec.contentopts[b'obsolescence'] = True
1635 bundlespec.contentopts[b'obsolescence'] = True
1636 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1636 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1637 bundlespec.contentopts[b'phases'] = True
1637 bundlespec.contentopts[b'phases'] = True
1638
1638
1639 bundle2.writenewbundle(
1639 bundle2.writenewbundle(
1640 ui,
1640 ui,
1641 repo,
1641 repo,
1642 b'bundle',
1642 b'bundle',
1643 fname,
1643 fname,
1644 bversion,
1644 bversion,
1645 outgoing,
1645 outgoing,
1646 bundlespec.contentopts,
1646 bundlespec.contentopts,
1647 compression=bcompression,
1647 compression=bcompression,
1648 compopts=compopts,
1648 compopts=compopts,
1649 )
1649 )
1650
1650
1651
1651
1652 @command(
1652 @command(
1653 b'cat',
1653 b'cat',
1654 [
1654 [
1655 (
1655 (
1656 b'o',
1656 b'o',
1657 b'output',
1657 b'output',
1658 b'',
1658 b'',
1659 _(b'print output to file with formatted name'),
1659 _(b'print output to file with formatted name'),
1660 _(b'FORMAT'),
1660 _(b'FORMAT'),
1661 ),
1661 ),
1662 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1662 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1663 (b'', b'decode', None, _(b'apply any matching decode filter')),
1663 (b'', b'decode', None, _(b'apply any matching decode filter')),
1664 ]
1664 ]
1665 + walkopts
1665 + walkopts
1666 + formatteropts,
1666 + formatteropts,
1667 _(b'[OPTION]... FILE...'),
1667 _(b'[OPTION]... FILE...'),
1668 helpcategory=command.CATEGORY_FILE_CONTENTS,
1668 helpcategory=command.CATEGORY_FILE_CONTENTS,
1669 inferrepo=True,
1669 inferrepo=True,
1670 intents={INTENT_READONLY},
1670 intents={INTENT_READONLY},
1671 )
1671 )
1672 def cat(ui, repo, file1, *pats, **opts):
1672 def cat(ui, repo, file1, *pats, **opts):
1673 """output the current or given revision of files
1673 """output the current or given revision of files
1674
1674
1675 Print the specified files as they were at the given revision. If
1675 Print the specified files as they were at the given revision. If
1676 no revision is given, the parent of the working directory is used.
1676 no revision is given, the parent of the working directory is used.
1677
1677
1678 Output may be to a file, in which case the name of the file is
1678 Output may be to a file, in which case the name of the file is
1679 given using a template string. See :hg:`help templates`. In addition
1679 given using a template string. See :hg:`help templates`. In addition
1680 to the common template keywords, the following formatting rules are
1680 to the common template keywords, the following formatting rules are
1681 supported:
1681 supported:
1682
1682
1683 :``%%``: literal "%" character
1683 :``%%``: literal "%" character
1684 :``%s``: basename of file being printed
1684 :``%s``: basename of file being printed
1685 :``%d``: dirname of file being printed, or '.' if in repository root
1685 :``%d``: dirname of file being printed, or '.' if in repository root
1686 :``%p``: root-relative path name of file being printed
1686 :``%p``: root-relative path name of file being printed
1687 :``%H``: changeset hash (40 hexadecimal digits)
1687 :``%H``: changeset hash (40 hexadecimal digits)
1688 :``%R``: changeset revision number
1688 :``%R``: changeset revision number
1689 :``%h``: short-form changeset hash (12 hexadecimal digits)
1689 :``%h``: short-form changeset hash (12 hexadecimal digits)
1690 :``%r``: zero-padded changeset revision number
1690 :``%r``: zero-padded changeset revision number
1691 :``%b``: basename of the exporting repository
1691 :``%b``: basename of the exporting repository
1692 :``\\``: literal "\\" character
1692 :``\\``: literal "\\" character
1693
1693
1694 .. container:: verbose
1694 .. container:: verbose
1695
1695
1696 Template:
1696 Template:
1697
1697
1698 The following keywords are supported in addition to the common template
1698 The following keywords are supported in addition to the common template
1699 keywords and functions. See also :hg:`help templates`.
1699 keywords and functions. See also :hg:`help templates`.
1700
1700
1701 :data: String. File content.
1701 :data: String. File content.
1702 :path: String. Repository-absolute path of the file.
1702 :path: String. Repository-absolute path of the file.
1703
1703
1704 Returns 0 on success.
1704 Returns 0 on success.
1705 """
1705 """
1706 opts = pycompat.byteskwargs(opts)
1706 opts = pycompat.byteskwargs(opts)
1707 rev = opts.get(b'rev')
1707 rev = opts.get(b'rev')
1708 if rev:
1708 if rev:
1709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1710 ctx = scmutil.revsingle(repo, rev)
1710 ctx = scmutil.revsingle(repo, rev)
1711 m = scmutil.match(ctx, (file1,) + pats, opts)
1711 m = scmutil.match(ctx, (file1,) + pats, opts)
1712 fntemplate = opts.pop(b'output', b'')
1712 fntemplate = opts.pop(b'output', b'')
1713 if cmdutil.isstdiofilename(fntemplate):
1713 if cmdutil.isstdiofilename(fntemplate):
1714 fntemplate = b''
1714 fntemplate = b''
1715
1715
1716 if fntemplate:
1716 if fntemplate:
1717 fm = formatter.nullformatter(ui, b'cat', opts)
1717 fm = formatter.nullformatter(ui, b'cat', opts)
1718 else:
1718 else:
1719 ui.pager(b'cat')
1719 ui.pager(b'cat')
1720 fm = ui.formatter(b'cat', opts)
1720 fm = ui.formatter(b'cat', opts)
1721 with fm:
1721 with fm:
1722 return cmdutil.cat(
1722 return cmdutil.cat(
1723 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1723 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1724 )
1724 )
1725
1725
1726
1726
1727 @command(
1727 @command(
1728 b'clone',
1728 b'clone',
1729 [
1729 [
1730 (
1730 (
1731 b'U',
1731 b'U',
1732 b'noupdate',
1732 b'noupdate',
1733 None,
1733 None,
1734 _(
1734 _(
1735 b'the clone will include an empty working '
1735 b'the clone will include an empty working '
1736 b'directory (only a repository)'
1736 b'directory (only a repository)'
1737 ),
1737 ),
1738 ),
1738 ),
1739 (
1739 (
1740 b'u',
1740 b'u',
1741 b'updaterev',
1741 b'updaterev',
1742 b'',
1742 b'',
1743 _(b'revision, tag, or branch to check out'),
1743 _(b'revision, tag, or branch to check out'),
1744 _(b'REV'),
1744 _(b'REV'),
1745 ),
1745 ),
1746 (
1746 (
1747 b'r',
1747 b'r',
1748 b'rev',
1748 b'rev',
1749 [],
1749 [],
1750 _(
1750 _(
1751 b'do not clone everything, but include this changeset'
1751 b'do not clone everything, but include this changeset'
1752 b' and its ancestors'
1752 b' and its ancestors'
1753 ),
1753 ),
1754 _(b'REV'),
1754 _(b'REV'),
1755 ),
1755 ),
1756 (
1756 (
1757 b'b',
1757 b'b',
1758 b'branch',
1758 b'branch',
1759 [],
1759 [],
1760 _(
1760 _(
1761 b'do not clone everything, but include this branch\'s'
1761 b'do not clone everything, but include this branch\'s'
1762 b' changesets and their ancestors'
1762 b' changesets and their ancestors'
1763 ),
1763 ),
1764 _(b'BRANCH'),
1764 _(b'BRANCH'),
1765 ),
1765 ),
1766 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1766 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1767 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1767 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1768 (b'', b'stream', None, _(b'clone with minimal data processing')),
1768 (b'', b'stream', None, _(b'clone with minimal data processing')),
1769 ]
1769 ]
1770 + remoteopts,
1770 + remoteopts,
1771 _(b'[OPTION]... SOURCE [DEST]'),
1771 _(b'[OPTION]... SOURCE [DEST]'),
1772 helpcategory=command.CATEGORY_REPO_CREATION,
1772 helpcategory=command.CATEGORY_REPO_CREATION,
1773 helpbasic=True,
1773 helpbasic=True,
1774 norepo=True,
1774 norepo=True,
1775 )
1775 )
1776 def clone(ui, source, dest=None, **opts):
1776 def clone(ui, source, dest=None, **opts):
1777 """make a copy of an existing repository
1777 """make a copy of an existing repository
1778
1778
1779 Create a copy of an existing repository in a new directory.
1779 Create a copy of an existing repository in a new directory.
1780
1780
1781 If no destination directory name is specified, it defaults to the
1781 If no destination directory name is specified, it defaults to the
1782 basename of the source.
1782 basename of the source.
1783
1783
1784 The location of the source is added to the new repository's
1784 The location of the source is added to the new repository's
1785 ``.hg/hgrc`` file, as the default to be used for future pulls.
1785 ``.hg/hgrc`` file, as the default to be used for future pulls.
1786
1786
1787 Only local paths and ``ssh://`` URLs are supported as
1787 Only local paths and ``ssh://`` URLs are supported as
1788 destinations. For ``ssh://`` destinations, no working directory or
1788 destinations. For ``ssh://`` destinations, no working directory or
1789 ``.hg/hgrc`` will be created on the remote side.
1789 ``.hg/hgrc`` will be created on the remote side.
1790
1790
1791 If the source repository has a bookmark called '@' set, that
1791 If the source repository has a bookmark called '@' set, that
1792 revision will be checked out in the new repository by default.
1792 revision will be checked out in the new repository by default.
1793
1793
1794 To check out a particular version, use -u/--update, or
1794 To check out a particular version, use -u/--update, or
1795 -U/--noupdate to create a clone with no working directory.
1795 -U/--noupdate to create a clone with no working directory.
1796
1796
1797 To pull only a subset of changesets, specify one or more revisions
1797 To pull only a subset of changesets, specify one or more revisions
1798 identifiers with -r/--rev or branches with -b/--branch. The
1798 identifiers with -r/--rev or branches with -b/--branch. The
1799 resulting clone will contain only the specified changesets and
1799 resulting clone will contain only the specified changesets and
1800 their ancestors. These options (or 'clone src#rev dest') imply
1800 their ancestors. These options (or 'clone src#rev dest') imply
1801 --pull, even for local source repositories.
1801 --pull, even for local source repositories.
1802
1802
1803 In normal clone mode, the remote normalizes repository data into a common
1803 In normal clone mode, the remote normalizes repository data into a common
1804 exchange format and the receiving end translates this data into its local
1804 exchange format and the receiving end translates this data into its local
1805 storage format. --stream activates a different clone mode that essentially
1805 storage format. --stream activates a different clone mode that essentially
1806 copies repository files from the remote with minimal data processing. This
1806 copies repository files from the remote with minimal data processing. This
1807 significantly reduces the CPU cost of a clone both remotely and locally.
1807 significantly reduces the CPU cost of a clone both remotely and locally.
1808 However, it often increases the transferred data size by 30-40%. This can
1808 However, it often increases the transferred data size by 30-40%. This can
1809 result in substantially faster clones where I/O throughput is plentiful,
1809 result in substantially faster clones where I/O throughput is plentiful,
1810 especially for larger repositories. A side-effect of --stream clones is
1810 especially for larger repositories. A side-effect of --stream clones is
1811 that storage settings and requirements on the remote are applied locally:
1811 that storage settings and requirements on the remote are applied locally:
1812 a modern client may inherit legacy or inefficient storage used by the
1812 a modern client may inherit legacy or inefficient storage used by the
1813 remote or a legacy Mercurial client may not be able to clone from a
1813 remote or a legacy Mercurial client may not be able to clone from a
1814 modern Mercurial remote.
1814 modern Mercurial remote.
1815
1815
1816 .. note::
1816 .. note::
1817
1817
1818 Specifying a tag will include the tagged changeset but not the
1818 Specifying a tag will include the tagged changeset but not the
1819 changeset containing the tag.
1819 changeset containing the tag.
1820
1820
1821 .. container:: verbose
1821 .. container:: verbose
1822
1822
1823 For efficiency, hardlinks are used for cloning whenever the
1823 For efficiency, hardlinks are used for cloning whenever the
1824 source and destination are on the same filesystem (note this
1824 source and destination are on the same filesystem (note this
1825 applies only to the repository data, not to the working
1825 applies only to the repository data, not to the working
1826 directory). Some filesystems, such as AFS, implement hardlinking
1826 directory). Some filesystems, such as AFS, implement hardlinking
1827 incorrectly, but do not report errors. In these cases, use the
1827 incorrectly, but do not report errors. In these cases, use the
1828 --pull option to avoid hardlinking.
1828 --pull option to avoid hardlinking.
1829
1829
1830 Mercurial will update the working directory to the first applicable
1830 Mercurial will update the working directory to the first applicable
1831 revision from this list:
1831 revision from this list:
1832
1832
1833 a) null if -U or the source repository has no changesets
1833 a) null if -U or the source repository has no changesets
1834 b) if -u . and the source repository is local, the first parent of
1834 b) if -u . and the source repository is local, the first parent of
1835 the source repository's working directory
1835 the source repository's working directory
1836 c) the changeset specified with -u (if a branch name, this means the
1836 c) the changeset specified with -u (if a branch name, this means the
1837 latest head of that branch)
1837 latest head of that branch)
1838 d) the changeset specified with -r
1838 d) the changeset specified with -r
1839 e) the tipmost head specified with -b
1839 e) the tipmost head specified with -b
1840 f) the tipmost head specified with the url#branch source syntax
1840 f) the tipmost head specified with the url#branch source syntax
1841 g) the revision marked with the '@' bookmark, if present
1841 g) the revision marked with the '@' bookmark, if present
1842 h) the tipmost head of the default branch
1842 h) the tipmost head of the default branch
1843 i) tip
1843 i) tip
1844
1844
1845 When cloning from servers that support it, Mercurial may fetch
1845 When cloning from servers that support it, Mercurial may fetch
1846 pre-generated data from a server-advertised URL or inline from the
1846 pre-generated data from a server-advertised URL or inline from the
1847 same stream. When this is done, hooks operating on incoming changesets
1847 same stream. When this is done, hooks operating on incoming changesets
1848 and changegroups may fire more than once, once for each pre-generated
1848 and changegroups may fire more than once, once for each pre-generated
1849 bundle and as well as for any additional remaining data. In addition,
1849 bundle and as well as for any additional remaining data. In addition,
1850 if an error occurs, the repository may be rolled back to a partial
1850 if an error occurs, the repository may be rolled back to a partial
1851 clone. This behavior may change in future releases.
1851 clone. This behavior may change in future releases.
1852 See :hg:`help -e clonebundles` for more.
1852 See :hg:`help -e clonebundles` for more.
1853
1853
1854 Examples:
1854 Examples:
1855
1855
1856 - clone a remote repository to a new directory named hg/::
1856 - clone a remote repository to a new directory named hg/::
1857
1857
1858 hg clone https://www.mercurial-scm.org/repo/hg/
1858 hg clone https://www.mercurial-scm.org/repo/hg/
1859
1859
1860 - create a lightweight local clone::
1860 - create a lightweight local clone::
1861
1861
1862 hg clone project/ project-feature/
1862 hg clone project/ project-feature/
1863
1863
1864 - clone from an absolute path on an ssh server (note double-slash)::
1864 - clone from an absolute path on an ssh server (note double-slash)::
1865
1865
1866 hg clone ssh://user@server//home/projects/alpha/
1866 hg clone ssh://user@server//home/projects/alpha/
1867
1867
1868 - do a streaming clone while checking out a specified version::
1868 - do a streaming clone while checking out a specified version::
1869
1869
1870 hg clone --stream http://server/repo -u 1.5
1870 hg clone --stream http://server/repo -u 1.5
1871
1871
1872 - create a repository without changesets after a particular revision::
1872 - create a repository without changesets after a particular revision::
1873
1873
1874 hg clone -r 04e544 experimental/ good/
1874 hg clone -r 04e544 experimental/ good/
1875
1875
1876 - clone (and track) a particular named branch::
1876 - clone (and track) a particular named branch::
1877
1877
1878 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1878 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1879
1879
1880 See :hg:`help urls` for details on specifying URLs.
1880 See :hg:`help urls` for details on specifying URLs.
1881
1881
1882 Returns 0 on success.
1882 Returns 0 on success.
1883 """
1883 """
1884 opts = pycompat.byteskwargs(opts)
1884 opts = pycompat.byteskwargs(opts)
1885 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1885 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1886
1886
1887 # --include/--exclude can come from narrow or sparse.
1887 # --include/--exclude can come from narrow or sparse.
1888 includepats, excludepats = None, None
1888 includepats, excludepats = None, None
1889
1889
1890 # hg.clone() differentiates between None and an empty set. So make sure
1890 # hg.clone() differentiates between None and an empty set. So make sure
1891 # patterns are sets if narrow is requested without patterns.
1891 # patterns are sets if narrow is requested without patterns.
1892 if opts.get(b'narrow'):
1892 if opts.get(b'narrow'):
1893 includepats = set()
1893 includepats = set()
1894 excludepats = set()
1894 excludepats = set()
1895
1895
1896 if opts.get(b'include'):
1896 if opts.get(b'include'):
1897 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1897 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1898 if opts.get(b'exclude'):
1898 if opts.get(b'exclude'):
1899 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1899 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1900
1900
1901 r = hg.clone(
1901 r = hg.clone(
1902 ui,
1902 ui,
1903 opts,
1903 opts,
1904 source,
1904 source,
1905 dest,
1905 dest,
1906 pull=opts.get(b'pull'),
1906 pull=opts.get(b'pull'),
1907 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1907 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1908 revs=opts.get(b'rev'),
1908 revs=opts.get(b'rev'),
1909 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1909 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1910 branch=opts.get(b'branch'),
1910 branch=opts.get(b'branch'),
1911 shareopts=opts.get(b'shareopts'),
1911 shareopts=opts.get(b'shareopts'),
1912 storeincludepats=includepats,
1912 storeincludepats=includepats,
1913 storeexcludepats=excludepats,
1913 storeexcludepats=excludepats,
1914 depth=opts.get(b'depth') or None,
1914 depth=opts.get(b'depth') or None,
1915 )
1915 )
1916
1916
1917 return r is None
1917 return r is None
1918
1918
1919
1919
1920 @command(
1920 @command(
1921 b'commit|ci',
1921 b'commit|ci',
1922 [
1922 [
1923 (
1923 (
1924 b'A',
1924 b'A',
1925 b'addremove',
1925 b'addremove',
1926 None,
1926 None,
1927 _(b'mark new/missing files as added/removed before committing'),
1927 _(b'mark new/missing files as added/removed before committing'),
1928 ),
1928 ),
1929 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1929 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1930 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1930 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1931 (b's', b'secret', None, _(b'use the secret phase for committing')),
1931 (b's', b'secret', None, _(b'use the secret phase for committing')),
1932 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1932 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1933 (
1933 (
1934 b'',
1934 b'',
1935 b'force-close-branch',
1935 b'force-close-branch',
1936 None,
1936 None,
1937 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1937 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1938 ),
1938 ),
1939 (b'i', b'interactive', None, _(b'use interactive mode')),
1939 (b'i', b'interactive', None, _(b'use interactive mode')),
1940 ]
1940 ]
1941 + walkopts
1941 + walkopts
1942 + commitopts
1942 + commitopts
1943 + commitopts2
1943 + commitopts2
1944 + subrepoopts,
1944 + subrepoopts,
1945 _(b'[OPTION]... [FILE]...'),
1945 _(b'[OPTION]... [FILE]...'),
1946 helpcategory=command.CATEGORY_COMMITTING,
1946 helpcategory=command.CATEGORY_COMMITTING,
1947 helpbasic=True,
1947 helpbasic=True,
1948 inferrepo=True,
1948 inferrepo=True,
1949 )
1949 )
1950 def commit(ui, repo, *pats, **opts):
1950 def commit(ui, repo, *pats, **opts):
1951 """commit the specified files or all outstanding changes
1951 """commit the specified files or all outstanding changes
1952
1952
1953 Commit changes to the given files into the repository. Unlike a
1953 Commit changes to the given files into the repository. Unlike a
1954 centralized SCM, this operation is a local operation. See
1954 centralized SCM, this operation is a local operation. See
1955 :hg:`push` for a way to actively distribute your changes.
1955 :hg:`push` for a way to actively distribute your changes.
1956
1956
1957 If a list of files is omitted, all changes reported by :hg:`status`
1957 If a list of files is omitted, all changes reported by :hg:`status`
1958 will be committed.
1958 will be committed.
1959
1959
1960 If you are committing the result of a merge, do not provide any
1960 If you are committing the result of a merge, do not provide any
1961 filenames or -I/-X filters.
1961 filenames or -I/-X filters.
1962
1962
1963 If no commit message is specified, Mercurial starts your
1963 If no commit message is specified, Mercurial starts your
1964 configured editor where you can enter a message. In case your
1964 configured editor where you can enter a message. In case your
1965 commit fails, you will find a backup of your message in
1965 commit fails, you will find a backup of your message in
1966 ``.hg/last-message.txt``.
1966 ``.hg/last-message.txt``.
1967
1967
1968 The --close-branch flag can be used to mark the current branch
1968 The --close-branch flag can be used to mark the current branch
1969 head closed. When all heads of a branch are closed, the branch
1969 head closed. When all heads of a branch are closed, the branch
1970 will be considered closed and no longer listed.
1970 will be considered closed and no longer listed.
1971
1971
1972 The --amend flag can be used to amend the parent of the
1972 The --amend flag can be used to amend the parent of the
1973 working directory with a new commit that contains the changes
1973 working directory with a new commit that contains the changes
1974 in the parent in addition to those currently reported by :hg:`status`,
1974 in the parent in addition to those currently reported by :hg:`status`,
1975 if there are any. The old commit is stored in a backup bundle in
1975 if there are any. The old commit is stored in a backup bundle in
1976 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1976 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1977 on how to restore it).
1977 on how to restore it).
1978
1978
1979 Message, user and date are taken from the amended commit unless
1979 Message, user and date are taken from the amended commit unless
1980 specified. When a message isn't specified on the command line,
1980 specified. When a message isn't specified on the command line,
1981 the editor will open with the message of the amended commit.
1981 the editor will open with the message of the amended commit.
1982
1982
1983 It is not possible to amend public changesets (see :hg:`help phases`)
1983 It is not possible to amend public changesets (see :hg:`help phases`)
1984 or changesets that have children.
1984 or changesets that have children.
1985
1985
1986 See :hg:`help dates` for a list of formats valid for -d/--date.
1986 See :hg:`help dates` for a list of formats valid for -d/--date.
1987
1987
1988 Returns 0 on success, 1 if nothing changed.
1988 Returns 0 on success, 1 if nothing changed.
1989
1989
1990 .. container:: verbose
1990 .. container:: verbose
1991
1991
1992 Examples:
1992 Examples:
1993
1993
1994 - commit all files ending in .py::
1994 - commit all files ending in .py::
1995
1995
1996 hg commit --include "set:**.py"
1996 hg commit --include "set:**.py"
1997
1997
1998 - commit all non-binary files::
1998 - commit all non-binary files::
1999
1999
2000 hg commit --exclude "set:binary()"
2000 hg commit --exclude "set:binary()"
2001
2001
2002 - amend the current commit and set the date to now::
2002 - amend the current commit and set the date to now::
2003
2003
2004 hg commit --amend --date now
2004 hg commit --amend --date now
2005 """
2005 """
2006 with repo.wlock(), repo.lock():
2006 with repo.wlock(), repo.lock():
2007 return _docommit(ui, repo, *pats, **opts)
2007 return _docommit(ui, repo, *pats, **opts)
2008
2008
2009
2009
2010 def _docommit(ui, repo, *pats, **opts):
2010 def _docommit(ui, repo, *pats, **opts):
2011 if opts.get('interactive'):
2011 if opts.get('interactive'):
2012 opts.pop('interactive')
2012 opts.pop('interactive')
2013 ret = cmdutil.dorecord(
2013 ret = cmdutil.dorecord(
2014 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2014 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2015 )
2015 )
2016 # ret can be 0 (no changes to record) or the value returned by
2016 # ret can be 0 (no changes to record) or the value returned by
2017 # commit(), 1 if nothing changed or None on success.
2017 # commit(), 1 if nothing changed or None on success.
2018 return 1 if ret == 0 else ret
2018 return 1 if ret == 0 else ret
2019
2019
2020 opts = pycompat.byteskwargs(opts)
2020 opts = pycompat.byteskwargs(opts)
2021 if opts.get(b'subrepos'):
2021 if opts.get(b'subrepos'):
2022 if opts.get(b'amend'):
2022 if opts.get(b'amend'):
2023 raise error.Abort(_(b'cannot amend with --subrepos'))
2023 raise error.Abort(_(b'cannot amend with --subrepos'))
2024 # Let --subrepos on the command line override config setting.
2024 # Let --subrepos on the command line override config setting.
2025 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2025 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2026
2026
2027 cmdutil.checkunfinished(repo, commit=True)
2027 cmdutil.checkunfinished(repo, commit=True)
2028
2028
2029 branch = repo[None].branch()
2029 branch = repo[None].branch()
2030 bheads = repo.branchheads(branch)
2030 bheads = repo.branchheads(branch)
2031
2031
2032 extra = {}
2032 extra = {}
2033 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2033 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2034 extra[b'close'] = b'1'
2034 extra[b'close'] = b'1'
2035
2035
2036 if repo[b'.'].closesbranch():
2036 if repo[b'.'].closesbranch():
2037 raise error.Abort(
2037 raise error.Abort(
2038 _(b'current revision is already a branch closing head')
2038 _(b'current revision is already a branch closing head')
2039 )
2039 )
2040 elif not bheads:
2040 elif not bheads:
2041 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2041 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2042 elif (
2042 elif (
2043 branch == repo[b'.'].branch()
2043 branch == repo[b'.'].branch()
2044 and repo[b'.'].node() not in bheads
2044 and repo[b'.'].node() not in bheads
2045 and not opts.get(b'force_close_branch')
2045 and not opts.get(b'force_close_branch')
2046 ):
2046 ):
2047 hint = _(
2047 hint = _(
2048 b'use --force-close-branch to close branch from a non-head'
2048 b'use --force-close-branch to close branch from a non-head'
2049 b' changeset'
2049 b' changeset'
2050 )
2050 )
2051 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2051 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2052 elif opts.get(b'amend'):
2052 elif opts.get(b'amend'):
2053 if (
2053 if (
2054 repo[b'.'].p1().branch() != branch
2054 repo[b'.'].p1().branch() != branch
2055 and repo[b'.'].p2().branch() != branch
2055 and repo[b'.'].p2().branch() != branch
2056 ):
2056 ):
2057 raise error.Abort(_(b'can only close branch heads'))
2057 raise error.Abort(_(b'can only close branch heads'))
2058
2058
2059 if opts.get(b'amend'):
2059 if opts.get(b'amend'):
2060 if ui.configbool(b'ui', b'commitsubrepos'):
2060 if ui.configbool(b'ui', b'commitsubrepos'):
2061 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2061 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2062
2062
2063 old = repo[b'.']
2063 old = repo[b'.']
2064 rewriteutil.precheck(repo, [old.rev()], b'amend')
2064 rewriteutil.precheck(repo, [old.rev()], b'amend')
2065
2065
2066 # Currently histedit gets confused if an amend happens while histedit
2066 # Currently histedit gets confused if an amend happens while histedit
2067 # is in progress. Since we have a checkunfinished command, we are
2067 # is in progress. Since we have a checkunfinished command, we are
2068 # temporarily honoring it.
2068 # temporarily honoring it.
2069 #
2069 #
2070 # Note: eventually this guard will be removed. Please do not expect
2070 # Note: eventually this guard will be removed. Please do not expect
2071 # this behavior to remain.
2071 # this behavior to remain.
2072 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2072 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2073 cmdutil.checkunfinished(repo)
2073 cmdutil.checkunfinished(repo)
2074
2074
2075 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2075 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2076 if node == old.node():
2076 if node == old.node():
2077 ui.status(_(b"nothing changed\n"))
2077 ui.status(_(b"nothing changed\n"))
2078 return 1
2078 return 1
2079 else:
2079 else:
2080
2080
2081 def commitfunc(ui, repo, message, match, opts):
2081 def commitfunc(ui, repo, message, match, opts):
2082 overrides = {}
2082 overrides = {}
2083 if opts.get(b'secret'):
2083 if opts.get(b'secret'):
2084 overrides[(b'phases', b'new-commit')] = b'secret'
2084 overrides[(b'phases', b'new-commit')] = b'secret'
2085
2085
2086 baseui = repo.baseui
2086 baseui = repo.baseui
2087 with baseui.configoverride(overrides, b'commit'):
2087 with baseui.configoverride(overrides, b'commit'):
2088 with ui.configoverride(overrides, b'commit'):
2088 with ui.configoverride(overrides, b'commit'):
2089 editform = cmdutil.mergeeditform(
2089 editform = cmdutil.mergeeditform(
2090 repo[None], b'commit.normal'
2090 repo[None], b'commit.normal'
2091 )
2091 )
2092 editor = cmdutil.getcommiteditor(
2092 editor = cmdutil.getcommiteditor(
2093 editform=editform, **pycompat.strkwargs(opts)
2093 editform=editform, **pycompat.strkwargs(opts)
2094 )
2094 )
2095 return repo.commit(
2095 return repo.commit(
2096 message,
2096 message,
2097 opts.get(b'user'),
2097 opts.get(b'user'),
2098 opts.get(b'date'),
2098 opts.get(b'date'),
2099 match,
2099 match,
2100 editor=editor,
2100 editor=editor,
2101 extra=extra,
2101 extra=extra,
2102 )
2102 )
2103
2103
2104 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2104 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2105
2105
2106 if not node:
2106 if not node:
2107 stat = cmdutil.postcommitstatus(repo, pats, opts)
2107 stat = cmdutil.postcommitstatus(repo, pats, opts)
2108 if stat.deleted:
2108 if stat.deleted:
2109 ui.status(
2109 ui.status(
2110 _(
2110 _(
2111 b"nothing changed (%d missing files, see "
2111 b"nothing changed (%d missing files, see "
2112 b"'hg status')\n"
2112 b"'hg status')\n"
2113 )
2113 )
2114 % len(stat.deleted)
2114 % len(stat.deleted)
2115 )
2115 )
2116 else:
2116 else:
2117 ui.status(_(b"nothing changed\n"))
2117 ui.status(_(b"nothing changed\n"))
2118 return 1
2118 return 1
2119
2119
2120 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2120 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2121
2121
2122 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2122 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2123 status(
2123 status(
2124 ui,
2124 ui,
2125 repo,
2125 repo,
2126 modified=True,
2126 modified=True,
2127 added=True,
2127 added=True,
2128 removed=True,
2128 removed=True,
2129 deleted=True,
2129 deleted=True,
2130 unknown=True,
2130 unknown=True,
2131 subrepos=opts.get(b'subrepos'),
2131 subrepos=opts.get(b'subrepos'),
2132 )
2132 )
2133
2133
2134
2134
2135 @command(
2135 @command(
2136 b'config|showconfig|debugconfig',
2136 b'config|showconfig|debugconfig',
2137 [
2137 [
2138 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2138 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2139 (b'e', b'edit', None, _(b'edit user config')),
2139 (b'e', b'edit', None, _(b'edit user config')),
2140 (b'l', b'local', None, _(b'edit repository config')),
2140 (b'l', b'local', None, _(b'edit repository config')),
2141 (
2141 (
2142 b'',
2142 b'',
2143 b'shared',
2143 b'shared',
2144 None,
2144 None,
2145 _(b'edit shared source repository config (EXPERIMENTAL)'),
2145 _(b'edit shared source repository config (EXPERIMENTAL)'),
2146 ),
2146 ),
2147 (b'g', b'global', None, _(b'edit global config')),
2147 (b'g', b'global', None, _(b'edit global config')),
2148 ]
2148 ]
2149 + formatteropts,
2149 + formatteropts,
2150 _(b'[-u] [NAME]...'),
2150 _(b'[-u] [NAME]...'),
2151 helpcategory=command.CATEGORY_HELP,
2151 helpcategory=command.CATEGORY_HELP,
2152 optionalrepo=True,
2152 optionalrepo=True,
2153 intents={INTENT_READONLY},
2153 intents={INTENT_READONLY},
2154 )
2154 )
2155 def config(ui, repo, *values, **opts):
2155 def config(ui, repo, *values, **opts):
2156 """show combined config settings from all hgrc files
2156 """show combined config settings from all hgrc files
2157
2157
2158 With no arguments, print names and values of all config items.
2158 With no arguments, print names and values of all config items.
2159
2159
2160 With one argument of the form section.name, print just the value
2160 With one argument of the form section.name, print just the value
2161 of that config item.
2161 of that config item.
2162
2162
2163 With multiple arguments, print names and values of all config
2163 With multiple arguments, print names and values of all config
2164 items with matching section names or section.names.
2164 items with matching section names or section.names.
2165
2165
2166 With --edit, start an editor on the user-level config file. With
2166 With --edit, start an editor on the user-level config file. With
2167 --global, edit the system-wide config file. With --local, edit the
2167 --global, edit the system-wide config file. With --local, edit the
2168 repository-level config file.
2168 repository-level config file.
2169
2169
2170 With --debug, the source (filename and line number) is printed
2170 With --debug, the source (filename and line number) is printed
2171 for each config item.
2171 for each config item.
2172
2172
2173 See :hg:`help config` for more information about config files.
2173 See :hg:`help config` for more information about config files.
2174
2174
2175 .. container:: verbose
2175 .. container:: verbose
2176
2176
2177 Template:
2177 Template:
2178
2178
2179 The following keywords are supported. See also :hg:`help templates`.
2179 The following keywords are supported. See also :hg:`help templates`.
2180
2180
2181 :name: String. Config name.
2181 :name: String. Config name.
2182 :source: String. Filename and line number where the item is defined.
2182 :source: String. Filename and line number where the item is defined.
2183 :value: String. Config value.
2183 :value: String. Config value.
2184
2184
2185 The --shared flag can be used to edit the config file of shared source
2185 The --shared flag can be used to edit the config file of shared source
2186 repository. It only works when you have shared using the experimental
2186 repository. It only works when you have shared using the experimental
2187 share safe feature.
2187 share safe feature.
2188
2188
2189 Returns 0 on success, 1 if NAME does not exist.
2189 Returns 0 on success, 1 if NAME does not exist.
2190
2190
2191 """
2191 """
2192
2192
2193 opts = pycompat.byteskwargs(opts)
2193 opts = pycompat.byteskwargs(opts)
2194 editopts = (b'edit', b'local', b'global', b'shared')
2194 editopts = (b'edit', b'local', b'global', b'shared')
2195 if any(opts.get(o) for o in editopts):
2195 if any(opts.get(o) for o in editopts):
2196 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2196 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2197 if opts.get(b'local'):
2197 if opts.get(b'local'):
2198 if not repo:
2198 if not repo:
2199 raise error.Abort(_(b"can't use --local outside a repository"))
2199 raise error.Abort(_(b"can't use --local outside a repository"))
2200 paths = [repo.vfs.join(b'hgrc')]
2200 paths = [repo.vfs.join(b'hgrc')]
2201 elif opts.get(b'global'):
2201 elif opts.get(b'global'):
2202 paths = rcutil.systemrcpath()
2202 paths = rcutil.systemrcpath()
2203 elif opts.get(b'shared'):
2203 elif opts.get(b'shared'):
2204 if not repo.shared():
2204 if not repo.shared():
2205 raise error.Abort(
2205 raise error.Abort(
2206 _(b"repository is not shared; can't use --shared")
2206 _(b"repository is not shared; can't use --shared")
2207 )
2207 )
2208 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2208 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2209 raise error.Abort(
2209 raise error.Abort(
2210 _(
2210 _(
2211 b"share safe feature not unabled; "
2211 b"share safe feature not unabled; "
2212 b"unable to edit shared source repository config"
2212 b"unable to edit shared source repository config"
2213 )
2213 )
2214 )
2214 )
2215 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2215 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2216 else:
2216 else:
2217 paths = rcutil.userrcpath()
2217 paths = rcutil.userrcpath()
2218
2218
2219 for f in paths:
2219 for f in paths:
2220 if os.path.exists(f):
2220 if os.path.exists(f):
2221 break
2221 break
2222 else:
2222 else:
2223 if opts.get(b'global'):
2223 if opts.get(b'global'):
2224 samplehgrc = uimod.samplehgrcs[b'global']
2224 samplehgrc = uimod.samplehgrcs[b'global']
2225 elif opts.get(b'local'):
2225 elif opts.get(b'local'):
2226 samplehgrc = uimod.samplehgrcs[b'local']
2226 samplehgrc = uimod.samplehgrcs[b'local']
2227 else:
2227 else:
2228 samplehgrc = uimod.samplehgrcs[b'user']
2228 samplehgrc = uimod.samplehgrcs[b'user']
2229
2229
2230 f = paths[0]
2230 f = paths[0]
2231 fp = open(f, b"wb")
2231 fp = open(f, b"wb")
2232 fp.write(util.tonativeeol(samplehgrc))
2232 fp.write(util.tonativeeol(samplehgrc))
2233 fp.close()
2233 fp.close()
2234
2234
2235 editor = ui.geteditor()
2235 editor = ui.geteditor()
2236 ui.system(
2236 ui.system(
2237 b"%s \"%s\"" % (editor, f),
2237 b"%s \"%s\"" % (editor, f),
2238 onerr=error.Abort,
2238 onerr=error.Abort,
2239 errprefix=_(b"edit failed"),
2239 errprefix=_(b"edit failed"),
2240 blockedtag=b'config_edit',
2240 blockedtag=b'config_edit',
2241 )
2241 )
2242 return
2242 return
2243 ui.pager(b'config')
2243 ui.pager(b'config')
2244 fm = ui.formatter(b'config', opts)
2244 fm = ui.formatter(b'config', opts)
2245 for t, f in rcutil.rccomponents():
2245 for t, f in rcutil.rccomponents():
2246 if t == b'path':
2246 if t == b'path':
2247 ui.debug(b'read config from: %s\n' % f)
2247 ui.debug(b'read config from: %s\n' % f)
2248 elif t == b'resource':
2248 elif t == b'resource':
2249 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2249 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2250 elif t == b'items':
2250 elif t == b'items':
2251 # Don't print anything for 'items'.
2251 # Don't print anything for 'items'.
2252 pass
2252 pass
2253 else:
2253 else:
2254 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2254 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2255 untrusted = bool(opts.get(b'untrusted'))
2255 untrusted = bool(opts.get(b'untrusted'))
2256
2256
2257 selsections = selentries = []
2257 selsections = selentries = []
2258 if values:
2258 if values:
2259 selsections = [v for v in values if b'.' not in v]
2259 selsections = [v for v in values if b'.' not in v]
2260 selentries = [v for v in values if b'.' in v]
2260 selentries = [v for v in values if b'.' in v]
2261 uniquesel = len(selentries) == 1 and not selsections
2261 uniquesel = len(selentries) == 1 and not selsections
2262 selsections = set(selsections)
2262 selsections = set(selsections)
2263 selentries = set(selentries)
2263 selentries = set(selentries)
2264
2264
2265 matched = False
2265 matched = False
2266 for section, name, value in ui.walkconfig(untrusted=untrusted):
2266 for section, name, value in ui.walkconfig(untrusted=untrusted):
2267 source = ui.configsource(section, name, untrusted)
2267 source = ui.configsource(section, name, untrusted)
2268 value = pycompat.bytestr(value)
2268 value = pycompat.bytestr(value)
2269 defaultvalue = ui.configdefault(section, name)
2269 defaultvalue = ui.configdefault(section, name)
2270 if fm.isplain():
2270 if fm.isplain():
2271 source = source or b'none'
2271 source = source or b'none'
2272 value = value.replace(b'\n', b'\\n')
2272 value = value.replace(b'\n', b'\\n')
2273 entryname = section + b'.' + name
2273 entryname = section + b'.' + name
2274 if values and not (section in selsections or entryname in selentries):
2274 if values and not (section in selsections or entryname in selentries):
2275 continue
2275 continue
2276 fm.startitem()
2276 fm.startitem()
2277 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2277 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2278 if uniquesel:
2278 if uniquesel:
2279 fm.data(name=entryname)
2279 fm.data(name=entryname)
2280 fm.write(b'value', b'%s\n', value)
2280 fm.write(b'value', b'%s\n', value)
2281 else:
2281 else:
2282 fm.write(b'name value', b'%s=%s\n', entryname, value)
2282 fm.write(b'name value', b'%s=%s\n', entryname, value)
2283 if formatter.isprintable(defaultvalue):
2283 if formatter.isprintable(defaultvalue):
2284 fm.data(defaultvalue=defaultvalue)
2284 fm.data(defaultvalue=defaultvalue)
2285 elif isinstance(defaultvalue, list) and all(
2285 elif isinstance(defaultvalue, list) and all(
2286 formatter.isprintable(e) for e in defaultvalue
2286 formatter.isprintable(e) for e in defaultvalue
2287 ):
2287 ):
2288 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2288 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2289 # TODO: no idea how to process unsupported defaultvalue types
2289 # TODO: no idea how to process unsupported defaultvalue types
2290 matched = True
2290 matched = True
2291 fm.end()
2291 fm.end()
2292 if matched:
2292 if matched:
2293 return 0
2293 return 0
2294 return 1
2294 return 1
2295
2295
2296
2296
2297 @command(
2297 @command(
2298 b'continue',
2298 b'continue',
2299 dryrunopts,
2299 dryrunopts,
2300 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2300 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2301 helpbasic=True,
2301 helpbasic=True,
2302 )
2302 )
2303 def continuecmd(ui, repo, **opts):
2303 def continuecmd(ui, repo, **opts):
2304 """resumes an interrupted operation (EXPERIMENTAL)
2304 """resumes an interrupted operation (EXPERIMENTAL)
2305
2305
2306 Finishes a multistep operation like graft, histedit, rebase, merge,
2306 Finishes a multistep operation like graft, histedit, rebase, merge,
2307 and unshelve if they are in an interrupted state.
2307 and unshelve if they are in an interrupted state.
2308
2308
2309 use --dry-run/-n to dry run the command.
2309 use --dry-run/-n to dry run the command.
2310 """
2310 """
2311 dryrun = opts.get('dry_run')
2311 dryrun = opts.get('dry_run')
2312 contstate = cmdutil.getunfinishedstate(repo)
2312 contstate = cmdutil.getunfinishedstate(repo)
2313 if not contstate:
2313 if not contstate:
2314 raise error.Abort(_(b'no operation in progress'))
2314 raise error.Abort(_(b'no operation in progress'))
2315 if not contstate.continuefunc:
2315 if not contstate.continuefunc:
2316 raise error.Abort(
2316 raise error.Abort(
2317 (
2317 (
2318 _(b"%s in progress but does not support 'hg continue'")
2318 _(b"%s in progress but does not support 'hg continue'")
2319 % (contstate._opname)
2319 % (contstate._opname)
2320 ),
2320 ),
2321 hint=contstate.continuemsg(),
2321 hint=contstate.continuemsg(),
2322 )
2322 )
2323 if dryrun:
2323 if dryrun:
2324 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2324 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2325 return
2325 return
2326 return contstate.continuefunc(ui, repo)
2326 return contstate.continuefunc(ui, repo)
2327
2327
2328
2328
2329 @command(
2329 @command(
2330 b'copy|cp',
2330 b'copy|cp',
2331 [
2331 [
2332 (b'', b'forget', None, _(b'unmark a file as copied')),
2332 (b'', b'forget', None, _(b'unmark a file as copied')),
2333 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2333 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2334 (
2334 (
2335 b'',
2335 b'',
2336 b'at-rev',
2336 b'at-rev',
2337 b'',
2337 b'',
2338 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2338 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2339 _(b'REV'),
2339 _(b'REV'),
2340 ),
2340 ),
2341 (
2341 (
2342 b'f',
2342 b'f',
2343 b'force',
2343 b'force',
2344 None,
2344 None,
2345 _(b'forcibly copy over an existing managed file'),
2345 _(b'forcibly copy over an existing managed file'),
2346 ),
2346 ),
2347 ]
2347 ]
2348 + walkopts
2348 + walkopts
2349 + dryrunopts,
2349 + dryrunopts,
2350 _(b'[OPTION]... SOURCE... DEST'),
2350 _(b'[OPTION]... SOURCE... DEST'),
2351 helpcategory=command.CATEGORY_FILE_CONTENTS,
2351 helpcategory=command.CATEGORY_FILE_CONTENTS,
2352 )
2352 )
2353 def copy(ui, repo, *pats, **opts):
2353 def copy(ui, repo, *pats, **opts):
2354 """mark files as copied for the next commit
2354 """mark files as copied for the next commit
2355
2355
2356 Mark dest as having copies of source files. If dest is a
2356 Mark dest as having copies of source files. If dest is a
2357 directory, copies are put in that directory. If dest is a file,
2357 directory, copies are put in that directory. If dest is a file,
2358 the source must be a single file.
2358 the source must be a single file.
2359
2359
2360 By default, this command copies the contents of files as they
2360 By default, this command copies the contents of files as they
2361 exist in the working directory. If invoked with -A/--after, the
2361 exist in the working directory. If invoked with -A/--after, the
2362 operation is recorded, but no copying is performed.
2362 operation is recorded, but no copying is performed.
2363
2363
2364 To undo marking a file as copied, use --forget. With that option,
2364 To undo marking a file as copied, use --forget. With that option,
2365 all given (positional) arguments are unmarked as copies. The destination
2365 all given (positional) arguments are unmarked as copies. The destination
2366 file(s) will be left in place (still tracked).
2366 file(s) will be left in place (still tracked).
2367
2367
2368 This command takes effect with the next commit by default.
2368 This command takes effect with the next commit by default.
2369
2369
2370 Returns 0 on success, 1 if errors are encountered.
2370 Returns 0 on success, 1 if errors are encountered.
2371 """
2371 """
2372 opts = pycompat.byteskwargs(opts)
2372 opts = pycompat.byteskwargs(opts)
2373 with repo.wlock():
2373 with repo.wlock():
2374 return cmdutil.copy(ui, repo, pats, opts)
2374 return cmdutil.copy(ui, repo, pats, opts)
2375
2375
2376
2376
2377 @command(
2377 @command(
2378 b'debugcommands',
2378 b'debugcommands',
2379 [],
2379 [],
2380 _(b'[COMMAND]'),
2380 _(b'[COMMAND]'),
2381 helpcategory=command.CATEGORY_HELP,
2381 helpcategory=command.CATEGORY_HELP,
2382 norepo=True,
2382 norepo=True,
2383 )
2383 )
2384 def debugcommands(ui, cmd=b'', *args):
2384 def debugcommands(ui, cmd=b'', *args):
2385 """list all available commands and options"""
2385 """list all available commands and options"""
2386 for cmd, vals in sorted(pycompat.iteritems(table)):
2386 for cmd, vals in sorted(pycompat.iteritems(table)):
2387 cmd = cmd.split(b'|')[0]
2387 cmd = cmd.split(b'|')[0]
2388 opts = b', '.join([i[1] for i in vals[1]])
2388 opts = b', '.join([i[1] for i in vals[1]])
2389 ui.write(b'%s: %s\n' % (cmd, opts))
2389 ui.write(b'%s: %s\n' % (cmd, opts))
2390
2390
2391
2391
2392 @command(
2392 @command(
2393 b'debugcomplete',
2393 b'debugcomplete',
2394 [(b'o', b'options', None, _(b'show the command options'))],
2394 [(b'o', b'options', None, _(b'show the command options'))],
2395 _(b'[-o] CMD'),
2395 _(b'[-o] CMD'),
2396 helpcategory=command.CATEGORY_HELP,
2396 helpcategory=command.CATEGORY_HELP,
2397 norepo=True,
2397 norepo=True,
2398 )
2398 )
2399 def debugcomplete(ui, cmd=b'', **opts):
2399 def debugcomplete(ui, cmd=b'', **opts):
2400 """returns the completion list associated with the given command"""
2400 """returns the completion list associated with the given command"""
2401
2401
2402 if opts.get('options'):
2402 if opts.get('options'):
2403 options = []
2403 options = []
2404 otables = [globalopts]
2404 otables = [globalopts]
2405 if cmd:
2405 if cmd:
2406 aliases, entry = cmdutil.findcmd(cmd, table, False)
2406 aliases, entry = cmdutil.findcmd(cmd, table, False)
2407 otables.append(entry[1])
2407 otables.append(entry[1])
2408 for t in otables:
2408 for t in otables:
2409 for o in t:
2409 for o in t:
2410 if b"(DEPRECATED)" in o[3]:
2410 if b"(DEPRECATED)" in o[3]:
2411 continue
2411 continue
2412 if o[0]:
2412 if o[0]:
2413 options.append(b'-%s' % o[0])
2413 options.append(b'-%s' % o[0])
2414 options.append(b'--%s' % o[1])
2414 options.append(b'--%s' % o[1])
2415 ui.write(b"%s\n" % b"\n".join(options))
2415 ui.write(b"%s\n" % b"\n".join(options))
2416 return
2416 return
2417
2417
2418 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2418 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2419 if ui.verbose:
2419 if ui.verbose:
2420 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2420 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2421 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2421 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2422
2422
2423
2423
2424 @command(
2424 @command(
2425 b'diff',
2425 b'diff',
2426 [
2426 [
2427 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2427 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2428 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2428 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2429 ]
2429 ]
2430 + diffopts
2430 + diffopts
2431 + diffopts2
2431 + diffopts2
2432 + walkopts
2432 + walkopts
2433 + subrepoopts,
2433 + subrepoopts,
2434 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2434 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2435 helpcategory=command.CATEGORY_FILE_CONTENTS,
2435 helpcategory=command.CATEGORY_FILE_CONTENTS,
2436 helpbasic=True,
2436 helpbasic=True,
2437 inferrepo=True,
2437 inferrepo=True,
2438 intents={INTENT_READONLY},
2438 intents={INTENT_READONLY},
2439 )
2439 )
2440 def diff(ui, repo, *pats, **opts):
2440 def diff(ui, repo, *pats, **opts):
2441 """diff repository (or selected files)
2441 """diff repository (or selected files)
2442
2442
2443 Show differences between revisions for the specified files.
2443 Show differences between revisions for the specified files.
2444
2444
2445 Differences between files are shown using the unified diff format.
2445 Differences between files are shown using the unified diff format.
2446
2446
2447 .. note::
2447 .. note::
2448
2448
2449 :hg:`diff` may generate unexpected results for merges, as it will
2449 :hg:`diff` may generate unexpected results for merges, as it will
2450 default to comparing against the working directory's first
2450 default to comparing against the working directory's first
2451 parent changeset if no revisions are specified.
2451 parent changeset if no revisions are specified.
2452
2452
2453 When two revision arguments are given, then changes are shown
2453 When two revision arguments are given, then changes are shown
2454 between those revisions. If only one revision is specified then
2454 between those revisions. If only one revision is specified then
2455 that revision is compared to the working directory, and, when no
2455 that revision is compared to the working directory, and, when no
2456 revisions are specified, the working directory files are compared
2456 revisions are specified, the working directory files are compared
2457 to its first parent.
2457 to its first parent.
2458
2458
2459 Alternatively you can specify -c/--change with a revision to see
2459 Alternatively you can specify -c/--change with a revision to see
2460 the changes in that changeset relative to its first parent.
2460 the changes in that changeset relative to its first parent.
2461
2461
2462 Without the -a/--text option, diff will avoid generating diffs of
2462 Without the -a/--text option, diff will avoid generating diffs of
2463 files it detects as binary. With -a, diff will generate a diff
2463 files it detects as binary. With -a, diff will generate a diff
2464 anyway, probably with undesirable results.
2464 anyway, probably with undesirable results.
2465
2465
2466 Use the -g/--git option to generate diffs in the git extended diff
2466 Use the -g/--git option to generate diffs in the git extended diff
2467 format. For more information, read :hg:`help diffs`.
2467 format. For more information, read :hg:`help diffs`.
2468
2468
2469 .. container:: verbose
2469 .. container:: verbose
2470
2470
2471 Examples:
2471 Examples:
2472
2472
2473 - compare a file in the current working directory to its parent::
2473 - compare a file in the current working directory to its parent::
2474
2474
2475 hg diff foo.c
2475 hg diff foo.c
2476
2476
2477 - compare two historical versions of a directory, with rename info::
2477 - compare two historical versions of a directory, with rename info::
2478
2478
2479 hg diff --git -r 1.0:1.2 lib/
2479 hg diff --git -r 1.0:1.2 lib/
2480
2480
2481 - get change stats relative to the last change on some date::
2481 - get change stats relative to the last change on some date::
2482
2482
2483 hg diff --stat -r "date('may 2')"
2483 hg diff --stat -r "date('may 2')"
2484
2484
2485 - diff all newly-added files that contain a keyword::
2485 - diff all newly-added files that contain a keyword::
2486
2486
2487 hg diff "set:added() and grep(GNU)"
2487 hg diff "set:added() and grep(GNU)"
2488
2488
2489 - compare a revision and its parents::
2489 - compare a revision and its parents::
2490
2490
2491 hg diff -c 9353 # compare against first parent
2491 hg diff -c 9353 # compare against first parent
2492 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^:9353 # same using revset syntax
2493 hg diff -r 9353^2:9353 # compare against the second parent
2493 hg diff -r 9353^2:9353 # compare against the second parent
2494
2494
2495 Returns 0 on success.
2495 Returns 0 on success.
2496 """
2496 """
2497
2497
2498 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2498 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2499 opts = pycompat.byteskwargs(opts)
2499 opts = pycompat.byteskwargs(opts)
2500 revs = opts.get(b'rev')
2500 revs = opts.get(b'rev')
2501 change = opts.get(b'change')
2501 change = opts.get(b'change')
2502 stat = opts.get(b'stat')
2502 stat = opts.get(b'stat')
2503 reverse = opts.get(b'reverse')
2503 reverse = opts.get(b'reverse')
2504
2504
2505 if change:
2505 if change:
2506 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2506 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2507 ctx2 = scmutil.revsingle(repo, change, None)
2507 ctx2 = scmutil.revsingle(repo, change, None)
2508 ctx1 = ctx2.p1()
2508 ctx1 = ctx2.p1()
2509 else:
2509 else:
2510 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2510 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2511 ctx1, ctx2 = scmutil.revpair(repo, revs)
2511 ctx1, ctx2 = scmutil.revpair(repo, revs)
2512
2512
2513 if reverse:
2513 if reverse:
2514 ctxleft = ctx2
2514 ctxleft = ctx2
2515 ctxright = ctx1
2515 ctxright = ctx1
2516 else:
2516 else:
2517 ctxleft = ctx1
2517 ctxleft = ctx1
2518 ctxright = ctx2
2518 ctxright = ctx2
2519
2519
2520 diffopts = patch.diffallopts(ui, opts)
2520 diffopts = patch.diffallopts(ui, opts)
2521 m = scmutil.match(ctx2, pats, opts)
2521 m = scmutil.match(ctx2, pats, opts)
2522 m = repo.narrowmatch(m)
2522 m = repo.narrowmatch(m)
2523 ui.pager(b'diff')
2523 ui.pager(b'diff')
2524 logcmdutil.diffordiffstat(
2524 logcmdutil.diffordiffstat(
2525 ui,
2525 ui,
2526 repo,
2526 repo,
2527 diffopts,
2527 diffopts,
2528 ctxleft,
2528 ctxleft,
2529 ctxright,
2529 ctxright,
2530 m,
2530 m,
2531 stat=stat,
2531 stat=stat,
2532 listsubrepos=opts.get(b'subrepos'),
2532 listsubrepos=opts.get(b'subrepos'),
2533 root=opts.get(b'root'),
2533 root=opts.get(b'root'),
2534 )
2534 )
2535
2535
2536
2536
2537 @command(
2537 @command(
2538 b'export',
2538 b'export',
2539 [
2539 [
2540 (
2540 (
2541 b'B',
2541 b'B',
2542 b'bookmark',
2542 b'bookmark',
2543 b'',
2543 b'',
2544 _(b'export changes only reachable by given bookmark'),
2544 _(b'export changes only reachable by given bookmark'),
2545 _(b'BOOKMARK'),
2545 _(b'BOOKMARK'),
2546 ),
2546 ),
2547 (
2547 (
2548 b'o',
2548 b'o',
2549 b'output',
2549 b'output',
2550 b'',
2550 b'',
2551 _(b'print output to file with formatted name'),
2551 _(b'print output to file with formatted name'),
2552 _(b'FORMAT'),
2552 _(b'FORMAT'),
2553 ),
2553 ),
2554 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2554 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2555 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2555 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2556 ]
2556 ]
2557 + diffopts
2557 + diffopts
2558 + formatteropts,
2558 + formatteropts,
2559 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2559 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2560 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2560 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2561 helpbasic=True,
2561 helpbasic=True,
2562 intents={INTENT_READONLY},
2562 intents={INTENT_READONLY},
2563 )
2563 )
2564 def export(ui, repo, *changesets, **opts):
2564 def export(ui, repo, *changesets, **opts):
2565 """dump the header and diffs for one or more changesets
2565 """dump the header and diffs for one or more changesets
2566
2566
2567 Print the changeset header and diffs for one or more revisions.
2567 Print the changeset header and diffs for one or more revisions.
2568 If no revision is given, the parent of the working directory is used.
2568 If no revision is given, the parent of the working directory is used.
2569
2569
2570 The information shown in the changeset header is: author, date,
2570 The information shown in the changeset header is: author, date,
2571 branch name (if non-default), changeset hash, parent(s) and commit
2571 branch name (if non-default), changeset hash, parent(s) and commit
2572 comment.
2572 comment.
2573
2573
2574 .. note::
2574 .. note::
2575
2575
2576 :hg:`export` may generate unexpected diff output for merge
2576 :hg:`export` may generate unexpected diff output for merge
2577 changesets, as it will compare the merge changeset against its
2577 changesets, as it will compare the merge changeset against its
2578 first parent only.
2578 first parent only.
2579
2579
2580 Output may be to a file, in which case the name of the file is
2580 Output may be to a file, in which case the name of the file is
2581 given using a template string. See :hg:`help templates`. In addition
2581 given using a template string. See :hg:`help templates`. In addition
2582 to the common template keywords, the following formatting rules are
2582 to the common template keywords, the following formatting rules are
2583 supported:
2583 supported:
2584
2584
2585 :``%%``: literal "%" character
2585 :``%%``: literal "%" character
2586 :``%H``: changeset hash (40 hexadecimal digits)
2586 :``%H``: changeset hash (40 hexadecimal digits)
2587 :``%N``: number of patches being generated
2587 :``%N``: number of patches being generated
2588 :``%R``: changeset revision number
2588 :``%R``: changeset revision number
2589 :``%b``: basename of the exporting repository
2589 :``%b``: basename of the exporting repository
2590 :``%h``: short-form changeset hash (12 hexadecimal digits)
2590 :``%h``: short-form changeset hash (12 hexadecimal digits)
2591 :``%m``: first line of the commit message (only alphanumeric characters)
2591 :``%m``: first line of the commit message (only alphanumeric characters)
2592 :``%n``: zero-padded sequence number, starting at 1
2592 :``%n``: zero-padded sequence number, starting at 1
2593 :``%r``: zero-padded changeset revision number
2593 :``%r``: zero-padded changeset revision number
2594 :``\\``: literal "\\" character
2594 :``\\``: literal "\\" character
2595
2595
2596 Without the -a/--text option, export will avoid generating diffs
2596 Without the -a/--text option, export will avoid generating diffs
2597 of files it detects as binary. With -a, export will generate a
2597 of files it detects as binary. With -a, export will generate a
2598 diff anyway, probably with undesirable results.
2598 diff anyway, probably with undesirable results.
2599
2599
2600 With -B/--bookmark changesets reachable by the given bookmark are
2600 With -B/--bookmark changesets reachable by the given bookmark are
2601 selected.
2601 selected.
2602
2602
2603 Use the -g/--git option to generate diffs in the git extended diff
2603 Use the -g/--git option to generate diffs in the git extended diff
2604 format. See :hg:`help diffs` for more information.
2604 format. See :hg:`help diffs` for more information.
2605
2605
2606 With the --switch-parent option, the diff will be against the
2606 With the --switch-parent option, the diff will be against the
2607 second parent. It can be useful to review a merge.
2607 second parent. It can be useful to review a merge.
2608
2608
2609 .. container:: verbose
2609 .. container:: verbose
2610
2610
2611 Template:
2611 Template:
2612
2612
2613 The following keywords are supported in addition to the common template
2613 The following keywords are supported in addition to the common template
2614 keywords and functions. See also :hg:`help templates`.
2614 keywords and functions. See also :hg:`help templates`.
2615
2615
2616 :diff: String. Diff content.
2616 :diff: String. Diff content.
2617 :parents: List of strings. Parent nodes of the changeset.
2617 :parents: List of strings. Parent nodes of the changeset.
2618
2618
2619 Examples:
2619 Examples:
2620
2620
2621 - use export and import to transplant a bugfix to the current
2621 - use export and import to transplant a bugfix to the current
2622 branch::
2622 branch::
2623
2623
2624 hg export -r 9353 | hg import -
2624 hg export -r 9353 | hg import -
2625
2625
2626 - export all the changesets between two revisions to a file with
2626 - export all the changesets between two revisions to a file with
2627 rename information::
2627 rename information::
2628
2628
2629 hg export --git -r 123:150 > changes.txt
2629 hg export --git -r 123:150 > changes.txt
2630
2630
2631 - split outgoing changes into a series of patches with
2631 - split outgoing changes into a series of patches with
2632 descriptive names::
2632 descriptive names::
2633
2633
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2635
2635
2636 Returns 0 on success.
2636 Returns 0 on success.
2637 """
2637 """
2638 opts = pycompat.byteskwargs(opts)
2638 opts = pycompat.byteskwargs(opts)
2639 bookmark = opts.get(b'bookmark')
2639 bookmark = opts.get(b'bookmark')
2640 changesets += tuple(opts.get(b'rev', []))
2640 changesets += tuple(opts.get(b'rev', []))
2641
2641
2642 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2642 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2643
2643
2644 if bookmark:
2644 if bookmark:
2645 if bookmark not in repo._bookmarks:
2645 if bookmark not in repo._bookmarks:
2646 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2646 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2647
2647
2648 revs = scmutil.bookmarkrevs(repo, bookmark)
2648 revs = scmutil.bookmarkrevs(repo, bookmark)
2649 else:
2649 else:
2650 if not changesets:
2650 if not changesets:
2651 changesets = [b'.']
2651 changesets = [b'.']
2652
2652
2653 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2653 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2654 revs = scmutil.revrange(repo, changesets)
2654 revs = scmutil.revrange(repo, changesets)
2655
2655
2656 if not revs:
2656 if not revs:
2657 raise error.Abort(_(b"export requires at least one changeset"))
2657 raise error.Abort(_(b"export requires at least one changeset"))
2658 if len(revs) > 1:
2658 if len(revs) > 1:
2659 ui.note(_(b'exporting patches:\n'))
2659 ui.note(_(b'exporting patches:\n'))
2660 else:
2660 else:
2661 ui.note(_(b'exporting patch:\n'))
2661 ui.note(_(b'exporting patch:\n'))
2662
2662
2663 fntemplate = opts.get(b'output')
2663 fntemplate = opts.get(b'output')
2664 if cmdutil.isstdiofilename(fntemplate):
2664 if cmdutil.isstdiofilename(fntemplate):
2665 fntemplate = b''
2665 fntemplate = b''
2666
2666
2667 if fntemplate:
2667 if fntemplate:
2668 fm = formatter.nullformatter(ui, b'export', opts)
2668 fm = formatter.nullformatter(ui, b'export', opts)
2669 else:
2669 else:
2670 ui.pager(b'export')
2670 ui.pager(b'export')
2671 fm = ui.formatter(b'export', opts)
2671 fm = ui.formatter(b'export', opts)
2672 with fm:
2672 with fm:
2673 cmdutil.export(
2673 cmdutil.export(
2674 repo,
2674 repo,
2675 revs,
2675 revs,
2676 fm,
2676 fm,
2677 fntemplate=fntemplate,
2677 fntemplate=fntemplate,
2678 switch_parent=opts.get(b'switch_parent'),
2678 switch_parent=opts.get(b'switch_parent'),
2679 opts=patch.diffallopts(ui, opts),
2679 opts=patch.diffallopts(ui, opts),
2680 )
2680 )
2681
2681
2682
2682
2683 @command(
2683 @command(
2684 b'files',
2684 b'files',
2685 [
2685 [
2686 (
2686 (
2687 b'r',
2687 b'r',
2688 b'rev',
2688 b'rev',
2689 b'',
2689 b'',
2690 _(b'search the repository as it is in REV'),
2690 _(b'search the repository as it is in REV'),
2691 _(b'REV'),
2691 _(b'REV'),
2692 ),
2692 ),
2693 (
2693 (
2694 b'0',
2694 b'0',
2695 b'print0',
2695 b'print0',
2696 None,
2696 None,
2697 _(b'end filenames with NUL, for use with xargs'),
2697 _(b'end filenames with NUL, for use with xargs'),
2698 ),
2698 ),
2699 ]
2699 ]
2700 + walkopts
2700 + walkopts
2701 + formatteropts
2701 + formatteropts
2702 + subrepoopts,
2702 + subrepoopts,
2703 _(b'[OPTION]... [FILE]...'),
2703 _(b'[OPTION]... [FILE]...'),
2704 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2704 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2705 intents={INTENT_READONLY},
2705 intents={INTENT_READONLY},
2706 )
2706 )
2707 def files(ui, repo, *pats, **opts):
2707 def files(ui, repo, *pats, **opts):
2708 """list tracked files
2708 """list tracked files
2709
2709
2710 Print files under Mercurial control in the working directory or
2710 Print files under Mercurial control in the working directory or
2711 specified revision for given files (excluding removed files).
2711 specified revision for given files (excluding removed files).
2712 Files can be specified as filenames or filesets.
2712 Files can be specified as filenames or filesets.
2713
2713
2714 If no files are given to match, this command prints the names
2714 If no files are given to match, this command prints the names
2715 of all files under Mercurial control.
2715 of all files under Mercurial control.
2716
2716
2717 .. container:: verbose
2717 .. container:: verbose
2718
2718
2719 Template:
2719 Template:
2720
2720
2721 The following keywords are supported in addition to the common template
2721 The following keywords are supported in addition to the common template
2722 keywords and functions. See also :hg:`help templates`.
2722 keywords and functions. See also :hg:`help templates`.
2723
2723
2724 :flags: String. Character denoting file's symlink and executable bits.
2724 :flags: String. Character denoting file's symlink and executable bits.
2725 :path: String. Repository-absolute path of the file.
2725 :path: String. Repository-absolute path of the file.
2726 :size: Integer. Size of the file in bytes.
2726 :size: Integer. Size of the file in bytes.
2727
2727
2728 Examples:
2728 Examples:
2729
2729
2730 - list all files under the current directory::
2730 - list all files under the current directory::
2731
2731
2732 hg files .
2732 hg files .
2733
2733
2734 - shows sizes and flags for current revision::
2734 - shows sizes and flags for current revision::
2735
2735
2736 hg files -vr .
2736 hg files -vr .
2737
2737
2738 - list all files named README::
2738 - list all files named README::
2739
2739
2740 hg files -I "**/README"
2740 hg files -I "**/README"
2741
2741
2742 - list all binary files::
2742 - list all binary files::
2743
2743
2744 hg files "set:binary()"
2744 hg files "set:binary()"
2745
2745
2746 - find files containing a regular expression::
2746 - find files containing a regular expression::
2747
2747
2748 hg files "set:grep('bob')"
2748 hg files "set:grep('bob')"
2749
2749
2750 - search tracked file contents with xargs and grep::
2750 - search tracked file contents with xargs and grep::
2751
2751
2752 hg files -0 | xargs -0 grep foo
2752 hg files -0 | xargs -0 grep foo
2753
2753
2754 See :hg:`help patterns` and :hg:`help filesets` for more information
2754 See :hg:`help patterns` and :hg:`help filesets` for more information
2755 on specifying file patterns.
2755 on specifying file patterns.
2756
2756
2757 Returns 0 if a match is found, 1 otherwise.
2757 Returns 0 if a match is found, 1 otherwise.
2758
2758
2759 """
2759 """
2760
2760
2761 opts = pycompat.byteskwargs(opts)
2761 opts = pycompat.byteskwargs(opts)
2762 rev = opts.get(b'rev')
2762 rev = opts.get(b'rev')
2763 if rev:
2763 if rev:
2764 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2764 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2765 ctx = scmutil.revsingle(repo, rev, None)
2765 ctx = scmutil.revsingle(repo, rev, None)
2766
2766
2767 end = b'\n'
2767 end = b'\n'
2768 if opts.get(b'print0'):
2768 if opts.get(b'print0'):
2769 end = b'\0'
2769 end = b'\0'
2770 fmt = b'%s' + end
2770 fmt = b'%s' + end
2771
2771
2772 m = scmutil.match(ctx, pats, opts)
2772 m = scmutil.match(ctx, pats, opts)
2773 ui.pager(b'files')
2773 ui.pager(b'files')
2774 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2774 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2775 with ui.formatter(b'files', opts) as fm:
2775 with ui.formatter(b'files', opts) as fm:
2776 return cmdutil.files(
2776 return cmdutil.files(
2777 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2777 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2778 )
2778 )
2779
2779
2780
2780
2781 @command(
2781 @command(
2782 b'forget',
2782 b'forget',
2783 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2783 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2784 + walkopts
2784 + walkopts
2785 + dryrunopts,
2785 + dryrunopts,
2786 _(b'[OPTION]... FILE...'),
2786 _(b'[OPTION]... FILE...'),
2787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2788 helpbasic=True,
2788 helpbasic=True,
2789 inferrepo=True,
2789 inferrepo=True,
2790 )
2790 )
2791 def forget(ui, repo, *pats, **opts):
2791 def forget(ui, repo, *pats, **opts):
2792 """forget the specified files on the next commit
2792 """forget the specified files on the next commit
2793
2793
2794 Mark the specified files so they will no longer be tracked
2794 Mark the specified files so they will no longer be tracked
2795 after the next commit.
2795 after the next commit.
2796
2796
2797 This only removes files from the current branch, not from the
2797 This only removes files from the current branch, not from the
2798 entire project history, and it does not delete them from the
2798 entire project history, and it does not delete them from the
2799 working directory.
2799 working directory.
2800
2800
2801 To delete the file from the working directory, see :hg:`remove`.
2801 To delete the file from the working directory, see :hg:`remove`.
2802
2802
2803 To undo a forget before the next commit, see :hg:`add`.
2803 To undo a forget before the next commit, see :hg:`add`.
2804
2804
2805 .. container:: verbose
2805 .. container:: verbose
2806
2806
2807 Examples:
2807 Examples:
2808
2808
2809 - forget newly-added binary files::
2809 - forget newly-added binary files::
2810
2810
2811 hg forget "set:added() and binary()"
2811 hg forget "set:added() and binary()"
2812
2812
2813 - forget files that would be excluded by .hgignore::
2813 - forget files that would be excluded by .hgignore::
2814
2814
2815 hg forget "set:hgignore()"
2815 hg forget "set:hgignore()"
2816
2816
2817 Returns 0 on success.
2817 Returns 0 on success.
2818 """
2818 """
2819
2819
2820 opts = pycompat.byteskwargs(opts)
2820 opts = pycompat.byteskwargs(opts)
2821 if not pats:
2821 if not pats:
2822 raise error.Abort(_(b'no files specified'))
2822 raise error.Abort(_(b'no files specified'))
2823
2823
2824 m = scmutil.match(repo[None], pats, opts)
2824 m = scmutil.match(repo[None], pats, opts)
2825 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2825 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2826 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2826 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2827 rejected = cmdutil.forget(
2827 rejected = cmdutil.forget(
2828 ui,
2828 ui,
2829 repo,
2829 repo,
2830 m,
2830 m,
2831 prefix=b"",
2831 prefix=b"",
2832 uipathfn=uipathfn,
2832 uipathfn=uipathfn,
2833 explicitonly=False,
2833 explicitonly=False,
2834 dryrun=dryrun,
2834 dryrun=dryrun,
2835 interactive=interactive,
2835 interactive=interactive,
2836 )[0]
2836 )[0]
2837 return rejected and 1 or 0
2837 return rejected and 1 or 0
2838
2838
2839
2839
2840 @command(
2840 @command(
2841 b'graft',
2841 b'graft',
2842 [
2842 [
2843 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2843 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2844 (
2844 (
2845 b'',
2845 b'',
2846 b'base',
2846 b'base',
2847 b'',
2847 b'',
2848 _(b'base revision when doing the graft merge (ADVANCED)'),
2848 _(b'base revision when doing the graft merge (ADVANCED)'),
2849 _(b'REV'),
2849 _(b'REV'),
2850 ),
2850 ),
2851 (b'c', b'continue', False, _(b'resume interrupted graft')),
2851 (b'c', b'continue', False, _(b'resume interrupted graft')),
2852 (b'', b'stop', False, _(b'stop interrupted graft')),
2852 (b'', b'stop', False, _(b'stop interrupted graft')),
2853 (b'', b'abort', False, _(b'abort interrupted graft')),
2853 (b'', b'abort', False, _(b'abort interrupted graft')),
2854 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2854 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2855 (b'', b'log', None, _(b'append graft info to log message')),
2855 (b'', b'log', None, _(b'append graft info to log message')),
2856 (
2856 (
2857 b'',
2857 b'',
2858 b'no-commit',
2858 b'no-commit',
2859 None,
2859 None,
2860 _(b"don't commit, just apply the changes in working directory"),
2860 _(b"don't commit, just apply the changes in working directory"),
2861 ),
2861 ),
2862 (b'f', b'force', False, _(b'force graft')),
2862 (b'f', b'force', False, _(b'force graft')),
2863 (
2863 (
2864 b'D',
2864 b'D',
2865 b'currentdate',
2865 b'currentdate',
2866 False,
2866 False,
2867 _(b'record the current date as commit date'),
2867 _(b'record the current date as commit date'),
2868 ),
2868 ),
2869 (
2869 (
2870 b'U',
2870 b'U',
2871 b'currentuser',
2871 b'currentuser',
2872 False,
2872 False,
2873 _(b'record the current user as committer'),
2873 _(b'record the current user as committer'),
2874 ),
2874 ),
2875 ]
2875 ]
2876 + commitopts2
2876 + commitopts2
2877 + mergetoolopts
2877 + mergetoolopts
2878 + dryrunopts,
2878 + dryrunopts,
2879 _(b'[OPTION]... [-r REV]... REV...'),
2879 _(b'[OPTION]... [-r REV]... REV...'),
2880 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2880 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2881 )
2881 )
2882 def graft(ui, repo, *revs, **opts):
2882 def graft(ui, repo, *revs, **opts):
2883 '''copy changes from other branches onto the current branch
2883 '''copy changes from other branches onto the current branch
2884
2884
2885 This command uses Mercurial's merge logic to copy individual
2885 This command uses Mercurial's merge logic to copy individual
2886 changes from other branches without merging branches in the
2886 changes from other branches without merging branches in the
2887 history graph. This is sometimes known as 'backporting' or
2887 history graph. This is sometimes known as 'backporting' or
2888 'cherry-picking'. By default, graft will copy user, date, and
2888 'cherry-picking'. By default, graft will copy user, date, and
2889 description from the source changesets.
2889 description from the source changesets.
2890
2890
2891 Changesets that are ancestors of the current revision, that have
2891 Changesets that are ancestors of the current revision, that have
2892 already been grafted, or that are merges will be skipped.
2892 already been grafted, or that are merges will be skipped.
2893
2893
2894 If --log is specified, log messages will have a comment appended
2894 If --log is specified, log messages will have a comment appended
2895 of the form::
2895 of the form::
2896
2896
2897 (grafted from CHANGESETHASH)
2897 (grafted from CHANGESETHASH)
2898
2898
2899 If --force is specified, revisions will be grafted even if they
2899 If --force is specified, revisions will be grafted even if they
2900 are already ancestors of, or have been grafted to, the destination.
2900 are already ancestors of, or have been grafted to, the destination.
2901 This is useful when the revisions have since been backed out.
2901 This is useful when the revisions have since been backed out.
2902
2902
2903 If a graft merge results in conflicts, the graft process is
2903 If a graft merge results in conflicts, the graft process is
2904 interrupted so that the current merge can be manually resolved.
2904 interrupted so that the current merge can be manually resolved.
2905 Once all conflicts are addressed, the graft process can be
2905 Once all conflicts are addressed, the graft process can be
2906 continued with the -c/--continue option.
2906 continued with the -c/--continue option.
2907
2907
2908 The -c/--continue option reapplies all the earlier options.
2908 The -c/--continue option reapplies all the earlier options.
2909
2909
2910 .. container:: verbose
2910 .. container:: verbose
2911
2911
2912 The --base option exposes more of how graft internally uses merge with a
2912 The --base option exposes more of how graft internally uses merge with a
2913 custom base revision. --base can be used to specify another ancestor than
2913 custom base revision. --base can be used to specify another ancestor than
2914 the first and only parent.
2914 the first and only parent.
2915
2915
2916 The command::
2916 The command::
2917
2917
2918 hg graft -r 345 --base 234
2918 hg graft -r 345 --base 234
2919
2919
2920 is thus pretty much the same as::
2920 is thus pretty much the same as::
2921
2921
2922 hg diff -r 234 -r 345 | hg import
2922 hg diff -r 234 -r 345 | hg import
2923
2923
2924 but using merge to resolve conflicts and track moved files.
2924 but using merge to resolve conflicts and track moved files.
2925
2925
2926 The result of a merge can thus be backported as a single commit by
2926 The result of a merge can thus be backported as a single commit by
2927 specifying one of the merge parents as base, and thus effectively
2927 specifying one of the merge parents as base, and thus effectively
2928 grafting the changes from the other side.
2928 grafting the changes from the other side.
2929
2929
2930 It is also possible to collapse multiple changesets and clean up history
2930 It is also possible to collapse multiple changesets and clean up history
2931 by specifying another ancestor as base, much like rebase --collapse
2931 by specifying another ancestor as base, much like rebase --collapse
2932 --keep.
2932 --keep.
2933
2933
2934 The commit message can be tweaked after the fact using commit --amend .
2934 The commit message can be tweaked after the fact using commit --amend .
2935
2935
2936 For using non-ancestors as the base to backout changes, see the backout
2936 For using non-ancestors as the base to backout changes, see the backout
2937 command and the hidden --parent option.
2937 command and the hidden --parent option.
2938
2938
2939 .. container:: verbose
2939 .. container:: verbose
2940
2940
2941 Examples:
2941 Examples:
2942
2942
2943 - copy a single change to the stable branch and edit its description::
2943 - copy a single change to the stable branch and edit its description::
2944
2944
2945 hg update stable
2945 hg update stable
2946 hg graft --edit 9393
2946 hg graft --edit 9393
2947
2947
2948 - graft a range of changesets with one exception, updating dates::
2948 - graft a range of changesets with one exception, updating dates::
2949
2949
2950 hg graft -D "2085::2093 and not 2091"
2950 hg graft -D "2085::2093 and not 2091"
2951
2951
2952 - continue a graft after resolving conflicts::
2952 - continue a graft after resolving conflicts::
2953
2953
2954 hg graft -c
2954 hg graft -c
2955
2955
2956 - show the source of a grafted changeset::
2956 - show the source of a grafted changeset::
2957
2957
2958 hg log --debug -r .
2958 hg log --debug -r .
2959
2959
2960 - show revisions sorted by date::
2960 - show revisions sorted by date::
2961
2961
2962 hg log -r "sort(all(), date)"
2962 hg log -r "sort(all(), date)"
2963
2963
2964 - backport the result of a merge as a single commit::
2964 - backport the result of a merge as a single commit::
2965
2965
2966 hg graft -r 123 --base 123^
2966 hg graft -r 123 --base 123^
2967
2967
2968 - land a feature branch as one changeset::
2968 - land a feature branch as one changeset::
2969
2969
2970 hg up -cr default
2970 hg up -cr default
2971 hg graft -r featureX --base "ancestor('featureX', 'default')"
2971 hg graft -r featureX --base "ancestor('featureX', 'default')"
2972
2972
2973 See :hg:`help revisions` for more about specifying revisions.
2973 See :hg:`help revisions` for more about specifying revisions.
2974
2974
2975 Returns 0 on successful completion, 1 if there are unresolved files.
2975 Returns 0 on successful completion, 1 if there are unresolved files.
2976 '''
2976 '''
2977 with repo.wlock():
2977 with repo.wlock():
2978 return _dograft(ui, repo, *revs, **opts)
2978 return _dograft(ui, repo, *revs, **opts)
2979
2979
2980
2980
2981 def _dograft(ui, repo, *revs, **opts):
2981 def _dograft(ui, repo, *revs, **opts):
2982 opts = pycompat.byteskwargs(opts)
2982 opts = pycompat.byteskwargs(opts)
2983 if revs and opts.get(b'rev'):
2983 if revs and opts.get(b'rev'):
2984 ui.warn(
2984 ui.warn(
2985 _(
2985 _(
2986 b'warning: inconsistent use of --rev might give unexpected '
2986 b'warning: inconsistent use of --rev might give unexpected '
2987 b'revision ordering!\n'
2987 b'revision ordering!\n'
2988 )
2988 )
2989 )
2989 )
2990
2990
2991 revs = list(revs)
2991 revs = list(revs)
2992 revs.extend(opts.get(b'rev'))
2992 revs.extend(opts.get(b'rev'))
2993 # a dict of data to be stored in state file
2993 # a dict of data to be stored in state file
2994 statedata = {}
2994 statedata = {}
2995 # list of new nodes created by ongoing graft
2995 # list of new nodes created by ongoing graft
2996 statedata[b'newnodes'] = []
2996 statedata[b'newnodes'] = []
2997
2997
2998 cmdutil.resolvecommitoptions(ui, opts)
2998 cmdutil.resolvecommitoptions(ui, opts)
2999
2999
3000 editor = cmdutil.getcommiteditor(
3000 editor = cmdutil.getcommiteditor(
3001 editform=b'graft', **pycompat.strkwargs(opts)
3001 editform=b'graft', **pycompat.strkwargs(opts)
3002 )
3002 )
3003
3003
3004 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3004 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3005
3005
3006 cont = False
3006 cont = False
3007 if opts.get(b'no_commit'):
3007 if opts.get(b'no_commit'):
3008 cmdutil.check_incompatible_arguments(
3008 cmdutil.check_incompatible_arguments(
3009 opts,
3009 opts,
3010 b'no_commit',
3010 b'no_commit',
3011 [b'edit', b'currentuser', b'currentdate', b'log'],
3011 [b'edit', b'currentuser', b'currentdate', b'log'],
3012 )
3012 )
3013
3013
3014 graftstate = statemod.cmdstate(repo, b'graftstate')
3014 graftstate = statemod.cmdstate(repo, b'graftstate')
3015
3015
3016 if opts.get(b'stop'):
3016 if opts.get(b'stop'):
3017 cmdutil.check_incompatible_arguments(
3017 cmdutil.check_incompatible_arguments(
3018 opts,
3018 opts,
3019 b'stop',
3019 b'stop',
3020 [
3020 [
3021 b'edit',
3021 b'edit',
3022 b'log',
3022 b'log',
3023 b'user',
3023 b'user',
3024 b'date',
3024 b'date',
3025 b'currentdate',
3025 b'currentdate',
3026 b'currentuser',
3026 b'currentuser',
3027 b'rev',
3027 b'rev',
3028 ],
3028 ],
3029 )
3029 )
3030 return _stopgraft(ui, repo, graftstate)
3030 return _stopgraft(ui, repo, graftstate)
3031 elif opts.get(b'abort'):
3031 elif opts.get(b'abort'):
3032 cmdutil.check_incompatible_arguments(
3032 cmdutil.check_incompatible_arguments(
3033 opts,
3033 opts,
3034 b'abort',
3034 b'abort',
3035 [
3035 [
3036 b'edit',
3036 b'edit',
3037 b'log',
3037 b'log',
3038 b'user',
3038 b'user',
3039 b'date',
3039 b'date',
3040 b'currentdate',
3040 b'currentdate',
3041 b'currentuser',
3041 b'currentuser',
3042 b'rev',
3042 b'rev',
3043 ],
3043 ],
3044 )
3044 )
3045 return cmdutil.abortgraft(ui, repo, graftstate)
3045 return cmdutil.abortgraft(ui, repo, graftstate)
3046 elif opts.get(b'continue'):
3046 elif opts.get(b'continue'):
3047 cont = True
3047 cont = True
3048 if revs:
3048 if revs:
3049 raise error.Abort(_(b"can't specify --continue and revisions"))
3049 raise error.Abort(_(b"can't specify --continue and revisions"))
3050 # read in unfinished revisions
3050 # read in unfinished revisions
3051 if graftstate.exists():
3051 if graftstate.exists():
3052 statedata = cmdutil.readgraftstate(repo, graftstate)
3052 statedata = cmdutil.readgraftstate(repo, graftstate)
3053 if statedata.get(b'date'):
3053 if statedata.get(b'date'):
3054 opts[b'date'] = statedata[b'date']
3054 opts[b'date'] = statedata[b'date']
3055 if statedata.get(b'user'):
3055 if statedata.get(b'user'):
3056 opts[b'user'] = statedata[b'user']
3056 opts[b'user'] = statedata[b'user']
3057 if statedata.get(b'log'):
3057 if statedata.get(b'log'):
3058 opts[b'log'] = True
3058 opts[b'log'] = True
3059 if statedata.get(b'no_commit'):
3059 if statedata.get(b'no_commit'):
3060 opts[b'no_commit'] = statedata.get(b'no_commit')
3060 opts[b'no_commit'] = statedata.get(b'no_commit')
3061 if statedata.get(b'base'):
3061 if statedata.get(b'base'):
3062 opts[b'base'] = statedata.get(b'base')
3062 opts[b'base'] = statedata.get(b'base')
3063 nodes = statedata[b'nodes']
3063 nodes = statedata[b'nodes']
3064 revs = [repo[node].rev() for node in nodes]
3064 revs = [repo[node].rev() for node in nodes]
3065 else:
3065 else:
3066 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3066 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3067 else:
3067 else:
3068 if not revs:
3068 if not revs:
3069 raise error.Abort(_(b'no revisions specified'))
3069 raise error.Abort(_(b'no revisions specified'))
3070 cmdutil.checkunfinished(repo)
3070 cmdutil.checkunfinished(repo)
3071 cmdutil.bailifchanged(repo)
3071 cmdutil.bailifchanged(repo)
3072 revs = scmutil.revrange(repo, revs)
3072 revs = scmutil.revrange(repo, revs)
3073
3073
3074 skipped = set()
3074 skipped = set()
3075 basectx = None
3075 basectx = None
3076 if opts.get(b'base'):
3076 if opts.get(b'base'):
3077 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3077 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3078 if basectx is None:
3078 if basectx is None:
3079 # check for merges
3079 # check for merges
3080 for rev in repo.revs(b'%ld and merge()', revs):
3080 for rev in repo.revs(b'%ld and merge()', revs):
3081 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3081 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3082 skipped.add(rev)
3082 skipped.add(rev)
3083 revs = [r for r in revs if r not in skipped]
3083 revs = [r for r in revs if r not in skipped]
3084 if not revs:
3084 if not revs:
3085 return -1
3085 return -1
3086 if basectx is not None and len(revs) != 1:
3086 if basectx is not None and len(revs) != 1:
3087 raise error.Abort(_(b'only one revision allowed with --base '))
3087 raise error.Abort(_(b'only one revision allowed with --base '))
3088
3088
3089 # Don't check in the --continue case, in effect retaining --force across
3089 # Don't check in the --continue case, in effect retaining --force across
3090 # --continues. That's because without --force, any revisions we decided to
3090 # --continues. That's because without --force, any revisions we decided to
3091 # skip would have been filtered out here, so they wouldn't have made their
3091 # skip would have been filtered out here, so they wouldn't have made their
3092 # way to the graftstate. With --force, any revisions we would have otherwise
3092 # way to the graftstate. With --force, any revisions we would have otherwise
3093 # skipped would not have been filtered out, and if they hadn't been applied
3093 # skipped would not have been filtered out, and if they hadn't been applied
3094 # already, they'd have been in the graftstate.
3094 # already, they'd have been in the graftstate.
3095 if not (cont or opts.get(b'force')) and basectx is None:
3095 if not (cont or opts.get(b'force')) and basectx is None:
3096 # check for ancestors of dest branch
3096 # check for ancestors of dest branch
3097 ancestors = repo.revs(b'%ld & (::.)', revs)
3097 ancestors = repo.revs(b'%ld & (::.)', revs)
3098 for rev in ancestors:
3098 for rev in ancestors:
3099 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3099 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3100
3100
3101 revs = [r for r in revs if r not in ancestors]
3101 revs = [r for r in revs if r not in ancestors]
3102
3102
3103 if not revs:
3103 if not revs:
3104 return -1
3104 return -1
3105
3105
3106 # analyze revs for earlier grafts
3106 # analyze revs for earlier grafts
3107 ids = {}
3107 ids = {}
3108 for ctx in repo.set(b"%ld", revs):
3108 for ctx in repo.set(b"%ld", revs):
3109 ids[ctx.hex()] = ctx.rev()
3109 ids[ctx.hex()] = ctx.rev()
3110 n = ctx.extra().get(b'source')
3110 n = ctx.extra().get(b'source')
3111 if n:
3111 if n:
3112 ids[n] = ctx.rev()
3112 ids[n] = ctx.rev()
3113
3113
3114 # check ancestors for earlier grafts
3114 # check ancestors for earlier grafts
3115 ui.debug(b'scanning for duplicate grafts\n')
3115 ui.debug(b'scanning for duplicate grafts\n')
3116
3116
3117 # The only changesets we can be sure doesn't contain grafts of any
3117 # The only changesets we can be sure doesn't contain grafts of any
3118 # revs, are the ones that are common ancestors of *all* revs:
3118 # revs, are the ones that are common ancestors of *all* revs:
3119 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3119 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3120 ctx = repo[rev]
3120 ctx = repo[rev]
3121 n = ctx.extra().get(b'source')
3121 n = ctx.extra().get(b'source')
3122 if n in ids:
3122 if n in ids:
3123 try:
3123 try:
3124 r = repo[n].rev()
3124 r = repo[n].rev()
3125 except error.RepoLookupError:
3125 except error.RepoLookupError:
3126 r = None
3126 r = None
3127 if r in revs:
3127 if r in revs:
3128 ui.warn(
3128 ui.warn(
3129 _(
3129 _(
3130 b'skipping revision %d:%s '
3130 b'skipping revision %d:%s '
3131 b'(already grafted to %d:%s)\n'
3131 b'(already grafted to %d:%s)\n'
3132 )
3132 )
3133 % (r, repo[r], rev, ctx)
3133 % (r, repo[r], rev, ctx)
3134 )
3134 )
3135 revs.remove(r)
3135 revs.remove(r)
3136 elif ids[n] in revs:
3136 elif ids[n] in revs:
3137 if r is None:
3137 if r is None:
3138 ui.warn(
3138 ui.warn(
3139 _(
3139 _(
3140 b'skipping already grafted revision %d:%s '
3140 b'skipping already grafted revision %d:%s '
3141 b'(%d:%s also has unknown origin %s)\n'
3141 b'(%d:%s also has unknown origin %s)\n'
3142 )
3142 )
3143 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3143 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3144 )
3144 )
3145 else:
3145 else:
3146 ui.warn(
3146 ui.warn(
3147 _(
3147 _(
3148 b'skipping already grafted revision %d:%s '
3148 b'skipping already grafted revision %d:%s '
3149 b'(%d:%s also has origin %d:%s)\n'
3149 b'(%d:%s also has origin %d:%s)\n'
3150 )
3150 )
3151 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3151 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3152 )
3152 )
3153 revs.remove(ids[n])
3153 revs.remove(ids[n])
3154 elif ctx.hex() in ids:
3154 elif ctx.hex() in ids:
3155 r = ids[ctx.hex()]
3155 r = ids[ctx.hex()]
3156 if r in revs:
3156 if r in revs:
3157 ui.warn(
3157 ui.warn(
3158 _(
3158 _(
3159 b'skipping already grafted revision %d:%s '
3159 b'skipping already grafted revision %d:%s '
3160 b'(was grafted from %d:%s)\n'
3160 b'(was grafted from %d:%s)\n'
3161 )
3161 )
3162 % (r, repo[r], rev, ctx)
3162 % (r, repo[r], rev, ctx)
3163 )
3163 )
3164 revs.remove(r)
3164 revs.remove(r)
3165 if not revs:
3165 if not revs:
3166 return -1
3166 return -1
3167
3167
3168 if opts.get(b'no_commit'):
3168 if opts.get(b'no_commit'):
3169 statedata[b'no_commit'] = True
3169 statedata[b'no_commit'] = True
3170 if opts.get(b'base'):
3170 if opts.get(b'base'):
3171 statedata[b'base'] = opts[b'base']
3171 statedata[b'base'] = opts[b'base']
3172 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3172 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3173 desc = b'%d:%s "%s"' % (
3173 desc = b'%d:%s "%s"' % (
3174 ctx.rev(),
3174 ctx.rev(),
3175 ctx,
3175 ctx,
3176 ctx.description().split(b'\n', 1)[0],
3176 ctx.description().split(b'\n', 1)[0],
3177 )
3177 )
3178 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3178 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3179 if names:
3179 if names:
3180 desc += b' (%s)' % b' '.join(names)
3180 desc += b' (%s)' % b' '.join(names)
3181 ui.status(_(b'grafting %s\n') % desc)
3181 ui.status(_(b'grafting %s\n') % desc)
3182 if opts.get(b'dry_run'):
3182 if opts.get(b'dry_run'):
3183 continue
3183 continue
3184
3184
3185 source = ctx.extra().get(b'source')
3185 source = ctx.extra().get(b'source')
3186 extra = {}
3186 extra = {}
3187 if source:
3187 if source:
3188 extra[b'source'] = source
3188 extra[b'source'] = source
3189 extra[b'intermediate-source'] = ctx.hex()
3189 extra[b'intermediate-source'] = ctx.hex()
3190 else:
3190 else:
3191 extra[b'source'] = ctx.hex()
3191 extra[b'source'] = ctx.hex()
3192 user = ctx.user()
3192 user = ctx.user()
3193 if opts.get(b'user'):
3193 if opts.get(b'user'):
3194 user = opts[b'user']
3194 user = opts[b'user']
3195 statedata[b'user'] = user
3195 statedata[b'user'] = user
3196 date = ctx.date()
3196 date = ctx.date()
3197 if opts.get(b'date'):
3197 if opts.get(b'date'):
3198 date = opts[b'date']
3198 date = opts[b'date']
3199 statedata[b'date'] = date
3199 statedata[b'date'] = date
3200 message = ctx.description()
3200 message = ctx.description()
3201 if opts.get(b'log'):
3201 if opts.get(b'log'):
3202 message += b'\n(grafted from %s)' % ctx.hex()
3202 message += b'\n(grafted from %s)' % ctx.hex()
3203 statedata[b'log'] = True
3203 statedata[b'log'] = True
3204
3204
3205 # we don't merge the first commit when continuing
3205 # we don't merge the first commit when continuing
3206 if not cont:
3206 if not cont:
3207 # perform the graft merge with p1(rev) as 'ancestor'
3207 # perform the graft merge with p1(rev) as 'ancestor'
3208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3209 base = ctx.p1() if basectx is None else basectx
3209 base = ctx.p1() if basectx is None else basectx
3210 with ui.configoverride(overrides, b'graft'):
3210 with ui.configoverride(overrides, b'graft'):
3211 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3211 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3212 # report any conflicts
3212 # report any conflicts
3213 if stats.unresolvedcount > 0:
3213 if stats.unresolvedcount > 0:
3214 # write out state for --continue
3214 # write out state for --continue
3215 nodes = [repo[rev].hex() for rev in revs[pos:]]
3215 nodes = [repo[rev].hex() for rev in revs[pos:]]
3216 statedata[b'nodes'] = nodes
3216 statedata[b'nodes'] = nodes
3217 stateversion = 1
3217 stateversion = 1
3218 graftstate.save(stateversion, statedata)
3218 graftstate.save(stateversion, statedata)
3219 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3219 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3220 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3220 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3221 return 1
3221 return 1
3222 else:
3222 else:
3223 cont = False
3223 cont = False
3224
3224
3225 # commit if --no-commit is false
3225 # commit if --no-commit is false
3226 if not opts.get(b'no_commit'):
3226 if not opts.get(b'no_commit'):
3227 node = repo.commit(
3227 node = repo.commit(
3228 text=message, user=user, date=date, extra=extra, editor=editor
3228 text=message, user=user, date=date, extra=extra, editor=editor
3229 )
3229 )
3230 if node is None:
3230 if node is None:
3231 ui.warn(
3231 ui.warn(
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3233 % (ctx.rev(), ctx)
3233 % (ctx.rev(), ctx)
3234 )
3234 )
3235 # checking that newnodes exist because old state files won't have it
3235 # checking that newnodes exist because old state files won't have it
3236 elif statedata.get(b'newnodes') is not None:
3236 elif statedata.get(b'newnodes') is not None:
3237 statedata[b'newnodes'].append(node)
3237 statedata[b'newnodes'].append(node)
3238
3238
3239 # remove state when we complete successfully
3239 # remove state when we complete successfully
3240 if not opts.get(b'dry_run'):
3240 if not opts.get(b'dry_run'):
3241 graftstate.delete()
3241 graftstate.delete()
3242
3242
3243 return 0
3243 return 0
3244
3244
3245
3245
3246 def _stopgraft(ui, repo, graftstate):
3246 def _stopgraft(ui, repo, graftstate):
3247 """stop the interrupted graft"""
3247 """stop the interrupted graft"""
3248 if not graftstate.exists():
3248 if not graftstate.exists():
3249 raise error.Abort(_(b"no interrupted graft found"))
3249 raise error.Abort(_(b"no interrupted graft found"))
3250 pctx = repo[b'.']
3250 pctx = repo[b'.']
3251 mergemod.clean_update(pctx)
3251 mergemod.clean_update(pctx)
3252 graftstate.delete()
3252 graftstate.delete()
3253 ui.status(_(b"stopped the interrupted graft\n"))
3253 ui.status(_(b"stopped the interrupted graft\n"))
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3255 return 0
3255 return 0
3256
3256
3257
3257
3258 statemod.addunfinished(
3258 statemod.addunfinished(
3259 b'graft',
3259 b'graft',
3260 fname=b'graftstate',
3260 fname=b'graftstate',
3261 clearable=True,
3261 clearable=True,
3262 stopflag=True,
3262 stopflag=True,
3263 continueflag=True,
3263 continueflag=True,
3264 abortfunc=cmdutil.hgabortgraft,
3264 abortfunc=cmdutil.hgabortgraft,
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3266 )
3266 )
3267
3267
3268
3268
3269 @command(
3269 @command(
3270 b'grep',
3270 b'grep',
3271 [
3271 [
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3273 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3273 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3274 (
3274 (
3275 b'',
3275 b'',
3276 b'diff',
3276 b'diff',
3277 None,
3277 None,
3278 _(
3278 _(
3279 b'search revision differences for when the pattern was added '
3279 b'search revision differences for when the pattern was added '
3280 b'or removed'
3280 b'or removed'
3281 ),
3281 ),
3282 ),
3282 ),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3284 (
3284 (
3285 b'f',
3285 b'f',
3286 b'follow',
3286 b'follow',
3287 None,
3287 None,
3288 _(
3288 _(
3289 b'follow changeset history,'
3289 b'follow changeset history,'
3290 b' or file history across copies and renames'
3290 b' or file history across copies and renames'
3291 ),
3291 ),
3292 ),
3292 ),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3294 (
3294 (
3295 b'l',
3295 b'l',
3296 b'files-with-matches',
3296 b'files-with-matches',
3297 None,
3297 None,
3298 _(b'print only filenames and revisions that match'),
3298 _(b'print only filenames and revisions that match'),
3299 ),
3299 ),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3301 (
3301 (
3302 b'r',
3302 b'r',
3303 b'rev',
3303 b'rev',
3304 [],
3304 [],
3305 _(b'search files changed within revision range'),
3305 _(b'search files changed within revision range'),
3306 _(b'REV'),
3306 _(b'REV'),
3307 ),
3307 ),
3308 (
3308 (
3309 b'',
3309 b'',
3310 b'all-files',
3310 b'all-files',
3311 None,
3311 None,
3312 _(
3312 _(
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3314 ),
3314 ),
3315 ),
3315 ),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3318 ]
3318 ]
3319 + formatteropts
3319 + formatteropts
3320 + walkopts,
3320 + walkopts,
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3323 inferrepo=True,
3323 inferrepo=True,
3324 intents={INTENT_READONLY},
3324 intents={INTENT_READONLY},
3325 )
3325 )
3326 def grep(ui, repo, pattern, *pats, **opts):
3326 def grep(ui, repo, pattern, *pats, **opts):
3327 """search for a pattern in specified files
3327 """search for a pattern in specified files
3328
3328
3329 Search the working directory or revision history for a regular
3329 Search the working directory or revision history for a regular
3330 expression in the specified files for the entire repository.
3330 expression in the specified files for the entire repository.
3331
3331
3332 By default, grep searches the repository files in the working
3332 By default, grep searches the repository files in the working
3333 directory and prints the files where it finds a match. To specify
3333 directory and prints the files where it finds a match. To specify
3334 historical revisions instead of the working directory, use the
3334 historical revisions instead of the working directory, use the
3335 --rev flag.
3335 --rev flag.
3336
3336
3337 To search instead historical revision differences that contains a
3337 To search instead historical revision differences that contains a
3338 change in match status ("-" for a match that becomes a non-match,
3338 change in match status ("-" for a match that becomes a non-match,
3339 or "+" for a non-match that becomes a match), use the --diff flag.
3339 or "+" for a non-match that becomes a match), use the --diff flag.
3340
3340
3341 PATTERN can be any Python (roughly Perl-compatible) regular
3341 PATTERN can be any Python (roughly Perl-compatible) regular
3342 expression.
3342 expression.
3343
3343
3344 If no FILEs are specified and the --rev flag isn't supplied, all
3344 If no FILEs are specified and the --rev flag isn't supplied, all
3345 files in the working directory are searched. When using the --rev
3345 files in the working directory are searched. When using the --rev
3346 flag and specifying FILEs, use the --follow argument to also
3346 flag and specifying FILEs, use the --follow argument to also
3347 follow the specified FILEs across renames and copies.
3347 follow the specified FILEs across renames and copies.
3348
3348
3349 .. container:: verbose
3349 .. container:: verbose
3350
3350
3351 Template:
3351 Template:
3352
3352
3353 The following keywords are supported in addition to the common template
3353 The following keywords are supported in addition to the common template
3354 keywords and functions. See also :hg:`help templates`.
3354 keywords and functions. See also :hg:`help templates`.
3355
3355
3356 :change: String. Character denoting insertion ``+`` or removal ``-``.
3356 :change: String. Character denoting insertion ``+`` or removal ``-``.
3357 Available if ``--diff`` is specified.
3357 Available if ``--diff`` is specified.
3358 :lineno: Integer. Line number of the match.
3358 :lineno: Integer. Line number of the match.
3359 :path: String. Repository-absolute path of the file.
3359 :path: String. Repository-absolute path of the file.
3360 :texts: List of text chunks.
3360 :texts: List of text chunks.
3361
3361
3362 And each entry of ``{texts}`` provides the following sub-keywords.
3362 And each entry of ``{texts}`` provides the following sub-keywords.
3363
3363
3364 :matched: Boolean. True if the chunk matches the specified pattern.
3364 :matched: Boolean. True if the chunk matches the specified pattern.
3365 :text: String. Chunk content.
3365 :text: String. Chunk content.
3366
3366
3367 See :hg:`help templates.operators` for the list expansion syntax.
3367 See :hg:`help templates.operators` for the list expansion syntax.
3368
3368
3369 Returns 0 if a match is found, 1 otherwise.
3369 Returns 0 if a match is found, 1 otherwise.
3370
3370
3371 """
3371 """
3372 opts = pycompat.byteskwargs(opts)
3372 opts = pycompat.byteskwargs(opts)
3373 diff = opts.get(b'all') or opts.get(b'diff')
3373 diff = opts.get(b'all') or opts.get(b'diff')
3374 if diff and opts.get(b'all_files'):
3374 if diff and opts.get(b'all_files'):
3375 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3375 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3376 if opts.get(b'all_files') is None and not diff:
3376 if opts.get(b'all_files') is None and not diff:
3377 opts[b'all_files'] = True
3377 opts[b'all_files'] = True
3378 plaingrep = (
3378 plaingrep = (
3379 opts.get(b'all_files')
3379 opts.get(b'all_files')
3380 and not opts.get(b'rev')
3380 and not opts.get(b'rev')
3381 and not opts.get(b'follow')
3381 and not opts.get(b'follow')
3382 )
3382 )
3383 all_files = opts.get(b'all_files')
3383 all_files = opts.get(b'all_files')
3384 if plaingrep:
3384 if plaingrep:
3385 opts[b'rev'] = [b'wdir()']
3385 opts[b'rev'] = [b'wdir()']
3386
3386
3387 reflags = re.M
3387 reflags = re.M
3388 if opts.get(b'ignore_case'):
3388 if opts.get(b'ignore_case'):
3389 reflags |= re.I
3389 reflags |= re.I
3390 try:
3390 try:
3391 regexp = util.re.compile(pattern, reflags)
3391 regexp = util.re.compile(pattern, reflags)
3392 except re.error as inst:
3392 except re.error as inst:
3393 ui.warn(
3393 ui.warn(
3394 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3394 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3395 )
3395 )
3396 return 1
3396 return 1
3397 sep, eol = b':', b'\n'
3397 sep, eol = b':', b'\n'
3398 if opts.get(b'print0'):
3398 if opts.get(b'print0'):
3399 sep = eol = b'\0'
3399 sep = eol = b'\0'
3400
3400
3401 getfile = util.lrucachefunc(repo.file)
3401 getfile = util.lrucachefunc(repo.file)
3402
3402
3403 def matchlines(body):
3403 def matchlines(body, regexp):
3404 begin = 0
3404 begin = 0
3405 linenum = 0
3405 linenum = 0
3406 while begin < len(body):
3406 while begin < len(body):
3407 match = regexp.search(body, begin)
3407 match = regexp.search(body, begin)
3408 if not match:
3408 if not match:
3409 break
3409 break
3410 mstart, mend = match.span()
3410 mstart, mend = match.span()
3411 linenum += body.count(b'\n', begin, mstart) + 1
3411 linenum += body.count(b'\n', begin, mstart) + 1
3412 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3412 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3413 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3413 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3414 lend = begin - 1
3414 lend = begin - 1
3415 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3415 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3416
3416
3417 class linestate(object):
3417 class linestate(object):
3418 def __init__(self, line, linenum, colstart, colend):
3418 def __init__(self, line, linenum, colstart, colend):
3419 self.line = line
3419 self.line = line
3420 self.linenum = linenum
3420 self.linenum = linenum
3421 self.colstart = colstart
3421 self.colstart = colstart
3422 self.colend = colend
3422 self.colend = colend
3423
3423
3424 def __hash__(self):
3424 def __hash__(self):
3425 return hash(self.line)
3425 return hash(self.line)
3426
3426
3427 def __eq__(self, other):
3427 def __eq__(self, other):
3428 return self.line == other.line
3428 return self.line == other.line
3429
3429
3430 def findpos(self):
3430 def findpos(self, regexp):
3431 """Iterate all (start, end) indices of matches"""
3431 """Iterate all (start, end) indices of matches"""
3432 yield self.colstart, self.colend
3432 yield self.colstart, self.colend
3433 p = self.colend
3433 p = self.colend
3434 while p < len(self.line):
3434 while p < len(self.line):
3435 m = regexp.search(self.line, p)
3435 m = regexp.search(self.line, p)
3436 if not m:
3436 if not m:
3437 break
3437 break
3438 if m.end() == p:
3438 if m.end() == p:
3439 p += 1
3439 p += 1
3440 else:
3440 else:
3441 yield m.span()
3441 yield m.span()
3442 p = m.end()
3442 p = m.end()
3443
3443
3444 matches = {}
3444 matches = {}
3445 copies = {}
3445 copies = {}
3446
3446
3447 def grepbody(fn, rev, body):
3447 def grepbody(fn, rev, body):
3448 matches[rev].setdefault(fn, [])
3448 matches[rev].setdefault(fn, [])
3449 m = matches[rev][fn]
3449 m = matches[rev][fn]
3450 if body is None:
3450 if body is None:
3451 return
3451 return
3452
3452
3453 for lnum, cstart, cend, line in matchlines(body):
3453 for lnum, cstart, cend, line in matchlines(body, regexp):
3454 s = linestate(line, lnum, cstart, cend)
3454 s = linestate(line, lnum, cstart, cend)
3455 m.append(s)
3455 m.append(s)
3456
3456
3457 def difflinestates(a, b):
3457 def difflinestates(a, b):
3458 sm = difflib.SequenceMatcher(None, a, b)
3458 sm = difflib.SequenceMatcher(None, a, b)
3459 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3459 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3460 if tag == 'insert':
3460 if tag == 'insert':
3461 for i in pycompat.xrange(blo, bhi):
3461 for i in pycompat.xrange(blo, bhi):
3462 yield (b'+', b[i])
3462 yield (b'+', b[i])
3463 elif tag == 'delete':
3463 elif tag == 'delete':
3464 for i in pycompat.xrange(alo, ahi):
3464 for i in pycompat.xrange(alo, ahi):
3465 yield (b'-', a[i])
3465 yield (b'-', a[i])
3466 elif tag == 'replace':
3466 elif tag == 'replace':
3467 for i in pycompat.xrange(alo, ahi):
3467 for i in pycompat.xrange(alo, ahi):
3468 yield (b'-', a[i])
3468 yield (b'-', a[i])
3469 for i in pycompat.xrange(blo, bhi):
3469 for i in pycompat.xrange(blo, bhi):
3470 yield (b'+', b[i])
3470 yield (b'+', b[i])
3471
3471
3472 uipathfn = scmutil.getuipathfn(repo)
3472 uipathfn = scmutil.getuipathfn(repo)
3473
3473
3474 def display(fm, fn, ctx, pstates, states):
3474 def display(fm, fn, ctx, pstates, states):
3475 rev = scmutil.intrev(ctx)
3475 rev = scmutil.intrev(ctx)
3476 if fm.isplain():
3476 if fm.isplain():
3477 formatuser = ui.shortuser
3477 formatuser = ui.shortuser
3478 else:
3478 else:
3479 formatuser = pycompat.bytestr
3479 formatuser = pycompat.bytestr
3480 if ui.quiet:
3480 if ui.quiet:
3481 datefmt = b'%Y-%m-%d'
3481 datefmt = b'%Y-%m-%d'
3482 else:
3482 else:
3483 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3483 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3484 found = False
3484 found = False
3485
3485
3486 @util.cachefunc
3486 @util.cachefunc
3487 def binary():
3487 def binary():
3488 flog = getfile(fn)
3488 flog = getfile(fn)
3489 try:
3489 try:
3490 return stringutil.binary(flog.read(ctx.filenode(fn)))
3490 return stringutil.binary(flog.read(ctx.filenode(fn)))
3491 except error.WdirUnsupported:
3491 except error.WdirUnsupported:
3492 return ctx[fn].isbinary()
3492 return ctx[fn].isbinary()
3493
3493
3494 fieldnamemap = {b'linenumber': b'lineno'}
3494 fieldnamemap = {b'linenumber': b'lineno'}
3495 if diff:
3495 if diff:
3496 iter = difflinestates(pstates, states)
3496 iter = difflinestates(pstates, states)
3497 else:
3497 else:
3498 iter = [(b'', l) for l in states]
3498 iter = [(b'', l) for l in states]
3499 for change, l in iter:
3499 for change, l in iter:
3500 fm.startitem()
3500 fm.startitem()
3501 fm.context(ctx=ctx)
3501 fm.context(ctx=ctx)
3502 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3502 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3503 fm.plain(uipathfn(fn), label=b'grep.filename')
3503 fm.plain(uipathfn(fn), label=b'grep.filename')
3504
3504
3505 cols = [
3505 cols = [
3506 (b'rev', b'%d', rev, not plaingrep, b''),
3506 (b'rev', b'%d', rev, not plaingrep, b''),
3507 (
3507 (
3508 b'linenumber',
3508 b'linenumber',
3509 b'%d',
3509 b'%d',
3510 l.linenum,
3510 l.linenum,
3511 opts.get(b'line_number'),
3511 opts.get(b'line_number'),
3512 b'',
3512 b'',
3513 ),
3513 ),
3514 ]
3514 ]
3515 if diff:
3515 if diff:
3516 cols.append(
3516 cols.append(
3517 (
3517 (
3518 b'change',
3518 b'change',
3519 b'%s',
3519 b'%s',
3520 change,
3520 change,
3521 True,
3521 True,
3522 b'grep.inserted '
3522 b'grep.inserted '
3523 if change == b'+'
3523 if change == b'+'
3524 else b'grep.deleted ',
3524 else b'grep.deleted ',
3525 )
3525 )
3526 )
3526 )
3527 cols.extend(
3527 cols.extend(
3528 [
3528 [
3529 (
3529 (
3530 b'user',
3530 b'user',
3531 b'%s',
3531 b'%s',
3532 formatuser(ctx.user()),
3532 formatuser(ctx.user()),
3533 opts.get(b'user'),
3533 opts.get(b'user'),
3534 b'',
3534 b'',
3535 ),
3535 ),
3536 (
3536 (
3537 b'date',
3537 b'date',
3538 b'%s',
3538 b'%s',
3539 fm.formatdate(ctx.date(), datefmt),
3539 fm.formatdate(ctx.date(), datefmt),
3540 opts.get(b'date'),
3540 opts.get(b'date'),
3541 b'',
3541 b'',
3542 ),
3542 ),
3543 ]
3543 ]
3544 )
3544 )
3545 for name, fmt, data, cond, extra_label in cols:
3545 for name, fmt, data, cond, extra_label in cols:
3546 if cond:
3546 if cond:
3547 fm.plain(sep, label=b'grep.sep')
3547 fm.plain(sep, label=b'grep.sep')
3548 field = fieldnamemap.get(name, name)
3548 field = fieldnamemap.get(name, name)
3549 label = extra_label + (b'grep.%s' % name)
3549 label = extra_label + (b'grep.%s' % name)
3550 fm.condwrite(cond, field, fmt, data, label=label)
3550 fm.condwrite(cond, field, fmt, data, label=label)
3551 if not opts.get(b'files_with_matches'):
3551 if not opts.get(b'files_with_matches'):
3552 fm.plain(sep, label=b'grep.sep')
3552 fm.plain(sep, label=b'grep.sep')
3553 if not opts.get(b'text') and binary():
3553 if not opts.get(b'text') and binary():
3554 fm.plain(_(b" Binary file matches"))
3554 fm.plain(_(b" Binary file matches"))
3555 else:
3555 else:
3556 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3556 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3557 fm.plain(eol)
3557 fm.plain(eol)
3558 found = True
3558 found = True
3559 if opts.get(b'files_with_matches'):
3559 if opts.get(b'files_with_matches'):
3560 break
3560 break
3561 return found
3561 return found
3562
3562
3563 def displaymatches(fm, l):
3563 def displaymatches(fm, l):
3564 p = 0
3564 p = 0
3565 for s, e in l.findpos():
3565 for s, e in l.findpos(regexp):
3566 if p < s:
3566 if p < s:
3567 fm.startitem()
3567 fm.startitem()
3568 fm.write(b'text', b'%s', l.line[p:s])
3568 fm.write(b'text', b'%s', l.line[p:s])
3569 fm.data(matched=False)
3569 fm.data(matched=False)
3570 fm.startitem()
3570 fm.startitem()
3571 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3571 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3572 fm.data(matched=True)
3572 fm.data(matched=True)
3573 p = e
3573 p = e
3574 if p < len(l.line):
3574 if p < len(l.line):
3575 fm.startitem()
3575 fm.startitem()
3576 fm.write(b'text', b'%s', l.line[p:])
3576 fm.write(b'text', b'%s', l.line[p:])
3577 fm.data(matched=False)
3577 fm.data(matched=False)
3578 fm.end()
3578 fm.end()
3579
3579
3580 skip = set()
3580 skip = set()
3581 revfiles = {}
3581 revfiles = {}
3582 found = False
3582 found = False
3583 follow = opts.get(b'follow')
3583 follow = opts.get(b'follow')
3584
3584
3585 getrenamed = scmutil.getrenamedfn(repo)
3585 getrenamed = scmutil.getrenamedfn(repo)
3586
3586
3587 def readfile(ctx, fn):
3587 def readfile(ctx, fn):
3588 rev = ctx.rev()
3588 rev = ctx.rev()
3589 if rev is None:
3589 if rev is None:
3590 fctx = ctx[fn]
3590 fctx = ctx[fn]
3591 try:
3591 try:
3592 return fctx.data()
3592 return fctx.data()
3593 except IOError as e:
3593 except IOError as e:
3594 if e.errno != errno.ENOENT:
3594 if e.errno != errno.ENOENT:
3595 raise
3595 raise
3596 else:
3596 else:
3597 flog = getfile(fn)
3597 flog = getfile(fn)
3598 fnode = ctx.filenode(fn)
3598 fnode = ctx.filenode(fn)
3599 try:
3599 try:
3600 return flog.read(fnode)
3600 return flog.read(fnode)
3601 except error.CensoredNodeError:
3601 except error.CensoredNodeError:
3602 ui.warn(
3602 ui.warn(
3603 _(
3603 _(
3604 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3604 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3605 )
3605 )
3606 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3606 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3607 )
3607 )
3608
3608
3609 def prep(ctx, fmatch):
3609 def prep(ctx, fmatch):
3610 rev = ctx.rev()
3610 rev = ctx.rev()
3611 pctx = ctx.p1()
3611 pctx = ctx.p1()
3612 matches.setdefault(rev, {})
3612 matches.setdefault(rev, {})
3613 if diff:
3613 if diff:
3614 parent = pctx.rev()
3614 parent = pctx.rev()
3615 matches.setdefault(parent, {})
3615 matches.setdefault(parent, {})
3616 files = revfiles.setdefault(rev, [])
3616 files = revfiles.setdefault(rev, [])
3617 if rev is None:
3617 if rev is None:
3618 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3618 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3619 # pathauditor checks without this in mozilla-central
3619 # pathauditor checks without this in mozilla-central
3620 contextmanager = repo.wvfs.audit.cached
3620 contextmanager = repo.wvfs.audit.cached
3621 else:
3621 else:
3622 contextmanager = util.nullcontextmanager
3622 contextmanager = util.nullcontextmanager
3623 with contextmanager():
3623 with contextmanager():
3624 # TODO: maybe better to warn missing files?
3624 # TODO: maybe better to warn missing files?
3625 if all_files:
3625 if all_files:
3626 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3626 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3627 filenames = ctx.matches(fmatch)
3627 filenames = ctx.matches(fmatch)
3628 else:
3628 else:
3629 filenames = (f for f in ctx.files() if fmatch(f))
3629 filenames = (f for f in ctx.files() if fmatch(f))
3630 for fn in filenames:
3630 for fn in filenames:
3631 # fn might not exist in the revision (could be a file removed by
3631 # fn might not exist in the revision (could be a file removed by
3632 # the revision). We could check `fn not in ctx` even when rev is
3632 # the revision). We could check `fn not in ctx` even when rev is
3633 # None, but it's less racy to protect againt that in readfile.
3633 # None, but it's less racy to protect againt that in readfile.
3634 if rev is not None and fn not in ctx:
3634 if rev is not None and fn not in ctx:
3635 continue
3635 continue
3636
3636
3637 copy = None
3637 copy = None
3638 if follow:
3638 if follow:
3639 copy = getrenamed(fn, rev)
3639 copy = getrenamed(fn, rev)
3640 if copy:
3640 if copy:
3641 copies.setdefault(rev, {})[fn] = copy
3641 copies.setdefault(rev, {})[fn] = copy
3642 if fn in skip:
3642 if fn in skip:
3643 skip.add(copy)
3643 skip.add(copy)
3644 if fn in skip:
3644 if fn in skip:
3645 continue
3645 continue
3646 files.append(fn)
3646 files.append(fn)
3647
3647
3648 if fn not in matches[rev]:
3648 if fn not in matches[rev]:
3649 grepbody(fn, rev, readfile(ctx, fn))
3649 grepbody(fn, rev, readfile(ctx, fn))
3650
3650
3651 if diff:
3651 if diff:
3652 pfn = copy or fn
3652 pfn = copy or fn
3653 if pfn not in matches[parent] and pfn in pctx:
3653 if pfn not in matches[parent] and pfn in pctx:
3654 grepbody(pfn, parent, readfile(pctx, pfn))
3654 grepbody(pfn, parent, readfile(pctx, pfn))
3655
3655
3656 wopts = logcmdutil.walkopts(
3656 wopts = logcmdutil.walkopts(
3657 pats=pats,
3657 pats=pats,
3658 opts=opts,
3658 opts=opts,
3659 revspec=opts[b'rev'],
3659 revspec=opts[b'rev'],
3660 include_pats=opts[b'include'],
3660 include_pats=opts[b'include'],
3661 exclude_pats=opts[b'exclude'],
3661 exclude_pats=opts[b'exclude'],
3662 follow=follow,
3662 follow=follow,
3663 force_changelog_traversal=all_files,
3663 force_changelog_traversal=all_files,
3664 filter_revisions_by_pats=not all_files,
3664 filter_revisions_by_pats=not all_files,
3665 )
3665 )
3666 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3666 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3667
3667
3668 ui.pager(b'grep')
3668 ui.pager(b'grep')
3669 fm = ui.formatter(b'grep', opts)
3669 fm = ui.formatter(b'grep', opts)
3670 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3670 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3671 rev = ctx.rev()
3671 rev = ctx.rev()
3672 parent = ctx.p1().rev()
3672 parent = ctx.p1().rev()
3673 for fn in sorted(revfiles.get(rev, [])):
3673 for fn in sorted(revfiles.get(rev, [])):
3674 states = matches[rev][fn]
3674 states = matches[rev][fn]
3675 copy = copies.get(rev, {}).get(fn)
3675 copy = copies.get(rev, {}).get(fn)
3676 if fn in skip:
3676 if fn in skip:
3677 if copy:
3677 if copy:
3678 skip.add(copy)
3678 skip.add(copy)
3679 continue
3679 continue
3680 pstates = matches.get(parent, {}).get(copy or fn, [])
3680 pstates = matches.get(parent, {}).get(copy or fn, [])
3681 if pstates or states:
3681 if pstates or states:
3682 r = display(fm, fn, ctx, pstates, states)
3682 r = display(fm, fn, ctx, pstates, states)
3683 found = found or r
3683 found = found or r
3684 if r and not diff and not all_files:
3684 if r and not diff and not all_files:
3685 skip.add(fn)
3685 skip.add(fn)
3686 if copy:
3686 if copy:
3687 skip.add(copy)
3687 skip.add(copy)
3688 del revfiles[rev]
3688 del revfiles[rev]
3689 # We will keep the matches dict for the duration of the window
3689 # We will keep the matches dict for the duration of the window
3690 # clear the matches dict once the window is over
3690 # clear the matches dict once the window is over
3691 if not revfiles:
3691 if not revfiles:
3692 matches.clear()
3692 matches.clear()
3693 fm.end()
3693 fm.end()
3694
3694
3695 return not found
3695 return not found
3696
3696
3697
3697
3698 @command(
3698 @command(
3699 b'heads',
3699 b'heads',
3700 [
3700 [
3701 (
3701 (
3702 b'r',
3702 b'r',
3703 b'rev',
3703 b'rev',
3704 b'',
3704 b'',
3705 _(b'show only heads which are descendants of STARTREV'),
3705 _(b'show only heads which are descendants of STARTREV'),
3706 _(b'STARTREV'),
3706 _(b'STARTREV'),
3707 ),
3707 ),
3708 (b't', b'topo', False, _(b'show topological heads only')),
3708 (b't', b'topo', False, _(b'show topological heads only')),
3709 (
3709 (
3710 b'a',
3710 b'a',
3711 b'active',
3711 b'active',
3712 False,
3712 False,
3713 _(b'show active branchheads only (DEPRECATED)'),
3713 _(b'show active branchheads only (DEPRECATED)'),
3714 ),
3714 ),
3715 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3715 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3716 ]
3716 ]
3717 + templateopts,
3717 + templateopts,
3718 _(b'[-ct] [-r STARTREV] [REV]...'),
3718 _(b'[-ct] [-r STARTREV] [REV]...'),
3719 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3719 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3720 intents={INTENT_READONLY},
3720 intents={INTENT_READONLY},
3721 )
3721 )
3722 def heads(ui, repo, *branchrevs, **opts):
3722 def heads(ui, repo, *branchrevs, **opts):
3723 """show branch heads
3723 """show branch heads
3724
3724
3725 With no arguments, show all open branch heads in the repository.
3725 With no arguments, show all open branch heads in the repository.
3726 Branch heads are changesets that have no descendants on the
3726 Branch heads are changesets that have no descendants on the
3727 same branch. They are where development generally takes place and
3727 same branch. They are where development generally takes place and
3728 are the usual targets for update and merge operations.
3728 are the usual targets for update and merge operations.
3729
3729
3730 If one or more REVs are given, only open branch heads on the
3730 If one or more REVs are given, only open branch heads on the
3731 branches associated with the specified changesets are shown. This
3731 branches associated with the specified changesets are shown. This
3732 means that you can use :hg:`heads .` to see the heads on the
3732 means that you can use :hg:`heads .` to see the heads on the
3733 currently checked-out branch.
3733 currently checked-out branch.
3734
3734
3735 If -c/--closed is specified, also show branch heads marked closed
3735 If -c/--closed is specified, also show branch heads marked closed
3736 (see :hg:`commit --close-branch`).
3736 (see :hg:`commit --close-branch`).
3737
3737
3738 If STARTREV is specified, only those heads that are descendants of
3738 If STARTREV is specified, only those heads that are descendants of
3739 STARTREV will be displayed.
3739 STARTREV will be displayed.
3740
3740
3741 If -t/--topo is specified, named branch mechanics will be ignored and only
3741 If -t/--topo is specified, named branch mechanics will be ignored and only
3742 topological heads (changesets with no children) will be shown.
3742 topological heads (changesets with no children) will be shown.
3743
3743
3744 Returns 0 if matching heads are found, 1 if not.
3744 Returns 0 if matching heads are found, 1 if not.
3745 """
3745 """
3746
3746
3747 opts = pycompat.byteskwargs(opts)
3747 opts = pycompat.byteskwargs(opts)
3748 start = None
3748 start = None
3749 rev = opts.get(b'rev')
3749 rev = opts.get(b'rev')
3750 if rev:
3750 if rev:
3751 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3751 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3752 start = scmutil.revsingle(repo, rev, None).node()
3752 start = scmutil.revsingle(repo, rev, None).node()
3753
3753
3754 if opts.get(b'topo'):
3754 if opts.get(b'topo'):
3755 heads = [repo[h] for h in repo.heads(start)]
3755 heads = [repo[h] for h in repo.heads(start)]
3756 else:
3756 else:
3757 heads = []
3757 heads = []
3758 for branch in repo.branchmap():
3758 for branch in repo.branchmap():
3759 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3759 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3760 heads = [repo[h] for h in heads]
3760 heads = [repo[h] for h in heads]
3761
3761
3762 if branchrevs:
3762 if branchrevs:
3763 branches = {
3763 branches = {
3764 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3764 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3765 }
3765 }
3766 heads = [h for h in heads if h.branch() in branches]
3766 heads = [h for h in heads if h.branch() in branches]
3767
3767
3768 if opts.get(b'active') and branchrevs:
3768 if opts.get(b'active') and branchrevs:
3769 dagheads = repo.heads(start)
3769 dagheads = repo.heads(start)
3770 heads = [h for h in heads if h.node() in dagheads]
3770 heads = [h for h in heads if h.node() in dagheads]
3771
3771
3772 if branchrevs:
3772 if branchrevs:
3773 haveheads = {h.branch() for h in heads}
3773 haveheads = {h.branch() for h in heads}
3774 if branches - haveheads:
3774 if branches - haveheads:
3775 headless = b', '.join(b for b in branches - haveheads)
3775 headless = b', '.join(b for b in branches - haveheads)
3776 msg = _(b'no open branch heads found on branches %s')
3776 msg = _(b'no open branch heads found on branches %s')
3777 if opts.get(b'rev'):
3777 if opts.get(b'rev'):
3778 msg += _(b' (started at %s)') % opts[b'rev']
3778 msg += _(b' (started at %s)') % opts[b'rev']
3779 ui.warn((msg + b'\n') % headless)
3779 ui.warn((msg + b'\n') % headless)
3780
3780
3781 if not heads:
3781 if not heads:
3782 return 1
3782 return 1
3783
3783
3784 ui.pager(b'heads')
3784 ui.pager(b'heads')
3785 heads = sorted(heads, key=lambda x: -(x.rev()))
3785 heads = sorted(heads, key=lambda x: -(x.rev()))
3786 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3786 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3787 for ctx in heads:
3787 for ctx in heads:
3788 displayer.show(ctx)
3788 displayer.show(ctx)
3789 displayer.close()
3789 displayer.close()
3790
3790
3791
3791
3792 @command(
3792 @command(
3793 b'help',
3793 b'help',
3794 [
3794 [
3795 (b'e', b'extension', None, _(b'show only help for extensions')),
3795 (b'e', b'extension', None, _(b'show only help for extensions')),
3796 (b'c', b'command', None, _(b'show only help for commands')),
3796 (b'c', b'command', None, _(b'show only help for commands')),
3797 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3797 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3798 (
3798 (
3799 b's',
3799 b's',
3800 b'system',
3800 b'system',
3801 [],
3801 [],
3802 _(b'show help for specific platform(s)'),
3802 _(b'show help for specific platform(s)'),
3803 _(b'PLATFORM'),
3803 _(b'PLATFORM'),
3804 ),
3804 ),
3805 ],
3805 ],
3806 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3806 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3807 helpcategory=command.CATEGORY_HELP,
3807 helpcategory=command.CATEGORY_HELP,
3808 norepo=True,
3808 norepo=True,
3809 intents={INTENT_READONLY},
3809 intents={INTENT_READONLY},
3810 )
3810 )
3811 def help_(ui, name=None, **opts):
3811 def help_(ui, name=None, **opts):
3812 """show help for a given topic or a help overview
3812 """show help for a given topic or a help overview
3813
3813
3814 With no arguments, print a list of commands with short help messages.
3814 With no arguments, print a list of commands with short help messages.
3815
3815
3816 Given a topic, extension, or command name, print help for that
3816 Given a topic, extension, or command name, print help for that
3817 topic.
3817 topic.
3818
3818
3819 Returns 0 if successful.
3819 Returns 0 if successful.
3820 """
3820 """
3821
3821
3822 keep = opts.get('system') or []
3822 keep = opts.get('system') or []
3823 if len(keep) == 0:
3823 if len(keep) == 0:
3824 if pycompat.sysplatform.startswith(b'win'):
3824 if pycompat.sysplatform.startswith(b'win'):
3825 keep.append(b'windows')
3825 keep.append(b'windows')
3826 elif pycompat.sysplatform == b'OpenVMS':
3826 elif pycompat.sysplatform == b'OpenVMS':
3827 keep.append(b'vms')
3827 keep.append(b'vms')
3828 elif pycompat.sysplatform == b'plan9':
3828 elif pycompat.sysplatform == b'plan9':
3829 keep.append(b'plan9')
3829 keep.append(b'plan9')
3830 else:
3830 else:
3831 keep.append(b'unix')
3831 keep.append(b'unix')
3832 keep.append(pycompat.sysplatform.lower())
3832 keep.append(pycompat.sysplatform.lower())
3833 if ui.verbose:
3833 if ui.verbose:
3834 keep.append(b'verbose')
3834 keep.append(b'verbose')
3835
3835
3836 commands = sys.modules[__name__]
3836 commands = sys.modules[__name__]
3837 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3837 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3838 ui.pager(b'help')
3838 ui.pager(b'help')
3839 ui.write(formatted)
3839 ui.write(formatted)
3840
3840
3841
3841
3842 @command(
3842 @command(
3843 b'identify|id',
3843 b'identify|id',
3844 [
3844 [
3845 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3845 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3846 (b'n', b'num', None, _(b'show local revision number')),
3846 (b'n', b'num', None, _(b'show local revision number')),
3847 (b'i', b'id', None, _(b'show global revision id')),
3847 (b'i', b'id', None, _(b'show global revision id')),
3848 (b'b', b'branch', None, _(b'show branch')),
3848 (b'b', b'branch', None, _(b'show branch')),
3849 (b't', b'tags', None, _(b'show tags')),
3849 (b't', b'tags', None, _(b'show tags')),
3850 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3850 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3851 ]
3851 ]
3852 + remoteopts
3852 + remoteopts
3853 + formatteropts,
3853 + formatteropts,
3854 _(b'[-nibtB] [-r REV] [SOURCE]'),
3854 _(b'[-nibtB] [-r REV] [SOURCE]'),
3855 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3855 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3856 optionalrepo=True,
3856 optionalrepo=True,
3857 intents={INTENT_READONLY},
3857 intents={INTENT_READONLY},
3858 )
3858 )
3859 def identify(
3859 def identify(
3860 ui,
3860 ui,
3861 repo,
3861 repo,
3862 source=None,
3862 source=None,
3863 rev=None,
3863 rev=None,
3864 num=None,
3864 num=None,
3865 id=None,
3865 id=None,
3866 branch=None,
3866 branch=None,
3867 tags=None,
3867 tags=None,
3868 bookmarks=None,
3868 bookmarks=None,
3869 **opts
3869 **opts
3870 ):
3870 ):
3871 """identify the working directory or specified revision
3871 """identify the working directory or specified revision
3872
3872
3873 Print a summary identifying the repository state at REV using one or
3873 Print a summary identifying the repository state at REV using one or
3874 two parent hash identifiers, followed by a "+" if the working
3874 two parent hash identifiers, followed by a "+" if the working
3875 directory has uncommitted changes, the branch name (if not default),
3875 directory has uncommitted changes, the branch name (if not default),
3876 a list of tags, and a list of bookmarks.
3876 a list of tags, and a list of bookmarks.
3877
3877
3878 When REV is not given, print a summary of the current state of the
3878 When REV is not given, print a summary of the current state of the
3879 repository including the working directory. Specify -r. to get information
3879 repository including the working directory. Specify -r. to get information
3880 of the working directory parent without scanning uncommitted changes.
3880 of the working directory parent without scanning uncommitted changes.
3881
3881
3882 Specifying a path to a repository root or Mercurial bundle will
3882 Specifying a path to a repository root or Mercurial bundle will
3883 cause lookup to operate on that repository/bundle.
3883 cause lookup to operate on that repository/bundle.
3884
3884
3885 .. container:: verbose
3885 .. container:: verbose
3886
3886
3887 Template:
3887 Template:
3888
3888
3889 The following keywords are supported in addition to the common template
3889 The following keywords are supported in addition to the common template
3890 keywords and functions. See also :hg:`help templates`.
3890 keywords and functions. See also :hg:`help templates`.
3891
3891
3892 :dirty: String. Character ``+`` denoting if the working directory has
3892 :dirty: String. Character ``+`` denoting if the working directory has
3893 uncommitted changes.
3893 uncommitted changes.
3894 :id: String. One or two nodes, optionally followed by ``+``.
3894 :id: String. One or two nodes, optionally followed by ``+``.
3895 :parents: List of strings. Parent nodes of the changeset.
3895 :parents: List of strings. Parent nodes of the changeset.
3896
3896
3897 Examples:
3897 Examples:
3898
3898
3899 - generate a build identifier for the working directory::
3899 - generate a build identifier for the working directory::
3900
3900
3901 hg id --id > build-id.dat
3901 hg id --id > build-id.dat
3902
3902
3903 - find the revision corresponding to a tag::
3903 - find the revision corresponding to a tag::
3904
3904
3905 hg id -n -r 1.3
3905 hg id -n -r 1.3
3906
3906
3907 - check the most recent revision of a remote repository::
3907 - check the most recent revision of a remote repository::
3908
3908
3909 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3909 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3910
3910
3911 See :hg:`log` for generating more information about specific revisions,
3911 See :hg:`log` for generating more information about specific revisions,
3912 including full hash identifiers.
3912 including full hash identifiers.
3913
3913
3914 Returns 0 if successful.
3914 Returns 0 if successful.
3915 """
3915 """
3916
3916
3917 opts = pycompat.byteskwargs(opts)
3917 opts = pycompat.byteskwargs(opts)
3918 if not repo and not source:
3918 if not repo and not source:
3919 raise error.Abort(
3919 raise error.Abort(
3920 _(b"there is no Mercurial repository here (.hg not found)")
3920 _(b"there is no Mercurial repository here (.hg not found)")
3921 )
3921 )
3922
3922
3923 default = not (num or id or branch or tags or bookmarks)
3923 default = not (num or id or branch or tags or bookmarks)
3924 output = []
3924 output = []
3925 revs = []
3925 revs = []
3926
3926
3927 if source:
3927 if source:
3928 source, branches = hg.parseurl(ui.expandpath(source))
3928 source, branches = hg.parseurl(ui.expandpath(source))
3929 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3929 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3930 repo = peer.local()
3930 repo = peer.local()
3931 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3931 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3932
3932
3933 fm = ui.formatter(b'identify', opts)
3933 fm = ui.formatter(b'identify', opts)
3934 fm.startitem()
3934 fm.startitem()
3935
3935
3936 if not repo:
3936 if not repo:
3937 if num or branch or tags:
3937 if num or branch or tags:
3938 raise error.Abort(
3938 raise error.Abort(
3939 _(b"can't query remote revision number, branch, or tags")
3939 _(b"can't query remote revision number, branch, or tags")
3940 )
3940 )
3941 if not rev and revs:
3941 if not rev and revs:
3942 rev = revs[0]
3942 rev = revs[0]
3943 if not rev:
3943 if not rev:
3944 rev = b"tip"
3944 rev = b"tip"
3945
3945
3946 remoterev = peer.lookup(rev)
3946 remoterev = peer.lookup(rev)
3947 hexrev = fm.hexfunc(remoterev)
3947 hexrev = fm.hexfunc(remoterev)
3948 if default or id:
3948 if default or id:
3949 output = [hexrev]
3949 output = [hexrev]
3950 fm.data(id=hexrev)
3950 fm.data(id=hexrev)
3951
3951
3952 @util.cachefunc
3952 @util.cachefunc
3953 def getbms():
3953 def getbms():
3954 bms = []
3954 bms = []
3955
3955
3956 if b'bookmarks' in peer.listkeys(b'namespaces'):
3956 if b'bookmarks' in peer.listkeys(b'namespaces'):
3957 hexremoterev = hex(remoterev)
3957 hexremoterev = hex(remoterev)
3958 bms = [
3958 bms = [
3959 bm
3959 bm
3960 for bm, bmr in pycompat.iteritems(
3960 for bm, bmr in pycompat.iteritems(
3961 peer.listkeys(b'bookmarks')
3961 peer.listkeys(b'bookmarks')
3962 )
3962 )
3963 if bmr == hexremoterev
3963 if bmr == hexremoterev
3964 ]
3964 ]
3965
3965
3966 return sorted(bms)
3966 return sorted(bms)
3967
3967
3968 if fm.isplain():
3968 if fm.isplain():
3969 if bookmarks:
3969 if bookmarks:
3970 output.extend(getbms())
3970 output.extend(getbms())
3971 elif default and not ui.quiet:
3971 elif default and not ui.quiet:
3972 # multiple bookmarks for a single parent separated by '/'
3972 # multiple bookmarks for a single parent separated by '/'
3973 bm = b'/'.join(getbms())
3973 bm = b'/'.join(getbms())
3974 if bm:
3974 if bm:
3975 output.append(bm)
3975 output.append(bm)
3976 else:
3976 else:
3977 fm.data(node=hex(remoterev))
3977 fm.data(node=hex(remoterev))
3978 if bookmarks or b'bookmarks' in fm.datahint():
3978 if bookmarks or b'bookmarks' in fm.datahint():
3979 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3979 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3980 else:
3980 else:
3981 if rev:
3981 if rev:
3982 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3982 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3983 ctx = scmutil.revsingle(repo, rev, None)
3983 ctx = scmutil.revsingle(repo, rev, None)
3984
3984
3985 if ctx.rev() is None:
3985 if ctx.rev() is None:
3986 ctx = repo[None]
3986 ctx = repo[None]
3987 parents = ctx.parents()
3987 parents = ctx.parents()
3988 taglist = []
3988 taglist = []
3989 for p in parents:
3989 for p in parents:
3990 taglist.extend(p.tags())
3990 taglist.extend(p.tags())
3991
3991
3992 dirty = b""
3992 dirty = b""
3993 if ctx.dirty(missing=True, merge=False, branch=False):
3993 if ctx.dirty(missing=True, merge=False, branch=False):
3994 dirty = b'+'
3994 dirty = b'+'
3995 fm.data(dirty=dirty)
3995 fm.data(dirty=dirty)
3996
3996
3997 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3997 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3998 if default or id:
3998 if default or id:
3999 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3999 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
4000 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4000 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
4001
4001
4002 if num:
4002 if num:
4003 numoutput = [b"%d" % p.rev() for p in parents]
4003 numoutput = [b"%d" % p.rev() for p in parents]
4004 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4004 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
4005
4005
4006 fm.data(
4006 fm.data(
4007 parents=fm.formatlist(
4007 parents=fm.formatlist(
4008 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4008 [fm.hexfunc(p.node()) for p in parents], name=b'node'
4009 )
4009 )
4010 )
4010 )
4011 else:
4011 else:
4012 hexoutput = fm.hexfunc(ctx.node())
4012 hexoutput = fm.hexfunc(ctx.node())
4013 if default or id:
4013 if default or id:
4014 output = [hexoutput]
4014 output = [hexoutput]
4015 fm.data(id=hexoutput)
4015 fm.data(id=hexoutput)
4016
4016
4017 if num:
4017 if num:
4018 output.append(pycompat.bytestr(ctx.rev()))
4018 output.append(pycompat.bytestr(ctx.rev()))
4019 taglist = ctx.tags()
4019 taglist = ctx.tags()
4020
4020
4021 if default and not ui.quiet:
4021 if default and not ui.quiet:
4022 b = ctx.branch()
4022 b = ctx.branch()
4023 if b != b'default':
4023 if b != b'default':
4024 output.append(b"(%s)" % b)
4024 output.append(b"(%s)" % b)
4025
4025
4026 # multiple tags for a single parent separated by '/'
4026 # multiple tags for a single parent separated by '/'
4027 t = b'/'.join(taglist)
4027 t = b'/'.join(taglist)
4028 if t:
4028 if t:
4029 output.append(t)
4029 output.append(t)
4030
4030
4031 # multiple bookmarks for a single parent separated by '/'
4031 # multiple bookmarks for a single parent separated by '/'
4032 bm = b'/'.join(ctx.bookmarks())
4032 bm = b'/'.join(ctx.bookmarks())
4033 if bm:
4033 if bm:
4034 output.append(bm)
4034 output.append(bm)
4035 else:
4035 else:
4036 if branch:
4036 if branch:
4037 output.append(ctx.branch())
4037 output.append(ctx.branch())
4038
4038
4039 if tags:
4039 if tags:
4040 output.extend(taglist)
4040 output.extend(taglist)
4041
4041
4042 if bookmarks:
4042 if bookmarks:
4043 output.extend(ctx.bookmarks())
4043 output.extend(ctx.bookmarks())
4044
4044
4045 fm.data(node=ctx.hex())
4045 fm.data(node=ctx.hex())
4046 fm.data(branch=ctx.branch())
4046 fm.data(branch=ctx.branch())
4047 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4047 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4048 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4048 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4049 fm.context(ctx=ctx)
4049 fm.context(ctx=ctx)
4050
4050
4051 fm.plain(b"%s\n" % b' '.join(output))
4051 fm.plain(b"%s\n" % b' '.join(output))
4052 fm.end()
4052 fm.end()
4053
4053
4054
4054
4055 @command(
4055 @command(
4056 b'import|patch',
4056 b'import|patch',
4057 [
4057 [
4058 (
4058 (
4059 b'p',
4059 b'p',
4060 b'strip',
4060 b'strip',
4061 1,
4061 1,
4062 _(
4062 _(
4063 b'directory strip option for patch. This has the same '
4063 b'directory strip option for patch. This has the same '
4064 b'meaning as the corresponding patch option'
4064 b'meaning as the corresponding patch option'
4065 ),
4065 ),
4066 _(b'NUM'),
4066 _(b'NUM'),
4067 ),
4067 ),
4068 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4068 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4069 (b'', b'secret', None, _(b'use the secret phase for committing')),
4069 (b'', b'secret', None, _(b'use the secret phase for committing')),
4070 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4070 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4071 (
4071 (
4072 b'f',
4072 b'f',
4073 b'force',
4073 b'force',
4074 None,
4074 None,
4075 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4075 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4076 ),
4076 ),
4077 (
4077 (
4078 b'',
4078 b'',
4079 b'no-commit',
4079 b'no-commit',
4080 None,
4080 None,
4081 _(b"don't commit, just update the working directory"),
4081 _(b"don't commit, just update the working directory"),
4082 ),
4082 ),
4083 (
4083 (
4084 b'',
4084 b'',
4085 b'bypass',
4085 b'bypass',
4086 None,
4086 None,
4087 _(b"apply patch without touching the working directory"),
4087 _(b"apply patch without touching the working directory"),
4088 ),
4088 ),
4089 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4089 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4090 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4090 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4091 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4091 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4092 (
4092 (
4093 b'',
4093 b'',
4094 b'import-branch',
4094 b'import-branch',
4095 None,
4095 None,
4096 _(b'use any branch information in patch (implied by --exact)'),
4096 _(b'use any branch information in patch (implied by --exact)'),
4097 ),
4097 ),
4098 ]
4098 ]
4099 + commitopts
4099 + commitopts
4100 + commitopts2
4100 + commitopts2
4101 + similarityopts,
4101 + similarityopts,
4102 _(b'[OPTION]... PATCH...'),
4102 _(b'[OPTION]... PATCH...'),
4103 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4103 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4104 )
4104 )
4105 def import_(ui, repo, patch1=None, *patches, **opts):
4105 def import_(ui, repo, patch1=None, *patches, **opts):
4106 """import an ordered set of patches
4106 """import an ordered set of patches
4107
4107
4108 Import a list of patches and commit them individually (unless
4108 Import a list of patches and commit them individually (unless
4109 --no-commit is specified).
4109 --no-commit is specified).
4110
4110
4111 To read a patch from standard input (stdin), use "-" as the patch
4111 To read a patch from standard input (stdin), use "-" as the patch
4112 name. If a URL is specified, the patch will be downloaded from
4112 name. If a URL is specified, the patch will be downloaded from
4113 there.
4113 there.
4114
4114
4115 Import first applies changes to the working directory (unless
4115 Import first applies changes to the working directory (unless
4116 --bypass is specified), import will abort if there are outstanding
4116 --bypass is specified), import will abort if there are outstanding
4117 changes.
4117 changes.
4118
4118
4119 Use --bypass to apply and commit patches directly to the
4119 Use --bypass to apply and commit patches directly to the
4120 repository, without affecting the working directory. Without
4120 repository, without affecting the working directory. Without
4121 --exact, patches will be applied on top of the working directory
4121 --exact, patches will be applied on top of the working directory
4122 parent revision.
4122 parent revision.
4123
4123
4124 You can import a patch straight from a mail message. Even patches
4124 You can import a patch straight from a mail message. Even patches
4125 as attachments work (to use the body part, it must have type
4125 as attachments work (to use the body part, it must have type
4126 text/plain or text/x-patch). From and Subject headers of email
4126 text/plain or text/x-patch). From and Subject headers of email
4127 message are used as default committer and commit message. All
4127 message are used as default committer and commit message. All
4128 text/plain body parts before first diff are added to the commit
4128 text/plain body parts before first diff are added to the commit
4129 message.
4129 message.
4130
4130
4131 If the imported patch was generated by :hg:`export`, user and
4131 If the imported patch was generated by :hg:`export`, user and
4132 description from patch override values from message headers and
4132 description from patch override values from message headers and
4133 body. Values given on command line with -m/--message and -u/--user
4133 body. Values given on command line with -m/--message and -u/--user
4134 override these.
4134 override these.
4135
4135
4136 If --exact is specified, import will set the working directory to
4136 If --exact is specified, import will set the working directory to
4137 the parent of each patch before applying it, and will abort if the
4137 the parent of each patch before applying it, and will abort if the
4138 resulting changeset has a different ID than the one recorded in
4138 resulting changeset has a different ID than the one recorded in
4139 the patch. This will guard against various ways that portable
4139 the patch. This will guard against various ways that portable
4140 patch formats and mail systems might fail to transfer Mercurial
4140 patch formats and mail systems might fail to transfer Mercurial
4141 data or metadata. See :hg:`bundle` for lossless transmission.
4141 data or metadata. See :hg:`bundle` for lossless transmission.
4142
4142
4143 Use --partial to ensure a changeset will be created from the patch
4143 Use --partial to ensure a changeset will be created from the patch
4144 even if some hunks fail to apply. Hunks that fail to apply will be
4144 even if some hunks fail to apply. Hunks that fail to apply will be
4145 written to a <target-file>.rej file. Conflicts can then be resolved
4145 written to a <target-file>.rej file. Conflicts can then be resolved
4146 by hand before :hg:`commit --amend` is run to update the created
4146 by hand before :hg:`commit --amend` is run to update the created
4147 changeset. This flag exists to let people import patches that
4147 changeset. This flag exists to let people import patches that
4148 partially apply without losing the associated metadata (author,
4148 partially apply without losing the associated metadata (author,
4149 date, description, ...).
4149 date, description, ...).
4150
4150
4151 .. note::
4151 .. note::
4152
4152
4153 When no hunks apply cleanly, :hg:`import --partial` will create
4153 When no hunks apply cleanly, :hg:`import --partial` will create
4154 an empty changeset, importing only the patch metadata.
4154 an empty changeset, importing only the patch metadata.
4155
4155
4156 With -s/--similarity, hg will attempt to discover renames and
4156 With -s/--similarity, hg will attempt to discover renames and
4157 copies in the patch in the same way as :hg:`addremove`.
4157 copies in the patch in the same way as :hg:`addremove`.
4158
4158
4159 It is possible to use external patch programs to perform the patch
4159 It is possible to use external patch programs to perform the patch
4160 by setting the ``ui.patch`` configuration option. For the default
4160 by setting the ``ui.patch`` configuration option. For the default
4161 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4161 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4162 See :hg:`help config` for more information about configuration
4162 See :hg:`help config` for more information about configuration
4163 files and how to use these options.
4163 files and how to use these options.
4164
4164
4165 See :hg:`help dates` for a list of formats valid for -d/--date.
4165 See :hg:`help dates` for a list of formats valid for -d/--date.
4166
4166
4167 .. container:: verbose
4167 .. container:: verbose
4168
4168
4169 Examples:
4169 Examples:
4170
4170
4171 - import a traditional patch from a website and detect renames::
4171 - import a traditional patch from a website and detect renames::
4172
4172
4173 hg import -s 80 http://example.com/bugfix.patch
4173 hg import -s 80 http://example.com/bugfix.patch
4174
4174
4175 - import a changeset from an hgweb server::
4175 - import a changeset from an hgweb server::
4176
4176
4177 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4177 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4178
4178
4179 - import all the patches in an Unix-style mbox::
4179 - import all the patches in an Unix-style mbox::
4180
4180
4181 hg import incoming-patches.mbox
4181 hg import incoming-patches.mbox
4182
4182
4183 - import patches from stdin::
4183 - import patches from stdin::
4184
4184
4185 hg import -
4185 hg import -
4186
4186
4187 - attempt to exactly restore an exported changeset (not always
4187 - attempt to exactly restore an exported changeset (not always
4188 possible)::
4188 possible)::
4189
4189
4190 hg import --exact proposed-fix.patch
4190 hg import --exact proposed-fix.patch
4191
4191
4192 - use an external tool to apply a patch which is too fuzzy for
4192 - use an external tool to apply a patch which is too fuzzy for
4193 the default internal tool.
4193 the default internal tool.
4194
4194
4195 hg import --config ui.patch="patch --merge" fuzzy.patch
4195 hg import --config ui.patch="patch --merge" fuzzy.patch
4196
4196
4197 - change the default fuzzing from 2 to a less strict 7
4197 - change the default fuzzing from 2 to a less strict 7
4198
4198
4199 hg import --config ui.fuzz=7 fuzz.patch
4199 hg import --config ui.fuzz=7 fuzz.patch
4200
4200
4201 Returns 0 on success, 1 on partial success (see --partial).
4201 Returns 0 on success, 1 on partial success (see --partial).
4202 """
4202 """
4203
4203
4204 opts = pycompat.byteskwargs(opts)
4204 opts = pycompat.byteskwargs(opts)
4205 if not patch1:
4205 if not patch1:
4206 raise error.Abort(_(b'need at least one patch to import'))
4206 raise error.Abort(_(b'need at least one patch to import'))
4207
4207
4208 patches = (patch1,) + patches
4208 patches = (patch1,) + patches
4209
4209
4210 date = opts.get(b'date')
4210 date = opts.get(b'date')
4211 if date:
4211 if date:
4212 opts[b'date'] = dateutil.parsedate(date)
4212 opts[b'date'] = dateutil.parsedate(date)
4213
4213
4214 exact = opts.get(b'exact')
4214 exact = opts.get(b'exact')
4215 update = not opts.get(b'bypass')
4215 update = not opts.get(b'bypass')
4216 if not update and opts.get(b'no_commit'):
4216 if not update and opts.get(b'no_commit'):
4217 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4217 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4218 if opts.get(b'secret') and opts.get(b'no_commit'):
4218 if opts.get(b'secret') and opts.get(b'no_commit'):
4219 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4219 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4220 try:
4220 try:
4221 sim = float(opts.get(b'similarity') or 0)
4221 sim = float(opts.get(b'similarity') or 0)
4222 except ValueError:
4222 except ValueError:
4223 raise error.Abort(_(b'similarity must be a number'))
4223 raise error.Abort(_(b'similarity must be a number'))
4224 if sim < 0 or sim > 100:
4224 if sim < 0 or sim > 100:
4225 raise error.Abort(_(b'similarity must be between 0 and 100'))
4225 raise error.Abort(_(b'similarity must be between 0 and 100'))
4226 if sim and not update:
4226 if sim and not update:
4227 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4227 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4228 if exact:
4228 if exact:
4229 if opts.get(b'edit'):
4229 if opts.get(b'edit'):
4230 raise error.Abort(_(b'cannot use --exact with --edit'))
4230 raise error.Abort(_(b'cannot use --exact with --edit'))
4231 if opts.get(b'prefix'):
4231 if opts.get(b'prefix'):
4232 raise error.Abort(_(b'cannot use --exact with --prefix'))
4232 raise error.Abort(_(b'cannot use --exact with --prefix'))
4233
4233
4234 base = opts[b"base"]
4234 base = opts[b"base"]
4235 msgs = []
4235 msgs = []
4236 ret = 0
4236 ret = 0
4237
4237
4238 with repo.wlock():
4238 with repo.wlock():
4239 if update:
4239 if update:
4240 cmdutil.checkunfinished(repo)
4240 cmdutil.checkunfinished(repo)
4241 if exact or not opts.get(b'force'):
4241 if exact or not opts.get(b'force'):
4242 cmdutil.bailifchanged(repo)
4242 cmdutil.bailifchanged(repo)
4243
4243
4244 if not opts.get(b'no_commit'):
4244 if not opts.get(b'no_commit'):
4245 lock = repo.lock
4245 lock = repo.lock
4246 tr = lambda: repo.transaction(b'import')
4246 tr = lambda: repo.transaction(b'import')
4247 dsguard = util.nullcontextmanager
4247 dsguard = util.nullcontextmanager
4248 else:
4248 else:
4249 lock = util.nullcontextmanager
4249 lock = util.nullcontextmanager
4250 tr = util.nullcontextmanager
4250 tr = util.nullcontextmanager
4251 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4251 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4252 with lock(), tr(), dsguard():
4252 with lock(), tr(), dsguard():
4253 parents = repo[None].parents()
4253 parents = repo[None].parents()
4254 for patchurl in patches:
4254 for patchurl in patches:
4255 if patchurl == b'-':
4255 if patchurl == b'-':
4256 ui.status(_(b'applying patch from stdin\n'))
4256 ui.status(_(b'applying patch from stdin\n'))
4257 patchfile = ui.fin
4257 patchfile = ui.fin
4258 patchurl = b'stdin' # for error message
4258 patchurl = b'stdin' # for error message
4259 else:
4259 else:
4260 patchurl = os.path.join(base, patchurl)
4260 patchurl = os.path.join(base, patchurl)
4261 ui.status(_(b'applying %s\n') % patchurl)
4261 ui.status(_(b'applying %s\n') % patchurl)
4262 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4262 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4263
4263
4264 haspatch = False
4264 haspatch = False
4265 for hunk in patch.split(patchfile):
4265 for hunk in patch.split(patchfile):
4266 with patch.extract(ui, hunk) as patchdata:
4266 with patch.extract(ui, hunk) as patchdata:
4267 msg, node, rej = cmdutil.tryimportone(
4267 msg, node, rej = cmdutil.tryimportone(
4268 ui, repo, patchdata, parents, opts, msgs, hg.clean
4268 ui, repo, patchdata, parents, opts, msgs, hg.clean
4269 )
4269 )
4270 if msg:
4270 if msg:
4271 haspatch = True
4271 haspatch = True
4272 ui.note(msg + b'\n')
4272 ui.note(msg + b'\n')
4273 if update or exact:
4273 if update or exact:
4274 parents = repo[None].parents()
4274 parents = repo[None].parents()
4275 else:
4275 else:
4276 parents = [repo[node]]
4276 parents = [repo[node]]
4277 if rej:
4277 if rej:
4278 ui.write_err(_(b"patch applied partially\n"))
4278 ui.write_err(_(b"patch applied partially\n"))
4279 ui.write_err(
4279 ui.write_err(
4280 _(
4280 _(
4281 b"(fix the .rej files and run "
4281 b"(fix the .rej files and run "
4282 b"`hg commit --amend`)\n"
4282 b"`hg commit --amend`)\n"
4283 )
4283 )
4284 )
4284 )
4285 ret = 1
4285 ret = 1
4286 break
4286 break
4287
4287
4288 if not haspatch:
4288 if not haspatch:
4289 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4289 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4290
4290
4291 if msgs:
4291 if msgs:
4292 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4292 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4293 return ret
4293 return ret
4294
4294
4295
4295
4296 @command(
4296 @command(
4297 b'incoming|in',
4297 b'incoming|in',
4298 [
4298 [
4299 (
4299 (
4300 b'f',
4300 b'f',
4301 b'force',
4301 b'force',
4302 None,
4302 None,
4303 _(b'run even if remote repository is unrelated'),
4303 _(b'run even if remote repository is unrelated'),
4304 ),
4304 ),
4305 (b'n', b'newest-first', None, _(b'show newest record first')),
4305 (b'n', b'newest-first', None, _(b'show newest record first')),
4306 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4306 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4307 (
4307 (
4308 b'r',
4308 b'r',
4309 b'rev',
4309 b'rev',
4310 [],
4310 [],
4311 _(b'a remote changeset intended to be added'),
4311 _(b'a remote changeset intended to be added'),
4312 _(b'REV'),
4312 _(b'REV'),
4313 ),
4313 ),
4314 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4314 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4315 (
4315 (
4316 b'b',
4316 b'b',
4317 b'branch',
4317 b'branch',
4318 [],
4318 [],
4319 _(b'a specific branch you would like to pull'),
4319 _(b'a specific branch you would like to pull'),
4320 _(b'BRANCH'),
4320 _(b'BRANCH'),
4321 ),
4321 ),
4322 ]
4322 ]
4323 + logopts
4323 + logopts
4324 + remoteopts
4324 + remoteopts
4325 + subrepoopts,
4325 + subrepoopts,
4326 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4326 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4327 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4327 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4328 )
4328 )
4329 def incoming(ui, repo, source=b"default", **opts):
4329 def incoming(ui, repo, source=b"default", **opts):
4330 """show new changesets found in source
4330 """show new changesets found in source
4331
4331
4332 Show new changesets found in the specified path/URL or the default
4332 Show new changesets found in the specified path/URL or the default
4333 pull location. These are the changesets that would have been pulled
4333 pull location. These are the changesets that would have been pulled
4334 by :hg:`pull` at the time you issued this command.
4334 by :hg:`pull` at the time you issued this command.
4335
4335
4336 See pull for valid source format details.
4336 See pull for valid source format details.
4337
4337
4338 .. container:: verbose
4338 .. container:: verbose
4339
4339
4340 With -B/--bookmarks, the result of bookmark comparison between
4340 With -B/--bookmarks, the result of bookmark comparison between
4341 local and remote repositories is displayed. With -v/--verbose,
4341 local and remote repositories is displayed. With -v/--verbose,
4342 status is also displayed for each bookmark like below::
4342 status is also displayed for each bookmark like below::
4343
4343
4344 BM1 01234567890a added
4344 BM1 01234567890a added
4345 BM2 1234567890ab advanced
4345 BM2 1234567890ab advanced
4346 BM3 234567890abc diverged
4346 BM3 234567890abc diverged
4347 BM4 34567890abcd changed
4347 BM4 34567890abcd changed
4348
4348
4349 The action taken locally when pulling depends on the
4349 The action taken locally when pulling depends on the
4350 status of each bookmark:
4350 status of each bookmark:
4351
4351
4352 :``added``: pull will create it
4352 :``added``: pull will create it
4353 :``advanced``: pull will update it
4353 :``advanced``: pull will update it
4354 :``diverged``: pull will create a divergent bookmark
4354 :``diverged``: pull will create a divergent bookmark
4355 :``changed``: result depends on remote changesets
4355 :``changed``: result depends on remote changesets
4356
4356
4357 From the point of view of pulling behavior, bookmark
4357 From the point of view of pulling behavior, bookmark
4358 existing only in the remote repository are treated as ``added``,
4358 existing only in the remote repository are treated as ``added``,
4359 even if it is in fact locally deleted.
4359 even if it is in fact locally deleted.
4360
4360
4361 .. container:: verbose
4361 .. container:: verbose
4362
4362
4363 For remote repository, using --bundle avoids downloading the
4363 For remote repository, using --bundle avoids downloading the
4364 changesets twice if the incoming is followed by a pull.
4364 changesets twice if the incoming is followed by a pull.
4365
4365
4366 Examples:
4366 Examples:
4367
4367
4368 - show incoming changes with patches and full description::
4368 - show incoming changes with patches and full description::
4369
4369
4370 hg incoming -vp
4370 hg incoming -vp
4371
4371
4372 - show incoming changes excluding merges, store a bundle::
4372 - show incoming changes excluding merges, store a bundle::
4373
4373
4374 hg in -vpM --bundle incoming.hg
4374 hg in -vpM --bundle incoming.hg
4375 hg pull incoming.hg
4375 hg pull incoming.hg
4376
4376
4377 - briefly list changes inside a bundle::
4377 - briefly list changes inside a bundle::
4378
4378
4379 hg in changes.hg -T "{desc|firstline}\\n"
4379 hg in changes.hg -T "{desc|firstline}\\n"
4380
4380
4381 Returns 0 if there are incoming changes, 1 otherwise.
4381 Returns 0 if there are incoming changes, 1 otherwise.
4382 """
4382 """
4383 opts = pycompat.byteskwargs(opts)
4383 opts = pycompat.byteskwargs(opts)
4384 if opts.get(b'graph'):
4384 if opts.get(b'graph'):
4385 logcmdutil.checkunsupportedgraphflags([], opts)
4385 logcmdutil.checkunsupportedgraphflags([], opts)
4386
4386
4387 def display(other, chlist, displayer):
4387 def display(other, chlist, displayer):
4388 revdag = logcmdutil.graphrevs(other, chlist, opts)
4388 revdag = logcmdutil.graphrevs(other, chlist, opts)
4389 logcmdutil.displaygraph(
4389 logcmdutil.displaygraph(
4390 ui, repo, revdag, displayer, graphmod.asciiedges
4390 ui, repo, revdag, displayer, graphmod.asciiedges
4391 )
4391 )
4392
4392
4393 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4393 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4394 return 0
4394 return 0
4395
4395
4396 if opts.get(b'bundle') and opts.get(b'subrepos'):
4396 if opts.get(b'bundle') and opts.get(b'subrepos'):
4397 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4397 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4398
4398
4399 if opts.get(b'bookmarks'):
4399 if opts.get(b'bookmarks'):
4400 source, branches = hg.parseurl(
4400 source, branches = hg.parseurl(
4401 ui.expandpath(source), opts.get(b'branch')
4401 ui.expandpath(source), opts.get(b'branch')
4402 )
4402 )
4403 other = hg.peer(repo, opts, source)
4403 other = hg.peer(repo, opts, source)
4404 if b'bookmarks' not in other.listkeys(b'namespaces'):
4404 if b'bookmarks' not in other.listkeys(b'namespaces'):
4405 ui.warn(_(b"remote doesn't support bookmarks\n"))
4405 ui.warn(_(b"remote doesn't support bookmarks\n"))
4406 return 0
4406 return 0
4407 ui.pager(b'incoming')
4407 ui.pager(b'incoming')
4408 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4408 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4409 return bookmarks.incoming(ui, repo, other)
4409 return bookmarks.incoming(ui, repo, other)
4410
4410
4411 repo._subtoppath = ui.expandpath(source)
4411 repo._subtoppath = ui.expandpath(source)
4412 try:
4412 try:
4413 return hg.incoming(ui, repo, source, opts)
4413 return hg.incoming(ui, repo, source, opts)
4414 finally:
4414 finally:
4415 del repo._subtoppath
4415 del repo._subtoppath
4416
4416
4417
4417
4418 @command(
4418 @command(
4419 b'init',
4419 b'init',
4420 remoteopts,
4420 remoteopts,
4421 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4421 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4422 helpcategory=command.CATEGORY_REPO_CREATION,
4422 helpcategory=command.CATEGORY_REPO_CREATION,
4423 helpbasic=True,
4423 helpbasic=True,
4424 norepo=True,
4424 norepo=True,
4425 )
4425 )
4426 def init(ui, dest=b".", **opts):
4426 def init(ui, dest=b".", **opts):
4427 """create a new repository in the given directory
4427 """create a new repository in the given directory
4428
4428
4429 Initialize a new repository in the given directory. If the given
4429 Initialize a new repository in the given directory. If the given
4430 directory does not exist, it will be created.
4430 directory does not exist, it will be created.
4431
4431
4432 If no directory is given, the current directory is used.
4432 If no directory is given, the current directory is used.
4433
4433
4434 It is possible to specify an ``ssh://`` URL as the destination.
4434 It is possible to specify an ``ssh://`` URL as the destination.
4435 See :hg:`help urls` for more information.
4435 See :hg:`help urls` for more information.
4436
4436
4437 Returns 0 on success.
4437 Returns 0 on success.
4438 """
4438 """
4439 opts = pycompat.byteskwargs(opts)
4439 opts = pycompat.byteskwargs(opts)
4440 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4440 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4441
4441
4442
4442
4443 @command(
4443 @command(
4444 b'locate',
4444 b'locate',
4445 [
4445 [
4446 (
4446 (
4447 b'r',
4447 b'r',
4448 b'rev',
4448 b'rev',
4449 b'',
4449 b'',
4450 _(b'search the repository as it is in REV'),
4450 _(b'search the repository as it is in REV'),
4451 _(b'REV'),
4451 _(b'REV'),
4452 ),
4452 ),
4453 (
4453 (
4454 b'0',
4454 b'0',
4455 b'print0',
4455 b'print0',
4456 None,
4456 None,
4457 _(b'end filenames with NUL, for use with xargs'),
4457 _(b'end filenames with NUL, for use with xargs'),
4458 ),
4458 ),
4459 (
4459 (
4460 b'f',
4460 b'f',
4461 b'fullpath',
4461 b'fullpath',
4462 None,
4462 None,
4463 _(b'print complete paths from the filesystem root'),
4463 _(b'print complete paths from the filesystem root'),
4464 ),
4464 ),
4465 ]
4465 ]
4466 + walkopts,
4466 + walkopts,
4467 _(b'[OPTION]... [PATTERN]...'),
4467 _(b'[OPTION]... [PATTERN]...'),
4468 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4468 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4469 )
4469 )
4470 def locate(ui, repo, *pats, **opts):
4470 def locate(ui, repo, *pats, **opts):
4471 """locate files matching specific patterns (DEPRECATED)
4471 """locate files matching specific patterns (DEPRECATED)
4472
4472
4473 Print files under Mercurial control in the working directory whose
4473 Print files under Mercurial control in the working directory whose
4474 names match the given patterns.
4474 names match the given patterns.
4475
4475
4476 By default, this command searches all directories in the working
4476 By default, this command searches all directories in the working
4477 directory. To search just the current directory and its
4477 directory. To search just the current directory and its
4478 subdirectories, use "--include .".
4478 subdirectories, use "--include .".
4479
4479
4480 If no patterns are given to match, this command prints the names
4480 If no patterns are given to match, this command prints the names
4481 of all files under Mercurial control in the working directory.
4481 of all files under Mercurial control in the working directory.
4482
4482
4483 If you want to feed the output of this command into the "xargs"
4483 If you want to feed the output of this command into the "xargs"
4484 command, use the -0 option to both this command and "xargs". This
4484 command, use the -0 option to both this command and "xargs". This
4485 will avoid the problem of "xargs" treating single filenames that
4485 will avoid the problem of "xargs" treating single filenames that
4486 contain whitespace as multiple filenames.
4486 contain whitespace as multiple filenames.
4487
4487
4488 See :hg:`help files` for a more versatile command.
4488 See :hg:`help files` for a more versatile command.
4489
4489
4490 Returns 0 if a match is found, 1 otherwise.
4490 Returns 0 if a match is found, 1 otherwise.
4491 """
4491 """
4492 opts = pycompat.byteskwargs(opts)
4492 opts = pycompat.byteskwargs(opts)
4493 if opts.get(b'print0'):
4493 if opts.get(b'print0'):
4494 end = b'\0'
4494 end = b'\0'
4495 else:
4495 else:
4496 end = b'\n'
4496 end = b'\n'
4497 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4497 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4498
4498
4499 ret = 1
4499 ret = 1
4500 m = scmutil.match(
4500 m = scmutil.match(
4501 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4501 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4502 )
4502 )
4503
4503
4504 ui.pager(b'locate')
4504 ui.pager(b'locate')
4505 if ctx.rev() is None:
4505 if ctx.rev() is None:
4506 # When run on the working copy, "locate" includes removed files, so
4506 # When run on the working copy, "locate" includes removed files, so
4507 # we get the list of files from the dirstate.
4507 # we get the list of files from the dirstate.
4508 filesgen = sorted(repo.dirstate.matches(m))
4508 filesgen = sorted(repo.dirstate.matches(m))
4509 else:
4509 else:
4510 filesgen = ctx.matches(m)
4510 filesgen = ctx.matches(m)
4511 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4511 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4512 for abs in filesgen:
4512 for abs in filesgen:
4513 if opts.get(b'fullpath'):
4513 if opts.get(b'fullpath'):
4514 ui.write(repo.wjoin(abs), end)
4514 ui.write(repo.wjoin(abs), end)
4515 else:
4515 else:
4516 ui.write(uipathfn(abs), end)
4516 ui.write(uipathfn(abs), end)
4517 ret = 0
4517 ret = 0
4518
4518
4519 return ret
4519 return ret
4520
4520
4521
4521
4522 @command(
4522 @command(
4523 b'log|history',
4523 b'log|history',
4524 [
4524 [
4525 (
4525 (
4526 b'f',
4526 b'f',
4527 b'follow',
4527 b'follow',
4528 None,
4528 None,
4529 _(
4529 _(
4530 b'follow changeset history, or file history across copies and renames'
4530 b'follow changeset history, or file history across copies and renames'
4531 ),
4531 ),
4532 ),
4532 ),
4533 (
4533 (
4534 b'',
4534 b'',
4535 b'follow-first',
4535 b'follow-first',
4536 None,
4536 None,
4537 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4537 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4538 ),
4538 ),
4539 (
4539 (
4540 b'd',
4540 b'd',
4541 b'date',
4541 b'date',
4542 b'',
4542 b'',
4543 _(b'show revisions matching date spec'),
4543 _(b'show revisions matching date spec'),
4544 _(b'DATE'),
4544 _(b'DATE'),
4545 ),
4545 ),
4546 (b'C', b'copies', None, _(b'show copied files')),
4546 (b'C', b'copies', None, _(b'show copied files')),
4547 (
4547 (
4548 b'k',
4548 b'k',
4549 b'keyword',
4549 b'keyword',
4550 [],
4550 [],
4551 _(b'do case-insensitive search for a given text'),
4551 _(b'do case-insensitive search for a given text'),
4552 _(b'TEXT'),
4552 _(b'TEXT'),
4553 ),
4553 ),
4554 (
4554 (
4555 b'r',
4555 b'r',
4556 b'rev',
4556 b'rev',
4557 [],
4557 [],
4558 _(b'show the specified revision or revset'),
4558 _(b'show the specified revision or revset'),
4559 _(b'REV'),
4559 _(b'REV'),
4560 ),
4560 ),
4561 (
4561 (
4562 b'L',
4562 b'L',
4563 b'line-range',
4563 b'line-range',
4564 [],
4564 [],
4565 _(b'follow line range of specified file (EXPERIMENTAL)'),
4565 _(b'follow line range of specified file (EXPERIMENTAL)'),
4566 _(b'FILE,RANGE'),
4566 _(b'FILE,RANGE'),
4567 ),
4567 ),
4568 (
4568 (
4569 b'',
4569 b'',
4570 b'removed',
4570 b'removed',
4571 None,
4571 None,
4572 _(b'include revisions where files were removed'),
4572 _(b'include revisions where files were removed'),
4573 ),
4573 ),
4574 (
4574 (
4575 b'm',
4575 b'm',
4576 b'only-merges',
4576 b'only-merges',
4577 None,
4577 None,
4578 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4578 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4579 ),
4579 ),
4580 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4580 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4581 (
4581 (
4582 b'',
4582 b'',
4583 b'only-branch',
4583 b'only-branch',
4584 [],
4584 [],
4585 _(
4585 _(
4586 b'show only changesets within the given named branch (DEPRECATED)'
4586 b'show only changesets within the given named branch (DEPRECATED)'
4587 ),
4587 ),
4588 _(b'BRANCH'),
4588 _(b'BRANCH'),
4589 ),
4589 ),
4590 (
4590 (
4591 b'b',
4591 b'b',
4592 b'branch',
4592 b'branch',
4593 [],
4593 [],
4594 _(b'show changesets within the given named branch'),
4594 _(b'show changesets within the given named branch'),
4595 _(b'BRANCH'),
4595 _(b'BRANCH'),
4596 ),
4596 ),
4597 (
4597 (
4598 b'P',
4598 b'P',
4599 b'prune',
4599 b'prune',
4600 [],
4600 [],
4601 _(b'do not display revision or any of its ancestors'),
4601 _(b'do not display revision or any of its ancestors'),
4602 _(b'REV'),
4602 _(b'REV'),
4603 ),
4603 ),
4604 ]
4604 ]
4605 + logopts
4605 + logopts
4606 + walkopts,
4606 + walkopts,
4607 _(b'[OPTION]... [FILE]'),
4607 _(b'[OPTION]... [FILE]'),
4608 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4608 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4609 helpbasic=True,
4609 helpbasic=True,
4610 inferrepo=True,
4610 inferrepo=True,
4611 intents={INTENT_READONLY},
4611 intents={INTENT_READONLY},
4612 )
4612 )
4613 def log(ui, repo, *pats, **opts):
4613 def log(ui, repo, *pats, **opts):
4614 """show revision history of entire repository or files
4614 """show revision history of entire repository or files
4615
4615
4616 Print the revision history of the specified files or the entire
4616 Print the revision history of the specified files or the entire
4617 project.
4617 project.
4618
4618
4619 If no revision range is specified, the default is ``tip:0`` unless
4619 If no revision range is specified, the default is ``tip:0`` unless
4620 --follow is set, in which case the working directory parent is
4620 --follow is set, in which case the working directory parent is
4621 used as the starting revision.
4621 used as the starting revision.
4622
4622
4623 File history is shown without following rename or copy history of
4623 File history is shown without following rename or copy history of
4624 files. Use -f/--follow with a filename to follow history across
4624 files. Use -f/--follow with a filename to follow history across
4625 renames and copies. --follow without a filename will only show
4625 renames and copies. --follow without a filename will only show
4626 ancestors of the starting revision.
4626 ancestors of the starting revision.
4627
4627
4628 By default this command prints revision number and changeset id,
4628 By default this command prints revision number and changeset id,
4629 tags, non-trivial parents, user, date and time, and a summary for
4629 tags, non-trivial parents, user, date and time, and a summary for
4630 each commit. When the -v/--verbose switch is used, the list of
4630 each commit. When the -v/--verbose switch is used, the list of
4631 changed files and full commit message are shown.
4631 changed files and full commit message are shown.
4632
4632
4633 With --graph the revisions are shown as an ASCII art DAG with the most
4633 With --graph the revisions are shown as an ASCII art DAG with the most
4634 recent changeset at the top.
4634 recent changeset at the top.
4635 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4635 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4636 involved in an unresolved merge conflict, '_' closes a branch,
4636 involved in an unresolved merge conflict, '_' closes a branch,
4637 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4637 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4638 changeset from the lines below is a parent of the 'o' merge on the same
4638 changeset from the lines below is a parent of the 'o' merge on the same
4639 line.
4639 line.
4640 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4640 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4641 of a '|' indicates one or more revisions in a path are omitted.
4641 of a '|' indicates one or more revisions in a path are omitted.
4642
4642
4643 .. container:: verbose
4643 .. container:: verbose
4644
4644
4645 Use -L/--line-range FILE,M:N options to follow the history of lines
4645 Use -L/--line-range FILE,M:N options to follow the history of lines
4646 from M to N in FILE. With -p/--patch only diff hunks affecting
4646 from M to N in FILE. With -p/--patch only diff hunks affecting
4647 specified line range will be shown. This option requires --follow;
4647 specified line range will be shown. This option requires --follow;
4648 it can be specified multiple times. Currently, this option is not
4648 it can be specified multiple times. Currently, this option is not
4649 compatible with --graph. This option is experimental.
4649 compatible with --graph. This option is experimental.
4650
4650
4651 .. note::
4651 .. note::
4652
4652
4653 :hg:`log --patch` may generate unexpected diff output for merge
4653 :hg:`log --patch` may generate unexpected diff output for merge
4654 changesets, as it will only compare the merge changeset against
4654 changesets, as it will only compare the merge changeset against
4655 its first parent. Also, only files different from BOTH parents
4655 its first parent. Also, only files different from BOTH parents
4656 will appear in files:.
4656 will appear in files:.
4657
4657
4658 .. note::
4658 .. note::
4659
4659
4660 For performance reasons, :hg:`log FILE` may omit duplicate changes
4660 For performance reasons, :hg:`log FILE` may omit duplicate changes
4661 made on branches and will not show removals or mode changes. To
4661 made on branches and will not show removals or mode changes. To
4662 see all such changes, use the --removed switch.
4662 see all such changes, use the --removed switch.
4663
4663
4664 .. container:: verbose
4664 .. container:: verbose
4665
4665
4666 .. note::
4666 .. note::
4667
4667
4668 The history resulting from -L/--line-range options depends on diff
4668 The history resulting from -L/--line-range options depends on diff
4669 options; for instance if white-spaces are ignored, respective changes
4669 options; for instance if white-spaces are ignored, respective changes
4670 with only white-spaces in specified line range will not be listed.
4670 with only white-spaces in specified line range will not be listed.
4671
4671
4672 .. container:: verbose
4672 .. container:: verbose
4673
4673
4674 Some examples:
4674 Some examples:
4675
4675
4676 - changesets with full descriptions and file lists::
4676 - changesets with full descriptions and file lists::
4677
4677
4678 hg log -v
4678 hg log -v
4679
4679
4680 - changesets ancestral to the working directory::
4680 - changesets ancestral to the working directory::
4681
4681
4682 hg log -f
4682 hg log -f
4683
4683
4684 - last 10 commits on the current branch::
4684 - last 10 commits on the current branch::
4685
4685
4686 hg log -l 10 -b .
4686 hg log -l 10 -b .
4687
4687
4688 - changesets showing all modifications of a file, including removals::
4688 - changesets showing all modifications of a file, including removals::
4689
4689
4690 hg log --removed file.c
4690 hg log --removed file.c
4691
4691
4692 - all changesets that touch a directory, with diffs, excluding merges::
4692 - all changesets that touch a directory, with diffs, excluding merges::
4693
4693
4694 hg log -Mp lib/
4694 hg log -Mp lib/
4695
4695
4696 - all revision numbers that match a keyword::
4696 - all revision numbers that match a keyword::
4697
4697
4698 hg log -k bug --template "{rev}\\n"
4698 hg log -k bug --template "{rev}\\n"
4699
4699
4700 - the full hash identifier of the working directory parent::
4700 - the full hash identifier of the working directory parent::
4701
4701
4702 hg log -r . --template "{node}\\n"
4702 hg log -r . --template "{node}\\n"
4703
4703
4704 - list available log templates::
4704 - list available log templates::
4705
4705
4706 hg log -T list
4706 hg log -T list
4707
4707
4708 - check if a given changeset is included in a tagged release::
4708 - check if a given changeset is included in a tagged release::
4709
4709
4710 hg log -r "a21ccf and ancestor(1.9)"
4710 hg log -r "a21ccf and ancestor(1.9)"
4711
4711
4712 - find all changesets by some user in a date range::
4712 - find all changesets by some user in a date range::
4713
4713
4714 hg log -k alice -d "may 2008 to jul 2008"
4714 hg log -k alice -d "may 2008 to jul 2008"
4715
4715
4716 - summary of all changesets after the last tag::
4716 - summary of all changesets after the last tag::
4717
4717
4718 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4718 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4719
4719
4720 - changesets touching lines 13 to 23 for file.c::
4720 - changesets touching lines 13 to 23 for file.c::
4721
4721
4722 hg log -L file.c,13:23
4722 hg log -L file.c,13:23
4723
4723
4724 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4724 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4725 main.c with patch::
4725 main.c with patch::
4726
4726
4727 hg log -L file.c,13:23 -L main.c,2:6 -p
4727 hg log -L file.c,13:23 -L main.c,2:6 -p
4728
4728
4729 See :hg:`help dates` for a list of formats valid for -d/--date.
4729 See :hg:`help dates` for a list of formats valid for -d/--date.
4730
4730
4731 See :hg:`help revisions` for more about specifying and ordering
4731 See :hg:`help revisions` for more about specifying and ordering
4732 revisions.
4732 revisions.
4733
4733
4734 See :hg:`help templates` for more about pre-packaged styles and
4734 See :hg:`help templates` for more about pre-packaged styles and
4735 specifying custom templates. The default template used by the log
4735 specifying custom templates. The default template used by the log
4736 command can be customized via the ``ui.logtemplate`` configuration
4736 command can be customized via the ``ui.logtemplate`` configuration
4737 setting.
4737 setting.
4738
4738
4739 Returns 0 on success.
4739 Returns 0 on success.
4740
4740
4741 """
4741 """
4742 opts = pycompat.byteskwargs(opts)
4742 opts = pycompat.byteskwargs(opts)
4743 linerange = opts.get(b'line_range')
4743 linerange = opts.get(b'line_range')
4744
4744
4745 if linerange and not opts.get(b'follow'):
4745 if linerange and not opts.get(b'follow'):
4746 raise error.Abort(_(b'--line-range requires --follow'))
4746 raise error.Abort(_(b'--line-range requires --follow'))
4747
4747
4748 if linerange and pats:
4748 if linerange and pats:
4749 # TODO: take pats as patterns with no line-range filter
4749 # TODO: take pats as patterns with no line-range filter
4750 raise error.Abort(
4750 raise error.Abort(
4751 _(b'FILE arguments are not compatible with --line-range option')
4751 _(b'FILE arguments are not compatible with --line-range option')
4752 )
4752 )
4753
4753
4754 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4754 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4755 revs, differ = logcmdutil.getrevs(
4755 revs, differ = logcmdutil.getrevs(
4756 repo, logcmdutil.parseopts(ui, pats, opts)
4756 repo, logcmdutil.parseopts(ui, pats, opts)
4757 )
4757 )
4758 if linerange:
4758 if linerange:
4759 # TODO: should follow file history from logcmdutil._initialrevs(),
4759 # TODO: should follow file history from logcmdutil._initialrevs(),
4760 # then filter the result by logcmdutil._makerevset() and --limit
4760 # then filter the result by logcmdutil._makerevset() and --limit
4761 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4761 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4762
4762
4763 getcopies = None
4763 getcopies = None
4764 if opts.get(b'copies'):
4764 if opts.get(b'copies'):
4765 endrev = None
4765 endrev = None
4766 if revs:
4766 if revs:
4767 endrev = revs.max() + 1
4767 endrev = revs.max() + 1
4768 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4768 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4769
4769
4770 ui.pager(b'log')
4770 ui.pager(b'log')
4771 displayer = logcmdutil.changesetdisplayer(
4771 displayer = logcmdutil.changesetdisplayer(
4772 ui, repo, opts, differ, buffered=True
4772 ui, repo, opts, differ, buffered=True
4773 )
4773 )
4774 if opts.get(b'graph'):
4774 if opts.get(b'graph'):
4775 displayfn = logcmdutil.displaygraphrevs
4775 displayfn = logcmdutil.displaygraphrevs
4776 else:
4776 else:
4777 displayfn = logcmdutil.displayrevs
4777 displayfn = logcmdutil.displayrevs
4778 displayfn(ui, repo, revs, displayer, getcopies)
4778 displayfn(ui, repo, revs, displayer, getcopies)
4779
4779
4780
4780
4781 @command(
4781 @command(
4782 b'manifest',
4782 b'manifest',
4783 [
4783 [
4784 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4784 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4785 (b'', b'all', False, _(b"list files from all revisions")),
4785 (b'', b'all', False, _(b"list files from all revisions")),
4786 ]
4786 ]
4787 + formatteropts,
4787 + formatteropts,
4788 _(b'[-r REV]'),
4788 _(b'[-r REV]'),
4789 helpcategory=command.CATEGORY_MAINTENANCE,
4789 helpcategory=command.CATEGORY_MAINTENANCE,
4790 intents={INTENT_READONLY},
4790 intents={INTENT_READONLY},
4791 )
4791 )
4792 def manifest(ui, repo, node=None, rev=None, **opts):
4792 def manifest(ui, repo, node=None, rev=None, **opts):
4793 """output the current or given revision of the project manifest
4793 """output the current or given revision of the project manifest
4794
4794
4795 Print a list of version controlled files for the given revision.
4795 Print a list of version controlled files for the given revision.
4796 If no revision is given, the first parent of the working directory
4796 If no revision is given, the first parent of the working directory
4797 is used, or the null revision if no revision is checked out.
4797 is used, or the null revision if no revision is checked out.
4798
4798
4799 With -v, print file permissions, symlink and executable bits.
4799 With -v, print file permissions, symlink and executable bits.
4800 With --debug, print file revision hashes.
4800 With --debug, print file revision hashes.
4801
4801
4802 If option --all is specified, the list of all files from all revisions
4802 If option --all is specified, the list of all files from all revisions
4803 is printed. This includes deleted and renamed files.
4803 is printed. This includes deleted and renamed files.
4804
4804
4805 Returns 0 on success.
4805 Returns 0 on success.
4806 """
4806 """
4807 opts = pycompat.byteskwargs(opts)
4807 opts = pycompat.byteskwargs(opts)
4808 fm = ui.formatter(b'manifest', opts)
4808 fm = ui.formatter(b'manifest', opts)
4809
4809
4810 if opts.get(b'all'):
4810 if opts.get(b'all'):
4811 if rev or node:
4811 if rev or node:
4812 raise error.Abort(_(b"can't specify a revision with --all"))
4812 raise error.Abort(_(b"can't specify a revision with --all"))
4813
4813
4814 res = set()
4814 res = set()
4815 for rev in repo:
4815 for rev in repo:
4816 ctx = repo[rev]
4816 ctx = repo[rev]
4817 res |= set(ctx.files())
4817 res |= set(ctx.files())
4818
4818
4819 ui.pager(b'manifest')
4819 ui.pager(b'manifest')
4820 for f in sorted(res):
4820 for f in sorted(res):
4821 fm.startitem()
4821 fm.startitem()
4822 fm.write(b"path", b'%s\n', f)
4822 fm.write(b"path", b'%s\n', f)
4823 fm.end()
4823 fm.end()
4824 return
4824 return
4825
4825
4826 if rev and node:
4826 if rev and node:
4827 raise error.Abort(_(b"please specify just one revision"))
4827 raise error.Abort(_(b"please specify just one revision"))
4828
4828
4829 if not node:
4829 if not node:
4830 node = rev
4830 node = rev
4831
4831
4832 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4832 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4833 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4833 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4834 if node:
4834 if node:
4835 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4835 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4836 ctx = scmutil.revsingle(repo, node)
4836 ctx = scmutil.revsingle(repo, node)
4837 mf = ctx.manifest()
4837 mf = ctx.manifest()
4838 ui.pager(b'manifest')
4838 ui.pager(b'manifest')
4839 for f in ctx:
4839 for f in ctx:
4840 fm.startitem()
4840 fm.startitem()
4841 fm.context(ctx=ctx)
4841 fm.context(ctx=ctx)
4842 fl = ctx[f].flags()
4842 fl = ctx[f].flags()
4843 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4843 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4844 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4844 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4845 fm.write(b'path', b'%s\n', f)
4845 fm.write(b'path', b'%s\n', f)
4846 fm.end()
4846 fm.end()
4847
4847
4848
4848
4849 @command(
4849 @command(
4850 b'merge',
4850 b'merge',
4851 [
4851 [
4852 (
4852 (
4853 b'f',
4853 b'f',
4854 b'force',
4854 b'force',
4855 None,
4855 None,
4856 _(b'force a merge including outstanding changes (DEPRECATED)'),
4856 _(b'force a merge including outstanding changes (DEPRECATED)'),
4857 ),
4857 ),
4858 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4858 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4859 (
4859 (
4860 b'P',
4860 b'P',
4861 b'preview',
4861 b'preview',
4862 None,
4862 None,
4863 _(b'review revisions to merge (no merge is performed)'),
4863 _(b'review revisions to merge (no merge is performed)'),
4864 ),
4864 ),
4865 (b'', b'abort', None, _(b'abort the ongoing merge')),
4865 (b'', b'abort', None, _(b'abort the ongoing merge')),
4866 ]
4866 ]
4867 + mergetoolopts,
4867 + mergetoolopts,
4868 _(b'[-P] [[-r] REV]'),
4868 _(b'[-P] [[-r] REV]'),
4869 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4869 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4870 helpbasic=True,
4870 helpbasic=True,
4871 )
4871 )
4872 def merge(ui, repo, node=None, **opts):
4872 def merge(ui, repo, node=None, **opts):
4873 """merge another revision into working directory
4873 """merge another revision into working directory
4874
4874
4875 The current working directory is updated with all changes made in
4875 The current working directory is updated with all changes made in
4876 the requested revision since the last common predecessor revision.
4876 the requested revision since the last common predecessor revision.
4877
4877
4878 Files that changed between either parent are marked as changed for
4878 Files that changed between either parent are marked as changed for
4879 the next commit and a commit must be performed before any further
4879 the next commit and a commit must be performed before any further
4880 updates to the repository are allowed. The next commit will have
4880 updates to the repository are allowed. The next commit will have
4881 two parents.
4881 two parents.
4882
4882
4883 ``--tool`` can be used to specify the merge tool used for file
4883 ``--tool`` can be used to specify the merge tool used for file
4884 merges. It overrides the HGMERGE environment variable and your
4884 merges. It overrides the HGMERGE environment variable and your
4885 configuration files. See :hg:`help merge-tools` for options.
4885 configuration files. See :hg:`help merge-tools` for options.
4886
4886
4887 If no revision is specified, the working directory's parent is a
4887 If no revision is specified, the working directory's parent is a
4888 head revision, and the current branch contains exactly one other
4888 head revision, and the current branch contains exactly one other
4889 head, the other head is merged with by default. Otherwise, an
4889 head, the other head is merged with by default. Otherwise, an
4890 explicit revision with which to merge must be provided.
4890 explicit revision with which to merge must be provided.
4891
4891
4892 See :hg:`help resolve` for information on handling file conflicts.
4892 See :hg:`help resolve` for information on handling file conflicts.
4893
4893
4894 To undo an uncommitted merge, use :hg:`merge --abort` which
4894 To undo an uncommitted merge, use :hg:`merge --abort` which
4895 will check out a clean copy of the original merge parent, losing
4895 will check out a clean copy of the original merge parent, losing
4896 all changes.
4896 all changes.
4897
4897
4898 Returns 0 on success, 1 if there are unresolved files.
4898 Returns 0 on success, 1 if there are unresolved files.
4899 """
4899 """
4900
4900
4901 opts = pycompat.byteskwargs(opts)
4901 opts = pycompat.byteskwargs(opts)
4902 abort = opts.get(b'abort')
4902 abort = opts.get(b'abort')
4903 if abort and repo.dirstate.p2() == nullid:
4903 if abort and repo.dirstate.p2() == nullid:
4904 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4904 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4905 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4905 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4906 if abort:
4906 if abort:
4907 state = cmdutil.getunfinishedstate(repo)
4907 state = cmdutil.getunfinishedstate(repo)
4908 if state and state._opname != b'merge':
4908 if state and state._opname != b'merge':
4909 raise error.Abort(
4909 raise error.Abort(
4910 _(b'cannot abort merge with %s in progress') % (state._opname),
4910 _(b'cannot abort merge with %s in progress') % (state._opname),
4911 hint=state.hint(),
4911 hint=state.hint(),
4912 )
4912 )
4913 if node:
4913 if node:
4914 raise error.Abort(_(b"cannot specify a node with --abort"))
4914 raise error.Abort(_(b"cannot specify a node with --abort"))
4915 return hg.abortmerge(repo.ui, repo)
4915 return hg.abortmerge(repo.ui, repo)
4916
4916
4917 if opts.get(b'rev') and node:
4917 if opts.get(b'rev') and node:
4918 raise error.Abort(_(b"please specify just one revision"))
4918 raise error.Abort(_(b"please specify just one revision"))
4919 if not node:
4919 if not node:
4920 node = opts.get(b'rev')
4920 node = opts.get(b'rev')
4921
4921
4922 if node:
4922 if node:
4923 ctx = scmutil.revsingle(repo, node)
4923 ctx = scmutil.revsingle(repo, node)
4924 else:
4924 else:
4925 if ui.configbool(b'commands', b'merge.require-rev'):
4925 if ui.configbool(b'commands', b'merge.require-rev'):
4926 raise error.Abort(
4926 raise error.Abort(
4927 _(
4927 _(
4928 b'configuration requires specifying revision to merge '
4928 b'configuration requires specifying revision to merge '
4929 b'with'
4929 b'with'
4930 )
4930 )
4931 )
4931 )
4932 ctx = repo[destutil.destmerge(repo)]
4932 ctx = repo[destutil.destmerge(repo)]
4933
4933
4934 if ctx.node() is None:
4934 if ctx.node() is None:
4935 raise error.Abort(_(b'merging with the working copy has no effect'))
4935 raise error.Abort(_(b'merging with the working copy has no effect'))
4936
4936
4937 if opts.get(b'preview'):
4937 if opts.get(b'preview'):
4938 # find nodes that are ancestors of p2 but not of p1
4938 # find nodes that are ancestors of p2 but not of p1
4939 p1 = repo[b'.'].node()
4939 p1 = repo[b'.'].node()
4940 p2 = ctx.node()
4940 p2 = ctx.node()
4941 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4941 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4942
4942
4943 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4943 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4944 for node in nodes:
4944 for node in nodes:
4945 displayer.show(repo[node])
4945 displayer.show(repo[node])
4946 displayer.close()
4946 displayer.close()
4947 return 0
4947 return 0
4948
4948
4949 # ui.forcemerge is an internal variable, do not document
4949 # ui.forcemerge is an internal variable, do not document
4950 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4950 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4951 with ui.configoverride(overrides, b'merge'):
4951 with ui.configoverride(overrides, b'merge'):
4952 force = opts.get(b'force')
4952 force = opts.get(b'force')
4953 labels = [b'working copy', b'merge rev']
4953 labels = [b'working copy', b'merge rev']
4954 return hg.merge(ctx, force=force, labels=labels)
4954 return hg.merge(ctx, force=force, labels=labels)
4955
4955
4956
4956
4957 statemod.addunfinished(
4957 statemod.addunfinished(
4958 b'merge',
4958 b'merge',
4959 fname=None,
4959 fname=None,
4960 clearable=True,
4960 clearable=True,
4961 allowcommit=True,
4961 allowcommit=True,
4962 cmdmsg=_(b'outstanding uncommitted merge'),
4962 cmdmsg=_(b'outstanding uncommitted merge'),
4963 abortfunc=hg.abortmerge,
4963 abortfunc=hg.abortmerge,
4964 statushint=_(
4964 statushint=_(
4965 b'To continue: hg commit\nTo abort: hg merge --abort'
4965 b'To continue: hg commit\nTo abort: hg merge --abort'
4966 ),
4966 ),
4967 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4967 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4968 )
4968 )
4969
4969
4970
4970
4971 @command(
4971 @command(
4972 b'outgoing|out',
4972 b'outgoing|out',
4973 [
4973 [
4974 (
4974 (
4975 b'f',
4975 b'f',
4976 b'force',
4976 b'force',
4977 None,
4977 None,
4978 _(b'run even when the destination is unrelated'),
4978 _(b'run even when the destination is unrelated'),
4979 ),
4979 ),
4980 (
4980 (
4981 b'r',
4981 b'r',
4982 b'rev',
4982 b'rev',
4983 [],
4983 [],
4984 _(b'a changeset intended to be included in the destination'),
4984 _(b'a changeset intended to be included in the destination'),
4985 _(b'REV'),
4985 _(b'REV'),
4986 ),
4986 ),
4987 (b'n', b'newest-first', None, _(b'show newest record first')),
4987 (b'n', b'newest-first', None, _(b'show newest record first')),
4988 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4988 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4989 (
4989 (
4990 b'b',
4990 b'b',
4991 b'branch',
4991 b'branch',
4992 [],
4992 [],
4993 _(b'a specific branch you would like to push'),
4993 _(b'a specific branch you would like to push'),
4994 _(b'BRANCH'),
4994 _(b'BRANCH'),
4995 ),
4995 ),
4996 ]
4996 ]
4997 + logopts
4997 + logopts
4998 + remoteopts
4998 + remoteopts
4999 + subrepoopts,
4999 + subrepoopts,
5000 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
5000 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
5001 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5001 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5002 )
5002 )
5003 def outgoing(ui, repo, dest=None, **opts):
5003 def outgoing(ui, repo, dest=None, **opts):
5004 """show changesets not found in the destination
5004 """show changesets not found in the destination
5005
5005
5006 Show changesets not found in the specified destination repository
5006 Show changesets not found in the specified destination repository
5007 or the default push location. These are the changesets that would
5007 or the default push location. These are the changesets that would
5008 be pushed if a push was requested.
5008 be pushed if a push was requested.
5009
5009
5010 See pull for details of valid destination formats.
5010 See pull for details of valid destination formats.
5011
5011
5012 .. container:: verbose
5012 .. container:: verbose
5013
5013
5014 With -B/--bookmarks, the result of bookmark comparison between
5014 With -B/--bookmarks, the result of bookmark comparison between
5015 local and remote repositories is displayed. With -v/--verbose,
5015 local and remote repositories is displayed. With -v/--verbose,
5016 status is also displayed for each bookmark like below::
5016 status is also displayed for each bookmark like below::
5017
5017
5018 BM1 01234567890a added
5018 BM1 01234567890a added
5019 BM2 deleted
5019 BM2 deleted
5020 BM3 234567890abc advanced
5020 BM3 234567890abc advanced
5021 BM4 34567890abcd diverged
5021 BM4 34567890abcd diverged
5022 BM5 4567890abcde changed
5022 BM5 4567890abcde changed
5023
5023
5024 The action taken when pushing depends on the
5024 The action taken when pushing depends on the
5025 status of each bookmark:
5025 status of each bookmark:
5026
5026
5027 :``added``: push with ``-B`` will create it
5027 :``added``: push with ``-B`` will create it
5028 :``deleted``: push with ``-B`` will delete it
5028 :``deleted``: push with ``-B`` will delete it
5029 :``advanced``: push will update it
5029 :``advanced``: push will update it
5030 :``diverged``: push with ``-B`` will update it
5030 :``diverged``: push with ``-B`` will update it
5031 :``changed``: push with ``-B`` will update it
5031 :``changed``: push with ``-B`` will update it
5032
5032
5033 From the point of view of pushing behavior, bookmarks
5033 From the point of view of pushing behavior, bookmarks
5034 existing only in the remote repository are treated as
5034 existing only in the remote repository are treated as
5035 ``deleted``, even if it is in fact added remotely.
5035 ``deleted``, even if it is in fact added remotely.
5036
5036
5037 Returns 0 if there are outgoing changes, 1 otherwise.
5037 Returns 0 if there are outgoing changes, 1 otherwise.
5038 """
5038 """
5039 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5039 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5040 # style URLs, so don't overwrite dest.
5040 # style URLs, so don't overwrite dest.
5041 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5041 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5042 if not path:
5042 if not path:
5043 raise error.Abort(
5043 raise error.Abort(
5044 _(b'default repository not configured!'),
5044 _(b'default repository not configured!'),
5045 hint=_(b"see 'hg help config.paths'"),
5045 hint=_(b"see 'hg help config.paths'"),
5046 )
5046 )
5047
5047
5048 opts = pycompat.byteskwargs(opts)
5048 opts = pycompat.byteskwargs(opts)
5049 if opts.get(b'graph'):
5049 if opts.get(b'graph'):
5050 logcmdutil.checkunsupportedgraphflags([], opts)
5050 logcmdutil.checkunsupportedgraphflags([], opts)
5051 o, other = hg._outgoing(ui, repo, dest, opts)
5051 o, other = hg._outgoing(ui, repo, dest, opts)
5052 if not o:
5052 if not o:
5053 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5053 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5054 return
5054 return
5055
5055
5056 revdag = logcmdutil.graphrevs(repo, o, opts)
5056 revdag = logcmdutil.graphrevs(repo, o, opts)
5057 ui.pager(b'outgoing')
5057 ui.pager(b'outgoing')
5058 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5058 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5059 logcmdutil.displaygraph(
5059 logcmdutil.displaygraph(
5060 ui, repo, revdag, displayer, graphmod.asciiedges
5060 ui, repo, revdag, displayer, graphmod.asciiedges
5061 )
5061 )
5062 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5062 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5063 return 0
5063 return 0
5064
5064
5065 if opts.get(b'bookmarks'):
5065 if opts.get(b'bookmarks'):
5066 dest = path.pushloc or path.loc
5066 dest = path.pushloc or path.loc
5067 other = hg.peer(repo, opts, dest)
5067 other = hg.peer(repo, opts, dest)
5068 if b'bookmarks' not in other.listkeys(b'namespaces'):
5068 if b'bookmarks' not in other.listkeys(b'namespaces'):
5069 ui.warn(_(b"remote doesn't support bookmarks\n"))
5069 ui.warn(_(b"remote doesn't support bookmarks\n"))
5070 return 0
5070 return 0
5071 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5071 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5072 ui.pager(b'outgoing')
5072 ui.pager(b'outgoing')
5073 return bookmarks.outgoing(ui, repo, other)
5073 return bookmarks.outgoing(ui, repo, other)
5074
5074
5075 repo._subtoppath = path.pushloc or path.loc
5075 repo._subtoppath = path.pushloc or path.loc
5076 try:
5076 try:
5077 return hg.outgoing(ui, repo, dest, opts)
5077 return hg.outgoing(ui, repo, dest, opts)
5078 finally:
5078 finally:
5079 del repo._subtoppath
5079 del repo._subtoppath
5080
5080
5081
5081
5082 @command(
5082 @command(
5083 b'parents',
5083 b'parents',
5084 [
5084 [
5085 (
5085 (
5086 b'r',
5086 b'r',
5087 b'rev',
5087 b'rev',
5088 b'',
5088 b'',
5089 _(b'show parents of the specified revision'),
5089 _(b'show parents of the specified revision'),
5090 _(b'REV'),
5090 _(b'REV'),
5091 ),
5091 ),
5092 ]
5092 ]
5093 + templateopts,
5093 + templateopts,
5094 _(b'[-r REV] [FILE]'),
5094 _(b'[-r REV] [FILE]'),
5095 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5095 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5096 inferrepo=True,
5096 inferrepo=True,
5097 )
5097 )
5098 def parents(ui, repo, file_=None, **opts):
5098 def parents(ui, repo, file_=None, **opts):
5099 """show the parents of the working directory or revision (DEPRECATED)
5099 """show the parents of the working directory or revision (DEPRECATED)
5100
5100
5101 Print the working directory's parent revisions. If a revision is
5101 Print the working directory's parent revisions. If a revision is
5102 given via -r/--rev, the parent of that revision will be printed.
5102 given via -r/--rev, the parent of that revision will be printed.
5103 If a file argument is given, the revision in which the file was
5103 If a file argument is given, the revision in which the file was
5104 last changed (before the working directory revision or the
5104 last changed (before the working directory revision or the
5105 argument to --rev if given) is printed.
5105 argument to --rev if given) is printed.
5106
5106
5107 This command is equivalent to::
5107 This command is equivalent to::
5108
5108
5109 hg log -r "p1()+p2()" or
5109 hg log -r "p1()+p2()" or
5110 hg log -r "p1(REV)+p2(REV)" or
5110 hg log -r "p1(REV)+p2(REV)" or
5111 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5111 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5112 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5112 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5113
5113
5114 See :hg:`summary` and :hg:`help revsets` for related information.
5114 See :hg:`summary` and :hg:`help revsets` for related information.
5115
5115
5116 Returns 0 on success.
5116 Returns 0 on success.
5117 """
5117 """
5118
5118
5119 opts = pycompat.byteskwargs(opts)
5119 opts = pycompat.byteskwargs(opts)
5120 rev = opts.get(b'rev')
5120 rev = opts.get(b'rev')
5121 if rev:
5121 if rev:
5122 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5122 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5123 ctx = scmutil.revsingle(repo, rev, None)
5123 ctx = scmutil.revsingle(repo, rev, None)
5124
5124
5125 if file_:
5125 if file_:
5126 m = scmutil.match(ctx, (file_,), opts)
5126 m = scmutil.match(ctx, (file_,), opts)
5127 if m.anypats() or len(m.files()) != 1:
5127 if m.anypats() or len(m.files()) != 1:
5128 raise error.Abort(_(b'can only specify an explicit filename'))
5128 raise error.Abort(_(b'can only specify an explicit filename'))
5129 file_ = m.files()[0]
5129 file_ = m.files()[0]
5130 filenodes = []
5130 filenodes = []
5131 for cp in ctx.parents():
5131 for cp in ctx.parents():
5132 if not cp:
5132 if not cp:
5133 continue
5133 continue
5134 try:
5134 try:
5135 filenodes.append(cp.filenode(file_))
5135 filenodes.append(cp.filenode(file_))
5136 except error.LookupError:
5136 except error.LookupError:
5137 pass
5137 pass
5138 if not filenodes:
5138 if not filenodes:
5139 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5139 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5140 p = []
5140 p = []
5141 for fn in filenodes:
5141 for fn in filenodes:
5142 fctx = repo.filectx(file_, fileid=fn)
5142 fctx = repo.filectx(file_, fileid=fn)
5143 p.append(fctx.node())
5143 p.append(fctx.node())
5144 else:
5144 else:
5145 p = [cp.node() for cp in ctx.parents()]
5145 p = [cp.node() for cp in ctx.parents()]
5146
5146
5147 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5147 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5148 for n in p:
5148 for n in p:
5149 if n != nullid:
5149 if n != nullid:
5150 displayer.show(repo[n])
5150 displayer.show(repo[n])
5151 displayer.close()
5151 displayer.close()
5152
5152
5153
5153
5154 @command(
5154 @command(
5155 b'paths',
5155 b'paths',
5156 formatteropts,
5156 formatteropts,
5157 _(b'[NAME]'),
5157 _(b'[NAME]'),
5158 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5158 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5159 optionalrepo=True,
5159 optionalrepo=True,
5160 intents={INTENT_READONLY},
5160 intents={INTENT_READONLY},
5161 )
5161 )
5162 def paths(ui, repo, search=None, **opts):
5162 def paths(ui, repo, search=None, **opts):
5163 """show aliases for remote repositories
5163 """show aliases for remote repositories
5164
5164
5165 Show definition of symbolic path name NAME. If no name is given,
5165 Show definition of symbolic path name NAME. If no name is given,
5166 show definition of all available names.
5166 show definition of all available names.
5167
5167
5168 Option -q/--quiet suppresses all output when searching for NAME
5168 Option -q/--quiet suppresses all output when searching for NAME
5169 and shows only the path names when listing all definitions.
5169 and shows only the path names when listing all definitions.
5170
5170
5171 Path names are defined in the [paths] section of your
5171 Path names are defined in the [paths] section of your
5172 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5172 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5173 repository, ``.hg/hgrc`` is used, too.
5173 repository, ``.hg/hgrc`` is used, too.
5174
5174
5175 The path names ``default`` and ``default-push`` have a special
5175 The path names ``default`` and ``default-push`` have a special
5176 meaning. When performing a push or pull operation, they are used
5176 meaning. When performing a push or pull operation, they are used
5177 as fallbacks if no location is specified on the command-line.
5177 as fallbacks if no location is specified on the command-line.
5178 When ``default-push`` is set, it will be used for push and
5178 When ``default-push`` is set, it will be used for push and
5179 ``default`` will be used for pull; otherwise ``default`` is used
5179 ``default`` will be used for pull; otherwise ``default`` is used
5180 as the fallback for both. When cloning a repository, the clone
5180 as the fallback for both. When cloning a repository, the clone
5181 source is written as ``default`` in ``.hg/hgrc``.
5181 source is written as ``default`` in ``.hg/hgrc``.
5182
5182
5183 .. note::
5183 .. note::
5184
5184
5185 ``default`` and ``default-push`` apply to all inbound (e.g.
5185 ``default`` and ``default-push`` apply to all inbound (e.g.
5186 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5186 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5187 and :hg:`bundle`) operations.
5187 and :hg:`bundle`) operations.
5188
5188
5189 See :hg:`help urls` for more information.
5189 See :hg:`help urls` for more information.
5190
5190
5191 .. container:: verbose
5191 .. container:: verbose
5192
5192
5193 Template:
5193 Template:
5194
5194
5195 The following keywords are supported. See also :hg:`help templates`.
5195 The following keywords are supported. See also :hg:`help templates`.
5196
5196
5197 :name: String. Symbolic name of the path alias.
5197 :name: String. Symbolic name of the path alias.
5198 :pushurl: String. URL for push operations.
5198 :pushurl: String. URL for push operations.
5199 :url: String. URL or directory path for the other operations.
5199 :url: String. URL or directory path for the other operations.
5200
5200
5201 Returns 0 on success.
5201 Returns 0 on success.
5202 """
5202 """
5203
5203
5204 opts = pycompat.byteskwargs(opts)
5204 opts = pycompat.byteskwargs(opts)
5205 ui.pager(b'paths')
5205 ui.pager(b'paths')
5206 if search:
5206 if search:
5207 pathitems = [
5207 pathitems = [
5208 (name, path)
5208 (name, path)
5209 for name, path in pycompat.iteritems(ui.paths)
5209 for name, path in pycompat.iteritems(ui.paths)
5210 if name == search
5210 if name == search
5211 ]
5211 ]
5212 else:
5212 else:
5213 pathitems = sorted(pycompat.iteritems(ui.paths))
5213 pathitems = sorted(pycompat.iteritems(ui.paths))
5214
5214
5215 fm = ui.formatter(b'paths', opts)
5215 fm = ui.formatter(b'paths', opts)
5216 if fm.isplain():
5216 if fm.isplain():
5217 hidepassword = util.hidepassword
5217 hidepassword = util.hidepassword
5218 else:
5218 else:
5219 hidepassword = bytes
5219 hidepassword = bytes
5220 if ui.quiet:
5220 if ui.quiet:
5221 namefmt = b'%s\n'
5221 namefmt = b'%s\n'
5222 else:
5222 else:
5223 namefmt = b'%s = '
5223 namefmt = b'%s = '
5224 showsubopts = not search and not ui.quiet
5224 showsubopts = not search and not ui.quiet
5225
5225
5226 for name, path in pathitems:
5226 for name, path in pathitems:
5227 fm.startitem()
5227 fm.startitem()
5228 fm.condwrite(not search, b'name', namefmt, name)
5228 fm.condwrite(not search, b'name', namefmt, name)
5229 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5229 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5230 for subopt, value in sorted(path.suboptions.items()):
5230 for subopt, value in sorted(path.suboptions.items()):
5231 assert subopt not in (b'name', b'url')
5231 assert subopt not in (b'name', b'url')
5232 if showsubopts:
5232 if showsubopts:
5233 fm.plain(b'%s:%s = ' % (name, subopt))
5233 fm.plain(b'%s:%s = ' % (name, subopt))
5234 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5234 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5235
5235
5236 fm.end()
5236 fm.end()
5237
5237
5238 if search and not pathitems:
5238 if search and not pathitems:
5239 if not ui.quiet:
5239 if not ui.quiet:
5240 ui.warn(_(b"not found!\n"))
5240 ui.warn(_(b"not found!\n"))
5241 return 1
5241 return 1
5242 else:
5242 else:
5243 return 0
5243 return 0
5244
5244
5245
5245
5246 @command(
5246 @command(
5247 b'phase',
5247 b'phase',
5248 [
5248 [
5249 (b'p', b'public', False, _(b'set changeset phase to public')),
5249 (b'p', b'public', False, _(b'set changeset phase to public')),
5250 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5250 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5251 (b's', b'secret', False, _(b'set changeset phase to secret')),
5251 (b's', b'secret', False, _(b'set changeset phase to secret')),
5252 (b'f', b'force', False, _(b'allow to move boundary backward')),
5252 (b'f', b'force', False, _(b'allow to move boundary backward')),
5253 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5253 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5254 ],
5254 ],
5255 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5255 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5256 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5256 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5257 )
5257 )
5258 def phase(ui, repo, *revs, **opts):
5258 def phase(ui, repo, *revs, **opts):
5259 """set or show the current phase name
5259 """set or show the current phase name
5260
5260
5261 With no argument, show the phase name of the current revision(s).
5261 With no argument, show the phase name of the current revision(s).
5262
5262
5263 With one of -p/--public, -d/--draft or -s/--secret, change the
5263 With one of -p/--public, -d/--draft or -s/--secret, change the
5264 phase value of the specified revisions.
5264 phase value of the specified revisions.
5265
5265
5266 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5266 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5267 lower phase to a higher phase. Phases are ordered as follows::
5267 lower phase to a higher phase. Phases are ordered as follows::
5268
5268
5269 public < draft < secret
5269 public < draft < secret
5270
5270
5271 Returns 0 on success, 1 if some phases could not be changed.
5271 Returns 0 on success, 1 if some phases could not be changed.
5272
5272
5273 (For more information about the phases concept, see :hg:`help phases`.)
5273 (For more information about the phases concept, see :hg:`help phases`.)
5274 """
5274 """
5275 opts = pycompat.byteskwargs(opts)
5275 opts = pycompat.byteskwargs(opts)
5276 # search for a unique phase argument
5276 # search for a unique phase argument
5277 targetphase = None
5277 targetphase = None
5278 for idx, name in enumerate(phases.cmdphasenames):
5278 for idx, name in enumerate(phases.cmdphasenames):
5279 if opts[name]:
5279 if opts[name]:
5280 if targetphase is not None:
5280 if targetphase is not None:
5281 raise error.Abort(_(b'only one phase can be specified'))
5281 raise error.Abort(_(b'only one phase can be specified'))
5282 targetphase = idx
5282 targetphase = idx
5283
5283
5284 # look for specified revision
5284 # look for specified revision
5285 revs = list(revs)
5285 revs = list(revs)
5286 revs.extend(opts[b'rev'])
5286 revs.extend(opts[b'rev'])
5287 if not revs:
5287 if not revs:
5288 # display both parents as the second parent phase can influence
5288 # display both parents as the second parent phase can influence
5289 # the phase of a merge commit
5289 # the phase of a merge commit
5290 revs = [c.rev() for c in repo[None].parents()]
5290 revs = [c.rev() for c in repo[None].parents()]
5291
5291
5292 revs = scmutil.revrange(repo, revs)
5292 revs = scmutil.revrange(repo, revs)
5293
5293
5294 ret = 0
5294 ret = 0
5295 if targetphase is None:
5295 if targetphase is None:
5296 # display
5296 # display
5297 for r in revs:
5297 for r in revs:
5298 ctx = repo[r]
5298 ctx = repo[r]
5299 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5299 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5300 else:
5300 else:
5301 with repo.lock(), repo.transaction(b"phase") as tr:
5301 with repo.lock(), repo.transaction(b"phase") as tr:
5302 # set phase
5302 # set phase
5303 if not revs:
5303 if not revs:
5304 raise error.Abort(_(b'empty revision set'))
5304 raise error.Abort(_(b'empty revision set'))
5305 nodes = [repo[r].node() for r in revs]
5305 nodes = [repo[r].node() for r in revs]
5306 # moving revision from public to draft may hide them
5306 # moving revision from public to draft may hide them
5307 # We have to check result on an unfiltered repository
5307 # We have to check result on an unfiltered repository
5308 unfi = repo.unfiltered()
5308 unfi = repo.unfiltered()
5309 getphase = unfi._phasecache.phase
5309 getphase = unfi._phasecache.phase
5310 olddata = [getphase(unfi, r) for r in unfi]
5310 olddata = [getphase(unfi, r) for r in unfi]
5311 phases.advanceboundary(repo, tr, targetphase, nodes)
5311 phases.advanceboundary(repo, tr, targetphase, nodes)
5312 if opts[b'force']:
5312 if opts[b'force']:
5313 phases.retractboundary(repo, tr, targetphase, nodes)
5313 phases.retractboundary(repo, tr, targetphase, nodes)
5314 getphase = unfi._phasecache.phase
5314 getphase = unfi._phasecache.phase
5315 newdata = [getphase(unfi, r) for r in unfi]
5315 newdata = [getphase(unfi, r) for r in unfi]
5316 changes = sum(newdata[r] != olddata[r] for r in unfi)
5316 changes = sum(newdata[r] != olddata[r] for r in unfi)
5317 cl = unfi.changelog
5317 cl = unfi.changelog
5318 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5318 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5319 if rejected:
5319 if rejected:
5320 ui.warn(
5320 ui.warn(
5321 _(
5321 _(
5322 b'cannot move %i changesets to a higher '
5322 b'cannot move %i changesets to a higher '
5323 b'phase, use --force\n'
5323 b'phase, use --force\n'
5324 )
5324 )
5325 % len(rejected)
5325 % len(rejected)
5326 )
5326 )
5327 ret = 1
5327 ret = 1
5328 if changes:
5328 if changes:
5329 msg = _(b'phase changed for %i changesets\n') % changes
5329 msg = _(b'phase changed for %i changesets\n') % changes
5330 if ret:
5330 if ret:
5331 ui.status(msg)
5331 ui.status(msg)
5332 else:
5332 else:
5333 ui.note(msg)
5333 ui.note(msg)
5334 else:
5334 else:
5335 ui.warn(_(b'no phases changed\n'))
5335 ui.warn(_(b'no phases changed\n'))
5336 return ret
5336 return ret
5337
5337
5338
5338
5339 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5339 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5340 """Run after a changegroup has been added via pull/unbundle
5340 """Run after a changegroup has been added via pull/unbundle
5341
5341
5342 This takes arguments below:
5342 This takes arguments below:
5343
5343
5344 :modheads: change of heads by pull/unbundle
5344 :modheads: change of heads by pull/unbundle
5345 :optupdate: updating working directory is needed or not
5345 :optupdate: updating working directory is needed or not
5346 :checkout: update destination revision (or None to default destination)
5346 :checkout: update destination revision (or None to default destination)
5347 :brev: a name, which might be a bookmark to be activated after updating
5347 :brev: a name, which might be a bookmark to be activated after updating
5348 """
5348 """
5349 if modheads == 0:
5349 if modheads == 0:
5350 return
5350 return
5351 if optupdate:
5351 if optupdate:
5352 try:
5352 try:
5353 return hg.updatetotally(ui, repo, checkout, brev)
5353 return hg.updatetotally(ui, repo, checkout, brev)
5354 except error.UpdateAbort as inst:
5354 except error.UpdateAbort as inst:
5355 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5355 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5356 hint = inst.hint
5356 hint = inst.hint
5357 raise error.UpdateAbort(msg, hint=hint)
5357 raise error.UpdateAbort(msg, hint=hint)
5358 if modheads is not None and modheads > 1:
5358 if modheads is not None and modheads > 1:
5359 currentbranchheads = len(repo.branchheads())
5359 currentbranchheads = len(repo.branchheads())
5360 if currentbranchheads == modheads:
5360 if currentbranchheads == modheads:
5361 ui.status(
5361 ui.status(
5362 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5362 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5363 )
5363 )
5364 elif currentbranchheads > 1:
5364 elif currentbranchheads > 1:
5365 ui.status(
5365 ui.status(
5366 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5366 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5367 )
5367 )
5368 else:
5368 else:
5369 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5369 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5370 elif not ui.configbool(b'commands', b'update.requiredest'):
5370 elif not ui.configbool(b'commands', b'update.requiredest'):
5371 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5371 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5372
5372
5373
5373
5374 @command(
5374 @command(
5375 b'pull',
5375 b'pull',
5376 [
5376 [
5377 (
5377 (
5378 b'u',
5378 b'u',
5379 b'update',
5379 b'update',
5380 None,
5380 None,
5381 _(b'update to new branch head if new descendants were pulled'),
5381 _(b'update to new branch head if new descendants were pulled'),
5382 ),
5382 ),
5383 (
5383 (
5384 b'f',
5384 b'f',
5385 b'force',
5385 b'force',
5386 None,
5386 None,
5387 _(b'run even when remote repository is unrelated'),
5387 _(b'run even when remote repository is unrelated'),
5388 ),
5388 ),
5389 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5389 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5390 (
5390 (
5391 b'r',
5391 b'r',
5392 b'rev',
5392 b'rev',
5393 [],
5393 [],
5394 _(b'a remote changeset intended to be added'),
5394 _(b'a remote changeset intended to be added'),
5395 _(b'REV'),
5395 _(b'REV'),
5396 ),
5396 ),
5397 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5397 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5398 (
5398 (
5399 b'b',
5399 b'b',
5400 b'branch',
5400 b'branch',
5401 [],
5401 [],
5402 _(b'a specific branch you would like to pull'),
5402 _(b'a specific branch you would like to pull'),
5403 _(b'BRANCH'),
5403 _(b'BRANCH'),
5404 ),
5404 ),
5405 ]
5405 ]
5406 + remoteopts,
5406 + remoteopts,
5407 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5407 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5408 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5408 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5409 helpbasic=True,
5409 helpbasic=True,
5410 )
5410 )
5411 def pull(ui, repo, source=b"default", **opts):
5411 def pull(ui, repo, source=b"default", **opts):
5412 """pull changes from the specified source
5412 """pull changes from the specified source
5413
5413
5414 Pull changes from a remote repository to a local one.
5414 Pull changes from a remote repository to a local one.
5415
5415
5416 This finds all changes from the repository at the specified path
5416 This finds all changes from the repository at the specified path
5417 or URL and adds them to a local repository (the current one unless
5417 or URL and adds them to a local repository (the current one unless
5418 -R is specified). By default, this does not update the copy of the
5418 -R is specified). By default, this does not update the copy of the
5419 project in the working directory.
5419 project in the working directory.
5420
5420
5421 When cloning from servers that support it, Mercurial may fetch
5421 When cloning from servers that support it, Mercurial may fetch
5422 pre-generated data. When this is done, hooks operating on incoming
5422 pre-generated data. When this is done, hooks operating on incoming
5423 changesets and changegroups may fire more than once, once for each
5423 changesets and changegroups may fire more than once, once for each
5424 pre-generated bundle and as well as for any additional remaining
5424 pre-generated bundle and as well as for any additional remaining
5425 data. See :hg:`help -e clonebundles` for more.
5425 data. See :hg:`help -e clonebundles` for more.
5426
5426
5427 Use :hg:`incoming` if you want to see what would have been added
5427 Use :hg:`incoming` if you want to see what would have been added
5428 by a pull at the time you issued this command. If you then decide
5428 by a pull at the time you issued this command. If you then decide
5429 to add those changes to the repository, you should use :hg:`pull
5429 to add those changes to the repository, you should use :hg:`pull
5430 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5430 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5431
5431
5432 If SOURCE is omitted, the 'default' path will be used.
5432 If SOURCE is omitted, the 'default' path will be used.
5433 See :hg:`help urls` for more information.
5433 See :hg:`help urls` for more information.
5434
5434
5435 Specifying bookmark as ``.`` is equivalent to specifying the active
5435 Specifying bookmark as ``.`` is equivalent to specifying the active
5436 bookmark's name.
5436 bookmark's name.
5437
5437
5438 Returns 0 on success, 1 if an update had unresolved files.
5438 Returns 0 on success, 1 if an update had unresolved files.
5439 """
5439 """
5440
5440
5441 opts = pycompat.byteskwargs(opts)
5441 opts = pycompat.byteskwargs(opts)
5442 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5442 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5443 b'update'
5443 b'update'
5444 ):
5444 ):
5445 msg = _(b'update destination required by configuration')
5445 msg = _(b'update destination required by configuration')
5446 hint = _(b'use hg pull followed by hg update DEST')
5446 hint = _(b'use hg pull followed by hg update DEST')
5447 raise error.Abort(msg, hint=hint)
5447 raise error.Abort(msg, hint=hint)
5448
5448
5449 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5449 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5450 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5450 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5451 other = hg.peer(repo, opts, source)
5451 other = hg.peer(repo, opts, source)
5452 try:
5452 try:
5453 revs, checkout = hg.addbranchrevs(
5453 revs, checkout = hg.addbranchrevs(
5454 repo, other, branches, opts.get(b'rev')
5454 repo, other, branches, opts.get(b'rev')
5455 )
5455 )
5456
5456
5457 pullopargs = {}
5457 pullopargs = {}
5458
5458
5459 nodes = None
5459 nodes = None
5460 if opts.get(b'bookmark') or revs:
5460 if opts.get(b'bookmark') or revs:
5461 # The list of bookmark used here is the same used to actually update
5461 # The list of bookmark used here is the same used to actually update
5462 # the bookmark names, to avoid the race from issue 4689 and we do
5462 # the bookmark names, to avoid the race from issue 4689 and we do
5463 # all lookup and bookmark queries in one go so they see the same
5463 # all lookup and bookmark queries in one go so they see the same
5464 # version of the server state (issue 4700).
5464 # version of the server state (issue 4700).
5465 nodes = []
5465 nodes = []
5466 fnodes = []
5466 fnodes = []
5467 revs = revs or []
5467 revs = revs or []
5468 if revs and not other.capable(b'lookup'):
5468 if revs and not other.capable(b'lookup'):
5469 err = _(
5469 err = _(
5470 b"other repository doesn't support revision lookup, "
5470 b"other repository doesn't support revision lookup, "
5471 b"so a rev cannot be specified."
5471 b"so a rev cannot be specified."
5472 )
5472 )
5473 raise error.Abort(err)
5473 raise error.Abort(err)
5474 with other.commandexecutor() as e:
5474 with other.commandexecutor() as e:
5475 fremotebookmarks = e.callcommand(
5475 fremotebookmarks = e.callcommand(
5476 b'listkeys', {b'namespace': b'bookmarks'}
5476 b'listkeys', {b'namespace': b'bookmarks'}
5477 )
5477 )
5478 for r in revs:
5478 for r in revs:
5479 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5479 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5480 remotebookmarks = fremotebookmarks.result()
5480 remotebookmarks = fremotebookmarks.result()
5481 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5481 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5482 pullopargs[b'remotebookmarks'] = remotebookmarks
5482 pullopargs[b'remotebookmarks'] = remotebookmarks
5483 for b in opts.get(b'bookmark', []):
5483 for b in opts.get(b'bookmark', []):
5484 b = repo._bookmarks.expandname(b)
5484 b = repo._bookmarks.expandname(b)
5485 if b not in remotebookmarks:
5485 if b not in remotebookmarks:
5486 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5486 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5487 nodes.append(remotebookmarks[b])
5487 nodes.append(remotebookmarks[b])
5488 for i, rev in enumerate(revs):
5488 for i, rev in enumerate(revs):
5489 node = fnodes[i].result()
5489 node = fnodes[i].result()
5490 nodes.append(node)
5490 nodes.append(node)
5491 if rev == checkout:
5491 if rev == checkout:
5492 checkout = node
5492 checkout = node
5493
5493
5494 wlock = util.nullcontextmanager()
5494 wlock = util.nullcontextmanager()
5495 if opts.get(b'update'):
5495 if opts.get(b'update'):
5496 wlock = repo.wlock()
5496 wlock = repo.wlock()
5497 with wlock:
5497 with wlock:
5498 pullopargs.update(opts.get(b'opargs', {}))
5498 pullopargs.update(opts.get(b'opargs', {}))
5499 modheads = exchange.pull(
5499 modheads = exchange.pull(
5500 repo,
5500 repo,
5501 other,
5501 other,
5502 heads=nodes,
5502 heads=nodes,
5503 force=opts.get(b'force'),
5503 force=opts.get(b'force'),
5504 bookmarks=opts.get(b'bookmark', ()),
5504 bookmarks=opts.get(b'bookmark', ()),
5505 opargs=pullopargs,
5505 opargs=pullopargs,
5506 confirm=opts.get(b'confirm'),
5506 confirm=opts.get(b'confirm'),
5507 ).cgresult
5507 ).cgresult
5508
5508
5509 # brev is a name, which might be a bookmark to be activated at
5509 # brev is a name, which might be a bookmark to be activated at
5510 # the end of the update. In other words, it is an explicit
5510 # the end of the update. In other words, it is an explicit
5511 # destination of the update
5511 # destination of the update
5512 brev = None
5512 brev = None
5513
5513
5514 if checkout:
5514 if checkout:
5515 checkout = repo.unfiltered().changelog.rev(checkout)
5515 checkout = repo.unfiltered().changelog.rev(checkout)
5516
5516
5517 # order below depends on implementation of
5517 # order below depends on implementation of
5518 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5518 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5519 # because 'checkout' is determined without it.
5519 # because 'checkout' is determined without it.
5520 if opts.get(b'rev'):
5520 if opts.get(b'rev'):
5521 brev = opts[b'rev'][0]
5521 brev = opts[b'rev'][0]
5522 elif opts.get(b'branch'):
5522 elif opts.get(b'branch'):
5523 brev = opts[b'branch'][0]
5523 brev = opts[b'branch'][0]
5524 else:
5524 else:
5525 brev = branches[0]
5525 brev = branches[0]
5526 repo._subtoppath = source
5526 repo._subtoppath = source
5527 try:
5527 try:
5528 ret = postincoming(
5528 ret = postincoming(
5529 ui, repo, modheads, opts.get(b'update'), checkout, brev
5529 ui, repo, modheads, opts.get(b'update'), checkout, brev
5530 )
5530 )
5531 except error.FilteredRepoLookupError as exc:
5531 except error.FilteredRepoLookupError as exc:
5532 msg = _(b'cannot update to target: %s') % exc.args[0]
5532 msg = _(b'cannot update to target: %s') % exc.args[0]
5533 exc.args = (msg,) + exc.args[1:]
5533 exc.args = (msg,) + exc.args[1:]
5534 raise
5534 raise
5535 finally:
5535 finally:
5536 del repo._subtoppath
5536 del repo._subtoppath
5537
5537
5538 finally:
5538 finally:
5539 other.close()
5539 other.close()
5540 return ret
5540 return ret
5541
5541
5542
5542
5543 @command(
5543 @command(
5544 b'push',
5544 b'push',
5545 [
5545 [
5546 (b'f', b'force', None, _(b'force push')),
5546 (b'f', b'force', None, _(b'force push')),
5547 (
5547 (
5548 b'r',
5548 b'r',
5549 b'rev',
5549 b'rev',
5550 [],
5550 [],
5551 _(b'a changeset intended to be included in the destination'),
5551 _(b'a changeset intended to be included in the destination'),
5552 _(b'REV'),
5552 _(b'REV'),
5553 ),
5553 ),
5554 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5554 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5555 (
5555 (
5556 b'b',
5556 b'b',
5557 b'branch',
5557 b'branch',
5558 [],
5558 [],
5559 _(b'a specific branch you would like to push'),
5559 _(b'a specific branch you would like to push'),
5560 _(b'BRANCH'),
5560 _(b'BRANCH'),
5561 ),
5561 ),
5562 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5562 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5563 (
5563 (
5564 b'',
5564 b'',
5565 b'pushvars',
5565 b'pushvars',
5566 [],
5566 [],
5567 _(b'variables that can be sent to server (ADVANCED)'),
5567 _(b'variables that can be sent to server (ADVANCED)'),
5568 ),
5568 ),
5569 (
5569 (
5570 b'',
5570 b'',
5571 b'publish',
5571 b'publish',
5572 False,
5572 False,
5573 _(b'push the changeset as public (EXPERIMENTAL)'),
5573 _(b'push the changeset as public (EXPERIMENTAL)'),
5574 ),
5574 ),
5575 ]
5575 ]
5576 + remoteopts,
5576 + remoteopts,
5577 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5577 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5578 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5578 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5579 helpbasic=True,
5579 helpbasic=True,
5580 )
5580 )
5581 def push(ui, repo, dest=None, **opts):
5581 def push(ui, repo, dest=None, **opts):
5582 """push changes to the specified destination
5582 """push changes to the specified destination
5583
5583
5584 Push changesets from the local repository to the specified
5584 Push changesets from the local repository to the specified
5585 destination.
5585 destination.
5586
5586
5587 This operation is symmetrical to pull: it is identical to a pull
5587 This operation is symmetrical to pull: it is identical to a pull
5588 in the destination repository from the current one.
5588 in the destination repository from the current one.
5589
5589
5590 By default, push will not allow creation of new heads at the
5590 By default, push will not allow creation of new heads at the
5591 destination, since multiple heads would make it unclear which head
5591 destination, since multiple heads would make it unclear which head
5592 to use. In this situation, it is recommended to pull and merge
5592 to use. In this situation, it is recommended to pull and merge
5593 before pushing.
5593 before pushing.
5594
5594
5595 Use --new-branch if you want to allow push to create a new named
5595 Use --new-branch if you want to allow push to create a new named
5596 branch that is not present at the destination. This allows you to
5596 branch that is not present at the destination. This allows you to
5597 only create a new branch without forcing other changes.
5597 only create a new branch without forcing other changes.
5598
5598
5599 .. note::
5599 .. note::
5600
5600
5601 Extra care should be taken with the -f/--force option,
5601 Extra care should be taken with the -f/--force option,
5602 which will push all new heads on all branches, an action which will
5602 which will push all new heads on all branches, an action which will
5603 almost always cause confusion for collaborators.
5603 almost always cause confusion for collaborators.
5604
5604
5605 If -r/--rev is used, the specified revision and all its ancestors
5605 If -r/--rev is used, the specified revision and all its ancestors
5606 will be pushed to the remote repository.
5606 will be pushed to the remote repository.
5607
5607
5608 If -B/--bookmark is used, the specified bookmarked revision, its
5608 If -B/--bookmark is used, the specified bookmarked revision, its
5609 ancestors, and the bookmark will be pushed to the remote
5609 ancestors, and the bookmark will be pushed to the remote
5610 repository. Specifying ``.`` is equivalent to specifying the active
5610 repository. Specifying ``.`` is equivalent to specifying the active
5611 bookmark's name.
5611 bookmark's name.
5612
5612
5613 Please see :hg:`help urls` for important details about ``ssh://``
5613 Please see :hg:`help urls` for important details about ``ssh://``
5614 URLs. If DESTINATION is omitted, a default path will be used.
5614 URLs. If DESTINATION is omitted, a default path will be used.
5615
5615
5616 .. container:: verbose
5616 .. container:: verbose
5617
5617
5618 The --pushvars option sends strings to the server that become
5618 The --pushvars option sends strings to the server that become
5619 environment variables prepended with ``HG_USERVAR_``. For example,
5619 environment variables prepended with ``HG_USERVAR_``. For example,
5620 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5620 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5621 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5621 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5622
5622
5623 pushvars can provide for user-overridable hooks as well as set debug
5623 pushvars can provide for user-overridable hooks as well as set debug
5624 levels. One example is having a hook that blocks commits containing
5624 levels. One example is having a hook that blocks commits containing
5625 conflict markers, but enables the user to override the hook if the file
5625 conflict markers, but enables the user to override the hook if the file
5626 is using conflict markers for testing purposes or the file format has
5626 is using conflict markers for testing purposes or the file format has
5627 strings that look like conflict markers.
5627 strings that look like conflict markers.
5628
5628
5629 By default, servers will ignore `--pushvars`. To enable it add the
5629 By default, servers will ignore `--pushvars`. To enable it add the
5630 following to your configuration file::
5630 following to your configuration file::
5631
5631
5632 [push]
5632 [push]
5633 pushvars.server = true
5633 pushvars.server = true
5634
5634
5635 Returns 0 if push was successful, 1 if nothing to push.
5635 Returns 0 if push was successful, 1 if nothing to push.
5636 """
5636 """
5637
5637
5638 opts = pycompat.byteskwargs(opts)
5638 opts = pycompat.byteskwargs(opts)
5639 if opts.get(b'bookmark'):
5639 if opts.get(b'bookmark'):
5640 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5640 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5641 for b in opts[b'bookmark']:
5641 for b in opts[b'bookmark']:
5642 # translate -B options to -r so changesets get pushed
5642 # translate -B options to -r so changesets get pushed
5643 b = repo._bookmarks.expandname(b)
5643 b = repo._bookmarks.expandname(b)
5644 if b in repo._bookmarks:
5644 if b in repo._bookmarks:
5645 opts.setdefault(b'rev', []).append(b)
5645 opts.setdefault(b'rev', []).append(b)
5646 else:
5646 else:
5647 # if we try to push a deleted bookmark, translate it to null
5647 # if we try to push a deleted bookmark, translate it to null
5648 # this lets simultaneous -r, -b options continue working
5648 # this lets simultaneous -r, -b options continue working
5649 opts.setdefault(b'rev', []).append(b"null")
5649 opts.setdefault(b'rev', []).append(b"null")
5650
5650
5651 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5651 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5652 if not path:
5652 if not path:
5653 raise error.Abort(
5653 raise error.Abort(
5654 _(b'default repository not configured!'),
5654 _(b'default repository not configured!'),
5655 hint=_(b"see 'hg help config.paths'"),
5655 hint=_(b"see 'hg help config.paths'"),
5656 )
5656 )
5657 dest = path.pushloc or path.loc
5657 dest = path.pushloc or path.loc
5658 branches = (path.branch, opts.get(b'branch') or [])
5658 branches = (path.branch, opts.get(b'branch') or [])
5659 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5659 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5660 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5660 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5661 other = hg.peer(repo, opts, dest)
5661 other = hg.peer(repo, opts, dest)
5662
5662
5663 if revs:
5663 if revs:
5664 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5664 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5665 if not revs:
5665 if not revs:
5666 raise error.Abort(
5666 raise error.Abort(
5667 _(b"specified revisions evaluate to an empty set"),
5667 _(b"specified revisions evaluate to an empty set"),
5668 hint=_(b"use different revision arguments"),
5668 hint=_(b"use different revision arguments"),
5669 )
5669 )
5670 elif path.pushrev:
5670 elif path.pushrev:
5671 # It doesn't make any sense to specify ancestor revisions. So limit
5671 # It doesn't make any sense to specify ancestor revisions. So limit
5672 # to DAG heads to make discovery simpler.
5672 # to DAG heads to make discovery simpler.
5673 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5673 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5674 revs = scmutil.revrange(repo, [expr])
5674 revs = scmutil.revrange(repo, [expr])
5675 revs = [repo[rev].node() for rev in revs]
5675 revs = [repo[rev].node() for rev in revs]
5676 if not revs:
5676 if not revs:
5677 raise error.Abort(
5677 raise error.Abort(
5678 _(b'default push revset for path evaluates to an empty set')
5678 _(b'default push revset for path evaluates to an empty set')
5679 )
5679 )
5680 elif ui.configbool(b'commands', b'push.require-revs'):
5680 elif ui.configbool(b'commands', b'push.require-revs'):
5681 raise error.Abort(
5681 raise error.Abort(
5682 _(b'no revisions specified to push'),
5682 _(b'no revisions specified to push'),
5683 hint=_(b'did you mean "hg push -r ."?'),
5683 hint=_(b'did you mean "hg push -r ."?'),
5684 )
5684 )
5685
5685
5686 repo._subtoppath = dest
5686 repo._subtoppath = dest
5687 try:
5687 try:
5688 # push subrepos depth-first for coherent ordering
5688 # push subrepos depth-first for coherent ordering
5689 c = repo[b'.']
5689 c = repo[b'.']
5690 subs = c.substate # only repos that are committed
5690 subs = c.substate # only repos that are committed
5691 for s in sorted(subs):
5691 for s in sorted(subs):
5692 result = c.sub(s).push(opts)
5692 result = c.sub(s).push(opts)
5693 if result == 0:
5693 if result == 0:
5694 return not result
5694 return not result
5695 finally:
5695 finally:
5696 del repo._subtoppath
5696 del repo._subtoppath
5697
5697
5698 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5698 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5699 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5699 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5700
5700
5701 pushop = exchange.push(
5701 pushop = exchange.push(
5702 repo,
5702 repo,
5703 other,
5703 other,
5704 opts.get(b'force'),
5704 opts.get(b'force'),
5705 revs=revs,
5705 revs=revs,
5706 newbranch=opts.get(b'new_branch'),
5706 newbranch=opts.get(b'new_branch'),
5707 bookmarks=opts.get(b'bookmark', ()),
5707 bookmarks=opts.get(b'bookmark', ()),
5708 publish=opts.get(b'publish'),
5708 publish=opts.get(b'publish'),
5709 opargs=opargs,
5709 opargs=opargs,
5710 )
5710 )
5711
5711
5712 result = not pushop.cgresult
5712 result = not pushop.cgresult
5713
5713
5714 if pushop.bkresult is not None:
5714 if pushop.bkresult is not None:
5715 if pushop.bkresult == 2:
5715 if pushop.bkresult == 2:
5716 result = 2
5716 result = 2
5717 elif not result and pushop.bkresult:
5717 elif not result and pushop.bkresult:
5718 result = 2
5718 result = 2
5719
5719
5720 return result
5720 return result
5721
5721
5722
5722
5723 @command(
5723 @command(
5724 b'recover',
5724 b'recover',
5725 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5725 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5726 helpcategory=command.CATEGORY_MAINTENANCE,
5726 helpcategory=command.CATEGORY_MAINTENANCE,
5727 )
5727 )
5728 def recover(ui, repo, **opts):
5728 def recover(ui, repo, **opts):
5729 """roll back an interrupted transaction
5729 """roll back an interrupted transaction
5730
5730
5731 Recover from an interrupted commit or pull.
5731 Recover from an interrupted commit or pull.
5732
5732
5733 This command tries to fix the repository status after an
5733 This command tries to fix the repository status after an
5734 interrupted operation. It should only be necessary when Mercurial
5734 interrupted operation. It should only be necessary when Mercurial
5735 suggests it.
5735 suggests it.
5736
5736
5737 Returns 0 if successful, 1 if nothing to recover or verify fails.
5737 Returns 0 if successful, 1 if nothing to recover or verify fails.
5738 """
5738 """
5739 ret = repo.recover()
5739 ret = repo.recover()
5740 if ret:
5740 if ret:
5741 if opts['verify']:
5741 if opts['verify']:
5742 return hg.verify(repo)
5742 return hg.verify(repo)
5743 else:
5743 else:
5744 msg = _(
5744 msg = _(
5745 b"(verify step skipped, run `hg verify` to check your "
5745 b"(verify step skipped, run `hg verify` to check your "
5746 b"repository content)\n"
5746 b"repository content)\n"
5747 )
5747 )
5748 ui.warn(msg)
5748 ui.warn(msg)
5749 return 0
5749 return 0
5750 return 1
5750 return 1
5751
5751
5752
5752
5753 @command(
5753 @command(
5754 b'remove|rm',
5754 b'remove|rm',
5755 [
5755 [
5756 (b'A', b'after', None, _(b'record delete for missing files')),
5756 (b'A', b'after', None, _(b'record delete for missing files')),
5757 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5757 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5758 ]
5758 ]
5759 + subrepoopts
5759 + subrepoopts
5760 + walkopts
5760 + walkopts
5761 + dryrunopts,
5761 + dryrunopts,
5762 _(b'[OPTION]... FILE...'),
5762 _(b'[OPTION]... FILE...'),
5763 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5763 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5764 helpbasic=True,
5764 helpbasic=True,
5765 inferrepo=True,
5765 inferrepo=True,
5766 )
5766 )
5767 def remove(ui, repo, *pats, **opts):
5767 def remove(ui, repo, *pats, **opts):
5768 """remove the specified files on the next commit
5768 """remove the specified files on the next commit
5769
5769
5770 Schedule the indicated files for removal from the current branch.
5770 Schedule the indicated files for removal from the current branch.
5771
5771
5772 This command schedules the files to be removed at the next commit.
5772 This command schedules the files to be removed at the next commit.
5773 To undo a remove before that, see :hg:`revert`. To undo added
5773 To undo a remove before that, see :hg:`revert`. To undo added
5774 files, see :hg:`forget`.
5774 files, see :hg:`forget`.
5775
5775
5776 .. container:: verbose
5776 .. container:: verbose
5777
5777
5778 -A/--after can be used to remove only files that have already
5778 -A/--after can be used to remove only files that have already
5779 been deleted, -f/--force can be used to force deletion, and -Af
5779 been deleted, -f/--force can be used to force deletion, and -Af
5780 can be used to remove files from the next revision without
5780 can be used to remove files from the next revision without
5781 deleting them from the working directory.
5781 deleting them from the working directory.
5782
5782
5783 The following table details the behavior of remove for different
5783 The following table details the behavior of remove for different
5784 file states (columns) and option combinations (rows). The file
5784 file states (columns) and option combinations (rows). The file
5785 states are Added [A], Clean [C], Modified [M] and Missing [!]
5785 states are Added [A], Clean [C], Modified [M] and Missing [!]
5786 (as reported by :hg:`status`). The actions are Warn, Remove
5786 (as reported by :hg:`status`). The actions are Warn, Remove
5787 (from branch) and Delete (from disk):
5787 (from branch) and Delete (from disk):
5788
5788
5789 ========= == == == ==
5789 ========= == == == ==
5790 opt/state A C M !
5790 opt/state A C M !
5791 ========= == == == ==
5791 ========= == == == ==
5792 none W RD W R
5792 none W RD W R
5793 -f R RD RD R
5793 -f R RD RD R
5794 -A W W W R
5794 -A W W W R
5795 -Af R R R R
5795 -Af R R R R
5796 ========= == == == ==
5796 ========= == == == ==
5797
5797
5798 .. note::
5798 .. note::
5799
5799
5800 :hg:`remove` never deletes files in Added [A] state from the
5800 :hg:`remove` never deletes files in Added [A] state from the
5801 working directory, not even if ``--force`` is specified.
5801 working directory, not even if ``--force`` is specified.
5802
5802
5803 Returns 0 on success, 1 if any warnings encountered.
5803 Returns 0 on success, 1 if any warnings encountered.
5804 """
5804 """
5805
5805
5806 opts = pycompat.byteskwargs(opts)
5806 opts = pycompat.byteskwargs(opts)
5807 after, force = opts.get(b'after'), opts.get(b'force')
5807 after, force = opts.get(b'after'), opts.get(b'force')
5808 dryrun = opts.get(b'dry_run')
5808 dryrun = opts.get(b'dry_run')
5809 if not pats and not after:
5809 if not pats and not after:
5810 raise error.Abort(_(b'no files specified'))
5810 raise error.Abort(_(b'no files specified'))
5811
5811
5812 m = scmutil.match(repo[None], pats, opts)
5812 m = scmutil.match(repo[None], pats, opts)
5813 subrepos = opts.get(b'subrepos')
5813 subrepos = opts.get(b'subrepos')
5814 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5814 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5815 return cmdutil.remove(
5815 return cmdutil.remove(
5816 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5816 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5817 )
5817 )
5818
5818
5819
5819
5820 @command(
5820 @command(
5821 b'rename|move|mv',
5821 b'rename|move|mv',
5822 [
5822 [
5823 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5823 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5824 (
5824 (
5825 b'',
5825 b'',
5826 b'at-rev',
5826 b'at-rev',
5827 b'',
5827 b'',
5828 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5828 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5829 _(b'REV'),
5829 _(b'REV'),
5830 ),
5830 ),
5831 (
5831 (
5832 b'f',
5832 b'f',
5833 b'force',
5833 b'force',
5834 None,
5834 None,
5835 _(b'forcibly move over an existing managed file'),
5835 _(b'forcibly move over an existing managed file'),
5836 ),
5836 ),
5837 ]
5837 ]
5838 + walkopts
5838 + walkopts
5839 + dryrunopts,
5839 + dryrunopts,
5840 _(b'[OPTION]... SOURCE... DEST'),
5840 _(b'[OPTION]... SOURCE... DEST'),
5841 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5841 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5842 )
5842 )
5843 def rename(ui, repo, *pats, **opts):
5843 def rename(ui, repo, *pats, **opts):
5844 """rename files; equivalent of copy + remove
5844 """rename files; equivalent of copy + remove
5845
5845
5846 Mark dest as copies of sources; mark sources for deletion. If dest
5846 Mark dest as copies of sources; mark sources for deletion. If dest
5847 is a directory, copies are put in that directory. If dest is a
5847 is a directory, copies are put in that directory. If dest is a
5848 file, there can only be one source.
5848 file, there can only be one source.
5849
5849
5850 By default, this command copies the contents of files as they
5850 By default, this command copies the contents of files as they
5851 exist in the working directory. If invoked with -A/--after, the
5851 exist in the working directory. If invoked with -A/--after, the
5852 operation is recorded, but no copying is performed.
5852 operation is recorded, but no copying is performed.
5853
5853
5854 This command takes effect at the next commit. To undo a rename
5854 This command takes effect at the next commit. To undo a rename
5855 before that, see :hg:`revert`.
5855 before that, see :hg:`revert`.
5856
5856
5857 Returns 0 on success, 1 if errors are encountered.
5857 Returns 0 on success, 1 if errors are encountered.
5858 """
5858 """
5859 opts = pycompat.byteskwargs(opts)
5859 opts = pycompat.byteskwargs(opts)
5860 with repo.wlock():
5860 with repo.wlock():
5861 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5861 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5862
5862
5863
5863
5864 @command(
5864 @command(
5865 b'resolve',
5865 b'resolve',
5866 [
5866 [
5867 (b'a', b'all', None, _(b'select all unresolved files')),
5867 (b'a', b'all', None, _(b'select all unresolved files')),
5868 (b'l', b'list', None, _(b'list state of files needing merge')),
5868 (b'l', b'list', None, _(b'list state of files needing merge')),
5869 (b'm', b'mark', None, _(b'mark files as resolved')),
5869 (b'm', b'mark', None, _(b'mark files as resolved')),
5870 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5870 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5871 (b'n', b'no-status', None, _(b'hide status prefix')),
5871 (b'n', b'no-status', None, _(b'hide status prefix')),
5872 (b'', b're-merge', None, _(b're-merge files')),
5872 (b'', b're-merge', None, _(b're-merge files')),
5873 ]
5873 ]
5874 + mergetoolopts
5874 + mergetoolopts
5875 + walkopts
5875 + walkopts
5876 + formatteropts,
5876 + formatteropts,
5877 _(b'[OPTION]... [FILE]...'),
5877 _(b'[OPTION]... [FILE]...'),
5878 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5878 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5879 inferrepo=True,
5879 inferrepo=True,
5880 )
5880 )
5881 def resolve(ui, repo, *pats, **opts):
5881 def resolve(ui, repo, *pats, **opts):
5882 """redo merges or set/view the merge status of files
5882 """redo merges or set/view the merge status of files
5883
5883
5884 Merges with unresolved conflicts are often the result of
5884 Merges with unresolved conflicts are often the result of
5885 non-interactive merging using the ``internal:merge`` configuration
5885 non-interactive merging using the ``internal:merge`` configuration
5886 setting, or a command-line merge tool like ``diff3``. The resolve
5886 setting, or a command-line merge tool like ``diff3``. The resolve
5887 command is used to manage the files involved in a merge, after
5887 command is used to manage the files involved in a merge, after
5888 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5888 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5889 working directory must have two parents). See :hg:`help
5889 working directory must have two parents). See :hg:`help
5890 merge-tools` for information on configuring merge tools.
5890 merge-tools` for information on configuring merge tools.
5891
5891
5892 The resolve command can be used in the following ways:
5892 The resolve command can be used in the following ways:
5893
5893
5894 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5894 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5895 the specified files, discarding any previous merge attempts. Re-merging
5895 the specified files, discarding any previous merge attempts. Re-merging
5896 is not performed for files already marked as resolved. Use ``--all/-a``
5896 is not performed for files already marked as resolved. Use ``--all/-a``
5897 to select all unresolved files. ``--tool`` can be used to specify
5897 to select all unresolved files. ``--tool`` can be used to specify
5898 the merge tool used for the given files. It overrides the HGMERGE
5898 the merge tool used for the given files. It overrides the HGMERGE
5899 environment variable and your configuration files. Previous file
5899 environment variable and your configuration files. Previous file
5900 contents are saved with a ``.orig`` suffix.
5900 contents are saved with a ``.orig`` suffix.
5901
5901
5902 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5902 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5903 (e.g. after having manually fixed-up the files). The default is
5903 (e.g. after having manually fixed-up the files). The default is
5904 to mark all unresolved files.
5904 to mark all unresolved files.
5905
5905
5906 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5906 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5907 default is to mark all resolved files.
5907 default is to mark all resolved files.
5908
5908
5909 - :hg:`resolve -l`: list files which had or still have conflicts.
5909 - :hg:`resolve -l`: list files which had or still have conflicts.
5910 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5910 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5911 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5911 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5912 the list. See :hg:`help filesets` for details.
5912 the list. See :hg:`help filesets` for details.
5913
5913
5914 .. note::
5914 .. note::
5915
5915
5916 Mercurial will not let you commit files with unresolved merge
5916 Mercurial will not let you commit files with unresolved merge
5917 conflicts. You must use :hg:`resolve -m ...` before you can
5917 conflicts. You must use :hg:`resolve -m ...` before you can
5918 commit after a conflicting merge.
5918 commit after a conflicting merge.
5919
5919
5920 .. container:: verbose
5920 .. container:: verbose
5921
5921
5922 Template:
5922 Template:
5923
5923
5924 The following keywords are supported in addition to the common template
5924 The following keywords are supported in addition to the common template
5925 keywords and functions. See also :hg:`help templates`.
5925 keywords and functions. See also :hg:`help templates`.
5926
5926
5927 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5927 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5928 :path: String. Repository-absolute path of the file.
5928 :path: String. Repository-absolute path of the file.
5929
5929
5930 Returns 0 on success, 1 if any files fail a resolve attempt.
5930 Returns 0 on success, 1 if any files fail a resolve attempt.
5931 """
5931 """
5932
5932
5933 opts = pycompat.byteskwargs(opts)
5933 opts = pycompat.byteskwargs(opts)
5934 confirm = ui.configbool(b'commands', b'resolve.confirm')
5934 confirm = ui.configbool(b'commands', b'resolve.confirm')
5935 flaglist = b'all mark unmark list no_status re_merge'.split()
5935 flaglist = b'all mark unmark list no_status re_merge'.split()
5936 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5936 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5937
5937
5938 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5938 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5939 if actioncount > 1:
5939 if actioncount > 1:
5940 raise error.Abort(_(b"too many actions specified"))
5940 raise error.Abort(_(b"too many actions specified"))
5941 elif actioncount == 0 and ui.configbool(
5941 elif actioncount == 0 and ui.configbool(
5942 b'commands', b'resolve.explicit-re-merge'
5942 b'commands', b'resolve.explicit-re-merge'
5943 ):
5943 ):
5944 hint = _(b'use --mark, --unmark, --list or --re-merge')
5944 hint = _(b'use --mark, --unmark, --list or --re-merge')
5945 raise error.Abort(_(b'no action specified'), hint=hint)
5945 raise error.Abort(_(b'no action specified'), hint=hint)
5946 if pats and all:
5946 if pats and all:
5947 raise error.Abort(_(b"can't specify --all and patterns"))
5947 raise error.Abort(_(b"can't specify --all and patterns"))
5948 if not (all or pats or show or mark or unmark):
5948 if not (all or pats or show or mark or unmark):
5949 raise error.Abort(
5949 raise error.Abort(
5950 _(b'no files or directories specified'),
5950 _(b'no files or directories specified'),
5951 hint=b'use --all to re-merge all unresolved files',
5951 hint=b'use --all to re-merge all unresolved files',
5952 )
5952 )
5953
5953
5954 if confirm:
5954 if confirm:
5955 if all:
5955 if all:
5956 if ui.promptchoice(
5956 if ui.promptchoice(
5957 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5957 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5958 ):
5958 ):
5959 raise error.Abort(_(b'user quit'))
5959 raise error.Abort(_(b'user quit'))
5960 if mark and not pats:
5960 if mark and not pats:
5961 if ui.promptchoice(
5961 if ui.promptchoice(
5962 _(
5962 _(
5963 b'mark all unresolved files as resolved (yn)?'
5963 b'mark all unresolved files as resolved (yn)?'
5964 b'$$ &Yes $$ &No'
5964 b'$$ &Yes $$ &No'
5965 )
5965 )
5966 ):
5966 ):
5967 raise error.Abort(_(b'user quit'))
5967 raise error.Abort(_(b'user quit'))
5968 if unmark and not pats:
5968 if unmark and not pats:
5969 if ui.promptchoice(
5969 if ui.promptchoice(
5970 _(
5970 _(
5971 b'mark all resolved files as unresolved (yn)?'
5971 b'mark all resolved files as unresolved (yn)?'
5972 b'$$ &Yes $$ &No'
5972 b'$$ &Yes $$ &No'
5973 )
5973 )
5974 ):
5974 ):
5975 raise error.Abort(_(b'user quit'))
5975 raise error.Abort(_(b'user quit'))
5976
5976
5977 uipathfn = scmutil.getuipathfn(repo)
5977 uipathfn = scmutil.getuipathfn(repo)
5978
5978
5979 if show:
5979 if show:
5980 ui.pager(b'resolve')
5980 ui.pager(b'resolve')
5981 fm = ui.formatter(b'resolve', opts)
5981 fm = ui.formatter(b'resolve', opts)
5982 ms = mergestatemod.mergestate.read(repo)
5982 ms = mergestatemod.mergestate.read(repo)
5983 wctx = repo[None]
5983 wctx = repo[None]
5984 m = scmutil.match(wctx, pats, opts)
5984 m = scmutil.match(wctx, pats, opts)
5985
5985
5986 # Labels and keys based on merge state. Unresolved path conflicts show
5986 # Labels and keys based on merge state. Unresolved path conflicts show
5987 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5987 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5988 # resolved conflicts.
5988 # resolved conflicts.
5989 mergestateinfo = {
5989 mergestateinfo = {
5990 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5990 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5991 b'resolve.unresolved',
5991 b'resolve.unresolved',
5992 b'U',
5992 b'U',
5993 ),
5993 ),
5994 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5994 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5995 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5995 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5996 b'resolve.unresolved',
5996 b'resolve.unresolved',
5997 b'P',
5997 b'P',
5998 ),
5998 ),
5999 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5999 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6000 b'resolve.resolved',
6000 b'resolve.resolved',
6001 b'R',
6001 b'R',
6002 ),
6002 ),
6003 }
6003 }
6004
6004
6005 for f in ms:
6005 for f in ms:
6006 if not m(f):
6006 if not m(f):
6007 continue
6007 continue
6008
6008
6009 label, key = mergestateinfo[ms[f]]
6009 label, key = mergestateinfo[ms[f]]
6010 fm.startitem()
6010 fm.startitem()
6011 fm.context(ctx=wctx)
6011 fm.context(ctx=wctx)
6012 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6012 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6013 fm.data(path=f)
6013 fm.data(path=f)
6014 fm.plain(b'%s\n' % uipathfn(f), label=label)
6014 fm.plain(b'%s\n' % uipathfn(f), label=label)
6015 fm.end()
6015 fm.end()
6016 return 0
6016 return 0
6017
6017
6018 with repo.wlock():
6018 with repo.wlock():
6019 ms = mergestatemod.mergestate.read(repo)
6019 ms = mergestatemod.mergestate.read(repo)
6020
6020
6021 if not (ms.active() or repo.dirstate.p2() != nullid):
6021 if not (ms.active() or repo.dirstate.p2() != nullid):
6022 raise error.Abort(
6022 raise error.Abort(
6023 _(b'resolve command not applicable when not merging')
6023 _(b'resolve command not applicable when not merging')
6024 )
6024 )
6025
6025
6026 wctx = repo[None]
6026 wctx = repo[None]
6027 m = scmutil.match(wctx, pats, opts)
6027 m = scmutil.match(wctx, pats, opts)
6028 ret = 0
6028 ret = 0
6029 didwork = False
6029 didwork = False
6030
6030
6031 tocomplete = []
6031 tocomplete = []
6032 hasconflictmarkers = []
6032 hasconflictmarkers = []
6033 if mark:
6033 if mark:
6034 markcheck = ui.config(b'commands', b'resolve.mark-check')
6034 markcheck = ui.config(b'commands', b'resolve.mark-check')
6035 if markcheck not in [b'warn', b'abort']:
6035 if markcheck not in [b'warn', b'abort']:
6036 # Treat all invalid / unrecognized values as 'none'.
6036 # Treat all invalid / unrecognized values as 'none'.
6037 markcheck = False
6037 markcheck = False
6038 for f in ms:
6038 for f in ms:
6039 if not m(f):
6039 if not m(f):
6040 continue
6040 continue
6041
6041
6042 didwork = True
6042 didwork = True
6043
6043
6044 # path conflicts must be resolved manually
6044 # path conflicts must be resolved manually
6045 if ms[f] in (
6045 if ms[f] in (
6046 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6046 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6047 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6047 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6048 ):
6048 ):
6049 if mark:
6049 if mark:
6050 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6050 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6051 elif unmark:
6051 elif unmark:
6052 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6052 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6053 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6053 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6054 ui.warn(
6054 ui.warn(
6055 _(b'%s: path conflict must be resolved manually\n')
6055 _(b'%s: path conflict must be resolved manually\n')
6056 % uipathfn(f)
6056 % uipathfn(f)
6057 )
6057 )
6058 continue
6058 continue
6059
6059
6060 if mark:
6060 if mark:
6061 if markcheck:
6061 if markcheck:
6062 fdata = repo.wvfs.tryread(f)
6062 fdata = repo.wvfs.tryread(f)
6063 if (
6063 if (
6064 filemerge.hasconflictmarkers(fdata)
6064 filemerge.hasconflictmarkers(fdata)
6065 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6065 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6066 ):
6066 ):
6067 hasconflictmarkers.append(f)
6067 hasconflictmarkers.append(f)
6068 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6068 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6069 elif unmark:
6069 elif unmark:
6070 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6070 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6071 else:
6071 else:
6072 # backup pre-resolve (merge uses .orig for its own purposes)
6072 # backup pre-resolve (merge uses .orig for its own purposes)
6073 a = repo.wjoin(f)
6073 a = repo.wjoin(f)
6074 try:
6074 try:
6075 util.copyfile(a, a + b".resolve")
6075 util.copyfile(a, a + b".resolve")
6076 except (IOError, OSError) as inst:
6076 except (IOError, OSError) as inst:
6077 if inst.errno != errno.ENOENT:
6077 if inst.errno != errno.ENOENT:
6078 raise
6078 raise
6079
6079
6080 try:
6080 try:
6081 # preresolve file
6081 # preresolve file
6082 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6082 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6083 with ui.configoverride(overrides, b'resolve'):
6083 with ui.configoverride(overrides, b'resolve'):
6084 complete, r = ms.preresolve(f, wctx)
6084 complete, r = ms.preresolve(f, wctx)
6085 if not complete:
6085 if not complete:
6086 tocomplete.append(f)
6086 tocomplete.append(f)
6087 elif r:
6087 elif r:
6088 ret = 1
6088 ret = 1
6089 finally:
6089 finally:
6090 ms.commit()
6090 ms.commit()
6091
6091
6092 # replace filemerge's .orig file with our resolve file, but only
6092 # replace filemerge's .orig file with our resolve file, but only
6093 # for merges that are complete
6093 # for merges that are complete
6094 if complete:
6094 if complete:
6095 try:
6095 try:
6096 util.rename(
6096 util.rename(
6097 a + b".resolve", scmutil.backuppath(ui, repo, f)
6097 a + b".resolve", scmutil.backuppath(ui, repo, f)
6098 )
6098 )
6099 except OSError as inst:
6099 except OSError as inst:
6100 if inst.errno != errno.ENOENT:
6100 if inst.errno != errno.ENOENT:
6101 raise
6101 raise
6102
6102
6103 if hasconflictmarkers:
6103 if hasconflictmarkers:
6104 ui.warn(
6104 ui.warn(
6105 _(
6105 _(
6106 b'warning: the following files still have conflict '
6106 b'warning: the following files still have conflict '
6107 b'markers:\n'
6107 b'markers:\n'
6108 )
6108 )
6109 + b''.join(
6109 + b''.join(
6110 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6110 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6111 )
6111 )
6112 )
6112 )
6113 if markcheck == b'abort' and not all and not pats:
6113 if markcheck == b'abort' and not all and not pats:
6114 raise error.Abort(
6114 raise error.Abort(
6115 _(b'conflict markers detected'),
6115 _(b'conflict markers detected'),
6116 hint=_(b'use --all to mark anyway'),
6116 hint=_(b'use --all to mark anyway'),
6117 )
6117 )
6118
6118
6119 for f in tocomplete:
6119 for f in tocomplete:
6120 try:
6120 try:
6121 # resolve file
6121 # resolve file
6122 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6122 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6123 with ui.configoverride(overrides, b'resolve'):
6123 with ui.configoverride(overrides, b'resolve'):
6124 r = ms.resolve(f, wctx)
6124 r = ms.resolve(f, wctx)
6125 if r:
6125 if r:
6126 ret = 1
6126 ret = 1
6127 finally:
6127 finally:
6128 ms.commit()
6128 ms.commit()
6129
6129
6130 # replace filemerge's .orig file with our resolve file
6130 # replace filemerge's .orig file with our resolve file
6131 a = repo.wjoin(f)
6131 a = repo.wjoin(f)
6132 try:
6132 try:
6133 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6133 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6134 except OSError as inst:
6134 except OSError as inst:
6135 if inst.errno != errno.ENOENT:
6135 if inst.errno != errno.ENOENT:
6136 raise
6136 raise
6137
6137
6138 ms.commit()
6138 ms.commit()
6139 branchmerge = repo.dirstate.p2() != nullid
6139 branchmerge = repo.dirstate.p2() != nullid
6140 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6140 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6141
6141
6142 if not didwork and pats:
6142 if not didwork and pats:
6143 hint = None
6143 hint = None
6144 if not any([p for p in pats if p.find(b':') >= 0]):
6144 if not any([p for p in pats if p.find(b':') >= 0]):
6145 pats = [b'path:%s' % p for p in pats]
6145 pats = [b'path:%s' % p for p in pats]
6146 m = scmutil.match(wctx, pats, opts)
6146 m = scmutil.match(wctx, pats, opts)
6147 for f in ms:
6147 for f in ms:
6148 if not m(f):
6148 if not m(f):
6149 continue
6149 continue
6150
6150
6151 def flag(o):
6151 def flag(o):
6152 if o == b're_merge':
6152 if o == b're_merge':
6153 return b'--re-merge '
6153 return b'--re-merge '
6154 return b'-%s ' % o[0:1]
6154 return b'-%s ' % o[0:1]
6155
6155
6156 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6156 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6157 hint = _(b"(try: hg resolve %s%s)\n") % (
6157 hint = _(b"(try: hg resolve %s%s)\n") % (
6158 flags,
6158 flags,
6159 b' '.join(pats),
6159 b' '.join(pats),
6160 )
6160 )
6161 break
6161 break
6162 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6162 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6163 if hint:
6163 if hint:
6164 ui.warn(hint)
6164 ui.warn(hint)
6165
6165
6166 unresolvedf = list(ms.unresolved())
6166 unresolvedf = list(ms.unresolved())
6167 if not unresolvedf:
6167 if not unresolvedf:
6168 ui.status(_(b'(no more unresolved files)\n'))
6168 ui.status(_(b'(no more unresolved files)\n'))
6169 cmdutil.checkafterresolved(repo)
6169 cmdutil.checkafterresolved(repo)
6170
6170
6171 return ret
6171 return ret
6172
6172
6173
6173
6174 @command(
6174 @command(
6175 b'revert',
6175 b'revert',
6176 [
6176 [
6177 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6177 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6178 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6178 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6179 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6179 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6180 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6180 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6181 (b'i', b'interactive', None, _(b'interactively select the changes')),
6181 (b'i', b'interactive', None, _(b'interactively select the changes')),
6182 ]
6182 ]
6183 + walkopts
6183 + walkopts
6184 + dryrunopts,
6184 + dryrunopts,
6185 _(b'[OPTION]... [-r REV] [NAME]...'),
6185 _(b'[OPTION]... [-r REV] [NAME]...'),
6186 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6186 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6187 )
6187 )
6188 def revert(ui, repo, *pats, **opts):
6188 def revert(ui, repo, *pats, **opts):
6189 """restore files to their checkout state
6189 """restore files to their checkout state
6190
6190
6191 .. note::
6191 .. note::
6192
6192
6193 To check out earlier revisions, you should use :hg:`update REV`.
6193 To check out earlier revisions, you should use :hg:`update REV`.
6194 To cancel an uncommitted merge (and lose your changes),
6194 To cancel an uncommitted merge (and lose your changes),
6195 use :hg:`merge --abort`.
6195 use :hg:`merge --abort`.
6196
6196
6197 With no revision specified, revert the specified files or directories
6197 With no revision specified, revert the specified files or directories
6198 to the contents they had in the parent of the working directory.
6198 to the contents they had in the parent of the working directory.
6199 This restores the contents of files to an unmodified
6199 This restores the contents of files to an unmodified
6200 state and unschedules adds, removes, copies, and renames. If the
6200 state and unschedules adds, removes, copies, and renames. If the
6201 working directory has two parents, you must explicitly specify a
6201 working directory has two parents, you must explicitly specify a
6202 revision.
6202 revision.
6203
6203
6204 Using the -r/--rev or -d/--date options, revert the given files or
6204 Using the -r/--rev or -d/--date options, revert the given files or
6205 directories to their states as of a specific revision. Because
6205 directories to their states as of a specific revision. Because
6206 revert does not change the working directory parents, this will
6206 revert does not change the working directory parents, this will
6207 cause these files to appear modified. This can be helpful to "back
6207 cause these files to appear modified. This can be helpful to "back
6208 out" some or all of an earlier change. See :hg:`backout` for a
6208 out" some or all of an earlier change. See :hg:`backout` for a
6209 related method.
6209 related method.
6210
6210
6211 Modified files are saved with a .orig suffix before reverting.
6211 Modified files are saved with a .orig suffix before reverting.
6212 To disable these backups, use --no-backup. It is possible to store
6212 To disable these backups, use --no-backup. It is possible to store
6213 the backup files in a custom directory relative to the root of the
6213 the backup files in a custom directory relative to the root of the
6214 repository by setting the ``ui.origbackuppath`` configuration
6214 repository by setting the ``ui.origbackuppath`` configuration
6215 option.
6215 option.
6216
6216
6217 See :hg:`help dates` for a list of formats valid for -d/--date.
6217 See :hg:`help dates` for a list of formats valid for -d/--date.
6218
6218
6219 See :hg:`help backout` for a way to reverse the effect of an
6219 See :hg:`help backout` for a way to reverse the effect of an
6220 earlier changeset.
6220 earlier changeset.
6221
6221
6222 Returns 0 on success.
6222 Returns 0 on success.
6223 """
6223 """
6224
6224
6225 opts = pycompat.byteskwargs(opts)
6225 opts = pycompat.byteskwargs(opts)
6226 if opts.get(b"date"):
6226 if opts.get(b"date"):
6227 if opts.get(b"rev"):
6227 if opts.get(b"rev"):
6228 raise error.Abort(_(b"you can't specify a revision and a date"))
6228 raise error.Abort(_(b"you can't specify a revision and a date"))
6229 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6229 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6230
6230
6231 parent, p2 = repo.dirstate.parents()
6231 parent, p2 = repo.dirstate.parents()
6232 if not opts.get(b'rev') and p2 != nullid:
6232 if not opts.get(b'rev') and p2 != nullid:
6233 # revert after merge is a trap for new users (issue2915)
6233 # revert after merge is a trap for new users (issue2915)
6234 raise error.Abort(
6234 raise error.Abort(
6235 _(b'uncommitted merge with no revision specified'),
6235 _(b'uncommitted merge with no revision specified'),
6236 hint=_(b"use 'hg update' or see 'hg help revert'"),
6236 hint=_(b"use 'hg update' or see 'hg help revert'"),
6237 )
6237 )
6238
6238
6239 rev = opts.get(b'rev')
6239 rev = opts.get(b'rev')
6240 if rev:
6240 if rev:
6241 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6241 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6242 ctx = scmutil.revsingle(repo, rev)
6242 ctx = scmutil.revsingle(repo, rev)
6243
6243
6244 if not (
6244 if not (
6245 pats
6245 pats
6246 or opts.get(b'include')
6246 or opts.get(b'include')
6247 or opts.get(b'exclude')
6247 or opts.get(b'exclude')
6248 or opts.get(b'all')
6248 or opts.get(b'all')
6249 or opts.get(b'interactive')
6249 or opts.get(b'interactive')
6250 ):
6250 ):
6251 msg = _(b"no files or directories specified")
6251 msg = _(b"no files or directories specified")
6252 if p2 != nullid:
6252 if p2 != nullid:
6253 hint = _(
6253 hint = _(
6254 b"uncommitted merge, use --all to discard all changes,"
6254 b"uncommitted merge, use --all to discard all changes,"
6255 b" or 'hg update -C .' to abort the merge"
6255 b" or 'hg update -C .' to abort the merge"
6256 )
6256 )
6257 raise error.Abort(msg, hint=hint)
6257 raise error.Abort(msg, hint=hint)
6258 dirty = any(repo.status())
6258 dirty = any(repo.status())
6259 node = ctx.node()
6259 node = ctx.node()
6260 if node != parent:
6260 if node != parent:
6261 if dirty:
6261 if dirty:
6262 hint = (
6262 hint = (
6263 _(
6263 _(
6264 b"uncommitted changes, use --all to discard all"
6264 b"uncommitted changes, use --all to discard all"
6265 b" changes, or 'hg update %d' to update"
6265 b" changes, or 'hg update %d' to update"
6266 )
6266 )
6267 % ctx.rev()
6267 % ctx.rev()
6268 )
6268 )
6269 else:
6269 else:
6270 hint = (
6270 hint = (
6271 _(
6271 _(
6272 b"use --all to revert all files,"
6272 b"use --all to revert all files,"
6273 b" or 'hg update %d' to update"
6273 b" or 'hg update %d' to update"
6274 )
6274 )
6275 % ctx.rev()
6275 % ctx.rev()
6276 )
6276 )
6277 elif dirty:
6277 elif dirty:
6278 hint = _(b"uncommitted changes, use --all to discard all changes")
6278 hint = _(b"uncommitted changes, use --all to discard all changes")
6279 else:
6279 else:
6280 hint = _(b"use --all to revert all files")
6280 hint = _(b"use --all to revert all files")
6281 raise error.Abort(msg, hint=hint)
6281 raise error.Abort(msg, hint=hint)
6282
6282
6283 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6283 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6284
6284
6285
6285
6286 @command(
6286 @command(
6287 b'rollback',
6287 b'rollback',
6288 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6288 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6289 helpcategory=command.CATEGORY_MAINTENANCE,
6289 helpcategory=command.CATEGORY_MAINTENANCE,
6290 )
6290 )
6291 def rollback(ui, repo, **opts):
6291 def rollback(ui, repo, **opts):
6292 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6292 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6293
6293
6294 Please use :hg:`commit --amend` instead of rollback to correct
6294 Please use :hg:`commit --amend` instead of rollback to correct
6295 mistakes in the last commit.
6295 mistakes in the last commit.
6296
6296
6297 This command should be used with care. There is only one level of
6297 This command should be used with care. There is only one level of
6298 rollback, and there is no way to undo a rollback. It will also
6298 rollback, and there is no way to undo a rollback. It will also
6299 restore the dirstate at the time of the last transaction, losing
6299 restore the dirstate at the time of the last transaction, losing
6300 any dirstate changes since that time. This command does not alter
6300 any dirstate changes since that time. This command does not alter
6301 the working directory.
6301 the working directory.
6302
6302
6303 Transactions are used to encapsulate the effects of all commands
6303 Transactions are used to encapsulate the effects of all commands
6304 that create new changesets or propagate existing changesets into a
6304 that create new changesets or propagate existing changesets into a
6305 repository.
6305 repository.
6306
6306
6307 .. container:: verbose
6307 .. container:: verbose
6308
6308
6309 For example, the following commands are transactional, and their
6309 For example, the following commands are transactional, and their
6310 effects can be rolled back:
6310 effects can be rolled back:
6311
6311
6312 - commit
6312 - commit
6313 - import
6313 - import
6314 - pull
6314 - pull
6315 - push (with this repository as the destination)
6315 - push (with this repository as the destination)
6316 - unbundle
6316 - unbundle
6317
6317
6318 To avoid permanent data loss, rollback will refuse to rollback a
6318 To avoid permanent data loss, rollback will refuse to rollback a
6319 commit transaction if it isn't checked out. Use --force to
6319 commit transaction if it isn't checked out. Use --force to
6320 override this protection.
6320 override this protection.
6321
6321
6322 The rollback command can be entirely disabled by setting the
6322 The rollback command can be entirely disabled by setting the
6323 ``ui.rollback`` configuration setting to false. If you're here
6323 ``ui.rollback`` configuration setting to false. If you're here
6324 because you want to use rollback and it's disabled, you can
6324 because you want to use rollback and it's disabled, you can
6325 re-enable the command by setting ``ui.rollback`` to true.
6325 re-enable the command by setting ``ui.rollback`` to true.
6326
6326
6327 This command is not intended for use on public repositories. Once
6327 This command is not intended for use on public repositories. Once
6328 changes are visible for pull by other users, rolling a transaction
6328 changes are visible for pull by other users, rolling a transaction
6329 back locally is ineffective (someone else may already have pulled
6329 back locally is ineffective (someone else may already have pulled
6330 the changes). Furthermore, a race is possible with readers of the
6330 the changes). Furthermore, a race is possible with readers of the
6331 repository; for example an in-progress pull from the repository
6331 repository; for example an in-progress pull from the repository
6332 may fail if a rollback is performed.
6332 may fail if a rollback is performed.
6333
6333
6334 Returns 0 on success, 1 if no rollback data is available.
6334 Returns 0 on success, 1 if no rollback data is available.
6335 """
6335 """
6336 if not ui.configbool(b'ui', b'rollback'):
6336 if not ui.configbool(b'ui', b'rollback'):
6337 raise error.Abort(
6337 raise error.Abort(
6338 _(b'rollback is disabled because it is unsafe'),
6338 _(b'rollback is disabled because it is unsafe'),
6339 hint=b'see `hg help -v rollback` for information',
6339 hint=b'see `hg help -v rollback` for information',
6340 )
6340 )
6341 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6341 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6342
6342
6343
6343
6344 @command(
6344 @command(
6345 b'root',
6345 b'root',
6346 [] + formatteropts,
6346 [] + formatteropts,
6347 intents={INTENT_READONLY},
6347 intents={INTENT_READONLY},
6348 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6348 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6349 )
6349 )
6350 def root(ui, repo, **opts):
6350 def root(ui, repo, **opts):
6351 """print the root (top) of the current working directory
6351 """print the root (top) of the current working directory
6352
6352
6353 Print the root directory of the current repository.
6353 Print the root directory of the current repository.
6354
6354
6355 .. container:: verbose
6355 .. container:: verbose
6356
6356
6357 Template:
6357 Template:
6358
6358
6359 The following keywords are supported in addition to the common template
6359 The following keywords are supported in addition to the common template
6360 keywords and functions. See also :hg:`help templates`.
6360 keywords and functions. See also :hg:`help templates`.
6361
6361
6362 :hgpath: String. Path to the .hg directory.
6362 :hgpath: String. Path to the .hg directory.
6363 :storepath: String. Path to the directory holding versioned data.
6363 :storepath: String. Path to the directory holding versioned data.
6364
6364
6365 Returns 0 on success.
6365 Returns 0 on success.
6366 """
6366 """
6367 opts = pycompat.byteskwargs(opts)
6367 opts = pycompat.byteskwargs(opts)
6368 with ui.formatter(b'root', opts) as fm:
6368 with ui.formatter(b'root', opts) as fm:
6369 fm.startitem()
6369 fm.startitem()
6370 fm.write(b'reporoot', b'%s\n', repo.root)
6370 fm.write(b'reporoot', b'%s\n', repo.root)
6371 fm.data(hgpath=repo.path, storepath=repo.spath)
6371 fm.data(hgpath=repo.path, storepath=repo.spath)
6372
6372
6373
6373
6374 @command(
6374 @command(
6375 b'serve',
6375 b'serve',
6376 [
6376 [
6377 (
6377 (
6378 b'A',
6378 b'A',
6379 b'accesslog',
6379 b'accesslog',
6380 b'',
6380 b'',
6381 _(b'name of access log file to write to'),
6381 _(b'name of access log file to write to'),
6382 _(b'FILE'),
6382 _(b'FILE'),
6383 ),
6383 ),
6384 (b'd', b'daemon', None, _(b'run server in background')),
6384 (b'd', b'daemon', None, _(b'run server in background')),
6385 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6385 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6386 (
6386 (
6387 b'E',
6387 b'E',
6388 b'errorlog',
6388 b'errorlog',
6389 b'',
6389 b'',
6390 _(b'name of error log file to write to'),
6390 _(b'name of error log file to write to'),
6391 _(b'FILE'),
6391 _(b'FILE'),
6392 ),
6392 ),
6393 # use string type, then we can check if something was passed
6393 # use string type, then we can check if something was passed
6394 (
6394 (
6395 b'p',
6395 b'p',
6396 b'port',
6396 b'port',
6397 b'',
6397 b'',
6398 _(b'port to listen on (default: 8000)'),
6398 _(b'port to listen on (default: 8000)'),
6399 _(b'PORT'),
6399 _(b'PORT'),
6400 ),
6400 ),
6401 (
6401 (
6402 b'a',
6402 b'a',
6403 b'address',
6403 b'address',
6404 b'',
6404 b'',
6405 _(b'address to listen on (default: all interfaces)'),
6405 _(b'address to listen on (default: all interfaces)'),
6406 _(b'ADDR'),
6406 _(b'ADDR'),
6407 ),
6407 ),
6408 (
6408 (
6409 b'',
6409 b'',
6410 b'prefix',
6410 b'prefix',
6411 b'',
6411 b'',
6412 _(b'prefix path to serve from (default: server root)'),
6412 _(b'prefix path to serve from (default: server root)'),
6413 _(b'PREFIX'),
6413 _(b'PREFIX'),
6414 ),
6414 ),
6415 (
6415 (
6416 b'n',
6416 b'n',
6417 b'name',
6417 b'name',
6418 b'',
6418 b'',
6419 _(b'name to show in web pages (default: working directory)'),
6419 _(b'name to show in web pages (default: working directory)'),
6420 _(b'NAME'),
6420 _(b'NAME'),
6421 ),
6421 ),
6422 (
6422 (
6423 b'',
6423 b'',
6424 b'web-conf',
6424 b'web-conf',
6425 b'',
6425 b'',
6426 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6426 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6427 _(b'FILE'),
6427 _(b'FILE'),
6428 ),
6428 ),
6429 (
6429 (
6430 b'',
6430 b'',
6431 b'webdir-conf',
6431 b'webdir-conf',
6432 b'',
6432 b'',
6433 _(b'name of the hgweb config file (DEPRECATED)'),
6433 _(b'name of the hgweb config file (DEPRECATED)'),
6434 _(b'FILE'),
6434 _(b'FILE'),
6435 ),
6435 ),
6436 (
6436 (
6437 b'',
6437 b'',
6438 b'pid-file',
6438 b'pid-file',
6439 b'',
6439 b'',
6440 _(b'name of file to write process ID to'),
6440 _(b'name of file to write process ID to'),
6441 _(b'FILE'),
6441 _(b'FILE'),
6442 ),
6442 ),
6443 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6443 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6444 (
6444 (
6445 b'',
6445 b'',
6446 b'cmdserver',
6446 b'cmdserver',
6447 b'',
6447 b'',
6448 _(b'for remote clients (ADVANCED)'),
6448 _(b'for remote clients (ADVANCED)'),
6449 _(b'MODE'),
6449 _(b'MODE'),
6450 ),
6450 ),
6451 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6451 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6452 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6452 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6453 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6453 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6454 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6454 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6455 (b'', b'print-url', None, _(b'start and print only the URL')),
6455 (b'', b'print-url', None, _(b'start and print only the URL')),
6456 ]
6456 ]
6457 + subrepoopts,
6457 + subrepoopts,
6458 _(b'[OPTION]...'),
6458 _(b'[OPTION]...'),
6459 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6459 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6460 helpbasic=True,
6460 helpbasic=True,
6461 optionalrepo=True,
6461 optionalrepo=True,
6462 )
6462 )
6463 def serve(ui, repo, **opts):
6463 def serve(ui, repo, **opts):
6464 """start stand-alone webserver
6464 """start stand-alone webserver
6465
6465
6466 Start a local HTTP repository browser and pull server. You can use
6466 Start a local HTTP repository browser and pull server. You can use
6467 this for ad-hoc sharing and browsing of repositories. It is
6467 this for ad-hoc sharing and browsing of repositories. It is
6468 recommended to use a real web server to serve a repository for
6468 recommended to use a real web server to serve a repository for
6469 longer periods of time.
6469 longer periods of time.
6470
6470
6471 Please note that the server does not implement access control.
6471 Please note that the server does not implement access control.
6472 This means that, by default, anybody can read from the server and
6472 This means that, by default, anybody can read from the server and
6473 nobody can write to it by default. Set the ``web.allow-push``
6473 nobody can write to it by default. Set the ``web.allow-push``
6474 option to ``*`` to allow everybody to push to the server. You
6474 option to ``*`` to allow everybody to push to the server. You
6475 should use a real web server if you need to authenticate users.
6475 should use a real web server if you need to authenticate users.
6476
6476
6477 By default, the server logs accesses to stdout and errors to
6477 By default, the server logs accesses to stdout and errors to
6478 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6478 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6479 files.
6479 files.
6480
6480
6481 To have the server choose a free port number to listen on, specify
6481 To have the server choose a free port number to listen on, specify
6482 a port number of 0; in this case, the server will print the port
6482 a port number of 0; in this case, the server will print the port
6483 number it uses.
6483 number it uses.
6484
6484
6485 Returns 0 on success.
6485 Returns 0 on success.
6486 """
6486 """
6487
6487
6488 opts = pycompat.byteskwargs(opts)
6488 opts = pycompat.byteskwargs(opts)
6489 if opts[b"stdio"] and opts[b"cmdserver"]:
6489 if opts[b"stdio"] and opts[b"cmdserver"]:
6490 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6490 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6491 if opts[b"print_url"] and ui.verbose:
6491 if opts[b"print_url"] and ui.verbose:
6492 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6492 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6493
6493
6494 if opts[b"stdio"]:
6494 if opts[b"stdio"]:
6495 if repo is None:
6495 if repo is None:
6496 raise error.RepoError(
6496 raise error.RepoError(
6497 _(b"there is no Mercurial repository here (.hg not found)")
6497 _(b"there is no Mercurial repository here (.hg not found)")
6498 )
6498 )
6499 s = wireprotoserver.sshserver(ui, repo)
6499 s = wireprotoserver.sshserver(ui, repo)
6500 s.serve_forever()
6500 s.serve_forever()
6501
6501
6502 service = server.createservice(ui, repo, opts)
6502 service = server.createservice(ui, repo, opts)
6503 return server.runservice(opts, initfn=service.init, runfn=service.run)
6503 return server.runservice(opts, initfn=service.init, runfn=service.run)
6504
6504
6505
6505
6506 @command(
6506 @command(
6507 b'shelve',
6507 b'shelve',
6508 [
6508 [
6509 (
6509 (
6510 b'A',
6510 b'A',
6511 b'addremove',
6511 b'addremove',
6512 None,
6512 None,
6513 _(b'mark new/missing files as added/removed before shelving'),
6513 _(b'mark new/missing files as added/removed before shelving'),
6514 ),
6514 ),
6515 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6515 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6516 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6516 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6517 (
6517 (
6518 b'',
6518 b'',
6519 b'date',
6519 b'date',
6520 b'',
6520 b'',
6521 _(b'shelve with the specified commit date'),
6521 _(b'shelve with the specified commit date'),
6522 _(b'DATE'),
6522 _(b'DATE'),
6523 ),
6523 ),
6524 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6524 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6525 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6525 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6526 (
6526 (
6527 b'k',
6527 b'k',
6528 b'keep',
6528 b'keep',
6529 False,
6529 False,
6530 _(b'shelve, but keep changes in the working directory'),
6530 _(b'shelve, but keep changes in the working directory'),
6531 ),
6531 ),
6532 (b'l', b'list', None, _(b'list current shelves')),
6532 (b'l', b'list', None, _(b'list current shelves')),
6533 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6533 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6534 (
6534 (
6535 b'n',
6535 b'n',
6536 b'name',
6536 b'name',
6537 b'',
6537 b'',
6538 _(b'use the given name for the shelved commit'),
6538 _(b'use the given name for the shelved commit'),
6539 _(b'NAME'),
6539 _(b'NAME'),
6540 ),
6540 ),
6541 (
6541 (
6542 b'p',
6542 b'p',
6543 b'patch',
6543 b'patch',
6544 None,
6544 None,
6545 _(
6545 _(
6546 b'output patches for changes (provide the names of the shelved '
6546 b'output patches for changes (provide the names of the shelved '
6547 b'changes as positional arguments)'
6547 b'changes as positional arguments)'
6548 ),
6548 ),
6549 ),
6549 ),
6550 (b'i', b'interactive', None, _(b'interactive mode')),
6550 (b'i', b'interactive', None, _(b'interactive mode')),
6551 (
6551 (
6552 b'',
6552 b'',
6553 b'stat',
6553 b'stat',
6554 None,
6554 None,
6555 _(
6555 _(
6556 b'output diffstat-style summary of changes (provide the names of '
6556 b'output diffstat-style summary of changes (provide the names of '
6557 b'the shelved changes as positional arguments)'
6557 b'the shelved changes as positional arguments)'
6558 ),
6558 ),
6559 ),
6559 ),
6560 ]
6560 ]
6561 + cmdutil.walkopts,
6561 + cmdutil.walkopts,
6562 _(b'hg shelve [OPTION]... [FILE]...'),
6562 _(b'hg shelve [OPTION]... [FILE]...'),
6563 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6563 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6564 )
6564 )
6565 def shelve(ui, repo, *pats, **opts):
6565 def shelve(ui, repo, *pats, **opts):
6566 '''save and set aside changes from the working directory
6566 '''save and set aside changes from the working directory
6567
6567
6568 Shelving takes files that "hg status" reports as not clean, saves
6568 Shelving takes files that "hg status" reports as not clean, saves
6569 the modifications to a bundle (a shelved change), and reverts the
6569 the modifications to a bundle (a shelved change), and reverts the
6570 files so that their state in the working directory becomes clean.
6570 files so that their state in the working directory becomes clean.
6571
6571
6572 To restore these changes to the working directory, using "hg
6572 To restore these changes to the working directory, using "hg
6573 unshelve"; this will work even if you switch to a different
6573 unshelve"; this will work even if you switch to a different
6574 commit.
6574 commit.
6575
6575
6576 When no files are specified, "hg shelve" saves all not-clean
6576 When no files are specified, "hg shelve" saves all not-clean
6577 files. If specific files or directories are named, only changes to
6577 files. If specific files or directories are named, only changes to
6578 those files are shelved.
6578 those files are shelved.
6579
6579
6580 In bare shelve (when no files are specified, without interactive,
6580 In bare shelve (when no files are specified, without interactive,
6581 include and exclude option), shelving remembers information if the
6581 include and exclude option), shelving remembers information if the
6582 working directory was on newly created branch, in other words working
6582 working directory was on newly created branch, in other words working
6583 directory was on different branch than its first parent. In this
6583 directory was on different branch than its first parent. In this
6584 situation unshelving restores branch information to the working directory.
6584 situation unshelving restores branch information to the working directory.
6585
6585
6586 Each shelved change has a name that makes it easier to find later.
6586 Each shelved change has a name that makes it easier to find later.
6587 The name of a shelved change defaults to being based on the active
6587 The name of a shelved change defaults to being based on the active
6588 bookmark, or if there is no active bookmark, the current named
6588 bookmark, or if there is no active bookmark, the current named
6589 branch. To specify a different name, use ``--name``.
6589 branch. To specify a different name, use ``--name``.
6590
6590
6591 To see a list of existing shelved changes, use the ``--list``
6591 To see a list of existing shelved changes, use the ``--list``
6592 option. For each shelved change, this will print its name, age,
6592 option. For each shelved change, this will print its name, age,
6593 and description; use ``--patch`` or ``--stat`` for more details.
6593 and description; use ``--patch`` or ``--stat`` for more details.
6594
6594
6595 To delete specific shelved changes, use ``--delete``. To delete
6595 To delete specific shelved changes, use ``--delete``. To delete
6596 all shelved changes, use ``--cleanup``.
6596 all shelved changes, use ``--cleanup``.
6597 '''
6597 '''
6598 opts = pycompat.byteskwargs(opts)
6598 opts = pycompat.byteskwargs(opts)
6599 allowables = [
6599 allowables = [
6600 (b'addremove', {b'create'}), # 'create' is pseudo action
6600 (b'addremove', {b'create'}), # 'create' is pseudo action
6601 (b'unknown', {b'create'}),
6601 (b'unknown', {b'create'}),
6602 (b'cleanup', {b'cleanup'}),
6602 (b'cleanup', {b'cleanup'}),
6603 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6603 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6604 (b'delete', {b'delete'}),
6604 (b'delete', {b'delete'}),
6605 (b'edit', {b'create'}),
6605 (b'edit', {b'create'}),
6606 (b'keep', {b'create'}),
6606 (b'keep', {b'create'}),
6607 (b'list', {b'list'}),
6607 (b'list', {b'list'}),
6608 (b'message', {b'create'}),
6608 (b'message', {b'create'}),
6609 (b'name', {b'create'}),
6609 (b'name', {b'create'}),
6610 (b'patch', {b'patch', b'list'}),
6610 (b'patch', {b'patch', b'list'}),
6611 (b'stat', {b'stat', b'list'}),
6611 (b'stat', {b'stat', b'list'}),
6612 ]
6612 ]
6613
6613
6614 def checkopt(opt):
6614 def checkopt(opt):
6615 if opts.get(opt):
6615 if opts.get(opt):
6616 for i, allowable in allowables:
6616 for i, allowable in allowables:
6617 if opts[i] and opt not in allowable:
6617 if opts[i] and opt not in allowable:
6618 raise error.Abort(
6618 raise error.Abort(
6619 _(
6619 _(
6620 b"options '--%s' and '--%s' may not be "
6620 b"options '--%s' and '--%s' may not be "
6621 b"used together"
6621 b"used together"
6622 )
6622 )
6623 % (opt, i)
6623 % (opt, i)
6624 )
6624 )
6625 return True
6625 return True
6626
6626
6627 if checkopt(b'cleanup'):
6627 if checkopt(b'cleanup'):
6628 if pats:
6628 if pats:
6629 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6629 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6630 return shelvemod.cleanupcmd(ui, repo)
6630 return shelvemod.cleanupcmd(ui, repo)
6631 elif checkopt(b'delete'):
6631 elif checkopt(b'delete'):
6632 return shelvemod.deletecmd(ui, repo, pats)
6632 return shelvemod.deletecmd(ui, repo, pats)
6633 elif checkopt(b'list'):
6633 elif checkopt(b'list'):
6634 return shelvemod.listcmd(ui, repo, pats, opts)
6634 return shelvemod.listcmd(ui, repo, pats, opts)
6635 elif checkopt(b'patch') or checkopt(b'stat'):
6635 elif checkopt(b'patch') or checkopt(b'stat'):
6636 return shelvemod.patchcmds(ui, repo, pats, opts)
6636 return shelvemod.patchcmds(ui, repo, pats, opts)
6637 else:
6637 else:
6638 return shelvemod.createcmd(ui, repo, pats, opts)
6638 return shelvemod.createcmd(ui, repo, pats, opts)
6639
6639
6640
6640
6641 _NOTTERSE = b'nothing'
6641 _NOTTERSE = b'nothing'
6642
6642
6643
6643
6644 @command(
6644 @command(
6645 b'status|st',
6645 b'status|st',
6646 [
6646 [
6647 (b'A', b'all', None, _(b'show status of all files')),
6647 (b'A', b'all', None, _(b'show status of all files')),
6648 (b'm', b'modified', None, _(b'show only modified files')),
6648 (b'm', b'modified', None, _(b'show only modified files')),
6649 (b'a', b'added', None, _(b'show only added files')),
6649 (b'a', b'added', None, _(b'show only added files')),
6650 (b'r', b'removed', None, _(b'show only removed files')),
6650 (b'r', b'removed', None, _(b'show only removed files')),
6651 (b'd', b'deleted', None, _(b'show only missing files')),
6651 (b'd', b'deleted', None, _(b'show only missing files')),
6652 (b'c', b'clean', None, _(b'show only files without changes')),
6652 (b'c', b'clean', None, _(b'show only files without changes')),
6653 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6653 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6654 (b'i', b'ignored', None, _(b'show only ignored files')),
6654 (b'i', b'ignored', None, _(b'show only ignored files')),
6655 (b'n', b'no-status', None, _(b'hide status prefix')),
6655 (b'n', b'no-status', None, _(b'hide status prefix')),
6656 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6656 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6657 (
6657 (
6658 b'C',
6658 b'C',
6659 b'copies',
6659 b'copies',
6660 None,
6660 None,
6661 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6661 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6662 ),
6662 ),
6663 (
6663 (
6664 b'0',
6664 b'0',
6665 b'print0',
6665 b'print0',
6666 None,
6666 None,
6667 _(b'end filenames with NUL, for use with xargs'),
6667 _(b'end filenames with NUL, for use with xargs'),
6668 ),
6668 ),
6669 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6669 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6670 (
6670 (
6671 b'',
6671 b'',
6672 b'change',
6672 b'change',
6673 b'',
6673 b'',
6674 _(b'list the changed files of a revision'),
6674 _(b'list the changed files of a revision'),
6675 _(b'REV'),
6675 _(b'REV'),
6676 ),
6676 ),
6677 ]
6677 ]
6678 + walkopts
6678 + walkopts
6679 + subrepoopts
6679 + subrepoopts
6680 + formatteropts,
6680 + formatteropts,
6681 _(b'[OPTION]... [FILE]...'),
6681 _(b'[OPTION]... [FILE]...'),
6682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6683 helpbasic=True,
6683 helpbasic=True,
6684 inferrepo=True,
6684 inferrepo=True,
6685 intents={INTENT_READONLY},
6685 intents={INTENT_READONLY},
6686 )
6686 )
6687 def status(ui, repo, *pats, **opts):
6687 def status(ui, repo, *pats, **opts):
6688 """show changed files in the working directory
6688 """show changed files in the working directory
6689
6689
6690 Show status of files in the repository. If names are given, only
6690 Show status of files in the repository. If names are given, only
6691 files that match are shown. Files that are clean or ignored or
6691 files that match are shown. Files that are clean or ignored or
6692 the source of a copy/move operation, are not listed unless
6692 the source of a copy/move operation, are not listed unless
6693 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6693 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6694 Unless options described with "show only ..." are given, the
6694 Unless options described with "show only ..." are given, the
6695 options -mardu are used.
6695 options -mardu are used.
6696
6696
6697 Option -q/--quiet hides untracked (unknown and ignored) files
6697 Option -q/--quiet hides untracked (unknown and ignored) files
6698 unless explicitly requested with -u/--unknown or -i/--ignored.
6698 unless explicitly requested with -u/--unknown or -i/--ignored.
6699
6699
6700 .. note::
6700 .. note::
6701
6701
6702 :hg:`status` may appear to disagree with diff if permissions have
6702 :hg:`status` may appear to disagree with diff if permissions have
6703 changed or a merge has occurred. The standard diff format does
6703 changed or a merge has occurred. The standard diff format does
6704 not report permission changes and diff only reports changes
6704 not report permission changes and diff only reports changes
6705 relative to one merge parent.
6705 relative to one merge parent.
6706
6706
6707 If one revision is given, it is used as the base revision.
6707 If one revision is given, it is used as the base revision.
6708 If two revisions are given, the differences between them are
6708 If two revisions are given, the differences between them are
6709 shown. The --change option can also be used as a shortcut to list
6709 shown. The --change option can also be used as a shortcut to list
6710 the changed files of a revision from its first parent.
6710 the changed files of a revision from its first parent.
6711
6711
6712 The codes used to show the status of files are::
6712 The codes used to show the status of files are::
6713
6713
6714 M = modified
6714 M = modified
6715 A = added
6715 A = added
6716 R = removed
6716 R = removed
6717 C = clean
6717 C = clean
6718 ! = missing (deleted by non-hg command, but still tracked)
6718 ! = missing (deleted by non-hg command, but still tracked)
6719 ? = not tracked
6719 ? = not tracked
6720 I = ignored
6720 I = ignored
6721 = origin of the previous file (with --copies)
6721 = origin of the previous file (with --copies)
6722
6722
6723 .. container:: verbose
6723 .. container:: verbose
6724
6724
6725 The -t/--terse option abbreviates the output by showing only the directory
6725 The -t/--terse option abbreviates the output by showing only the directory
6726 name if all the files in it share the same status. The option takes an
6726 name if all the files in it share the same status. The option takes an
6727 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6727 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6728 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6728 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6729 for 'ignored' and 'c' for clean.
6729 for 'ignored' and 'c' for clean.
6730
6730
6731 It abbreviates only those statuses which are passed. Note that clean and
6731 It abbreviates only those statuses which are passed. Note that clean and
6732 ignored files are not displayed with '--terse ic' unless the -c/--clean
6732 ignored files are not displayed with '--terse ic' unless the -c/--clean
6733 and -i/--ignored options are also used.
6733 and -i/--ignored options are also used.
6734
6734
6735 The -v/--verbose option shows information when the repository is in an
6735 The -v/--verbose option shows information when the repository is in an
6736 unfinished merge, shelve, rebase state etc. You can have this behavior
6736 unfinished merge, shelve, rebase state etc. You can have this behavior
6737 turned on by default by enabling the ``commands.status.verbose`` option.
6737 turned on by default by enabling the ``commands.status.verbose`` option.
6738
6738
6739 You can skip displaying some of these states by setting
6739 You can skip displaying some of these states by setting
6740 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6740 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6741 'histedit', 'merge', 'rebase', or 'unshelve'.
6741 'histedit', 'merge', 'rebase', or 'unshelve'.
6742
6742
6743 Template:
6743 Template:
6744
6744
6745 The following keywords are supported in addition to the common template
6745 The following keywords are supported in addition to the common template
6746 keywords and functions. See also :hg:`help templates`.
6746 keywords and functions. See also :hg:`help templates`.
6747
6747
6748 :path: String. Repository-absolute path of the file.
6748 :path: String. Repository-absolute path of the file.
6749 :source: String. Repository-absolute path of the file originated from.
6749 :source: String. Repository-absolute path of the file originated from.
6750 Available if ``--copies`` is specified.
6750 Available if ``--copies`` is specified.
6751 :status: String. Character denoting file's status.
6751 :status: String. Character denoting file's status.
6752
6752
6753 Examples:
6753 Examples:
6754
6754
6755 - show changes in the working directory relative to a
6755 - show changes in the working directory relative to a
6756 changeset::
6756 changeset::
6757
6757
6758 hg status --rev 9353
6758 hg status --rev 9353
6759
6759
6760 - show changes in the working directory relative to the
6760 - show changes in the working directory relative to the
6761 current directory (see :hg:`help patterns` for more information)::
6761 current directory (see :hg:`help patterns` for more information)::
6762
6762
6763 hg status re:
6763 hg status re:
6764
6764
6765 - show all changes including copies in an existing changeset::
6765 - show all changes including copies in an existing changeset::
6766
6766
6767 hg status --copies --change 9353
6767 hg status --copies --change 9353
6768
6768
6769 - get a NUL separated list of added files, suitable for xargs::
6769 - get a NUL separated list of added files, suitable for xargs::
6770
6770
6771 hg status -an0
6771 hg status -an0
6772
6772
6773 - show more information about the repository status, abbreviating
6773 - show more information about the repository status, abbreviating
6774 added, removed, modified, deleted, and untracked paths::
6774 added, removed, modified, deleted, and untracked paths::
6775
6775
6776 hg status -v -t mardu
6776 hg status -v -t mardu
6777
6777
6778 Returns 0 on success.
6778 Returns 0 on success.
6779
6779
6780 """
6780 """
6781
6781
6782 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6782 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6783 opts = pycompat.byteskwargs(opts)
6783 opts = pycompat.byteskwargs(opts)
6784 revs = opts.get(b'rev')
6784 revs = opts.get(b'rev')
6785 change = opts.get(b'change')
6785 change = opts.get(b'change')
6786 terse = opts.get(b'terse')
6786 terse = opts.get(b'terse')
6787 if terse is _NOTTERSE:
6787 if terse is _NOTTERSE:
6788 if revs:
6788 if revs:
6789 terse = b''
6789 terse = b''
6790 else:
6790 else:
6791 terse = ui.config(b'commands', b'status.terse')
6791 terse = ui.config(b'commands', b'status.terse')
6792
6792
6793 if revs and terse:
6793 if revs and terse:
6794 msg = _(b'cannot use --terse with --rev')
6794 msg = _(b'cannot use --terse with --rev')
6795 raise error.Abort(msg)
6795 raise error.Abort(msg)
6796 elif change:
6796 elif change:
6797 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6797 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6798 ctx2 = scmutil.revsingle(repo, change, None)
6798 ctx2 = scmutil.revsingle(repo, change, None)
6799 ctx1 = ctx2.p1()
6799 ctx1 = ctx2.p1()
6800 else:
6800 else:
6801 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6801 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6802 ctx1, ctx2 = scmutil.revpair(repo, revs)
6802 ctx1, ctx2 = scmutil.revpair(repo, revs)
6803
6803
6804 forcerelativevalue = None
6804 forcerelativevalue = None
6805 if ui.hasconfig(b'commands', b'status.relative'):
6805 if ui.hasconfig(b'commands', b'status.relative'):
6806 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6806 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6807 uipathfn = scmutil.getuipathfn(
6807 uipathfn = scmutil.getuipathfn(
6808 repo,
6808 repo,
6809 legacyrelativevalue=bool(pats),
6809 legacyrelativevalue=bool(pats),
6810 forcerelativevalue=forcerelativevalue,
6810 forcerelativevalue=forcerelativevalue,
6811 )
6811 )
6812
6812
6813 if opts.get(b'print0'):
6813 if opts.get(b'print0'):
6814 end = b'\0'
6814 end = b'\0'
6815 else:
6815 else:
6816 end = b'\n'
6816 end = b'\n'
6817 states = b'modified added removed deleted unknown ignored clean'.split()
6817 states = b'modified added removed deleted unknown ignored clean'.split()
6818 show = [k for k in states if opts.get(k)]
6818 show = [k for k in states if opts.get(k)]
6819 if opts.get(b'all'):
6819 if opts.get(b'all'):
6820 show += ui.quiet and (states[:4] + [b'clean']) or states
6820 show += ui.quiet and (states[:4] + [b'clean']) or states
6821
6821
6822 if not show:
6822 if not show:
6823 if ui.quiet:
6823 if ui.quiet:
6824 show = states[:4]
6824 show = states[:4]
6825 else:
6825 else:
6826 show = states[:5]
6826 show = states[:5]
6827
6827
6828 m = scmutil.match(ctx2, pats, opts)
6828 m = scmutil.match(ctx2, pats, opts)
6829 if terse:
6829 if terse:
6830 # we need to compute clean and unknown to terse
6830 # we need to compute clean and unknown to terse
6831 stat = repo.status(
6831 stat = repo.status(
6832 ctx1.node(),
6832 ctx1.node(),
6833 ctx2.node(),
6833 ctx2.node(),
6834 m,
6834 m,
6835 b'ignored' in show or b'i' in terse,
6835 b'ignored' in show or b'i' in terse,
6836 clean=True,
6836 clean=True,
6837 unknown=True,
6837 unknown=True,
6838 listsubrepos=opts.get(b'subrepos'),
6838 listsubrepos=opts.get(b'subrepos'),
6839 )
6839 )
6840
6840
6841 stat = cmdutil.tersedir(stat, terse)
6841 stat = cmdutil.tersedir(stat, terse)
6842 else:
6842 else:
6843 stat = repo.status(
6843 stat = repo.status(
6844 ctx1.node(),
6844 ctx1.node(),
6845 ctx2.node(),
6845 ctx2.node(),
6846 m,
6846 m,
6847 b'ignored' in show,
6847 b'ignored' in show,
6848 b'clean' in show,
6848 b'clean' in show,
6849 b'unknown' in show,
6849 b'unknown' in show,
6850 opts.get(b'subrepos'),
6850 opts.get(b'subrepos'),
6851 )
6851 )
6852
6852
6853 changestates = zip(
6853 changestates = zip(
6854 states,
6854 states,
6855 pycompat.iterbytestr(b'MAR!?IC'),
6855 pycompat.iterbytestr(b'MAR!?IC'),
6856 [getattr(stat, s.decode('utf8')) for s in states],
6856 [getattr(stat, s.decode('utf8')) for s in states],
6857 )
6857 )
6858
6858
6859 copy = {}
6859 copy = {}
6860 if (
6860 if (
6861 opts.get(b'all')
6861 opts.get(b'all')
6862 or opts.get(b'copies')
6862 or opts.get(b'copies')
6863 or ui.configbool(b'ui', b'statuscopies')
6863 or ui.configbool(b'ui', b'statuscopies')
6864 ) and not opts.get(b'no_status'):
6864 ) and not opts.get(b'no_status'):
6865 copy = copies.pathcopies(ctx1, ctx2, m)
6865 copy = copies.pathcopies(ctx1, ctx2, m)
6866
6866
6867 morestatus = None
6867 morestatus = None
6868 if (
6868 if (
6869 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6869 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6870 ) and not ui.plain():
6870 ) and not ui.plain():
6871 morestatus = cmdutil.readmorestatus(repo)
6871 morestatus = cmdutil.readmorestatus(repo)
6872
6872
6873 ui.pager(b'status')
6873 ui.pager(b'status')
6874 fm = ui.formatter(b'status', opts)
6874 fm = ui.formatter(b'status', opts)
6875 fmt = b'%s' + end
6875 fmt = b'%s' + end
6876 showchar = not opts.get(b'no_status')
6876 showchar = not opts.get(b'no_status')
6877
6877
6878 for state, char, files in changestates:
6878 for state, char, files in changestates:
6879 if state in show:
6879 if state in show:
6880 label = b'status.' + state
6880 label = b'status.' + state
6881 for f in files:
6881 for f in files:
6882 fm.startitem()
6882 fm.startitem()
6883 fm.context(ctx=ctx2)
6883 fm.context(ctx=ctx2)
6884 fm.data(itemtype=b'file', path=f)
6884 fm.data(itemtype=b'file', path=f)
6885 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6885 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6886 fm.plain(fmt % uipathfn(f), label=label)
6886 fm.plain(fmt % uipathfn(f), label=label)
6887 if f in copy:
6887 if f in copy:
6888 fm.data(source=copy[f])
6888 fm.data(source=copy[f])
6889 fm.plain(
6889 fm.plain(
6890 (b' %s' + end) % uipathfn(copy[f]),
6890 (b' %s' + end) % uipathfn(copy[f]),
6891 label=b'status.copied',
6891 label=b'status.copied',
6892 )
6892 )
6893 if morestatus:
6893 if morestatus:
6894 morestatus.formatfile(f, fm)
6894 morestatus.formatfile(f, fm)
6895
6895
6896 if morestatus:
6896 if morestatus:
6897 morestatus.formatfooter(fm)
6897 morestatus.formatfooter(fm)
6898 fm.end()
6898 fm.end()
6899
6899
6900
6900
6901 @command(
6901 @command(
6902 b'summary|sum',
6902 b'summary|sum',
6903 [(b'', b'remote', None, _(b'check for push and pull'))],
6903 [(b'', b'remote', None, _(b'check for push and pull'))],
6904 b'[--remote]',
6904 b'[--remote]',
6905 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6905 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6906 helpbasic=True,
6906 helpbasic=True,
6907 intents={INTENT_READONLY},
6907 intents={INTENT_READONLY},
6908 )
6908 )
6909 def summary(ui, repo, **opts):
6909 def summary(ui, repo, **opts):
6910 """summarize working directory state
6910 """summarize working directory state
6911
6911
6912 This generates a brief summary of the working directory state,
6912 This generates a brief summary of the working directory state,
6913 including parents, branch, commit status, phase and available updates.
6913 including parents, branch, commit status, phase and available updates.
6914
6914
6915 With the --remote option, this will check the default paths for
6915 With the --remote option, this will check the default paths for
6916 incoming and outgoing changes. This can be time-consuming.
6916 incoming and outgoing changes. This can be time-consuming.
6917
6917
6918 Returns 0 on success.
6918 Returns 0 on success.
6919 """
6919 """
6920
6920
6921 opts = pycompat.byteskwargs(opts)
6921 opts = pycompat.byteskwargs(opts)
6922 ui.pager(b'summary')
6922 ui.pager(b'summary')
6923 ctx = repo[None]
6923 ctx = repo[None]
6924 parents = ctx.parents()
6924 parents = ctx.parents()
6925 pnode = parents[0].node()
6925 pnode = parents[0].node()
6926 marks = []
6926 marks = []
6927
6927
6928 try:
6928 try:
6929 ms = mergestatemod.mergestate.read(repo)
6929 ms = mergestatemod.mergestate.read(repo)
6930 except error.UnsupportedMergeRecords as e:
6930 except error.UnsupportedMergeRecords as e:
6931 s = b' '.join(e.recordtypes)
6931 s = b' '.join(e.recordtypes)
6932 ui.warn(
6932 ui.warn(
6933 _(b'warning: merge state has unsupported record types: %s\n') % s
6933 _(b'warning: merge state has unsupported record types: %s\n') % s
6934 )
6934 )
6935 unresolved = []
6935 unresolved = []
6936 else:
6936 else:
6937 unresolved = list(ms.unresolved())
6937 unresolved = list(ms.unresolved())
6938
6938
6939 for p in parents:
6939 for p in parents:
6940 # label with log.changeset (instead of log.parent) since this
6940 # label with log.changeset (instead of log.parent) since this
6941 # shows a working directory parent *changeset*:
6941 # shows a working directory parent *changeset*:
6942 # i18n: column positioning for "hg summary"
6942 # i18n: column positioning for "hg summary"
6943 ui.write(
6943 ui.write(
6944 _(b'parent: %d:%s ') % (p.rev(), p),
6944 _(b'parent: %d:%s ') % (p.rev(), p),
6945 label=logcmdutil.changesetlabels(p),
6945 label=logcmdutil.changesetlabels(p),
6946 )
6946 )
6947 ui.write(b' '.join(p.tags()), label=b'log.tag')
6947 ui.write(b' '.join(p.tags()), label=b'log.tag')
6948 if p.bookmarks():
6948 if p.bookmarks():
6949 marks.extend(p.bookmarks())
6949 marks.extend(p.bookmarks())
6950 if p.rev() == -1:
6950 if p.rev() == -1:
6951 if not len(repo):
6951 if not len(repo):
6952 ui.write(_(b' (empty repository)'))
6952 ui.write(_(b' (empty repository)'))
6953 else:
6953 else:
6954 ui.write(_(b' (no revision checked out)'))
6954 ui.write(_(b' (no revision checked out)'))
6955 if p.obsolete():
6955 if p.obsolete():
6956 ui.write(_(b' (obsolete)'))
6956 ui.write(_(b' (obsolete)'))
6957 if p.isunstable():
6957 if p.isunstable():
6958 instabilities = (
6958 instabilities = (
6959 ui.label(instability, b'trouble.%s' % instability)
6959 ui.label(instability, b'trouble.%s' % instability)
6960 for instability in p.instabilities()
6960 for instability in p.instabilities()
6961 )
6961 )
6962 ui.write(b' (' + b', '.join(instabilities) + b')')
6962 ui.write(b' (' + b', '.join(instabilities) + b')')
6963 ui.write(b'\n')
6963 ui.write(b'\n')
6964 if p.description():
6964 if p.description():
6965 ui.status(
6965 ui.status(
6966 b' ' + p.description().splitlines()[0].strip() + b'\n',
6966 b' ' + p.description().splitlines()[0].strip() + b'\n',
6967 label=b'log.summary',
6967 label=b'log.summary',
6968 )
6968 )
6969
6969
6970 branch = ctx.branch()
6970 branch = ctx.branch()
6971 bheads = repo.branchheads(branch)
6971 bheads = repo.branchheads(branch)
6972 # i18n: column positioning for "hg summary"
6972 # i18n: column positioning for "hg summary"
6973 m = _(b'branch: %s\n') % branch
6973 m = _(b'branch: %s\n') % branch
6974 if branch != b'default':
6974 if branch != b'default':
6975 ui.write(m, label=b'log.branch')
6975 ui.write(m, label=b'log.branch')
6976 else:
6976 else:
6977 ui.status(m, label=b'log.branch')
6977 ui.status(m, label=b'log.branch')
6978
6978
6979 if marks:
6979 if marks:
6980 active = repo._activebookmark
6980 active = repo._activebookmark
6981 # i18n: column positioning for "hg summary"
6981 # i18n: column positioning for "hg summary"
6982 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6982 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6983 if active is not None:
6983 if active is not None:
6984 if active in marks:
6984 if active in marks:
6985 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6985 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6986 marks.remove(active)
6986 marks.remove(active)
6987 else:
6987 else:
6988 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6988 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6989 for m in marks:
6989 for m in marks:
6990 ui.write(b' ' + m, label=b'log.bookmark')
6990 ui.write(b' ' + m, label=b'log.bookmark')
6991 ui.write(b'\n', label=b'log.bookmark')
6991 ui.write(b'\n', label=b'log.bookmark')
6992
6992
6993 status = repo.status(unknown=True)
6993 status = repo.status(unknown=True)
6994
6994
6995 c = repo.dirstate.copies()
6995 c = repo.dirstate.copies()
6996 copied, renamed = [], []
6996 copied, renamed = [], []
6997 for d, s in pycompat.iteritems(c):
6997 for d, s in pycompat.iteritems(c):
6998 if s in status.removed:
6998 if s in status.removed:
6999 status.removed.remove(s)
6999 status.removed.remove(s)
7000 renamed.append(d)
7000 renamed.append(d)
7001 else:
7001 else:
7002 copied.append(d)
7002 copied.append(d)
7003 if d in status.added:
7003 if d in status.added:
7004 status.added.remove(d)
7004 status.added.remove(d)
7005
7005
7006 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7006 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7007
7007
7008 labels = [
7008 labels = [
7009 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7009 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7010 (ui.label(_(b'%d added'), b'status.added'), status.added),
7010 (ui.label(_(b'%d added'), b'status.added'), status.added),
7011 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7011 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7012 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7012 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7013 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7013 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7014 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7014 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7015 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7015 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7016 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7016 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7017 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7017 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7018 ]
7018 ]
7019 t = []
7019 t = []
7020 for l, s in labels:
7020 for l, s in labels:
7021 if s:
7021 if s:
7022 t.append(l % len(s))
7022 t.append(l % len(s))
7023
7023
7024 t = b', '.join(t)
7024 t = b', '.join(t)
7025 cleanworkdir = False
7025 cleanworkdir = False
7026
7026
7027 if repo.vfs.exists(b'graftstate'):
7027 if repo.vfs.exists(b'graftstate'):
7028 t += _(b' (graft in progress)')
7028 t += _(b' (graft in progress)')
7029 if repo.vfs.exists(b'updatestate'):
7029 if repo.vfs.exists(b'updatestate'):
7030 t += _(b' (interrupted update)')
7030 t += _(b' (interrupted update)')
7031 elif len(parents) > 1:
7031 elif len(parents) > 1:
7032 t += _(b' (merge)')
7032 t += _(b' (merge)')
7033 elif branch != parents[0].branch():
7033 elif branch != parents[0].branch():
7034 t += _(b' (new branch)')
7034 t += _(b' (new branch)')
7035 elif parents[0].closesbranch() and pnode in repo.branchheads(
7035 elif parents[0].closesbranch() and pnode in repo.branchheads(
7036 branch, closed=True
7036 branch, closed=True
7037 ):
7037 ):
7038 t += _(b' (head closed)')
7038 t += _(b' (head closed)')
7039 elif not (
7039 elif not (
7040 status.modified
7040 status.modified
7041 or status.added
7041 or status.added
7042 or status.removed
7042 or status.removed
7043 or renamed
7043 or renamed
7044 or copied
7044 or copied
7045 or subs
7045 or subs
7046 ):
7046 ):
7047 t += _(b' (clean)')
7047 t += _(b' (clean)')
7048 cleanworkdir = True
7048 cleanworkdir = True
7049 elif pnode not in bheads:
7049 elif pnode not in bheads:
7050 t += _(b' (new branch head)')
7050 t += _(b' (new branch head)')
7051
7051
7052 if parents:
7052 if parents:
7053 pendingphase = max(p.phase() for p in parents)
7053 pendingphase = max(p.phase() for p in parents)
7054 else:
7054 else:
7055 pendingphase = phases.public
7055 pendingphase = phases.public
7056
7056
7057 if pendingphase > phases.newcommitphase(ui):
7057 if pendingphase > phases.newcommitphase(ui):
7058 t += b' (%s)' % phases.phasenames[pendingphase]
7058 t += b' (%s)' % phases.phasenames[pendingphase]
7059
7059
7060 if cleanworkdir:
7060 if cleanworkdir:
7061 # i18n: column positioning for "hg summary"
7061 # i18n: column positioning for "hg summary"
7062 ui.status(_(b'commit: %s\n') % t.strip())
7062 ui.status(_(b'commit: %s\n') % t.strip())
7063 else:
7063 else:
7064 # i18n: column positioning for "hg summary"
7064 # i18n: column positioning for "hg summary"
7065 ui.write(_(b'commit: %s\n') % t.strip())
7065 ui.write(_(b'commit: %s\n') % t.strip())
7066
7066
7067 # all ancestors of branch heads - all ancestors of parent = new csets
7067 # all ancestors of branch heads - all ancestors of parent = new csets
7068 new = len(
7068 new = len(
7069 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7069 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7070 )
7070 )
7071
7071
7072 if new == 0:
7072 if new == 0:
7073 # i18n: column positioning for "hg summary"
7073 # i18n: column positioning for "hg summary"
7074 ui.status(_(b'update: (current)\n'))
7074 ui.status(_(b'update: (current)\n'))
7075 elif pnode not in bheads:
7075 elif pnode not in bheads:
7076 # i18n: column positioning for "hg summary"
7076 # i18n: column positioning for "hg summary"
7077 ui.write(_(b'update: %d new changesets (update)\n') % new)
7077 ui.write(_(b'update: %d new changesets (update)\n') % new)
7078 else:
7078 else:
7079 # i18n: column positioning for "hg summary"
7079 # i18n: column positioning for "hg summary"
7080 ui.write(
7080 ui.write(
7081 _(b'update: %d new changesets, %d branch heads (merge)\n')
7081 _(b'update: %d new changesets, %d branch heads (merge)\n')
7082 % (new, len(bheads))
7082 % (new, len(bheads))
7083 )
7083 )
7084
7084
7085 t = []
7085 t = []
7086 draft = len(repo.revs(b'draft()'))
7086 draft = len(repo.revs(b'draft()'))
7087 if draft:
7087 if draft:
7088 t.append(_(b'%d draft') % draft)
7088 t.append(_(b'%d draft') % draft)
7089 secret = len(repo.revs(b'secret()'))
7089 secret = len(repo.revs(b'secret()'))
7090 if secret:
7090 if secret:
7091 t.append(_(b'%d secret') % secret)
7091 t.append(_(b'%d secret') % secret)
7092
7092
7093 if draft or secret:
7093 if draft or secret:
7094 ui.status(_(b'phases: %s\n') % b', '.join(t))
7094 ui.status(_(b'phases: %s\n') % b', '.join(t))
7095
7095
7096 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7096 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7097 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7097 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7098 numtrouble = len(repo.revs(trouble + b"()"))
7098 numtrouble = len(repo.revs(trouble + b"()"))
7099 # We write all the possibilities to ease translation
7099 # We write all the possibilities to ease translation
7100 troublemsg = {
7100 troublemsg = {
7101 b"orphan": _(b"orphan: %d changesets"),
7101 b"orphan": _(b"orphan: %d changesets"),
7102 b"contentdivergent": _(b"content-divergent: %d changesets"),
7102 b"contentdivergent": _(b"content-divergent: %d changesets"),
7103 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7103 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7104 }
7104 }
7105 if numtrouble > 0:
7105 if numtrouble > 0:
7106 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7106 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7107
7107
7108 cmdutil.summaryhooks(ui, repo)
7108 cmdutil.summaryhooks(ui, repo)
7109
7109
7110 if opts.get(b'remote'):
7110 if opts.get(b'remote'):
7111 needsincoming, needsoutgoing = True, True
7111 needsincoming, needsoutgoing = True, True
7112 else:
7112 else:
7113 needsincoming, needsoutgoing = False, False
7113 needsincoming, needsoutgoing = False, False
7114 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7114 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7115 if i:
7115 if i:
7116 needsincoming = True
7116 needsincoming = True
7117 if o:
7117 if o:
7118 needsoutgoing = True
7118 needsoutgoing = True
7119 if not needsincoming and not needsoutgoing:
7119 if not needsincoming and not needsoutgoing:
7120 return
7120 return
7121
7121
7122 def getincoming():
7122 def getincoming():
7123 source, branches = hg.parseurl(ui.expandpath(b'default'))
7123 source, branches = hg.parseurl(ui.expandpath(b'default'))
7124 sbranch = branches[0]
7124 sbranch = branches[0]
7125 try:
7125 try:
7126 other = hg.peer(repo, {}, source)
7126 other = hg.peer(repo, {}, source)
7127 except error.RepoError:
7127 except error.RepoError:
7128 if opts.get(b'remote'):
7128 if opts.get(b'remote'):
7129 raise
7129 raise
7130 return source, sbranch, None, None, None
7130 return source, sbranch, None, None, None
7131 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7131 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7132 if revs:
7132 if revs:
7133 revs = [other.lookup(rev) for rev in revs]
7133 revs = [other.lookup(rev) for rev in revs]
7134 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7134 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7135 repo.ui.pushbuffer()
7135 repo.ui.pushbuffer()
7136 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7136 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7137 repo.ui.popbuffer()
7137 repo.ui.popbuffer()
7138 return source, sbranch, other, commoninc, commoninc[1]
7138 return source, sbranch, other, commoninc, commoninc[1]
7139
7139
7140 if needsincoming:
7140 if needsincoming:
7141 source, sbranch, sother, commoninc, incoming = getincoming()
7141 source, sbranch, sother, commoninc, incoming = getincoming()
7142 else:
7142 else:
7143 source = sbranch = sother = commoninc = incoming = None
7143 source = sbranch = sother = commoninc = incoming = None
7144
7144
7145 def getoutgoing():
7145 def getoutgoing():
7146 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7146 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7147 dbranch = branches[0]
7147 dbranch = branches[0]
7148 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7148 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7149 if source != dest:
7149 if source != dest:
7150 try:
7150 try:
7151 dother = hg.peer(repo, {}, dest)
7151 dother = hg.peer(repo, {}, dest)
7152 except error.RepoError:
7152 except error.RepoError:
7153 if opts.get(b'remote'):
7153 if opts.get(b'remote'):
7154 raise
7154 raise
7155 return dest, dbranch, None, None
7155 return dest, dbranch, None, None
7156 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7156 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7157 elif sother is None:
7157 elif sother is None:
7158 # there is no explicit destination peer, but source one is invalid
7158 # there is no explicit destination peer, but source one is invalid
7159 return dest, dbranch, None, None
7159 return dest, dbranch, None, None
7160 else:
7160 else:
7161 dother = sother
7161 dother = sother
7162 if source != dest or (sbranch is not None and sbranch != dbranch):
7162 if source != dest or (sbranch is not None and sbranch != dbranch):
7163 common = None
7163 common = None
7164 else:
7164 else:
7165 common = commoninc
7165 common = commoninc
7166 if revs:
7166 if revs:
7167 revs = [repo.lookup(rev) for rev in revs]
7167 revs = [repo.lookup(rev) for rev in revs]
7168 repo.ui.pushbuffer()
7168 repo.ui.pushbuffer()
7169 outgoing = discovery.findcommonoutgoing(
7169 outgoing = discovery.findcommonoutgoing(
7170 repo, dother, onlyheads=revs, commoninc=common
7170 repo, dother, onlyheads=revs, commoninc=common
7171 )
7171 )
7172 repo.ui.popbuffer()
7172 repo.ui.popbuffer()
7173 return dest, dbranch, dother, outgoing
7173 return dest, dbranch, dother, outgoing
7174
7174
7175 if needsoutgoing:
7175 if needsoutgoing:
7176 dest, dbranch, dother, outgoing = getoutgoing()
7176 dest, dbranch, dother, outgoing = getoutgoing()
7177 else:
7177 else:
7178 dest = dbranch = dother = outgoing = None
7178 dest = dbranch = dother = outgoing = None
7179
7179
7180 if opts.get(b'remote'):
7180 if opts.get(b'remote'):
7181 t = []
7181 t = []
7182 if incoming:
7182 if incoming:
7183 t.append(_(b'1 or more incoming'))
7183 t.append(_(b'1 or more incoming'))
7184 o = outgoing.missing
7184 o = outgoing.missing
7185 if o:
7185 if o:
7186 t.append(_(b'%d outgoing') % len(o))
7186 t.append(_(b'%d outgoing') % len(o))
7187 other = dother or sother
7187 other = dother or sother
7188 if b'bookmarks' in other.listkeys(b'namespaces'):
7188 if b'bookmarks' in other.listkeys(b'namespaces'):
7189 counts = bookmarks.summary(repo, other)
7189 counts = bookmarks.summary(repo, other)
7190 if counts[0] > 0:
7190 if counts[0] > 0:
7191 t.append(_(b'%d incoming bookmarks') % counts[0])
7191 t.append(_(b'%d incoming bookmarks') % counts[0])
7192 if counts[1] > 0:
7192 if counts[1] > 0:
7193 t.append(_(b'%d outgoing bookmarks') % counts[1])
7193 t.append(_(b'%d outgoing bookmarks') % counts[1])
7194
7194
7195 if t:
7195 if t:
7196 # i18n: column positioning for "hg summary"
7196 # i18n: column positioning for "hg summary"
7197 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7197 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7198 else:
7198 else:
7199 # i18n: column positioning for "hg summary"
7199 # i18n: column positioning for "hg summary"
7200 ui.status(_(b'remote: (synced)\n'))
7200 ui.status(_(b'remote: (synced)\n'))
7201
7201
7202 cmdutil.summaryremotehooks(
7202 cmdutil.summaryremotehooks(
7203 ui,
7203 ui,
7204 repo,
7204 repo,
7205 opts,
7205 opts,
7206 (
7206 (
7207 (source, sbranch, sother, commoninc),
7207 (source, sbranch, sother, commoninc),
7208 (dest, dbranch, dother, outgoing),
7208 (dest, dbranch, dother, outgoing),
7209 ),
7209 ),
7210 )
7210 )
7211
7211
7212
7212
7213 @command(
7213 @command(
7214 b'tag',
7214 b'tag',
7215 [
7215 [
7216 (b'f', b'force', None, _(b'force tag')),
7216 (b'f', b'force', None, _(b'force tag')),
7217 (b'l', b'local', None, _(b'make the tag local')),
7217 (b'l', b'local', None, _(b'make the tag local')),
7218 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7218 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7219 (b'', b'remove', None, _(b'remove a tag')),
7219 (b'', b'remove', None, _(b'remove a tag')),
7220 # -l/--local is already there, commitopts cannot be used
7220 # -l/--local is already there, commitopts cannot be used
7221 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7221 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7222 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7222 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7223 ]
7223 ]
7224 + commitopts2,
7224 + commitopts2,
7225 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7225 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7226 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7226 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7227 )
7227 )
7228 def tag(ui, repo, name1, *names, **opts):
7228 def tag(ui, repo, name1, *names, **opts):
7229 """add one or more tags for the current or given revision
7229 """add one or more tags for the current or given revision
7230
7230
7231 Name a particular revision using <name>.
7231 Name a particular revision using <name>.
7232
7232
7233 Tags are used to name particular revisions of the repository and are
7233 Tags are used to name particular revisions of the repository and are
7234 very useful to compare different revisions, to go back to significant
7234 very useful to compare different revisions, to go back to significant
7235 earlier versions or to mark branch points as releases, etc. Changing
7235 earlier versions or to mark branch points as releases, etc. Changing
7236 an existing tag is normally disallowed; use -f/--force to override.
7236 an existing tag is normally disallowed; use -f/--force to override.
7237
7237
7238 If no revision is given, the parent of the working directory is
7238 If no revision is given, the parent of the working directory is
7239 used.
7239 used.
7240
7240
7241 To facilitate version control, distribution, and merging of tags,
7241 To facilitate version control, distribution, and merging of tags,
7242 they are stored as a file named ".hgtags" which is managed similarly
7242 they are stored as a file named ".hgtags" which is managed similarly
7243 to other project files and can be hand-edited if necessary. This
7243 to other project files and can be hand-edited if necessary. This
7244 also means that tagging creates a new commit. The file
7244 also means that tagging creates a new commit. The file
7245 ".hg/localtags" is used for local tags (not shared among
7245 ".hg/localtags" is used for local tags (not shared among
7246 repositories).
7246 repositories).
7247
7247
7248 Tag commits are usually made at the head of a branch. If the parent
7248 Tag commits are usually made at the head of a branch. If the parent
7249 of the working directory is not a branch head, :hg:`tag` aborts; use
7249 of the working directory is not a branch head, :hg:`tag` aborts; use
7250 -f/--force to force the tag commit to be based on a non-head
7250 -f/--force to force the tag commit to be based on a non-head
7251 changeset.
7251 changeset.
7252
7252
7253 See :hg:`help dates` for a list of formats valid for -d/--date.
7253 See :hg:`help dates` for a list of formats valid for -d/--date.
7254
7254
7255 Since tag names have priority over branch names during revision
7255 Since tag names have priority over branch names during revision
7256 lookup, using an existing branch name as a tag name is discouraged.
7256 lookup, using an existing branch name as a tag name is discouraged.
7257
7257
7258 Returns 0 on success.
7258 Returns 0 on success.
7259 """
7259 """
7260 opts = pycompat.byteskwargs(opts)
7260 opts = pycompat.byteskwargs(opts)
7261 with repo.wlock(), repo.lock():
7261 with repo.wlock(), repo.lock():
7262 rev_ = b"."
7262 rev_ = b"."
7263 names = [t.strip() for t in (name1,) + names]
7263 names = [t.strip() for t in (name1,) + names]
7264 if len(names) != len(set(names)):
7264 if len(names) != len(set(names)):
7265 raise error.Abort(_(b'tag names must be unique'))
7265 raise error.Abort(_(b'tag names must be unique'))
7266 for n in names:
7266 for n in names:
7267 scmutil.checknewlabel(repo, n, b'tag')
7267 scmutil.checknewlabel(repo, n, b'tag')
7268 if not n:
7268 if not n:
7269 raise error.Abort(
7269 raise error.Abort(
7270 _(b'tag names cannot consist entirely of whitespace')
7270 _(b'tag names cannot consist entirely of whitespace')
7271 )
7271 )
7272 if opts.get(b'rev') and opts.get(b'remove'):
7272 if opts.get(b'rev') and opts.get(b'remove'):
7273 raise error.Abort(_(b"--rev and --remove are incompatible"))
7273 raise error.Abort(_(b"--rev and --remove are incompatible"))
7274 if opts.get(b'rev'):
7274 if opts.get(b'rev'):
7275 rev_ = opts[b'rev']
7275 rev_ = opts[b'rev']
7276 message = opts.get(b'message')
7276 message = opts.get(b'message')
7277 if opts.get(b'remove'):
7277 if opts.get(b'remove'):
7278 if opts.get(b'local'):
7278 if opts.get(b'local'):
7279 expectedtype = b'local'
7279 expectedtype = b'local'
7280 else:
7280 else:
7281 expectedtype = b'global'
7281 expectedtype = b'global'
7282
7282
7283 for n in names:
7283 for n in names:
7284 if repo.tagtype(n) == b'global':
7284 if repo.tagtype(n) == b'global':
7285 alltags = tagsmod.findglobaltags(ui, repo)
7285 alltags = tagsmod.findglobaltags(ui, repo)
7286 if alltags[n][0] == nullid:
7286 if alltags[n][0] == nullid:
7287 raise error.Abort(_(b"tag '%s' is already removed") % n)
7287 raise error.Abort(_(b"tag '%s' is already removed") % n)
7288 if not repo.tagtype(n):
7288 if not repo.tagtype(n):
7289 raise error.Abort(_(b"tag '%s' does not exist") % n)
7289 raise error.Abort(_(b"tag '%s' does not exist") % n)
7290 if repo.tagtype(n) != expectedtype:
7290 if repo.tagtype(n) != expectedtype:
7291 if expectedtype == b'global':
7291 if expectedtype == b'global':
7292 raise error.Abort(
7292 raise error.Abort(
7293 _(b"tag '%s' is not a global tag") % n
7293 _(b"tag '%s' is not a global tag") % n
7294 )
7294 )
7295 else:
7295 else:
7296 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7296 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7297 rev_ = b'null'
7297 rev_ = b'null'
7298 if not message:
7298 if not message:
7299 # we don't translate commit messages
7299 # we don't translate commit messages
7300 message = b'Removed tag %s' % b', '.join(names)
7300 message = b'Removed tag %s' % b', '.join(names)
7301 elif not opts.get(b'force'):
7301 elif not opts.get(b'force'):
7302 for n in names:
7302 for n in names:
7303 if n in repo.tags():
7303 if n in repo.tags():
7304 raise error.Abort(
7304 raise error.Abort(
7305 _(b"tag '%s' already exists (use -f to force)") % n
7305 _(b"tag '%s' already exists (use -f to force)") % n
7306 )
7306 )
7307 if not opts.get(b'local'):
7307 if not opts.get(b'local'):
7308 p1, p2 = repo.dirstate.parents()
7308 p1, p2 = repo.dirstate.parents()
7309 if p2 != nullid:
7309 if p2 != nullid:
7310 raise error.Abort(_(b'uncommitted merge'))
7310 raise error.Abort(_(b'uncommitted merge'))
7311 bheads = repo.branchheads()
7311 bheads = repo.branchheads()
7312 if not opts.get(b'force') and bheads and p1 not in bheads:
7312 if not opts.get(b'force') and bheads and p1 not in bheads:
7313 raise error.Abort(
7313 raise error.Abort(
7314 _(
7314 _(
7315 b'working directory is not at a branch head '
7315 b'working directory is not at a branch head '
7316 b'(use -f to force)'
7316 b'(use -f to force)'
7317 )
7317 )
7318 )
7318 )
7319 node = scmutil.revsingle(repo, rev_).node()
7319 node = scmutil.revsingle(repo, rev_).node()
7320
7320
7321 if not message:
7321 if not message:
7322 # we don't translate commit messages
7322 # we don't translate commit messages
7323 message = b'Added tag %s for changeset %s' % (
7323 message = b'Added tag %s for changeset %s' % (
7324 b', '.join(names),
7324 b', '.join(names),
7325 short(node),
7325 short(node),
7326 )
7326 )
7327
7327
7328 date = opts.get(b'date')
7328 date = opts.get(b'date')
7329 if date:
7329 if date:
7330 date = dateutil.parsedate(date)
7330 date = dateutil.parsedate(date)
7331
7331
7332 if opts.get(b'remove'):
7332 if opts.get(b'remove'):
7333 editform = b'tag.remove'
7333 editform = b'tag.remove'
7334 else:
7334 else:
7335 editform = b'tag.add'
7335 editform = b'tag.add'
7336 editor = cmdutil.getcommiteditor(
7336 editor = cmdutil.getcommiteditor(
7337 editform=editform, **pycompat.strkwargs(opts)
7337 editform=editform, **pycompat.strkwargs(opts)
7338 )
7338 )
7339
7339
7340 # don't allow tagging the null rev
7340 # don't allow tagging the null rev
7341 if (
7341 if (
7342 not opts.get(b'remove')
7342 not opts.get(b'remove')
7343 and scmutil.revsingle(repo, rev_).rev() == nullrev
7343 and scmutil.revsingle(repo, rev_).rev() == nullrev
7344 ):
7344 ):
7345 raise error.Abort(_(b"cannot tag null revision"))
7345 raise error.Abort(_(b"cannot tag null revision"))
7346
7346
7347 tagsmod.tag(
7347 tagsmod.tag(
7348 repo,
7348 repo,
7349 names,
7349 names,
7350 node,
7350 node,
7351 message,
7351 message,
7352 opts.get(b'local'),
7352 opts.get(b'local'),
7353 opts.get(b'user'),
7353 opts.get(b'user'),
7354 date,
7354 date,
7355 editor=editor,
7355 editor=editor,
7356 )
7356 )
7357
7357
7358
7358
7359 @command(
7359 @command(
7360 b'tags',
7360 b'tags',
7361 formatteropts,
7361 formatteropts,
7362 b'',
7362 b'',
7363 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7363 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7364 intents={INTENT_READONLY},
7364 intents={INTENT_READONLY},
7365 )
7365 )
7366 def tags(ui, repo, **opts):
7366 def tags(ui, repo, **opts):
7367 """list repository tags
7367 """list repository tags
7368
7368
7369 This lists both regular and local tags. When the -v/--verbose
7369 This lists both regular and local tags. When the -v/--verbose
7370 switch is used, a third column "local" is printed for local tags.
7370 switch is used, a third column "local" is printed for local tags.
7371 When the -q/--quiet switch is used, only the tag name is printed.
7371 When the -q/--quiet switch is used, only the tag name is printed.
7372
7372
7373 .. container:: verbose
7373 .. container:: verbose
7374
7374
7375 Template:
7375 Template:
7376
7376
7377 The following keywords are supported in addition to the common template
7377 The following keywords are supported in addition to the common template
7378 keywords and functions such as ``{tag}``. See also
7378 keywords and functions such as ``{tag}``. See also
7379 :hg:`help templates`.
7379 :hg:`help templates`.
7380
7380
7381 :type: String. ``local`` for local tags.
7381 :type: String. ``local`` for local tags.
7382
7382
7383 Returns 0 on success.
7383 Returns 0 on success.
7384 """
7384 """
7385
7385
7386 opts = pycompat.byteskwargs(opts)
7386 opts = pycompat.byteskwargs(opts)
7387 ui.pager(b'tags')
7387 ui.pager(b'tags')
7388 fm = ui.formatter(b'tags', opts)
7388 fm = ui.formatter(b'tags', opts)
7389 hexfunc = fm.hexfunc
7389 hexfunc = fm.hexfunc
7390
7390
7391 for t, n in reversed(repo.tagslist()):
7391 for t, n in reversed(repo.tagslist()):
7392 hn = hexfunc(n)
7392 hn = hexfunc(n)
7393 label = b'tags.normal'
7393 label = b'tags.normal'
7394 tagtype = b''
7394 tagtype = b''
7395 if repo.tagtype(t) == b'local':
7395 if repo.tagtype(t) == b'local':
7396 label = b'tags.local'
7396 label = b'tags.local'
7397 tagtype = b'local'
7397 tagtype = b'local'
7398
7398
7399 fm.startitem()
7399 fm.startitem()
7400 fm.context(repo=repo)
7400 fm.context(repo=repo)
7401 fm.write(b'tag', b'%s', t, label=label)
7401 fm.write(b'tag', b'%s', t, label=label)
7402 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7402 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7403 fm.condwrite(
7403 fm.condwrite(
7404 not ui.quiet,
7404 not ui.quiet,
7405 b'rev node',
7405 b'rev node',
7406 fmt,
7406 fmt,
7407 repo.changelog.rev(n),
7407 repo.changelog.rev(n),
7408 hn,
7408 hn,
7409 label=label,
7409 label=label,
7410 )
7410 )
7411 fm.condwrite(
7411 fm.condwrite(
7412 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7412 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7413 )
7413 )
7414 fm.plain(b'\n')
7414 fm.plain(b'\n')
7415 fm.end()
7415 fm.end()
7416
7416
7417
7417
7418 @command(
7418 @command(
7419 b'tip',
7419 b'tip',
7420 [
7420 [
7421 (b'p', b'patch', None, _(b'show patch')),
7421 (b'p', b'patch', None, _(b'show patch')),
7422 (b'g', b'git', None, _(b'use git extended diff format')),
7422 (b'g', b'git', None, _(b'use git extended diff format')),
7423 ]
7423 ]
7424 + templateopts,
7424 + templateopts,
7425 _(b'[-p] [-g]'),
7425 _(b'[-p] [-g]'),
7426 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7426 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7427 )
7427 )
7428 def tip(ui, repo, **opts):
7428 def tip(ui, repo, **opts):
7429 """show the tip revision (DEPRECATED)
7429 """show the tip revision (DEPRECATED)
7430
7430
7431 The tip revision (usually just called the tip) is the changeset
7431 The tip revision (usually just called the tip) is the changeset
7432 most recently added to the repository (and therefore the most
7432 most recently added to the repository (and therefore the most
7433 recently changed head).
7433 recently changed head).
7434
7434
7435 If you have just made a commit, that commit will be the tip. If
7435 If you have just made a commit, that commit will be the tip. If
7436 you have just pulled changes from another repository, the tip of
7436 you have just pulled changes from another repository, the tip of
7437 that repository becomes the current tip. The "tip" tag is special
7437 that repository becomes the current tip. The "tip" tag is special
7438 and cannot be renamed or assigned to a different changeset.
7438 and cannot be renamed or assigned to a different changeset.
7439
7439
7440 This command is deprecated, please use :hg:`heads` instead.
7440 This command is deprecated, please use :hg:`heads` instead.
7441
7441
7442 Returns 0 on success.
7442 Returns 0 on success.
7443 """
7443 """
7444 opts = pycompat.byteskwargs(opts)
7444 opts = pycompat.byteskwargs(opts)
7445 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7445 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7446 displayer.show(repo[b'tip'])
7446 displayer.show(repo[b'tip'])
7447 displayer.close()
7447 displayer.close()
7448
7448
7449
7449
7450 @command(
7450 @command(
7451 b'unbundle',
7451 b'unbundle',
7452 [
7452 [
7453 (
7453 (
7454 b'u',
7454 b'u',
7455 b'update',
7455 b'update',
7456 None,
7456 None,
7457 _(b'update to new branch head if changesets were unbundled'),
7457 _(b'update to new branch head if changesets were unbundled'),
7458 )
7458 )
7459 ],
7459 ],
7460 _(b'[-u] FILE...'),
7460 _(b'[-u] FILE...'),
7461 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7461 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7462 )
7462 )
7463 def unbundle(ui, repo, fname1, *fnames, **opts):
7463 def unbundle(ui, repo, fname1, *fnames, **opts):
7464 """apply one or more bundle files
7464 """apply one or more bundle files
7465
7465
7466 Apply one or more bundle files generated by :hg:`bundle`.
7466 Apply one or more bundle files generated by :hg:`bundle`.
7467
7467
7468 Returns 0 on success, 1 if an update has unresolved files.
7468 Returns 0 on success, 1 if an update has unresolved files.
7469 """
7469 """
7470 fnames = (fname1,) + fnames
7470 fnames = (fname1,) + fnames
7471
7471
7472 with repo.lock():
7472 with repo.lock():
7473 for fname in fnames:
7473 for fname in fnames:
7474 f = hg.openpath(ui, fname)
7474 f = hg.openpath(ui, fname)
7475 gen = exchange.readbundle(ui, f, fname)
7475 gen = exchange.readbundle(ui, f, fname)
7476 if isinstance(gen, streamclone.streamcloneapplier):
7476 if isinstance(gen, streamclone.streamcloneapplier):
7477 raise error.Abort(
7477 raise error.Abort(
7478 _(
7478 _(
7479 b'packed bundles cannot be applied with '
7479 b'packed bundles cannot be applied with '
7480 b'"hg unbundle"'
7480 b'"hg unbundle"'
7481 ),
7481 ),
7482 hint=_(b'use "hg debugapplystreamclonebundle"'),
7482 hint=_(b'use "hg debugapplystreamclonebundle"'),
7483 )
7483 )
7484 url = b'bundle:' + fname
7484 url = b'bundle:' + fname
7485 try:
7485 try:
7486 txnname = b'unbundle'
7486 txnname = b'unbundle'
7487 if not isinstance(gen, bundle2.unbundle20):
7487 if not isinstance(gen, bundle2.unbundle20):
7488 txnname = b'unbundle\n%s' % util.hidepassword(url)
7488 txnname = b'unbundle\n%s' % util.hidepassword(url)
7489 with repo.transaction(txnname) as tr:
7489 with repo.transaction(txnname) as tr:
7490 op = bundle2.applybundle(
7490 op = bundle2.applybundle(
7491 repo, gen, tr, source=b'unbundle', url=url
7491 repo, gen, tr, source=b'unbundle', url=url
7492 )
7492 )
7493 except error.BundleUnknownFeatureError as exc:
7493 except error.BundleUnknownFeatureError as exc:
7494 raise error.Abort(
7494 raise error.Abort(
7495 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7495 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7496 hint=_(
7496 hint=_(
7497 b"see https://mercurial-scm.org/"
7497 b"see https://mercurial-scm.org/"
7498 b"wiki/BundleFeature for more "
7498 b"wiki/BundleFeature for more "
7499 b"information"
7499 b"information"
7500 ),
7500 ),
7501 )
7501 )
7502 modheads = bundle2.combinechangegroupresults(op)
7502 modheads = bundle2.combinechangegroupresults(op)
7503
7503
7504 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7504 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7505
7505
7506
7506
7507 @command(
7507 @command(
7508 b'unshelve',
7508 b'unshelve',
7509 [
7509 [
7510 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7510 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7511 (
7511 (
7512 b'c',
7512 b'c',
7513 b'continue',
7513 b'continue',
7514 None,
7514 None,
7515 _(b'continue an incomplete unshelve operation'),
7515 _(b'continue an incomplete unshelve operation'),
7516 ),
7516 ),
7517 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7517 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7518 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7518 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7519 (
7519 (
7520 b'n',
7520 b'n',
7521 b'name',
7521 b'name',
7522 b'',
7522 b'',
7523 _(b'restore shelved change with given name'),
7523 _(b'restore shelved change with given name'),
7524 _(b'NAME'),
7524 _(b'NAME'),
7525 ),
7525 ),
7526 (b't', b'tool', b'', _(b'specify merge tool')),
7526 (b't', b'tool', b'', _(b'specify merge tool')),
7527 (
7527 (
7528 b'',
7528 b'',
7529 b'date',
7529 b'date',
7530 b'',
7530 b'',
7531 _(b'set date for temporary commits (DEPRECATED)'),
7531 _(b'set date for temporary commits (DEPRECATED)'),
7532 _(b'DATE'),
7532 _(b'DATE'),
7533 ),
7533 ),
7534 ],
7534 ],
7535 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7535 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7536 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7536 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7537 )
7537 )
7538 def unshelve(ui, repo, *shelved, **opts):
7538 def unshelve(ui, repo, *shelved, **opts):
7539 """restore a shelved change to the working directory
7539 """restore a shelved change to the working directory
7540
7540
7541 This command accepts an optional name of a shelved change to
7541 This command accepts an optional name of a shelved change to
7542 restore. If none is given, the most recent shelved change is used.
7542 restore. If none is given, the most recent shelved change is used.
7543
7543
7544 If a shelved change is applied successfully, the bundle that
7544 If a shelved change is applied successfully, the bundle that
7545 contains the shelved changes is moved to a backup location
7545 contains the shelved changes is moved to a backup location
7546 (.hg/shelve-backup).
7546 (.hg/shelve-backup).
7547
7547
7548 Since you can restore a shelved change on top of an arbitrary
7548 Since you can restore a shelved change on top of an arbitrary
7549 commit, it is possible that unshelving will result in a conflict
7549 commit, it is possible that unshelving will result in a conflict
7550 between your changes and the commits you are unshelving onto. If
7550 between your changes and the commits you are unshelving onto. If
7551 this occurs, you must resolve the conflict, then use
7551 this occurs, you must resolve the conflict, then use
7552 ``--continue`` to complete the unshelve operation. (The bundle
7552 ``--continue`` to complete the unshelve operation. (The bundle
7553 will not be moved until you successfully complete the unshelve.)
7553 will not be moved until you successfully complete the unshelve.)
7554
7554
7555 (Alternatively, you can use ``--abort`` to abandon an unshelve
7555 (Alternatively, you can use ``--abort`` to abandon an unshelve
7556 that causes a conflict. This reverts the unshelved changes, and
7556 that causes a conflict. This reverts the unshelved changes, and
7557 leaves the bundle in place.)
7557 leaves the bundle in place.)
7558
7558
7559 If bare shelved change (without interactive, include and exclude
7559 If bare shelved change (without interactive, include and exclude
7560 option) was done on newly created branch it would restore branch
7560 option) was done on newly created branch it would restore branch
7561 information to the working directory.
7561 information to the working directory.
7562
7562
7563 After a successful unshelve, the shelved changes are stored in a
7563 After a successful unshelve, the shelved changes are stored in a
7564 backup directory. Only the N most recent backups are kept. N
7564 backup directory. Only the N most recent backups are kept. N
7565 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7565 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7566 configuration option.
7566 configuration option.
7567
7567
7568 .. container:: verbose
7568 .. container:: verbose
7569
7569
7570 Timestamp in seconds is used to decide order of backups. More
7570 Timestamp in seconds is used to decide order of backups. More
7571 than ``maxbackups`` backups are kept, if same timestamp
7571 than ``maxbackups`` backups are kept, if same timestamp
7572 prevents from deciding exact order of them, for safety.
7572 prevents from deciding exact order of them, for safety.
7573
7573
7574 Selected changes can be unshelved with ``--interactive`` flag.
7574 Selected changes can be unshelved with ``--interactive`` flag.
7575 The working directory is updated with the selected changes, and
7575 The working directory is updated with the selected changes, and
7576 only the unselected changes remain shelved.
7576 only the unselected changes remain shelved.
7577 Note: The whole shelve is applied to working directory first before
7577 Note: The whole shelve is applied to working directory first before
7578 running interactively. So, this will bring up all the conflicts between
7578 running interactively. So, this will bring up all the conflicts between
7579 working directory and the shelve, irrespective of which changes will be
7579 working directory and the shelve, irrespective of which changes will be
7580 unshelved.
7580 unshelved.
7581 """
7581 """
7582 with repo.wlock():
7582 with repo.wlock():
7583 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7583 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7584
7584
7585
7585
7586 statemod.addunfinished(
7586 statemod.addunfinished(
7587 b'unshelve',
7587 b'unshelve',
7588 fname=b'shelvedstate',
7588 fname=b'shelvedstate',
7589 continueflag=True,
7589 continueflag=True,
7590 abortfunc=shelvemod.hgabortunshelve,
7590 abortfunc=shelvemod.hgabortunshelve,
7591 continuefunc=shelvemod.hgcontinueunshelve,
7591 continuefunc=shelvemod.hgcontinueunshelve,
7592 cmdmsg=_(b'unshelve already in progress'),
7592 cmdmsg=_(b'unshelve already in progress'),
7593 )
7593 )
7594
7594
7595
7595
7596 @command(
7596 @command(
7597 b'update|up|checkout|co',
7597 b'update|up|checkout|co',
7598 [
7598 [
7599 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7599 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7600 (b'c', b'check', None, _(b'require clean working directory')),
7600 (b'c', b'check', None, _(b'require clean working directory')),
7601 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7601 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7602 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7602 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7603 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7603 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7604 ]
7604 ]
7605 + mergetoolopts,
7605 + mergetoolopts,
7606 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7606 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7607 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7607 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7608 helpbasic=True,
7608 helpbasic=True,
7609 )
7609 )
7610 def update(ui, repo, node=None, **opts):
7610 def update(ui, repo, node=None, **opts):
7611 """update working directory (or switch revisions)
7611 """update working directory (or switch revisions)
7612
7612
7613 Update the repository's working directory to the specified
7613 Update the repository's working directory to the specified
7614 changeset. If no changeset is specified, update to the tip of the
7614 changeset. If no changeset is specified, update to the tip of the
7615 current named branch and move the active bookmark (see :hg:`help
7615 current named branch and move the active bookmark (see :hg:`help
7616 bookmarks`).
7616 bookmarks`).
7617
7617
7618 Update sets the working directory's parent revision to the specified
7618 Update sets the working directory's parent revision to the specified
7619 changeset (see :hg:`help parents`).
7619 changeset (see :hg:`help parents`).
7620
7620
7621 If the changeset is not a descendant or ancestor of the working
7621 If the changeset is not a descendant or ancestor of the working
7622 directory's parent and there are uncommitted changes, the update is
7622 directory's parent and there are uncommitted changes, the update is
7623 aborted. With the -c/--check option, the working directory is checked
7623 aborted. With the -c/--check option, the working directory is checked
7624 for uncommitted changes; if none are found, the working directory is
7624 for uncommitted changes; if none are found, the working directory is
7625 updated to the specified changeset.
7625 updated to the specified changeset.
7626
7626
7627 .. container:: verbose
7627 .. container:: verbose
7628
7628
7629 The -C/--clean, -c/--check, and -m/--merge options control what
7629 The -C/--clean, -c/--check, and -m/--merge options control what
7630 happens if the working directory contains uncommitted changes.
7630 happens if the working directory contains uncommitted changes.
7631 At most of one of them can be specified.
7631 At most of one of them can be specified.
7632
7632
7633 1. If no option is specified, and if
7633 1. If no option is specified, and if
7634 the requested changeset is an ancestor or descendant of
7634 the requested changeset is an ancestor or descendant of
7635 the working directory's parent, the uncommitted changes
7635 the working directory's parent, the uncommitted changes
7636 are merged into the requested changeset and the merged
7636 are merged into the requested changeset and the merged
7637 result is left uncommitted. If the requested changeset is
7637 result is left uncommitted. If the requested changeset is
7638 not an ancestor or descendant (that is, it is on another
7638 not an ancestor or descendant (that is, it is on another
7639 branch), the update is aborted and the uncommitted changes
7639 branch), the update is aborted and the uncommitted changes
7640 are preserved.
7640 are preserved.
7641
7641
7642 2. With the -m/--merge option, the update is allowed even if the
7642 2. With the -m/--merge option, the update is allowed even if the
7643 requested changeset is not an ancestor or descendant of
7643 requested changeset is not an ancestor or descendant of
7644 the working directory's parent.
7644 the working directory's parent.
7645
7645
7646 3. With the -c/--check option, the update is aborted and the
7646 3. With the -c/--check option, the update is aborted and the
7647 uncommitted changes are preserved.
7647 uncommitted changes are preserved.
7648
7648
7649 4. With the -C/--clean option, uncommitted changes are discarded and
7649 4. With the -C/--clean option, uncommitted changes are discarded and
7650 the working directory is updated to the requested changeset.
7650 the working directory is updated to the requested changeset.
7651
7651
7652 To cancel an uncommitted merge (and lose your changes), use
7652 To cancel an uncommitted merge (and lose your changes), use
7653 :hg:`merge --abort`.
7653 :hg:`merge --abort`.
7654
7654
7655 Use null as the changeset to remove the working directory (like
7655 Use null as the changeset to remove the working directory (like
7656 :hg:`clone -U`).
7656 :hg:`clone -U`).
7657
7657
7658 If you want to revert just one file to an older revision, use
7658 If you want to revert just one file to an older revision, use
7659 :hg:`revert [-r REV] NAME`.
7659 :hg:`revert [-r REV] NAME`.
7660
7660
7661 See :hg:`help dates` for a list of formats valid for -d/--date.
7661 See :hg:`help dates` for a list of formats valid for -d/--date.
7662
7662
7663 Returns 0 on success, 1 if there are unresolved files.
7663 Returns 0 on success, 1 if there are unresolved files.
7664 """
7664 """
7665 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7665 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7666 rev = opts.get('rev')
7666 rev = opts.get('rev')
7667 date = opts.get('date')
7667 date = opts.get('date')
7668 clean = opts.get('clean')
7668 clean = opts.get('clean')
7669 check = opts.get('check')
7669 check = opts.get('check')
7670 merge = opts.get('merge')
7670 merge = opts.get('merge')
7671 if rev and node:
7671 if rev and node:
7672 raise error.Abort(_(b"please specify just one revision"))
7672 raise error.Abort(_(b"please specify just one revision"))
7673
7673
7674 if ui.configbool(b'commands', b'update.requiredest'):
7674 if ui.configbool(b'commands', b'update.requiredest'):
7675 if not node and not rev and not date:
7675 if not node and not rev and not date:
7676 raise error.Abort(
7676 raise error.Abort(
7677 _(b'you must specify a destination'),
7677 _(b'you must specify a destination'),
7678 hint=_(b'for example: hg update ".::"'),
7678 hint=_(b'for example: hg update ".::"'),
7679 )
7679 )
7680
7680
7681 if rev is None or rev == b'':
7681 if rev is None or rev == b'':
7682 rev = node
7682 rev = node
7683
7683
7684 if date and rev is not None:
7684 if date and rev is not None:
7685 raise error.Abort(_(b"you can't specify a revision and a date"))
7685 raise error.Abort(_(b"you can't specify a revision and a date"))
7686
7686
7687 updatecheck = None
7687 updatecheck = None
7688 if check:
7688 if check:
7689 updatecheck = b'abort'
7689 updatecheck = b'abort'
7690 elif merge:
7690 elif merge:
7691 updatecheck = b'none'
7691 updatecheck = b'none'
7692
7692
7693 with repo.wlock():
7693 with repo.wlock():
7694 cmdutil.clearunfinished(repo)
7694 cmdutil.clearunfinished(repo)
7695 if date:
7695 if date:
7696 rev = cmdutil.finddate(ui, repo, date)
7696 rev = cmdutil.finddate(ui, repo, date)
7697
7697
7698 # if we defined a bookmark, we have to remember the original name
7698 # if we defined a bookmark, we have to remember the original name
7699 brev = rev
7699 brev = rev
7700 if rev:
7700 if rev:
7701 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7701 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7702 ctx = scmutil.revsingle(repo, rev, default=None)
7702 ctx = scmutil.revsingle(repo, rev, default=None)
7703 rev = ctx.rev()
7703 rev = ctx.rev()
7704 hidden = ctx.hidden()
7704 hidden = ctx.hidden()
7705 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7705 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7706 with ui.configoverride(overrides, b'update'):
7706 with ui.configoverride(overrides, b'update'):
7707 ret = hg.updatetotally(
7707 ret = hg.updatetotally(
7708 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7708 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7709 )
7709 )
7710 if hidden:
7710 if hidden:
7711 ctxstr = ctx.hex()[:12]
7711 ctxstr = ctx.hex()[:12]
7712 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7712 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7713
7713
7714 if ctx.obsolete():
7714 if ctx.obsolete():
7715 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7715 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7716 ui.warn(b"(%s)\n" % obsfatemsg)
7716 ui.warn(b"(%s)\n" % obsfatemsg)
7717 return ret
7717 return ret
7718
7718
7719
7719
7720 @command(
7720 @command(
7721 b'verify',
7721 b'verify',
7722 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7722 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7723 helpcategory=command.CATEGORY_MAINTENANCE,
7723 helpcategory=command.CATEGORY_MAINTENANCE,
7724 )
7724 )
7725 def verify(ui, repo, **opts):
7725 def verify(ui, repo, **opts):
7726 """verify the integrity of the repository
7726 """verify the integrity of the repository
7727
7727
7728 Verify the integrity of the current repository.
7728 Verify the integrity of the current repository.
7729
7729
7730 This will perform an extensive check of the repository's
7730 This will perform an extensive check of the repository's
7731 integrity, validating the hashes and checksums of each entry in
7731 integrity, validating the hashes and checksums of each entry in
7732 the changelog, manifest, and tracked files, as well as the
7732 the changelog, manifest, and tracked files, as well as the
7733 integrity of their crosslinks and indices.
7733 integrity of their crosslinks and indices.
7734
7734
7735 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7735 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7736 for more information about recovery from corruption of the
7736 for more information about recovery from corruption of the
7737 repository.
7737 repository.
7738
7738
7739 Returns 0 on success, 1 if errors are encountered.
7739 Returns 0 on success, 1 if errors are encountered.
7740 """
7740 """
7741 opts = pycompat.byteskwargs(opts)
7741 opts = pycompat.byteskwargs(opts)
7742
7742
7743 level = None
7743 level = None
7744 if opts[b'full']:
7744 if opts[b'full']:
7745 level = verifymod.VERIFY_FULL
7745 level = verifymod.VERIFY_FULL
7746 return hg.verify(repo, level)
7746 return hg.verify(repo, level)
7747
7747
7748
7748
7749 @command(
7749 @command(
7750 b'version',
7750 b'version',
7751 [] + formatteropts,
7751 [] + formatteropts,
7752 helpcategory=command.CATEGORY_HELP,
7752 helpcategory=command.CATEGORY_HELP,
7753 norepo=True,
7753 norepo=True,
7754 intents={INTENT_READONLY},
7754 intents={INTENT_READONLY},
7755 )
7755 )
7756 def version_(ui, **opts):
7756 def version_(ui, **opts):
7757 """output version and copyright information
7757 """output version and copyright information
7758
7758
7759 .. container:: verbose
7759 .. container:: verbose
7760
7760
7761 Template:
7761 Template:
7762
7762
7763 The following keywords are supported. See also :hg:`help templates`.
7763 The following keywords are supported. See also :hg:`help templates`.
7764
7764
7765 :extensions: List of extensions.
7765 :extensions: List of extensions.
7766 :ver: String. Version number.
7766 :ver: String. Version number.
7767
7767
7768 And each entry of ``{extensions}`` provides the following sub-keywords
7768 And each entry of ``{extensions}`` provides the following sub-keywords
7769 in addition to ``{ver}``.
7769 in addition to ``{ver}``.
7770
7770
7771 :bundled: Boolean. True if included in the release.
7771 :bundled: Boolean. True if included in the release.
7772 :name: String. Extension name.
7772 :name: String. Extension name.
7773 """
7773 """
7774 opts = pycompat.byteskwargs(opts)
7774 opts = pycompat.byteskwargs(opts)
7775 if ui.verbose:
7775 if ui.verbose:
7776 ui.pager(b'version')
7776 ui.pager(b'version')
7777 fm = ui.formatter(b"version", opts)
7777 fm = ui.formatter(b"version", opts)
7778 fm.startitem()
7778 fm.startitem()
7779 fm.write(
7779 fm.write(
7780 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7780 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7781 )
7781 )
7782 license = _(
7782 license = _(
7783 b"(see https://mercurial-scm.org for more information)\n"
7783 b"(see https://mercurial-scm.org for more information)\n"
7784 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7784 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7785 b"This is free software; see the source for copying conditions. "
7785 b"This is free software; see the source for copying conditions. "
7786 b"There is NO\nwarranty; "
7786 b"There is NO\nwarranty; "
7787 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7787 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7788 )
7788 )
7789 if not ui.quiet:
7789 if not ui.quiet:
7790 fm.plain(license)
7790 fm.plain(license)
7791
7791
7792 if ui.verbose:
7792 if ui.verbose:
7793 fm.plain(_(b"\nEnabled extensions:\n\n"))
7793 fm.plain(_(b"\nEnabled extensions:\n\n"))
7794 # format names and versions into columns
7794 # format names and versions into columns
7795 names = []
7795 names = []
7796 vers = []
7796 vers = []
7797 isinternals = []
7797 isinternals = []
7798 for name, module in sorted(extensions.extensions()):
7798 for name, module in sorted(extensions.extensions()):
7799 names.append(name)
7799 names.append(name)
7800 vers.append(extensions.moduleversion(module) or None)
7800 vers.append(extensions.moduleversion(module) or None)
7801 isinternals.append(extensions.ismoduleinternal(module))
7801 isinternals.append(extensions.ismoduleinternal(module))
7802 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7802 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7803 if names:
7803 if names:
7804 namefmt = b" %%-%ds " % max(len(n) for n in names)
7804 namefmt = b" %%-%ds " % max(len(n) for n in names)
7805 places = [_(b"external"), _(b"internal")]
7805 places = [_(b"external"), _(b"internal")]
7806 for n, v, p in zip(names, vers, isinternals):
7806 for n, v, p in zip(names, vers, isinternals):
7807 fn.startitem()
7807 fn.startitem()
7808 fn.condwrite(ui.verbose, b"name", namefmt, n)
7808 fn.condwrite(ui.verbose, b"name", namefmt, n)
7809 if ui.verbose:
7809 if ui.verbose:
7810 fn.plain(b"%s " % places[p])
7810 fn.plain(b"%s " % places[p])
7811 fn.data(bundled=p)
7811 fn.data(bundled=p)
7812 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7812 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7813 if ui.verbose:
7813 if ui.verbose:
7814 fn.plain(b"\n")
7814 fn.plain(b"\n")
7815 fn.end()
7815 fn.end()
7816 fm.end()
7816 fm.end()
7817
7817
7818
7818
7819 def loadcmdtable(ui, name, cmdtable):
7819 def loadcmdtable(ui, name, cmdtable):
7820 """Load command functions from specified cmdtable
7820 """Load command functions from specified cmdtable
7821 """
7821 """
7822 overrides = [cmd for cmd in cmdtable if cmd in table]
7822 overrides = [cmd for cmd in cmdtable if cmd in table]
7823 if overrides:
7823 if overrides:
7824 ui.warn(
7824 ui.warn(
7825 _(b"extension '%s' overrides commands: %s\n")
7825 _(b"extension '%s' overrides commands: %s\n")
7826 % (name, b" ".join(overrides))
7826 % (name, b" ".join(overrides))
7827 )
7827 )
7828 table.update(cmdtable)
7828 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now