##// END OF EJS Templates
grep: move getbody() to grepsearcher class
Yuya Nishihara -
r46290:41e0cbcc default
parent child Browse files
Show More
@@ -1,7773 +1,7763 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 copies,
31 copies,
32 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 discovery,
35 discovery,
36 encoding,
36 encoding,
37 error,
37 error,
38 exchange,
38 exchange,
39 extensions,
39 extensions,
40 filemerge,
40 filemerge,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 grep as grepmod,
43 grep as grepmod,
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 searcher = grepmod.grepsearcher(ui, repo, regexp)
3401 searcher = grepmod.grepsearcher(ui, repo, regexp)
3402
3402
3403 getfile = searcher._getfile
3403 getfile = searcher._getfile
3404 matches = searcher._matches
3404 matches = searcher._matches
3405 copies = searcher._copies
3405 copies = searcher._copies
3406
3406
3407 def grepbody(fn, rev, body):
3408 matches[rev].setdefault(fn, [])
3409 m = matches[rev][fn]
3410 if body is None:
3411 return
3412
3413 for lnum, cstart, cend, line in grepmod.matchlines(body, regexp):
3414 s = grepmod.linestate(line, lnum, cstart, cend)
3415 m.append(s)
3416
3417 uipathfn = scmutil.getuipathfn(repo)
3407 uipathfn = scmutil.getuipathfn(repo)
3418
3408
3419 def display(fm, fn, ctx, pstates, states):
3409 def display(fm, fn, ctx, pstates, states):
3420 rev = scmutil.intrev(ctx)
3410 rev = scmutil.intrev(ctx)
3421 if fm.isplain():
3411 if fm.isplain():
3422 formatuser = ui.shortuser
3412 formatuser = ui.shortuser
3423 else:
3413 else:
3424 formatuser = pycompat.bytestr
3414 formatuser = pycompat.bytestr
3425 if ui.quiet:
3415 if ui.quiet:
3426 datefmt = b'%Y-%m-%d'
3416 datefmt = b'%Y-%m-%d'
3427 else:
3417 else:
3428 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3429 found = False
3419 found = False
3430
3420
3431 @util.cachefunc
3421 @util.cachefunc
3432 def binary():
3422 def binary():
3433 flog = getfile(fn)
3423 flog = getfile(fn)
3434 try:
3424 try:
3435 return stringutil.binary(flog.read(ctx.filenode(fn)))
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3436 except error.WdirUnsupported:
3426 except error.WdirUnsupported:
3437 return ctx[fn].isbinary()
3427 return ctx[fn].isbinary()
3438
3428
3439 fieldnamemap = {b'linenumber': b'lineno'}
3429 fieldnamemap = {b'linenumber': b'lineno'}
3440 if diff:
3430 if diff:
3441 iter = grepmod.difflinestates(pstates, states)
3431 iter = grepmod.difflinestates(pstates, states)
3442 else:
3432 else:
3443 iter = [(b'', l) for l in states]
3433 iter = [(b'', l) for l in states]
3444 for change, l in iter:
3434 for change, l in iter:
3445 fm.startitem()
3435 fm.startitem()
3446 fm.context(ctx=ctx)
3436 fm.context(ctx=ctx)
3447 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3448 fm.plain(uipathfn(fn), label=b'grep.filename')
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3449
3439
3450 cols = [
3440 cols = [
3451 (b'rev', b'%d', rev, not plaingrep, b''),
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3452 (
3442 (
3453 b'linenumber',
3443 b'linenumber',
3454 b'%d',
3444 b'%d',
3455 l.linenum,
3445 l.linenum,
3456 opts.get(b'line_number'),
3446 opts.get(b'line_number'),
3457 b'',
3447 b'',
3458 ),
3448 ),
3459 ]
3449 ]
3460 if diff:
3450 if diff:
3461 cols.append(
3451 cols.append(
3462 (
3452 (
3463 b'change',
3453 b'change',
3464 b'%s',
3454 b'%s',
3465 change,
3455 change,
3466 True,
3456 True,
3467 b'grep.inserted '
3457 b'grep.inserted '
3468 if change == b'+'
3458 if change == b'+'
3469 else b'grep.deleted ',
3459 else b'grep.deleted ',
3470 )
3460 )
3471 )
3461 )
3472 cols.extend(
3462 cols.extend(
3473 [
3463 [
3474 (
3464 (
3475 b'user',
3465 b'user',
3476 b'%s',
3466 b'%s',
3477 formatuser(ctx.user()),
3467 formatuser(ctx.user()),
3478 opts.get(b'user'),
3468 opts.get(b'user'),
3479 b'',
3469 b'',
3480 ),
3470 ),
3481 (
3471 (
3482 b'date',
3472 b'date',
3483 b'%s',
3473 b'%s',
3484 fm.formatdate(ctx.date(), datefmt),
3474 fm.formatdate(ctx.date(), datefmt),
3485 opts.get(b'date'),
3475 opts.get(b'date'),
3486 b'',
3476 b'',
3487 ),
3477 ),
3488 ]
3478 ]
3489 )
3479 )
3490 for name, fmt, data, cond, extra_label in cols:
3480 for name, fmt, data, cond, extra_label in cols:
3491 if cond:
3481 if cond:
3492 fm.plain(sep, label=b'grep.sep')
3482 fm.plain(sep, label=b'grep.sep')
3493 field = fieldnamemap.get(name, name)
3483 field = fieldnamemap.get(name, name)
3494 label = extra_label + (b'grep.%s' % name)
3484 label = extra_label + (b'grep.%s' % name)
3495 fm.condwrite(cond, field, fmt, data, label=label)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3496 if not opts.get(b'files_with_matches'):
3486 if not opts.get(b'files_with_matches'):
3497 fm.plain(sep, label=b'grep.sep')
3487 fm.plain(sep, label=b'grep.sep')
3498 if not opts.get(b'text') and binary():
3488 if not opts.get(b'text') and binary():
3499 fm.plain(_(b" Binary file matches"))
3489 fm.plain(_(b" Binary file matches"))
3500 else:
3490 else:
3501 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3502 fm.plain(eol)
3492 fm.plain(eol)
3503 found = True
3493 found = True
3504 if opts.get(b'files_with_matches'):
3494 if opts.get(b'files_with_matches'):
3505 break
3495 break
3506 return found
3496 return found
3507
3497
3508 def displaymatches(fm, l):
3498 def displaymatches(fm, l):
3509 p = 0
3499 p = 0
3510 for s, e in l.findpos(regexp):
3500 for s, e in l.findpos(regexp):
3511 if p < s:
3501 if p < s:
3512 fm.startitem()
3502 fm.startitem()
3513 fm.write(b'text', b'%s', l.line[p:s])
3503 fm.write(b'text', b'%s', l.line[p:s])
3514 fm.data(matched=False)
3504 fm.data(matched=False)
3515 fm.startitem()
3505 fm.startitem()
3516 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3517 fm.data(matched=True)
3507 fm.data(matched=True)
3518 p = e
3508 p = e
3519 if p < len(l.line):
3509 if p < len(l.line):
3520 fm.startitem()
3510 fm.startitem()
3521 fm.write(b'text', b'%s', l.line[p:])
3511 fm.write(b'text', b'%s', l.line[p:])
3522 fm.data(matched=False)
3512 fm.data(matched=False)
3523 fm.end()
3513 fm.end()
3524
3514
3525 skip = searcher._skip
3515 skip = searcher._skip
3526 revfiles = searcher._revfiles
3516 revfiles = searcher._revfiles
3527 found = False
3517 found = False
3528 follow = opts.get(b'follow')
3518 follow = opts.get(b'follow')
3529
3519
3530 getrenamed = searcher._getrenamed
3520 getrenamed = searcher._getrenamed
3531
3521
3532 def readfile(ctx, fn):
3522 def readfile(ctx, fn):
3533 rev = ctx.rev()
3523 rev = ctx.rev()
3534 if rev is None:
3524 if rev is None:
3535 fctx = ctx[fn]
3525 fctx = ctx[fn]
3536 try:
3526 try:
3537 return fctx.data()
3527 return fctx.data()
3538 except IOError as e:
3528 except IOError as e:
3539 if e.errno != errno.ENOENT:
3529 if e.errno != errno.ENOENT:
3540 raise
3530 raise
3541 else:
3531 else:
3542 flog = getfile(fn)
3532 flog = getfile(fn)
3543 fnode = ctx.filenode(fn)
3533 fnode = ctx.filenode(fn)
3544 try:
3534 try:
3545 return flog.read(fnode)
3535 return flog.read(fnode)
3546 except error.CensoredNodeError:
3536 except error.CensoredNodeError:
3547 ui.warn(
3537 ui.warn(
3548 _(
3538 _(
3549 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3539 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3550 )
3540 )
3551 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3541 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3552 )
3542 )
3553
3543
3554 def prep(ctx, fmatch):
3544 def prep(ctx, fmatch):
3555 rev = ctx.rev()
3545 rev = ctx.rev()
3556 pctx = ctx.p1()
3546 pctx = ctx.p1()
3557 matches.setdefault(rev, {})
3547 matches.setdefault(rev, {})
3558 if diff:
3548 if diff:
3559 parent = pctx.rev()
3549 parent = pctx.rev()
3560 matches.setdefault(parent, {})
3550 matches.setdefault(parent, {})
3561 files = revfiles.setdefault(rev, [])
3551 files = revfiles.setdefault(rev, [])
3562 if rev is None:
3552 if rev is None:
3563 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3553 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3564 # pathauditor checks without this in mozilla-central
3554 # pathauditor checks without this in mozilla-central
3565 contextmanager = repo.wvfs.audit.cached
3555 contextmanager = repo.wvfs.audit.cached
3566 else:
3556 else:
3567 contextmanager = util.nullcontextmanager
3557 contextmanager = util.nullcontextmanager
3568 with contextmanager():
3558 with contextmanager():
3569 # TODO: maybe better to warn missing files?
3559 # TODO: maybe better to warn missing files?
3570 if all_files:
3560 if all_files:
3571 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3561 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3572 filenames = ctx.matches(fmatch)
3562 filenames = ctx.matches(fmatch)
3573 else:
3563 else:
3574 filenames = (f for f in ctx.files() if fmatch(f))
3564 filenames = (f for f in ctx.files() if fmatch(f))
3575 for fn in filenames:
3565 for fn in filenames:
3576 # fn might not exist in the revision (could be a file removed by
3566 # fn might not exist in the revision (could be a file removed by
3577 # the revision). We could check `fn not in ctx` even when rev is
3567 # the revision). We could check `fn not in ctx` even when rev is
3578 # None, but it's less racy to protect againt that in readfile.
3568 # None, but it's less racy to protect againt that in readfile.
3579 if rev is not None and fn not in ctx:
3569 if rev is not None and fn not in ctx:
3580 continue
3570 continue
3581
3571
3582 copy = None
3572 copy = None
3583 if follow:
3573 if follow:
3584 copy = getrenamed(fn, rev)
3574 copy = getrenamed(fn, rev)
3585 if copy:
3575 if copy:
3586 copies.setdefault(rev, {})[fn] = copy
3576 copies.setdefault(rev, {})[fn] = copy
3587 if fn in skip:
3577 if fn in skip:
3588 skip.add(copy)
3578 skip.add(copy)
3589 if fn in skip:
3579 if fn in skip:
3590 continue
3580 continue
3591 files.append(fn)
3581 files.append(fn)
3592
3582
3593 if fn not in matches[rev]:
3583 if fn not in matches[rev]:
3594 grepbody(fn, rev, readfile(ctx, fn))
3584 searcher._grepbody(fn, rev, readfile(ctx, fn))
3595
3585
3596 if diff:
3586 if diff:
3597 pfn = copy or fn
3587 pfn = copy or fn
3598 if pfn not in matches[parent] and pfn in pctx:
3588 if pfn not in matches[parent] and pfn in pctx:
3599 grepbody(pfn, parent, readfile(pctx, pfn))
3589 searcher._grepbody(pfn, parent, readfile(pctx, pfn))
3600
3590
3601 wopts = logcmdutil.walkopts(
3591 wopts = logcmdutil.walkopts(
3602 pats=pats,
3592 pats=pats,
3603 opts=opts,
3593 opts=opts,
3604 revspec=opts[b'rev'],
3594 revspec=opts[b'rev'],
3605 include_pats=opts[b'include'],
3595 include_pats=opts[b'include'],
3606 exclude_pats=opts[b'exclude'],
3596 exclude_pats=opts[b'exclude'],
3607 follow=follow,
3597 follow=follow,
3608 force_changelog_traversal=all_files,
3598 force_changelog_traversal=all_files,
3609 filter_revisions_by_pats=not all_files,
3599 filter_revisions_by_pats=not all_files,
3610 )
3600 )
3611 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3601 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3612
3602
3613 ui.pager(b'grep')
3603 ui.pager(b'grep')
3614 fm = ui.formatter(b'grep', opts)
3604 fm = ui.formatter(b'grep', opts)
3615 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3605 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3616 rev = ctx.rev()
3606 rev = ctx.rev()
3617 parent = ctx.p1().rev()
3607 parent = ctx.p1().rev()
3618 for fn in sorted(revfiles.get(rev, [])):
3608 for fn in sorted(revfiles.get(rev, [])):
3619 states = matches[rev][fn]
3609 states = matches[rev][fn]
3620 copy = copies.get(rev, {}).get(fn)
3610 copy = copies.get(rev, {}).get(fn)
3621 if fn in skip:
3611 if fn in skip:
3622 if copy:
3612 if copy:
3623 skip.add(copy)
3613 skip.add(copy)
3624 continue
3614 continue
3625 pstates = matches.get(parent, {}).get(copy or fn, [])
3615 pstates = matches.get(parent, {}).get(copy or fn, [])
3626 if pstates or states:
3616 if pstates or states:
3627 r = display(fm, fn, ctx, pstates, states)
3617 r = display(fm, fn, ctx, pstates, states)
3628 found = found or r
3618 found = found or r
3629 if r and not diff and not all_files:
3619 if r and not diff and not all_files:
3630 skip.add(fn)
3620 skip.add(fn)
3631 if copy:
3621 if copy:
3632 skip.add(copy)
3622 skip.add(copy)
3633 del revfiles[rev]
3623 del revfiles[rev]
3634 # We will keep the matches dict for the duration of the window
3624 # We will keep the matches dict for the duration of the window
3635 # clear the matches dict once the window is over
3625 # clear the matches dict once the window is over
3636 if not revfiles:
3626 if not revfiles:
3637 matches.clear()
3627 matches.clear()
3638 fm.end()
3628 fm.end()
3639
3629
3640 return not found
3630 return not found
3641
3631
3642
3632
3643 @command(
3633 @command(
3644 b'heads',
3634 b'heads',
3645 [
3635 [
3646 (
3636 (
3647 b'r',
3637 b'r',
3648 b'rev',
3638 b'rev',
3649 b'',
3639 b'',
3650 _(b'show only heads which are descendants of STARTREV'),
3640 _(b'show only heads which are descendants of STARTREV'),
3651 _(b'STARTREV'),
3641 _(b'STARTREV'),
3652 ),
3642 ),
3653 (b't', b'topo', False, _(b'show topological heads only')),
3643 (b't', b'topo', False, _(b'show topological heads only')),
3654 (
3644 (
3655 b'a',
3645 b'a',
3656 b'active',
3646 b'active',
3657 False,
3647 False,
3658 _(b'show active branchheads only (DEPRECATED)'),
3648 _(b'show active branchheads only (DEPRECATED)'),
3659 ),
3649 ),
3660 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3650 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3661 ]
3651 ]
3662 + templateopts,
3652 + templateopts,
3663 _(b'[-ct] [-r STARTREV] [REV]...'),
3653 _(b'[-ct] [-r STARTREV] [REV]...'),
3664 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3654 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3665 intents={INTENT_READONLY},
3655 intents={INTENT_READONLY},
3666 )
3656 )
3667 def heads(ui, repo, *branchrevs, **opts):
3657 def heads(ui, repo, *branchrevs, **opts):
3668 """show branch heads
3658 """show branch heads
3669
3659
3670 With no arguments, show all open branch heads in the repository.
3660 With no arguments, show all open branch heads in the repository.
3671 Branch heads are changesets that have no descendants on the
3661 Branch heads are changesets that have no descendants on the
3672 same branch. They are where development generally takes place and
3662 same branch. They are where development generally takes place and
3673 are the usual targets for update and merge operations.
3663 are the usual targets for update and merge operations.
3674
3664
3675 If one or more REVs are given, only open branch heads on the
3665 If one or more REVs are given, only open branch heads on the
3676 branches associated with the specified changesets are shown. This
3666 branches associated with the specified changesets are shown. This
3677 means that you can use :hg:`heads .` to see the heads on the
3667 means that you can use :hg:`heads .` to see the heads on the
3678 currently checked-out branch.
3668 currently checked-out branch.
3679
3669
3680 If -c/--closed is specified, also show branch heads marked closed
3670 If -c/--closed is specified, also show branch heads marked closed
3681 (see :hg:`commit --close-branch`).
3671 (see :hg:`commit --close-branch`).
3682
3672
3683 If STARTREV is specified, only those heads that are descendants of
3673 If STARTREV is specified, only those heads that are descendants of
3684 STARTREV will be displayed.
3674 STARTREV will be displayed.
3685
3675
3686 If -t/--topo is specified, named branch mechanics will be ignored and only
3676 If -t/--topo is specified, named branch mechanics will be ignored and only
3687 topological heads (changesets with no children) will be shown.
3677 topological heads (changesets with no children) will be shown.
3688
3678
3689 Returns 0 if matching heads are found, 1 if not.
3679 Returns 0 if matching heads are found, 1 if not.
3690 """
3680 """
3691
3681
3692 opts = pycompat.byteskwargs(opts)
3682 opts = pycompat.byteskwargs(opts)
3693 start = None
3683 start = None
3694 rev = opts.get(b'rev')
3684 rev = opts.get(b'rev')
3695 if rev:
3685 if rev:
3696 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3686 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3697 start = scmutil.revsingle(repo, rev, None).node()
3687 start = scmutil.revsingle(repo, rev, None).node()
3698
3688
3699 if opts.get(b'topo'):
3689 if opts.get(b'topo'):
3700 heads = [repo[h] for h in repo.heads(start)]
3690 heads = [repo[h] for h in repo.heads(start)]
3701 else:
3691 else:
3702 heads = []
3692 heads = []
3703 for branch in repo.branchmap():
3693 for branch in repo.branchmap():
3704 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3694 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3705 heads = [repo[h] for h in heads]
3695 heads = [repo[h] for h in heads]
3706
3696
3707 if branchrevs:
3697 if branchrevs:
3708 branches = {
3698 branches = {
3709 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3699 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3710 }
3700 }
3711 heads = [h for h in heads if h.branch() in branches]
3701 heads = [h for h in heads if h.branch() in branches]
3712
3702
3713 if opts.get(b'active') and branchrevs:
3703 if opts.get(b'active') and branchrevs:
3714 dagheads = repo.heads(start)
3704 dagheads = repo.heads(start)
3715 heads = [h for h in heads if h.node() in dagheads]
3705 heads = [h for h in heads if h.node() in dagheads]
3716
3706
3717 if branchrevs:
3707 if branchrevs:
3718 haveheads = {h.branch() for h in heads}
3708 haveheads = {h.branch() for h in heads}
3719 if branches - haveheads:
3709 if branches - haveheads:
3720 headless = b', '.join(b for b in branches - haveheads)
3710 headless = b', '.join(b for b in branches - haveheads)
3721 msg = _(b'no open branch heads found on branches %s')
3711 msg = _(b'no open branch heads found on branches %s')
3722 if opts.get(b'rev'):
3712 if opts.get(b'rev'):
3723 msg += _(b' (started at %s)') % opts[b'rev']
3713 msg += _(b' (started at %s)') % opts[b'rev']
3724 ui.warn((msg + b'\n') % headless)
3714 ui.warn((msg + b'\n') % headless)
3725
3715
3726 if not heads:
3716 if not heads:
3727 return 1
3717 return 1
3728
3718
3729 ui.pager(b'heads')
3719 ui.pager(b'heads')
3730 heads = sorted(heads, key=lambda x: -(x.rev()))
3720 heads = sorted(heads, key=lambda x: -(x.rev()))
3731 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3721 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3732 for ctx in heads:
3722 for ctx in heads:
3733 displayer.show(ctx)
3723 displayer.show(ctx)
3734 displayer.close()
3724 displayer.close()
3735
3725
3736
3726
3737 @command(
3727 @command(
3738 b'help',
3728 b'help',
3739 [
3729 [
3740 (b'e', b'extension', None, _(b'show only help for extensions')),
3730 (b'e', b'extension', None, _(b'show only help for extensions')),
3741 (b'c', b'command', None, _(b'show only help for commands')),
3731 (b'c', b'command', None, _(b'show only help for commands')),
3742 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3732 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3743 (
3733 (
3744 b's',
3734 b's',
3745 b'system',
3735 b'system',
3746 [],
3736 [],
3747 _(b'show help for specific platform(s)'),
3737 _(b'show help for specific platform(s)'),
3748 _(b'PLATFORM'),
3738 _(b'PLATFORM'),
3749 ),
3739 ),
3750 ],
3740 ],
3751 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3741 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3752 helpcategory=command.CATEGORY_HELP,
3742 helpcategory=command.CATEGORY_HELP,
3753 norepo=True,
3743 norepo=True,
3754 intents={INTENT_READONLY},
3744 intents={INTENT_READONLY},
3755 )
3745 )
3756 def help_(ui, name=None, **opts):
3746 def help_(ui, name=None, **opts):
3757 """show help for a given topic or a help overview
3747 """show help for a given topic or a help overview
3758
3748
3759 With no arguments, print a list of commands with short help messages.
3749 With no arguments, print a list of commands with short help messages.
3760
3750
3761 Given a topic, extension, or command name, print help for that
3751 Given a topic, extension, or command name, print help for that
3762 topic.
3752 topic.
3763
3753
3764 Returns 0 if successful.
3754 Returns 0 if successful.
3765 """
3755 """
3766
3756
3767 keep = opts.get('system') or []
3757 keep = opts.get('system') or []
3768 if len(keep) == 0:
3758 if len(keep) == 0:
3769 if pycompat.sysplatform.startswith(b'win'):
3759 if pycompat.sysplatform.startswith(b'win'):
3770 keep.append(b'windows')
3760 keep.append(b'windows')
3771 elif pycompat.sysplatform == b'OpenVMS':
3761 elif pycompat.sysplatform == b'OpenVMS':
3772 keep.append(b'vms')
3762 keep.append(b'vms')
3773 elif pycompat.sysplatform == b'plan9':
3763 elif pycompat.sysplatform == b'plan9':
3774 keep.append(b'plan9')
3764 keep.append(b'plan9')
3775 else:
3765 else:
3776 keep.append(b'unix')
3766 keep.append(b'unix')
3777 keep.append(pycompat.sysplatform.lower())
3767 keep.append(pycompat.sysplatform.lower())
3778 if ui.verbose:
3768 if ui.verbose:
3779 keep.append(b'verbose')
3769 keep.append(b'verbose')
3780
3770
3781 commands = sys.modules[__name__]
3771 commands = sys.modules[__name__]
3782 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3772 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3783 ui.pager(b'help')
3773 ui.pager(b'help')
3784 ui.write(formatted)
3774 ui.write(formatted)
3785
3775
3786
3776
3787 @command(
3777 @command(
3788 b'identify|id',
3778 b'identify|id',
3789 [
3779 [
3790 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3780 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3791 (b'n', b'num', None, _(b'show local revision number')),
3781 (b'n', b'num', None, _(b'show local revision number')),
3792 (b'i', b'id', None, _(b'show global revision id')),
3782 (b'i', b'id', None, _(b'show global revision id')),
3793 (b'b', b'branch', None, _(b'show branch')),
3783 (b'b', b'branch', None, _(b'show branch')),
3794 (b't', b'tags', None, _(b'show tags')),
3784 (b't', b'tags', None, _(b'show tags')),
3795 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3785 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3796 ]
3786 ]
3797 + remoteopts
3787 + remoteopts
3798 + formatteropts,
3788 + formatteropts,
3799 _(b'[-nibtB] [-r REV] [SOURCE]'),
3789 _(b'[-nibtB] [-r REV] [SOURCE]'),
3800 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3790 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3801 optionalrepo=True,
3791 optionalrepo=True,
3802 intents={INTENT_READONLY},
3792 intents={INTENT_READONLY},
3803 )
3793 )
3804 def identify(
3794 def identify(
3805 ui,
3795 ui,
3806 repo,
3796 repo,
3807 source=None,
3797 source=None,
3808 rev=None,
3798 rev=None,
3809 num=None,
3799 num=None,
3810 id=None,
3800 id=None,
3811 branch=None,
3801 branch=None,
3812 tags=None,
3802 tags=None,
3813 bookmarks=None,
3803 bookmarks=None,
3814 **opts
3804 **opts
3815 ):
3805 ):
3816 """identify the working directory or specified revision
3806 """identify the working directory or specified revision
3817
3807
3818 Print a summary identifying the repository state at REV using one or
3808 Print a summary identifying the repository state at REV using one or
3819 two parent hash identifiers, followed by a "+" if the working
3809 two parent hash identifiers, followed by a "+" if the working
3820 directory has uncommitted changes, the branch name (if not default),
3810 directory has uncommitted changes, the branch name (if not default),
3821 a list of tags, and a list of bookmarks.
3811 a list of tags, and a list of bookmarks.
3822
3812
3823 When REV is not given, print a summary of the current state of the
3813 When REV is not given, print a summary of the current state of the
3824 repository including the working directory. Specify -r. to get information
3814 repository including the working directory. Specify -r. to get information
3825 of the working directory parent without scanning uncommitted changes.
3815 of the working directory parent without scanning uncommitted changes.
3826
3816
3827 Specifying a path to a repository root or Mercurial bundle will
3817 Specifying a path to a repository root or Mercurial bundle will
3828 cause lookup to operate on that repository/bundle.
3818 cause lookup to operate on that repository/bundle.
3829
3819
3830 .. container:: verbose
3820 .. container:: verbose
3831
3821
3832 Template:
3822 Template:
3833
3823
3834 The following keywords are supported in addition to the common template
3824 The following keywords are supported in addition to the common template
3835 keywords and functions. See also :hg:`help templates`.
3825 keywords and functions. See also :hg:`help templates`.
3836
3826
3837 :dirty: String. Character ``+`` denoting if the working directory has
3827 :dirty: String. Character ``+`` denoting if the working directory has
3838 uncommitted changes.
3828 uncommitted changes.
3839 :id: String. One or two nodes, optionally followed by ``+``.
3829 :id: String. One or two nodes, optionally followed by ``+``.
3840 :parents: List of strings. Parent nodes of the changeset.
3830 :parents: List of strings. Parent nodes of the changeset.
3841
3831
3842 Examples:
3832 Examples:
3843
3833
3844 - generate a build identifier for the working directory::
3834 - generate a build identifier for the working directory::
3845
3835
3846 hg id --id > build-id.dat
3836 hg id --id > build-id.dat
3847
3837
3848 - find the revision corresponding to a tag::
3838 - find the revision corresponding to a tag::
3849
3839
3850 hg id -n -r 1.3
3840 hg id -n -r 1.3
3851
3841
3852 - check the most recent revision of a remote repository::
3842 - check the most recent revision of a remote repository::
3853
3843
3854 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3844 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3855
3845
3856 See :hg:`log` for generating more information about specific revisions,
3846 See :hg:`log` for generating more information about specific revisions,
3857 including full hash identifiers.
3847 including full hash identifiers.
3858
3848
3859 Returns 0 if successful.
3849 Returns 0 if successful.
3860 """
3850 """
3861
3851
3862 opts = pycompat.byteskwargs(opts)
3852 opts = pycompat.byteskwargs(opts)
3863 if not repo and not source:
3853 if not repo and not source:
3864 raise error.Abort(
3854 raise error.Abort(
3865 _(b"there is no Mercurial repository here (.hg not found)")
3855 _(b"there is no Mercurial repository here (.hg not found)")
3866 )
3856 )
3867
3857
3868 default = not (num or id or branch or tags or bookmarks)
3858 default = not (num or id or branch or tags or bookmarks)
3869 output = []
3859 output = []
3870 revs = []
3860 revs = []
3871
3861
3872 if source:
3862 if source:
3873 source, branches = hg.parseurl(ui.expandpath(source))
3863 source, branches = hg.parseurl(ui.expandpath(source))
3874 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3864 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3875 repo = peer.local()
3865 repo = peer.local()
3876 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3866 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3877
3867
3878 fm = ui.formatter(b'identify', opts)
3868 fm = ui.formatter(b'identify', opts)
3879 fm.startitem()
3869 fm.startitem()
3880
3870
3881 if not repo:
3871 if not repo:
3882 if num or branch or tags:
3872 if num or branch or tags:
3883 raise error.Abort(
3873 raise error.Abort(
3884 _(b"can't query remote revision number, branch, or tags")
3874 _(b"can't query remote revision number, branch, or tags")
3885 )
3875 )
3886 if not rev and revs:
3876 if not rev and revs:
3887 rev = revs[0]
3877 rev = revs[0]
3888 if not rev:
3878 if not rev:
3889 rev = b"tip"
3879 rev = b"tip"
3890
3880
3891 remoterev = peer.lookup(rev)
3881 remoterev = peer.lookup(rev)
3892 hexrev = fm.hexfunc(remoterev)
3882 hexrev = fm.hexfunc(remoterev)
3893 if default or id:
3883 if default or id:
3894 output = [hexrev]
3884 output = [hexrev]
3895 fm.data(id=hexrev)
3885 fm.data(id=hexrev)
3896
3886
3897 @util.cachefunc
3887 @util.cachefunc
3898 def getbms():
3888 def getbms():
3899 bms = []
3889 bms = []
3900
3890
3901 if b'bookmarks' in peer.listkeys(b'namespaces'):
3891 if b'bookmarks' in peer.listkeys(b'namespaces'):
3902 hexremoterev = hex(remoterev)
3892 hexremoterev = hex(remoterev)
3903 bms = [
3893 bms = [
3904 bm
3894 bm
3905 for bm, bmr in pycompat.iteritems(
3895 for bm, bmr in pycompat.iteritems(
3906 peer.listkeys(b'bookmarks')
3896 peer.listkeys(b'bookmarks')
3907 )
3897 )
3908 if bmr == hexremoterev
3898 if bmr == hexremoterev
3909 ]
3899 ]
3910
3900
3911 return sorted(bms)
3901 return sorted(bms)
3912
3902
3913 if fm.isplain():
3903 if fm.isplain():
3914 if bookmarks:
3904 if bookmarks:
3915 output.extend(getbms())
3905 output.extend(getbms())
3916 elif default and not ui.quiet:
3906 elif default and not ui.quiet:
3917 # multiple bookmarks for a single parent separated by '/'
3907 # multiple bookmarks for a single parent separated by '/'
3918 bm = b'/'.join(getbms())
3908 bm = b'/'.join(getbms())
3919 if bm:
3909 if bm:
3920 output.append(bm)
3910 output.append(bm)
3921 else:
3911 else:
3922 fm.data(node=hex(remoterev))
3912 fm.data(node=hex(remoterev))
3923 if bookmarks or b'bookmarks' in fm.datahint():
3913 if bookmarks or b'bookmarks' in fm.datahint():
3924 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3914 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3925 else:
3915 else:
3926 if rev:
3916 if rev:
3927 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3917 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3928 ctx = scmutil.revsingle(repo, rev, None)
3918 ctx = scmutil.revsingle(repo, rev, None)
3929
3919
3930 if ctx.rev() is None:
3920 if ctx.rev() is None:
3931 ctx = repo[None]
3921 ctx = repo[None]
3932 parents = ctx.parents()
3922 parents = ctx.parents()
3933 taglist = []
3923 taglist = []
3934 for p in parents:
3924 for p in parents:
3935 taglist.extend(p.tags())
3925 taglist.extend(p.tags())
3936
3926
3937 dirty = b""
3927 dirty = b""
3938 if ctx.dirty(missing=True, merge=False, branch=False):
3928 if ctx.dirty(missing=True, merge=False, branch=False):
3939 dirty = b'+'
3929 dirty = b'+'
3940 fm.data(dirty=dirty)
3930 fm.data(dirty=dirty)
3941
3931
3942 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3932 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3943 if default or id:
3933 if default or id:
3944 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3934 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3945 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3935 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3946
3936
3947 if num:
3937 if num:
3948 numoutput = [b"%d" % p.rev() for p in parents]
3938 numoutput = [b"%d" % p.rev() for p in parents]
3949 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3939 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3950
3940
3951 fm.data(
3941 fm.data(
3952 parents=fm.formatlist(
3942 parents=fm.formatlist(
3953 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3943 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3954 )
3944 )
3955 )
3945 )
3956 else:
3946 else:
3957 hexoutput = fm.hexfunc(ctx.node())
3947 hexoutput = fm.hexfunc(ctx.node())
3958 if default or id:
3948 if default or id:
3959 output = [hexoutput]
3949 output = [hexoutput]
3960 fm.data(id=hexoutput)
3950 fm.data(id=hexoutput)
3961
3951
3962 if num:
3952 if num:
3963 output.append(pycompat.bytestr(ctx.rev()))
3953 output.append(pycompat.bytestr(ctx.rev()))
3964 taglist = ctx.tags()
3954 taglist = ctx.tags()
3965
3955
3966 if default and not ui.quiet:
3956 if default and not ui.quiet:
3967 b = ctx.branch()
3957 b = ctx.branch()
3968 if b != b'default':
3958 if b != b'default':
3969 output.append(b"(%s)" % b)
3959 output.append(b"(%s)" % b)
3970
3960
3971 # multiple tags for a single parent separated by '/'
3961 # multiple tags for a single parent separated by '/'
3972 t = b'/'.join(taglist)
3962 t = b'/'.join(taglist)
3973 if t:
3963 if t:
3974 output.append(t)
3964 output.append(t)
3975
3965
3976 # multiple bookmarks for a single parent separated by '/'
3966 # multiple bookmarks for a single parent separated by '/'
3977 bm = b'/'.join(ctx.bookmarks())
3967 bm = b'/'.join(ctx.bookmarks())
3978 if bm:
3968 if bm:
3979 output.append(bm)
3969 output.append(bm)
3980 else:
3970 else:
3981 if branch:
3971 if branch:
3982 output.append(ctx.branch())
3972 output.append(ctx.branch())
3983
3973
3984 if tags:
3974 if tags:
3985 output.extend(taglist)
3975 output.extend(taglist)
3986
3976
3987 if bookmarks:
3977 if bookmarks:
3988 output.extend(ctx.bookmarks())
3978 output.extend(ctx.bookmarks())
3989
3979
3990 fm.data(node=ctx.hex())
3980 fm.data(node=ctx.hex())
3991 fm.data(branch=ctx.branch())
3981 fm.data(branch=ctx.branch())
3992 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3982 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3993 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3983 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3994 fm.context(ctx=ctx)
3984 fm.context(ctx=ctx)
3995
3985
3996 fm.plain(b"%s\n" % b' '.join(output))
3986 fm.plain(b"%s\n" % b' '.join(output))
3997 fm.end()
3987 fm.end()
3998
3988
3999
3989
4000 @command(
3990 @command(
4001 b'import|patch',
3991 b'import|patch',
4002 [
3992 [
4003 (
3993 (
4004 b'p',
3994 b'p',
4005 b'strip',
3995 b'strip',
4006 1,
3996 1,
4007 _(
3997 _(
4008 b'directory strip option for patch. This has the same '
3998 b'directory strip option for patch. This has the same '
4009 b'meaning as the corresponding patch option'
3999 b'meaning as the corresponding patch option'
4010 ),
4000 ),
4011 _(b'NUM'),
4001 _(b'NUM'),
4012 ),
4002 ),
4013 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4003 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4014 (b'', b'secret', None, _(b'use the secret phase for committing')),
4004 (b'', b'secret', None, _(b'use the secret phase for committing')),
4015 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4005 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4016 (
4006 (
4017 b'f',
4007 b'f',
4018 b'force',
4008 b'force',
4019 None,
4009 None,
4020 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4010 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4021 ),
4011 ),
4022 (
4012 (
4023 b'',
4013 b'',
4024 b'no-commit',
4014 b'no-commit',
4025 None,
4015 None,
4026 _(b"don't commit, just update the working directory"),
4016 _(b"don't commit, just update the working directory"),
4027 ),
4017 ),
4028 (
4018 (
4029 b'',
4019 b'',
4030 b'bypass',
4020 b'bypass',
4031 None,
4021 None,
4032 _(b"apply patch without touching the working directory"),
4022 _(b"apply patch without touching the working directory"),
4033 ),
4023 ),
4034 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4024 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4035 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4025 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4036 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4026 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4037 (
4027 (
4038 b'',
4028 b'',
4039 b'import-branch',
4029 b'import-branch',
4040 None,
4030 None,
4041 _(b'use any branch information in patch (implied by --exact)'),
4031 _(b'use any branch information in patch (implied by --exact)'),
4042 ),
4032 ),
4043 ]
4033 ]
4044 + commitopts
4034 + commitopts
4045 + commitopts2
4035 + commitopts2
4046 + similarityopts,
4036 + similarityopts,
4047 _(b'[OPTION]... PATCH...'),
4037 _(b'[OPTION]... PATCH...'),
4048 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4038 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4049 )
4039 )
4050 def import_(ui, repo, patch1=None, *patches, **opts):
4040 def import_(ui, repo, patch1=None, *patches, **opts):
4051 """import an ordered set of patches
4041 """import an ordered set of patches
4052
4042
4053 Import a list of patches and commit them individually (unless
4043 Import a list of patches and commit them individually (unless
4054 --no-commit is specified).
4044 --no-commit is specified).
4055
4045
4056 To read a patch from standard input (stdin), use "-" as the patch
4046 To read a patch from standard input (stdin), use "-" as the patch
4057 name. If a URL is specified, the patch will be downloaded from
4047 name. If a URL is specified, the patch will be downloaded from
4058 there.
4048 there.
4059
4049
4060 Import first applies changes to the working directory (unless
4050 Import first applies changes to the working directory (unless
4061 --bypass is specified), import will abort if there are outstanding
4051 --bypass is specified), import will abort if there are outstanding
4062 changes.
4052 changes.
4063
4053
4064 Use --bypass to apply and commit patches directly to the
4054 Use --bypass to apply and commit patches directly to the
4065 repository, without affecting the working directory. Without
4055 repository, without affecting the working directory. Without
4066 --exact, patches will be applied on top of the working directory
4056 --exact, patches will be applied on top of the working directory
4067 parent revision.
4057 parent revision.
4068
4058
4069 You can import a patch straight from a mail message. Even patches
4059 You can import a patch straight from a mail message. Even patches
4070 as attachments work (to use the body part, it must have type
4060 as attachments work (to use the body part, it must have type
4071 text/plain or text/x-patch). From and Subject headers of email
4061 text/plain or text/x-patch). From and Subject headers of email
4072 message are used as default committer and commit message. All
4062 message are used as default committer and commit message. All
4073 text/plain body parts before first diff are added to the commit
4063 text/plain body parts before first diff are added to the commit
4074 message.
4064 message.
4075
4065
4076 If the imported patch was generated by :hg:`export`, user and
4066 If the imported patch was generated by :hg:`export`, user and
4077 description from patch override values from message headers and
4067 description from patch override values from message headers and
4078 body. Values given on command line with -m/--message and -u/--user
4068 body. Values given on command line with -m/--message and -u/--user
4079 override these.
4069 override these.
4080
4070
4081 If --exact is specified, import will set the working directory to
4071 If --exact is specified, import will set the working directory to
4082 the parent of each patch before applying it, and will abort if the
4072 the parent of each patch before applying it, and will abort if the
4083 resulting changeset has a different ID than the one recorded in
4073 resulting changeset has a different ID than the one recorded in
4084 the patch. This will guard against various ways that portable
4074 the patch. This will guard against various ways that portable
4085 patch formats and mail systems might fail to transfer Mercurial
4075 patch formats and mail systems might fail to transfer Mercurial
4086 data or metadata. See :hg:`bundle` for lossless transmission.
4076 data or metadata. See :hg:`bundle` for lossless transmission.
4087
4077
4088 Use --partial to ensure a changeset will be created from the patch
4078 Use --partial to ensure a changeset will be created from the patch
4089 even if some hunks fail to apply. Hunks that fail to apply will be
4079 even if some hunks fail to apply. Hunks that fail to apply will be
4090 written to a <target-file>.rej file. Conflicts can then be resolved
4080 written to a <target-file>.rej file. Conflicts can then be resolved
4091 by hand before :hg:`commit --amend` is run to update the created
4081 by hand before :hg:`commit --amend` is run to update the created
4092 changeset. This flag exists to let people import patches that
4082 changeset. This flag exists to let people import patches that
4093 partially apply without losing the associated metadata (author,
4083 partially apply without losing the associated metadata (author,
4094 date, description, ...).
4084 date, description, ...).
4095
4085
4096 .. note::
4086 .. note::
4097
4087
4098 When no hunks apply cleanly, :hg:`import --partial` will create
4088 When no hunks apply cleanly, :hg:`import --partial` will create
4099 an empty changeset, importing only the patch metadata.
4089 an empty changeset, importing only the patch metadata.
4100
4090
4101 With -s/--similarity, hg will attempt to discover renames and
4091 With -s/--similarity, hg will attempt to discover renames and
4102 copies in the patch in the same way as :hg:`addremove`.
4092 copies in the patch in the same way as :hg:`addremove`.
4103
4093
4104 It is possible to use external patch programs to perform the patch
4094 It is possible to use external patch programs to perform the patch
4105 by setting the ``ui.patch`` configuration option. For the default
4095 by setting the ``ui.patch`` configuration option. For the default
4106 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4096 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4107 See :hg:`help config` for more information about configuration
4097 See :hg:`help config` for more information about configuration
4108 files and how to use these options.
4098 files and how to use these options.
4109
4099
4110 See :hg:`help dates` for a list of formats valid for -d/--date.
4100 See :hg:`help dates` for a list of formats valid for -d/--date.
4111
4101
4112 .. container:: verbose
4102 .. container:: verbose
4113
4103
4114 Examples:
4104 Examples:
4115
4105
4116 - import a traditional patch from a website and detect renames::
4106 - import a traditional patch from a website and detect renames::
4117
4107
4118 hg import -s 80 http://example.com/bugfix.patch
4108 hg import -s 80 http://example.com/bugfix.patch
4119
4109
4120 - import a changeset from an hgweb server::
4110 - import a changeset from an hgweb server::
4121
4111
4122 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4112 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4123
4113
4124 - import all the patches in an Unix-style mbox::
4114 - import all the patches in an Unix-style mbox::
4125
4115
4126 hg import incoming-patches.mbox
4116 hg import incoming-patches.mbox
4127
4117
4128 - import patches from stdin::
4118 - import patches from stdin::
4129
4119
4130 hg import -
4120 hg import -
4131
4121
4132 - attempt to exactly restore an exported changeset (not always
4122 - attempt to exactly restore an exported changeset (not always
4133 possible)::
4123 possible)::
4134
4124
4135 hg import --exact proposed-fix.patch
4125 hg import --exact proposed-fix.patch
4136
4126
4137 - use an external tool to apply a patch which is too fuzzy for
4127 - use an external tool to apply a patch which is too fuzzy for
4138 the default internal tool.
4128 the default internal tool.
4139
4129
4140 hg import --config ui.patch="patch --merge" fuzzy.patch
4130 hg import --config ui.patch="patch --merge" fuzzy.patch
4141
4131
4142 - change the default fuzzing from 2 to a less strict 7
4132 - change the default fuzzing from 2 to a less strict 7
4143
4133
4144 hg import --config ui.fuzz=7 fuzz.patch
4134 hg import --config ui.fuzz=7 fuzz.patch
4145
4135
4146 Returns 0 on success, 1 on partial success (see --partial).
4136 Returns 0 on success, 1 on partial success (see --partial).
4147 """
4137 """
4148
4138
4149 opts = pycompat.byteskwargs(opts)
4139 opts = pycompat.byteskwargs(opts)
4150 if not patch1:
4140 if not patch1:
4151 raise error.Abort(_(b'need at least one patch to import'))
4141 raise error.Abort(_(b'need at least one patch to import'))
4152
4142
4153 patches = (patch1,) + patches
4143 patches = (patch1,) + patches
4154
4144
4155 date = opts.get(b'date')
4145 date = opts.get(b'date')
4156 if date:
4146 if date:
4157 opts[b'date'] = dateutil.parsedate(date)
4147 opts[b'date'] = dateutil.parsedate(date)
4158
4148
4159 exact = opts.get(b'exact')
4149 exact = opts.get(b'exact')
4160 update = not opts.get(b'bypass')
4150 update = not opts.get(b'bypass')
4161 if not update and opts.get(b'no_commit'):
4151 if not update and opts.get(b'no_commit'):
4162 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4152 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4163 if opts.get(b'secret') and opts.get(b'no_commit'):
4153 if opts.get(b'secret') and opts.get(b'no_commit'):
4164 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4154 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4165 try:
4155 try:
4166 sim = float(opts.get(b'similarity') or 0)
4156 sim = float(opts.get(b'similarity') or 0)
4167 except ValueError:
4157 except ValueError:
4168 raise error.Abort(_(b'similarity must be a number'))
4158 raise error.Abort(_(b'similarity must be a number'))
4169 if sim < 0 or sim > 100:
4159 if sim < 0 or sim > 100:
4170 raise error.Abort(_(b'similarity must be between 0 and 100'))
4160 raise error.Abort(_(b'similarity must be between 0 and 100'))
4171 if sim and not update:
4161 if sim and not update:
4172 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4162 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4173 if exact:
4163 if exact:
4174 if opts.get(b'edit'):
4164 if opts.get(b'edit'):
4175 raise error.Abort(_(b'cannot use --exact with --edit'))
4165 raise error.Abort(_(b'cannot use --exact with --edit'))
4176 if opts.get(b'prefix'):
4166 if opts.get(b'prefix'):
4177 raise error.Abort(_(b'cannot use --exact with --prefix'))
4167 raise error.Abort(_(b'cannot use --exact with --prefix'))
4178
4168
4179 base = opts[b"base"]
4169 base = opts[b"base"]
4180 msgs = []
4170 msgs = []
4181 ret = 0
4171 ret = 0
4182
4172
4183 with repo.wlock():
4173 with repo.wlock():
4184 if update:
4174 if update:
4185 cmdutil.checkunfinished(repo)
4175 cmdutil.checkunfinished(repo)
4186 if exact or not opts.get(b'force'):
4176 if exact or not opts.get(b'force'):
4187 cmdutil.bailifchanged(repo)
4177 cmdutil.bailifchanged(repo)
4188
4178
4189 if not opts.get(b'no_commit'):
4179 if not opts.get(b'no_commit'):
4190 lock = repo.lock
4180 lock = repo.lock
4191 tr = lambda: repo.transaction(b'import')
4181 tr = lambda: repo.transaction(b'import')
4192 dsguard = util.nullcontextmanager
4182 dsguard = util.nullcontextmanager
4193 else:
4183 else:
4194 lock = util.nullcontextmanager
4184 lock = util.nullcontextmanager
4195 tr = util.nullcontextmanager
4185 tr = util.nullcontextmanager
4196 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4186 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4197 with lock(), tr(), dsguard():
4187 with lock(), tr(), dsguard():
4198 parents = repo[None].parents()
4188 parents = repo[None].parents()
4199 for patchurl in patches:
4189 for patchurl in patches:
4200 if patchurl == b'-':
4190 if patchurl == b'-':
4201 ui.status(_(b'applying patch from stdin\n'))
4191 ui.status(_(b'applying patch from stdin\n'))
4202 patchfile = ui.fin
4192 patchfile = ui.fin
4203 patchurl = b'stdin' # for error message
4193 patchurl = b'stdin' # for error message
4204 else:
4194 else:
4205 patchurl = os.path.join(base, patchurl)
4195 patchurl = os.path.join(base, patchurl)
4206 ui.status(_(b'applying %s\n') % patchurl)
4196 ui.status(_(b'applying %s\n') % patchurl)
4207 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4197 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4208
4198
4209 haspatch = False
4199 haspatch = False
4210 for hunk in patch.split(patchfile):
4200 for hunk in patch.split(patchfile):
4211 with patch.extract(ui, hunk) as patchdata:
4201 with patch.extract(ui, hunk) as patchdata:
4212 msg, node, rej = cmdutil.tryimportone(
4202 msg, node, rej = cmdutil.tryimportone(
4213 ui, repo, patchdata, parents, opts, msgs, hg.clean
4203 ui, repo, patchdata, parents, opts, msgs, hg.clean
4214 )
4204 )
4215 if msg:
4205 if msg:
4216 haspatch = True
4206 haspatch = True
4217 ui.note(msg + b'\n')
4207 ui.note(msg + b'\n')
4218 if update or exact:
4208 if update or exact:
4219 parents = repo[None].parents()
4209 parents = repo[None].parents()
4220 else:
4210 else:
4221 parents = [repo[node]]
4211 parents = [repo[node]]
4222 if rej:
4212 if rej:
4223 ui.write_err(_(b"patch applied partially\n"))
4213 ui.write_err(_(b"patch applied partially\n"))
4224 ui.write_err(
4214 ui.write_err(
4225 _(
4215 _(
4226 b"(fix the .rej files and run "
4216 b"(fix the .rej files and run "
4227 b"`hg commit --amend`)\n"
4217 b"`hg commit --amend`)\n"
4228 )
4218 )
4229 )
4219 )
4230 ret = 1
4220 ret = 1
4231 break
4221 break
4232
4222
4233 if not haspatch:
4223 if not haspatch:
4234 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4224 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4235
4225
4236 if msgs:
4226 if msgs:
4237 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4227 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4238 return ret
4228 return ret
4239
4229
4240
4230
4241 @command(
4231 @command(
4242 b'incoming|in',
4232 b'incoming|in',
4243 [
4233 [
4244 (
4234 (
4245 b'f',
4235 b'f',
4246 b'force',
4236 b'force',
4247 None,
4237 None,
4248 _(b'run even if remote repository is unrelated'),
4238 _(b'run even if remote repository is unrelated'),
4249 ),
4239 ),
4250 (b'n', b'newest-first', None, _(b'show newest record first')),
4240 (b'n', b'newest-first', None, _(b'show newest record first')),
4251 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4241 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4252 (
4242 (
4253 b'r',
4243 b'r',
4254 b'rev',
4244 b'rev',
4255 [],
4245 [],
4256 _(b'a remote changeset intended to be added'),
4246 _(b'a remote changeset intended to be added'),
4257 _(b'REV'),
4247 _(b'REV'),
4258 ),
4248 ),
4259 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4249 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4260 (
4250 (
4261 b'b',
4251 b'b',
4262 b'branch',
4252 b'branch',
4263 [],
4253 [],
4264 _(b'a specific branch you would like to pull'),
4254 _(b'a specific branch you would like to pull'),
4265 _(b'BRANCH'),
4255 _(b'BRANCH'),
4266 ),
4256 ),
4267 ]
4257 ]
4268 + logopts
4258 + logopts
4269 + remoteopts
4259 + remoteopts
4270 + subrepoopts,
4260 + subrepoopts,
4271 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4261 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4272 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4262 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4273 )
4263 )
4274 def incoming(ui, repo, source=b"default", **opts):
4264 def incoming(ui, repo, source=b"default", **opts):
4275 """show new changesets found in source
4265 """show new changesets found in source
4276
4266
4277 Show new changesets found in the specified path/URL or the default
4267 Show new changesets found in the specified path/URL or the default
4278 pull location. These are the changesets that would have been pulled
4268 pull location. These are the changesets that would have been pulled
4279 by :hg:`pull` at the time you issued this command.
4269 by :hg:`pull` at the time you issued this command.
4280
4270
4281 See pull for valid source format details.
4271 See pull for valid source format details.
4282
4272
4283 .. container:: verbose
4273 .. container:: verbose
4284
4274
4285 With -B/--bookmarks, the result of bookmark comparison between
4275 With -B/--bookmarks, the result of bookmark comparison between
4286 local and remote repositories is displayed. With -v/--verbose,
4276 local and remote repositories is displayed. With -v/--verbose,
4287 status is also displayed for each bookmark like below::
4277 status is also displayed for each bookmark like below::
4288
4278
4289 BM1 01234567890a added
4279 BM1 01234567890a added
4290 BM2 1234567890ab advanced
4280 BM2 1234567890ab advanced
4291 BM3 234567890abc diverged
4281 BM3 234567890abc diverged
4292 BM4 34567890abcd changed
4282 BM4 34567890abcd changed
4293
4283
4294 The action taken locally when pulling depends on the
4284 The action taken locally when pulling depends on the
4295 status of each bookmark:
4285 status of each bookmark:
4296
4286
4297 :``added``: pull will create it
4287 :``added``: pull will create it
4298 :``advanced``: pull will update it
4288 :``advanced``: pull will update it
4299 :``diverged``: pull will create a divergent bookmark
4289 :``diverged``: pull will create a divergent bookmark
4300 :``changed``: result depends on remote changesets
4290 :``changed``: result depends on remote changesets
4301
4291
4302 From the point of view of pulling behavior, bookmark
4292 From the point of view of pulling behavior, bookmark
4303 existing only in the remote repository are treated as ``added``,
4293 existing only in the remote repository are treated as ``added``,
4304 even if it is in fact locally deleted.
4294 even if it is in fact locally deleted.
4305
4295
4306 .. container:: verbose
4296 .. container:: verbose
4307
4297
4308 For remote repository, using --bundle avoids downloading the
4298 For remote repository, using --bundle avoids downloading the
4309 changesets twice if the incoming is followed by a pull.
4299 changesets twice if the incoming is followed by a pull.
4310
4300
4311 Examples:
4301 Examples:
4312
4302
4313 - show incoming changes with patches and full description::
4303 - show incoming changes with patches and full description::
4314
4304
4315 hg incoming -vp
4305 hg incoming -vp
4316
4306
4317 - show incoming changes excluding merges, store a bundle::
4307 - show incoming changes excluding merges, store a bundle::
4318
4308
4319 hg in -vpM --bundle incoming.hg
4309 hg in -vpM --bundle incoming.hg
4320 hg pull incoming.hg
4310 hg pull incoming.hg
4321
4311
4322 - briefly list changes inside a bundle::
4312 - briefly list changes inside a bundle::
4323
4313
4324 hg in changes.hg -T "{desc|firstline}\\n"
4314 hg in changes.hg -T "{desc|firstline}\\n"
4325
4315
4326 Returns 0 if there are incoming changes, 1 otherwise.
4316 Returns 0 if there are incoming changes, 1 otherwise.
4327 """
4317 """
4328 opts = pycompat.byteskwargs(opts)
4318 opts = pycompat.byteskwargs(opts)
4329 if opts.get(b'graph'):
4319 if opts.get(b'graph'):
4330 logcmdutil.checkunsupportedgraphflags([], opts)
4320 logcmdutil.checkunsupportedgraphflags([], opts)
4331
4321
4332 def display(other, chlist, displayer):
4322 def display(other, chlist, displayer):
4333 revdag = logcmdutil.graphrevs(other, chlist, opts)
4323 revdag = logcmdutil.graphrevs(other, chlist, opts)
4334 logcmdutil.displaygraph(
4324 logcmdutil.displaygraph(
4335 ui, repo, revdag, displayer, graphmod.asciiedges
4325 ui, repo, revdag, displayer, graphmod.asciiedges
4336 )
4326 )
4337
4327
4338 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4328 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4339 return 0
4329 return 0
4340
4330
4341 if opts.get(b'bundle') and opts.get(b'subrepos'):
4331 if opts.get(b'bundle') and opts.get(b'subrepos'):
4342 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4332 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4343
4333
4344 if opts.get(b'bookmarks'):
4334 if opts.get(b'bookmarks'):
4345 source, branches = hg.parseurl(
4335 source, branches = hg.parseurl(
4346 ui.expandpath(source), opts.get(b'branch')
4336 ui.expandpath(source), opts.get(b'branch')
4347 )
4337 )
4348 other = hg.peer(repo, opts, source)
4338 other = hg.peer(repo, opts, source)
4349 if b'bookmarks' not in other.listkeys(b'namespaces'):
4339 if b'bookmarks' not in other.listkeys(b'namespaces'):
4350 ui.warn(_(b"remote doesn't support bookmarks\n"))
4340 ui.warn(_(b"remote doesn't support bookmarks\n"))
4351 return 0
4341 return 0
4352 ui.pager(b'incoming')
4342 ui.pager(b'incoming')
4353 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4343 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4354 return bookmarks.incoming(ui, repo, other)
4344 return bookmarks.incoming(ui, repo, other)
4355
4345
4356 repo._subtoppath = ui.expandpath(source)
4346 repo._subtoppath = ui.expandpath(source)
4357 try:
4347 try:
4358 return hg.incoming(ui, repo, source, opts)
4348 return hg.incoming(ui, repo, source, opts)
4359 finally:
4349 finally:
4360 del repo._subtoppath
4350 del repo._subtoppath
4361
4351
4362
4352
4363 @command(
4353 @command(
4364 b'init',
4354 b'init',
4365 remoteopts,
4355 remoteopts,
4366 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4356 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4367 helpcategory=command.CATEGORY_REPO_CREATION,
4357 helpcategory=command.CATEGORY_REPO_CREATION,
4368 helpbasic=True,
4358 helpbasic=True,
4369 norepo=True,
4359 norepo=True,
4370 )
4360 )
4371 def init(ui, dest=b".", **opts):
4361 def init(ui, dest=b".", **opts):
4372 """create a new repository in the given directory
4362 """create a new repository in the given directory
4373
4363
4374 Initialize a new repository in the given directory. If the given
4364 Initialize a new repository in the given directory. If the given
4375 directory does not exist, it will be created.
4365 directory does not exist, it will be created.
4376
4366
4377 If no directory is given, the current directory is used.
4367 If no directory is given, the current directory is used.
4378
4368
4379 It is possible to specify an ``ssh://`` URL as the destination.
4369 It is possible to specify an ``ssh://`` URL as the destination.
4380 See :hg:`help urls` for more information.
4370 See :hg:`help urls` for more information.
4381
4371
4382 Returns 0 on success.
4372 Returns 0 on success.
4383 """
4373 """
4384 opts = pycompat.byteskwargs(opts)
4374 opts = pycompat.byteskwargs(opts)
4385 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4375 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4386
4376
4387
4377
4388 @command(
4378 @command(
4389 b'locate',
4379 b'locate',
4390 [
4380 [
4391 (
4381 (
4392 b'r',
4382 b'r',
4393 b'rev',
4383 b'rev',
4394 b'',
4384 b'',
4395 _(b'search the repository as it is in REV'),
4385 _(b'search the repository as it is in REV'),
4396 _(b'REV'),
4386 _(b'REV'),
4397 ),
4387 ),
4398 (
4388 (
4399 b'0',
4389 b'0',
4400 b'print0',
4390 b'print0',
4401 None,
4391 None,
4402 _(b'end filenames with NUL, for use with xargs'),
4392 _(b'end filenames with NUL, for use with xargs'),
4403 ),
4393 ),
4404 (
4394 (
4405 b'f',
4395 b'f',
4406 b'fullpath',
4396 b'fullpath',
4407 None,
4397 None,
4408 _(b'print complete paths from the filesystem root'),
4398 _(b'print complete paths from the filesystem root'),
4409 ),
4399 ),
4410 ]
4400 ]
4411 + walkopts,
4401 + walkopts,
4412 _(b'[OPTION]... [PATTERN]...'),
4402 _(b'[OPTION]... [PATTERN]...'),
4413 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4403 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4414 )
4404 )
4415 def locate(ui, repo, *pats, **opts):
4405 def locate(ui, repo, *pats, **opts):
4416 """locate files matching specific patterns (DEPRECATED)
4406 """locate files matching specific patterns (DEPRECATED)
4417
4407
4418 Print files under Mercurial control in the working directory whose
4408 Print files under Mercurial control in the working directory whose
4419 names match the given patterns.
4409 names match the given patterns.
4420
4410
4421 By default, this command searches all directories in the working
4411 By default, this command searches all directories in the working
4422 directory. To search just the current directory and its
4412 directory. To search just the current directory and its
4423 subdirectories, use "--include .".
4413 subdirectories, use "--include .".
4424
4414
4425 If no patterns are given to match, this command prints the names
4415 If no patterns are given to match, this command prints the names
4426 of all files under Mercurial control in the working directory.
4416 of all files under Mercurial control in the working directory.
4427
4417
4428 If you want to feed the output of this command into the "xargs"
4418 If you want to feed the output of this command into the "xargs"
4429 command, use the -0 option to both this command and "xargs". This
4419 command, use the -0 option to both this command and "xargs". This
4430 will avoid the problem of "xargs" treating single filenames that
4420 will avoid the problem of "xargs" treating single filenames that
4431 contain whitespace as multiple filenames.
4421 contain whitespace as multiple filenames.
4432
4422
4433 See :hg:`help files` for a more versatile command.
4423 See :hg:`help files` for a more versatile command.
4434
4424
4435 Returns 0 if a match is found, 1 otherwise.
4425 Returns 0 if a match is found, 1 otherwise.
4436 """
4426 """
4437 opts = pycompat.byteskwargs(opts)
4427 opts = pycompat.byteskwargs(opts)
4438 if opts.get(b'print0'):
4428 if opts.get(b'print0'):
4439 end = b'\0'
4429 end = b'\0'
4440 else:
4430 else:
4441 end = b'\n'
4431 end = b'\n'
4442 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4432 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4443
4433
4444 ret = 1
4434 ret = 1
4445 m = scmutil.match(
4435 m = scmutil.match(
4446 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4436 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4447 )
4437 )
4448
4438
4449 ui.pager(b'locate')
4439 ui.pager(b'locate')
4450 if ctx.rev() is None:
4440 if ctx.rev() is None:
4451 # When run on the working copy, "locate" includes removed files, so
4441 # When run on the working copy, "locate" includes removed files, so
4452 # we get the list of files from the dirstate.
4442 # we get the list of files from the dirstate.
4453 filesgen = sorted(repo.dirstate.matches(m))
4443 filesgen = sorted(repo.dirstate.matches(m))
4454 else:
4444 else:
4455 filesgen = ctx.matches(m)
4445 filesgen = ctx.matches(m)
4456 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4446 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4457 for abs in filesgen:
4447 for abs in filesgen:
4458 if opts.get(b'fullpath'):
4448 if opts.get(b'fullpath'):
4459 ui.write(repo.wjoin(abs), end)
4449 ui.write(repo.wjoin(abs), end)
4460 else:
4450 else:
4461 ui.write(uipathfn(abs), end)
4451 ui.write(uipathfn(abs), end)
4462 ret = 0
4452 ret = 0
4463
4453
4464 return ret
4454 return ret
4465
4455
4466
4456
4467 @command(
4457 @command(
4468 b'log|history',
4458 b'log|history',
4469 [
4459 [
4470 (
4460 (
4471 b'f',
4461 b'f',
4472 b'follow',
4462 b'follow',
4473 None,
4463 None,
4474 _(
4464 _(
4475 b'follow changeset history, or file history across copies and renames'
4465 b'follow changeset history, or file history across copies and renames'
4476 ),
4466 ),
4477 ),
4467 ),
4478 (
4468 (
4479 b'',
4469 b'',
4480 b'follow-first',
4470 b'follow-first',
4481 None,
4471 None,
4482 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4472 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4483 ),
4473 ),
4484 (
4474 (
4485 b'd',
4475 b'd',
4486 b'date',
4476 b'date',
4487 b'',
4477 b'',
4488 _(b'show revisions matching date spec'),
4478 _(b'show revisions matching date spec'),
4489 _(b'DATE'),
4479 _(b'DATE'),
4490 ),
4480 ),
4491 (b'C', b'copies', None, _(b'show copied files')),
4481 (b'C', b'copies', None, _(b'show copied files')),
4492 (
4482 (
4493 b'k',
4483 b'k',
4494 b'keyword',
4484 b'keyword',
4495 [],
4485 [],
4496 _(b'do case-insensitive search for a given text'),
4486 _(b'do case-insensitive search for a given text'),
4497 _(b'TEXT'),
4487 _(b'TEXT'),
4498 ),
4488 ),
4499 (
4489 (
4500 b'r',
4490 b'r',
4501 b'rev',
4491 b'rev',
4502 [],
4492 [],
4503 _(b'show the specified revision or revset'),
4493 _(b'show the specified revision or revset'),
4504 _(b'REV'),
4494 _(b'REV'),
4505 ),
4495 ),
4506 (
4496 (
4507 b'L',
4497 b'L',
4508 b'line-range',
4498 b'line-range',
4509 [],
4499 [],
4510 _(b'follow line range of specified file (EXPERIMENTAL)'),
4500 _(b'follow line range of specified file (EXPERIMENTAL)'),
4511 _(b'FILE,RANGE'),
4501 _(b'FILE,RANGE'),
4512 ),
4502 ),
4513 (
4503 (
4514 b'',
4504 b'',
4515 b'removed',
4505 b'removed',
4516 None,
4506 None,
4517 _(b'include revisions where files were removed'),
4507 _(b'include revisions where files were removed'),
4518 ),
4508 ),
4519 (
4509 (
4520 b'm',
4510 b'm',
4521 b'only-merges',
4511 b'only-merges',
4522 None,
4512 None,
4523 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4513 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4524 ),
4514 ),
4525 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4515 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4526 (
4516 (
4527 b'',
4517 b'',
4528 b'only-branch',
4518 b'only-branch',
4529 [],
4519 [],
4530 _(
4520 _(
4531 b'show only changesets within the given named branch (DEPRECATED)'
4521 b'show only changesets within the given named branch (DEPRECATED)'
4532 ),
4522 ),
4533 _(b'BRANCH'),
4523 _(b'BRANCH'),
4534 ),
4524 ),
4535 (
4525 (
4536 b'b',
4526 b'b',
4537 b'branch',
4527 b'branch',
4538 [],
4528 [],
4539 _(b'show changesets within the given named branch'),
4529 _(b'show changesets within the given named branch'),
4540 _(b'BRANCH'),
4530 _(b'BRANCH'),
4541 ),
4531 ),
4542 (
4532 (
4543 b'P',
4533 b'P',
4544 b'prune',
4534 b'prune',
4545 [],
4535 [],
4546 _(b'do not display revision or any of its ancestors'),
4536 _(b'do not display revision or any of its ancestors'),
4547 _(b'REV'),
4537 _(b'REV'),
4548 ),
4538 ),
4549 ]
4539 ]
4550 + logopts
4540 + logopts
4551 + walkopts,
4541 + walkopts,
4552 _(b'[OPTION]... [FILE]'),
4542 _(b'[OPTION]... [FILE]'),
4553 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4543 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4554 helpbasic=True,
4544 helpbasic=True,
4555 inferrepo=True,
4545 inferrepo=True,
4556 intents={INTENT_READONLY},
4546 intents={INTENT_READONLY},
4557 )
4547 )
4558 def log(ui, repo, *pats, **opts):
4548 def log(ui, repo, *pats, **opts):
4559 """show revision history of entire repository or files
4549 """show revision history of entire repository or files
4560
4550
4561 Print the revision history of the specified files or the entire
4551 Print the revision history of the specified files or the entire
4562 project.
4552 project.
4563
4553
4564 If no revision range is specified, the default is ``tip:0`` unless
4554 If no revision range is specified, the default is ``tip:0`` unless
4565 --follow is set, in which case the working directory parent is
4555 --follow is set, in which case the working directory parent is
4566 used as the starting revision.
4556 used as the starting revision.
4567
4557
4568 File history is shown without following rename or copy history of
4558 File history is shown without following rename or copy history of
4569 files. Use -f/--follow with a filename to follow history across
4559 files. Use -f/--follow with a filename to follow history across
4570 renames and copies. --follow without a filename will only show
4560 renames and copies. --follow without a filename will only show
4571 ancestors of the starting revision.
4561 ancestors of the starting revision.
4572
4562
4573 By default this command prints revision number and changeset id,
4563 By default this command prints revision number and changeset id,
4574 tags, non-trivial parents, user, date and time, and a summary for
4564 tags, non-trivial parents, user, date and time, and a summary for
4575 each commit. When the -v/--verbose switch is used, the list of
4565 each commit. When the -v/--verbose switch is used, the list of
4576 changed files and full commit message are shown.
4566 changed files and full commit message are shown.
4577
4567
4578 With --graph the revisions are shown as an ASCII art DAG with the most
4568 With --graph the revisions are shown as an ASCII art DAG with the most
4579 recent changeset at the top.
4569 recent changeset at the top.
4580 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4570 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4581 involved in an unresolved merge conflict, '_' closes a branch,
4571 involved in an unresolved merge conflict, '_' closes a branch,
4582 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4572 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4583 changeset from the lines below is a parent of the 'o' merge on the same
4573 changeset from the lines below is a parent of the 'o' merge on the same
4584 line.
4574 line.
4585 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4575 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4586 of a '|' indicates one or more revisions in a path are omitted.
4576 of a '|' indicates one or more revisions in a path are omitted.
4587
4577
4588 .. container:: verbose
4578 .. container:: verbose
4589
4579
4590 Use -L/--line-range FILE,M:N options to follow the history of lines
4580 Use -L/--line-range FILE,M:N options to follow the history of lines
4591 from M to N in FILE. With -p/--patch only diff hunks affecting
4581 from M to N in FILE. With -p/--patch only diff hunks affecting
4592 specified line range will be shown. This option requires --follow;
4582 specified line range will be shown. This option requires --follow;
4593 it can be specified multiple times. Currently, this option is not
4583 it can be specified multiple times. Currently, this option is not
4594 compatible with --graph. This option is experimental.
4584 compatible with --graph. This option is experimental.
4595
4585
4596 .. note::
4586 .. note::
4597
4587
4598 :hg:`log --patch` may generate unexpected diff output for merge
4588 :hg:`log --patch` may generate unexpected diff output for merge
4599 changesets, as it will only compare the merge changeset against
4589 changesets, as it will only compare the merge changeset against
4600 its first parent. Also, only files different from BOTH parents
4590 its first parent. Also, only files different from BOTH parents
4601 will appear in files:.
4591 will appear in files:.
4602
4592
4603 .. note::
4593 .. note::
4604
4594
4605 For performance reasons, :hg:`log FILE` may omit duplicate changes
4595 For performance reasons, :hg:`log FILE` may omit duplicate changes
4606 made on branches and will not show removals or mode changes. To
4596 made on branches and will not show removals or mode changes. To
4607 see all such changes, use the --removed switch.
4597 see all such changes, use the --removed switch.
4608
4598
4609 .. container:: verbose
4599 .. container:: verbose
4610
4600
4611 .. note::
4601 .. note::
4612
4602
4613 The history resulting from -L/--line-range options depends on diff
4603 The history resulting from -L/--line-range options depends on diff
4614 options; for instance if white-spaces are ignored, respective changes
4604 options; for instance if white-spaces are ignored, respective changes
4615 with only white-spaces in specified line range will not be listed.
4605 with only white-spaces in specified line range will not be listed.
4616
4606
4617 .. container:: verbose
4607 .. container:: verbose
4618
4608
4619 Some examples:
4609 Some examples:
4620
4610
4621 - changesets with full descriptions and file lists::
4611 - changesets with full descriptions and file lists::
4622
4612
4623 hg log -v
4613 hg log -v
4624
4614
4625 - changesets ancestral to the working directory::
4615 - changesets ancestral to the working directory::
4626
4616
4627 hg log -f
4617 hg log -f
4628
4618
4629 - last 10 commits on the current branch::
4619 - last 10 commits on the current branch::
4630
4620
4631 hg log -l 10 -b .
4621 hg log -l 10 -b .
4632
4622
4633 - changesets showing all modifications of a file, including removals::
4623 - changesets showing all modifications of a file, including removals::
4634
4624
4635 hg log --removed file.c
4625 hg log --removed file.c
4636
4626
4637 - all changesets that touch a directory, with diffs, excluding merges::
4627 - all changesets that touch a directory, with diffs, excluding merges::
4638
4628
4639 hg log -Mp lib/
4629 hg log -Mp lib/
4640
4630
4641 - all revision numbers that match a keyword::
4631 - all revision numbers that match a keyword::
4642
4632
4643 hg log -k bug --template "{rev}\\n"
4633 hg log -k bug --template "{rev}\\n"
4644
4634
4645 - the full hash identifier of the working directory parent::
4635 - the full hash identifier of the working directory parent::
4646
4636
4647 hg log -r . --template "{node}\\n"
4637 hg log -r . --template "{node}\\n"
4648
4638
4649 - list available log templates::
4639 - list available log templates::
4650
4640
4651 hg log -T list
4641 hg log -T list
4652
4642
4653 - check if a given changeset is included in a tagged release::
4643 - check if a given changeset is included in a tagged release::
4654
4644
4655 hg log -r "a21ccf and ancestor(1.9)"
4645 hg log -r "a21ccf and ancestor(1.9)"
4656
4646
4657 - find all changesets by some user in a date range::
4647 - find all changesets by some user in a date range::
4658
4648
4659 hg log -k alice -d "may 2008 to jul 2008"
4649 hg log -k alice -d "may 2008 to jul 2008"
4660
4650
4661 - summary of all changesets after the last tag::
4651 - summary of all changesets after the last tag::
4662
4652
4663 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4653 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4664
4654
4665 - changesets touching lines 13 to 23 for file.c::
4655 - changesets touching lines 13 to 23 for file.c::
4666
4656
4667 hg log -L file.c,13:23
4657 hg log -L file.c,13:23
4668
4658
4669 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4659 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4670 main.c with patch::
4660 main.c with patch::
4671
4661
4672 hg log -L file.c,13:23 -L main.c,2:6 -p
4662 hg log -L file.c,13:23 -L main.c,2:6 -p
4673
4663
4674 See :hg:`help dates` for a list of formats valid for -d/--date.
4664 See :hg:`help dates` for a list of formats valid for -d/--date.
4675
4665
4676 See :hg:`help revisions` for more about specifying and ordering
4666 See :hg:`help revisions` for more about specifying and ordering
4677 revisions.
4667 revisions.
4678
4668
4679 See :hg:`help templates` for more about pre-packaged styles and
4669 See :hg:`help templates` for more about pre-packaged styles and
4680 specifying custom templates. The default template used by the log
4670 specifying custom templates. The default template used by the log
4681 command can be customized via the ``ui.logtemplate`` configuration
4671 command can be customized via the ``ui.logtemplate`` configuration
4682 setting.
4672 setting.
4683
4673
4684 Returns 0 on success.
4674 Returns 0 on success.
4685
4675
4686 """
4676 """
4687 opts = pycompat.byteskwargs(opts)
4677 opts = pycompat.byteskwargs(opts)
4688 linerange = opts.get(b'line_range')
4678 linerange = opts.get(b'line_range')
4689
4679
4690 if linerange and not opts.get(b'follow'):
4680 if linerange and not opts.get(b'follow'):
4691 raise error.Abort(_(b'--line-range requires --follow'))
4681 raise error.Abort(_(b'--line-range requires --follow'))
4692
4682
4693 if linerange and pats:
4683 if linerange and pats:
4694 # TODO: take pats as patterns with no line-range filter
4684 # TODO: take pats as patterns with no line-range filter
4695 raise error.Abort(
4685 raise error.Abort(
4696 _(b'FILE arguments are not compatible with --line-range option')
4686 _(b'FILE arguments are not compatible with --line-range option')
4697 )
4687 )
4698
4688
4699 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4689 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4700 revs, differ = logcmdutil.getrevs(
4690 revs, differ = logcmdutil.getrevs(
4701 repo, logcmdutil.parseopts(ui, pats, opts)
4691 repo, logcmdutil.parseopts(ui, pats, opts)
4702 )
4692 )
4703 if linerange:
4693 if linerange:
4704 # TODO: should follow file history from logcmdutil._initialrevs(),
4694 # TODO: should follow file history from logcmdutil._initialrevs(),
4705 # then filter the result by logcmdutil._makerevset() and --limit
4695 # then filter the result by logcmdutil._makerevset() and --limit
4706 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4696 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4707
4697
4708 getcopies = None
4698 getcopies = None
4709 if opts.get(b'copies'):
4699 if opts.get(b'copies'):
4710 endrev = None
4700 endrev = None
4711 if revs:
4701 if revs:
4712 endrev = revs.max() + 1
4702 endrev = revs.max() + 1
4713 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4703 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4714
4704
4715 ui.pager(b'log')
4705 ui.pager(b'log')
4716 displayer = logcmdutil.changesetdisplayer(
4706 displayer = logcmdutil.changesetdisplayer(
4717 ui, repo, opts, differ, buffered=True
4707 ui, repo, opts, differ, buffered=True
4718 )
4708 )
4719 if opts.get(b'graph'):
4709 if opts.get(b'graph'):
4720 displayfn = logcmdutil.displaygraphrevs
4710 displayfn = logcmdutil.displaygraphrevs
4721 else:
4711 else:
4722 displayfn = logcmdutil.displayrevs
4712 displayfn = logcmdutil.displayrevs
4723 displayfn(ui, repo, revs, displayer, getcopies)
4713 displayfn(ui, repo, revs, displayer, getcopies)
4724
4714
4725
4715
4726 @command(
4716 @command(
4727 b'manifest',
4717 b'manifest',
4728 [
4718 [
4729 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4719 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4730 (b'', b'all', False, _(b"list files from all revisions")),
4720 (b'', b'all', False, _(b"list files from all revisions")),
4731 ]
4721 ]
4732 + formatteropts,
4722 + formatteropts,
4733 _(b'[-r REV]'),
4723 _(b'[-r REV]'),
4734 helpcategory=command.CATEGORY_MAINTENANCE,
4724 helpcategory=command.CATEGORY_MAINTENANCE,
4735 intents={INTENT_READONLY},
4725 intents={INTENT_READONLY},
4736 )
4726 )
4737 def manifest(ui, repo, node=None, rev=None, **opts):
4727 def manifest(ui, repo, node=None, rev=None, **opts):
4738 """output the current or given revision of the project manifest
4728 """output the current or given revision of the project manifest
4739
4729
4740 Print a list of version controlled files for the given revision.
4730 Print a list of version controlled files for the given revision.
4741 If no revision is given, the first parent of the working directory
4731 If no revision is given, the first parent of the working directory
4742 is used, or the null revision if no revision is checked out.
4732 is used, or the null revision if no revision is checked out.
4743
4733
4744 With -v, print file permissions, symlink and executable bits.
4734 With -v, print file permissions, symlink and executable bits.
4745 With --debug, print file revision hashes.
4735 With --debug, print file revision hashes.
4746
4736
4747 If option --all is specified, the list of all files from all revisions
4737 If option --all is specified, the list of all files from all revisions
4748 is printed. This includes deleted and renamed files.
4738 is printed. This includes deleted and renamed files.
4749
4739
4750 Returns 0 on success.
4740 Returns 0 on success.
4751 """
4741 """
4752 opts = pycompat.byteskwargs(opts)
4742 opts = pycompat.byteskwargs(opts)
4753 fm = ui.formatter(b'manifest', opts)
4743 fm = ui.formatter(b'manifest', opts)
4754
4744
4755 if opts.get(b'all'):
4745 if opts.get(b'all'):
4756 if rev or node:
4746 if rev or node:
4757 raise error.Abort(_(b"can't specify a revision with --all"))
4747 raise error.Abort(_(b"can't specify a revision with --all"))
4758
4748
4759 res = set()
4749 res = set()
4760 for rev in repo:
4750 for rev in repo:
4761 ctx = repo[rev]
4751 ctx = repo[rev]
4762 res |= set(ctx.files())
4752 res |= set(ctx.files())
4763
4753
4764 ui.pager(b'manifest')
4754 ui.pager(b'manifest')
4765 for f in sorted(res):
4755 for f in sorted(res):
4766 fm.startitem()
4756 fm.startitem()
4767 fm.write(b"path", b'%s\n', f)
4757 fm.write(b"path", b'%s\n', f)
4768 fm.end()
4758 fm.end()
4769 return
4759 return
4770
4760
4771 if rev and node:
4761 if rev and node:
4772 raise error.Abort(_(b"please specify just one revision"))
4762 raise error.Abort(_(b"please specify just one revision"))
4773
4763
4774 if not node:
4764 if not node:
4775 node = rev
4765 node = rev
4776
4766
4777 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4767 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4778 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4768 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4779 if node:
4769 if node:
4780 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4770 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4781 ctx = scmutil.revsingle(repo, node)
4771 ctx = scmutil.revsingle(repo, node)
4782 mf = ctx.manifest()
4772 mf = ctx.manifest()
4783 ui.pager(b'manifest')
4773 ui.pager(b'manifest')
4784 for f in ctx:
4774 for f in ctx:
4785 fm.startitem()
4775 fm.startitem()
4786 fm.context(ctx=ctx)
4776 fm.context(ctx=ctx)
4787 fl = ctx[f].flags()
4777 fl = ctx[f].flags()
4788 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4778 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4789 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4779 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4790 fm.write(b'path', b'%s\n', f)
4780 fm.write(b'path', b'%s\n', f)
4791 fm.end()
4781 fm.end()
4792
4782
4793
4783
4794 @command(
4784 @command(
4795 b'merge',
4785 b'merge',
4796 [
4786 [
4797 (
4787 (
4798 b'f',
4788 b'f',
4799 b'force',
4789 b'force',
4800 None,
4790 None,
4801 _(b'force a merge including outstanding changes (DEPRECATED)'),
4791 _(b'force a merge including outstanding changes (DEPRECATED)'),
4802 ),
4792 ),
4803 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4793 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4804 (
4794 (
4805 b'P',
4795 b'P',
4806 b'preview',
4796 b'preview',
4807 None,
4797 None,
4808 _(b'review revisions to merge (no merge is performed)'),
4798 _(b'review revisions to merge (no merge is performed)'),
4809 ),
4799 ),
4810 (b'', b'abort', None, _(b'abort the ongoing merge')),
4800 (b'', b'abort', None, _(b'abort the ongoing merge')),
4811 ]
4801 ]
4812 + mergetoolopts,
4802 + mergetoolopts,
4813 _(b'[-P] [[-r] REV]'),
4803 _(b'[-P] [[-r] REV]'),
4814 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4804 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4815 helpbasic=True,
4805 helpbasic=True,
4816 )
4806 )
4817 def merge(ui, repo, node=None, **opts):
4807 def merge(ui, repo, node=None, **opts):
4818 """merge another revision into working directory
4808 """merge another revision into working directory
4819
4809
4820 The current working directory is updated with all changes made in
4810 The current working directory is updated with all changes made in
4821 the requested revision since the last common predecessor revision.
4811 the requested revision since the last common predecessor revision.
4822
4812
4823 Files that changed between either parent are marked as changed for
4813 Files that changed between either parent are marked as changed for
4824 the next commit and a commit must be performed before any further
4814 the next commit and a commit must be performed before any further
4825 updates to the repository are allowed. The next commit will have
4815 updates to the repository are allowed. The next commit will have
4826 two parents.
4816 two parents.
4827
4817
4828 ``--tool`` can be used to specify the merge tool used for file
4818 ``--tool`` can be used to specify the merge tool used for file
4829 merges. It overrides the HGMERGE environment variable and your
4819 merges. It overrides the HGMERGE environment variable and your
4830 configuration files. See :hg:`help merge-tools` for options.
4820 configuration files. See :hg:`help merge-tools` for options.
4831
4821
4832 If no revision is specified, the working directory's parent is a
4822 If no revision is specified, the working directory's parent is a
4833 head revision, and the current branch contains exactly one other
4823 head revision, and the current branch contains exactly one other
4834 head, the other head is merged with by default. Otherwise, an
4824 head, the other head is merged with by default. Otherwise, an
4835 explicit revision with which to merge must be provided.
4825 explicit revision with which to merge must be provided.
4836
4826
4837 See :hg:`help resolve` for information on handling file conflicts.
4827 See :hg:`help resolve` for information on handling file conflicts.
4838
4828
4839 To undo an uncommitted merge, use :hg:`merge --abort` which
4829 To undo an uncommitted merge, use :hg:`merge --abort` which
4840 will check out a clean copy of the original merge parent, losing
4830 will check out a clean copy of the original merge parent, losing
4841 all changes.
4831 all changes.
4842
4832
4843 Returns 0 on success, 1 if there are unresolved files.
4833 Returns 0 on success, 1 if there are unresolved files.
4844 """
4834 """
4845
4835
4846 opts = pycompat.byteskwargs(opts)
4836 opts = pycompat.byteskwargs(opts)
4847 abort = opts.get(b'abort')
4837 abort = opts.get(b'abort')
4848 if abort and repo.dirstate.p2() == nullid:
4838 if abort and repo.dirstate.p2() == nullid:
4849 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4839 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4850 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4840 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4851 if abort:
4841 if abort:
4852 state = cmdutil.getunfinishedstate(repo)
4842 state = cmdutil.getunfinishedstate(repo)
4853 if state and state._opname != b'merge':
4843 if state and state._opname != b'merge':
4854 raise error.Abort(
4844 raise error.Abort(
4855 _(b'cannot abort merge with %s in progress') % (state._opname),
4845 _(b'cannot abort merge with %s in progress') % (state._opname),
4856 hint=state.hint(),
4846 hint=state.hint(),
4857 )
4847 )
4858 if node:
4848 if node:
4859 raise error.Abort(_(b"cannot specify a node with --abort"))
4849 raise error.Abort(_(b"cannot specify a node with --abort"))
4860 return hg.abortmerge(repo.ui, repo)
4850 return hg.abortmerge(repo.ui, repo)
4861
4851
4862 if opts.get(b'rev') and node:
4852 if opts.get(b'rev') and node:
4863 raise error.Abort(_(b"please specify just one revision"))
4853 raise error.Abort(_(b"please specify just one revision"))
4864 if not node:
4854 if not node:
4865 node = opts.get(b'rev')
4855 node = opts.get(b'rev')
4866
4856
4867 if node:
4857 if node:
4868 ctx = scmutil.revsingle(repo, node)
4858 ctx = scmutil.revsingle(repo, node)
4869 else:
4859 else:
4870 if ui.configbool(b'commands', b'merge.require-rev'):
4860 if ui.configbool(b'commands', b'merge.require-rev'):
4871 raise error.Abort(
4861 raise error.Abort(
4872 _(
4862 _(
4873 b'configuration requires specifying revision to merge '
4863 b'configuration requires specifying revision to merge '
4874 b'with'
4864 b'with'
4875 )
4865 )
4876 )
4866 )
4877 ctx = repo[destutil.destmerge(repo)]
4867 ctx = repo[destutil.destmerge(repo)]
4878
4868
4879 if ctx.node() is None:
4869 if ctx.node() is None:
4880 raise error.Abort(_(b'merging with the working copy has no effect'))
4870 raise error.Abort(_(b'merging with the working copy has no effect'))
4881
4871
4882 if opts.get(b'preview'):
4872 if opts.get(b'preview'):
4883 # find nodes that are ancestors of p2 but not of p1
4873 # find nodes that are ancestors of p2 but not of p1
4884 p1 = repo[b'.'].node()
4874 p1 = repo[b'.'].node()
4885 p2 = ctx.node()
4875 p2 = ctx.node()
4886 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4876 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4887
4877
4888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4878 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4889 for node in nodes:
4879 for node in nodes:
4890 displayer.show(repo[node])
4880 displayer.show(repo[node])
4891 displayer.close()
4881 displayer.close()
4892 return 0
4882 return 0
4893
4883
4894 # ui.forcemerge is an internal variable, do not document
4884 # ui.forcemerge is an internal variable, do not document
4895 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4885 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4896 with ui.configoverride(overrides, b'merge'):
4886 with ui.configoverride(overrides, b'merge'):
4897 force = opts.get(b'force')
4887 force = opts.get(b'force')
4898 labels = [b'working copy', b'merge rev']
4888 labels = [b'working copy', b'merge rev']
4899 return hg.merge(ctx, force=force, labels=labels)
4889 return hg.merge(ctx, force=force, labels=labels)
4900
4890
4901
4891
4902 statemod.addunfinished(
4892 statemod.addunfinished(
4903 b'merge',
4893 b'merge',
4904 fname=None,
4894 fname=None,
4905 clearable=True,
4895 clearable=True,
4906 allowcommit=True,
4896 allowcommit=True,
4907 cmdmsg=_(b'outstanding uncommitted merge'),
4897 cmdmsg=_(b'outstanding uncommitted merge'),
4908 abortfunc=hg.abortmerge,
4898 abortfunc=hg.abortmerge,
4909 statushint=_(
4899 statushint=_(
4910 b'To continue: hg commit\nTo abort: hg merge --abort'
4900 b'To continue: hg commit\nTo abort: hg merge --abort'
4911 ),
4901 ),
4912 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4902 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4913 )
4903 )
4914
4904
4915
4905
4916 @command(
4906 @command(
4917 b'outgoing|out',
4907 b'outgoing|out',
4918 [
4908 [
4919 (
4909 (
4920 b'f',
4910 b'f',
4921 b'force',
4911 b'force',
4922 None,
4912 None,
4923 _(b'run even when the destination is unrelated'),
4913 _(b'run even when the destination is unrelated'),
4924 ),
4914 ),
4925 (
4915 (
4926 b'r',
4916 b'r',
4927 b'rev',
4917 b'rev',
4928 [],
4918 [],
4929 _(b'a changeset intended to be included in the destination'),
4919 _(b'a changeset intended to be included in the destination'),
4930 _(b'REV'),
4920 _(b'REV'),
4931 ),
4921 ),
4932 (b'n', b'newest-first', None, _(b'show newest record first')),
4922 (b'n', b'newest-first', None, _(b'show newest record first')),
4933 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4923 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4934 (
4924 (
4935 b'b',
4925 b'b',
4936 b'branch',
4926 b'branch',
4937 [],
4927 [],
4938 _(b'a specific branch you would like to push'),
4928 _(b'a specific branch you would like to push'),
4939 _(b'BRANCH'),
4929 _(b'BRANCH'),
4940 ),
4930 ),
4941 ]
4931 ]
4942 + logopts
4932 + logopts
4943 + remoteopts
4933 + remoteopts
4944 + subrepoopts,
4934 + subrepoopts,
4945 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4935 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4946 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4936 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4947 )
4937 )
4948 def outgoing(ui, repo, dest=None, **opts):
4938 def outgoing(ui, repo, dest=None, **opts):
4949 """show changesets not found in the destination
4939 """show changesets not found in the destination
4950
4940
4951 Show changesets not found in the specified destination repository
4941 Show changesets not found in the specified destination repository
4952 or the default push location. These are the changesets that would
4942 or the default push location. These are the changesets that would
4953 be pushed if a push was requested.
4943 be pushed if a push was requested.
4954
4944
4955 See pull for details of valid destination formats.
4945 See pull for details of valid destination formats.
4956
4946
4957 .. container:: verbose
4947 .. container:: verbose
4958
4948
4959 With -B/--bookmarks, the result of bookmark comparison between
4949 With -B/--bookmarks, the result of bookmark comparison between
4960 local and remote repositories is displayed. With -v/--verbose,
4950 local and remote repositories is displayed. With -v/--verbose,
4961 status is also displayed for each bookmark like below::
4951 status is also displayed for each bookmark like below::
4962
4952
4963 BM1 01234567890a added
4953 BM1 01234567890a added
4964 BM2 deleted
4954 BM2 deleted
4965 BM3 234567890abc advanced
4955 BM3 234567890abc advanced
4966 BM4 34567890abcd diverged
4956 BM4 34567890abcd diverged
4967 BM5 4567890abcde changed
4957 BM5 4567890abcde changed
4968
4958
4969 The action taken when pushing depends on the
4959 The action taken when pushing depends on the
4970 status of each bookmark:
4960 status of each bookmark:
4971
4961
4972 :``added``: push with ``-B`` will create it
4962 :``added``: push with ``-B`` will create it
4973 :``deleted``: push with ``-B`` will delete it
4963 :``deleted``: push with ``-B`` will delete it
4974 :``advanced``: push will update it
4964 :``advanced``: push will update it
4975 :``diverged``: push with ``-B`` will update it
4965 :``diverged``: push with ``-B`` will update it
4976 :``changed``: push with ``-B`` will update it
4966 :``changed``: push with ``-B`` will update it
4977
4967
4978 From the point of view of pushing behavior, bookmarks
4968 From the point of view of pushing behavior, bookmarks
4979 existing only in the remote repository are treated as
4969 existing only in the remote repository are treated as
4980 ``deleted``, even if it is in fact added remotely.
4970 ``deleted``, even if it is in fact added remotely.
4981
4971
4982 Returns 0 if there are outgoing changes, 1 otherwise.
4972 Returns 0 if there are outgoing changes, 1 otherwise.
4983 """
4973 """
4984 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4974 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4985 # style URLs, so don't overwrite dest.
4975 # style URLs, so don't overwrite dest.
4986 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4976 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4987 if not path:
4977 if not path:
4988 raise error.Abort(
4978 raise error.Abort(
4989 _(b'default repository not configured!'),
4979 _(b'default repository not configured!'),
4990 hint=_(b"see 'hg help config.paths'"),
4980 hint=_(b"see 'hg help config.paths'"),
4991 )
4981 )
4992
4982
4993 opts = pycompat.byteskwargs(opts)
4983 opts = pycompat.byteskwargs(opts)
4994 if opts.get(b'graph'):
4984 if opts.get(b'graph'):
4995 logcmdutil.checkunsupportedgraphflags([], opts)
4985 logcmdutil.checkunsupportedgraphflags([], opts)
4996 o, other = hg._outgoing(ui, repo, dest, opts)
4986 o, other = hg._outgoing(ui, repo, dest, opts)
4997 if not o:
4987 if not o:
4998 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4988 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4999 return
4989 return
5000
4990
5001 revdag = logcmdutil.graphrevs(repo, o, opts)
4991 revdag = logcmdutil.graphrevs(repo, o, opts)
5002 ui.pager(b'outgoing')
4992 ui.pager(b'outgoing')
5003 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4993 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5004 logcmdutil.displaygraph(
4994 logcmdutil.displaygraph(
5005 ui, repo, revdag, displayer, graphmod.asciiedges
4995 ui, repo, revdag, displayer, graphmod.asciiedges
5006 )
4996 )
5007 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4997 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5008 return 0
4998 return 0
5009
4999
5010 if opts.get(b'bookmarks'):
5000 if opts.get(b'bookmarks'):
5011 dest = path.pushloc or path.loc
5001 dest = path.pushloc or path.loc
5012 other = hg.peer(repo, opts, dest)
5002 other = hg.peer(repo, opts, dest)
5013 if b'bookmarks' not in other.listkeys(b'namespaces'):
5003 if b'bookmarks' not in other.listkeys(b'namespaces'):
5014 ui.warn(_(b"remote doesn't support bookmarks\n"))
5004 ui.warn(_(b"remote doesn't support bookmarks\n"))
5015 return 0
5005 return 0
5016 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5006 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5017 ui.pager(b'outgoing')
5007 ui.pager(b'outgoing')
5018 return bookmarks.outgoing(ui, repo, other)
5008 return bookmarks.outgoing(ui, repo, other)
5019
5009
5020 repo._subtoppath = path.pushloc or path.loc
5010 repo._subtoppath = path.pushloc or path.loc
5021 try:
5011 try:
5022 return hg.outgoing(ui, repo, dest, opts)
5012 return hg.outgoing(ui, repo, dest, opts)
5023 finally:
5013 finally:
5024 del repo._subtoppath
5014 del repo._subtoppath
5025
5015
5026
5016
5027 @command(
5017 @command(
5028 b'parents',
5018 b'parents',
5029 [
5019 [
5030 (
5020 (
5031 b'r',
5021 b'r',
5032 b'rev',
5022 b'rev',
5033 b'',
5023 b'',
5034 _(b'show parents of the specified revision'),
5024 _(b'show parents of the specified revision'),
5035 _(b'REV'),
5025 _(b'REV'),
5036 ),
5026 ),
5037 ]
5027 ]
5038 + templateopts,
5028 + templateopts,
5039 _(b'[-r REV] [FILE]'),
5029 _(b'[-r REV] [FILE]'),
5040 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5030 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5041 inferrepo=True,
5031 inferrepo=True,
5042 )
5032 )
5043 def parents(ui, repo, file_=None, **opts):
5033 def parents(ui, repo, file_=None, **opts):
5044 """show the parents of the working directory or revision (DEPRECATED)
5034 """show the parents of the working directory or revision (DEPRECATED)
5045
5035
5046 Print the working directory's parent revisions. If a revision is
5036 Print the working directory's parent revisions. If a revision is
5047 given via -r/--rev, the parent of that revision will be printed.
5037 given via -r/--rev, the parent of that revision will be printed.
5048 If a file argument is given, the revision in which the file was
5038 If a file argument is given, the revision in which the file was
5049 last changed (before the working directory revision or the
5039 last changed (before the working directory revision or the
5050 argument to --rev if given) is printed.
5040 argument to --rev if given) is printed.
5051
5041
5052 This command is equivalent to::
5042 This command is equivalent to::
5053
5043
5054 hg log -r "p1()+p2()" or
5044 hg log -r "p1()+p2()" or
5055 hg log -r "p1(REV)+p2(REV)" or
5045 hg log -r "p1(REV)+p2(REV)" or
5056 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5046 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5057 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5047 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5058
5048
5059 See :hg:`summary` and :hg:`help revsets` for related information.
5049 See :hg:`summary` and :hg:`help revsets` for related information.
5060
5050
5061 Returns 0 on success.
5051 Returns 0 on success.
5062 """
5052 """
5063
5053
5064 opts = pycompat.byteskwargs(opts)
5054 opts = pycompat.byteskwargs(opts)
5065 rev = opts.get(b'rev')
5055 rev = opts.get(b'rev')
5066 if rev:
5056 if rev:
5067 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5057 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5068 ctx = scmutil.revsingle(repo, rev, None)
5058 ctx = scmutil.revsingle(repo, rev, None)
5069
5059
5070 if file_:
5060 if file_:
5071 m = scmutil.match(ctx, (file_,), opts)
5061 m = scmutil.match(ctx, (file_,), opts)
5072 if m.anypats() or len(m.files()) != 1:
5062 if m.anypats() or len(m.files()) != 1:
5073 raise error.Abort(_(b'can only specify an explicit filename'))
5063 raise error.Abort(_(b'can only specify an explicit filename'))
5074 file_ = m.files()[0]
5064 file_ = m.files()[0]
5075 filenodes = []
5065 filenodes = []
5076 for cp in ctx.parents():
5066 for cp in ctx.parents():
5077 if not cp:
5067 if not cp:
5078 continue
5068 continue
5079 try:
5069 try:
5080 filenodes.append(cp.filenode(file_))
5070 filenodes.append(cp.filenode(file_))
5081 except error.LookupError:
5071 except error.LookupError:
5082 pass
5072 pass
5083 if not filenodes:
5073 if not filenodes:
5084 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5074 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5085 p = []
5075 p = []
5086 for fn in filenodes:
5076 for fn in filenodes:
5087 fctx = repo.filectx(file_, fileid=fn)
5077 fctx = repo.filectx(file_, fileid=fn)
5088 p.append(fctx.node())
5078 p.append(fctx.node())
5089 else:
5079 else:
5090 p = [cp.node() for cp in ctx.parents()]
5080 p = [cp.node() for cp in ctx.parents()]
5091
5081
5092 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5082 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5093 for n in p:
5083 for n in p:
5094 if n != nullid:
5084 if n != nullid:
5095 displayer.show(repo[n])
5085 displayer.show(repo[n])
5096 displayer.close()
5086 displayer.close()
5097
5087
5098
5088
5099 @command(
5089 @command(
5100 b'paths',
5090 b'paths',
5101 formatteropts,
5091 formatteropts,
5102 _(b'[NAME]'),
5092 _(b'[NAME]'),
5103 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5093 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5104 optionalrepo=True,
5094 optionalrepo=True,
5105 intents={INTENT_READONLY},
5095 intents={INTENT_READONLY},
5106 )
5096 )
5107 def paths(ui, repo, search=None, **opts):
5097 def paths(ui, repo, search=None, **opts):
5108 """show aliases for remote repositories
5098 """show aliases for remote repositories
5109
5099
5110 Show definition of symbolic path name NAME. If no name is given,
5100 Show definition of symbolic path name NAME. If no name is given,
5111 show definition of all available names.
5101 show definition of all available names.
5112
5102
5113 Option -q/--quiet suppresses all output when searching for NAME
5103 Option -q/--quiet suppresses all output when searching for NAME
5114 and shows only the path names when listing all definitions.
5104 and shows only the path names when listing all definitions.
5115
5105
5116 Path names are defined in the [paths] section of your
5106 Path names are defined in the [paths] section of your
5117 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5107 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5118 repository, ``.hg/hgrc`` is used, too.
5108 repository, ``.hg/hgrc`` is used, too.
5119
5109
5120 The path names ``default`` and ``default-push`` have a special
5110 The path names ``default`` and ``default-push`` have a special
5121 meaning. When performing a push or pull operation, they are used
5111 meaning. When performing a push or pull operation, they are used
5122 as fallbacks if no location is specified on the command-line.
5112 as fallbacks if no location is specified on the command-line.
5123 When ``default-push`` is set, it will be used for push and
5113 When ``default-push`` is set, it will be used for push and
5124 ``default`` will be used for pull; otherwise ``default`` is used
5114 ``default`` will be used for pull; otherwise ``default`` is used
5125 as the fallback for both. When cloning a repository, the clone
5115 as the fallback for both. When cloning a repository, the clone
5126 source is written as ``default`` in ``.hg/hgrc``.
5116 source is written as ``default`` in ``.hg/hgrc``.
5127
5117
5128 .. note::
5118 .. note::
5129
5119
5130 ``default`` and ``default-push`` apply to all inbound (e.g.
5120 ``default`` and ``default-push`` apply to all inbound (e.g.
5131 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5121 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5132 and :hg:`bundle`) operations.
5122 and :hg:`bundle`) operations.
5133
5123
5134 See :hg:`help urls` for more information.
5124 See :hg:`help urls` for more information.
5135
5125
5136 .. container:: verbose
5126 .. container:: verbose
5137
5127
5138 Template:
5128 Template:
5139
5129
5140 The following keywords are supported. See also :hg:`help templates`.
5130 The following keywords are supported. See also :hg:`help templates`.
5141
5131
5142 :name: String. Symbolic name of the path alias.
5132 :name: String. Symbolic name of the path alias.
5143 :pushurl: String. URL for push operations.
5133 :pushurl: String. URL for push operations.
5144 :url: String. URL or directory path for the other operations.
5134 :url: String. URL or directory path for the other operations.
5145
5135
5146 Returns 0 on success.
5136 Returns 0 on success.
5147 """
5137 """
5148
5138
5149 opts = pycompat.byteskwargs(opts)
5139 opts = pycompat.byteskwargs(opts)
5150 ui.pager(b'paths')
5140 ui.pager(b'paths')
5151 if search:
5141 if search:
5152 pathitems = [
5142 pathitems = [
5153 (name, path)
5143 (name, path)
5154 for name, path in pycompat.iteritems(ui.paths)
5144 for name, path in pycompat.iteritems(ui.paths)
5155 if name == search
5145 if name == search
5156 ]
5146 ]
5157 else:
5147 else:
5158 pathitems = sorted(pycompat.iteritems(ui.paths))
5148 pathitems = sorted(pycompat.iteritems(ui.paths))
5159
5149
5160 fm = ui.formatter(b'paths', opts)
5150 fm = ui.formatter(b'paths', opts)
5161 if fm.isplain():
5151 if fm.isplain():
5162 hidepassword = util.hidepassword
5152 hidepassword = util.hidepassword
5163 else:
5153 else:
5164 hidepassword = bytes
5154 hidepassword = bytes
5165 if ui.quiet:
5155 if ui.quiet:
5166 namefmt = b'%s\n'
5156 namefmt = b'%s\n'
5167 else:
5157 else:
5168 namefmt = b'%s = '
5158 namefmt = b'%s = '
5169 showsubopts = not search and not ui.quiet
5159 showsubopts = not search and not ui.quiet
5170
5160
5171 for name, path in pathitems:
5161 for name, path in pathitems:
5172 fm.startitem()
5162 fm.startitem()
5173 fm.condwrite(not search, b'name', namefmt, name)
5163 fm.condwrite(not search, b'name', namefmt, name)
5174 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5164 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5175 for subopt, value in sorted(path.suboptions.items()):
5165 for subopt, value in sorted(path.suboptions.items()):
5176 assert subopt not in (b'name', b'url')
5166 assert subopt not in (b'name', b'url')
5177 if showsubopts:
5167 if showsubopts:
5178 fm.plain(b'%s:%s = ' % (name, subopt))
5168 fm.plain(b'%s:%s = ' % (name, subopt))
5179 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5169 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5180
5170
5181 fm.end()
5171 fm.end()
5182
5172
5183 if search and not pathitems:
5173 if search and not pathitems:
5184 if not ui.quiet:
5174 if not ui.quiet:
5185 ui.warn(_(b"not found!\n"))
5175 ui.warn(_(b"not found!\n"))
5186 return 1
5176 return 1
5187 else:
5177 else:
5188 return 0
5178 return 0
5189
5179
5190
5180
5191 @command(
5181 @command(
5192 b'phase',
5182 b'phase',
5193 [
5183 [
5194 (b'p', b'public', False, _(b'set changeset phase to public')),
5184 (b'p', b'public', False, _(b'set changeset phase to public')),
5195 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5185 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5196 (b's', b'secret', False, _(b'set changeset phase to secret')),
5186 (b's', b'secret', False, _(b'set changeset phase to secret')),
5197 (b'f', b'force', False, _(b'allow to move boundary backward')),
5187 (b'f', b'force', False, _(b'allow to move boundary backward')),
5198 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5188 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5199 ],
5189 ],
5200 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5190 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5201 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5191 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5202 )
5192 )
5203 def phase(ui, repo, *revs, **opts):
5193 def phase(ui, repo, *revs, **opts):
5204 """set or show the current phase name
5194 """set or show the current phase name
5205
5195
5206 With no argument, show the phase name of the current revision(s).
5196 With no argument, show the phase name of the current revision(s).
5207
5197
5208 With one of -p/--public, -d/--draft or -s/--secret, change the
5198 With one of -p/--public, -d/--draft or -s/--secret, change the
5209 phase value of the specified revisions.
5199 phase value of the specified revisions.
5210
5200
5211 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5201 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5212 lower phase to a higher phase. Phases are ordered as follows::
5202 lower phase to a higher phase. Phases are ordered as follows::
5213
5203
5214 public < draft < secret
5204 public < draft < secret
5215
5205
5216 Returns 0 on success, 1 if some phases could not be changed.
5206 Returns 0 on success, 1 if some phases could not be changed.
5217
5207
5218 (For more information about the phases concept, see :hg:`help phases`.)
5208 (For more information about the phases concept, see :hg:`help phases`.)
5219 """
5209 """
5220 opts = pycompat.byteskwargs(opts)
5210 opts = pycompat.byteskwargs(opts)
5221 # search for a unique phase argument
5211 # search for a unique phase argument
5222 targetphase = None
5212 targetphase = None
5223 for idx, name in enumerate(phases.cmdphasenames):
5213 for idx, name in enumerate(phases.cmdphasenames):
5224 if opts[name]:
5214 if opts[name]:
5225 if targetphase is not None:
5215 if targetphase is not None:
5226 raise error.Abort(_(b'only one phase can be specified'))
5216 raise error.Abort(_(b'only one phase can be specified'))
5227 targetphase = idx
5217 targetphase = idx
5228
5218
5229 # look for specified revision
5219 # look for specified revision
5230 revs = list(revs)
5220 revs = list(revs)
5231 revs.extend(opts[b'rev'])
5221 revs.extend(opts[b'rev'])
5232 if not revs:
5222 if not revs:
5233 # display both parents as the second parent phase can influence
5223 # display both parents as the second parent phase can influence
5234 # the phase of a merge commit
5224 # the phase of a merge commit
5235 revs = [c.rev() for c in repo[None].parents()]
5225 revs = [c.rev() for c in repo[None].parents()]
5236
5226
5237 revs = scmutil.revrange(repo, revs)
5227 revs = scmutil.revrange(repo, revs)
5238
5228
5239 ret = 0
5229 ret = 0
5240 if targetphase is None:
5230 if targetphase is None:
5241 # display
5231 # display
5242 for r in revs:
5232 for r in revs:
5243 ctx = repo[r]
5233 ctx = repo[r]
5244 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5234 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5245 else:
5235 else:
5246 with repo.lock(), repo.transaction(b"phase") as tr:
5236 with repo.lock(), repo.transaction(b"phase") as tr:
5247 # set phase
5237 # set phase
5248 if not revs:
5238 if not revs:
5249 raise error.Abort(_(b'empty revision set'))
5239 raise error.Abort(_(b'empty revision set'))
5250 nodes = [repo[r].node() for r in revs]
5240 nodes = [repo[r].node() for r in revs]
5251 # moving revision from public to draft may hide them
5241 # moving revision from public to draft may hide them
5252 # We have to check result on an unfiltered repository
5242 # We have to check result on an unfiltered repository
5253 unfi = repo.unfiltered()
5243 unfi = repo.unfiltered()
5254 getphase = unfi._phasecache.phase
5244 getphase = unfi._phasecache.phase
5255 olddata = [getphase(unfi, r) for r in unfi]
5245 olddata = [getphase(unfi, r) for r in unfi]
5256 phases.advanceboundary(repo, tr, targetphase, nodes)
5246 phases.advanceboundary(repo, tr, targetphase, nodes)
5257 if opts[b'force']:
5247 if opts[b'force']:
5258 phases.retractboundary(repo, tr, targetphase, nodes)
5248 phases.retractboundary(repo, tr, targetphase, nodes)
5259 getphase = unfi._phasecache.phase
5249 getphase = unfi._phasecache.phase
5260 newdata = [getphase(unfi, r) for r in unfi]
5250 newdata = [getphase(unfi, r) for r in unfi]
5261 changes = sum(newdata[r] != olddata[r] for r in unfi)
5251 changes = sum(newdata[r] != olddata[r] for r in unfi)
5262 cl = unfi.changelog
5252 cl = unfi.changelog
5263 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5253 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5264 if rejected:
5254 if rejected:
5265 ui.warn(
5255 ui.warn(
5266 _(
5256 _(
5267 b'cannot move %i changesets to a higher '
5257 b'cannot move %i changesets to a higher '
5268 b'phase, use --force\n'
5258 b'phase, use --force\n'
5269 )
5259 )
5270 % len(rejected)
5260 % len(rejected)
5271 )
5261 )
5272 ret = 1
5262 ret = 1
5273 if changes:
5263 if changes:
5274 msg = _(b'phase changed for %i changesets\n') % changes
5264 msg = _(b'phase changed for %i changesets\n') % changes
5275 if ret:
5265 if ret:
5276 ui.status(msg)
5266 ui.status(msg)
5277 else:
5267 else:
5278 ui.note(msg)
5268 ui.note(msg)
5279 else:
5269 else:
5280 ui.warn(_(b'no phases changed\n'))
5270 ui.warn(_(b'no phases changed\n'))
5281 return ret
5271 return ret
5282
5272
5283
5273
5284 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5274 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5285 """Run after a changegroup has been added via pull/unbundle
5275 """Run after a changegroup has been added via pull/unbundle
5286
5276
5287 This takes arguments below:
5277 This takes arguments below:
5288
5278
5289 :modheads: change of heads by pull/unbundle
5279 :modheads: change of heads by pull/unbundle
5290 :optupdate: updating working directory is needed or not
5280 :optupdate: updating working directory is needed or not
5291 :checkout: update destination revision (or None to default destination)
5281 :checkout: update destination revision (or None to default destination)
5292 :brev: a name, which might be a bookmark to be activated after updating
5282 :brev: a name, which might be a bookmark to be activated after updating
5293 """
5283 """
5294 if modheads == 0:
5284 if modheads == 0:
5295 return
5285 return
5296 if optupdate:
5286 if optupdate:
5297 try:
5287 try:
5298 return hg.updatetotally(ui, repo, checkout, brev)
5288 return hg.updatetotally(ui, repo, checkout, brev)
5299 except error.UpdateAbort as inst:
5289 except error.UpdateAbort as inst:
5300 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5290 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5301 hint = inst.hint
5291 hint = inst.hint
5302 raise error.UpdateAbort(msg, hint=hint)
5292 raise error.UpdateAbort(msg, hint=hint)
5303 if modheads is not None and modheads > 1:
5293 if modheads is not None and modheads > 1:
5304 currentbranchheads = len(repo.branchheads())
5294 currentbranchheads = len(repo.branchheads())
5305 if currentbranchheads == modheads:
5295 if currentbranchheads == modheads:
5306 ui.status(
5296 ui.status(
5307 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5297 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5308 )
5298 )
5309 elif currentbranchheads > 1:
5299 elif currentbranchheads > 1:
5310 ui.status(
5300 ui.status(
5311 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5301 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5312 )
5302 )
5313 else:
5303 else:
5314 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5304 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5315 elif not ui.configbool(b'commands', b'update.requiredest'):
5305 elif not ui.configbool(b'commands', b'update.requiredest'):
5316 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5306 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5317
5307
5318
5308
5319 @command(
5309 @command(
5320 b'pull',
5310 b'pull',
5321 [
5311 [
5322 (
5312 (
5323 b'u',
5313 b'u',
5324 b'update',
5314 b'update',
5325 None,
5315 None,
5326 _(b'update to new branch head if new descendants were pulled'),
5316 _(b'update to new branch head if new descendants were pulled'),
5327 ),
5317 ),
5328 (
5318 (
5329 b'f',
5319 b'f',
5330 b'force',
5320 b'force',
5331 None,
5321 None,
5332 _(b'run even when remote repository is unrelated'),
5322 _(b'run even when remote repository is unrelated'),
5333 ),
5323 ),
5334 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5324 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5335 (
5325 (
5336 b'r',
5326 b'r',
5337 b'rev',
5327 b'rev',
5338 [],
5328 [],
5339 _(b'a remote changeset intended to be added'),
5329 _(b'a remote changeset intended to be added'),
5340 _(b'REV'),
5330 _(b'REV'),
5341 ),
5331 ),
5342 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5332 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5343 (
5333 (
5344 b'b',
5334 b'b',
5345 b'branch',
5335 b'branch',
5346 [],
5336 [],
5347 _(b'a specific branch you would like to pull'),
5337 _(b'a specific branch you would like to pull'),
5348 _(b'BRANCH'),
5338 _(b'BRANCH'),
5349 ),
5339 ),
5350 ]
5340 ]
5351 + remoteopts,
5341 + remoteopts,
5352 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5342 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5353 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5343 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5354 helpbasic=True,
5344 helpbasic=True,
5355 )
5345 )
5356 def pull(ui, repo, source=b"default", **opts):
5346 def pull(ui, repo, source=b"default", **opts):
5357 """pull changes from the specified source
5347 """pull changes from the specified source
5358
5348
5359 Pull changes from a remote repository to a local one.
5349 Pull changes from a remote repository to a local one.
5360
5350
5361 This finds all changes from the repository at the specified path
5351 This finds all changes from the repository at the specified path
5362 or URL and adds them to a local repository (the current one unless
5352 or URL and adds them to a local repository (the current one unless
5363 -R is specified). By default, this does not update the copy of the
5353 -R is specified). By default, this does not update the copy of the
5364 project in the working directory.
5354 project in the working directory.
5365
5355
5366 When cloning from servers that support it, Mercurial may fetch
5356 When cloning from servers that support it, Mercurial may fetch
5367 pre-generated data. When this is done, hooks operating on incoming
5357 pre-generated data. When this is done, hooks operating on incoming
5368 changesets and changegroups may fire more than once, once for each
5358 changesets and changegroups may fire more than once, once for each
5369 pre-generated bundle and as well as for any additional remaining
5359 pre-generated bundle and as well as for any additional remaining
5370 data. See :hg:`help -e clonebundles` for more.
5360 data. See :hg:`help -e clonebundles` for more.
5371
5361
5372 Use :hg:`incoming` if you want to see what would have been added
5362 Use :hg:`incoming` if you want to see what would have been added
5373 by a pull at the time you issued this command. If you then decide
5363 by a pull at the time you issued this command. If you then decide
5374 to add those changes to the repository, you should use :hg:`pull
5364 to add those changes to the repository, you should use :hg:`pull
5375 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5365 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5376
5366
5377 If SOURCE is omitted, the 'default' path will be used.
5367 If SOURCE is omitted, the 'default' path will be used.
5378 See :hg:`help urls` for more information.
5368 See :hg:`help urls` for more information.
5379
5369
5380 Specifying bookmark as ``.`` is equivalent to specifying the active
5370 Specifying bookmark as ``.`` is equivalent to specifying the active
5381 bookmark's name.
5371 bookmark's name.
5382
5372
5383 Returns 0 on success, 1 if an update had unresolved files.
5373 Returns 0 on success, 1 if an update had unresolved files.
5384 """
5374 """
5385
5375
5386 opts = pycompat.byteskwargs(opts)
5376 opts = pycompat.byteskwargs(opts)
5387 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5377 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5388 b'update'
5378 b'update'
5389 ):
5379 ):
5390 msg = _(b'update destination required by configuration')
5380 msg = _(b'update destination required by configuration')
5391 hint = _(b'use hg pull followed by hg update DEST')
5381 hint = _(b'use hg pull followed by hg update DEST')
5392 raise error.Abort(msg, hint=hint)
5382 raise error.Abort(msg, hint=hint)
5393
5383
5394 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5384 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5395 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5385 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5396 other = hg.peer(repo, opts, source)
5386 other = hg.peer(repo, opts, source)
5397 try:
5387 try:
5398 revs, checkout = hg.addbranchrevs(
5388 revs, checkout = hg.addbranchrevs(
5399 repo, other, branches, opts.get(b'rev')
5389 repo, other, branches, opts.get(b'rev')
5400 )
5390 )
5401
5391
5402 pullopargs = {}
5392 pullopargs = {}
5403
5393
5404 nodes = None
5394 nodes = None
5405 if opts.get(b'bookmark') or revs:
5395 if opts.get(b'bookmark') or revs:
5406 # The list of bookmark used here is the same used to actually update
5396 # The list of bookmark used here is the same used to actually update
5407 # the bookmark names, to avoid the race from issue 4689 and we do
5397 # the bookmark names, to avoid the race from issue 4689 and we do
5408 # all lookup and bookmark queries in one go so they see the same
5398 # all lookup and bookmark queries in one go so they see the same
5409 # version of the server state (issue 4700).
5399 # version of the server state (issue 4700).
5410 nodes = []
5400 nodes = []
5411 fnodes = []
5401 fnodes = []
5412 revs = revs or []
5402 revs = revs or []
5413 if revs and not other.capable(b'lookup'):
5403 if revs and not other.capable(b'lookup'):
5414 err = _(
5404 err = _(
5415 b"other repository doesn't support revision lookup, "
5405 b"other repository doesn't support revision lookup, "
5416 b"so a rev cannot be specified."
5406 b"so a rev cannot be specified."
5417 )
5407 )
5418 raise error.Abort(err)
5408 raise error.Abort(err)
5419 with other.commandexecutor() as e:
5409 with other.commandexecutor() as e:
5420 fremotebookmarks = e.callcommand(
5410 fremotebookmarks = e.callcommand(
5421 b'listkeys', {b'namespace': b'bookmarks'}
5411 b'listkeys', {b'namespace': b'bookmarks'}
5422 )
5412 )
5423 for r in revs:
5413 for r in revs:
5424 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5414 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5425 remotebookmarks = fremotebookmarks.result()
5415 remotebookmarks = fremotebookmarks.result()
5426 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5416 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5427 pullopargs[b'remotebookmarks'] = remotebookmarks
5417 pullopargs[b'remotebookmarks'] = remotebookmarks
5428 for b in opts.get(b'bookmark', []):
5418 for b in opts.get(b'bookmark', []):
5429 b = repo._bookmarks.expandname(b)
5419 b = repo._bookmarks.expandname(b)
5430 if b not in remotebookmarks:
5420 if b not in remotebookmarks:
5431 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5421 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5432 nodes.append(remotebookmarks[b])
5422 nodes.append(remotebookmarks[b])
5433 for i, rev in enumerate(revs):
5423 for i, rev in enumerate(revs):
5434 node = fnodes[i].result()
5424 node = fnodes[i].result()
5435 nodes.append(node)
5425 nodes.append(node)
5436 if rev == checkout:
5426 if rev == checkout:
5437 checkout = node
5427 checkout = node
5438
5428
5439 wlock = util.nullcontextmanager()
5429 wlock = util.nullcontextmanager()
5440 if opts.get(b'update'):
5430 if opts.get(b'update'):
5441 wlock = repo.wlock()
5431 wlock = repo.wlock()
5442 with wlock:
5432 with wlock:
5443 pullopargs.update(opts.get(b'opargs', {}))
5433 pullopargs.update(opts.get(b'opargs', {}))
5444 modheads = exchange.pull(
5434 modheads = exchange.pull(
5445 repo,
5435 repo,
5446 other,
5436 other,
5447 heads=nodes,
5437 heads=nodes,
5448 force=opts.get(b'force'),
5438 force=opts.get(b'force'),
5449 bookmarks=opts.get(b'bookmark', ()),
5439 bookmarks=opts.get(b'bookmark', ()),
5450 opargs=pullopargs,
5440 opargs=pullopargs,
5451 confirm=opts.get(b'confirm'),
5441 confirm=opts.get(b'confirm'),
5452 ).cgresult
5442 ).cgresult
5453
5443
5454 # brev is a name, which might be a bookmark to be activated at
5444 # brev is a name, which might be a bookmark to be activated at
5455 # the end of the update. In other words, it is an explicit
5445 # the end of the update. In other words, it is an explicit
5456 # destination of the update
5446 # destination of the update
5457 brev = None
5447 brev = None
5458
5448
5459 if checkout:
5449 if checkout:
5460 checkout = repo.unfiltered().changelog.rev(checkout)
5450 checkout = repo.unfiltered().changelog.rev(checkout)
5461
5451
5462 # order below depends on implementation of
5452 # order below depends on implementation of
5463 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5453 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5464 # because 'checkout' is determined without it.
5454 # because 'checkout' is determined without it.
5465 if opts.get(b'rev'):
5455 if opts.get(b'rev'):
5466 brev = opts[b'rev'][0]
5456 brev = opts[b'rev'][0]
5467 elif opts.get(b'branch'):
5457 elif opts.get(b'branch'):
5468 brev = opts[b'branch'][0]
5458 brev = opts[b'branch'][0]
5469 else:
5459 else:
5470 brev = branches[0]
5460 brev = branches[0]
5471 repo._subtoppath = source
5461 repo._subtoppath = source
5472 try:
5462 try:
5473 ret = postincoming(
5463 ret = postincoming(
5474 ui, repo, modheads, opts.get(b'update'), checkout, brev
5464 ui, repo, modheads, opts.get(b'update'), checkout, brev
5475 )
5465 )
5476 except error.FilteredRepoLookupError as exc:
5466 except error.FilteredRepoLookupError as exc:
5477 msg = _(b'cannot update to target: %s') % exc.args[0]
5467 msg = _(b'cannot update to target: %s') % exc.args[0]
5478 exc.args = (msg,) + exc.args[1:]
5468 exc.args = (msg,) + exc.args[1:]
5479 raise
5469 raise
5480 finally:
5470 finally:
5481 del repo._subtoppath
5471 del repo._subtoppath
5482
5472
5483 finally:
5473 finally:
5484 other.close()
5474 other.close()
5485 return ret
5475 return ret
5486
5476
5487
5477
5488 @command(
5478 @command(
5489 b'push',
5479 b'push',
5490 [
5480 [
5491 (b'f', b'force', None, _(b'force push')),
5481 (b'f', b'force', None, _(b'force push')),
5492 (
5482 (
5493 b'r',
5483 b'r',
5494 b'rev',
5484 b'rev',
5495 [],
5485 [],
5496 _(b'a changeset intended to be included in the destination'),
5486 _(b'a changeset intended to be included in the destination'),
5497 _(b'REV'),
5487 _(b'REV'),
5498 ),
5488 ),
5499 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5489 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5500 (
5490 (
5501 b'b',
5491 b'b',
5502 b'branch',
5492 b'branch',
5503 [],
5493 [],
5504 _(b'a specific branch you would like to push'),
5494 _(b'a specific branch you would like to push'),
5505 _(b'BRANCH'),
5495 _(b'BRANCH'),
5506 ),
5496 ),
5507 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5497 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5508 (
5498 (
5509 b'',
5499 b'',
5510 b'pushvars',
5500 b'pushvars',
5511 [],
5501 [],
5512 _(b'variables that can be sent to server (ADVANCED)'),
5502 _(b'variables that can be sent to server (ADVANCED)'),
5513 ),
5503 ),
5514 (
5504 (
5515 b'',
5505 b'',
5516 b'publish',
5506 b'publish',
5517 False,
5507 False,
5518 _(b'push the changeset as public (EXPERIMENTAL)'),
5508 _(b'push the changeset as public (EXPERIMENTAL)'),
5519 ),
5509 ),
5520 ]
5510 ]
5521 + remoteopts,
5511 + remoteopts,
5522 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5512 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5523 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5513 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5524 helpbasic=True,
5514 helpbasic=True,
5525 )
5515 )
5526 def push(ui, repo, dest=None, **opts):
5516 def push(ui, repo, dest=None, **opts):
5527 """push changes to the specified destination
5517 """push changes to the specified destination
5528
5518
5529 Push changesets from the local repository to the specified
5519 Push changesets from the local repository to the specified
5530 destination.
5520 destination.
5531
5521
5532 This operation is symmetrical to pull: it is identical to a pull
5522 This operation is symmetrical to pull: it is identical to a pull
5533 in the destination repository from the current one.
5523 in the destination repository from the current one.
5534
5524
5535 By default, push will not allow creation of new heads at the
5525 By default, push will not allow creation of new heads at the
5536 destination, since multiple heads would make it unclear which head
5526 destination, since multiple heads would make it unclear which head
5537 to use. In this situation, it is recommended to pull and merge
5527 to use. In this situation, it is recommended to pull and merge
5538 before pushing.
5528 before pushing.
5539
5529
5540 Use --new-branch if you want to allow push to create a new named
5530 Use --new-branch if you want to allow push to create a new named
5541 branch that is not present at the destination. This allows you to
5531 branch that is not present at the destination. This allows you to
5542 only create a new branch without forcing other changes.
5532 only create a new branch without forcing other changes.
5543
5533
5544 .. note::
5534 .. note::
5545
5535
5546 Extra care should be taken with the -f/--force option,
5536 Extra care should be taken with the -f/--force option,
5547 which will push all new heads on all branches, an action which will
5537 which will push all new heads on all branches, an action which will
5548 almost always cause confusion for collaborators.
5538 almost always cause confusion for collaborators.
5549
5539
5550 If -r/--rev is used, the specified revision and all its ancestors
5540 If -r/--rev is used, the specified revision and all its ancestors
5551 will be pushed to the remote repository.
5541 will be pushed to the remote repository.
5552
5542
5553 If -B/--bookmark is used, the specified bookmarked revision, its
5543 If -B/--bookmark is used, the specified bookmarked revision, its
5554 ancestors, and the bookmark will be pushed to the remote
5544 ancestors, and the bookmark will be pushed to the remote
5555 repository. Specifying ``.`` is equivalent to specifying the active
5545 repository. Specifying ``.`` is equivalent to specifying the active
5556 bookmark's name.
5546 bookmark's name.
5557
5547
5558 Please see :hg:`help urls` for important details about ``ssh://``
5548 Please see :hg:`help urls` for important details about ``ssh://``
5559 URLs. If DESTINATION is omitted, a default path will be used.
5549 URLs. If DESTINATION is omitted, a default path will be used.
5560
5550
5561 .. container:: verbose
5551 .. container:: verbose
5562
5552
5563 The --pushvars option sends strings to the server that become
5553 The --pushvars option sends strings to the server that become
5564 environment variables prepended with ``HG_USERVAR_``. For example,
5554 environment variables prepended with ``HG_USERVAR_``. For example,
5565 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5555 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5566 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5556 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5567
5557
5568 pushvars can provide for user-overridable hooks as well as set debug
5558 pushvars can provide for user-overridable hooks as well as set debug
5569 levels. One example is having a hook that blocks commits containing
5559 levels. One example is having a hook that blocks commits containing
5570 conflict markers, but enables the user to override the hook if the file
5560 conflict markers, but enables the user to override the hook if the file
5571 is using conflict markers for testing purposes or the file format has
5561 is using conflict markers for testing purposes or the file format has
5572 strings that look like conflict markers.
5562 strings that look like conflict markers.
5573
5563
5574 By default, servers will ignore `--pushvars`. To enable it add the
5564 By default, servers will ignore `--pushvars`. To enable it add the
5575 following to your configuration file::
5565 following to your configuration file::
5576
5566
5577 [push]
5567 [push]
5578 pushvars.server = true
5568 pushvars.server = true
5579
5569
5580 Returns 0 if push was successful, 1 if nothing to push.
5570 Returns 0 if push was successful, 1 if nothing to push.
5581 """
5571 """
5582
5572
5583 opts = pycompat.byteskwargs(opts)
5573 opts = pycompat.byteskwargs(opts)
5584 if opts.get(b'bookmark'):
5574 if opts.get(b'bookmark'):
5585 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5575 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5586 for b in opts[b'bookmark']:
5576 for b in opts[b'bookmark']:
5587 # translate -B options to -r so changesets get pushed
5577 # translate -B options to -r so changesets get pushed
5588 b = repo._bookmarks.expandname(b)
5578 b = repo._bookmarks.expandname(b)
5589 if b in repo._bookmarks:
5579 if b in repo._bookmarks:
5590 opts.setdefault(b'rev', []).append(b)
5580 opts.setdefault(b'rev', []).append(b)
5591 else:
5581 else:
5592 # if we try to push a deleted bookmark, translate it to null
5582 # if we try to push a deleted bookmark, translate it to null
5593 # this lets simultaneous -r, -b options continue working
5583 # this lets simultaneous -r, -b options continue working
5594 opts.setdefault(b'rev', []).append(b"null")
5584 opts.setdefault(b'rev', []).append(b"null")
5595
5585
5596 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5586 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5597 if not path:
5587 if not path:
5598 raise error.Abort(
5588 raise error.Abort(
5599 _(b'default repository not configured!'),
5589 _(b'default repository not configured!'),
5600 hint=_(b"see 'hg help config.paths'"),
5590 hint=_(b"see 'hg help config.paths'"),
5601 )
5591 )
5602 dest = path.pushloc or path.loc
5592 dest = path.pushloc or path.loc
5603 branches = (path.branch, opts.get(b'branch') or [])
5593 branches = (path.branch, opts.get(b'branch') or [])
5604 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5594 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5605 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5595 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5606 other = hg.peer(repo, opts, dest)
5596 other = hg.peer(repo, opts, dest)
5607
5597
5608 if revs:
5598 if revs:
5609 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5599 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5610 if not revs:
5600 if not revs:
5611 raise error.Abort(
5601 raise error.Abort(
5612 _(b"specified revisions evaluate to an empty set"),
5602 _(b"specified revisions evaluate to an empty set"),
5613 hint=_(b"use different revision arguments"),
5603 hint=_(b"use different revision arguments"),
5614 )
5604 )
5615 elif path.pushrev:
5605 elif path.pushrev:
5616 # It doesn't make any sense to specify ancestor revisions. So limit
5606 # It doesn't make any sense to specify ancestor revisions. So limit
5617 # to DAG heads to make discovery simpler.
5607 # to DAG heads to make discovery simpler.
5618 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5608 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5619 revs = scmutil.revrange(repo, [expr])
5609 revs = scmutil.revrange(repo, [expr])
5620 revs = [repo[rev].node() for rev in revs]
5610 revs = [repo[rev].node() for rev in revs]
5621 if not revs:
5611 if not revs:
5622 raise error.Abort(
5612 raise error.Abort(
5623 _(b'default push revset for path evaluates to an empty set')
5613 _(b'default push revset for path evaluates to an empty set')
5624 )
5614 )
5625 elif ui.configbool(b'commands', b'push.require-revs'):
5615 elif ui.configbool(b'commands', b'push.require-revs'):
5626 raise error.Abort(
5616 raise error.Abort(
5627 _(b'no revisions specified to push'),
5617 _(b'no revisions specified to push'),
5628 hint=_(b'did you mean "hg push -r ."?'),
5618 hint=_(b'did you mean "hg push -r ."?'),
5629 )
5619 )
5630
5620
5631 repo._subtoppath = dest
5621 repo._subtoppath = dest
5632 try:
5622 try:
5633 # push subrepos depth-first for coherent ordering
5623 # push subrepos depth-first for coherent ordering
5634 c = repo[b'.']
5624 c = repo[b'.']
5635 subs = c.substate # only repos that are committed
5625 subs = c.substate # only repos that are committed
5636 for s in sorted(subs):
5626 for s in sorted(subs):
5637 result = c.sub(s).push(opts)
5627 result = c.sub(s).push(opts)
5638 if result == 0:
5628 if result == 0:
5639 return not result
5629 return not result
5640 finally:
5630 finally:
5641 del repo._subtoppath
5631 del repo._subtoppath
5642
5632
5643 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5633 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5644 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5634 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5645
5635
5646 pushop = exchange.push(
5636 pushop = exchange.push(
5647 repo,
5637 repo,
5648 other,
5638 other,
5649 opts.get(b'force'),
5639 opts.get(b'force'),
5650 revs=revs,
5640 revs=revs,
5651 newbranch=opts.get(b'new_branch'),
5641 newbranch=opts.get(b'new_branch'),
5652 bookmarks=opts.get(b'bookmark', ()),
5642 bookmarks=opts.get(b'bookmark', ()),
5653 publish=opts.get(b'publish'),
5643 publish=opts.get(b'publish'),
5654 opargs=opargs,
5644 opargs=opargs,
5655 )
5645 )
5656
5646
5657 result = not pushop.cgresult
5647 result = not pushop.cgresult
5658
5648
5659 if pushop.bkresult is not None:
5649 if pushop.bkresult is not None:
5660 if pushop.bkresult == 2:
5650 if pushop.bkresult == 2:
5661 result = 2
5651 result = 2
5662 elif not result and pushop.bkresult:
5652 elif not result and pushop.bkresult:
5663 result = 2
5653 result = 2
5664
5654
5665 return result
5655 return result
5666
5656
5667
5657
5668 @command(
5658 @command(
5669 b'recover',
5659 b'recover',
5670 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5660 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5671 helpcategory=command.CATEGORY_MAINTENANCE,
5661 helpcategory=command.CATEGORY_MAINTENANCE,
5672 )
5662 )
5673 def recover(ui, repo, **opts):
5663 def recover(ui, repo, **opts):
5674 """roll back an interrupted transaction
5664 """roll back an interrupted transaction
5675
5665
5676 Recover from an interrupted commit or pull.
5666 Recover from an interrupted commit or pull.
5677
5667
5678 This command tries to fix the repository status after an
5668 This command tries to fix the repository status after an
5679 interrupted operation. It should only be necessary when Mercurial
5669 interrupted operation. It should only be necessary when Mercurial
5680 suggests it.
5670 suggests it.
5681
5671
5682 Returns 0 if successful, 1 if nothing to recover or verify fails.
5672 Returns 0 if successful, 1 if nothing to recover or verify fails.
5683 """
5673 """
5684 ret = repo.recover()
5674 ret = repo.recover()
5685 if ret:
5675 if ret:
5686 if opts['verify']:
5676 if opts['verify']:
5687 return hg.verify(repo)
5677 return hg.verify(repo)
5688 else:
5678 else:
5689 msg = _(
5679 msg = _(
5690 b"(verify step skipped, run `hg verify` to check your "
5680 b"(verify step skipped, run `hg verify` to check your "
5691 b"repository content)\n"
5681 b"repository content)\n"
5692 )
5682 )
5693 ui.warn(msg)
5683 ui.warn(msg)
5694 return 0
5684 return 0
5695 return 1
5685 return 1
5696
5686
5697
5687
5698 @command(
5688 @command(
5699 b'remove|rm',
5689 b'remove|rm',
5700 [
5690 [
5701 (b'A', b'after', None, _(b'record delete for missing files')),
5691 (b'A', b'after', None, _(b'record delete for missing files')),
5702 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5692 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5703 ]
5693 ]
5704 + subrepoopts
5694 + subrepoopts
5705 + walkopts
5695 + walkopts
5706 + dryrunopts,
5696 + dryrunopts,
5707 _(b'[OPTION]... FILE...'),
5697 _(b'[OPTION]... FILE...'),
5708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5698 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5709 helpbasic=True,
5699 helpbasic=True,
5710 inferrepo=True,
5700 inferrepo=True,
5711 )
5701 )
5712 def remove(ui, repo, *pats, **opts):
5702 def remove(ui, repo, *pats, **opts):
5713 """remove the specified files on the next commit
5703 """remove the specified files on the next commit
5714
5704
5715 Schedule the indicated files for removal from the current branch.
5705 Schedule the indicated files for removal from the current branch.
5716
5706
5717 This command schedules the files to be removed at the next commit.
5707 This command schedules the files to be removed at the next commit.
5718 To undo a remove before that, see :hg:`revert`. To undo added
5708 To undo a remove before that, see :hg:`revert`. To undo added
5719 files, see :hg:`forget`.
5709 files, see :hg:`forget`.
5720
5710
5721 .. container:: verbose
5711 .. container:: verbose
5722
5712
5723 -A/--after can be used to remove only files that have already
5713 -A/--after can be used to remove only files that have already
5724 been deleted, -f/--force can be used to force deletion, and -Af
5714 been deleted, -f/--force can be used to force deletion, and -Af
5725 can be used to remove files from the next revision without
5715 can be used to remove files from the next revision without
5726 deleting them from the working directory.
5716 deleting them from the working directory.
5727
5717
5728 The following table details the behavior of remove for different
5718 The following table details the behavior of remove for different
5729 file states (columns) and option combinations (rows). The file
5719 file states (columns) and option combinations (rows). The file
5730 states are Added [A], Clean [C], Modified [M] and Missing [!]
5720 states are Added [A], Clean [C], Modified [M] and Missing [!]
5731 (as reported by :hg:`status`). The actions are Warn, Remove
5721 (as reported by :hg:`status`). The actions are Warn, Remove
5732 (from branch) and Delete (from disk):
5722 (from branch) and Delete (from disk):
5733
5723
5734 ========= == == == ==
5724 ========= == == == ==
5735 opt/state A C M !
5725 opt/state A C M !
5736 ========= == == == ==
5726 ========= == == == ==
5737 none W RD W R
5727 none W RD W R
5738 -f R RD RD R
5728 -f R RD RD R
5739 -A W W W R
5729 -A W W W R
5740 -Af R R R R
5730 -Af R R R R
5741 ========= == == == ==
5731 ========= == == == ==
5742
5732
5743 .. note::
5733 .. note::
5744
5734
5745 :hg:`remove` never deletes files in Added [A] state from the
5735 :hg:`remove` never deletes files in Added [A] state from the
5746 working directory, not even if ``--force`` is specified.
5736 working directory, not even if ``--force`` is specified.
5747
5737
5748 Returns 0 on success, 1 if any warnings encountered.
5738 Returns 0 on success, 1 if any warnings encountered.
5749 """
5739 """
5750
5740
5751 opts = pycompat.byteskwargs(opts)
5741 opts = pycompat.byteskwargs(opts)
5752 after, force = opts.get(b'after'), opts.get(b'force')
5742 after, force = opts.get(b'after'), opts.get(b'force')
5753 dryrun = opts.get(b'dry_run')
5743 dryrun = opts.get(b'dry_run')
5754 if not pats and not after:
5744 if not pats and not after:
5755 raise error.Abort(_(b'no files specified'))
5745 raise error.Abort(_(b'no files specified'))
5756
5746
5757 m = scmutil.match(repo[None], pats, opts)
5747 m = scmutil.match(repo[None], pats, opts)
5758 subrepos = opts.get(b'subrepos')
5748 subrepos = opts.get(b'subrepos')
5759 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5749 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5760 return cmdutil.remove(
5750 return cmdutil.remove(
5761 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5751 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5762 )
5752 )
5763
5753
5764
5754
5765 @command(
5755 @command(
5766 b'rename|move|mv',
5756 b'rename|move|mv',
5767 [
5757 [
5768 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5758 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5769 (
5759 (
5770 b'',
5760 b'',
5771 b'at-rev',
5761 b'at-rev',
5772 b'',
5762 b'',
5773 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5763 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5774 _(b'REV'),
5764 _(b'REV'),
5775 ),
5765 ),
5776 (
5766 (
5777 b'f',
5767 b'f',
5778 b'force',
5768 b'force',
5779 None,
5769 None,
5780 _(b'forcibly move over an existing managed file'),
5770 _(b'forcibly move over an existing managed file'),
5781 ),
5771 ),
5782 ]
5772 ]
5783 + walkopts
5773 + walkopts
5784 + dryrunopts,
5774 + dryrunopts,
5785 _(b'[OPTION]... SOURCE... DEST'),
5775 _(b'[OPTION]... SOURCE... DEST'),
5786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5776 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5787 )
5777 )
5788 def rename(ui, repo, *pats, **opts):
5778 def rename(ui, repo, *pats, **opts):
5789 """rename files; equivalent of copy + remove
5779 """rename files; equivalent of copy + remove
5790
5780
5791 Mark dest as copies of sources; mark sources for deletion. If dest
5781 Mark dest as copies of sources; mark sources for deletion. If dest
5792 is a directory, copies are put in that directory. If dest is a
5782 is a directory, copies are put in that directory. If dest is a
5793 file, there can only be one source.
5783 file, there can only be one source.
5794
5784
5795 By default, this command copies the contents of files as they
5785 By default, this command copies the contents of files as they
5796 exist in the working directory. If invoked with -A/--after, the
5786 exist in the working directory. If invoked with -A/--after, the
5797 operation is recorded, but no copying is performed.
5787 operation is recorded, but no copying is performed.
5798
5788
5799 This command takes effect at the next commit. To undo a rename
5789 This command takes effect at the next commit. To undo a rename
5800 before that, see :hg:`revert`.
5790 before that, see :hg:`revert`.
5801
5791
5802 Returns 0 on success, 1 if errors are encountered.
5792 Returns 0 on success, 1 if errors are encountered.
5803 """
5793 """
5804 opts = pycompat.byteskwargs(opts)
5794 opts = pycompat.byteskwargs(opts)
5805 with repo.wlock():
5795 with repo.wlock():
5806 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5796 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5807
5797
5808
5798
5809 @command(
5799 @command(
5810 b'resolve',
5800 b'resolve',
5811 [
5801 [
5812 (b'a', b'all', None, _(b'select all unresolved files')),
5802 (b'a', b'all', None, _(b'select all unresolved files')),
5813 (b'l', b'list', None, _(b'list state of files needing merge')),
5803 (b'l', b'list', None, _(b'list state of files needing merge')),
5814 (b'm', b'mark', None, _(b'mark files as resolved')),
5804 (b'm', b'mark', None, _(b'mark files as resolved')),
5815 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5805 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5816 (b'n', b'no-status', None, _(b'hide status prefix')),
5806 (b'n', b'no-status', None, _(b'hide status prefix')),
5817 (b'', b're-merge', None, _(b're-merge files')),
5807 (b'', b're-merge', None, _(b're-merge files')),
5818 ]
5808 ]
5819 + mergetoolopts
5809 + mergetoolopts
5820 + walkopts
5810 + walkopts
5821 + formatteropts,
5811 + formatteropts,
5822 _(b'[OPTION]... [FILE]...'),
5812 _(b'[OPTION]... [FILE]...'),
5823 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5824 inferrepo=True,
5814 inferrepo=True,
5825 )
5815 )
5826 def resolve(ui, repo, *pats, **opts):
5816 def resolve(ui, repo, *pats, **opts):
5827 """redo merges or set/view the merge status of files
5817 """redo merges or set/view the merge status of files
5828
5818
5829 Merges with unresolved conflicts are often the result of
5819 Merges with unresolved conflicts are often the result of
5830 non-interactive merging using the ``internal:merge`` configuration
5820 non-interactive merging using the ``internal:merge`` configuration
5831 setting, or a command-line merge tool like ``diff3``. The resolve
5821 setting, or a command-line merge tool like ``diff3``. The resolve
5832 command is used to manage the files involved in a merge, after
5822 command is used to manage the files involved in a merge, after
5833 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5823 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5834 working directory must have two parents). See :hg:`help
5824 working directory must have two parents). See :hg:`help
5835 merge-tools` for information on configuring merge tools.
5825 merge-tools` for information on configuring merge tools.
5836
5826
5837 The resolve command can be used in the following ways:
5827 The resolve command can be used in the following ways:
5838
5828
5839 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5829 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5840 the specified files, discarding any previous merge attempts. Re-merging
5830 the specified files, discarding any previous merge attempts. Re-merging
5841 is not performed for files already marked as resolved. Use ``--all/-a``
5831 is not performed for files already marked as resolved. Use ``--all/-a``
5842 to select all unresolved files. ``--tool`` can be used to specify
5832 to select all unresolved files. ``--tool`` can be used to specify
5843 the merge tool used for the given files. It overrides the HGMERGE
5833 the merge tool used for the given files. It overrides the HGMERGE
5844 environment variable and your configuration files. Previous file
5834 environment variable and your configuration files. Previous file
5845 contents are saved with a ``.orig`` suffix.
5835 contents are saved with a ``.orig`` suffix.
5846
5836
5847 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5837 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5848 (e.g. after having manually fixed-up the files). The default is
5838 (e.g. after having manually fixed-up the files). The default is
5849 to mark all unresolved files.
5839 to mark all unresolved files.
5850
5840
5851 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5841 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5852 default is to mark all resolved files.
5842 default is to mark all resolved files.
5853
5843
5854 - :hg:`resolve -l`: list files which had or still have conflicts.
5844 - :hg:`resolve -l`: list files which had or still have conflicts.
5855 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5845 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5856 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5846 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5857 the list. See :hg:`help filesets` for details.
5847 the list. See :hg:`help filesets` for details.
5858
5848
5859 .. note::
5849 .. note::
5860
5850
5861 Mercurial will not let you commit files with unresolved merge
5851 Mercurial will not let you commit files with unresolved merge
5862 conflicts. You must use :hg:`resolve -m ...` before you can
5852 conflicts. You must use :hg:`resolve -m ...` before you can
5863 commit after a conflicting merge.
5853 commit after a conflicting merge.
5864
5854
5865 .. container:: verbose
5855 .. container:: verbose
5866
5856
5867 Template:
5857 Template:
5868
5858
5869 The following keywords are supported in addition to the common template
5859 The following keywords are supported in addition to the common template
5870 keywords and functions. See also :hg:`help templates`.
5860 keywords and functions. See also :hg:`help templates`.
5871
5861
5872 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5862 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5873 :path: String. Repository-absolute path of the file.
5863 :path: String. Repository-absolute path of the file.
5874
5864
5875 Returns 0 on success, 1 if any files fail a resolve attempt.
5865 Returns 0 on success, 1 if any files fail a resolve attempt.
5876 """
5866 """
5877
5867
5878 opts = pycompat.byteskwargs(opts)
5868 opts = pycompat.byteskwargs(opts)
5879 confirm = ui.configbool(b'commands', b'resolve.confirm')
5869 confirm = ui.configbool(b'commands', b'resolve.confirm')
5880 flaglist = b'all mark unmark list no_status re_merge'.split()
5870 flaglist = b'all mark unmark list no_status re_merge'.split()
5881 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5871 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5882
5872
5883 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5873 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5884 if actioncount > 1:
5874 if actioncount > 1:
5885 raise error.Abort(_(b"too many actions specified"))
5875 raise error.Abort(_(b"too many actions specified"))
5886 elif actioncount == 0 and ui.configbool(
5876 elif actioncount == 0 and ui.configbool(
5887 b'commands', b'resolve.explicit-re-merge'
5877 b'commands', b'resolve.explicit-re-merge'
5888 ):
5878 ):
5889 hint = _(b'use --mark, --unmark, --list or --re-merge')
5879 hint = _(b'use --mark, --unmark, --list or --re-merge')
5890 raise error.Abort(_(b'no action specified'), hint=hint)
5880 raise error.Abort(_(b'no action specified'), hint=hint)
5891 if pats and all:
5881 if pats and all:
5892 raise error.Abort(_(b"can't specify --all and patterns"))
5882 raise error.Abort(_(b"can't specify --all and patterns"))
5893 if not (all or pats or show or mark or unmark):
5883 if not (all or pats or show or mark or unmark):
5894 raise error.Abort(
5884 raise error.Abort(
5895 _(b'no files or directories specified'),
5885 _(b'no files or directories specified'),
5896 hint=b'use --all to re-merge all unresolved files',
5886 hint=b'use --all to re-merge all unresolved files',
5897 )
5887 )
5898
5888
5899 if confirm:
5889 if confirm:
5900 if all:
5890 if all:
5901 if ui.promptchoice(
5891 if ui.promptchoice(
5902 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5892 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5903 ):
5893 ):
5904 raise error.Abort(_(b'user quit'))
5894 raise error.Abort(_(b'user quit'))
5905 if mark and not pats:
5895 if mark and not pats:
5906 if ui.promptchoice(
5896 if ui.promptchoice(
5907 _(
5897 _(
5908 b'mark all unresolved files as resolved (yn)?'
5898 b'mark all unresolved files as resolved (yn)?'
5909 b'$$ &Yes $$ &No'
5899 b'$$ &Yes $$ &No'
5910 )
5900 )
5911 ):
5901 ):
5912 raise error.Abort(_(b'user quit'))
5902 raise error.Abort(_(b'user quit'))
5913 if unmark and not pats:
5903 if unmark and not pats:
5914 if ui.promptchoice(
5904 if ui.promptchoice(
5915 _(
5905 _(
5916 b'mark all resolved files as unresolved (yn)?'
5906 b'mark all resolved files as unresolved (yn)?'
5917 b'$$ &Yes $$ &No'
5907 b'$$ &Yes $$ &No'
5918 )
5908 )
5919 ):
5909 ):
5920 raise error.Abort(_(b'user quit'))
5910 raise error.Abort(_(b'user quit'))
5921
5911
5922 uipathfn = scmutil.getuipathfn(repo)
5912 uipathfn = scmutil.getuipathfn(repo)
5923
5913
5924 if show:
5914 if show:
5925 ui.pager(b'resolve')
5915 ui.pager(b'resolve')
5926 fm = ui.formatter(b'resolve', opts)
5916 fm = ui.formatter(b'resolve', opts)
5927 ms = mergestatemod.mergestate.read(repo)
5917 ms = mergestatemod.mergestate.read(repo)
5928 wctx = repo[None]
5918 wctx = repo[None]
5929 m = scmutil.match(wctx, pats, opts)
5919 m = scmutil.match(wctx, pats, opts)
5930
5920
5931 # Labels and keys based on merge state. Unresolved path conflicts show
5921 # Labels and keys based on merge state. Unresolved path conflicts show
5932 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5922 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5933 # resolved conflicts.
5923 # resolved conflicts.
5934 mergestateinfo = {
5924 mergestateinfo = {
5935 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5925 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5936 b'resolve.unresolved',
5926 b'resolve.unresolved',
5937 b'U',
5927 b'U',
5938 ),
5928 ),
5939 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5929 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5940 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5930 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5941 b'resolve.unresolved',
5931 b'resolve.unresolved',
5942 b'P',
5932 b'P',
5943 ),
5933 ),
5944 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5934 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5945 b'resolve.resolved',
5935 b'resolve.resolved',
5946 b'R',
5936 b'R',
5947 ),
5937 ),
5948 }
5938 }
5949
5939
5950 for f in ms:
5940 for f in ms:
5951 if not m(f):
5941 if not m(f):
5952 continue
5942 continue
5953
5943
5954 label, key = mergestateinfo[ms[f]]
5944 label, key = mergestateinfo[ms[f]]
5955 fm.startitem()
5945 fm.startitem()
5956 fm.context(ctx=wctx)
5946 fm.context(ctx=wctx)
5957 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5947 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5958 fm.data(path=f)
5948 fm.data(path=f)
5959 fm.plain(b'%s\n' % uipathfn(f), label=label)
5949 fm.plain(b'%s\n' % uipathfn(f), label=label)
5960 fm.end()
5950 fm.end()
5961 return 0
5951 return 0
5962
5952
5963 with repo.wlock():
5953 with repo.wlock():
5964 ms = mergestatemod.mergestate.read(repo)
5954 ms = mergestatemod.mergestate.read(repo)
5965
5955
5966 if not (ms.active() or repo.dirstate.p2() != nullid):
5956 if not (ms.active() or repo.dirstate.p2() != nullid):
5967 raise error.Abort(
5957 raise error.Abort(
5968 _(b'resolve command not applicable when not merging')
5958 _(b'resolve command not applicable when not merging')
5969 )
5959 )
5970
5960
5971 wctx = repo[None]
5961 wctx = repo[None]
5972 m = scmutil.match(wctx, pats, opts)
5962 m = scmutil.match(wctx, pats, opts)
5973 ret = 0
5963 ret = 0
5974 didwork = False
5964 didwork = False
5975
5965
5976 tocomplete = []
5966 tocomplete = []
5977 hasconflictmarkers = []
5967 hasconflictmarkers = []
5978 if mark:
5968 if mark:
5979 markcheck = ui.config(b'commands', b'resolve.mark-check')
5969 markcheck = ui.config(b'commands', b'resolve.mark-check')
5980 if markcheck not in [b'warn', b'abort']:
5970 if markcheck not in [b'warn', b'abort']:
5981 # Treat all invalid / unrecognized values as 'none'.
5971 # Treat all invalid / unrecognized values as 'none'.
5982 markcheck = False
5972 markcheck = False
5983 for f in ms:
5973 for f in ms:
5984 if not m(f):
5974 if not m(f):
5985 continue
5975 continue
5986
5976
5987 didwork = True
5977 didwork = True
5988
5978
5989 # path conflicts must be resolved manually
5979 # path conflicts must be resolved manually
5990 if ms[f] in (
5980 if ms[f] in (
5991 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5981 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5992 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5982 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5993 ):
5983 ):
5994 if mark:
5984 if mark:
5995 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5985 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5996 elif unmark:
5986 elif unmark:
5997 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5987 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5998 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5988 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5999 ui.warn(
5989 ui.warn(
6000 _(b'%s: path conflict must be resolved manually\n')
5990 _(b'%s: path conflict must be resolved manually\n')
6001 % uipathfn(f)
5991 % uipathfn(f)
6002 )
5992 )
6003 continue
5993 continue
6004
5994
6005 if mark:
5995 if mark:
6006 if markcheck:
5996 if markcheck:
6007 fdata = repo.wvfs.tryread(f)
5997 fdata = repo.wvfs.tryread(f)
6008 if (
5998 if (
6009 filemerge.hasconflictmarkers(fdata)
5999 filemerge.hasconflictmarkers(fdata)
6010 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6000 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6011 ):
6001 ):
6012 hasconflictmarkers.append(f)
6002 hasconflictmarkers.append(f)
6013 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6003 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6014 elif unmark:
6004 elif unmark:
6015 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6005 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6016 else:
6006 else:
6017 # backup pre-resolve (merge uses .orig for its own purposes)
6007 # backup pre-resolve (merge uses .orig for its own purposes)
6018 a = repo.wjoin(f)
6008 a = repo.wjoin(f)
6019 try:
6009 try:
6020 util.copyfile(a, a + b".resolve")
6010 util.copyfile(a, a + b".resolve")
6021 except (IOError, OSError) as inst:
6011 except (IOError, OSError) as inst:
6022 if inst.errno != errno.ENOENT:
6012 if inst.errno != errno.ENOENT:
6023 raise
6013 raise
6024
6014
6025 try:
6015 try:
6026 # preresolve file
6016 # preresolve file
6027 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6017 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6028 with ui.configoverride(overrides, b'resolve'):
6018 with ui.configoverride(overrides, b'resolve'):
6029 complete, r = ms.preresolve(f, wctx)
6019 complete, r = ms.preresolve(f, wctx)
6030 if not complete:
6020 if not complete:
6031 tocomplete.append(f)
6021 tocomplete.append(f)
6032 elif r:
6022 elif r:
6033 ret = 1
6023 ret = 1
6034 finally:
6024 finally:
6035 ms.commit()
6025 ms.commit()
6036
6026
6037 # replace filemerge's .orig file with our resolve file, but only
6027 # replace filemerge's .orig file with our resolve file, but only
6038 # for merges that are complete
6028 # for merges that are complete
6039 if complete:
6029 if complete:
6040 try:
6030 try:
6041 util.rename(
6031 util.rename(
6042 a + b".resolve", scmutil.backuppath(ui, repo, f)
6032 a + b".resolve", scmutil.backuppath(ui, repo, f)
6043 )
6033 )
6044 except OSError as inst:
6034 except OSError as inst:
6045 if inst.errno != errno.ENOENT:
6035 if inst.errno != errno.ENOENT:
6046 raise
6036 raise
6047
6037
6048 if hasconflictmarkers:
6038 if hasconflictmarkers:
6049 ui.warn(
6039 ui.warn(
6050 _(
6040 _(
6051 b'warning: the following files still have conflict '
6041 b'warning: the following files still have conflict '
6052 b'markers:\n'
6042 b'markers:\n'
6053 )
6043 )
6054 + b''.join(
6044 + b''.join(
6055 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6045 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6056 )
6046 )
6057 )
6047 )
6058 if markcheck == b'abort' and not all and not pats:
6048 if markcheck == b'abort' and not all and not pats:
6059 raise error.Abort(
6049 raise error.Abort(
6060 _(b'conflict markers detected'),
6050 _(b'conflict markers detected'),
6061 hint=_(b'use --all to mark anyway'),
6051 hint=_(b'use --all to mark anyway'),
6062 )
6052 )
6063
6053
6064 for f in tocomplete:
6054 for f in tocomplete:
6065 try:
6055 try:
6066 # resolve file
6056 # resolve file
6067 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6057 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6068 with ui.configoverride(overrides, b'resolve'):
6058 with ui.configoverride(overrides, b'resolve'):
6069 r = ms.resolve(f, wctx)
6059 r = ms.resolve(f, wctx)
6070 if r:
6060 if r:
6071 ret = 1
6061 ret = 1
6072 finally:
6062 finally:
6073 ms.commit()
6063 ms.commit()
6074
6064
6075 # replace filemerge's .orig file with our resolve file
6065 # replace filemerge's .orig file with our resolve file
6076 a = repo.wjoin(f)
6066 a = repo.wjoin(f)
6077 try:
6067 try:
6078 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6068 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6079 except OSError as inst:
6069 except OSError as inst:
6080 if inst.errno != errno.ENOENT:
6070 if inst.errno != errno.ENOENT:
6081 raise
6071 raise
6082
6072
6083 ms.commit()
6073 ms.commit()
6084 branchmerge = repo.dirstate.p2() != nullid
6074 branchmerge = repo.dirstate.p2() != nullid
6085 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6075 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6086
6076
6087 if not didwork and pats:
6077 if not didwork and pats:
6088 hint = None
6078 hint = None
6089 if not any([p for p in pats if p.find(b':') >= 0]):
6079 if not any([p for p in pats if p.find(b':') >= 0]):
6090 pats = [b'path:%s' % p for p in pats]
6080 pats = [b'path:%s' % p for p in pats]
6091 m = scmutil.match(wctx, pats, opts)
6081 m = scmutil.match(wctx, pats, opts)
6092 for f in ms:
6082 for f in ms:
6093 if not m(f):
6083 if not m(f):
6094 continue
6084 continue
6095
6085
6096 def flag(o):
6086 def flag(o):
6097 if o == b're_merge':
6087 if o == b're_merge':
6098 return b'--re-merge '
6088 return b'--re-merge '
6099 return b'-%s ' % o[0:1]
6089 return b'-%s ' % o[0:1]
6100
6090
6101 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6091 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6102 hint = _(b"(try: hg resolve %s%s)\n") % (
6092 hint = _(b"(try: hg resolve %s%s)\n") % (
6103 flags,
6093 flags,
6104 b' '.join(pats),
6094 b' '.join(pats),
6105 )
6095 )
6106 break
6096 break
6107 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6097 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6108 if hint:
6098 if hint:
6109 ui.warn(hint)
6099 ui.warn(hint)
6110
6100
6111 unresolvedf = list(ms.unresolved())
6101 unresolvedf = list(ms.unresolved())
6112 if not unresolvedf:
6102 if not unresolvedf:
6113 ui.status(_(b'(no more unresolved files)\n'))
6103 ui.status(_(b'(no more unresolved files)\n'))
6114 cmdutil.checkafterresolved(repo)
6104 cmdutil.checkafterresolved(repo)
6115
6105
6116 return ret
6106 return ret
6117
6107
6118
6108
6119 @command(
6109 @command(
6120 b'revert',
6110 b'revert',
6121 [
6111 [
6122 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6112 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6123 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6113 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6124 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6114 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6125 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6115 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6126 (b'i', b'interactive', None, _(b'interactively select the changes')),
6116 (b'i', b'interactive', None, _(b'interactively select the changes')),
6127 ]
6117 ]
6128 + walkopts
6118 + walkopts
6129 + dryrunopts,
6119 + dryrunopts,
6130 _(b'[OPTION]... [-r REV] [NAME]...'),
6120 _(b'[OPTION]... [-r REV] [NAME]...'),
6131 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6121 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6132 )
6122 )
6133 def revert(ui, repo, *pats, **opts):
6123 def revert(ui, repo, *pats, **opts):
6134 """restore files to their checkout state
6124 """restore files to their checkout state
6135
6125
6136 .. note::
6126 .. note::
6137
6127
6138 To check out earlier revisions, you should use :hg:`update REV`.
6128 To check out earlier revisions, you should use :hg:`update REV`.
6139 To cancel an uncommitted merge (and lose your changes),
6129 To cancel an uncommitted merge (and lose your changes),
6140 use :hg:`merge --abort`.
6130 use :hg:`merge --abort`.
6141
6131
6142 With no revision specified, revert the specified files or directories
6132 With no revision specified, revert the specified files or directories
6143 to the contents they had in the parent of the working directory.
6133 to the contents they had in the parent of the working directory.
6144 This restores the contents of files to an unmodified
6134 This restores the contents of files to an unmodified
6145 state and unschedules adds, removes, copies, and renames. If the
6135 state and unschedules adds, removes, copies, and renames. If the
6146 working directory has two parents, you must explicitly specify a
6136 working directory has two parents, you must explicitly specify a
6147 revision.
6137 revision.
6148
6138
6149 Using the -r/--rev or -d/--date options, revert the given files or
6139 Using the -r/--rev or -d/--date options, revert the given files or
6150 directories to their states as of a specific revision. Because
6140 directories to their states as of a specific revision. Because
6151 revert does not change the working directory parents, this will
6141 revert does not change the working directory parents, this will
6152 cause these files to appear modified. This can be helpful to "back
6142 cause these files to appear modified. This can be helpful to "back
6153 out" some or all of an earlier change. See :hg:`backout` for a
6143 out" some or all of an earlier change. See :hg:`backout` for a
6154 related method.
6144 related method.
6155
6145
6156 Modified files are saved with a .orig suffix before reverting.
6146 Modified files are saved with a .orig suffix before reverting.
6157 To disable these backups, use --no-backup. It is possible to store
6147 To disable these backups, use --no-backup. It is possible to store
6158 the backup files in a custom directory relative to the root of the
6148 the backup files in a custom directory relative to the root of the
6159 repository by setting the ``ui.origbackuppath`` configuration
6149 repository by setting the ``ui.origbackuppath`` configuration
6160 option.
6150 option.
6161
6151
6162 See :hg:`help dates` for a list of formats valid for -d/--date.
6152 See :hg:`help dates` for a list of formats valid for -d/--date.
6163
6153
6164 See :hg:`help backout` for a way to reverse the effect of an
6154 See :hg:`help backout` for a way to reverse the effect of an
6165 earlier changeset.
6155 earlier changeset.
6166
6156
6167 Returns 0 on success.
6157 Returns 0 on success.
6168 """
6158 """
6169
6159
6170 opts = pycompat.byteskwargs(opts)
6160 opts = pycompat.byteskwargs(opts)
6171 if opts.get(b"date"):
6161 if opts.get(b"date"):
6172 if opts.get(b"rev"):
6162 if opts.get(b"rev"):
6173 raise error.Abort(_(b"you can't specify a revision and a date"))
6163 raise error.Abort(_(b"you can't specify a revision and a date"))
6174 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6164 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6175
6165
6176 parent, p2 = repo.dirstate.parents()
6166 parent, p2 = repo.dirstate.parents()
6177 if not opts.get(b'rev') and p2 != nullid:
6167 if not opts.get(b'rev') and p2 != nullid:
6178 # revert after merge is a trap for new users (issue2915)
6168 # revert after merge is a trap for new users (issue2915)
6179 raise error.Abort(
6169 raise error.Abort(
6180 _(b'uncommitted merge with no revision specified'),
6170 _(b'uncommitted merge with no revision specified'),
6181 hint=_(b"use 'hg update' or see 'hg help revert'"),
6171 hint=_(b"use 'hg update' or see 'hg help revert'"),
6182 )
6172 )
6183
6173
6184 rev = opts.get(b'rev')
6174 rev = opts.get(b'rev')
6185 if rev:
6175 if rev:
6186 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6176 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6187 ctx = scmutil.revsingle(repo, rev)
6177 ctx = scmutil.revsingle(repo, rev)
6188
6178
6189 if not (
6179 if not (
6190 pats
6180 pats
6191 or opts.get(b'include')
6181 or opts.get(b'include')
6192 or opts.get(b'exclude')
6182 or opts.get(b'exclude')
6193 or opts.get(b'all')
6183 or opts.get(b'all')
6194 or opts.get(b'interactive')
6184 or opts.get(b'interactive')
6195 ):
6185 ):
6196 msg = _(b"no files or directories specified")
6186 msg = _(b"no files or directories specified")
6197 if p2 != nullid:
6187 if p2 != nullid:
6198 hint = _(
6188 hint = _(
6199 b"uncommitted merge, use --all to discard all changes,"
6189 b"uncommitted merge, use --all to discard all changes,"
6200 b" or 'hg update -C .' to abort the merge"
6190 b" or 'hg update -C .' to abort the merge"
6201 )
6191 )
6202 raise error.Abort(msg, hint=hint)
6192 raise error.Abort(msg, hint=hint)
6203 dirty = any(repo.status())
6193 dirty = any(repo.status())
6204 node = ctx.node()
6194 node = ctx.node()
6205 if node != parent:
6195 if node != parent:
6206 if dirty:
6196 if dirty:
6207 hint = (
6197 hint = (
6208 _(
6198 _(
6209 b"uncommitted changes, use --all to discard all"
6199 b"uncommitted changes, use --all to discard all"
6210 b" changes, or 'hg update %d' to update"
6200 b" changes, or 'hg update %d' to update"
6211 )
6201 )
6212 % ctx.rev()
6202 % ctx.rev()
6213 )
6203 )
6214 else:
6204 else:
6215 hint = (
6205 hint = (
6216 _(
6206 _(
6217 b"use --all to revert all files,"
6207 b"use --all to revert all files,"
6218 b" or 'hg update %d' to update"
6208 b" or 'hg update %d' to update"
6219 )
6209 )
6220 % ctx.rev()
6210 % ctx.rev()
6221 )
6211 )
6222 elif dirty:
6212 elif dirty:
6223 hint = _(b"uncommitted changes, use --all to discard all changes")
6213 hint = _(b"uncommitted changes, use --all to discard all changes")
6224 else:
6214 else:
6225 hint = _(b"use --all to revert all files")
6215 hint = _(b"use --all to revert all files")
6226 raise error.Abort(msg, hint=hint)
6216 raise error.Abort(msg, hint=hint)
6227
6217
6228 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6218 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6229
6219
6230
6220
6231 @command(
6221 @command(
6232 b'rollback',
6222 b'rollback',
6233 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6223 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6234 helpcategory=command.CATEGORY_MAINTENANCE,
6224 helpcategory=command.CATEGORY_MAINTENANCE,
6235 )
6225 )
6236 def rollback(ui, repo, **opts):
6226 def rollback(ui, repo, **opts):
6237 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6227 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6238
6228
6239 Please use :hg:`commit --amend` instead of rollback to correct
6229 Please use :hg:`commit --amend` instead of rollback to correct
6240 mistakes in the last commit.
6230 mistakes in the last commit.
6241
6231
6242 This command should be used with care. There is only one level of
6232 This command should be used with care. There is only one level of
6243 rollback, and there is no way to undo a rollback. It will also
6233 rollback, and there is no way to undo a rollback. It will also
6244 restore the dirstate at the time of the last transaction, losing
6234 restore the dirstate at the time of the last transaction, losing
6245 any dirstate changes since that time. This command does not alter
6235 any dirstate changes since that time. This command does not alter
6246 the working directory.
6236 the working directory.
6247
6237
6248 Transactions are used to encapsulate the effects of all commands
6238 Transactions are used to encapsulate the effects of all commands
6249 that create new changesets or propagate existing changesets into a
6239 that create new changesets or propagate existing changesets into a
6250 repository.
6240 repository.
6251
6241
6252 .. container:: verbose
6242 .. container:: verbose
6253
6243
6254 For example, the following commands are transactional, and their
6244 For example, the following commands are transactional, and their
6255 effects can be rolled back:
6245 effects can be rolled back:
6256
6246
6257 - commit
6247 - commit
6258 - import
6248 - import
6259 - pull
6249 - pull
6260 - push (with this repository as the destination)
6250 - push (with this repository as the destination)
6261 - unbundle
6251 - unbundle
6262
6252
6263 To avoid permanent data loss, rollback will refuse to rollback a
6253 To avoid permanent data loss, rollback will refuse to rollback a
6264 commit transaction if it isn't checked out. Use --force to
6254 commit transaction if it isn't checked out. Use --force to
6265 override this protection.
6255 override this protection.
6266
6256
6267 The rollback command can be entirely disabled by setting the
6257 The rollback command can be entirely disabled by setting the
6268 ``ui.rollback`` configuration setting to false. If you're here
6258 ``ui.rollback`` configuration setting to false. If you're here
6269 because you want to use rollback and it's disabled, you can
6259 because you want to use rollback and it's disabled, you can
6270 re-enable the command by setting ``ui.rollback`` to true.
6260 re-enable the command by setting ``ui.rollback`` to true.
6271
6261
6272 This command is not intended for use on public repositories. Once
6262 This command is not intended for use on public repositories. Once
6273 changes are visible for pull by other users, rolling a transaction
6263 changes are visible for pull by other users, rolling a transaction
6274 back locally is ineffective (someone else may already have pulled
6264 back locally is ineffective (someone else may already have pulled
6275 the changes). Furthermore, a race is possible with readers of the
6265 the changes). Furthermore, a race is possible with readers of the
6276 repository; for example an in-progress pull from the repository
6266 repository; for example an in-progress pull from the repository
6277 may fail if a rollback is performed.
6267 may fail if a rollback is performed.
6278
6268
6279 Returns 0 on success, 1 if no rollback data is available.
6269 Returns 0 on success, 1 if no rollback data is available.
6280 """
6270 """
6281 if not ui.configbool(b'ui', b'rollback'):
6271 if not ui.configbool(b'ui', b'rollback'):
6282 raise error.Abort(
6272 raise error.Abort(
6283 _(b'rollback is disabled because it is unsafe'),
6273 _(b'rollback is disabled because it is unsafe'),
6284 hint=b'see `hg help -v rollback` for information',
6274 hint=b'see `hg help -v rollback` for information',
6285 )
6275 )
6286 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6276 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6287
6277
6288
6278
6289 @command(
6279 @command(
6290 b'root',
6280 b'root',
6291 [] + formatteropts,
6281 [] + formatteropts,
6292 intents={INTENT_READONLY},
6282 intents={INTENT_READONLY},
6293 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6283 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6294 )
6284 )
6295 def root(ui, repo, **opts):
6285 def root(ui, repo, **opts):
6296 """print the root (top) of the current working directory
6286 """print the root (top) of the current working directory
6297
6287
6298 Print the root directory of the current repository.
6288 Print the root directory of the current repository.
6299
6289
6300 .. container:: verbose
6290 .. container:: verbose
6301
6291
6302 Template:
6292 Template:
6303
6293
6304 The following keywords are supported in addition to the common template
6294 The following keywords are supported in addition to the common template
6305 keywords and functions. See also :hg:`help templates`.
6295 keywords and functions. See also :hg:`help templates`.
6306
6296
6307 :hgpath: String. Path to the .hg directory.
6297 :hgpath: String. Path to the .hg directory.
6308 :storepath: String. Path to the directory holding versioned data.
6298 :storepath: String. Path to the directory holding versioned data.
6309
6299
6310 Returns 0 on success.
6300 Returns 0 on success.
6311 """
6301 """
6312 opts = pycompat.byteskwargs(opts)
6302 opts = pycompat.byteskwargs(opts)
6313 with ui.formatter(b'root', opts) as fm:
6303 with ui.formatter(b'root', opts) as fm:
6314 fm.startitem()
6304 fm.startitem()
6315 fm.write(b'reporoot', b'%s\n', repo.root)
6305 fm.write(b'reporoot', b'%s\n', repo.root)
6316 fm.data(hgpath=repo.path, storepath=repo.spath)
6306 fm.data(hgpath=repo.path, storepath=repo.spath)
6317
6307
6318
6308
6319 @command(
6309 @command(
6320 b'serve',
6310 b'serve',
6321 [
6311 [
6322 (
6312 (
6323 b'A',
6313 b'A',
6324 b'accesslog',
6314 b'accesslog',
6325 b'',
6315 b'',
6326 _(b'name of access log file to write to'),
6316 _(b'name of access log file to write to'),
6327 _(b'FILE'),
6317 _(b'FILE'),
6328 ),
6318 ),
6329 (b'd', b'daemon', None, _(b'run server in background')),
6319 (b'd', b'daemon', None, _(b'run server in background')),
6330 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6320 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6331 (
6321 (
6332 b'E',
6322 b'E',
6333 b'errorlog',
6323 b'errorlog',
6334 b'',
6324 b'',
6335 _(b'name of error log file to write to'),
6325 _(b'name of error log file to write to'),
6336 _(b'FILE'),
6326 _(b'FILE'),
6337 ),
6327 ),
6338 # use string type, then we can check if something was passed
6328 # use string type, then we can check if something was passed
6339 (
6329 (
6340 b'p',
6330 b'p',
6341 b'port',
6331 b'port',
6342 b'',
6332 b'',
6343 _(b'port to listen on (default: 8000)'),
6333 _(b'port to listen on (default: 8000)'),
6344 _(b'PORT'),
6334 _(b'PORT'),
6345 ),
6335 ),
6346 (
6336 (
6347 b'a',
6337 b'a',
6348 b'address',
6338 b'address',
6349 b'',
6339 b'',
6350 _(b'address to listen on (default: all interfaces)'),
6340 _(b'address to listen on (default: all interfaces)'),
6351 _(b'ADDR'),
6341 _(b'ADDR'),
6352 ),
6342 ),
6353 (
6343 (
6354 b'',
6344 b'',
6355 b'prefix',
6345 b'prefix',
6356 b'',
6346 b'',
6357 _(b'prefix path to serve from (default: server root)'),
6347 _(b'prefix path to serve from (default: server root)'),
6358 _(b'PREFIX'),
6348 _(b'PREFIX'),
6359 ),
6349 ),
6360 (
6350 (
6361 b'n',
6351 b'n',
6362 b'name',
6352 b'name',
6363 b'',
6353 b'',
6364 _(b'name to show in web pages (default: working directory)'),
6354 _(b'name to show in web pages (default: working directory)'),
6365 _(b'NAME'),
6355 _(b'NAME'),
6366 ),
6356 ),
6367 (
6357 (
6368 b'',
6358 b'',
6369 b'web-conf',
6359 b'web-conf',
6370 b'',
6360 b'',
6371 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6361 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6372 _(b'FILE'),
6362 _(b'FILE'),
6373 ),
6363 ),
6374 (
6364 (
6375 b'',
6365 b'',
6376 b'webdir-conf',
6366 b'webdir-conf',
6377 b'',
6367 b'',
6378 _(b'name of the hgweb config file (DEPRECATED)'),
6368 _(b'name of the hgweb config file (DEPRECATED)'),
6379 _(b'FILE'),
6369 _(b'FILE'),
6380 ),
6370 ),
6381 (
6371 (
6382 b'',
6372 b'',
6383 b'pid-file',
6373 b'pid-file',
6384 b'',
6374 b'',
6385 _(b'name of file to write process ID to'),
6375 _(b'name of file to write process ID to'),
6386 _(b'FILE'),
6376 _(b'FILE'),
6387 ),
6377 ),
6388 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6378 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6389 (
6379 (
6390 b'',
6380 b'',
6391 b'cmdserver',
6381 b'cmdserver',
6392 b'',
6382 b'',
6393 _(b'for remote clients (ADVANCED)'),
6383 _(b'for remote clients (ADVANCED)'),
6394 _(b'MODE'),
6384 _(b'MODE'),
6395 ),
6385 ),
6396 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6386 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6397 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6387 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6398 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6388 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6399 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6389 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6400 (b'', b'print-url', None, _(b'start and print only the URL')),
6390 (b'', b'print-url', None, _(b'start and print only the URL')),
6401 ]
6391 ]
6402 + subrepoopts,
6392 + subrepoopts,
6403 _(b'[OPTION]...'),
6393 _(b'[OPTION]...'),
6404 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6394 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6405 helpbasic=True,
6395 helpbasic=True,
6406 optionalrepo=True,
6396 optionalrepo=True,
6407 )
6397 )
6408 def serve(ui, repo, **opts):
6398 def serve(ui, repo, **opts):
6409 """start stand-alone webserver
6399 """start stand-alone webserver
6410
6400
6411 Start a local HTTP repository browser and pull server. You can use
6401 Start a local HTTP repository browser and pull server. You can use
6412 this for ad-hoc sharing and browsing of repositories. It is
6402 this for ad-hoc sharing and browsing of repositories. It is
6413 recommended to use a real web server to serve a repository for
6403 recommended to use a real web server to serve a repository for
6414 longer periods of time.
6404 longer periods of time.
6415
6405
6416 Please note that the server does not implement access control.
6406 Please note that the server does not implement access control.
6417 This means that, by default, anybody can read from the server and
6407 This means that, by default, anybody can read from the server and
6418 nobody can write to it by default. Set the ``web.allow-push``
6408 nobody can write to it by default. Set the ``web.allow-push``
6419 option to ``*`` to allow everybody to push to the server. You
6409 option to ``*`` to allow everybody to push to the server. You
6420 should use a real web server if you need to authenticate users.
6410 should use a real web server if you need to authenticate users.
6421
6411
6422 By default, the server logs accesses to stdout and errors to
6412 By default, the server logs accesses to stdout and errors to
6423 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6413 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6424 files.
6414 files.
6425
6415
6426 To have the server choose a free port number to listen on, specify
6416 To have the server choose a free port number to listen on, specify
6427 a port number of 0; in this case, the server will print the port
6417 a port number of 0; in this case, the server will print the port
6428 number it uses.
6418 number it uses.
6429
6419
6430 Returns 0 on success.
6420 Returns 0 on success.
6431 """
6421 """
6432
6422
6433 opts = pycompat.byteskwargs(opts)
6423 opts = pycompat.byteskwargs(opts)
6434 if opts[b"stdio"] and opts[b"cmdserver"]:
6424 if opts[b"stdio"] and opts[b"cmdserver"]:
6435 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6425 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6436 if opts[b"print_url"] and ui.verbose:
6426 if opts[b"print_url"] and ui.verbose:
6437 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6427 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6438
6428
6439 if opts[b"stdio"]:
6429 if opts[b"stdio"]:
6440 if repo is None:
6430 if repo is None:
6441 raise error.RepoError(
6431 raise error.RepoError(
6442 _(b"there is no Mercurial repository here (.hg not found)")
6432 _(b"there is no Mercurial repository here (.hg not found)")
6443 )
6433 )
6444 s = wireprotoserver.sshserver(ui, repo)
6434 s = wireprotoserver.sshserver(ui, repo)
6445 s.serve_forever()
6435 s.serve_forever()
6446
6436
6447 service = server.createservice(ui, repo, opts)
6437 service = server.createservice(ui, repo, opts)
6448 return server.runservice(opts, initfn=service.init, runfn=service.run)
6438 return server.runservice(opts, initfn=service.init, runfn=service.run)
6449
6439
6450
6440
6451 @command(
6441 @command(
6452 b'shelve',
6442 b'shelve',
6453 [
6443 [
6454 (
6444 (
6455 b'A',
6445 b'A',
6456 b'addremove',
6446 b'addremove',
6457 None,
6447 None,
6458 _(b'mark new/missing files as added/removed before shelving'),
6448 _(b'mark new/missing files as added/removed before shelving'),
6459 ),
6449 ),
6460 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6450 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6461 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6451 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6462 (
6452 (
6463 b'',
6453 b'',
6464 b'date',
6454 b'date',
6465 b'',
6455 b'',
6466 _(b'shelve with the specified commit date'),
6456 _(b'shelve with the specified commit date'),
6467 _(b'DATE'),
6457 _(b'DATE'),
6468 ),
6458 ),
6469 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6459 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6470 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6460 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6471 (
6461 (
6472 b'k',
6462 b'k',
6473 b'keep',
6463 b'keep',
6474 False,
6464 False,
6475 _(b'shelve, but keep changes in the working directory'),
6465 _(b'shelve, but keep changes in the working directory'),
6476 ),
6466 ),
6477 (b'l', b'list', None, _(b'list current shelves')),
6467 (b'l', b'list', None, _(b'list current shelves')),
6478 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6468 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6479 (
6469 (
6480 b'n',
6470 b'n',
6481 b'name',
6471 b'name',
6482 b'',
6472 b'',
6483 _(b'use the given name for the shelved commit'),
6473 _(b'use the given name for the shelved commit'),
6484 _(b'NAME'),
6474 _(b'NAME'),
6485 ),
6475 ),
6486 (
6476 (
6487 b'p',
6477 b'p',
6488 b'patch',
6478 b'patch',
6489 None,
6479 None,
6490 _(
6480 _(
6491 b'output patches for changes (provide the names of the shelved '
6481 b'output patches for changes (provide the names of the shelved '
6492 b'changes as positional arguments)'
6482 b'changes as positional arguments)'
6493 ),
6483 ),
6494 ),
6484 ),
6495 (b'i', b'interactive', None, _(b'interactive mode')),
6485 (b'i', b'interactive', None, _(b'interactive mode')),
6496 (
6486 (
6497 b'',
6487 b'',
6498 b'stat',
6488 b'stat',
6499 None,
6489 None,
6500 _(
6490 _(
6501 b'output diffstat-style summary of changes (provide the names of '
6491 b'output diffstat-style summary of changes (provide the names of '
6502 b'the shelved changes as positional arguments)'
6492 b'the shelved changes as positional arguments)'
6503 ),
6493 ),
6504 ),
6494 ),
6505 ]
6495 ]
6506 + cmdutil.walkopts,
6496 + cmdutil.walkopts,
6507 _(b'hg shelve [OPTION]... [FILE]...'),
6497 _(b'hg shelve [OPTION]... [FILE]...'),
6508 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6498 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6509 )
6499 )
6510 def shelve(ui, repo, *pats, **opts):
6500 def shelve(ui, repo, *pats, **opts):
6511 '''save and set aside changes from the working directory
6501 '''save and set aside changes from the working directory
6512
6502
6513 Shelving takes files that "hg status" reports as not clean, saves
6503 Shelving takes files that "hg status" reports as not clean, saves
6514 the modifications to a bundle (a shelved change), and reverts the
6504 the modifications to a bundle (a shelved change), and reverts the
6515 files so that their state in the working directory becomes clean.
6505 files so that their state in the working directory becomes clean.
6516
6506
6517 To restore these changes to the working directory, using "hg
6507 To restore these changes to the working directory, using "hg
6518 unshelve"; this will work even if you switch to a different
6508 unshelve"; this will work even if you switch to a different
6519 commit.
6509 commit.
6520
6510
6521 When no files are specified, "hg shelve" saves all not-clean
6511 When no files are specified, "hg shelve" saves all not-clean
6522 files. If specific files or directories are named, only changes to
6512 files. If specific files or directories are named, only changes to
6523 those files are shelved.
6513 those files are shelved.
6524
6514
6525 In bare shelve (when no files are specified, without interactive,
6515 In bare shelve (when no files are specified, without interactive,
6526 include and exclude option), shelving remembers information if the
6516 include and exclude option), shelving remembers information if the
6527 working directory was on newly created branch, in other words working
6517 working directory was on newly created branch, in other words working
6528 directory was on different branch than its first parent. In this
6518 directory was on different branch than its first parent. In this
6529 situation unshelving restores branch information to the working directory.
6519 situation unshelving restores branch information to the working directory.
6530
6520
6531 Each shelved change has a name that makes it easier to find later.
6521 Each shelved change has a name that makes it easier to find later.
6532 The name of a shelved change defaults to being based on the active
6522 The name of a shelved change defaults to being based on the active
6533 bookmark, or if there is no active bookmark, the current named
6523 bookmark, or if there is no active bookmark, the current named
6534 branch. To specify a different name, use ``--name``.
6524 branch. To specify a different name, use ``--name``.
6535
6525
6536 To see a list of existing shelved changes, use the ``--list``
6526 To see a list of existing shelved changes, use the ``--list``
6537 option. For each shelved change, this will print its name, age,
6527 option. For each shelved change, this will print its name, age,
6538 and description; use ``--patch`` or ``--stat`` for more details.
6528 and description; use ``--patch`` or ``--stat`` for more details.
6539
6529
6540 To delete specific shelved changes, use ``--delete``. To delete
6530 To delete specific shelved changes, use ``--delete``. To delete
6541 all shelved changes, use ``--cleanup``.
6531 all shelved changes, use ``--cleanup``.
6542 '''
6532 '''
6543 opts = pycompat.byteskwargs(opts)
6533 opts = pycompat.byteskwargs(opts)
6544 allowables = [
6534 allowables = [
6545 (b'addremove', {b'create'}), # 'create' is pseudo action
6535 (b'addremove', {b'create'}), # 'create' is pseudo action
6546 (b'unknown', {b'create'}),
6536 (b'unknown', {b'create'}),
6547 (b'cleanup', {b'cleanup'}),
6537 (b'cleanup', {b'cleanup'}),
6548 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6538 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6549 (b'delete', {b'delete'}),
6539 (b'delete', {b'delete'}),
6550 (b'edit', {b'create'}),
6540 (b'edit', {b'create'}),
6551 (b'keep', {b'create'}),
6541 (b'keep', {b'create'}),
6552 (b'list', {b'list'}),
6542 (b'list', {b'list'}),
6553 (b'message', {b'create'}),
6543 (b'message', {b'create'}),
6554 (b'name', {b'create'}),
6544 (b'name', {b'create'}),
6555 (b'patch', {b'patch', b'list'}),
6545 (b'patch', {b'patch', b'list'}),
6556 (b'stat', {b'stat', b'list'}),
6546 (b'stat', {b'stat', b'list'}),
6557 ]
6547 ]
6558
6548
6559 def checkopt(opt):
6549 def checkopt(opt):
6560 if opts.get(opt):
6550 if opts.get(opt):
6561 for i, allowable in allowables:
6551 for i, allowable in allowables:
6562 if opts[i] and opt not in allowable:
6552 if opts[i] and opt not in allowable:
6563 raise error.Abort(
6553 raise error.Abort(
6564 _(
6554 _(
6565 b"options '--%s' and '--%s' may not be "
6555 b"options '--%s' and '--%s' may not be "
6566 b"used together"
6556 b"used together"
6567 )
6557 )
6568 % (opt, i)
6558 % (opt, i)
6569 )
6559 )
6570 return True
6560 return True
6571
6561
6572 if checkopt(b'cleanup'):
6562 if checkopt(b'cleanup'):
6573 if pats:
6563 if pats:
6574 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6564 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6575 return shelvemod.cleanupcmd(ui, repo)
6565 return shelvemod.cleanupcmd(ui, repo)
6576 elif checkopt(b'delete'):
6566 elif checkopt(b'delete'):
6577 return shelvemod.deletecmd(ui, repo, pats)
6567 return shelvemod.deletecmd(ui, repo, pats)
6578 elif checkopt(b'list'):
6568 elif checkopt(b'list'):
6579 return shelvemod.listcmd(ui, repo, pats, opts)
6569 return shelvemod.listcmd(ui, repo, pats, opts)
6580 elif checkopt(b'patch') or checkopt(b'stat'):
6570 elif checkopt(b'patch') or checkopt(b'stat'):
6581 return shelvemod.patchcmds(ui, repo, pats, opts)
6571 return shelvemod.patchcmds(ui, repo, pats, opts)
6582 else:
6572 else:
6583 return shelvemod.createcmd(ui, repo, pats, opts)
6573 return shelvemod.createcmd(ui, repo, pats, opts)
6584
6574
6585
6575
6586 _NOTTERSE = b'nothing'
6576 _NOTTERSE = b'nothing'
6587
6577
6588
6578
6589 @command(
6579 @command(
6590 b'status|st',
6580 b'status|st',
6591 [
6581 [
6592 (b'A', b'all', None, _(b'show status of all files')),
6582 (b'A', b'all', None, _(b'show status of all files')),
6593 (b'm', b'modified', None, _(b'show only modified files')),
6583 (b'm', b'modified', None, _(b'show only modified files')),
6594 (b'a', b'added', None, _(b'show only added files')),
6584 (b'a', b'added', None, _(b'show only added files')),
6595 (b'r', b'removed', None, _(b'show only removed files')),
6585 (b'r', b'removed', None, _(b'show only removed files')),
6596 (b'd', b'deleted', None, _(b'show only missing files')),
6586 (b'd', b'deleted', None, _(b'show only missing files')),
6597 (b'c', b'clean', None, _(b'show only files without changes')),
6587 (b'c', b'clean', None, _(b'show only files without changes')),
6598 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6588 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6599 (b'i', b'ignored', None, _(b'show only ignored files')),
6589 (b'i', b'ignored', None, _(b'show only ignored files')),
6600 (b'n', b'no-status', None, _(b'hide status prefix')),
6590 (b'n', b'no-status', None, _(b'hide status prefix')),
6601 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6591 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6602 (
6592 (
6603 b'C',
6593 b'C',
6604 b'copies',
6594 b'copies',
6605 None,
6595 None,
6606 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6596 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6607 ),
6597 ),
6608 (
6598 (
6609 b'0',
6599 b'0',
6610 b'print0',
6600 b'print0',
6611 None,
6601 None,
6612 _(b'end filenames with NUL, for use with xargs'),
6602 _(b'end filenames with NUL, for use with xargs'),
6613 ),
6603 ),
6614 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6604 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6615 (
6605 (
6616 b'',
6606 b'',
6617 b'change',
6607 b'change',
6618 b'',
6608 b'',
6619 _(b'list the changed files of a revision'),
6609 _(b'list the changed files of a revision'),
6620 _(b'REV'),
6610 _(b'REV'),
6621 ),
6611 ),
6622 ]
6612 ]
6623 + walkopts
6613 + walkopts
6624 + subrepoopts
6614 + subrepoopts
6625 + formatteropts,
6615 + formatteropts,
6626 _(b'[OPTION]... [FILE]...'),
6616 _(b'[OPTION]... [FILE]...'),
6627 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6617 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6628 helpbasic=True,
6618 helpbasic=True,
6629 inferrepo=True,
6619 inferrepo=True,
6630 intents={INTENT_READONLY},
6620 intents={INTENT_READONLY},
6631 )
6621 )
6632 def status(ui, repo, *pats, **opts):
6622 def status(ui, repo, *pats, **opts):
6633 """show changed files in the working directory
6623 """show changed files in the working directory
6634
6624
6635 Show status of files in the repository. If names are given, only
6625 Show status of files in the repository. If names are given, only
6636 files that match are shown. Files that are clean or ignored or
6626 files that match are shown. Files that are clean or ignored or
6637 the source of a copy/move operation, are not listed unless
6627 the source of a copy/move operation, are not listed unless
6638 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6628 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6639 Unless options described with "show only ..." are given, the
6629 Unless options described with "show only ..." are given, the
6640 options -mardu are used.
6630 options -mardu are used.
6641
6631
6642 Option -q/--quiet hides untracked (unknown and ignored) files
6632 Option -q/--quiet hides untracked (unknown and ignored) files
6643 unless explicitly requested with -u/--unknown or -i/--ignored.
6633 unless explicitly requested with -u/--unknown or -i/--ignored.
6644
6634
6645 .. note::
6635 .. note::
6646
6636
6647 :hg:`status` may appear to disagree with diff if permissions have
6637 :hg:`status` may appear to disagree with diff if permissions have
6648 changed or a merge has occurred. The standard diff format does
6638 changed or a merge has occurred. The standard diff format does
6649 not report permission changes and diff only reports changes
6639 not report permission changes and diff only reports changes
6650 relative to one merge parent.
6640 relative to one merge parent.
6651
6641
6652 If one revision is given, it is used as the base revision.
6642 If one revision is given, it is used as the base revision.
6653 If two revisions are given, the differences between them are
6643 If two revisions are given, the differences between them are
6654 shown. The --change option can also be used as a shortcut to list
6644 shown. The --change option can also be used as a shortcut to list
6655 the changed files of a revision from its first parent.
6645 the changed files of a revision from its first parent.
6656
6646
6657 The codes used to show the status of files are::
6647 The codes used to show the status of files are::
6658
6648
6659 M = modified
6649 M = modified
6660 A = added
6650 A = added
6661 R = removed
6651 R = removed
6662 C = clean
6652 C = clean
6663 ! = missing (deleted by non-hg command, but still tracked)
6653 ! = missing (deleted by non-hg command, but still tracked)
6664 ? = not tracked
6654 ? = not tracked
6665 I = ignored
6655 I = ignored
6666 = origin of the previous file (with --copies)
6656 = origin of the previous file (with --copies)
6667
6657
6668 .. container:: verbose
6658 .. container:: verbose
6669
6659
6670 The -t/--terse option abbreviates the output by showing only the directory
6660 The -t/--terse option abbreviates the output by showing only the directory
6671 name if all the files in it share the same status. The option takes an
6661 name if all the files in it share the same status. The option takes an
6672 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6662 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6673 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6663 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6674 for 'ignored' and 'c' for clean.
6664 for 'ignored' and 'c' for clean.
6675
6665
6676 It abbreviates only those statuses which are passed. Note that clean and
6666 It abbreviates only those statuses which are passed. Note that clean and
6677 ignored files are not displayed with '--terse ic' unless the -c/--clean
6667 ignored files are not displayed with '--terse ic' unless the -c/--clean
6678 and -i/--ignored options are also used.
6668 and -i/--ignored options are also used.
6679
6669
6680 The -v/--verbose option shows information when the repository is in an
6670 The -v/--verbose option shows information when the repository is in an
6681 unfinished merge, shelve, rebase state etc. You can have this behavior
6671 unfinished merge, shelve, rebase state etc. You can have this behavior
6682 turned on by default by enabling the ``commands.status.verbose`` option.
6672 turned on by default by enabling the ``commands.status.verbose`` option.
6683
6673
6684 You can skip displaying some of these states by setting
6674 You can skip displaying some of these states by setting
6685 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6675 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6686 'histedit', 'merge', 'rebase', or 'unshelve'.
6676 'histedit', 'merge', 'rebase', or 'unshelve'.
6687
6677
6688 Template:
6678 Template:
6689
6679
6690 The following keywords are supported in addition to the common template
6680 The following keywords are supported in addition to the common template
6691 keywords and functions. See also :hg:`help templates`.
6681 keywords and functions. See also :hg:`help templates`.
6692
6682
6693 :path: String. Repository-absolute path of the file.
6683 :path: String. Repository-absolute path of the file.
6694 :source: String. Repository-absolute path of the file originated from.
6684 :source: String. Repository-absolute path of the file originated from.
6695 Available if ``--copies`` is specified.
6685 Available if ``--copies`` is specified.
6696 :status: String. Character denoting file's status.
6686 :status: String. Character denoting file's status.
6697
6687
6698 Examples:
6688 Examples:
6699
6689
6700 - show changes in the working directory relative to a
6690 - show changes in the working directory relative to a
6701 changeset::
6691 changeset::
6702
6692
6703 hg status --rev 9353
6693 hg status --rev 9353
6704
6694
6705 - show changes in the working directory relative to the
6695 - show changes in the working directory relative to the
6706 current directory (see :hg:`help patterns` for more information)::
6696 current directory (see :hg:`help patterns` for more information)::
6707
6697
6708 hg status re:
6698 hg status re:
6709
6699
6710 - show all changes including copies in an existing changeset::
6700 - show all changes including copies in an existing changeset::
6711
6701
6712 hg status --copies --change 9353
6702 hg status --copies --change 9353
6713
6703
6714 - get a NUL separated list of added files, suitable for xargs::
6704 - get a NUL separated list of added files, suitable for xargs::
6715
6705
6716 hg status -an0
6706 hg status -an0
6717
6707
6718 - show more information about the repository status, abbreviating
6708 - show more information about the repository status, abbreviating
6719 added, removed, modified, deleted, and untracked paths::
6709 added, removed, modified, deleted, and untracked paths::
6720
6710
6721 hg status -v -t mardu
6711 hg status -v -t mardu
6722
6712
6723 Returns 0 on success.
6713 Returns 0 on success.
6724
6714
6725 """
6715 """
6726
6716
6727 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6717 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6728 opts = pycompat.byteskwargs(opts)
6718 opts = pycompat.byteskwargs(opts)
6729 revs = opts.get(b'rev')
6719 revs = opts.get(b'rev')
6730 change = opts.get(b'change')
6720 change = opts.get(b'change')
6731 terse = opts.get(b'terse')
6721 terse = opts.get(b'terse')
6732 if terse is _NOTTERSE:
6722 if terse is _NOTTERSE:
6733 if revs:
6723 if revs:
6734 terse = b''
6724 terse = b''
6735 else:
6725 else:
6736 terse = ui.config(b'commands', b'status.terse')
6726 terse = ui.config(b'commands', b'status.terse')
6737
6727
6738 if revs and terse:
6728 if revs and terse:
6739 msg = _(b'cannot use --terse with --rev')
6729 msg = _(b'cannot use --terse with --rev')
6740 raise error.Abort(msg)
6730 raise error.Abort(msg)
6741 elif change:
6731 elif change:
6742 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6732 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6743 ctx2 = scmutil.revsingle(repo, change, None)
6733 ctx2 = scmutil.revsingle(repo, change, None)
6744 ctx1 = ctx2.p1()
6734 ctx1 = ctx2.p1()
6745 else:
6735 else:
6746 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6736 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6747 ctx1, ctx2 = scmutil.revpair(repo, revs)
6737 ctx1, ctx2 = scmutil.revpair(repo, revs)
6748
6738
6749 forcerelativevalue = None
6739 forcerelativevalue = None
6750 if ui.hasconfig(b'commands', b'status.relative'):
6740 if ui.hasconfig(b'commands', b'status.relative'):
6751 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6741 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6752 uipathfn = scmutil.getuipathfn(
6742 uipathfn = scmutil.getuipathfn(
6753 repo,
6743 repo,
6754 legacyrelativevalue=bool(pats),
6744 legacyrelativevalue=bool(pats),
6755 forcerelativevalue=forcerelativevalue,
6745 forcerelativevalue=forcerelativevalue,
6756 )
6746 )
6757
6747
6758 if opts.get(b'print0'):
6748 if opts.get(b'print0'):
6759 end = b'\0'
6749 end = b'\0'
6760 else:
6750 else:
6761 end = b'\n'
6751 end = b'\n'
6762 states = b'modified added removed deleted unknown ignored clean'.split()
6752 states = b'modified added removed deleted unknown ignored clean'.split()
6763 show = [k for k in states if opts.get(k)]
6753 show = [k for k in states if opts.get(k)]
6764 if opts.get(b'all'):
6754 if opts.get(b'all'):
6765 show += ui.quiet and (states[:4] + [b'clean']) or states
6755 show += ui.quiet and (states[:4] + [b'clean']) or states
6766
6756
6767 if not show:
6757 if not show:
6768 if ui.quiet:
6758 if ui.quiet:
6769 show = states[:4]
6759 show = states[:4]
6770 else:
6760 else:
6771 show = states[:5]
6761 show = states[:5]
6772
6762
6773 m = scmutil.match(ctx2, pats, opts)
6763 m = scmutil.match(ctx2, pats, opts)
6774 if terse:
6764 if terse:
6775 # we need to compute clean and unknown to terse
6765 # we need to compute clean and unknown to terse
6776 stat = repo.status(
6766 stat = repo.status(
6777 ctx1.node(),
6767 ctx1.node(),
6778 ctx2.node(),
6768 ctx2.node(),
6779 m,
6769 m,
6780 b'ignored' in show or b'i' in terse,
6770 b'ignored' in show or b'i' in terse,
6781 clean=True,
6771 clean=True,
6782 unknown=True,
6772 unknown=True,
6783 listsubrepos=opts.get(b'subrepos'),
6773 listsubrepos=opts.get(b'subrepos'),
6784 )
6774 )
6785
6775
6786 stat = cmdutil.tersedir(stat, terse)
6776 stat = cmdutil.tersedir(stat, terse)
6787 else:
6777 else:
6788 stat = repo.status(
6778 stat = repo.status(
6789 ctx1.node(),
6779 ctx1.node(),
6790 ctx2.node(),
6780 ctx2.node(),
6791 m,
6781 m,
6792 b'ignored' in show,
6782 b'ignored' in show,
6793 b'clean' in show,
6783 b'clean' in show,
6794 b'unknown' in show,
6784 b'unknown' in show,
6795 opts.get(b'subrepos'),
6785 opts.get(b'subrepos'),
6796 )
6786 )
6797
6787
6798 changestates = zip(
6788 changestates = zip(
6799 states,
6789 states,
6800 pycompat.iterbytestr(b'MAR!?IC'),
6790 pycompat.iterbytestr(b'MAR!?IC'),
6801 [getattr(stat, s.decode('utf8')) for s in states],
6791 [getattr(stat, s.decode('utf8')) for s in states],
6802 )
6792 )
6803
6793
6804 copy = {}
6794 copy = {}
6805 if (
6795 if (
6806 opts.get(b'all')
6796 opts.get(b'all')
6807 or opts.get(b'copies')
6797 or opts.get(b'copies')
6808 or ui.configbool(b'ui', b'statuscopies')
6798 or ui.configbool(b'ui', b'statuscopies')
6809 ) and not opts.get(b'no_status'):
6799 ) and not opts.get(b'no_status'):
6810 copy = copies.pathcopies(ctx1, ctx2, m)
6800 copy = copies.pathcopies(ctx1, ctx2, m)
6811
6801
6812 morestatus = None
6802 morestatus = None
6813 if (
6803 if (
6814 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6804 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6815 ) and not ui.plain():
6805 ) and not ui.plain():
6816 morestatus = cmdutil.readmorestatus(repo)
6806 morestatus = cmdutil.readmorestatus(repo)
6817
6807
6818 ui.pager(b'status')
6808 ui.pager(b'status')
6819 fm = ui.formatter(b'status', opts)
6809 fm = ui.formatter(b'status', opts)
6820 fmt = b'%s' + end
6810 fmt = b'%s' + end
6821 showchar = not opts.get(b'no_status')
6811 showchar = not opts.get(b'no_status')
6822
6812
6823 for state, char, files in changestates:
6813 for state, char, files in changestates:
6824 if state in show:
6814 if state in show:
6825 label = b'status.' + state
6815 label = b'status.' + state
6826 for f in files:
6816 for f in files:
6827 fm.startitem()
6817 fm.startitem()
6828 fm.context(ctx=ctx2)
6818 fm.context(ctx=ctx2)
6829 fm.data(itemtype=b'file', path=f)
6819 fm.data(itemtype=b'file', path=f)
6830 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6820 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6831 fm.plain(fmt % uipathfn(f), label=label)
6821 fm.plain(fmt % uipathfn(f), label=label)
6832 if f in copy:
6822 if f in copy:
6833 fm.data(source=copy[f])
6823 fm.data(source=copy[f])
6834 fm.plain(
6824 fm.plain(
6835 (b' %s' + end) % uipathfn(copy[f]),
6825 (b' %s' + end) % uipathfn(copy[f]),
6836 label=b'status.copied',
6826 label=b'status.copied',
6837 )
6827 )
6838 if morestatus:
6828 if morestatus:
6839 morestatus.formatfile(f, fm)
6829 morestatus.formatfile(f, fm)
6840
6830
6841 if morestatus:
6831 if morestatus:
6842 morestatus.formatfooter(fm)
6832 morestatus.formatfooter(fm)
6843 fm.end()
6833 fm.end()
6844
6834
6845
6835
6846 @command(
6836 @command(
6847 b'summary|sum',
6837 b'summary|sum',
6848 [(b'', b'remote', None, _(b'check for push and pull'))],
6838 [(b'', b'remote', None, _(b'check for push and pull'))],
6849 b'[--remote]',
6839 b'[--remote]',
6850 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6840 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6851 helpbasic=True,
6841 helpbasic=True,
6852 intents={INTENT_READONLY},
6842 intents={INTENT_READONLY},
6853 )
6843 )
6854 def summary(ui, repo, **opts):
6844 def summary(ui, repo, **opts):
6855 """summarize working directory state
6845 """summarize working directory state
6856
6846
6857 This generates a brief summary of the working directory state,
6847 This generates a brief summary of the working directory state,
6858 including parents, branch, commit status, phase and available updates.
6848 including parents, branch, commit status, phase and available updates.
6859
6849
6860 With the --remote option, this will check the default paths for
6850 With the --remote option, this will check the default paths for
6861 incoming and outgoing changes. This can be time-consuming.
6851 incoming and outgoing changes. This can be time-consuming.
6862
6852
6863 Returns 0 on success.
6853 Returns 0 on success.
6864 """
6854 """
6865
6855
6866 opts = pycompat.byteskwargs(opts)
6856 opts = pycompat.byteskwargs(opts)
6867 ui.pager(b'summary')
6857 ui.pager(b'summary')
6868 ctx = repo[None]
6858 ctx = repo[None]
6869 parents = ctx.parents()
6859 parents = ctx.parents()
6870 pnode = parents[0].node()
6860 pnode = parents[0].node()
6871 marks = []
6861 marks = []
6872
6862
6873 try:
6863 try:
6874 ms = mergestatemod.mergestate.read(repo)
6864 ms = mergestatemod.mergestate.read(repo)
6875 except error.UnsupportedMergeRecords as e:
6865 except error.UnsupportedMergeRecords as e:
6876 s = b' '.join(e.recordtypes)
6866 s = b' '.join(e.recordtypes)
6877 ui.warn(
6867 ui.warn(
6878 _(b'warning: merge state has unsupported record types: %s\n') % s
6868 _(b'warning: merge state has unsupported record types: %s\n') % s
6879 )
6869 )
6880 unresolved = []
6870 unresolved = []
6881 else:
6871 else:
6882 unresolved = list(ms.unresolved())
6872 unresolved = list(ms.unresolved())
6883
6873
6884 for p in parents:
6874 for p in parents:
6885 # label with log.changeset (instead of log.parent) since this
6875 # label with log.changeset (instead of log.parent) since this
6886 # shows a working directory parent *changeset*:
6876 # shows a working directory parent *changeset*:
6887 # i18n: column positioning for "hg summary"
6877 # i18n: column positioning for "hg summary"
6888 ui.write(
6878 ui.write(
6889 _(b'parent: %d:%s ') % (p.rev(), p),
6879 _(b'parent: %d:%s ') % (p.rev(), p),
6890 label=logcmdutil.changesetlabels(p),
6880 label=logcmdutil.changesetlabels(p),
6891 )
6881 )
6892 ui.write(b' '.join(p.tags()), label=b'log.tag')
6882 ui.write(b' '.join(p.tags()), label=b'log.tag')
6893 if p.bookmarks():
6883 if p.bookmarks():
6894 marks.extend(p.bookmarks())
6884 marks.extend(p.bookmarks())
6895 if p.rev() == -1:
6885 if p.rev() == -1:
6896 if not len(repo):
6886 if not len(repo):
6897 ui.write(_(b' (empty repository)'))
6887 ui.write(_(b' (empty repository)'))
6898 else:
6888 else:
6899 ui.write(_(b' (no revision checked out)'))
6889 ui.write(_(b' (no revision checked out)'))
6900 if p.obsolete():
6890 if p.obsolete():
6901 ui.write(_(b' (obsolete)'))
6891 ui.write(_(b' (obsolete)'))
6902 if p.isunstable():
6892 if p.isunstable():
6903 instabilities = (
6893 instabilities = (
6904 ui.label(instability, b'trouble.%s' % instability)
6894 ui.label(instability, b'trouble.%s' % instability)
6905 for instability in p.instabilities()
6895 for instability in p.instabilities()
6906 )
6896 )
6907 ui.write(b' (' + b', '.join(instabilities) + b')')
6897 ui.write(b' (' + b', '.join(instabilities) + b')')
6908 ui.write(b'\n')
6898 ui.write(b'\n')
6909 if p.description():
6899 if p.description():
6910 ui.status(
6900 ui.status(
6911 b' ' + p.description().splitlines()[0].strip() + b'\n',
6901 b' ' + p.description().splitlines()[0].strip() + b'\n',
6912 label=b'log.summary',
6902 label=b'log.summary',
6913 )
6903 )
6914
6904
6915 branch = ctx.branch()
6905 branch = ctx.branch()
6916 bheads = repo.branchheads(branch)
6906 bheads = repo.branchheads(branch)
6917 # i18n: column positioning for "hg summary"
6907 # i18n: column positioning for "hg summary"
6918 m = _(b'branch: %s\n') % branch
6908 m = _(b'branch: %s\n') % branch
6919 if branch != b'default':
6909 if branch != b'default':
6920 ui.write(m, label=b'log.branch')
6910 ui.write(m, label=b'log.branch')
6921 else:
6911 else:
6922 ui.status(m, label=b'log.branch')
6912 ui.status(m, label=b'log.branch')
6923
6913
6924 if marks:
6914 if marks:
6925 active = repo._activebookmark
6915 active = repo._activebookmark
6926 # i18n: column positioning for "hg summary"
6916 # i18n: column positioning for "hg summary"
6927 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6917 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6928 if active is not None:
6918 if active is not None:
6929 if active in marks:
6919 if active in marks:
6930 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6920 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6931 marks.remove(active)
6921 marks.remove(active)
6932 else:
6922 else:
6933 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6923 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6934 for m in marks:
6924 for m in marks:
6935 ui.write(b' ' + m, label=b'log.bookmark')
6925 ui.write(b' ' + m, label=b'log.bookmark')
6936 ui.write(b'\n', label=b'log.bookmark')
6926 ui.write(b'\n', label=b'log.bookmark')
6937
6927
6938 status = repo.status(unknown=True)
6928 status = repo.status(unknown=True)
6939
6929
6940 c = repo.dirstate.copies()
6930 c = repo.dirstate.copies()
6941 copied, renamed = [], []
6931 copied, renamed = [], []
6942 for d, s in pycompat.iteritems(c):
6932 for d, s in pycompat.iteritems(c):
6943 if s in status.removed:
6933 if s in status.removed:
6944 status.removed.remove(s)
6934 status.removed.remove(s)
6945 renamed.append(d)
6935 renamed.append(d)
6946 else:
6936 else:
6947 copied.append(d)
6937 copied.append(d)
6948 if d in status.added:
6938 if d in status.added:
6949 status.added.remove(d)
6939 status.added.remove(d)
6950
6940
6951 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6941 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6952
6942
6953 labels = [
6943 labels = [
6954 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6944 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6955 (ui.label(_(b'%d added'), b'status.added'), status.added),
6945 (ui.label(_(b'%d added'), b'status.added'), status.added),
6956 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6946 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6957 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6947 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6958 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6948 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6959 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6949 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6960 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6950 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6961 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6951 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6962 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6952 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6963 ]
6953 ]
6964 t = []
6954 t = []
6965 for l, s in labels:
6955 for l, s in labels:
6966 if s:
6956 if s:
6967 t.append(l % len(s))
6957 t.append(l % len(s))
6968
6958
6969 t = b', '.join(t)
6959 t = b', '.join(t)
6970 cleanworkdir = False
6960 cleanworkdir = False
6971
6961
6972 if repo.vfs.exists(b'graftstate'):
6962 if repo.vfs.exists(b'graftstate'):
6973 t += _(b' (graft in progress)')
6963 t += _(b' (graft in progress)')
6974 if repo.vfs.exists(b'updatestate'):
6964 if repo.vfs.exists(b'updatestate'):
6975 t += _(b' (interrupted update)')
6965 t += _(b' (interrupted update)')
6976 elif len(parents) > 1:
6966 elif len(parents) > 1:
6977 t += _(b' (merge)')
6967 t += _(b' (merge)')
6978 elif branch != parents[0].branch():
6968 elif branch != parents[0].branch():
6979 t += _(b' (new branch)')
6969 t += _(b' (new branch)')
6980 elif parents[0].closesbranch() and pnode in repo.branchheads(
6970 elif parents[0].closesbranch() and pnode in repo.branchheads(
6981 branch, closed=True
6971 branch, closed=True
6982 ):
6972 ):
6983 t += _(b' (head closed)')
6973 t += _(b' (head closed)')
6984 elif not (
6974 elif not (
6985 status.modified
6975 status.modified
6986 or status.added
6976 or status.added
6987 or status.removed
6977 or status.removed
6988 or renamed
6978 or renamed
6989 or copied
6979 or copied
6990 or subs
6980 or subs
6991 ):
6981 ):
6992 t += _(b' (clean)')
6982 t += _(b' (clean)')
6993 cleanworkdir = True
6983 cleanworkdir = True
6994 elif pnode not in bheads:
6984 elif pnode not in bheads:
6995 t += _(b' (new branch head)')
6985 t += _(b' (new branch head)')
6996
6986
6997 if parents:
6987 if parents:
6998 pendingphase = max(p.phase() for p in parents)
6988 pendingphase = max(p.phase() for p in parents)
6999 else:
6989 else:
7000 pendingphase = phases.public
6990 pendingphase = phases.public
7001
6991
7002 if pendingphase > phases.newcommitphase(ui):
6992 if pendingphase > phases.newcommitphase(ui):
7003 t += b' (%s)' % phases.phasenames[pendingphase]
6993 t += b' (%s)' % phases.phasenames[pendingphase]
7004
6994
7005 if cleanworkdir:
6995 if cleanworkdir:
7006 # i18n: column positioning for "hg summary"
6996 # i18n: column positioning for "hg summary"
7007 ui.status(_(b'commit: %s\n') % t.strip())
6997 ui.status(_(b'commit: %s\n') % t.strip())
7008 else:
6998 else:
7009 # i18n: column positioning for "hg summary"
6999 # i18n: column positioning for "hg summary"
7010 ui.write(_(b'commit: %s\n') % t.strip())
7000 ui.write(_(b'commit: %s\n') % t.strip())
7011
7001
7012 # all ancestors of branch heads - all ancestors of parent = new csets
7002 # all ancestors of branch heads - all ancestors of parent = new csets
7013 new = len(
7003 new = len(
7014 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7004 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7015 )
7005 )
7016
7006
7017 if new == 0:
7007 if new == 0:
7018 # i18n: column positioning for "hg summary"
7008 # i18n: column positioning for "hg summary"
7019 ui.status(_(b'update: (current)\n'))
7009 ui.status(_(b'update: (current)\n'))
7020 elif pnode not in bheads:
7010 elif pnode not in bheads:
7021 # i18n: column positioning for "hg summary"
7011 # i18n: column positioning for "hg summary"
7022 ui.write(_(b'update: %d new changesets (update)\n') % new)
7012 ui.write(_(b'update: %d new changesets (update)\n') % new)
7023 else:
7013 else:
7024 # i18n: column positioning for "hg summary"
7014 # i18n: column positioning for "hg summary"
7025 ui.write(
7015 ui.write(
7026 _(b'update: %d new changesets, %d branch heads (merge)\n')
7016 _(b'update: %d new changesets, %d branch heads (merge)\n')
7027 % (new, len(bheads))
7017 % (new, len(bheads))
7028 )
7018 )
7029
7019
7030 t = []
7020 t = []
7031 draft = len(repo.revs(b'draft()'))
7021 draft = len(repo.revs(b'draft()'))
7032 if draft:
7022 if draft:
7033 t.append(_(b'%d draft') % draft)
7023 t.append(_(b'%d draft') % draft)
7034 secret = len(repo.revs(b'secret()'))
7024 secret = len(repo.revs(b'secret()'))
7035 if secret:
7025 if secret:
7036 t.append(_(b'%d secret') % secret)
7026 t.append(_(b'%d secret') % secret)
7037
7027
7038 if draft or secret:
7028 if draft or secret:
7039 ui.status(_(b'phases: %s\n') % b', '.join(t))
7029 ui.status(_(b'phases: %s\n') % b', '.join(t))
7040
7030
7041 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7031 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7042 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7032 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7043 numtrouble = len(repo.revs(trouble + b"()"))
7033 numtrouble = len(repo.revs(trouble + b"()"))
7044 # We write all the possibilities to ease translation
7034 # We write all the possibilities to ease translation
7045 troublemsg = {
7035 troublemsg = {
7046 b"orphan": _(b"orphan: %d changesets"),
7036 b"orphan": _(b"orphan: %d changesets"),
7047 b"contentdivergent": _(b"content-divergent: %d changesets"),
7037 b"contentdivergent": _(b"content-divergent: %d changesets"),
7048 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7038 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7049 }
7039 }
7050 if numtrouble > 0:
7040 if numtrouble > 0:
7051 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7041 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7052
7042
7053 cmdutil.summaryhooks(ui, repo)
7043 cmdutil.summaryhooks(ui, repo)
7054
7044
7055 if opts.get(b'remote'):
7045 if opts.get(b'remote'):
7056 needsincoming, needsoutgoing = True, True
7046 needsincoming, needsoutgoing = True, True
7057 else:
7047 else:
7058 needsincoming, needsoutgoing = False, False
7048 needsincoming, needsoutgoing = False, False
7059 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7049 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7060 if i:
7050 if i:
7061 needsincoming = True
7051 needsincoming = True
7062 if o:
7052 if o:
7063 needsoutgoing = True
7053 needsoutgoing = True
7064 if not needsincoming and not needsoutgoing:
7054 if not needsincoming and not needsoutgoing:
7065 return
7055 return
7066
7056
7067 def getincoming():
7057 def getincoming():
7068 source, branches = hg.parseurl(ui.expandpath(b'default'))
7058 source, branches = hg.parseurl(ui.expandpath(b'default'))
7069 sbranch = branches[0]
7059 sbranch = branches[0]
7070 try:
7060 try:
7071 other = hg.peer(repo, {}, source)
7061 other = hg.peer(repo, {}, source)
7072 except error.RepoError:
7062 except error.RepoError:
7073 if opts.get(b'remote'):
7063 if opts.get(b'remote'):
7074 raise
7064 raise
7075 return source, sbranch, None, None, None
7065 return source, sbranch, None, None, None
7076 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7066 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7077 if revs:
7067 if revs:
7078 revs = [other.lookup(rev) for rev in revs]
7068 revs = [other.lookup(rev) for rev in revs]
7079 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7069 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7080 repo.ui.pushbuffer()
7070 repo.ui.pushbuffer()
7081 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7071 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7082 repo.ui.popbuffer()
7072 repo.ui.popbuffer()
7083 return source, sbranch, other, commoninc, commoninc[1]
7073 return source, sbranch, other, commoninc, commoninc[1]
7084
7074
7085 if needsincoming:
7075 if needsincoming:
7086 source, sbranch, sother, commoninc, incoming = getincoming()
7076 source, sbranch, sother, commoninc, incoming = getincoming()
7087 else:
7077 else:
7088 source = sbranch = sother = commoninc = incoming = None
7078 source = sbranch = sother = commoninc = incoming = None
7089
7079
7090 def getoutgoing():
7080 def getoutgoing():
7091 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7081 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7092 dbranch = branches[0]
7082 dbranch = branches[0]
7093 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7083 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7094 if source != dest:
7084 if source != dest:
7095 try:
7085 try:
7096 dother = hg.peer(repo, {}, dest)
7086 dother = hg.peer(repo, {}, dest)
7097 except error.RepoError:
7087 except error.RepoError:
7098 if opts.get(b'remote'):
7088 if opts.get(b'remote'):
7099 raise
7089 raise
7100 return dest, dbranch, None, None
7090 return dest, dbranch, None, None
7101 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7091 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7102 elif sother is None:
7092 elif sother is None:
7103 # there is no explicit destination peer, but source one is invalid
7093 # there is no explicit destination peer, but source one is invalid
7104 return dest, dbranch, None, None
7094 return dest, dbranch, None, None
7105 else:
7095 else:
7106 dother = sother
7096 dother = sother
7107 if source != dest or (sbranch is not None and sbranch != dbranch):
7097 if source != dest or (sbranch is not None and sbranch != dbranch):
7108 common = None
7098 common = None
7109 else:
7099 else:
7110 common = commoninc
7100 common = commoninc
7111 if revs:
7101 if revs:
7112 revs = [repo.lookup(rev) for rev in revs]
7102 revs = [repo.lookup(rev) for rev in revs]
7113 repo.ui.pushbuffer()
7103 repo.ui.pushbuffer()
7114 outgoing = discovery.findcommonoutgoing(
7104 outgoing = discovery.findcommonoutgoing(
7115 repo, dother, onlyheads=revs, commoninc=common
7105 repo, dother, onlyheads=revs, commoninc=common
7116 )
7106 )
7117 repo.ui.popbuffer()
7107 repo.ui.popbuffer()
7118 return dest, dbranch, dother, outgoing
7108 return dest, dbranch, dother, outgoing
7119
7109
7120 if needsoutgoing:
7110 if needsoutgoing:
7121 dest, dbranch, dother, outgoing = getoutgoing()
7111 dest, dbranch, dother, outgoing = getoutgoing()
7122 else:
7112 else:
7123 dest = dbranch = dother = outgoing = None
7113 dest = dbranch = dother = outgoing = None
7124
7114
7125 if opts.get(b'remote'):
7115 if opts.get(b'remote'):
7126 t = []
7116 t = []
7127 if incoming:
7117 if incoming:
7128 t.append(_(b'1 or more incoming'))
7118 t.append(_(b'1 or more incoming'))
7129 o = outgoing.missing
7119 o = outgoing.missing
7130 if o:
7120 if o:
7131 t.append(_(b'%d outgoing') % len(o))
7121 t.append(_(b'%d outgoing') % len(o))
7132 other = dother or sother
7122 other = dother or sother
7133 if b'bookmarks' in other.listkeys(b'namespaces'):
7123 if b'bookmarks' in other.listkeys(b'namespaces'):
7134 counts = bookmarks.summary(repo, other)
7124 counts = bookmarks.summary(repo, other)
7135 if counts[0] > 0:
7125 if counts[0] > 0:
7136 t.append(_(b'%d incoming bookmarks') % counts[0])
7126 t.append(_(b'%d incoming bookmarks') % counts[0])
7137 if counts[1] > 0:
7127 if counts[1] > 0:
7138 t.append(_(b'%d outgoing bookmarks') % counts[1])
7128 t.append(_(b'%d outgoing bookmarks') % counts[1])
7139
7129
7140 if t:
7130 if t:
7141 # i18n: column positioning for "hg summary"
7131 # i18n: column positioning for "hg summary"
7142 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7132 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7143 else:
7133 else:
7144 # i18n: column positioning for "hg summary"
7134 # i18n: column positioning for "hg summary"
7145 ui.status(_(b'remote: (synced)\n'))
7135 ui.status(_(b'remote: (synced)\n'))
7146
7136
7147 cmdutil.summaryremotehooks(
7137 cmdutil.summaryremotehooks(
7148 ui,
7138 ui,
7149 repo,
7139 repo,
7150 opts,
7140 opts,
7151 (
7141 (
7152 (source, sbranch, sother, commoninc),
7142 (source, sbranch, sother, commoninc),
7153 (dest, dbranch, dother, outgoing),
7143 (dest, dbranch, dother, outgoing),
7154 ),
7144 ),
7155 )
7145 )
7156
7146
7157
7147
7158 @command(
7148 @command(
7159 b'tag',
7149 b'tag',
7160 [
7150 [
7161 (b'f', b'force', None, _(b'force tag')),
7151 (b'f', b'force', None, _(b'force tag')),
7162 (b'l', b'local', None, _(b'make the tag local')),
7152 (b'l', b'local', None, _(b'make the tag local')),
7163 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7153 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7164 (b'', b'remove', None, _(b'remove a tag')),
7154 (b'', b'remove', None, _(b'remove a tag')),
7165 # -l/--local is already there, commitopts cannot be used
7155 # -l/--local is already there, commitopts cannot be used
7166 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7156 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7167 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7157 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7168 ]
7158 ]
7169 + commitopts2,
7159 + commitopts2,
7170 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7160 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7171 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7161 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7172 )
7162 )
7173 def tag(ui, repo, name1, *names, **opts):
7163 def tag(ui, repo, name1, *names, **opts):
7174 """add one or more tags for the current or given revision
7164 """add one or more tags for the current or given revision
7175
7165
7176 Name a particular revision using <name>.
7166 Name a particular revision using <name>.
7177
7167
7178 Tags are used to name particular revisions of the repository and are
7168 Tags are used to name particular revisions of the repository and are
7179 very useful to compare different revisions, to go back to significant
7169 very useful to compare different revisions, to go back to significant
7180 earlier versions or to mark branch points as releases, etc. Changing
7170 earlier versions or to mark branch points as releases, etc. Changing
7181 an existing tag is normally disallowed; use -f/--force to override.
7171 an existing tag is normally disallowed; use -f/--force to override.
7182
7172
7183 If no revision is given, the parent of the working directory is
7173 If no revision is given, the parent of the working directory is
7184 used.
7174 used.
7185
7175
7186 To facilitate version control, distribution, and merging of tags,
7176 To facilitate version control, distribution, and merging of tags,
7187 they are stored as a file named ".hgtags" which is managed similarly
7177 they are stored as a file named ".hgtags" which is managed similarly
7188 to other project files and can be hand-edited if necessary. This
7178 to other project files and can be hand-edited if necessary. This
7189 also means that tagging creates a new commit. The file
7179 also means that tagging creates a new commit. The file
7190 ".hg/localtags" is used for local tags (not shared among
7180 ".hg/localtags" is used for local tags (not shared among
7191 repositories).
7181 repositories).
7192
7182
7193 Tag commits are usually made at the head of a branch. If the parent
7183 Tag commits are usually made at the head of a branch. If the parent
7194 of the working directory is not a branch head, :hg:`tag` aborts; use
7184 of the working directory is not a branch head, :hg:`tag` aborts; use
7195 -f/--force to force the tag commit to be based on a non-head
7185 -f/--force to force the tag commit to be based on a non-head
7196 changeset.
7186 changeset.
7197
7187
7198 See :hg:`help dates` for a list of formats valid for -d/--date.
7188 See :hg:`help dates` for a list of formats valid for -d/--date.
7199
7189
7200 Since tag names have priority over branch names during revision
7190 Since tag names have priority over branch names during revision
7201 lookup, using an existing branch name as a tag name is discouraged.
7191 lookup, using an existing branch name as a tag name is discouraged.
7202
7192
7203 Returns 0 on success.
7193 Returns 0 on success.
7204 """
7194 """
7205 opts = pycompat.byteskwargs(opts)
7195 opts = pycompat.byteskwargs(opts)
7206 with repo.wlock(), repo.lock():
7196 with repo.wlock(), repo.lock():
7207 rev_ = b"."
7197 rev_ = b"."
7208 names = [t.strip() for t in (name1,) + names]
7198 names = [t.strip() for t in (name1,) + names]
7209 if len(names) != len(set(names)):
7199 if len(names) != len(set(names)):
7210 raise error.Abort(_(b'tag names must be unique'))
7200 raise error.Abort(_(b'tag names must be unique'))
7211 for n in names:
7201 for n in names:
7212 scmutil.checknewlabel(repo, n, b'tag')
7202 scmutil.checknewlabel(repo, n, b'tag')
7213 if not n:
7203 if not n:
7214 raise error.Abort(
7204 raise error.Abort(
7215 _(b'tag names cannot consist entirely of whitespace')
7205 _(b'tag names cannot consist entirely of whitespace')
7216 )
7206 )
7217 if opts.get(b'rev') and opts.get(b'remove'):
7207 if opts.get(b'rev') and opts.get(b'remove'):
7218 raise error.Abort(_(b"--rev and --remove are incompatible"))
7208 raise error.Abort(_(b"--rev and --remove are incompatible"))
7219 if opts.get(b'rev'):
7209 if opts.get(b'rev'):
7220 rev_ = opts[b'rev']
7210 rev_ = opts[b'rev']
7221 message = opts.get(b'message')
7211 message = opts.get(b'message')
7222 if opts.get(b'remove'):
7212 if opts.get(b'remove'):
7223 if opts.get(b'local'):
7213 if opts.get(b'local'):
7224 expectedtype = b'local'
7214 expectedtype = b'local'
7225 else:
7215 else:
7226 expectedtype = b'global'
7216 expectedtype = b'global'
7227
7217
7228 for n in names:
7218 for n in names:
7229 if repo.tagtype(n) == b'global':
7219 if repo.tagtype(n) == b'global':
7230 alltags = tagsmod.findglobaltags(ui, repo)
7220 alltags = tagsmod.findglobaltags(ui, repo)
7231 if alltags[n][0] == nullid:
7221 if alltags[n][0] == nullid:
7232 raise error.Abort(_(b"tag '%s' is already removed") % n)
7222 raise error.Abort(_(b"tag '%s' is already removed") % n)
7233 if not repo.tagtype(n):
7223 if not repo.tagtype(n):
7234 raise error.Abort(_(b"tag '%s' does not exist") % n)
7224 raise error.Abort(_(b"tag '%s' does not exist") % n)
7235 if repo.tagtype(n) != expectedtype:
7225 if repo.tagtype(n) != expectedtype:
7236 if expectedtype == b'global':
7226 if expectedtype == b'global':
7237 raise error.Abort(
7227 raise error.Abort(
7238 _(b"tag '%s' is not a global tag") % n
7228 _(b"tag '%s' is not a global tag") % n
7239 )
7229 )
7240 else:
7230 else:
7241 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7231 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7242 rev_ = b'null'
7232 rev_ = b'null'
7243 if not message:
7233 if not message:
7244 # we don't translate commit messages
7234 # we don't translate commit messages
7245 message = b'Removed tag %s' % b', '.join(names)
7235 message = b'Removed tag %s' % b', '.join(names)
7246 elif not opts.get(b'force'):
7236 elif not opts.get(b'force'):
7247 for n in names:
7237 for n in names:
7248 if n in repo.tags():
7238 if n in repo.tags():
7249 raise error.Abort(
7239 raise error.Abort(
7250 _(b"tag '%s' already exists (use -f to force)") % n
7240 _(b"tag '%s' already exists (use -f to force)") % n
7251 )
7241 )
7252 if not opts.get(b'local'):
7242 if not opts.get(b'local'):
7253 p1, p2 = repo.dirstate.parents()
7243 p1, p2 = repo.dirstate.parents()
7254 if p2 != nullid:
7244 if p2 != nullid:
7255 raise error.Abort(_(b'uncommitted merge'))
7245 raise error.Abort(_(b'uncommitted merge'))
7256 bheads = repo.branchheads()
7246 bheads = repo.branchheads()
7257 if not opts.get(b'force') and bheads and p1 not in bheads:
7247 if not opts.get(b'force') and bheads and p1 not in bheads:
7258 raise error.Abort(
7248 raise error.Abort(
7259 _(
7249 _(
7260 b'working directory is not at a branch head '
7250 b'working directory is not at a branch head '
7261 b'(use -f to force)'
7251 b'(use -f to force)'
7262 )
7252 )
7263 )
7253 )
7264 node = scmutil.revsingle(repo, rev_).node()
7254 node = scmutil.revsingle(repo, rev_).node()
7265
7255
7266 if not message:
7256 if not message:
7267 # we don't translate commit messages
7257 # we don't translate commit messages
7268 message = b'Added tag %s for changeset %s' % (
7258 message = b'Added tag %s for changeset %s' % (
7269 b', '.join(names),
7259 b', '.join(names),
7270 short(node),
7260 short(node),
7271 )
7261 )
7272
7262
7273 date = opts.get(b'date')
7263 date = opts.get(b'date')
7274 if date:
7264 if date:
7275 date = dateutil.parsedate(date)
7265 date = dateutil.parsedate(date)
7276
7266
7277 if opts.get(b'remove'):
7267 if opts.get(b'remove'):
7278 editform = b'tag.remove'
7268 editform = b'tag.remove'
7279 else:
7269 else:
7280 editform = b'tag.add'
7270 editform = b'tag.add'
7281 editor = cmdutil.getcommiteditor(
7271 editor = cmdutil.getcommiteditor(
7282 editform=editform, **pycompat.strkwargs(opts)
7272 editform=editform, **pycompat.strkwargs(opts)
7283 )
7273 )
7284
7274
7285 # don't allow tagging the null rev
7275 # don't allow tagging the null rev
7286 if (
7276 if (
7287 not opts.get(b'remove')
7277 not opts.get(b'remove')
7288 and scmutil.revsingle(repo, rev_).rev() == nullrev
7278 and scmutil.revsingle(repo, rev_).rev() == nullrev
7289 ):
7279 ):
7290 raise error.Abort(_(b"cannot tag null revision"))
7280 raise error.Abort(_(b"cannot tag null revision"))
7291
7281
7292 tagsmod.tag(
7282 tagsmod.tag(
7293 repo,
7283 repo,
7294 names,
7284 names,
7295 node,
7285 node,
7296 message,
7286 message,
7297 opts.get(b'local'),
7287 opts.get(b'local'),
7298 opts.get(b'user'),
7288 opts.get(b'user'),
7299 date,
7289 date,
7300 editor=editor,
7290 editor=editor,
7301 )
7291 )
7302
7292
7303
7293
7304 @command(
7294 @command(
7305 b'tags',
7295 b'tags',
7306 formatteropts,
7296 formatteropts,
7307 b'',
7297 b'',
7308 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7298 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7309 intents={INTENT_READONLY},
7299 intents={INTENT_READONLY},
7310 )
7300 )
7311 def tags(ui, repo, **opts):
7301 def tags(ui, repo, **opts):
7312 """list repository tags
7302 """list repository tags
7313
7303
7314 This lists both regular and local tags. When the -v/--verbose
7304 This lists both regular and local tags. When the -v/--verbose
7315 switch is used, a third column "local" is printed for local tags.
7305 switch is used, a third column "local" is printed for local tags.
7316 When the -q/--quiet switch is used, only the tag name is printed.
7306 When the -q/--quiet switch is used, only the tag name is printed.
7317
7307
7318 .. container:: verbose
7308 .. container:: verbose
7319
7309
7320 Template:
7310 Template:
7321
7311
7322 The following keywords are supported in addition to the common template
7312 The following keywords are supported in addition to the common template
7323 keywords and functions such as ``{tag}``. See also
7313 keywords and functions such as ``{tag}``. See also
7324 :hg:`help templates`.
7314 :hg:`help templates`.
7325
7315
7326 :type: String. ``local`` for local tags.
7316 :type: String. ``local`` for local tags.
7327
7317
7328 Returns 0 on success.
7318 Returns 0 on success.
7329 """
7319 """
7330
7320
7331 opts = pycompat.byteskwargs(opts)
7321 opts = pycompat.byteskwargs(opts)
7332 ui.pager(b'tags')
7322 ui.pager(b'tags')
7333 fm = ui.formatter(b'tags', opts)
7323 fm = ui.formatter(b'tags', opts)
7334 hexfunc = fm.hexfunc
7324 hexfunc = fm.hexfunc
7335
7325
7336 for t, n in reversed(repo.tagslist()):
7326 for t, n in reversed(repo.tagslist()):
7337 hn = hexfunc(n)
7327 hn = hexfunc(n)
7338 label = b'tags.normal'
7328 label = b'tags.normal'
7339 tagtype = b''
7329 tagtype = b''
7340 if repo.tagtype(t) == b'local':
7330 if repo.tagtype(t) == b'local':
7341 label = b'tags.local'
7331 label = b'tags.local'
7342 tagtype = b'local'
7332 tagtype = b'local'
7343
7333
7344 fm.startitem()
7334 fm.startitem()
7345 fm.context(repo=repo)
7335 fm.context(repo=repo)
7346 fm.write(b'tag', b'%s', t, label=label)
7336 fm.write(b'tag', b'%s', t, label=label)
7347 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7337 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7348 fm.condwrite(
7338 fm.condwrite(
7349 not ui.quiet,
7339 not ui.quiet,
7350 b'rev node',
7340 b'rev node',
7351 fmt,
7341 fmt,
7352 repo.changelog.rev(n),
7342 repo.changelog.rev(n),
7353 hn,
7343 hn,
7354 label=label,
7344 label=label,
7355 )
7345 )
7356 fm.condwrite(
7346 fm.condwrite(
7357 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7347 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7358 )
7348 )
7359 fm.plain(b'\n')
7349 fm.plain(b'\n')
7360 fm.end()
7350 fm.end()
7361
7351
7362
7352
7363 @command(
7353 @command(
7364 b'tip',
7354 b'tip',
7365 [
7355 [
7366 (b'p', b'patch', None, _(b'show patch')),
7356 (b'p', b'patch', None, _(b'show patch')),
7367 (b'g', b'git', None, _(b'use git extended diff format')),
7357 (b'g', b'git', None, _(b'use git extended diff format')),
7368 ]
7358 ]
7369 + templateopts,
7359 + templateopts,
7370 _(b'[-p] [-g]'),
7360 _(b'[-p] [-g]'),
7371 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7361 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7372 )
7362 )
7373 def tip(ui, repo, **opts):
7363 def tip(ui, repo, **opts):
7374 """show the tip revision (DEPRECATED)
7364 """show the tip revision (DEPRECATED)
7375
7365
7376 The tip revision (usually just called the tip) is the changeset
7366 The tip revision (usually just called the tip) is the changeset
7377 most recently added to the repository (and therefore the most
7367 most recently added to the repository (and therefore the most
7378 recently changed head).
7368 recently changed head).
7379
7369
7380 If you have just made a commit, that commit will be the tip. If
7370 If you have just made a commit, that commit will be the tip. If
7381 you have just pulled changes from another repository, the tip of
7371 you have just pulled changes from another repository, the tip of
7382 that repository becomes the current tip. The "tip" tag is special
7372 that repository becomes the current tip. The "tip" tag is special
7383 and cannot be renamed or assigned to a different changeset.
7373 and cannot be renamed or assigned to a different changeset.
7384
7374
7385 This command is deprecated, please use :hg:`heads` instead.
7375 This command is deprecated, please use :hg:`heads` instead.
7386
7376
7387 Returns 0 on success.
7377 Returns 0 on success.
7388 """
7378 """
7389 opts = pycompat.byteskwargs(opts)
7379 opts = pycompat.byteskwargs(opts)
7390 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7380 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7391 displayer.show(repo[b'tip'])
7381 displayer.show(repo[b'tip'])
7392 displayer.close()
7382 displayer.close()
7393
7383
7394
7384
7395 @command(
7385 @command(
7396 b'unbundle',
7386 b'unbundle',
7397 [
7387 [
7398 (
7388 (
7399 b'u',
7389 b'u',
7400 b'update',
7390 b'update',
7401 None,
7391 None,
7402 _(b'update to new branch head if changesets were unbundled'),
7392 _(b'update to new branch head if changesets were unbundled'),
7403 )
7393 )
7404 ],
7394 ],
7405 _(b'[-u] FILE...'),
7395 _(b'[-u] FILE...'),
7406 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7396 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7407 )
7397 )
7408 def unbundle(ui, repo, fname1, *fnames, **opts):
7398 def unbundle(ui, repo, fname1, *fnames, **opts):
7409 """apply one or more bundle files
7399 """apply one or more bundle files
7410
7400
7411 Apply one or more bundle files generated by :hg:`bundle`.
7401 Apply one or more bundle files generated by :hg:`bundle`.
7412
7402
7413 Returns 0 on success, 1 if an update has unresolved files.
7403 Returns 0 on success, 1 if an update has unresolved files.
7414 """
7404 """
7415 fnames = (fname1,) + fnames
7405 fnames = (fname1,) + fnames
7416
7406
7417 with repo.lock():
7407 with repo.lock():
7418 for fname in fnames:
7408 for fname in fnames:
7419 f = hg.openpath(ui, fname)
7409 f = hg.openpath(ui, fname)
7420 gen = exchange.readbundle(ui, f, fname)
7410 gen = exchange.readbundle(ui, f, fname)
7421 if isinstance(gen, streamclone.streamcloneapplier):
7411 if isinstance(gen, streamclone.streamcloneapplier):
7422 raise error.Abort(
7412 raise error.Abort(
7423 _(
7413 _(
7424 b'packed bundles cannot be applied with '
7414 b'packed bundles cannot be applied with '
7425 b'"hg unbundle"'
7415 b'"hg unbundle"'
7426 ),
7416 ),
7427 hint=_(b'use "hg debugapplystreamclonebundle"'),
7417 hint=_(b'use "hg debugapplystreamclonebundle"'),
7428 )
7418 )
7429 url = b'bundle:' + fname
7419 url = b'bundle:' + fname
7430 try:
7420 try:
7431 txnname = b'unbundle'
7421 txnname = b'unbundle'
7432 if not isinstance(gen, bundle2.unbundle20):
7422 if not isinstance(gen, bundle2.unbundle20):
7433 txnname = b'unbundle\n%s' % util.hidepassword(url)
7423 txnname = b'unbundle\n%s' % util.hidepassword(url)
7434 with repo.transaction(txnname) as tr:
7424 with repo.transaction(txnname) as tr:
7435 op = bundle2.applybundle(
7425 op = bundle2.applybundle(
7436 repo, gen, tr, source=b'unbundle', url=url
7426 repo, gen, tr, source=b'unbundle', url=url
7437 )
7427 )
7438 except error.BundleUnknownFeatureError as exc:
7428 except error.BundleUnknownFeatureError as exc:
7439 raise error.Abort(
7429 raise error.Abort(
7440 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7430 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7441 hint=_(
7431 hint=_(
7442 b"see https://mercurial-scm.org/"
7432 b"see https://mercurial-scm.org/"
7443 b"wiki/BundleFeature for more "
7433 b"wiki/BundleFeature for more "
7444 b"information"
7434 b"information"
7445 ),
7435 ),
7446 )
7436 )
7447 modheads = bundle2.combinechangegroupresults(op)
7437 modheads = bundle2.combinechangegroupresults(op)
7448
7438
7449 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7439 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7450
7440
7451
7441
7452 @command(
7442 @command(
7453 b'unshelve',
7443 b'unshelve',
7454 [
7444 [
7455 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7445 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7456 (
7446 (
7457 b'c',
7447 b'c',
7458 b'continue',
7448 b'continue',
7459 None,
7449 None,
7460 _(b'continue an incomplete unshelve operation'),
7450 _(b'continue an incomplete unshelve operation'),
7461 ),
7451 ),
7462 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7452 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7463 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7453 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7464 (
7454 (
7465 b'n',
7455 b'n',
7466 b'name',
7456 b'name',
7467 b'',
7457 b'',
7468 _(b'restore shelved change with given name'),
7458 _(b'restore shelved change with given name'),
7469 _(b'NAME'),
7459 _(b'NAME'),
7470 ),
7460 ),
7471 (b't', b'tool', b'', _(b'specify merge tool')),
7461 (b't', b'tool', b'', _(b'specify merge tool')),
7472 (
7462 (
7473 b'',
7463 b'',
7474 b'date',
7464 b'date',
7475 b'',
7465 b'',
7476 _(b'set date for temporary commits (DEPRECATED)'),
7466 _(b'set date for temporary commits (DEPRECATED)'),
7477 _(b'DATE'),
7467 _(b'DATE'),
7478 ),
7468 ),
7479 ],
7469 ],
7480 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7470 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7481 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7471 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7482 )
7472 )
7483 def unshelve(ui, repo, *shelved, **opts):
7473 def unshelve(ui, repo, *shelved, **opts):
7484 """restore a shelved change to the working directory
7474 """restore a shelved change to the working directory
7485
7475
7486 This command accepts an optional name of a shelved change to
7476 This command accepts an optional name of a shelved change to
7487 restore. If none is given, the most recent shelved change is used.
7477 restore. If none is given, the most recent shelved change is used.
7488
7478
7489 If a shelved change is applied successfully, the bundle that
7479 If a shelved change is applied successfully, the bundle that
7490 contains the shelved changes is moved to a backup location
7480 contains the shelved changes is moved to a backup location
7491 (.hg/shelve-backup).
7481 (.hg/shelve-backup).
7492
7482
7493 Since you can restore a shelved change on top of an arbitrary
7483 Since you can restore a shelved change on top of an arbitrary
7494 commit, it is possible that unshelving will result in a conflict
7484 commit, it is possible that unshelving will result in a conflict
7495 between your changes and the commits you are unshelving onto. If
7485 between your changes and the commits you are unshelving onto. If
7496 this occurs, you must resolve the conflict, then use
7486 this occurs, you must resolve the conflict, then use
7497 ``--continue`` to complete the unshelve operation. (The bundle
7487 ``--continue`` to complete the unshelve operation. (The bundle
7498 will not be moved until you successfully complete the unshelve.)
7488 will not be moved until you successfully complete the unshelve.)
7499
7489
7500 (Alternatively, you can use ``--abort`` to abandon an unshelve
7490 (Alternatively, you can use ``--abort`` to abandon an unshelve
7501 that causes a conflict. This reverts the unshelved changes, and
7491 that causes a conflict. This reverts the unshelved changes, and
7502 leaves the bundle in place.)
7492 leaves the bundle in place.)
7503
7493
7504 If bare shelved change (without interactive, include and exclude
7494 If bare shelved change (without interactive, include and exclude
7505 option) was done on newly created branch it would restore branch
7495 option) was done on newly created branch it would restore branch
7506 information to the working directory.
7496 information to the working directory.
7507
7497
7508 After a successful unshelve, the shelved changes are stored in a
7498 After a successful unshelve, the shelved changes are stored in a
7509 backup directory. Only the N most recent backups are kept. N
7499 backup directory. Only the N most recent backups are kept. N
7510 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7500 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7511 configuration option.
7501 configuration option.
7512
7502
7513 .. container:: verbose
7503 .. container:: verbose
7514
7504
7515 Timestamp in seconds is used to decide order of backups. More
7505 Timestamp in seconds is used to decide order of backups. More
7516 than ``maxbackups`` backups are kept, if same timestamp
7506 than ``maxbackups`` backups are kept, if same timestamp
7517 prevents from deciding exact order of them, for safety.
7507 prevents from deciding exact order of them, for safety.
7518
7508
7519 Selected changes can be unshelved with ``--interactive`` flag.
7509 Selected changes can be unshelved with ``--interactive`` flag.
7520 The working directory is updated with the selected changes, and
7510 The working directory is updated with the selected changes, and
7521 only the unselected changes remain shelved.
7511 only the unselected changes remain shelved.
7522 Note: The whole shelve is applied to working directory first before
7512 Note: The whole shelve is applied to working directory first before
7523 running interactively. So, this will bring up all the conflicts between
7513 running interactively. So, this will bring up all the conflicts between
7524 working directory and the shelve, irrespective of which changes will be
7514 working directory and the shelve, irrespective of which changes will be
7525 unshelved.
7515 unshelved.
7526 """
7516 """
7527 with repo.wlock():
7517 with repo.wlock():
7528 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7518 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7529
7519
7530
7520
7531 statemod.addunfinished(
7521 statemod.addunfinished(
7532 b'unshelve',
7522 b'unshelve',
7533 fname=b'shelvedstate',
7523 fname=b'shelvedstate',
7534 continueflag=True,
7524 continueflag=True,
7535 abortfunc=shelvemod.hgabortunshelve,
7525 abortfunc=shelvemod.hgabortunshelve,
7536 continuefunc=shelvemod.hgcontinueunshelve,
7526 continuefunc=shelvemod.hgcontinueunshelve,
7537 cmdmsg=_(b'unshelve already in progress'),
7527 cmdmsg=_(b'unshelve already in progress'),
7538 )
7528 )
7539
7529
7540
7530
7541 @command(
7531 @command(
7542 b'update|up|checkout|co',
7532 b'update|up|checkout|co',
7543 [
7533 [
7544 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7534 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7545 (b'c', b'check', None, _(b'require clean working directory')),
7535 (b'c', b'check', None, _(b'require clean working directory')),
7546 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7536 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7547 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7537 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7548 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7538 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7549 ]
7539 ]
7550 + mergetoolopts,
7540 + mergetoolopts,
7551 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7541 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7552 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7542 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7553 helpbasic=True,
7543 helpbasic=True,
7554 )
7544 )
7555 def update(ui, repo, node=None, **opts):
7545 def update(ui, repo, node=None, **opts):
7556 """update working directory (or switch revisions)
7546 """update working directory (or switch revisions)
7557
7547
7558 Update the repository's working directory to the specified
7548 Update the repository's working directory to the specified
7559 changeset. If no changeset is specified, update to the tip of the
7549 changeset. If no changeset is specified, update to the tip of the
7560 current named branch and move the active bookmark (see :hg:`help
7550 current named branch and move the active bookmark (see :hg:`help
7561 bookmarks`).
7551 bookmarks`).
7562
7552
7563 Update sets the working directory's parent revision to the specified
7553 Update sets the working directory's parent revision to the specified
7564 changeset (see :hg:`help parents`).
7554 changeset (see :hg:`help parents`).
7565
7555
7566 If the changeset is not a descendant or ancestor of the working
7556 If the changeset is not a descendant or ancestor of the working
7567 directory's parent and there are uncommitted changes, the update is
7557 directory's parent and there are uncommitted changes, the update is
7568 aborted. With the -c/--check option, the working directory is checked
7558 aborted. With the -c/--check option, the working directory is checked
7569 for uncommitted changes; if none are found, the working directory is
7559 for uncommitted changes; if none are found, the working directory is
7570 updated to the specified changeset.
7560 updated to the specified changeset.
7571
7561
7572 .. container:: verbose
7562 .. container:: verbose
7573
7563
7574 The -C/--clean, -c/--check, and -m/--merge options control what
7564 The -C/--clean, -c/--check, and -m/--merge options control what
7575 happens if the working directory contains uncommitted changes.
7565 happens if the working directory contains uncommitted changes.
7576 At most of one of them can be specified.
7566 At most of one of them can be specified.
7577
7567
7578 1. If no option is specified, and if
7568 1. If no option is specified, and if
7579 the requested changeset is an ancestor or descendant of
7569 the requested changeset is an ancestor or descendant of
7580 the working directory's parent, the uncommitted changes
7570 the working directory's parent, the uncommitted changes
7581 are merged into the requested changeset and the merged
7571 are merged into the requested changeset and the merged
7582 result is left uncommitted. If the requested changeset is
7572 result is left uncommitted. If the requested changeset is
7583 not an ancestor or descendant (that is, it is on another
7573 not an ancestor or descendant (that is, it is on another
7584 branch), the update is aborted and the uncommitted changes
7574 branch), the update is aborted and the uncommitted changes
7585 are preserved.
7575 are preserved.
7586
7576
7587 2. With the -m/--merge option, the update is allowed even if the
7577 2. With the -m/--merge option, the update is allowed even if the
7588 requested changeset is not an ancestor or descendant of
7578 requested changeset is not an ancestor or descendant of
7589 the working directory's parent.
7579 the working directory's parent.
7590
7580
7591 3. With the -c/--check option, the update is aborted and the
7581 3. With the -c/--check option, the update is aborted and the
7592 uncommitted changes are preserved.
7582 uncommitted changes are preserved.
7593
7583
7594 4. With the -C/--clean option, uncommitted changes are discarded and
7584 4. With the -C/--clean option, uncommitted changes are discarded and
7595 the working directory is updated to the requested changeset.
7585 the working directory is updated to the requested changeset.
7596
7586
7597 To cancel an uncommitted merge (and lose your changes), use
7587 To cancel an uncommitted merge (and lose your changes), use
7598 :hg:`merge --abort`.
7588 :hg:`merge --abort`.
7599
7589
7600 Use null as the changeset to remove the working directory (like
7590 Use null as the changeset to remove the working directory (like
7601 :hg:`clone -U`).
7591 :hg:`clone -U`).
7602
7592
7603 If you want to revert just one file to an older revision, use
7593 If you want to revert just one file to an older revision, use
7604 :hg:`revert [-r REV] NAME`.
7594 :hg:`revert [-r REV] NAME`.
7605
7595
7606 See :hg:`help dates` for a list of formats valid for -d/--date.
7596 See :hg:`help dates` for a list of formats valid for -d/--date.
7607
7597
7608 Returns 0 on success, 1 if there are unresolved files.
7598 Returns 0 on success, 1 if there are unresolved files.
7609 """
7599 """
7610 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7600 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7611 rev = opts.get('rev')
7601 rev = opts.get('rev')
7612 date = opts.get('date')
7602 date = opts.get('date')
7613 clean = opts.get('clean')
7603 clean = opts.get('clean')
7614 check = opts.get('check')
7604 check = opts.get('check')
7615 merge = opts.get('merge')
7605 merge = opts.get('merge')
7616 if rev and node:
7606 if rev and node:
7617 raise error.Abort(_(b"please specify just one revision"))
7607 raise error.Abort(_(b"please specify just one revision"))
7618
7608
7619 if ui.configbool(b'commands', b'update.requiredest'):
7609 if ui.configbool(b'commands', b'update.requiredest'):
7620 if not node and not rev and not date:
7610 if not node and not rev and not date:
7621 raise error.Abort(
7611 raise error.Abort(
7622 _(b'you must specify a destination'),
7612 _(b'you must specify a destination'),
7623 hint=_(b'for example: hg update ".::"'),
7613 hint=_(b'for example: hg update ".::"'),
7624 )
7614 )
7625
7615
7626 if rev is None or rev == b'':
7616 if rev is None or rev == b'':
7627 rev = node
7617 rev = node
7628
7618
7629 if date and rev is not None:
7619 if date and rev is not None:
7630 raise error.Abort(_(b"you can't specify a revision and a date"))
7620 raise error.Abort(_(b"you can't specify a revision and a date"))
7631
7621
7632 updatecheck = None
7622 updatecheck = None
7633 if check:
7623 if check:
7634 updatecheck = b'abort'
7624 updatecheck = b'abort'
7635 elif merge:
7625 elif merge:
7636 updatecheck = b'none'
7626 updatecheck = b'none'
7637
7627
7638 with repo.wlock():
7628 with repo.wlock():
7639 cmdutil.clearunfinished(repo)
7629 cmdutil.clearunfinished(repo)
7640 if date:
7630 if date:
7641 rev = cmdutil.finddate(ui, repo, date)
7631 rev = cmdutil.finddate(ui, repo, date)
7642
7632
7643 # if we defined a bookmark, we have to remember the original name
7633 # if we defined a bookmark, we have to remember the original name
7644 brev = rev
7634 brev = rev
7645 if rev:
7635 if rev:
7646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7636 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7647 ctx = scmutil.revsingle(repo, rev, default=None)
7637 ctx = scmutil.revsingle(repo, rev, default=None)
7648 rev = ctx.rev()
7638 rev = ctx.rev()
7649 hidden = ctx.hidden()
7639 hidden = ctx.hidden()
7650 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7640 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7651 with ui.configoverride(overrides, b'update'):
7641 with ui.configoverride(overrides, b'update'):
7652 ret = hg.updatetotally(
7642 ret = hg.updatetotally(
7653 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7643 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7654 )
7644 )
7655 if hidden:
7645 if hidden:
7656 ctxstr = ctx.hex()[:12]
7646 ctxstr = ctx.hex()[:12]
7657 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7647 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7658
7648
7659 if ctx.obsolete():
7649 if ctx.obsolete():
7660 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7650 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7661 ui.warn(b"(%s)\n" % obsfatemsg)
7651 ui.warn(b"(%s)\n" % obsfatemsg)
7662 return ret
7652 return ret
7663
7653
7664
7654
7665 @command(
7655 @command(
7666 b'verify',
7656 b'verify',
7667 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7657 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7668 helpcategory=command.CATEGORY_MAINTENANCE,
7658 helpcategory=command.CATEGORY_MAINTENANCE,
7669 )
7659 )
7670 def verify(ui, repo, **opts):
7660 def verify(ui, repo, **opts):
7671 """verify the integrity of the repository
7661 """verify the integrity of the repository
7672
7662
7673 Verify the integrity of the current repository.
7663 Verify the integrity of the current repository.
7674
7664
7675 This will perform an extensive check of the repository's
7665 This will perform an extensive check of the repository's
7676 integrity, validating the hashes and checksums of each entry in
7666 integrity, validating the hashes and checksums of each entry in
7677 the changelog, manifest, and tracked files, as well as the
7667 the changelog, manifest, and tracked files, as well as the
7678 integrity of their crosslinks and indices.
7668 integrity of their crosslinks and indices.
7679
7669
7680 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7670 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7681 for more information about recovery from corruption of the
7671 for more information about recovery from corruption of the
7682 repository.
7672 repository.
7683
7673
7684 Returns 0 on success, 1 if errors are encountered.
7674 Returns 0 on success, 1 if errors are encountered.
7685 """
7675 """
7686 opts = pycompat.byteskwargs(opts)
7676 opts = pycompat.byteskwargs(opts)
7687
7677
7688 level = None
7678 level = None
7689 if opts[b'full']:
7679 if opts[b'full']:
7690 level = verifymod.VERIFY_FULL
7680 level = verifymod.VERIFY_FULL
7691 return hg.verify(repo, level)
7681 return hg.verify(repo, level)
7692
7682
7693
7683
7694 @command(
7684 @command(
7695 b'version',
7685 b'version',
7696 [] + formatteropts,
7686 [] + formatteropts,
7697 helpcategory=command.CATEGORY_HELP,
7687 helpcategory=command.CATEGORY_HELP,
7698 norepo=True,
7688 norepo=True,
7699 intents={INTENT_READONLY},
7689 intents={INTENT_READONLY},
7700 )
7690 )
7701 def version_(ui, **opts):
7691 def version_(ui, **opts):
7702 """output version and copyright information
7692 """output version and copyright information
7703
7693
7704 .. container:: verbose
7694 .. container:: verbose
7705
7695
7706 Template:
7696 Template:
7707
7697
7708 The following keywords are supported. See also :hg:`help templates`.
7698 The following keywords are supported. See also :hg:`help templates`.
7709
7699
7710 :extensions: List of extensions.
7700 :extensions: List of extensions.
7711 :ver: String. Version number.
7701 :ver: String. Version number.
7712
7702
7713 And each entry of ``{extensions}`` provides the following sub-keywords
7703 And each entry of ``{extensions}`` provides the following sub-keywords
7714 in addition to ``{ver}``.
7704 in addition to ``{ver}``.
7715
7705
7716 :bundled: Boolean. True if included in the release.
7706 :bundled: Boolean. True if included in the release.
7717 :name: String. Extension name.
7707 :name: String. Extension name.
7718 """
7708 """
7719 opts = pycompat.byteskwargs(opts)
7709 opts = pycompat.byteskwargs(opts)
7720 if ui.verbose:
7710 if ui.verbose:
7721 ui.pager(b'version')
7711 ui.pager(b'version')
7722 fm = ui.formatter(b"version", opts)
7712 fm = ui.formatter(b"version", opts)
7723 fm.startitem()
7713 fm.startitem()
7724 fm.write(
7714 fm.write(
7725 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7715 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7726 )
7716 )
7727 license = _(
7717 license = _(
7728 b"(see https://mercurial-scm.org for more information)\n"
7718 b"(see https://mercurial-scm.org for more information)\n"
7729 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7719 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7730 b"This is free software; see the source for copying conditions. "
7720 b"This is free software; see the source for copying conditions. "
7731 b"There is NO\nwarranty; "
7721 b"There is NO\nwarranty; "
7732 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7722 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7733 )
7723 )
7734 if not ui.quiet:
7724 if not ui.quiet:
7735 fm.plain(license)
7725 fm.plain(license)
7736
7726
7737 if ui.verbose:
7727 if ui.verbose:
7738 fm.plain(_(b"\nEnabled extensions:\n\n"))
7728 fm.plain(_(b"\nEnabled extensions:\n\n"))
7739 # format names and versions into columns
7729 # format names and versions into columns
7740 names = []
7730 names = []
7741 vers = []
7731 vers = []
7742 isinternals = []
7732 isinternals = []
7743 for name, module in sorted(extensions.extensions()):
7733 for name, module in sorted(extensions.extensions()):
7744 names.append(name)
7734 names.append(name)
7745 vers.append(extensions.moduleversion(module) or None)
7735 vers.append(extensions.moduleversion(module) or None)
7746 isinternals.append(extensions.ismoduleinternal(module))
7736 isinternals.append(extensions.ismoduleinternal(module))
7747 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7737 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7748 if names:
7738 if names:
7749 namefmt = b" %%-%ds " % max(len(n) for n in names)
7739 namefmt = b" %%-%ds " % max(len(n) for n in names)
7750 places = [_(b"external"), _(b"internal")]
7740 places = [_(b"external"), _(b"internal")]
7751 for n, v, p in zip(names, vers, isinternals):
7741 for n, v, p in zip(names, vers, isinternals):
7752 fn.startitem()
7742 fn.startitem()
7753 fn.condwrite(ui.verbose, b"name", namefmt, n)
7743 fn.condwrite(ui.verbose, b"name", namefmt, n)
7754 if ui.verbose:
7744 if ui.verbose:
7755 fn.plain(b"%s " % places[p])
7745 fn.plain(b"%s " % places[p])
7756 fn.data(bundled=p)
7746 fn.data(bundled=p)
7757 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7747 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7758 if ui.verbose:
7748 if ui.verbose:
7759 fn.plain(b"\n")
7749 fn.plain(b"\n")
7760 fn.end()
7750 fn.end()
7761 fm.end()
7751 fm.end()
7762
7752
7763
7753
7764 def loadcmdtable(ui, name, cmdtable):
7754 def loadcmdtable(ui, name, cmdtable):
7765 """Load command functions from specified cmdtable
7755 """Load command functions from specified cmdtable
7766 """
7756 """
7767 overrides = [cmd for cmd in cmdtable if cmd in table]
7757 overrides = [cmd for cmd in cmdtable if cmd in table]
7768 if overrides:
7758 if overrides:
7769 ui.warn(
7759 ui.warn(
7770 _(b"extension '%s' overrides commands: %s\n")
7760 _(b"extension '%s' overrides commands: %s\n")
7771 % (name, b" ".join(overrides))
7761 % (name, b" ".join(overrides))
7772 )
7762 )
7773 table.update(cmdtable)
7763 table.update(cmdtable)
@@ -1,92 +1,102 b''
1 # grep.py - logic for history walk and grep
1 # grep.py - logic for history walk and grep
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
11
12 from . import (
12 from . import (
13 pycompat,
13 pycompat,
14 scmutil,
14 scmutil,
15 util,
15 util,
16 )
16 )
17
17
18
18
19 def matchlines(body, regexp):
19 def matchlines(body, regexp):
20 begin = 0
20 begin = 0
21 linenum = 0
21 linenum = 0
22 while begin < len(body):
22 while begin < len(body):
23 match = regexp.search(body, begin)
23 match = regexp.search(body, begin)
24 if not match:
24 if not match:
25 break
25 break
26 mstart, mend = match.span()
26 mstart, mend = match.span()
27 linenum += body.count(b'\n', begin, mstart) + 1
27 linenum += body.count(b'\n', begin, mstart) + 1
28 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
28 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
29 begin = body.find(b'\n', mend) + 1 or len(body) + 1
29 begin = body.find(b'\n', mend) + 1 or len(body) + 1
30 lend = begin - 1
30 lend = begin - 1
31 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
31 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
32
32
33
33
34 class linestate(object):
34 class linestate(object):
35 def __init__(self, line, linenum, colstart, colend):
35 def __init__(self, line, linenum, colstart, colend):
36 self.line = line
36 self.line = line
37 self.linenum = linenum
37 self.linenum = linenum
38 self.colstart = colstart
38 self.colstart = colstart
39 self.colend = colend
39 self.colend = colend
40
40
41 def __hash__(self):
41 def __hash__(self):
42 return hash(self.line)
42 return hash(self.line)
43
43
44 def __eq__(self, other):
44 def __eq__(self, other):
45 return self.line == other.line
45 return self.line == other.line
46
46
47 def findpos(self, regexp):
47 def findpos(self, regexp):
48 """Iterate all (start, end) indices of matches"""
48 """Iterate all (start, end) indices of matches"""
49 yield self.colstart, self.colend
49 yield self.colstart, self.colend
50 p = self.colend
50 p = self.colend
51 while p < len(self.line):
51 while p < len(self.line):
52 m = regexp.search(self.line, p)
52 m = regexp.search(self.line, p)
53 if not m:
53 if not m:
54 break
54 break
55 if m.end() == p:
55 if m.end() == p:
56 p += 1
56 p += 1
57 else:
57 else:
58 yield m.span()
58 yield m.span()
59 p = m.end()
59 p = m.end()
60
60
61
61
62 def difflinestates(a, b):
62 def difflinestates(a, b):
63 sm = difflib.SequenceMatcher(None, a, b)
63 sm = difflib.SequenceMatcher(None, a, b)
64 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
64 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
65 if tag == 'insert':
65 if tag == 'insert':
66 for i in pycompat.xrange(blo, bhi):
66 for i in pycompat.xrange(blo, bhi):
67 yield (b'+', b[i])
67 yield (b'+', b[i])
68 elif tag == 'delete':
68 elif tag == 'delete':
69 for i in pycompat.xrange(alo, ahi):
69 for i in pycompat.xrange(alo, ahi):
70 yield (b'-', a[i])
70 yield (b'-', a[i])
71 elif tag == 'replace':
71 elif tag == 'replace':
72 for i in pycompat.xrange(alo, ahi):
72 for i in pycompat.xrange(alo, ahi):
73 yield (b'-', a[i])
73 yield (b'-', a[i])
74 for i in pycompat.xrange(blo, bhi):
74 for i in pycompat.xrange(blo, bhi):
75 yield (b'+', b[i])
75 yield (b'+', b[i])
76
76
77
77
78 class grepsearcher(object):
78 class grepsearcher(object):
79 """Search files and revisions for lines matching the given pattern"""
79 """Search files and revisions for lines matching the given pattern"""
80
80
81 def __init__(self, ui, repo, regexp):
81 def __init__(self, ui, repo, regexp):
82 self._ui = ui
82 self._ui = ui
83 self._repo = repo
83 self._repo = repo
84 self._regexp = regexp
84 self._regexp = regexp
85
85
86 self._getfile = util.lrucachefunc(repo.file)
86 self._getfile = util.lrucachefunc(repo.file)
87 self._getrenamed = scmutil.getrenamedfn(repo)
87 self._getrenamed = scmutil.getrenamedfn(repo)
88
88
89 self._matches = {}
89 self._matches = {}
90 self._copies = {}
90 self._copies = {}
91 self._skip = set()
91 self._skip = set()
92 self._revfiles = {}
92 self._revfiles = {}
93
94 def _grepbody(self, fn, rev, body):
95 self._matches[rev].setdefault(fn, [])
96 m = self._matches[rev][fn]
97 if body is None:
98 return
99
100 for lnum, cstart, cend, line in matchlines(body, self._regexp):
101 s = linestate(line, lnum, cstart, cend)
102 m.append(s)
General Comments 0
You need to be logged in to leave comments. Login now