##// END OF EJS Templates
help: document meaning of '%' in graphlog output...
Martin von Zweigbergk -
r45527:3d41172f stable
parent child Browse files
Show More
@@ -1,7841 +1,7842 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 (
84 (
85 b'R',
85 b'R',
86 b'repository',
86 b'repository',
87 b'',
87 b'',
88 _(b'repository root directory or name of overlay bundle file'),
88 _(b'repository root directory or name of overlay bundle file'),
89 _(b'REPO'),
89 _(b'REPO'),
90 ),
90 ),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (
92 (
93 b'y',
93 b'y',
94 b'noninteractive',
94 b'noninteractive',
95 None,
95 None,
96 _(
96 _(
97 b'do not prompt, automatically pick the first choice for all prompts'
97 b'do not prompt, automatically pick the first choice for all prompts'
98 ),
98 ),
99 ),
99 ),
100 (b'q', b'quiet', None, _(b'suppress output')),
100 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
102 (
102 (
103 b'',
103 b'',
104 b'color',
104 b'color',
105 b'',
105 b'',
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # and should not be translated
107 # and should not be translated
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b'TYPE'),
109 _(b'TYPE'),
110 ),
110 ),
111 (
111 (
112 b'',
112 b'',
113 b'config',
113 b'config',
114 [],
114 [],
115 _(b'set/override config option (use \'section.name=value\')'),
115 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'CONFIG'),
116 _(b'CONFIG'),
117 ),
117 ),
118 (b'', b'debug', None, _(b'enable debugging output')),
118 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debugger', None, _(b'start debugger')),
119 (b'', b'debugger', None, _(b'start debugger')),
120 (
120 (
121 b'',
121 b'',
122 b'encoding',
122 b'encoding',
123 encoding.encoding,
123 encoding.encoding,
124 _(b'set the charset encoding'),
124 _(b'set the charset encoding'),
125 _(b'ENCODE'),
125 _(b'ENCODE'),
126 ),
126 ),
127 (
127 (
128 b'',
128 b'',
129 b'encodingmode',
129 b'encodingmode',
130 encoding.encodingmode,
130 encoding.encodingmode,
131 _(b'set the charset encoding mode'),
131 _(b'set the charset encoding mode'),
132 _(b'MODE'),
132 _(b'MODE'),
133 ),
133 ),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'time', None, _(b'time how long the command takes')),
135 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'profile', None, _(b'print command execution profile')),
136 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'version', None, _(b'output version information and exit')),
137 (b'', b'version', None, _(b'output version information and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (
140 (
141 b'',
141 b'',
142 b'pager',
142 b'pager',
143 b'auto',
143 b'auto',
144 _(b"when to paginate (boolean, always, auto, or never)"),
144 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b'TYPE'),
145 _(b'TYPE'),
146 ),
146 ),
147 ]
147 ]
148
148
149 dryrunopts = cmdutil.dryrunopts
149 dryrunopts = cmdutil.dryrunopts
150 remoteopts = cmdutil.remoteopts
150 remoteopts = cmdutil.remoteopts
151 walkopts = cmdutil.walkopts
151 walkopts = cmdutil.walkopts
152 commitopts = cmdutil.commitopts
152 commitopts = cmdutil.commitopts
153 commitopts2 = cmdutil.commitopts2
153 commitopts2 = cmdutil.commitopts2
154 commitopts3 = cmdutil.commitopts3
154 commitopts3 = cmdutil.commitopts3
155 formatteropts = cmdutil.formatteropts
155 formatteropts = cmdutil.formatteropts
156 templateopts = cmdutil.templateopts
156 templateopts = cmdutil.templateopts
157 logopts = cmdutil.logopts
157 logopts = cmdutil.logopts
158 diffopts = cmdutil.diffopts
158 diffopts = cmdutil.diffopts
159 diffwsopts = cmdutil.diffwsopts
159 diffwsopts = cmdutil.diffwsopts
160 diffopts2 = cmdutil.diffopts2
160 diffopts2 = cmdutil.diffopts2
161 mergetoolopts = cmdutil.mergetoolopts
161 mergetoolopts = cmdutil.mergetoolopts
162 similarityopts = cmdutil.similarityopts
162 similarityopts = cmdutil.similarityopts
163 subrepoopts = cmdutil.subrepoopts
163 subrepoopts = cmdutil.subrepoopts
164 debugrevlogopts = cmdutil.debugrevlogopts
164 debugrevlogopts = cmdutil.debugrevlogopts
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168
168
169 @command(
169 @command(
170 b'abort',
170 b'abort',
171 dryrunopts,
171 dryrunopts,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpbasic=True,
173 helpbasic=True,
174 )
174 )
175 def abort(ui, repo, **opts):
175 def abort(ui, repo, **opts):
176 """abort an unfinished operation (EXPERIMENTAL)
176 """abort an unfinished operation (EXPERIMENTAL)
177
177
178 Aborts a multistep operation like graft, histedit, rebase, merge,
178 Aborts a multistep operation like graft, histedit, rebase, merge,
179 and unshelve if they are in an unfinished state.
179 and unshelve if they are in an unfinished state.
180
180
181 use --dry-run/-n to dry run the command.
181 use --dry-run/-n to dry run the command.
182 """
182 """
183 dryrun = opts.get('dry_run')
183 dryrun = opts.get('dry_run')
184 abortstate = cmdutil.getunfinishedstate(repo)
184 abortstate = cmdutil.getunfinishedstate(repo)
185 if not abortstate:
185 if not abortstate:
186 raise error.Abort(_(b'no operation in progress'))
186 raise error.Abort(_(b'no operation in progress'))
187 if not abortstate.abortfunc:
187 if not abortstate.abortfunc:
188 raise error.Abort(
188 raise error.Abort(
189 (
189 (
190 _(b"%s in progress but does not support 'hg abort'")
190 _(b"%s in progress but does not support 'hg abort'")
191 % (abortstate._opname)
191 % (abortstate._opname)
192 ),
192 ),
193 hint=abortstate.hint(),
193 hint=abortstate.hint(),
194 )
194 )
195 if dryrun:
195 if dryrun:
196 ui.status(
196 ui.status(
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 )
198 )
199 return
199 return
200 return abortstate.abortfunc(ui, repo)
200 return abortstate.abortfunc(ui, repo)
201
201
202
202
203 @command(
203 @command(
204 b'add',
204 b'add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _(b'[OPTION]... [FILE]...'),
206 _(b'[OPTION]... [FILE]...'),
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpbasic=True,
208 helpbasic=True,
209 inferrepo=True,
209 inferrepo=True,
210 )
210 )
211 def add(ui, repo, *pats, **opts):
211 def add(ui, repo, *pats, **opts):
212 """add the specified files on the next commit
212 """add the specified files on the next commit
213
213
214 Schedule files to be version controlled and added to the
214 Schedule files to be version controlled and added to the
215 repository.
215 repository.
216
216
217 The files will be added to the repository at the next commit. To
217 The files will be added to the repository at the next commit. To
218 undo an add before that, see :hg:`forget`.
218 undo an add before that, see :hg:`forget`.
219
219
220 If no names are given, add all files to the repository (except
220 If no names are given, add all files to the repository (except
221 files matching ``.hgignore``).
221 files matching ``.hgignore``).
222
222
223 .. container:: verbose
223 .. container:: verbose
224
224
225 Examples:
225 Examples:
226
226
227 - New (unknown) files are added
227 - New (unknown) files are added
228 automatically by :hg:`add`::
228 automatically by :hg:`add`::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ? foo.c
233 ? foo.c
234 $ hg add
234 $ hg add
235 adding foo.c
235 adding foo.c
236 $ hg status
236 $ hg status
237 A foo.c
237 A foo.c
238
238
239 - Specific files to be added can be specified::
239 - Specific files to be added can be specified::
240
240
241 $ ls
241 $ ls
242 bar.c foo.c
242 bar.c foo.c
243 $ hg status
243 $ hg status
244 ? bar.c
244 ? bar.c
245 ? foo.c
245 ? foo.c
246 $ hg add bar.c
246 $ hg add bar.c
247 $ hg status
247 $ hg status
248 A bar.c
248 A bar.c
249 ? foo.c
249 ? foo.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253
253
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259
259
260 @command(
260 @command(
261 b'addremove',
261 b'addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _(b'[OPTION]... [FILE]...'),
263 _(b'[OPTION]... [FILE]...'),
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 inferrepo=True,
265 inferrepo=True,
266 )
266 )
267 def addremove(ui, repo, *pats, **opts):
267 def addremove(ui, repo, *pats, **opts):
268 """add all new files, delete all missing files
268 """add all new files, delete all missing files
269
269
270 Add all new files and remove all missing files from the
270 Add all new files and remove all missing files from the
271 repository.
271 repository.
272
272
273 Unless names are given, new files are ignored if they match any of
273 Unless names are given, new files are ignored if they match any of
274 the patterns in ``.hgignore``. As with add, these changes take
274 the patterns in ``.hgignore``. As with add, these changes take
275 effect at the next commit.
275 effect at the next commit.
276
276
277 Use the -s/--similarity option to detect renamed files. This
277 Use the -s/--similarity option to detect renamed files. This
278 option takes a percentage between 0 (disabled) and 100 (files must
278 option takes a percentage between 0 (disabled) and 100 (files must
279 be identical) as its parameter. With a parameter greater than 0,
279 be identical) as its parameter. With a parameter greater than 0,
280 this compares every removed file with every added file and records
280 this compares every removed file with every added file and records
281 those similar enough as renames. Detecting renamed files this way
281 those similar enough as renames. Detecting renamed files this way
282 can be expensive. After using this option, :hg:`status -C` can be
282 can be expensive. After using this option, :hg:`status -C` can be
283 used to check which files were identified as moved or renamed. If
283 used to check which files were identified as moved or renamed. If
284 not specified, -s/--similarity defaults to 100 and only renames of
284 not specified, -s/--similarity defaults to 100 and only renames of
285 identical files are detected.
285 identical files are detected.
286
286
287 .. container:: verbose
287 .. container:: verbose
288
288
289 Examples:
289 Examples:
290
290
291 - A number of files (bar.c and foo.c) are new,
291 - A number of files (bar.c and foo.c) are new,
292 while foobar.c has been removed (without using :hg:`remove`)
292 while foobar.c has been removed (without using :hg:`remove`)
293 from the repository::
293 from the repository::
294
294
295 $ ls
295 $ ls
296 bar.c foo.c
296 bar.c foo.c
297 $ hg status
297 $ hg status
298 ! foobar.c
298 ! foobar.c
299 ? bar.c
299 ? bar.c
300 ? foo.c
300 ? foo.c
301 $ hg addremove
301 $ hg addremove
302 adding bar.c
302 adding bar.c
303 adding foo.c
303 adding foo.c
304 removing foobar.c
304 removing foobar.c
305 $ hg status
305 $ hg status
306 A bar.c
306 A bar.c
307 A foo.c
307 A foo.c
308 R foobar.c
308 R foobar.c
309
309
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 Afterwards, it was edited slightly::
311 Afterwards, it was edited slightly::
312
312
313 $ ls
313 $ ls
314 foo.c
314 foo.c
315 $ hg status
315 $ hg status
316 ! foobar.c
316 ! foobar.c
317 ? foo.c
317 ? foo.c
318 $ hg addremove --similarity 90
318 $ hg addremove --similarity 90
319 removing foobar.c
319 removing foobar.c
320 adding foo.c
320 adding foo.c
321 recording removal of foobar.c as rename to foo.c (94% similar)
321 recording removal of foobar.c as rename to foo.c (94% similar)
322 $ hg status -C
322 $ hg status -C
323 A foo.c
323 A foo.c
324 foobar.c
324 foobar.c
325 R foobar.c
325 R foobar.c
326
326
327 Returns 0 if all files are successfully added.
327 Returns 0 if all files are successfully added.
328 """
328 """
329 opts = pycompat.byteskwargs(opts)
329 opts = pycompat.byteskwargs(opts)
330 if not opts.get(b'similarity'):
330 if not opts.get(b'similarity'):
331 opts[b'similarity'] = b'100'
331 opts[b'similarity'] = b'100'
332 matcher = scmutil.match(repo[None], pats, opts)
332 matcher = scmutil.match(repo[None], pats, opts)
333 relative = scmutil.anypats(pats, opts)
333 relative = scmutil.anypats(pats, opts)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336
336
337
337
338 @command(
338 @command(
339 b'annotate|blame',
339 b'annotate|blame',
340 [
340 [
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (
342 (
343 b'',
343 b'',
344 b'follow',
344 b'follow',
345 None,
345 None,
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 ),
347 ),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'a', b'text', None, _(b'treat all files as text')),
349 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'f', b'file', None, _(b'list the filename')),
351 (b'f', b'file', None, _(b'list the filename')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
355 (
355 (
356 b'l',
356 b'l',
357 b'line-number',
357 b'line-number',
358 None,
358 None,
359 _(b'show line number at the first appearance'),
359 _(b'show line number at the first appearance'),
360 ),
360 ),
361 (
361 (
362 b'',
362 b'',
363 b'skip',
363 b'skip',
364 [],
364 [],
365 _(b'revset to not display (EXPERIMENTAL)'),
365 _(b'revset to not display (EXPERIMENTAL)'),
366 _(b'REV'),
366 _(b'REV'),
367 ),
367 ),
368 ]
368 ]
369 + diffwsopts
369 + diffwsopts
370 + walkopts
370 + walkopts
371 + formatteropts,
371 + formatteropts,
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpbasic=True,
374 helpbasic=True,
375 inferrepo=True,
375 inferrepo=True,
376 )
376 )
377 def annotate(ui, repo, *pats, **opts):
377 def annotate(ui, repo, *pats, **opts):
378 """show changeset information by line for each file
378 """show changeset information by line for each file
379
379
380 List changes in files, showing the revision id responsible for
380 List changes in files, showing the revision id responsible for
381 each line.
381 each line.
382
382
383 This command is useful for discovering when a change was made and
383 This command is useful for discovering when a change was made and
384 by whom.
384 by whom.
385
385
386 If you include --file, --user, or --date, the revision number is
386 If you include --file, --user, or --date, the revision number is
387 suppressed unless you also include --number.
387 suppressed unless you also include --number.
388
388
389 Without the -a/--text option, annotate will avoid processing files
389 Without the -a/--text option, annotate will avoid processing files
390 it detects as binary. With -a, annotate will annotate the file
390 it detects as binary. With -a, annotate will annotate the file
391 anyway, although the results will probably be neither useful
391 anyway, although the results will probably be neither useful
392 nor desirable.
392 nor desirable.
393
393
394 .. container:: verbose
394 .. container:: verbose
395
395
396 Template:
396 Template:
397
397
398 The following keywords are supported in addition to the common template
398 The following keywords are supported in addition to the common template
399 keywords and functions. See also :hg:`help templates`.
399 keywords and functions. See also :hg:`help templates`.
400
400
401 :lines: List of lines with annotation data.
401 :lines: List of lines with annotation data.
402 :path: String. Repository-absolute path of the specified file.
402 :path: String. Repository-absolute path of the specified file.
403
403
404 And each entry of ``{lines}`` provides the following sub-keywords in
404 And each entry of ``{lines}`` provides the following sub-keywords in
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406
406
407 :line: String. Line content.
407 :line: String. Line content.
408 :lineno: Integer. Line number at that revision.
408 :lineno: Integer. Line number at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
410
410
411 See :hg:`help templates.operators` for the list expansion syntax.
411 See :hg:`help templates.operators` for the list expansion syntax.
412
412
413 Returns 0 on success.
413 Returns 0 on success.
414 """
414 """
415 opts = pycompat.byteskwargs(opts)
415 opts = pycompat.byteskwargs(opts)
416 if not pats:
416 if not pats:
417 raise error.Abort(_(b'at least one filename or pattern is required'))
417 raise error.Abort(_(b'at least one filename or pattern is required'))
418
418
419 if opts.get(b'follow'):
419 if opts.get(b'follow'):
420 # --follow is deprecated and now just an alias for -f/--file
420 # --follow is deprecated and now just an alias for -f/--file
421 # to mimic the behavior of Mercurial before version 1.5
421 # to mimic the behavior of Mercurial before version 1.5
422 opts[b'file'] = True
422 opts[b'file'] = True
423
423
424 if (
424 if (
425 not opts.get(b'user')
425 not opts.get(b'user')
426 and not opts.get(b'changeset')
426 and not opts.get(b'changeset')
427 and not opts.get(b'date')
427 and not opts.get(b'date')
428 and not opts.get(b'file')
428 and not opts.get(b'file')
429 ):
429 ):
430 opts[b'number'] = True
430 opts[b'number'] = True
431
431
432 linenumber = opts.get(b'line_number') is not None
432 linenumber = opts.get(b'line_number') is not None
433 if (
433 if (
434 linenumber
434 linenumber
435 and (not opts.get(b'changeset'))
435 and (not opts.get(b'changeset'))
436 and (not opts.get(b'number'))
436 and (not opts.get(b'number'))
437 ):
437 ):
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439
439
440 rev = opts.get(b'rev')
440 rev = opts.get(b'rev')
441 if rev:
441 if rev:
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 ctx = scmutil.revsingle(repo, rev)
443 ctx = scmutil.revsingle(repo, rev)
444
444
445 ui.pager(b'annotate')
445 ui.pager(b'annotate')
446 rootfm = ui.formatter(b'annotate', opts)
446 rootfm = ui.formatter(b'annotate', opts)
447 if ui.debugflag:
447 if ui.debugflag:
448 shorthex = pycompat.identity
448 shorthex = pycompat.identity
449 else:
449 else:
450
450
451 def shorthex(h):
451 def shorthex(h):
452 return h[:12]
452 return h[:12]
453
453
454 if ui.quiet:
454 if ui.quiet:
455 datefunc = dateutil.shortdate
455 datefunc = dateutil.shortdate
456 else:
456 else:
457 datefunc = dateutil.datestr
457 datefunc = dateutil.datestr
458 if ctx.rev() is None:
458 if ctx.rev() is None:
459 if opts.get(b'changeset'):
459 if opts.get(b'changeset'):
460 # omit "+" suffix which is appended to node hex
460 # omit "+" suffix which is appended to node hex
461 def formatrev(rev):
461 def formatrev(rev):
462 if rev == wdirrev:
462 if rev == wdirrev:
463 return b'%d' % ctx.p1().rev()
463 return b'%d' % ctx.p1().rev()
464 else:
464 else:
465 return b'%d' % rev
465 return b'%d' % rev
466
466
467 else:
467 else:
468
468
469 def formatrev(rev):
469 def formatrev(rev):
470 if rev == wdirrev:
470 if rev == wdirrev:
471 return b'%d+' % ctx.p1().rev()
471 return b'%d+' % ctx.p1().rev()
472 else:
472 else:
473 return b'%d ' % rev
473 return b'%d ' % rev
474
474
475 def formathex(h):
475 def formathex(h):
476 if h == wdirhex:
476 if h == wdirhex:
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 else:
478 else:
479 return b'%s ' % shorthex(h)
479 return b'%s ' % shorthex(h)
480
480
481 else:
481 else:
482 formatrev = b'%d'.__mod__
482 formatrev = b'%d'.__mod__
483 formathex = shorthex
483 formathex = shorthex
484
484
485 opmap = [
485 opmap = [
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 ]
492 ]
493 opnamemap = {
493 opnamemap = {
494 b'rev': b'number',
494 b'rev': b'number',
495 b'node': b'changeset',
495 b'node': b'changeset',
496 b'path': b'file',
496 b'path': b'file',
497 b'lineno': b'line_number',
497 b'lineno': b'line_number',
498 }
498 }
499
499
500 if rootfm.isplain():
500 if rootfm.isplain():
501
501
502 def makefunc(get, fmt):
502 def makefunc(get, fmt):
503 return lambda x: fmt(get(x))
503 return lambda x: fmt(get(x))
504
504
505 else:
505 else:
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return get
508 return get
509
509
510 datahint = rootfm.datahint()
510 datahint = rootfm.datahint()
511 funcmap = [
511 funcmap = [
512 (makefunc(get, fmt), sep)
512 (makefunc(get, fmt), sep)
513 for fn, sep, get, fmt in opmap
513 for fn, sep, get, fmt in opmap
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 ]
515 ]
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 fields = b' '.join(
517 fields = b' '.join(
518 fn
518 fn
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 )
521 )
522
522
523 def bad(x, y):
523 def bad(x, y):
524 raise error.Abort(b"%s: %s" % (x, y))
524 raise error.Abort(b"%s: %s" % (x, y))
525
525
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
527
527
528 follow = not opts.get(b'no_follow')
528 follow = not opts.get(b'no_follow')
529 diffopts = patch.difffeatureopts(
529 diffopts = patch.difffeatureopts(
530 ui, opts, section=b'annotate', whitespace=True
530 ui, opts, section=b'annotate', whitespace=True
531 )
531 )
532 skiprevs = opts.get(b'skip')
532 skiprevs = opts.get(b'skip')
533 if skiprevs:
533 if skiprevs:
534 skiprevs = scmutil.revrange(repo, skiprevs)
534 skiprevs = scmutil.revrange(repo, skiprevs)
535
535
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fctx = ctx[abs]
538 fctx = ctx[abs]
539 rootfm.startitem()
539 rootfm.startitem()
540 rootfm.data(path=abs)
540 rootfm.data(path=abs)
541 if not opts.get(b'text') and fctx.isbinary():
541 if not opts.get(b'text') and fctx.isbinary():
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 continue
543 continue
544
544
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 lines = fctx.annotate(
546 lines = fctx.annotate(
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 )
548 )
549 if not lines:
549 if not lines:
550 fm.end()
550 fm.end()
551 continue
551 continue
552 formats = []
552 formats = []
553 pieces = []
553 pieces = []
554
554
555 for f, sep in funcmap:
555 for f, sep in funcmap:
556 l = [f(n) for n in lines]
556 l = [f(n) for n in lines]
557 if fm.isplain():
557 if fm.isplain():
558 sizes = [encoding.colwidth(x) for x in l]
558 sizes = [encoding.colwidth(x) for x in l]
559 ml = max(sizes)
559 ml = max(sizes)
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 else:
561 else:
562 formats.append([b'%s'] * len(l))
562 formats.append([b'%s'] * len(l))
563 pieces.append(l)
563 pieces.append(l)
564
564
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 fm.startitem()
566 fm.startitem()
567 fm.context(fctx=n.fctx)
567 fm.context(fctx=n.fctx)
568 fm.write(fields, b"".join(f), *p)
568 fm.write(fields, b"".join(f), *p)
569 if n.skip:
569 if n.skip:
570 fmt = b"* %s"
570 fmt = b"* %s"
571 else:
571 else:
572 fmt = b": %s"
572 fmt = b": %s"
573 fm.write(b'line', fmt, n.text)
573 fm.write(b'line', fmt, n.text)
574
574
575 if not lines[-1].text.endswith(b'\n'):
575 if not lines[-1].text.endswith(b'\n'):
576 fm.plain(b'\n')
576 fm.plain(b'\n')
577 fm.end()
577 fm.end()
578
578
579 rootfm.end()
579 rootfm.end()
580
580
581
581
582 @command(
582 @command(
583 b'archive',
583 b'archive',
584 [
584 [
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (
586 (
587 b'p',
587 b'p',
588 b'prefix',
588 b'prefix',
589 b'',
589 b'',
590 _(b'directory prefix for files in archive'),
590 _(b'directory prefix for files in archive'),
591 _(b'PREFIX'),
591 _(b'PREFIX'),
592 ),
592 ),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 ]
595 ]
596 + subrepoopts
596 + subrepoopts
597 + walkopts,
597 + walkopts,
598 _(b'[OPTION]... DEST'),
598 _(b'[OPTION]... DEST'),
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 )
600 )
601 def archive(ui, repo, dest, **opts):
601 def archive(ui, repo, dest, **opts):
602 '''create an unversioned archive of a repository revision
602 '''create an unversioned archive of a repository revision
603
603
604 By default, the revision used is the parent of the working
604 By default, the revision used is the parent of the working
605 directory; use -r/--rev to specify a different revision.
605 directory; use -r/--rev to specify a different revision.
606
606
607 The archive type is automatically detected based on file
607 The archive type is automatically detected based on file
608 extension (to override, use -t/--type).
608 extension (to override, use -t/--type).
609
609
610 .. container:: verbose
610 .. container:: verbose
611
611
612 Examples:
612 Examples:
613
613
614 - create a zip file containing the 1.0 release::
614 - create a zip file containing the 1.0 release::
615
615
616 hg archive -r 1.0 project-1.0.zip
616 hg archive -r 1.0 project-1.0.zip
617
617
618 - create a tarball excluding .hg files::
618 - create a tarball excluding .hg files::
619
619
620 hg archive project.tar.gz -X ".hg*"
620 hg archive project.tar.gz -X ".hg*"
621
621
622 Valid types are:
622 Valid types are:
623
623
624 :``files``: a directory full of files (default)
624 :``files``: a directory full of files (default)
625 :``tar``: tar archive, uncompressed
625 :``tar``: tar archive, uncompressed
626 :``tbz2``: tar archive, compressed using bzip2
626 :``tbz2``: tar archive, compressed using bzip2
627 :``tgz``: tar archive, compressed using gzip
627 :``tgz``: tar archive, compressed using gzip
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``uzip``: zip archive, uncompressed
629 :``uzip``: zip archive, uncompressed
630 :``zip``: zip archive, compressed using deflate
630 :``zip``: zip archive, compressed using deflate
631
631
632 The exact name of the destination archive or directory is given
632 The exact name of the destination archive or directory is given
633 using a format string; see :hg:`help export` for details.
633 using a format string; see :hg:`help export` for details.
634
634
635 Each member added to an archive file has a directory prefix
635 Each member added to an archive file has a directory prefix
636 prepended. Use -p/--prefix to specify a format string for the
636 prepended. Use -p/--prefix to specify a format string for the
637 prefix. The default is the basename of the archive, with suffixes
637 prefix. The default is the basename of the archive, with suffixes
638 removed.
638 removed.
639
639
640 Returns 0 on success.
640 Returns 0 on success.
641 '''
641 '''
642
642
643 opts = pycompat.byteskwargs(opts)
643 opts = pycompat.byteskwargs(opts)
644 rev = opts.get(b'rev')
644 rev = opts.get(b'rev')
645 if rev:
645 if rev:
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
648 if not ctx:
648 if not ctx:
649 raise error.Abort(_(b'no working directory: please specify a revision'))
649 raise error.Abort(_(b'no working directory: please specify a revision'))
650 node = ctx.node()
650 node = ctx.node()
651 dest = cmdutil.makefilename(ctx, dest)
651 dest = cmdutil.makefilename(ctx, dest)
652 if os.path.realpath(dest) == repo.root:
652 if os.path.realpath(dest) == repo.root:
653 raise error.Abort(_(b'repository root cannot be destination'))
653 raise error.Abort(_(b'repository root cannot be destination'))
654
654
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 prefix = opts.get(b'prefix')
656 prefix = opts.get(b'prefix')
657
657
658 if dest == b'-':
658 if dest == b'-':
659 if kind == b'files':
659 if kind == b'files':
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 dest = cmdutil.makefileobj(ctx, dest)
661 dest = cmdutil.makefileobj(ctx, dest)
662 if not prefix:
662 if not prefix:
663 prefix = os.path.basename(repo.root) + b'-%h'
663 prefix = os.path.basename(repo.root) + b'-%h'
664
664
665 prefix = cmdutil.makefilename(ctx, prefix)
665 prefix = cmdutil.makefilename(ctx, prefix)
666 match = scmutil.match(ctx, [], opts)
666 match = scmutil.match(ctx, [], opts)
667 archival.archive(
667 archival.archive(
668 repo,
668 repo,
669 dest,
669 dest,
670 node,
670 node,
671 kind,
671 kind,
672 not opts.get(b'no_decode'),
672 not opts.get(b'no_decode'),
673 match,
673 match,
674 prefix,
674 prefix,
675 subrepos=opts.get(b'subrepos'),
675 subrepos=opts.get(b'subrepos'),
676 )
676 )
677
677
678
678
679 @command(
679 @command(
680 b'backout',
680 b'backout',
681 [
681 [
682 (
682 (
683 b'',
683 b'',
684 b'merge',
684 b'merge',
685 None,
685 None,
686 _(b'merge with old dirstate parent after backout'),
686 _(b'merge with old dirstate parent after backout'),
687 ),
687 ),
688 (
688 (
689 b'',
689 b'',
690 b'commit',
690 b'commit',
691 None,
691 None,
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 ),
693 ),
694 (b'', b'no-commit', None, _(b'do not commit')),
694 (b'', b'no-commit', None, _(b'do not commit')),
695 (
695 (
696 b'',
696 b'',
697 b'parent',
697 b'parent',
698 b'',
698 b'',
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'REV'),
700 _(b'REV'),
701 ),
701 ),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 ]
704 ]
705 + mergetoolopts
705 + mergetoolopts
706 + walkopts
706 + walkopts
707 + commitopts
707 + commitopts
708 + commitopts2,
708 + commitopts2,
709 _(b'[OPTION]... [-r] REV'),
709 _(b'[OPTION]... [-r] REV'),
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 )
711 )
712 def backout(ui, repo, node=None, rev=None, **opts):
712 def backout(ui, repo, node=None, rev=None, **opts):
713 '''reverse effect of earlier changeset
713 '''reverse effect of earlier changeset
714
714
715 Prepare a new changeset with the effect of REV undone in the
715 Prepare a new changeset with the effect of REV undone in the
716 current working directory. If no conflicts were encountered,
716 current working directory. If no conflicts were encountered,
717 it will be committed immediately.
717 it will be committed immediately.
718
718
719 If REV is the parent of the working directory, then this new changeset
719 If REV is the parent of the working directory, then this new changeset
720 is committed automatically (unless --no-commit is specified).
720 is committed automatically (unless --no-commit is specified).
721
721
722 .. note::
722 .. note::
723
723
724 :hg:`backout` cannot be used to fix either an unwanted or
724 :hg:`backout` cannot be used to fix either an unwanted or
725 incorrect merge.
725 incorrect merge.
726
726
727 .. container:: verbose
727 .. container:: verbose
728
728
729 Examples:
729 Examples:
730
730
731 - Reverse the effect of the parent of the working directory.
731 - Reverse the effect of the parent of the working directory.
732 This backout will be committed immediately::
732 This backout will be committed immediately::
733
733
734 hg backout -r .
734 hg backout -r .
735
735
736 - Reverse the effect of previous bad revision 23::
736 - Reverse the effect of previous bad revision 23::
737
737
738 hg backout -r 23
738 hg backout -r 23
739
739
740 - Reverse the effect of previous bad revision 23 and
740 - Reverse the effect of previous bad revision 23 and
741 leave changes uncommitted::
741 leave changes uncommitted::
742
742
743 hg backout -r 23 --no-commit
743 hg backout -r 23 --no-commit
744 hg commit -m "Backout revision 23"
744 hg commit -m "Backout revision 23"
745
745
746 By default, the pending changeset will have one parent,
746 By default, the pending changeset will have one parent,
747 maintaining a linear history. With --merge, the pending
747 maintaining a linear history. With --merge, the pending
748 changeset will instead have two parents: the old parent of the
748 changeset will instead have two parents: the old parent of the
749 working directory and a new child of REV that simply undoes REV.
749 working directory and a new child of REV that simply undoes REV.
750
750
751 Before version 1.7, the behavior without --merge was equivalent
751 Before version 1.7, the behavior without --merge was equivalent
752 to specifying --merge followed by :hg:`update --clean .` to
752 to specifying --merge followed by :hg:`update --clean .` to
753 cancel the merge and leave the child of REV as a head to be
753 cancel the merge and leave the child of REV as a head to be
754 merged separately.
754 merged separately.
755
755
756 See :hg:`help dates` for a list of formats valid for -d/--date.
756 See :hg:`help dates` for a list of formats valid for -d/--date.
757
757
758 See :hg:`help revert` for a way to restore files to the state
758 See :hg:`help revert` for a way to restore files to the state
759 of another revision.
759 of another revision.
760
760
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 files.
762 files.
763 '''
763 '''
764 with repo.wlock(), repo.lock():
764 with repo.wlock(), repo.lock():
765 return _dobackout(ui, repo, node, rev, **opts)
765 return _dobackout(ui, repo, node, rev, **opts)
766
766
767
767
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
770 if opts.get(b'commit') and opts.get(b'no_commit'):
770 if opts.get(b'commit') and opts.get(b'no_commit'):
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 if opts.get(b'merge') and opts.get(b'no_commit'):
772 if opts.get(b'merge') and opts.get(b'no_commit'):
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774
774
775 if rev and node:
775 if rev and node:
776 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
777
777
778 if not rev:
778 if not rev:
779 rev = node
779 rev = node
780
780
781 if not rev:
781 if not rev:
782 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
783
783
784 date = opts.get(b'date')
784 date = opts.get(b'date')
785 if date:
785 if date:
786 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
787
787
788 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
789 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
790 node = scmutil.revsingle(repo, rev).node()
790 node = scmutil.revsingle(repo, rev).node()
791
791
792 op1, op2 = repo.dirstate.parents()
792 op1, op2 = repo.dirstate.parents()
793 if not repo.changelog.isancestor(node, op1):
793 if not repo.changelog.isancestor(node, op1):
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795
795
796 p1, p2 = repo.changelog.parents(node)
796 p1, p2 = repo.changelog.parents(node)
797 if p1 == nullid:
797 if p1 == nullid:
798 raise error.Abort(_(b'cannot backout a change with no parents'))
798 raise error.Abort(_(b'cannot backout a change with no parents'))
799 if p2 != nullid:
799 if p2 != nullid:
800 if not opts.get(b'parent'):
800 if not opts.get(b'parent'):
801 raise error.Abort(_(b'cannot backout a merge changeset'))
801 raise error.Abort(_(b'cannot backout a merge changeset'))
802 p = repo.lookup(opts[b'parent'])
802 p = repo.lookup(opts[b'parent'])
803 if p not in (p1, p2):
803 if p not in (p1, p2):
804 raise error.Abort(
804 raise error.Abort(
805 _(b'%s is not a parent of %s') % (short(p), short(node))
805 _(b'%s is not a parent of %s') % (short(p), short(node))
806 )
806 )
807 parent = p
807 parent = p
808 else:
808 else:
809 if opts.get(b'parent'):
809 if opts.get(b'parent'):
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 parent = p1
811 parent = p1
812
812
813 # the backout should appear on the same branch
813 # the backout should appear on the same branch
814 branch = repo.dirstate.branch()
814 branch = repo.dirstate.branch()
815 bheads = repo.branchheads(branch)
815 bheads = repo.branchheads(branch)
816 rctx = scmutil.revsingle(repo, hex(parent))
816 rctx = scmutil.revsingle(repo, hex(parent))
817 if not opts.get(b'merge') and op1 != node:
817 if not opts.get(b'merge') and op1 != node:
818 with dirstateguard.dirstateguard(repo, b'backout'):
818 with dirstateguard.dirstateguard(repo, b'backout'):
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 with ui.configoverride(overrides, b'backout'):
820 with ui.configoverride(overrides, b'backout'):
821 stats = mergemod.update(
821 stats = mergemod.update(
822 repo,
822 repo,
823 parent,
823 parent,
824 branchmerge=True,
824 branchmerge=True,
825 force=True,
825 force=True,
826 ancestor=node,
826 ancestor=node,
827 mergeancestor=False,
827 mergeancestor=False,
828 )
828 )
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 if not newnode:
860 if not newnode:
861 ui.status(_(b"nothing changed\n"))
861 ui.status(_(b"nothing changed\n"))
862 return 1
862 return 1
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
864
864
865 def nice(node):
865 def nice(node):
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867
867
868 ui.status(
868 ui.status(
869 _(b'changeset %s backs out changeset %s\n')
869 _(b'changeset %s backs out changeset %s\n')
870 % (nice(repo.changelog.tip()), nice(node))
870 % (nice(repo.changelog.tip()), nice(node))
871 )
871 )
872 if opts.get(b'merge') and op1 != node:
872 if opts.get(b'merge') and op1 != node:
873 hg.clean(repo, op1, show_stats=False)
873 hg.clean(repo, op1, show_stats=False)
874 ui.status(
874 ui.status(
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 )
876 )
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 with ui.configoverride(overrides, b'backout'):
878 with ui.configoverride(overrides, b'backout'):
879 return hg.merge(repo[b'tip'])
879 return hg.merge(repo[b'tip'])
880 return 0
880 return 0
881
881
882
882
883 @command(
883 @command(
884 b'bisect',
884 b'bisect',
885 [
885 [
886 (b'r', b'reset', False, _(b'reset bisect state')),
886 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'g', b'good', False, _(b'mark changeset good')),
887 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (
891 (
892 b'c',
892 b'c',
893 b'command',
893 b'command',
894 b'',
894 b'',
895 _(b'use command to check changeset state'),
895 _(b'use command to check changeset state'),
896 _(b'CMD'),
896 _(b'CMD'),
897 ),
897 ),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
899 ],
899 ],
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 )
902 )
903 def bisect(
903 def bisect(
904 ui,
904 ui,
905 repo,
905 repo,
906 rev=None,
906 rev=None,
907 extra=None,
907 extra=None,
908 command=None,
908 command=None,
909 reset=None,
909 reset=None,
910 good=None,
910 good=None,
911 bad=None,
911 bad=None,
912 skip=None,
912 skip=None,
913 extend=None,
913 extend=None,
914 noupdate=None,
914 noupdate=None,
915 ):
915 ):
916 """subdivision search of changesets
916 """subdivision search of changesets
917
917
918 This command helps to find changesets which introduce problems. To
918 This command helps to find changesets which introduce problems. To
919 use, mark the earliest changeset you know exhibits the problem as
919 use, mark the earliest changeset you know exhibits the problem as
920 bad, then mark the latest changeset which is free from the problem
920 bad, then mark the latest changeset which is free from the problem
921 as good. Bisect will update your working directory to a revision
921 as good. Bisect will update your working directory to a revision
922 for testing (unless the -U/--noupdate option is specified). Once
922 for testing (unless the -U/--noupdate option is specified). Once
923 you have performed tests, mark the working directory as good or
923 you have performed tests, mark the working directory as good or
924 bad, and bisect will either update to another candidate changeset
924 bad, and bisect will either update to another candidate changeset
925 or announce that it has found the bad revision.
925 or announce that it has found the bad revision.
926
926
927 As a shortcut, you can also use the revision argument to mark a
927 As a shortcut, you can also use the revision argument to mark a
928 revision as good or bad without checking it out first.
928 revision as good or bad without checking it out first.
929
929
930 If you supply a command, it will be used for automatic bisection.
930 If you supply a command, it will be used for automatic bisection.
931 The environment variable HG_NODE will contain the ID of the
931 The environment variable HG_NODE will contain the ID of the
932 changeset being tested. The exit status of the command will be
932 changeset being tested. The exit status of the command will be
933 used to mark revisions as good or bad: status 0 means good, 125
933 used to mark revisions as good or bad: status 0 means good, 125
934 means to skip the revision, 127 (command not found) will abort the
934 means to skip the revision, 127 (command not found) will abort the
935 bisection, and any other non-zero exit status means the revision
935 bisection, and any other non-zero exit status means the revision
936 is bad.
936 is bad.
937
937
938 .. container:: verbose
938 .. container:: verbose
939
939
940 Some examples:
940 Some examples:
941
941
942 - start a bisection with known bad revision 34, and good revision 12::
942 - start a bisection with known bad revision 34, and good revision 12::
943
943
944 hg bisect --bad 34
944 hg bisect --bad 34
945 hg bisect --good 12
945 hg bisect --good 12
946
946
947 - advance the current bisection by marking current revision as good or
947 - advance the current bisection by marking current revision as good or
948 bad::
948 bad::
949
949
950 hg bisect --good
950 hg bisect --good
951 hg bisect --bad
951 hg bisect --bad
952
952
953 - mark the current revision, or a known revision, to be skipped (e.g. if
953 - mark the current revision, or a known revision, to be skipped (e.g. if
954 that revision is not usable because of another issue)::
954 that revision is not usable because of another issue)::
955
955
956 hg bisect --skip
956 hg bisect --skip
957 hg bisect --skip 23
957 hg bisect --skip 23
958
958
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960
960
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962
962
963 - forget the current bisection::
963 - forget the current bisection::
964
964
965 hg bisect --reset
965 hg bisect --reset
966
966
967 - use 'make && make tests' to automatically find the first broken
967 - use 'make && make tests' to automatically find the first broken
968 revision::
968 revision::
969
969
970 hg bisect --reset
970 hg bisect --reset
971 hg bisect --bad 34
971 hg bisect --bad 34
972 hg bisect --good 12
972 hg bisect --good 12
973 hg bisect --command "make && make tests"
973 hg bisect --command "make && make tests"
974
974
975 - see all changesets whose states are already known in the current
975 - see all changesets whose states are already known in the current
976 bisection::
976 bisection::
977
977
978 hg log -r "bisect(pruned)"
978 hg log -r "bisect(pruned)"
979
979
980 - see the changeset currently being bisected (especially useful
980 - see the changeset currently being bisected (especially useful
981 if running with -U/--noupdate)::
981 if running with -U/--noupdate)::
982
982
983 hg log -r "bisect(current)"
983 hg log -r "bisect(current)"
984
984
985 - see all changesets that took part in the current bisection::
985 - see all changesets that took part in the current bisection::
986
986
987 hg log -r "bisect(range)"
987 hg log -r "bisect(range)"
988
988
989 - you can even get a nice graph::
989 - you can even get a nice graph::
990
990
991 hg log --graph -r "bisect(range)"
991 hg log --graph -r "bisect(range)"
992
992
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994
994
995 Returns 0 on success.
995 Returns 0 on success.
996 """
996 """
997 # backward compatibility
997 # backward compatibility
998 if rev in b"good bad reset init".split():
998 if rev in b"good bad reset init".split():
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 cmd, rev, extra = rev, extra, None
1000 cmd, rev, extra = rev, extra, None
1001 if cmd == b"good":
1001 if cmd == b"good":
1002 good = True
1002 good = True
1003 elif cmd == b"bad":
1003 elif cmd == b"bad":
1004 bad = True
1004 bad = True
1005 else:
1005 else:
1006 reset = True
1006 reset = True
1007 elif extra:
1007 elif extra:
1008 raise error.Abort(_(b'incompatible arguments'))
1008 raise error.Abort(_(b'incompatible arguments'))
1009
1009
1010 incompatibles = {
1010 incompatibles = {
1011 b'--bad': bad,
1011 b'--bad': bad,
1012 b'--command': bool(command),
1012 b'--command': bool(command),
1013 b'--extend': extend,
1013 b'--extend': extend,
1014 b'--good': good,
1014 b'--good': good,
1015 b'--reset': reset,
1015 b'--reset': reset,
1016 b'--skip': skip,
1016 b'--skip': skip,
1017 }
1017 }
1018
1018
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1020
1020
1021 if len(enabled) > 1:
1021 if len(enabled) > 1:
1022 raise error.Abort(
1022 raise error.Abort(
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 )
1024 )
1025
1025
1026 if reset:
1026 if reset:
1027 hbisect.resetstate(repo)
1027 hbisect.resetstate(repo)
1028 return
1028 return
1029
1029
1030 state = hbisect.load_state(repo)
1030 state = hbisect.load_state(repo)
1031
1031
1032 # update state
1032 # update state
1033 if good or bad or skip:
1033 if good or bad or skip:
1034 if rev:
1034 if rev:
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 else:
1036 else:
1037 nodes = [repo.lookup(b'.')]
1037 nodes = [repo.lookup(b'.')]
1038 if good:
1038 if good:
1039 state[b'good'] += nodes
1039 state[b'good'] += nodes
1040 elif bad:
1040 elif bad:
1041 state[b'bad'] += nodes
1041 state[b'bad'] += nodes
1042 elif skip:
1042 elif skip:
1043 state[b'skip'] += nodes
1043 state[b'skip'] += nodes
1044 hbisect.save_state(repo, state)
1044 hbisect.save_state(repo, state)
1045 if not (state[b'good'] and state[b'bad']):
1045 if not (state[b'good'] and state[b'bad']):
1046 return
1046 return
1047
1047
1048 def mayupdate(repo, node, show_stats=True):
1048 def mayupdate(repo, node, show_stats=True):
1049 """common used update sequence"""
1049 """common used update sequence"""
1050 if noupdate:
1050 if noupdate:
1051 return
1051 return
1052 cmdutil.checkunfinished(repo)
1052 cmdutil.checkunfinished(repo)
1053 cmdutil.bailifchanged(repo)
1053 cmdutil.bailifchanged(repo)
1054 return hg.clean(repo, node, show_stats=show_stats)
1054 return hg.clean(repo, node, show_stats=show_stats)
1055
1055
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057
1057
1058 if command:
1058 if command:
1059 changesets = 1
1059 changesets = 1
1060 if noupdate:
1060 if noupdate:
1061 try:
1061 try:
1062 node = state[b'current'][0]
1062 node = state[b'current'][0]
1063 except LookupError:
1063 except LookupError:
1064 raise error.Abort(
1064 raise error.Abort(
1065 _(
1065 _(
1066 b'current bisect revision is unknown - '
1066 b'current bisect revision is unknown - '
1067 b'start a new bisect to fix'
1067 b'start a new bisect to fix'
1068 )
1068 )
1069 )
1069 )
1070 else:
1070 else:
1071 node, p2 = repo.dirstate.parents()
1071 node, p2 = repo.dirstate.parents()
1072 if p2 != nullid:
1072 if p2 != nullid:
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1074 if rev:
1074 if rev:
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 with hbisect.restore_state(repo, state, node):
1076 with hbisect.restore_state(repo, state, node):
1077 while changesets:
1077 while changesets:
1078 # update state
1078 # update state
1079 state[b'current'] = [node]
1079 state[b'current'] = [node]
1080 hbisect.save_state(repo, state)
1080 hbisect.save_state(repo, state)
1081 status = ui.system(
1081 status = ui.system(
1082 command,
1082 command,
1083 environ={b'HG_NODE': hex(node)},
1083 environ={b'HG_NODE': hex(node)},
1084 blockedtag=b'bisect_check',
1084 blockedtag=b'bisect_check',
1085 )
1085 )
1086 if status == 125:
1086 if status == 125:
1087 transition = b"skip"
1087 transition = b"skip"
1088 elif status == 0:
1088 elif status == 0:
1089 transition = b"good"
1089 transition = b"good"
1090 # status < 0 means process was killed
1090 # status < 0 means process was killed
1091 elif status == 127:
1091 elif status == 127:
1092 raise error.Abort(_(b"failed to execute %s") % command)
1092 raise error.Abort(_(b"failed to execute %s") % command)
1093 elif status < 0:
1093 elif status < 0:
1094 raise error.Abort(_(b"%s killed") % command)
1094 raise error.Abort(_(b"%s killed") % command)
1095 else:
1095 else:
1096 transition = b"bad"
1096 transition = b"bad"
1097 state[transition].append(node)
1097 state[transition].append(node)
1098 ctx = repo[node]
1098 ctx = repo[node]
1099 ui.status(
1099 ui.status(
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 )
1101 )
1102 hbisect.checkstate(state)
1102 hbisect.checkstate(state)
1103 # bisect
1103 # bisect
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 # update to next check
1105 # update to next check
1106 node = nodes[0]
1106 node = nodes[0]
1107 mayupdate(repo, node, show_stats=False)
1107 mayupdate(repo, node, show_stats=False)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1109 return
1109 return
1110
1110
1111 hbisect.checkstate(state)
1111 hbisect.checkstate(state)
1112
1112
1113 # actually bisect
1113 # actually bisect
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1115 if extend:
1115 if extend:
1116 if not changesets:
1116 if not changesets:
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1118 if extendnode is not None:
1118 if extendnode is not None:
1119 ui.write(
1119 ui.write(
1120 _(b"Extending search to changeset %d:%s\n")
1120 _(b"Extending search to changeset %d:%s\n")
1121 % (extendnode.rev(), extendnode)
1121 % (extendnode.rev(), extendnode)
1122 )
1122 )
1123 state[b'current'] = [extendnode.node()]
1123 state[b'current'] = [extendnode.node()]
1124 hbisect.save_state(repo, state)
1124 hbisect.save_state(repo, state)
1125 return mayupdate(repo, extendnode.node())
1125 return mayupdate(repo, extendnode.node())
1126 raise error.Abort(_(b"nothing to extend"))
1126 raise error.Abort(_(b"nothing to extend"))
1127
1127
1128 if changesets == 0:
1128 if changesets == 0:
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1130 else:
1130 else:
1131 assert len(nodes) == 1 # only a single node can be tested next
1131 assert len(nodes) == 1 # only a single node can be tested next
1132 node = nodes[0]
1132 node = nodes[0]
1133 # compute the approximate number of remaining tests
1133 # compute the approximate number of remaining tests
1134 tests, size = 0, 2
1134 tests, size = 0, 2
1135 while size <= changesets:
1135 while size <= changesets:
1136 tests, size = tests + 1, size * 2
1136 tests, size = tests + 1, size * 2
1137 rev = repo.changelog.rev(node)
1137 rev = repo.changelog.rev(node)
1138 ui.write(
1138 ui.write(
1139 _(
1139 _(
1140 b"Testing changeset %d:%s "
1140 b"Testing changeset %d:%s "
1141 b"(%d changesets remaining, ~%d tests)\n"
1141 b"(%d changesets remaining, ~%d tests)\n"
1142 )
1142 )
1143 % (rev, short(node), changesets, tests)
1143 % (rev, short(node), changesets, tests)
1144 )
1144 )
1145 state[b'current'] = [node]
1145 state[b'current'] = [node]
1146 hbisect.save_state(repo, state)
1146 hbisect.save_state(repo, state)
1147 return mayupdate(repo, node)
1147 return mayupdate(repo, node)
1148
1148
1149
1149
1150 @command(
1150 @command(
1151 b'bookmarks|bookmark',
1151 b'bookmarks|bookmark',
1152 [
1152 [
1153 (b'f', b'force', False, _(b'force')),
1153 (b'f', b'force', False, _(b'force')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1159 ]
1159 ]
1160 + formatteropts,
1160 + formatteropts,
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1163 )
1163 )
1164 def bookmark(ui, repo, *names, **opts):
1164 def bookmark(ui, repo, *names, **opts):
1165 '''create a new bookmark or list existing bookmarks
1165 '''create a new bookmark or list existing bookmarks
1166
1166
1167 Bookmarks are labels on changesets to help track lines of development.
1167 Bookmarks are labels on changesets to help track lines of development.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1170
1170
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1172 The active bookmark is indicated with a '*'.
1172 The active bookmark is indicated with a '*'.
1173 When a commit is made, the active bookmark will advance to the new commit.
1173 When a commit is made, the active bookmark will advance to the new commit.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1175 Updating away from a bookmark will cause it to be deactivated.
1175 Updating away from a bookmark will cause it to be deactivated.
1176
1176
1177 Bookmarks can be pushed and pulled between repositories (see
1177 Bookmarks can be pushed and pulled between repositories (see
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1180 be created. Using :hg:`merge` will resolve the divergence.
1180 be created. Using :hg:`merge` will resolve the divergence.
1181
1181
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1183 the active bookmark's name.
1183 the active bookmark's name.
1184
1184
1185 A bookmark named '@' has the special property that :hg:`clone` will
1185 A bookmark named '@' has the special property that :hg:`clone` will
1186 check it out by default if it exists.
1186 check it out by default if it exists.
1187
1187
1188 .. container:: verbose
1188 .. container:: verbose
1189
1189
1190 Template:
1190 Template:
1191
1191
1192 The following keywords are supported in addition to the common template
1192 The following keywords are supported in addition to the common template
1193 keywords and functions such as ``{bookmark}``. See also
1193 keywords and functions such as ``{bookmark}``. See also
1194 :hg:`help templates`.
1194 :hg:`help templates`.
1195
1195
1196 :active: Boolean. True if the bookmark is active.
1196 :active: Boolean. True if the bookmark is active.
1197
1197
1198 Examples:
1198 Examples:
1199
1199
1200 - create an active bookmark for a new line of development::
1200 - create an active bookmark for a new line of development::
1201
1201
1202 hg book new-feature
1202 hg book new-feature
1203
1203
1204 - create an inactive bookmark as a place marker::
1204 - create an inactive bookmark as a place marker::
1205
1205
1206 hg book -i reviewed
1206 hg book -i reviewed
1207
1207
1208 - create an inactive bookmark on another changeset::
1208 - create an inactive bookmark on another changeset::
1209
1209
1210 hg book -r .^ tested
1210 hg book -r .^ tested
1211
1211
1212 - rename bookmark turkey to dinner::
1212 - rename bookmark turkey to dinner::
1213
1213
1214 hg book -m turkey dinner
1214 hg book -m turkey dinner
1215
1215
1216 - move the '@' bookmark from another branch::
1216 - move the '@' bookmark from another branch::
1217
1217
1218 hg book -f @
1218 hg book -f @
1219
1219
1220 - print only the active bookmark name::
1220 - print only the active bookmark name::
1221
1221
1222 hg book -ql .
1222 hg book -ql .
1223 '''
1223 '''
1224 opts = pycompat.byteskwargs(opts)
1224 opts = pycompat.byteskwargs(opts)
1225 force = opts.get(b'force')
1225 force = opts.get(b'force')
1226 rev = opts.get(b'rev')
1226 rev = opts.get(b'rev')
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1228
1228
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1230 if action:
1230 if action:
1231 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1231 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1232 elif names or rev:
1232 elif names or rev:
1233 action = b'add'
1233 action = b'add'
1234 elif inactive:
1234 elif inactive:
1235 action = b'inactive' # meaning deactivate
1235 action = b'inactive' # meaning deactivate
1236 else:
1236 else:
1237 action = b'list'
1237 action = b'list'
1238
1238
1239 cmdutil.check_incompatible_arguments(
1239 cmdutil.check_incompatible_arguments(
1240 opts, b'inactive', [b'delete', b'list']
1240 opts, b'inactive', [b'delete', b'list']
1241 )
1241 )
1242 if not names and action in {b'add', b'delete'}:
1242 if not names and action in {b'add', b'delete'}:
1243 raise error.Abort(_(b"bookmark name required"))
1243 raise error.Abort(_(b"bookmark name required"))
1244
1244
1245 if action in {b'add', b'delete', b'rename', b'inactive'}:
1245 if action in {b'add', b'delete', b'rename', b'inactive'}:
1246 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1246 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1247 if action == b'delete':
1247 if action == b'delete':
1248 names = pycompat.maplist(repo._bookmarks.expandname, names)
1248 names = pycompat.maplist(repo._bookmarks.expandname, names)
1249 bookmarks.delete(repo, tr, names)
1249 bookmarks.delete(repo, tr, names)
1250 elif action == b'rename':
1250 elif action == b'rename':
1251 if not names:
1251 if not names:
1252 raise error.Abort(_(b"new bookmark name required"))
1252 raise error.Abort(_(b"new bookmark name required"))
1253 elif len(names) > 1:
1253 elif len(names) > 1:
1254 raise error.Abort(_(b"only one new bookmark name allowed"))
1254 raise error.Abort(_(b"only one new bookmark name allowed"))
1255 oldname = repo._bookmarks.expandname(opts[b'rename'])
1255 oldname = repo._bookmarks.expandname(opts[b'rename'])
1256 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1256 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1257 elif action == b'add':
1257 elif action == b'add':
1258 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1258 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1259 elif action == b'inactive':
1259 elif action == b'inactive':
1260 if len(repo._bookmarks) == 0:
1260 if len(repo._bookmarks) == 0:
1261 ui.status(_(b"no bookmarks set\n"))
1261 ui.status(_(b"no bookmarks set\n"))
1262 elif not repo._activebookmark:
1262 elif not repo._activebookmark:
1263 ui.status(_(b"no active bookmark\n"))
1263 ui.status(_(b"no active bookmark\n"))
1264 else:
1264 else:
1265 bookmarks.deactivate(repo)
1265 bookmarks.deactivate(repo)
1266 elif action == b'list':
1266 elif action == b'list':
1267 names = pycompat.maplist(repo._bookmarks.expandname, names)
1267 names = pycompat.maplist(repo._bookmarks.expandname, names)
1268 with ui.formatter(b'bookmarks', opts) as fm:
1268 with ui.formatter(b'bookmarks', opts) as fm:
1269 bookmarks.printbookmarks(ui, repo, fm, names)
1269 bookmarks.printbookmarks(ui, repo, fm, names)
1270 else:
1270 else:
1271 raise error.ProgrammingError(b'invalid action: %s' % action)
1271 raise error.ProgrammingError(b'invalid action: %s' % action)
1272
1272
1273
1273
1274 @command(
1274 @command(
1275 b'branch',
1275 b'branch',
1276 [
1276 [
1277 (
1277 (
1278 b'f',
1278 b'f',
1279 b'force',
1279 b'force',
1280 None,
1280 None,
1281 _(b'set branch name even if it shadows an existing branch'),
1281 _(b'set branch name even if it shadows an existing branch'),
1282 ),
1282 ),
1283 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1283 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1284 (
1284 (
1285 b'r',
1285 b'r',
1286 b'rev',
1286 b'rev',
1287 [],
1287 [],
1288 _(b'change branches of the given revs (EXPERIMENTAL)'),
1288 _(b'change branches of the given revs (EXPERIMENTAL)'),
1289 ),
1289 ),
1290 ],
1290 ],
1291 _(b'[-fC] [NAME]'),
1291 _(b'[-fC] [NAME]'),
1292 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1292 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1293 )
1293 )
1294 def branch(ui, repo, label=None, **opts):
1294 def branch(ui, repo, label=None, **opts):
1295 """set or show the current branch name
1295 """set or show the current branch name
1296
1296
1297 .. note::
1297 .. note::
1298
1298
1299 Branch names are permanent and global. Use :hg:`bookmark` to create a
1299 Branch names are permanent and global. Use :hg:`bookmark` to create a
1300 light-weight bookmark instead. See :hg:`help glossary` for more
1300 light-weight bookmark instead. See :hg:`help glossary` for more
1301 information about named branches and bookmarks.
1301 information about named branches and bookmarks.
1302
1302
1303 With no argument, show the current branch name. With one argument,
1303 With no argument, show the current branch name. With one argument,
1304 set the working directory branch name (the branch will not exist
1304 set the working directory branch name (the branch will not exist
1305 in the repository until the next commit). Standard practice
1305 in the repository until the next commit). Standard practice
1306 recommends that primary development take place on the 'default'
1306 recommends that primary development take place on the 'default'
1307 branch.
1307 branch.
1308
1308
1309 Unless -f/--force is specified, branch will not let you set a
1309 Unless -f/--force is specified, branch will not let you set a
1310 branch name that already exists.
1310 branch name that already exists.
1311
1311
1312 Use -C/--clean to reset the working directory branch to that of
1312 Use -C/--clean to reset the working directory branch to that of
1313 the parent of the working directory, negating a previous branch
1313 the parent of the working directory, negating a previous branch
1314 change.
1314 change.
1315
1315
1316 Use the command :hg:`update` to switch to an existing branch. Use
1316 Use the command :hg:`update` to switch to an existing branch. Use
1317 :hg:`commit --close-branch` to mark this branch head as closed.
1317 :hg:`commit --close-branch` to mark this branch head as closed.
1318 When all heads of a branch are closed, the branch will be
1318 When all heads of a branch are closed, the branch will be
1319 considered closed.
1319 considered closed.
1320
1320
1321 Returns 0 on success.
1321 Returns 0 on success.
1322 """
1322 """
1323 opts = pycompat.byteskwargs(opts)
1323 opts = pycompat.byteskwargs(opts)
1324 revs = opts.get(b'rev')
1324 revs = opts.get(b'rev')
1325 if label:
1325 if label:
1326 label = label.strip()
1326 label = label.strip()
1327
1327
1328 if not opts.get(b'clean') and not label:
1328 if not opts.get(b'clean') and not label:
1329 if revs:
1329 if revs:
1330 raise error.Abort(_(b"no branch name specified for the revisions"))
1330 raise error.Abort(_(b"no branch name specified for the revisions"))
1331 ui.write(b"%s\n" % repo.dirstate.branch())
1331 ui.write(b"%s\n" % repo.dirstate.branch())
1332 return
1332 return
1333
1333
1334 with repo.wlock():
1334 with repo.wlock():
1335 if opts.get(b'clean'):
1335 if opts.get(b'clean'):
1336 label = repo[b'.'].branch()
1336 label = repo[b'.'].branch()
1337 repo.dirstate.setbranch(label)
1337 repo.dirstate.setbranch(label)
1338 ui.status(_(b'reset working directory to branch %s\n') % label)
1338 ui.status(_(b'reset working directory to branch %s\n') % label)
1339 elif label:
1339 elif label:
1340
1340
1341 scmutil.checknewlabel(repo, label, b'branch')
1341 scmutil.checknewlabel(repo, label, b'branch')
1342 if revs:
1342 if revs:
1343 return cmdutil.changebranch(ui, repo, revs, label, opts)
1343 return cmdutil.changebranch(ui, repo, revs, label, opts)
1344
1344
1345 if not opts.get(b'force') and label in repo.branchmap():
1345 if not opts.get(b'force') and label in repo.branchmap():
1346 if label not in [p.branch() for p in repo[None].parents()]:
1346 if label not in [p.branch() for p in repo[None].parents()]:
1347 raise error.Abort(
1347 raise error.Abort(
1348 _(b'a branch of the same name already exists'),
1348 _(b'a branch of the same name already exists'),
1349 # i18n: "it" refers to an existing branch
1349 # i18n: "it" refers to an existing branch
1350 hint=_(b"use 'hg update' to switch to it"),
1350 hint=_(b"use 'hg update' to switch to it"),
1351 )
1351 )
1352
1352
1353 repo.dirstate.setbranch(label)
1353 repo.dirstate.setbranch(label)
1354 ui.status(_(b'marked working directory as branch %s\n') % label)
1354 ui.status(_(b'marked working directory as branch %s\n') % label)
1355
1355
1356 # find any open named branches aside from default
1356 # find any open named branches aside from default
1357 for n, h, t, c in repo.branchmap().iterbranches():
1357 for n, h, t, c in repo.branchmap().iterbranches():
1358 if n != b"default" and not c:
1358 if n != b"default" and not c:
1359 return 0
1359 return 0
1360 ui.status(
1360 ui.status(
1361 _(
1361 _(
1362 b'(branches are permanent and global, '
1362 b'(branches are permanent and global, '
1363 b'did you want a bookmark?)\n'
1363 b'did you want a bookmark?)\n'
1364 )
1364 )
1365 )
1365 )
1366
1366
1367
1367
1368 @command(
1368 @command(
1369 b'branches',
1369 b'branches',
1370 [
1370 [
1371 (
1371 (
1372 b'a',
1372 b'a',
1373 b'active',
1373 b'active',
1374 False,
1374 False,
1375 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1375 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1376 ),
1376 ),
1377 (b'c', b'closed', False, _(b'show normal and closed branches')),
1377 (b'c', b'closed', False, _(b'show normal and closed branches')),
1378 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1378 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1379 ]
1379 ]
1380 + formatteropts,
1380 + formatteropts,
1381 _(b'[-c]'),
1381 _(b'[-c]'),
1382 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1382 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1383 intents={INTENT_READONLY},
1383 intents={INTENT_READONLY},
1384 )
1384 )
1385 def branches(ui, repo, active=False, closed=False, **opts):
1385 def branches(ui, repo, active=False, closed=False, **opts):
1386 """list repository named branches
1386 """list repository named branches
1387
1387
1388 List the repository's named branches, indicating which ones are
1388 List the repository's named branches, indicating which ones are
1389 inactive. If -c/--closed is specified, also list branches which have
1389 inactive. If -c/--closed is specified, also list branches which have
1390 been marked closed (see :hg:`commit --close-branch`).
1390 been marked closed (see :hg:`commit --close-branch`).
1391
1391
1392 Use the command :hg:`update` to switch to an existing branch.
1392 Use the command :hg:`update` to switch to an existing branch.
1393
1393
1394 .. container:: verbose
1394 .. container:: verbose
1395
1395
1396 Template:
1396 Template:
1397
1397
1398 The following keywords are supported in addition to the common template
1398 The following keywords are supported in addition to the common template
1399 keywords and functions such as ``{branch}``. See also
1399 keywords and functions such as ``{branch}``. See also
1400 :hg:`help templates`.
1400 :hg:`help templates`.
1401
1401
1402 :active: Boolean. True if the branch is active.
1402 :active: Boolean. True if the branch is active.
1403 :closed: Boolean. True if the branch is closed.
1403 :closed: Boolean. True if the branch is closed.
1404 :current: Boolean. True if it is the current branch.
1404 :current: Boolean. True if it is the current branch.
1405
1405
1406 Returns 0.
1406 Returns 0.
1407 """
1407 """
1408
1408
1409 opts = pycompat.byteskwargs(opts)
1409 opts = pycompat.byteskwargs(opts)
1410 revs = opts.get(b'rev')
1410 revs = opts.get(b'rev')
1411 selectedbranches = None
1411 selectedbranches = None
1412 if revs:
1412 if revs:
1413 revs = scmutil.revrange(repo, revs)
1413 revs = scmutil.revrange(repo, revs)
1414 getbi = repo.revbranchcache().branchinfo
1414 getbi = repo.revbranchcache().branchinfo
1415 selectedbranches = {getbi(r)[0] for r in revs}
1415 selectedbranches = {getbi(r)[0] for r in revs}
1416
1416
1417 ui.pager(b'branches')
1417 ui.pager(b'branches')
1418 fm = ui.formatter(b'branches', opts)
1418 fm = ui.formatter(b'branches', opts)
1419 hexfunc = fm.hexfunc
1419 hexfunc = fm.hexfunc
1420
1420
1421 allheads = set(repo.heads())
1421 allheads = set(repo.heads())
1422 branches = []
1422 branches = []
1423 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1423 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1424 if selectedbranches is not None and tag not in selectedbranches:
1424 if selectedbranches is not None and tag not in selectedbranches:
1425 continue
1425 continue
1426 isactive = False
1426 isactive = False
1427 if not isclosed:
1427 if not isclosed:
1428 openheads = set(repo.branchmap().iteropen(heads))
1428 openheads = set(repo.branchmap().iteropen(heads))
1429 isactive = bool(openheads & allheads)
1429 isactive = bool(openheads & allheads)
1430 branches.append((tag, repo[tip], isactive, not isclosed))
1430 branches.append((tag, repo[tip], isactive, not isclosed))
1431 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1431 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1432
1432
1433 for tag, ctx, isactive, isopen in branches:
1433 for tag, ctx, isactive, isopen in branches:
1434 if active and not isactive:
1434 if active and not isactive:
1435 continue
1435 continue
1436 if isactive:
1436 if isactive:
1437 label = b'branches.active'
1437 label = b'branches.active'
1438 notice = b''
1438 notice = b''
1439 elif not isopen:
1439 elif not isopen:
1440 if not closed:
1440 if not closed:
1441 continue
1441 continue
1442 label = b'branches.closed'
1442 label = b'branches.closed'
1443 notice = _(b' (closed)')
1443 notice = _(b' (closed)')
1444 else:
1444 else:
1445 label = b'branches.inactive'
1445 label = b'branches.inactive'
1446 notice = _(b' (inactive)')
1446 notice = _(b' (inactive)')
1447 current = tag == repo.dirstate.branch()
1447 current = tag == repo.dirstate.branch()
1448 if current:
1448 if current:
1449 label = b'branches.current'
1449 label = b'branches.current'
1450
1450
1451 fm.startitem()
1451 fm.startitem()
1452 fm.write(b'branch', b'%s', tag, label=label)
1452 fm.write(b'branch', b'%s', tag, label=label)
1453 rev = ctx.rev()
1453 rev = ctx.rev()
1454 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1454 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1455 fmt = b' ' * padsize + b' %d:%s'
1455 fmt = b' ' * padsize + b' %d:%s'
1456 fm.condwrite(
1456 fm.condwrite(
1457 not ui.quiet,
1457 not ui.quiet,
1458 b'rev node',
1458 b'rev node',
1459 fmt,
1459 fmt,
1460 rev,
1460 rev,
1461 hexfunc(ctx.node()),
1461 hexfunc(ctx.node()),
1462 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1462 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1463 )
1463 )
1464 fm.context(ctx=ctx)
1464 fm.context(ctx=ctx)
1465 fm.data(active=isactive, closed=not isopen, current=current)
1465 fm.data(active=isactive, closed=not isopen, current=current)
1466 if not ui.quiet:
1466 if not ui.quiet:
1467 fm.plain(notice)
1467 fm.plain(notice)
1468 fm.plain(b'\n')
1468 fm.plain(b'\n')
1469 fm.end()
1469 fm.end()
1470
1470
1471
1471
1472 @command(
1472 @command(
1473 b'bundle',
1473 b'bundle',
1474 [
1474 [
1475 (
1475 (
1476 b'f',
1476 b'f',
1477 b'force',
1477 b'force',
1478 None,
1478 None,
1479 _(b'run even when the destination is unrelated'),
1479 _(b'run even when the destination is unrelated'),
1480 ),
1480 ),
1481 (
1481 (
1482 b'r',
1482 b'r',
1483 b'rev',
1483 b'rev',
1484 [],
1484 [],
1485 _(b'a changeset intended to be added to the destination'),
1485 _(b'a changeset intended to be added to the destination'),
1486 _(b'REV'),
1486 _(b'REV'),
1487 ),
1487 ),
1488 (
1488 (
1489 b'b',
1489 b'b',
1490 b'branch',
1490 b'branch',
1491 [],
1491 [],
1492 _(b'a specific branch you would like to bundle'),
1492 _(b'a specific branch you would like to bundle'),
1493 _(b'BRANCH'),
1493 _(b'BRANCH'),
1494 ),
1494 ),
1495 (
1495 (
1496 b'',
1496 b'',
1497 b'base',
1497 b'base',
1498 [],
1498 [],
1499 _(b'a base changeset assumed to be available at the destination'),
1499 _(b'a base changeset assumed to be available at the destination'),
1500 _(b'REV'),
1500 _(b'REV'),
1501 ),
1501 ),
1502 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1502 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1503 (
1503 (
1504 b't',
1504 b't',
1505 b'type',
1505 b'type',
1506 b'bzip2',
1506 b'bzip2',
1507 _(b'bundle compression type to use'),
1507 _(b'bundle compression type to use'),
1508 _(b'TYPE'),
1508 _(b'TYPE'),
1509 ),
1509 ),
1510 ]
1510 ]
1511 + remoteopts,
1511 + remoteopts,
1512 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1512 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1513 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1513 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1514 )
1514 )
1515 def bundle(ui, repo, fname, dest=None, **opts):
1515 def bundle(ui, repo, fname, dest=None, **opts):
1516 """create a bundle file
1516 """create a bundle file
1517
1517
1518 Generate a bundle file containing data to be transferred to another
1518 Generate a bundle file containing data to be transferred to another
1519 repository.
1519 repository.
1520
1520
1521 To create a bundle containing all changesets, use -a/--all
1521 To create a bundle containing all changesets, use -a/--all
1522 (or --base null). Otherwise, hg assumes the destination will have
1522 (or --base null). Otherwise, hg assumes the destination will have
1523 all the nodes you specify with --base parameters. Otherwise, hg
1523 all the nodes you specify with --base parameters. Otherwise, hg
1524 will assume the repository has all the nodes in destination, or
1524 will assume the repository has all the nodes in destination, or
1525 default-push/default if no destination is specified, where destination
1525 default-push/default if no destination is specified, where destination
1526 is the repository you provide through DEST option.
1526 is the repository you provide through DEST option.
1527
1527
1528 You can change bundle format with the -t/--type option. See
1528 You can change bundle format with the -t/--type option. See
1529 :hg:`help bundlespec` for documentation on this format. By default,
1529 :hg:`help bundlespec` for documentation on this format. By default,
1530 the most appropriate format is used and compression defaults to
1530 the most appropriate format is used and compression defaults to
1531 bzip2.
1531 bzip2.
1532
1532
1533 The bundle file can then be transferred using conventional means
1533 The bundle file can then be transferred using conventional means
1534 and applied to another repository with the unbundle or pull
1534 and applied to another repository with the unbundle or pull
1535 command. This is useful when direct push and pull are not
1535 command. This is useful when direct push and pull are not
1536 available or when exporting an entire repository is undesirable.
1536 available or when exporting an entire repository is undesirable.
1537
1537
1538 Applying bundles preserves all changeset contents including
1538 Applying bundles preserves all changeset contents including
1539 permissions, copy/rename information, and revision history.
1539 permissions, copy/rename information, and revision history.
1540
1540
1541 Returns 0 on success, 1 if no changes found.
1541 Returns 0 on success, 1 if no changes found.
1542 """
1542 """
1543 opts = pycompat.byteskwargs(opts)
1543 opts = pycompat.byteskwargs(opts)
1544 revs = None
1544 revs = None
1545 if b'rev' in opts:
1545 if b'rev' in opts:
1546 revstrings = opts[b'rev']
1546 revstrings = opts[b'rev']
1547 revs = scmutil.revrange(repo, revstrings)
1547 revs = scmutil.revrange(repo, revstrings)
1548 if revstrings and not revs:
1548 if revstrings and not revs:
1549 raise error.Abort(_(b'no commits to bundle'))
1549 raise error.Abort(_(b'no commits to bundle'))
1550
1550
1551 bundletype = opts.get(b'type', b'bzip2').lower()
1551 bundletype = opts.get(b'type', b'bzip2').lower()
1552 try:
1552 try:
1553 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1553 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1554 except error.UnsupportedBundleSpecification as e:
1554 except error.UnsupportedBundleSpecification as e:
1555 raise error.Abort(
1555 raise error.Abort(
1556 pycompat.bytestr(e),
1556 pycompat.bytestr(e),
1557 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1557 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1558 )
1558 )
1559 cgversion = bundlespec.contentopts[b"cg.version"]
1559 cgversion = bundlespec.contentopts[b"cg.version"]
1560
1560
1561 # Packed bundles are a pseudo bundle format for now.
1561 # Packed bundles are a pseudo bundle format for now.
1562 if cgversion == b's1':
1562 if cgversion == b's1':
1563 raise error.Abort(
1563 raise error.Abort(
1564 _(b'packed bundles cannot be produced by "hg bundle"'),
1564 _(b'packed bundles cannot be produced by "hg bundle"'),
1565 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1565 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1566 )
1566 )
1567
1567
1568 if opts.get(b'all'):
1568 if opts.get(b'all'):
1569 if dest:
1569 if dest:
1570 raise error.Abort(
1570 raise error.Abort(
1571 _(b"--all is incompatible with specifying a destination")
1571 _(b"--all is incompatible with specifying a destination")
1572 )
1572 )
1573 if opts.get(b'base'):
1573 if opts.get(b'base'):
1574 ui.warn(_(b"ignoring --base because --all was specified\n"))
1574 ui.warn(_(b"ignoring --base because --all was specified\n"))
1575 base = [nullrev]
1575 base = [nullrev]
1576 else:
1576 else:
1577 base = scmutil.revrange(repo, opts.get(b'base'))
1577 base = scmutil.revrange(repo, opts.get(b'base'))
1578 if cgversion not in changegroup.supportedoutgoingversions(repo):
1578 if cgversion not in changegroup.supportedoutgoingversions(repo):
1579 raise error.Abort(
1579 raise error.Abort(
1580 _(b"repository does not support bundle version %s") % cgversion
1580 _(b"repository does not support bundle version %s") % cgversion
1581 )
1581 )
1582
1582
1583 if base:
1583 if base:
1584 if dest:
1584 if dest:
1585 raise error.Abort(
1585 raise error.Abort(
1586 _(b"--base is incompatible with specifying a destination")
1586 _(b"--base is incompatible with specifying a destination")
1587 )
1587 )
1588 common = [repo[rev].node() for rev in base]
1588 common = [repo[rev].node() for rev in base]
1589 heads = [repo[r].node() for r in revs] if revs else None
1589 heads = [repo[r].node() for r in revs] if revs else None
1590 outgoing = discovery.outgoing(repo, common, heads)
1590 outgoing = discovery.outgoing(repo, common, heads)
1591 else:
1591 else:
1592 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1592 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1593 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1593 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1594 other = hg.peer(repo, opts, dest)
1594 other = hg.peer(repo, opts, dest)
1595 revs = [repo[r].hex() for r in revs]
1595 revs = [repo[r].hex() for r in revs]
1596 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1596 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1597 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1597 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1598 outgoing = discovery.findcommonoutgoing(
1598 outgoing = discovery.findcommonoutgoing(
1599 repo,
1599 repo,
1600 other,
1600 other,
1601 onlyheads=heads,
1601 onlyheads=heads,
1602 force=opts.get(b'force'),
1602 force=opts.get(b'force'),
1603 portable=True,
1603 portable=True,
1604 )
1604 )
1605
1605
1606 if not outgoing.missing:
1606 if not outgoing.missing:
1607 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1607 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1608 return 1
1608 return 1
1609
1609
1610 if cgversion == b'01': # bundle1
1610 if cgversion == b'01': # bundle1
1611 bversion = b'HG10' + bundlespec.wirecompression
1611 bversion = b'HG10' + bundlespec.wirecompression
1612 bcompression = None
1612 bcompression = None
1613 elif cgversion in (b'02', b'03'):
1613 elif cgversion in (b'02', b'03'):
1614 bversion = b'HG20'
1614 bversion = b'HG20'
1615 bcompression = bundlespec.wirecompression
1615 bcompression = bundlespec.wirecompression
1616 else:
1616 else:
1617 raise error.ProgrammingError(
1617 raise error.ProgrammingError(
1618 b'bundle: unexpected changegroup version %s' % cgversion
1618 b'bundle: unexpected changegroup version %s' % cgversion
1619 )
1619 )
1620
1620
1621 # TODO compression options should be derived from bundlespec parsing.
1621 # TODO compression options should be derived from bundlespec parsing.
1622 # This is a temporary hack to allow adjusting bundle compression
1622 # This is a temporary hack to allow adjusting bundle compression
1623 # level without a) formalizing the bundlespec changes to declare it
1623 # level without a) formalizing the bundlespec changes to declare it
1624 # b) introducing a command flag.
1624 # b) introducing a command flag.
1625 compopts = {}
1625 compopts = {}
1626 complevel = ui.configint(
1626 complevel = ui.configint(
1627 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1627 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1628 )
1628 )
1629 if complevel is None:
1629 if complevel is None:
1630 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1630 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1631 if complevel is not None:
1631 if complevel is not None:
1632 compopts[b'level'] = complevel
1632 compopts[b'level'] = complevel
1633
1633
1634 # Allow overriding the bundling of obsmarker in phases through
1634 # Allow overriding the bundling of obsmarker in phases through
1635 # configuration while we don't have a bundle version that include them
1635 # configuration while we don't have a bundle version that include them
1636 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1636 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1637 bundlespec.contentopts[b'obsolescence'] = True
1637 bundlespec.contentopts[b'obsolescence'] = True
1638 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1638 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1639 bundlespec.contentopts[b'phases'] = True
1639 bundlespec.contentopts[b'phases'] = True
1640
1640
1641 bundle2.writenewbundle(
1641 bundle2.writenewbundle(
1642 ui,
1642 ui,
1643 repo,
1643 repo,
1644 b'bundle',
1644 b'bundle',
1645 fname,
1645 fname,
1646 bversion,
1646 bversion,
1647 outgoing,
1647 outgoing,
1648 bundlespec.contentopts,
1648 bundlespec.contentopts,
1649 compression=bcompression,
1649 compression=bcompression,
1650 compopts=compopts,
1650 compopts=compopts,
1651 )
1651 )
1652
1652
1653
1653
1654 @command(
1654 @command(
1655 b'cat',
1655 b'cat',
1656 [
1656 [
1657 (
1657 (
1658 b'o',
1658 b'o',
1659 b'output',
1659 b'output',
1660 b'',
1660 b'',
1661 _(b'print output to file with formatted name'),
1661 _(b'print output to file with formatted name'),
1662 _(b'FORMAT'),
1662 _(b'FORMAT'),
1663 ),
1663 ),
1664 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1664 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1665 (b'', b'decode', None, _(b'apply any matching decode filter')),
1665 (b'', b'decode', None, _(b'apply any matching decode filter')),
1666 ]
1666 ]
1667 + walkopts
1667 + walkopts
1668 + formatteropts,
1668 + formatteropts,
1669 _(b'[OPTION]... FILE...'),
1669 _(b'[OPTION]... FILE...'),
1670 helpcategory=command.CATEGORY_FILE_CONTENTS,
1670 helpcategory=command.CATEGORY_FILE_CONTENTS,
1671 inferrepo=True,
1671 inferrepo=True,
1672 intents={INTENT_READONLY},
1672 intents={INTENT_READONLY},
1673 )
1673 )
1674 def cat(ui, repo, file1, *pats, **opts):
1674 def cat(ui, repo, file1, *pats, **opts):
1675 """output the current or given revision of files
1675 """output the current or given revision of files
1676
1676
1677 Print the specified files as they were at the given revision. If
1677 Print the specified files as they were at the given revision. If
1678 no revision is given, the parent of the working directory is used.
1678 no revision is given, the parent of the working directory is used.
1679
1679
1680 Output may be to a file, in which case the name of the file is
1680 Output may be to a file, in which case the name of the file is
1681 given using a template string. See :hg:`help templates`. In addition
1681 given using a template string. See :hg:`help templates`. In addition
1682 to the common template keywords, the following formatting rules are
1682 to the common template keywords, the following formatting rules are
1683 supported:
1683 supported:
1684
1684
1685 :``%%``: literal "%" character
1685 :``%%``: literal "%" character
1686 :``%s``: basename of file being printed
1686 :``%s``: basename of file being printed
1687 :``%d``: dirname of file being printed, or '.' if in repository root
1687 :``%d``: dirname of file being printed, or '.' if in repository root
1688 :``%p``: root-relative path name of file being printed
1688 :``%p``: root-relative path name of file being printed
1689 :``%H``: changeset hash (40 hexadecimal digits)
1689 :``%H``: changeset hash (40 hexadecimal digits)
1690 :``%R``: changeset revision number
1690 :``%R``: changeset revision number
1691 :``%h``: short-form changeset hash (12 hexadecimal digits)
1691 :``%h``: short-form changeset hash (12 hexadecimal digits)
1692 :``%r``: zero-padded changeset revision number
1692 :``%r``: zero-padded changeset revision number
1693 :``%b``: basename of the exporting repository
1693 :``%b``: basename of the exporting repository
1694 :``\\``: literal "\\" character
1694 :``\\``: literal "\\" character
1695
1695
1696 .. container:: verbose
1696 .. container:: verbose
1697
1697
1698 Template:
1698 Template:
1699
1699
1700 The following keywords are supported in addition to the common template
1700 The following keywords are supported in addition to the common template
1701 keywords and functions. See also :hg:`help templates`.
1701 keywords and functions. See also :hg:`help templates`.
1702
1702
1703 :data: String. File content.
1703 :data: String. File content.
1704 :path: String. Repository-absolute path of the file.
1704 :path: String. Repository-absolute path of the file.
1705
1705
1706 Returns 0 on success.
1706 Returns 0 on success.
1707 """
1707 """
1708 opts = pycompat.byteskwargs(opts)
1708 opts = pycompat.byteskwargs(opts)
1709 rev = opts.get(b'rev')
1709 rev = opts.get(b'rev')
1710 if rev:
1710 if rev:
1711 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1711 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1712 ctx = scmutil.revsingle(repo, rev)
1712 ctx = scmutil.revsingle(repo, rev)
1713 m = scmutil.match(ctx, (file1,) + pats, opts)
1713 m = scmutil.match(ctx, (file1,) + pats, opts)
1714 fntemplate = opts.pop(b'output', b'')
1714 fntemplate = opts.pop(b'output', b'')
1715 if cmdutil.isstdiofilename(fntemplate):
1715 if cmdutil.isstdiofilename(fntemplate):
1716 fntemplate = b''
1716 fntemplate = b''
1717
1717
1718 if fntemplate:
1718 if fntemplate:
1719 fm = formatter.nullformatter(ui, b'cat', opts)
1719 fm = formatter.nullformatter(ui, b'cat', opts)
1720 else:
1720 else:
1721 ui.pager(b'cat')
1721 ui.pager(b'cat')
1722 fm = ui.formatter(b'cat', opts)
1722 fm = ui.formatter(b'cat', opts)
1723 with fm:
1723 with fm:
1724 return cmdutil.cat(
1724 return cmdutil.cat(
1725 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1725 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1726 )
1726 )
1727
1727
1728
1728
1729 @command(
1729 @command(
1730 b'clone',
1730 b'clone',
1731 [
1731 [
1732 (
1732 (
1733 b'U',
1733 b'U',
1734 b'noupdate',
1734 b'noupdate',
1735 None,
1735 None,
1736 _(
1736 _(
1737 b'the clone will include an empty working '
1737 b'the clone will include an empty working '
1738 b'directory (only a repository)'
1738 b'directory (only a repository)'
1739 ),
1739 ),
1740 ),
1740 ),
1741 (
1741 (
1742 b'u',
1742 b'u',
1743 b'updaterev',
1743 b'updaterev',
1744 b'',
1744 b'',
1745 _(b'revision, tag, or branch to check out'),
1745 _(b'revision, tag, or branch to check out'),
1746 _(b'REV'),
1746 _(b'REV'),
1747 ),
1747 ),
1748 (
1748 (
1749 b'r',
1749 b'r',
1750 b'rev',
1750 b'rev',
1751 [],
1751 [],
1752 _(
1752 _(
1753 b'do not clone everything, but include this changeset'
1753 b'do not clone everything, but include this changeset'
1754 b' and its ancestors'
1754 b' and its ancestors'
1755 ),
1755 ),
1756 _(b'REV'),
1756 _(b'REV'),
1757 ),
1757 ),
1758 (
1758 (
1759 b'b',
1759 b'b',
1760 b'branch',
1760 b'branch',
1761 [],
1761 [],
1762 _(
1762 _(
1763 b'do not clone everything, but include this branch\'s'
1763 b'do not clone everything, but include this branch\'s'
1764 b' changesets and their ancestors'
1764 b' changesets and their ancestors'
1765 ),
1765 ),
1766 _(b'BRANCH'),
1766 _(b'BRANCH'),
1767 ),
1767 ),
1768 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1768 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1769 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1769 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1770 (b'', b'stream', None, _(b'clone with minimal data processing')),
1770 (b'', b'stream', None, _(b'clone with minimal data processing')),
1771 ]
1771 ]
1772 + remoteopts,
1772 + remoteopts,
1773 _(b'[OPTION]... SOURCE [DEST]'),
1773 _(b'[OPTION]... SOURCE [DEST]'),
1774 helpcategory=command.CATEGORY_REPO_CREATION,
1774 helpcategory=command.CATEGORY_REPO_CREATION,
1775 helpbasic=True,
1775 helpbasic=True,
1776 norepo=True,
1776 norepo=True,
1777 )
1777 )
1778 def clone(ui, source, dest=None, **opts):
1778 def clone(ui, source, dest=None, **opts):
1779 """make a copy of an existing repository
1779 """make a copy of an existing repository
1780
1780
1781 Create a copy of an existing repository in a new directory.
1781 Create a copy of an existing repository in a new directory.
1782
1782
1783 If no destination directory name is specified, it defaults to the
1783 If no destination directory name is specified, it defaults to the
1784 basename of the source.
1784 basename of the source.
1785
1785
1786 The location of the source is added to the new repository's
1786 The location of the source is added to the new repository's
1787 ``.hg/hgrc`` file, as the default to be used for future pulls.
1787 ``.hg/hgrc`` file, as the default to be used for future pulls.
1788
1788
1789 Only local paths and ``ssh://`` URLs are supported as
1789 Only local paths and ``ssh://`` URLs are supported as
1790 destinations. For ``ssh://`` destinations, no working directory or
1790 destinations. For ``ssh://`` destinations, no working directory or
1791 ``.hg/hgrc`` will be created on the remote side.
1791 ``.hg/hgrc`` will be created on the remote side.
1792
1792
1793 If the source repository has a bookmark called '@' set, that
1793 If the source repository has a bookmark called '@' set, that
1794 revision will be checked out in the new repository by default.
1794 revision will be checked out in the new repository by default.
1795
1795
1796 To check out a particular version, use -u/--update, or
1796 To check out a particular version, use -u/--update, or
1797 -U/--noupdate to create a clone with no working directory.
1797 -U/--noupdate to create a clone with no working directory.
1798
1798
1799 To pull only a subset of changesets, specify one or more revisions
1799 To pull only a subset of changesets, specify one or more revisions
1800 identifiers with -r/--rev or branches with -b/--branch. The
1800 identifiers with -r/--rev or branches with -b/--branch. The
1801 resulting clone will contain only the specified changesets and
1801 resulting clone will contain only the specified changesets and
1802 their ancestors. These options (or 'clone src#rev dest') imply
1802 their ancestors. These options (or 'clone src#rev dest') imply
1803 --pull, even for local source repositories.
1803 --pull, even for local source repositories.
1804
1804
1805 In normal clone mode, the remote normalizes repository data into a common
1805 In normal clone mode, the remote normalizes repository data into a common
1806 exchange format and the receiving end translates this data into its local
1806 exchange format and the receiving end translates this data into its local
1807 storage format. --stream activates a different clone mode that essentially
1807 storage format. --stream activates a different clone mode that essentially
1808 copies repository files from the remote with minimal data processing. This
1808 copies repository files from the remote with minimal data processing. This
1809 significantly reduces the CPU cost of a clone both remotely and locally.
1809 significantly reduces the CPU cost of a clone both remotely and locally.
1810 However, it often increases the transferred data size by 30-40%. This can
1810 However, it often increases the transferred data size by 30-40%. This can
1811 result in substantially faster clones where I/O throughput is plentiful,
1811 result in substantially faster clones where I/O throughput is plentiful,
1812 especially for larger repositories. A side-effect of --stream clones is
1812 especially for larger repositories. A side-effect of --stream clones is
1813 that storage settings and requirements on the remote are applied locally:
1813 that storage settings and requirements on the remote are applied locally:
1814 a modern client may inherit legacy or inefficient storage used by the
1814 a modern client may inherit legacy or inefficient storage used by the
1815 remote or a legacy Mercurial client may not be able to clone from a
1815 remote or a legacy Mercurial client may not be able to clone from a
1816 modern Mercurial remote.
1816 modern Mercurial remote.
1817
1817
1818 .. note::
1818 .. note::
1819
1819
1820 Specifying a tag will include the tagged changeset but not the
1820 Specifying a tag will include the tagged changeset but not the
1821 changeset containing the tag.
1821 changeset containing the tag.
1822
1822
1823 .. container:: verbose
1823 .. container:: verbose
1824
1824
1825 For efficiency, hardlinks are used for cloning whenever the
1825 For efficiency, hardlinks are used for cloning whenever the
1826 source and destination are on the same filesystem (note this
1826 source and destination are on the same filesystem (note this
1827 applies only to the repository data, not to the working
1827 applies only to the repository data, not to the working
1828 directory). Some filesystems, such as AFS, implement hardlinking
1828 directory). Some filesystems, such as AFS, implement hardlinking
1829 incorrectly, but do not report errors. In these cases, use the
1829 incorrectly, but do not report errors. In these cases, use the
1830 --pull option to avoid hardlinking.
1830 --pull option to avoid hardlinking.
1831
1831
1832 Mercurial will update the working directory to the first applicable
1832 Mercurial will update the working directory to the first applicable
1833 revision from this list:
1833 revision from this list:
1834
1834
1835 a) null if -U or the source repository has no changesets
1835 a) null if -U or the source repository has no changesets
1836 b) if -u . and the source repository is local, the first parent of
1836 b) if -u . and the source repository is local, the first parent of
1837 the source repository's working directory
1837 the source repository's working directory
1838 c) the changeset specified with -u (if a branch name, this means the
1838 c) the changeset specified with -u (if a branch name, this means the
1839 latest head of that branch)
1839 latest head of that branch)
1840 d) the changeset specified with -r
1840 d) the changeset specified with -r
1841 e) the tipmost head specified with -b
1841 e) the tipmost head specified with -b
1842 f) the tipmost head specified with the url#branch source syntax
1842 f) the tipmost head specified with the url#branch source syntax
1843 g) the revision marked with the '@' bookmark, if present
1843 g) the revision marked with the '@' bookmark, if present
1844 h) the tipmost head of the default branch
1844 h) the tipmost head of the default branch
1845 i) tip
1845 i) tip
1846
1846
1847 When cloning from servers that support it, Mercurial may fetch
1847 When cloning from servers that support it, Mercurial may fetch
1848 pre-generated data from a server-advertised URL or inline from the
1848 pre-generated data from a server-advertised URL or inline from the
1849 same stream. When this is done, hooks operating on incoming changesets
1849 same stream. When this is done, hooks operating on incoming changesets
1850 and changegroups may fire more than once, once for each pre-generated
1850 and changegroups may fire more than once, once for each pre-generated
1851 bundle and as well as for any additional remaining data. In addition,
1851 bundle and as well as for any additional remaining data. In addition,
1852 if an error occurs, the repository may be rolled back to a partial
1852 if an error occurs, the repository may be rolled back to a partial
1853 clone. This behavior may change in future releases.
1853 clone. This behavior may change in future releases.
1854 See :hg:`help -e clonebundles` for more.
1854 See :hg:`help -e clonebundles` for more.
1855
1855
1856 Examples:
1856 Examples:
1857
1857
1858 - clone a remote repository to a new directory named hg/::
1858 - clone a remote repository to a new directory named hg/::
1859
1859
1860 hg clone https://www.mercurial-scm.org/repo/hg/
1860 hg clone https://www.mercurial-scm.org/repo/hg/
1861
1861
1862 - create a lightweight local clone::
1862 - create a lightweight local clone::
1863
1863
1864 hg clone project/ project-feature/
1864 hg clone project/ project-feature/
1865
1865
1866 - clone from an absolute path on an ssh server (note double-slash)::
1866 - clone from an absolute path on an ssh server (note double-slash)::
1867
1867
1868 hg clone ssh://user@server//home/projects/alpha/
1868 hg clone ssh://user@server//home/projects/alpha/
1869
1869
1870 - do a streaming clone while checking out a specified version::
1870 - do a streaming clone while checking out a specified version::
1871
1871
1872 hg clone --stream http://server/repo -u 1.5
1872 hg clone --stream http://server/repo -u 1.5
1873
1873
1874 - create a repository without changesets after a particular revision::
1874 - create a repository without changesets after a particular revision::
1875
1875
1876 hg clone -r 04e544 experimental/ good/
1876 hg clone -r 04e544 experimental/ good/
1877
1877
1878 - clone (and track) a particular named branch::
1878 - clone (and track) a particular named branch::
1879
1879
1880 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1880 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1881
1881
1882 See :hg:`help urls` for details on specifying URLs.
1882 See :hg:`help urls` for details on specifying URLs.
1883
1883
1884 Returns 0 on success.
1884 Returns 0 on success.
1885 """
1885 """
1886 opts = pycompat.byteskwargs(opts)
1886 opts = pycompat.byteskwargs(opts)
1887 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1887 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1888
1888
1889 # --include/--exclude can come from narrow or sparse.
1889 # --include/--exclude can come from narrow or sparse.
1890 includepats, excludepats = None, None
1890 includepats, excludepats = None, None
1891
1891
1892 # hg.clone() differentiates between None and an empty set. So make sure
1892 # hg.clone() differentiates between None and an empty set. So make sure
1893 # patterns are sets if narrow is requested without patterns.
1893 # patterns are sets if narrow is requested without patterns.
1894 if opts.get(b'narrow'):
1894 if opts.get(b'narrow'):
1895 includepats = set()
1895 includepats = set()
1896 excludepats = set()
1896 excludepats = set()
1897
1897
1898 if opts.get(b'include'):
1898 if opts.get(b'include'):
1899 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1899 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1900 if opts.get(b'exclude'):
1900 if opts.get(b'exclude'):
1901 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1901 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1902
1902
1903 r = hg.clone(
1903 r = hg.clone(
1904 ui,
1904 ui,
1905 opts,
1905 opts,
1906 source,
1906 source,
1907 dest,
1907 dest,
1908 pull=opts.get(b'pull'),
1908 pull=opts.get(b'pull'),
1909 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1909 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1910 revs=opts.get(b'rev'),
1910 revs=opts.get(b'rev'),
1911 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1911 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1912 branch=opts.get(b'branch'),
1912 branch=opts.get(b'branch'),
1913 shareopts=opts.get(b'shareopts'),
1913 shareopts=opts.get(b'shareopts'),
1914 storeincludepats=includepats,
1914 storeincludepats=includepats,
1915 storeexcludepats=excludepats,
1915 storeexcludepats=excludepats,
1916 depth=opts.get(b'depth') or None,
1916 depth=opts.get(b'depth') or None,
1917 )
1917 )
1918
1918
1919 return r is None
1919 return r is None
1920
1920
1921
1921
1922 @command(
1922 @command(
1923 b'commit|ci',
1923 b'commit|ci',
1924 [
1924 [
1925 (
1925 (
1926 b'A',
1926 b'A',
1927 b'addremove',
1927 b'addremove',
1928 None,
1928 None,
1929 _(b'mark new/missing files as added/removed before committing'),
1929 _(b'mark new/missing files as added/removed before committing'),
1930 ),
1930 ),
1931 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1931 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1932 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1932 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1933 (b's', b'secret', None, _(b'use the secret phase for committing')),
1933 (b's', b'secret', None, _(b'use the secret phase for committing')),
1934 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1934 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1935 (
1935 (
1936 b'',
1936 b'',
1937 b'force-close-branch',
1937 b'force-close-branch',
1938 None,
1938 None,
1939 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1939 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1940 ),
1940 ),
1941 (b'i', b'interactive', None, _(b'use interactive mode')),
1941 (b'i', b'interactive', None, _(b'use interactive mode')),
1942 ]
1942 ]
1943 + walkopts
1943 + walkopts
1944 + commitopts
1944 + commitopts
1945 + commitopts2
1945 + commitopts2
1946 + subrepoopts,
1946 + subrepoopts,
1947 _(b'[OPTION]... [FILE]...'),
1947 _(b'[OPTION]... [FILE]...'),
1948 helpcategory=command.CATEGORY_COMMITTING,
1948 helpcategory=command.CATEGORY_COMMITTING,
1949 helpbasic=True,
1949 helpbasic=True,
1950 inferrepo=True,
1950 inferrepo=True,
1951 )
1951 )
1952 def commit(ui, repo, *pats, **opts):
1952 def commit(ui, repo, *pats, **opts):
1953 """commit the specified files or all outstanding changes
1953 """commit the specified files or all outstanding changes
1954
1954
1955 Commit changes to the given files into the repository. Unlike a
1955 Commit changes to the given files into the repository. Unlike a
1956 centralized SCM, this operation is a local operation. See
1956 centralized SCM, this operation is a local operation. See
1957 :hg:`push` for a way to actively distribute your changes.
1957 :hg:`push` for a way to actively distribute your changes.
1958
1958
1959 If a list of files is omitted, all changes reported by :hg:`status`
1959 If a list of files is omitted, all changes reported by :hg:`status`
1960 will be committed.
1960 will be committed.
1961
1961
1962 If you are committing the result of a merge, do not provide any
1962 If you are committing the result of a merge, do not provide any
1963 filenames or -I/-X filters.
1963 filenames or -I/-X filters.
1964
1964
1965 If no commit message is specified, Mercurial starts your
1965 If no commit message is specified, Mercurial starts your
1966 configured editor where you can enter a message. In case your
1966 configured editor where you can enter a message. In case your
1967 commit fails, you will find a backup of your message in
1967 commit fails, you will find a backup of your message in
1968 ``.hg/last-message.txt``.
1968 ``.hg/last-message.txt``.
1969
1969
1970 The --close-branch flag can be used to mark the current branch
1970 The --close-branch flag can be used to mark the current branch
1971 head closed. When all heads of a branch are closed, the branch
1971 head closed. When all heads of a branch are closed, the branch
1972 will be considered closed and no longer listed.
1972 will be considered closed and no longer listed.
1973
1973
1974 The --amend flag can be used to amend the parent of the
1974 The --amend flag can be used to amend the parent of the
1975 working directory with a new commit that contains the changes
1975 working directory with a new commit that contains the changes
1976 in the parent in addition to those currently reported by :hg:`status`,
1976 in the parent in addition to those currently reported by :hg:`status`,
1977 if there are any. The old commit is stored in a backup bundle in
1977 if there are any. The old commit is stored in a backup bundle in
1978 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1978 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1979 on how to restore it).
1979 on how to restore it).
1980
1980
1981 Message, user and date are taken from the amended commit unless
1981 Message, user and date are taken from the amended commit unless
1982 specified. When a message isn't specified on the command line,
1982 specified. When a message isn't specified on the command line,
1983 the editor will open with the message of the amended commit.
1983 the editor will open with the message of the amended commit.
1984
1984
1985 It is not possible to amend public changesets (see :hg:`help phases`)
1985 It is not possible to amend public changesets (see :hg:`help phases`)
1986 or changesets that have children.
1986 or changesets that have children.
1987
1987
1988 See :hg:`help dates` for a list of formats valid for -d/--date.
1988 See :hg:`help dates` for a list of formats valid for -d/--date.
1989
1989
1990 Returns 0 on success, 1 if nothing changed.
1990 Returns 0 on success, 1 if nothing changed.
1991
1991
1992 .. container:: verbose
1992 .. container:: verbose
1993
1993
1994 Examples:
1994 Examples:
1995
1995
1996 - commit all files ending in .py::
1996 - commit all files ending in .py::
1997
1997
1998 hg commit --include "set:**.py"
1998 hg commit --include "set:**.py"
1999
1999
2000 - commit all non-binary files::
2000 - commit all non-binary files::
2001
2001
2002 hg commit --exclude "set:binary()"
2002 hg commit --exclude "set:binary()"
2003
2003
2004 - amend the current commit and set the date to now::
2004 - amend the current commit and set the date to now::
2005
2005
2006 hg commit --amend --date now
2006 hg commit --amend --date now
2007 """
2007 """
2008 with repo.wlock(), repo.lock():
2008 with repo.wlock(), repo.lock():
2009 return _docommit(ui, repo, *pats, **opts)
2009 return _docommit(ui, repo, *pats, **opts)
2010
2010
2011
2011
2012 def _docommit(ui, repo, *pats, **opts):
2012 def _docommit(ui, repo, *pats, **opts):
2013 if opts.get('interactive'):
2013 if opts.get('interactive'):
2014 opts.pop('interactive')
2014 opts.pop('interactive')
2015 ret = cmdutil.dorecord(
2015 ret = cmdutil.dorecord(
2016 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2016 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2017 )
2017 )
2018 # ret can be 0 (no changes to record) or the value returned by
2018 # ret can be 0 (no changes to record) or the value returned by
2019 # commit(), 1 if nothing changed or None on success.
2019 # commit(), 1 if nothing changed or None on success.
2020 return 1 if ret == 0 else ret
2020 return 1 if ret == 0 else ret
2021
2021
2022 opts = pycompat.byteskwargs(opts)
2022 opts = pycompat.byteskwargs(opts)
2023 if opts.get(b'subrepos'):
2023 if opts.get(b'subrepos'):
2024 if opts.get(b'amend'):
2024 if opts.get(b'amend'):
2025 raise error.Abort(_(b'cannot amend with --subrepos'))
2025 raise error.Abort(_(b'cannot amend with --subrepos'))
2026 # Let --subrepos on the command line override config setting.
2026 # Let --subrepos on the command line override config setting.
2027 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2027 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2028
2028
2029 cmdutil.checkunfinished(repo, commit=True)
2029 cmdutil.checkunfinished(repo, commit=True)
2030
2030
2031 branch = repo[None].branch()
2031 branch = repo[None].branch()
2032 bheads = repo.branchheads(branch)
2032 bheads = repo.branchheads(branch)
2033
2033
2034 extra = {}
2034 extra = {}
2035 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2035 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2036 extra[b'close'] = b'1'
2036 extra[b'close'] = b'1'
2037
2037
2038 if repo[b'.'].closesbranch():
2038 if repo[b'.'].closesbranch():
2039 raise error.Abort(
2039 raise error.Abort(
2040 _(b'current revision is already a branch closing head')
2040 _(b'current revision is already a branch closing head')
2041 )
2041 )
2042 elif not bheads:
2042 elif not bheads:
2043 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2043 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2044 elif (
2044 elif (
2045 branch == repo[b'.'].branch()
2045 branch == repo[b'.'].branch()
2046 and repo[b'.'].node() not in bheads
2046 and repo[b'.'].node() not in bheads
2047 and not opts.get(b'force_close_branch')
2047 and not opts.get(b'force_close_branch')
2048 ):
2048 ):
2049 hint = _(
2049 hint = _(
2050 b'use --force-close-branch to close branch from a non-head'
2050 b'use --force-close-branch to close branch from a non-head'
2051 b' changeset'
2051 b' changeset'
2052 )
2052 )
2053 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2053 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2054 elif opts.get(b'amend'):
2054 elif opts.get(b'amend'):
2055 if (
2055 if (
2056 repo[b'.'].p1().branch() != branch
2056 repo[b'.'].p1().branch() != branch
2057 and repo[b'.'].p2().branch() != branch
2057 and repo[b'.'].p2().branch() != branch
2058 ):
2058 ):
2059 raise error.Abort(_(b'can only close branch heads'))
2059 raise error.Abort(_(b'can only close branch heads'))
2060
2060
2061 if opts.get(b'amend'):
2061 if opts.get(b'amend'):
2062 if ui.configbool(b'ui', b'commitsubrepos'):
2062 if ui.configbool(b'ui', b'commitsubrepos'):
2063 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2063 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2064
2064
2065 old = repo[b'.']
2065 old = repo[b'.']
2066 rewriteutil.precheck(repo, [old.rev()], b'amend')
2066 rewriteutil.precheck(repo, [old.rev()], b'amend')
2067
2067
2068 # Currently histedit gets confused if an amend happens while histedit
2068 # Currently histedit gets confused if an amend happens while histedit
2069 # is in progress. Since we have a checkunfinished command, we are
2069 # is in progress. Since we have a checkunfinished command, we are
2070 # temporarily honoring it.
2070 # temporarily honoring it.
2071 #
2071 #
2072 # Note: eventually this guard will be removed. Please do not expect
2072 # Note: eventually this guard will be removed. Please do not expect
2073 # this behavior to remain.
2073 # this behavior to remain.
2074 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2074 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2075 cmdutil.checkunfinished(repo)
2075 cmdutil.checkunfinished(repo)
2076
2076
2077 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2077 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2078 if node == old.node():
2078 if node == old.node():
2079 ui.status(_(b"nothing changed\n"))
2079 ui.status(_(b"nothing changed\n"))
2080 return 1
2080 return 1
2081 else:
2081 else:
2082
2082
2083 def commitfunc(ui, repo, message, match, opts):
2083 def commitfunc(ui, repo, message, match, opts):
2084 overrides = {}
2084 overrides = {}
2085 if opts.get(b'secret'):
2085 if opts.get(b'secret'):
2086 overrides[(b'phases', b'new-commit')] = b'secret'
2086 overrides[(b'phases', b'new-commit')] = b'secret'
2087
2087
2088 baseui = repo.baseui
2088 baseui = repo.baseui
2089 with baseui.configoverride(overrides, b'commit'):
2089 with baseui.configoverride(overrides, b'commit'):
2090 with ui.configoverride(overrides, b'commit'):
2090 with ui.configoverride(overrides, b'commit'):
2091 editform = cmdutil.mergeeditform(
2091 editform = cmdutil.mergeeditform(
2092 repo[None], b'commit.normal'
2092 repo[None], b'commit.normal'
2093 )
2093 )
2094 editor = cmdutil.getcommiteditor(
2094 editor = cmdutil.getcommiteditor(
2095 editform=editform, **pycompat.strkwargs(opts)
2095 editform=editform, **pycompat.strkwargs(opts)
2096 )
2096 )
2097 return repo.commit(
2097 return repo.commit(
2098 message,
2098 message,
2099 opts.get(b'user'),
2099 opts.get(b'user'),
2100 opts.get(b'date'),
2100 opts.get(b'date'),
2101 match,
2101 match,
2102 editor=editor,
2102 editor=editor,
2103 extra=extra,
2103 extra=extra,
2104 )
2104 )
2105
2105
2106 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2106 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2107
2107
2108 if not node:
2108 if not node:
2109 stat = cmdutil.postcommitstatus(repo, pats, opts)
2109 stat = cmdutil.postcommitstatus(repo, pats, opts)
2110 if stat.deleted:
2110 if stat.deleted:
2111 ui.status(
2111 ui.status(
2112 _(
2112 _(
2113 b"nothing changed (%d missing files, see "
2113 b"nothing changed (%d missing files, see "
2114 b"'hg status')\n"
2114 b"'hg status')\n"
2115 )
2115 )
2116 % len(stat.deleted)
2116 % len(stat.deleted)
2117 )
2117 )
2118 else:
2118 else:
2119 ui.status(_(b"nothing changed\n"))
2119 ui.status(_(b"nothing changed\n"))
2120 return 1
2120 return 1
2121
2121
2122 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2122 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2123
2123
2124 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2124 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2125 status(
2125 status(
2126 ui,
2126 ui,
2127 repo,
2127 repo,
2128 modified=True,
2128 modified=True,
2129 added=True,
2129 added=True,
2130 removed=True,
2130 removed=True,
2131 deleted=True,
2131 deleted=True,
2132 unknown=True,
2132 unknown=True,
2133 subrepos=opts.get(b'subrepos'),
2133 subrepos=opts.get(b'subrepos'),
2134 )
2134 )
2135
2135
2136
2136
2137 @command(
2137 @command(
2138 b'config|showconfig|debugconfig',
2138 b'config|showconfig|debugconfig',
2139 [
2139 [
2140 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2140 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2141 (b'e', b'edit', None, _(b'edit user config')),
2141 (b'e', b'edit', None, _(b'edit user config')),
2142 (b'l', b'local', None, _(b'edit repository config')),
2142 (b'l', b'local', None, _(b'edit repository config')),
2143 (b'g', b'global', None, _(b'edit global config')),
2143 (b'g', b'global', None, _(b'edit global config')),
2144 ]
2144 ]
2145 + formatteropts,
2145 + formatteropts,
2146 _(b'[-u] [NAME]...'),
2146 _(b'[-u] [NAME]...'),
2147 helpcategory=command.CATEGORY_HELP,
2147 helpcategory=command.CATEGORY_HELP,
2148 optionalrepo=True,
2148 optionalrepo=True,
2149 intents={INTENT_READONLY},
2149 intents={INTENT_READONLY},
2150 )
2150 )
2151 def config(ui, repo, *values, **opts):
2151 def config(ui, repo, *values, **opts):
2152 """show combined config settings from all hgrc files
2152 """show combined config settings from all hgrc files
2153
2153
2154 With no arguments, print names and values of all config items.
2154 With no arguments, print names and values of all config items.
2155
2155
2156 With one argument of the form section.name, print just the value
2156 With one argument of the form section.name, print just the value
2157 of that config item.
2157 of that config item.
2158
2158
2159 With multiple arguments, print names and values of all config
2159 With multiple arguments, print names and values of all config
2160 items with matching section names or section.names.
2160 items with matching section names or section.names.
2161
2161
2162 With --edit, start an editor on the user-level config file. With
2162 With --edit, start an editor on the user-level config file. With
2163 --global, edit the system-wide config file. With --local, edit the
2163 --global, edit the system-wide config file. With --local, edit the
2164 repository-level config file.
2164 repository-level config file.
2165
2165
2166 With --debug, the source (filename and line number) is printed
2166 With --debug, the source (filename and line number) is printed
2167 for each config item.
2167 for each config item.
2168
2168
2169 See :hg:`help config` for more information about config files.
2169 See :hg:`help config` for more information about config files.
2170
2170
2171 .. container:: verbose
2171 .. container:: verbose
2172
2172
2173 Template:
2173 Template:
2174
2174
2175 The following keywords are supported. See also :hg:`help templates`.
2175 The following keywords are supported. See also :hg:`help templates`.
2176
2176
2177 :name: String. Config name.
2177 :name: String. Config name.
2178 :source: String. Filename and line number where the item is defined.
2178 :source: String. Filename and line number where the item is defined.
2179 :value: String. Config value.
2179 :value: String. Config value.
2180
2180
2181 Returns 0 on success, 1 if NAME does not exist.
2181 Returns 0 on success, 1 if NAME does not exist.
2182
2182
2183 """
2183 """
2184
2184
2185 opts = pycompat.byteskwargs(opts)
2185 opts = pycompat.byteskwargs(opts)
2186 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2186 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2187 if opts.get(b'local') and opts.get(b'global'):
2187 if opts.get(b'local') and opts.get(b'global'):
2188 raise error.Abort(_(b"can't use --local and --global together"))
2188 raise error.Abort(_(b"can't use --local and --global together"))
2189
2189
2190 if opts.get(b'local'):
2190 if opts.get(b'local'):
2191 if not repo:
2191 if not repo:
2192 raise error.Abort(_(b"can't use --local outside a repository"))
2192 raise error.Abort(_(b"can't use --local outside a repository"))
2193 paths = [repo.vfs.join(b'hgrc')]
2193 paths = [repo.vfs.join(b'hgrc')]
2194 elif opts.get(b'global'):
2194 elif opts.get(b'global'):
2195 paths = rcutil.systemrcpath()
2195 paths = rcutil.systemrcpath()
2196 else:
2196 else:
2197 paths = rcutil.userrcpath()
2197 paths = rcutil.userrcpath()
2198
2198
2199 for f in paths:
2199 for f in paths:
2200 if os.path.exists(f):
2200 if os.path.exists(f):
2201 break
2201 break
2202 else:
2202 else:
2203 if opts.get(b'global'):
2203 if opts.get(b'global'):
2204 samplehgrc = uimod.samplehgrcs[b'global']
2204 samplehgrc = uimod.samplehgrcs[b'global']
2205 elif opts.get(b'local'):
2205 elif opts.get(b'local'):
2206 samplehgrc = uimod.samplehgrcs[b'local']
2206 samplehgrc = uimod.samplehgrcs[b'local']
2207 else:
2207 else:
2208 samplehgrc = uimod.samplehgrcs[b'user']
2208 samplehgrc = uimod.samplehgrcs[b'user']
2209
2209
2210 f = paths[0]
2210 f = paths[0]
2211 fp = open(f, b"wb")
2211 fp = open(f, b"wb")
2212 fp.write(util.tonativeeol(samplehgrc))
2212 fp.write(util.tonativeeol(samplehgrc))
2213 fp.close()
2213 fp.close()
2214
2214
2215 editor = ui.geteditor()
2215 editor = ui.geteditor()
2216 ui.system(
2216 ui.system(
2217 b"%s \"%s\"" % (editor, f),
2217 b"%s \"%s\"" % (editor, f),
2218 onerr=error.Abort,
2218 onerr=error.Abort,
2219 errprefix=_(b"edit failed"),
2219 errprefix=_(b"edit failed"),
2220 blockedtag=b'config_edit',
2220 blockedtag=b'config_edit',
2221 )
2221 )
2222 return
2222 return
2223 ui.pager(b'config')
2223 ui.pager(b'config')
2224 fm = ui.formatter(b'config', opts)
2224 fm = ui.formatter(b'config', opts)
2225 for t, f in rcutil.rccomponents():
2225 for t, f in rcutil.rccomponents():
2226 if t == b'path':
2226 if t == b'path':
2227 ui.debug(b'read config from: %s\n' % f)
2227 ui.debug(b'read config from: %s\n' % f)
2228 elif t == b'resource':
2228 elif t == b'resource':
2229 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2229 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2230 elif t == b'items':
2230 elif t == b'items':
2231 # Don't print anything for 'items'.
2231 # Don't print anything for 'items'.
2232 pass
2232 pass
2233 else:
2233 else:
2234 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2234 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2235 untrusted = bool(opts.get(b'untrusted'))
2235 untrusted = bool(opts.get(b'untrusted'))
2236
2236
2237 selsections = selentries = []
2237 selsections = selentries = []
2238 if values:
2238 if values:
2239 selsections = [v for v in values if b'.' not in v]
2239 selsections = [v for v in values if b'.' not in v]
2240 selentries = [v for v in values if b'.' in v]
2240 selentries = [v for v in values if b'.' in v]
2241 uniquesel = len(selentries) == 1 and not selsections
2241 uniquesel = len(selentries) == 1 and not selsections
2242 selsections = set(selsections)
2242 selsections = set(selsections)
2243 selentries = set(selentries)
2243 selentries = set(selentries)
2244
2244
2245 matched = False
2245 matched = False
2246 for section, name, value in ui.walkconfig(untrusted=untrusted):
2246 for section, name, value in ui.walkconfig(untrusted=untrusted):
2247 source = ui.configsource(section, name, untrusted)
2247 source = ui.configsource(section, name, untrusted)
2248 value = pycompat.bytestr(value)
2248 value = pycompat.bytestr(value)
2249 defaultvalue = ui.configdefault(section, name)
2249 defaultvalue = ui.configdefault(section, name)
2250 if fm.isplain():
2250 if fm.isplain():
2251 source = source or b'none'
2251 source = source or b'none'
2252 value = value.replace(b'\n', b'\\n')
2252 value = value.replace(b'\n', b'\\n')
2253 entryname = section + b'.' + name
2253 entryname = section + b'.' + name
2254 if values and not (section in selsections or entryname in selentries):
2254 if values and not (section in selsections or entryname in selentries):
2255 continue
2255 continue
2256 fm.startitem()
2256 fm.startitem()
2257 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2257 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2258 if uniquesel:
2258 if uniquesel:
2259 fm.data(name=entryname)
2259 fm.data(name=entryname)
2260 fm.write(b'value', b'%s\n', value)
2260 fm.write(b'value', b'%s\n', value)
2261 else:
2261 else:
2262 fm.write(b'name value', b'%s=%s\n', entryname, value)
2262 fm.write(b'name value', b'%s=%s\n', entryname, value)
2263 if formatter.isprintable(defaultvalue):
2263 if formatter.isprintable(defaultvalue):
2264 fm.data(defaultvalue=defaultvalue)
2264 fm.data(defaultvalue=defaultvalue)
2265 elif isinstance(defaultvalue, list) and all(
2265 elif isinstance(defaultvalue, list) and all(
2266 formatter.isprintable(e) for e in defaultvalue
2266 formatter.isprintable(e) for e in defaultvalue
2267 ):
2267 ):
2268 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2268 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2269 # TODO: no idea how to process unsupported defaultvalue types
2269 # TODO: no idea how to process unsupported defaultvalue types
2270 matched = True
2270 matched = True
2271 fm.end()
2271 fm.end()
2272 if matched:
2272 if matched:
2273 return 0
2273 return 0
2274 return 1
2274 return 1
2275
2275
2276
2276
2277 @command(
2277 @command(
2278 b'continue',
2278 b'continue',
2279 dryrunopts,
2279 dryrunopts,
2280 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2280 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2281 helpbasic=True,
2281 helpbasic=True,
2282 )
2282 )
2283 def continuecmd(ui, repo, **opts):
2283 def continuecmd(ui, repo, **opts):
2284 """resumes an interrupted operation (EXPERIMENTAL)
2284 """resumes an interrupted operation (EXPERIMENTAL)
2285
2285
2286 Finishes a multistep operation like graft, histedit, rebase, merge,
2286 Finishes a multistep operation like graft, histedit, rebase, merge,
2287 and unshelve if they are in an interrupted state.
2287 and unshelve if they are in an interrupted state.
2288
2288
2289 use --dry-run/-n to dry run the command.
2289 use --dry-run/-n to dry run the command.
2290 """
2290 """
2291 dryrun = opts.get('dry_run')
2291 dryrun = opts.get('dry_run')
2292 contstate = cmdutil.getunfinishedstate(repo)
2292 contstate = cmdutil.getunfinishedstate(repo)
2293 if not contstate:
2293 if not contstate:
2294 raise error.Abort(_(b'no operation in progress'))
2294 raise error.Abort(_(b'no operation in progress'))
2295 if not contstate.continuefunc:
2295 if not contstate.continuefunc:
2296 raise error.Abort(
2296 raise error.Abort(
2297 (
2297 (
2298 _(b"%s in progress but does not support 'hg continue'")
2298 _(b"%s in progress but does not support 'hg continue'")
2299 % (contstate._opname)
2299 % (contstate._opname)
2300 ),
2300 ),
2301 hint=contstate.continuemsg(),
2301 hint=contstate.continuemsg(),
2302 )
2302 )
2303 if dryrun:
2303 if dryrun:
2304 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2304 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2305 return
2305 return
2306 return contstate.continuefunc(ui, repo)
2306 return contstate.continuefunc(ui, repo)
2307
2307
2308
2308
2309 @command(
2309 @command(
2310 b'copy|cp',
2310 b'copy|cp',
2311 [
2311 [
2312 (b'', b'forget', None, _(b'unmark a file as copied')),
2312 (b'', b'forget', None, _(b'unmark a file as copied')),
2313 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2313 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2314 (
2314 (
2315 b'',
2315 b'',
2316 b'at-rev',
2316 b'at-rev',
2317 b'',
2317 b'',
2318 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2318 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2319 _(b'REV'),
2319 _(b'REV'),
2320 ),
2320 ),
2321 (
2321 (
2322 b'f',
2322 b'f',
2323 b'force',
2323 b'force',
2324 None,
2324 None,
2325 _(b'forcibly copy over an existing managed file'),
2325 _(b'forcibly copy over an existing managed file'),
2326 ),
2326 ),
2327 ]
2327 ]
2328 + walkopts
2328 + walkopts
2329 + dryrunopts,
2329 + dryrunopts,
2330 _(b'[OPTION]... SOURCE... DEST'),
2330 _(b'[OPTION]... SOURCE... DEST'),
2331 helpcategory=command.CATEGORY_FILE_CONTENTS,
2331 helpcategory=command.CATEGORY_FILE_CONTENTS,
2332 )
2332 )
2333 def copy(ui, repo, *pats, **opts):
2333 def copy(ui, repo, *pats, **opts):
2334 """mark files as copied for the next commit
2334 """mark files as copied for the next commit
2335
2335
2336 Mark dest as having copies of source files. If dest is a
2336 Mark dest as having copies of source files. If dest is a
2337 directory, copies are put in that directory. If dest is a file,
2337 directory, copies are put in that directory. If dest is a file,
2338 the source must be a single file.
2338 the source must be a single file.
2339
2339
2340 By default, this command copies the contents of files as they
2340 By default, this command copies the contents of files as they
2341 exist in the working directory. If invoked with -A/--after, the
2341 exist in the working directory. If invoked with -A/--after, the
2342 operation is recorded, but no copying is performed.
2342 operation is recorded, but no copying is performed.
2343
2343
2344 To undo marking a file as copied, use --forget. With that option,
2344 To undo marking a file as copied, use --forget. With that option,
2345 all given (positional) arguments are unmarked as copies. The destination
2345 all given (positional) arguments are unmarked as copies. The destination
2346 file(s) will be left in place (still tracked).
2346 file(s) will be left in place (still tracked).
2347
2347
2348 This command takes effect with the next commit by default.
2348 This command takes effect with the next commit by default.
2349
2349
2350 Returns 0 on success, 1 if errors are encountered.
2350 Returns 0 on success, 1 if errors are encountered.
2351 """
2351 """
2352 opts = pycompat.byteskwargs(opts)
2352 opts = pycompat.byteskwargs(opts)
2353 with repo.wlock(False):
2353 with repo.wlock(False):
2354 return cmdutil.copy(ui, repo, pats, opts)
2354 return cmdutil.copy(ui, repo, pats, opts)
2355
2355
2356
2356
2357 @command(
2357 @command(
2358 b'debugcommands',
2358 b'debugcommands',
2359 [],
2359 [],
2360 _(b'[COMMAND]'),
2360 _(b'[COMMAND]'),
2361 helpcategory=command.CATEGORY_HELP,
2361 helpcategory=command.CATEGORY_HELP,
2362 norepo=True,
2362 norepo=True,
2363 )
2363 )
2364 def debugcommands(ui, cmd=b'', *args):
2364 def debugcommands(ui, cmd=b'', *args):
2365 """list all available commands and options"""
2365 """list all available commands and options"""
2366 for cmd, vals in sorted(pycompat.iteritems(table)):
2366 for cmd, vals in sorted(pycompat.iteritems(table)):
2367 cmd = cmd.split(b'|')[0]
2367 cmd = cmd.split(b'|')[0]
2368 opts = b', '.join([i[1] for i in vals[1]])
2368 opts = b', '.join([i[1] for i in vals[1]])
2369 ui.write(b'%s: %s\n' % (cmd, opts))
2369 ui.write(b'%s: %s\n' % (cmd, opts))
2370
2370
2371
2371
2372 @command(
2372 @command(
2373 b'debugcomplete',
2373 b'debugcomplete',
2374 [(b'o', b'options', None, _(b'show the command options'))],
2374 [(b'o', b'options', None, _(b'show the command options'))],
2375 _(b'[-o] CMD'),
2375 _(b'[-o] CMD'),
2376 helpcategory=command.CATEGORY_HELP,
2376 helpcategory=command.CATEGORY_HELP,
2377 norepo=True,
2377 norepo=True,
2378 )
2378 )
2379 def debugcomplete(ui, cmd=b'', **opts):
2379 def debugcomplete(ui, cmd=b'', **opts):
2380 """returns the completion list associated with the given command"""
2380 """returns the completion list associated with the given command"""
2381
2381
2382 if opts.get('options'):
2382 if opts.get('options'):
2383 options = []
2383 options = []
2384 otables = [globalopts]
2384 otables = [globalopts]
2385 if cmd:
2385 if cmd:
2386 aliases, entry = cmdutil.findcmd(cmd, table, False)
2386 aliases, entry = cmdutil.findcmd(cmd, table, False)
2387 otables.append(entry[1])
2387 otables.append(entry[1])
2388 for t in otables:
2388 for t in otables:
2389 for o in t:
2389 for o in t:
2390 if b"(DEPRECATED)" in o[3]:
2390 if b"(DEPRECATED)" in o[3]:
2391 continue
2391 continue
2392 if o[0]:
2392 if o[0]:
2393 options.append(b'-%s' % o[0])
2393 options.append(b'-%s' % o[0])
2394 options.append(b'--%s' % o[1])
2394 options.append(b'--%s' % o[1])
2395 ui.write(b"%s\n" % b"\n".join(options))
2395 ui.write(b"%s\n" % b"\n".join(options))
2396 return
2396 return
2397
2397
2398 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2398 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2399 if ui.verbose:
2399 if ui.verbose:
2400 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2400 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2401 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2401 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2402
2402
2403
2403
2404 @command(
2404 @command(
2405 b'diff',
2405 b'diff',
2406 [
2406 [
2407 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2407 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2408 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2408 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2409 ]
2409 ]
2410 + diffopts
2410 + diffopts
2411 + diffopts2
2411 + diffopts2
2412 + walkopts
2412 + walkopts
2413 + subrepoopts,
2413 + subrepoopts,
2414 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2414 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2415 helpcategory=command.CATEGORY_FILE_CONTENTS,
2415 helpcategory=command.CATEGORY_FILE_CONTENTS,
2416 helpbasic=True,
2416 helpbasic=True,
2417 inferrepo=True,
2417 inferrepo=True,
2418 intents={INTENT_READONLY},
2418 intents={INTENT_READONLY},
2419 )
2419 )
2420 def diff(ui, repo, *pats, **opts):
2420 def diff(ui, repo, *pats, **opts):
2421 """diff repository (or selected files)
2421 """diff repository (or selected files)
2422
2422
2423 Show differences between revisions for the specified files.
2423 Show differences between revisions for the specified files.
2424
2424
2425 Differences between files are shown using the unified diff format.
2425 Differences between files are shown using the unified diff format.
2426
2426
2427 .. note::
2427 .. note::
2428
2428
2429 :hg:`diff` may generate unexpected results for merges, as it will
2429 :hg:`diff` may generate unexpected results for merges, as it will
2430 default to comparing against the working directory's first
2430 default to comparing against the working directory's first
2431 parent changeset if no revisions are specified.
2431 parent changeset if no revisions are specified.
2432
2432
2433 When two revision arguments are given, then changes are shown
2433 When two revision arguments are given, then changes are shown
2434 between those revisions. If only one revision is specified then
2434 between those revisions. If only one revision is specified then
2435 that revision is compared to the working directory, and, when no
2435 that revision is compared to the working directory, and, when no
2436 revisions are specified, the working directory files are compared
2436 revisions are specified, the working directory files are compared
2437 to its first parent.
2437 to its first parent.
2438
2438
2439 Alternatively you can specify -c/--change with a revision to see
2439 Alternatively you can specify -c/--change with a revision to see
2440 the changes in that changeset relative to its first parent.
2440 the changes in that changeset relative to its first parent.
2441
2441
2442 Without the -a/--text option, diff will avoid generating diffs of
2442 Without the -a/--text option, diff will avoid generating diffs of
2443 files it detects as binary. With -a, diff will generate a diff
2443 files it detects as binary. With -a, diff will generate a diff
2444 anyway, probably with undesirable results.
2444 anyway, probably with undesirable results.
2445
2445
2446 Use the -g/--git option to generate diffs in the git extended diff
2446 Use the -g/--git option to generate diffs in the git extended diff
2447 format. For more information, read :hg:`help diffs`.
2447 format. For more information, read :hg:`help diffs`.
2448
2448
2449 .. container:: verbose
2449 .. container:: verbose
2450
2450
2451 Examples:
2451 Examples:
2452
2452
2453 - compare a file in the current working directory to its parent::
2453 - compare a file in the current working directory to its parent::
2454
2454
2455 hg diff foo.c
2455 hg diff foo.c
2456
2456
2457 - compare two historical versions of a directory, with rename info::
2457 - compare two historical versions of a directory, with rename info::
2458
2458
2459 hg diff --git -r 1.0:1.2 lib/
2459 hg diff --git -r 1.0:1.2 lib/
2460
2460
2461 - get change stats relative to the last change on some date::
2461 - get change stats relative to the last change on some date::
2462
2462
2463 hg diff --stat -r "date('may 2')"
2463 hg diff --stat -r "date('may 2')"
2464
2464
2465 - diff all newly-added files that contain a keyword::
2465 - diff all newly-added files that contain a keyword::
2466
2466
2467 hg diff "set:added() and grep(GNU)"
2467 hg diff "set:added() and grep(GNU)"
2468
2468
2469 - compare a revision and its parents::
2469 - compare a revision and its parents::
2470
2470
2471 hg diff -c 9353 # compare against first parent
2471 hg diff -c 9353 # compare against first parent
2472 hg diff -r 9353^:9353 # same using revset syntax
2472 hg diff -r 9353^:9353 # same using revset syntax
2473 hg diff -r 9353^2:9353 # compare against the second parent
2473 hg diff -r 9353^2:9353 # compare against the second parent
2474
2474
2475 Returns 0 on success.
2475 Returns 0 on success.
2476 """
2476 """
2477
2477
2478 opts = pycompat.byteskwargs(opts)
2478 opts = pycompat.byteskwargs(opts)
2479 revs = opts.get(b'rev')
2479 revs = opts.get(b'rev')
2480 change = opts.get(b'change')
2480 change = opts.get(b'change')
2481 stat = opts.get(b'stat')
2481 stat = opts.get(b'stat')
2482 reverse = opts.get(b'reverse')
2482 reverse = opts.get(b'reverse')
2483
2483
2484 if revs and change:
2484 if revs and change:
2485 msg = _(b'cannot specify --rev and --change at the same time')
2485 msg = _(b'cannot specify --rev and --change at the same time')
2486 raise error.Abort(msg)
2486 raise error.Abort(msg)
2487 elif change:
2487 elif change:
2488 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2488 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2489 ctx2 = scmutil.revsingle(repo, change, None)
2489 ctx2 = scmutil.revsingle(repo, change, None)
2490 ctx1 = ctx2.p1()
2490 ctx1 = ctx2.p1()
2491 else:
2491 else:
2492 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2492 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2493 ctx1, ctx2 = scmutil.revpair(repo, revs)
2493 ctx1, ctx2 = scmutil.revpair(repo, revs)
2494 node1, node2 = ctx1.node(), ctx2.node()
2494 node1, node2 = ctx1.node(), ctx2.node()
2495
2495
2496 if reverse:
2496 if reverse:
2497 node1, node2 = node2, node1
2497 node1, node2 = node2, node1
2498
2498
2499 diffopts = patch.diffallopts(ui, opts)
2499 diffopts = patch.diffallopts(ui, opts)
2500 m = scmutil.match(ctx2, pats, opts)
2500 m = scmutil.match(ctx2, pats, opts)
2501 m = repo.narrowmatch(m)
2501 m = repo.narrowmatch(m)
2502 ui.pager(b'diff')
2502 ui.pager(b'diff')
2503 logcmdutil.diffordiffstat(
2503 logcmdutil.diffordiffstat(
2504 ui,
2504 ui,
2505 repo,
2505 repo,
2506 diffopts,
2506 diffopts,
2507 node1,
2507 node1,
2508 node2,
2508 node2,
2509 m,
2509 m,
2510 stat=stat,
2510 stat=stat,
2511 listsubrepos=opts.get(b'subrepos'),
2511 listsubrepos=opts.get(b'subrepos'),
2512 root=opts.get(b'root'),
2512 root=opts.get(b'root'),
2513 )
2513 )
2514
2514
2515
2515
2516 @command(
2516 @command(
2517 b'export',
2517 b'export',
2518 [
2518 [
2519 (
2519 (
2520 b'B',
2520 b'B',
2521 b'bookmark',
2521 b'bookmark',
2522 b'',
2522 b'',
2523 _(b'export changes only reachable by given bookmark'),
2523 _(b'export changes only reachable by given bookmark'),
2524 _(b'BOOKMARK'),
2524 _(b'BOOKMARK'),
2525 ),
2525 ),
2526 (
2526 (
2527 b'o',
2527 b'o',
2528 b'output',
2528 b'output',
2529 b'',
2529 b'',
2530 _(b'print output to file with formatted name'),
2530 _(b'print output to file with formatted name'),
2531 _(b'FORMAT'),
2531 _(b'FORMAT'),
2532 ),
2532 ),
2533 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2533 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2534 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2534 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2535 ]
2535 ]
2536 + diffopts
2536 + diffopts
2537 + formatteropts,
2537 + formatteropts,
2538 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2538 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2539 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2539 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2540 helpbasic=True,
2540 helpbasic=True,
2541 intents={INTENT_READONLY},
2541 intents={INTENT_READONLY},
2542 )
2542 )
2543 def export(ui, repo, *changesets, **opts):
2543 def export(ui, repo, *changesets, **opts):
2544 """dump the header and diffs for one or more changesets
2544 """dump the header and diffs for one or more changesets
2545
2545
2546 Print the changeset header and diffs for one or more revisions.
2546 Print the changeset header and diffs for one or more revisions.
2547 If no revision is given, the parent of the working directory is used.
2547 If no revision is given, the parent of the working directory is used.
2548
2548
2549 The information shown in the changeset header is: author, date,
2549 The information shown in the changeset header is: author, date,
2550 branch name (if non-default), changeset hash, parent(s) and commit
2550 branch name (if non-default), changeset hash, parent(s) and commit
2551 comment.
2551 comment.
2552
2552
2553 .. note::
2553 .. note::
2554
2554
2555 :hg:`export` may generate unexpected diff output for merge
2555 :hg:`export` may generate unexpected diff output for merge
2556 changesets, as it will compare the merge changeset against its
2556 changesets, as it will compare the merge changeset against its
2557 first parent only.
2557 first parent only.
2558
2558
2559 Output may be to a file, in which case the name of the file is
2559 Output may be to a file, in which case the name of the file is
2560 given using a template string. See :hg:`help templates`. In addition
2560 given using a template string. See :hg:`help templates`. In addition
2561 to the common template keywords, the following formatting rules are
2561 to the common template keywords, the following formatting rules are
2562 supported:
2562 supported:
2563
2563
2564 :``%%``: literal "%" character
2564 :``%%``: literal "%" character
2565 :``%H``: changeset hash (40 hexadecimal digits)
2565 :``%H``: changeset hash (40 hexadecimal digits)
2566 :``%N``: number of patches being generated
2566 :``%N``: number of patches being generated
2567 :``%R``: changeset revision number
2567 :``%R``: changeset revision number
2568 :``%b``: basename of the exporting repository
2568 :``%b``: basename of the exporting repository
2569 :``%h``: short-form changeset hash (12 hexadecimal digits)
2569 :``%h``: short-form changeset hash (12 hexadecimal digits)
2570 :``%m``: first line of the commit message (only alphanumeric characters)
2570 :``%m``: first line of the commit message (only alphanumeric characters)
2571 :``%n``: zero-padded sequence number, starting at 1
2571 :``%n``: zero-padded sequence number, starting at 1
2572 :``%r``: zero-padded changeset revision number
2572 :``%r``: zero-padded changeset revision number
2573 :``\\``: literal "\\" character
2573 :``\\``: literal "\\" character
2574
2574
2575 Without the -a/--text option, export will avoid generating diffs
2575 Without the -a/--text option, export will avoid generating diffs
2576 of files it detects as binary. With -a, export will generate a
2576 of files it detects as binary. With -a, export will generate a
2577 diff anyway, probably with undesirable results.
2577 diff anyway, probably with undesirable results.
2578
2578
2579 With -B/--bookmark changesets reachable by the given bookmark are
2579 With -B/--bookmark changesets reachable by the given bookmark are
2580 selected.
2580 selected.
2581
2581
2582 Use the -g/--git option to generate diffs in the git extended diff
2582 Use the -g/--git option to generate diffs in the git extended diff
2583 format. See :hg:`help diffs` for more information.
2583 format. See :hg:`help diffs` for more information.
2584
2584
2585 With the --switch-parent option, the diff will be against the
2585 With the --switch-parent option, the diff will be against the
2586 second parent. It can be useful to review a merge.
2586 second parent. It can be useful to review a merge.
2587
2587
2588 .. container:: verbose
2588 .. container:: verbose
2589
2589
2590 Template:
2590 Template:
2591
2591
2592 The following keywords are supported in addition to the common template
2592 The following keywords are supported in addition to the common template
2593 keywords and functions. See also :hg:`help templates`.
2593 keywords and functions. See also :hg:`help templates`.
2594
2594
2595 :diff: String. Diff content.
2595 :diff: String. Diff content.
2596 :parents: List of strings. Parent nodes of the changeset.
2596 :parents: List of strings. Parent nodes of the changeset.
2597
2597
2598 Examples:
2598 Examples:
2599
2599
2600 - use export and import to transplant a bugfix to the current
2600 - use export and import to transplant a bugfix to the current
2601 branch::
2601 branch::
2602
2602
2603 hg export -r 9353 | hg import -
2603 hg export -r 9353 | hg import -
2604
2604
2605 - export all the changesets between two revisions to a file with
2605 - export all the changesets between two revisions to a file with
2606 rename information::
2606 rename information::
2607
2607
2608 hg export --git -r 123:150 > changes.txt
2608 hg export --git -r 123:150 > changes.txt
2609
2609
2610 - split outgoing changes into a series of patches with
2610 - split outgoing changes into a series of patches with
2611 descriptive names::
2611 descriptive names::
2612
2612
2613 hg export -r "outgoing()" -o "%n-%m.patch"
2613 hg export -r "outgoing()" -o "%n-%m.patch"
2614
2614
2615 Returns 0 on success.
2615 Returns 0 on success.
2616 """
2616 """
2617 opts = pycompat.byteskwargs(opts)
2617 opts = pycompat.byteskwargs(opts)
2618 bookmark = opts.get(b'bookmark')
2618 bookmark = opts.get(b'bookmark')
2619 changesets += tuple(opts.get(b'rev', []))
2619 changesets += tuple(opts.get(b'rev', []))
2620
2620
2621 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2621 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2622
2622
2623 if bookmark:
2623 if bookmark:
2624 if bookmark not in repo._bookmarks:
2624 if bookmark not in repo._bookmarks:
2625 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2625 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2626
2626
2627 revs = scmutil.bookmarkrevs(repo, bookmark)
2627 revs = scmutil.bookmarkrevs(repo, bookmark)
2628 else:
2628 else:
2629 if not changesets:
2629 if not changesets:
2630 changesets = [b'.']
2630 changesets = [b'.']
2631
2631
2632 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2632 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2633 revs = scmutil.revrange(repo, changesets)
2633 revs = scmutil.revrange(repo, changesets)
2634
2634
2635 if not revs:
2635 if not revs:
2636 raise error.Abort(_(b"export requires at least one changeset"))
2636 raise error.Abort(_(b"export requires at least one changeset"))
2637 if len(revs) > 1:
2637 if len(revs) > 1:
2638 ui.note(_(b'exporting patches:\n'))
2638 ui.note(_(b'exporting patches:\n'))
2639 else:
2639 else:
2640 ui.note(_(b'exporting patch:\n'))
2640 ui.note(_(b'exporting patch:\n'))
2641
2641
2642 fntemplate = opts.get(b'output')
2642 fntemplate = opts.get(b'output')
2643 if cmdutil.isstdiofilename(fntemplate):
2643 if cmdutil.isstdiofilename(fntemplate):
2644 fntemplate = b''
2644 fntemplate = b''
2645
2645
2646 if fntemplate:
2646 if fntemplate:
2647 fm = formatter.nullformatter(ui, b'export', opts)
2647 fm = formatter.nullformatter(ui, b'export', opts)
2648 else:
2648 else:
2649 ui.pager(b'export')
2649 ui.pager(b'export')
2650 fm = ui.formatter(b'export', opts)
2650 fm = ui.formatter(b'export', opts)
2651 with fm:
2651 with fm:
2652 cmdutil.export(
2652 cmdutil.export(
2653 repo,
2653 repo,
2654 revs,
2654 revs,
2655 fm,
2655 fm,
2656 fntemplate=fntemplate,
2656 fntemplate=fntemplate,
2657 switch_parent=opts.get(b'switch_parent'),
2657 switch_parent=opts.get(b'switch_parent'),
2658 opts=patch.diffallopts(ui, opts),
2658 opts=patch.diffallopts(ui, opts),
2659 )
2659 )
2660
2660
2661
2661
2662 @command(
2662 @command(
2663 b'files',
2663 b'files',
2664 [
2664 [
2665 (
2665 (
2666 b'r',
2666 b'r',
2667 b'rev',
2667 b'rev',
2668 b'',
2668 b'',
2669 _(b'search the repository as it is in REV'),
2669 _(b'search the repository as it is in REV'),
2670 _(b'REV'),
2670 _(b'REV'),
2671 ),
2671 ),
2672 (
2672 (
2673 b'0',
2673 b'0',
2674 b'print0',
2674 b'print0',
2675 None,
2675 None,
2676 _(b'end filenames with NUL, for use with xargs'),
2676 _(b'end filenames with NUL, for use with xargs'),
2677 ),
2677 ),
2678 ]
2678 ]
2679 + walkopts
2679 + walkopts
2680 + formatteropts
2680 + formatteropts
2681 + subrepoopts,
2681 + subrepoopts,
2682 _(b'[OPTION]... [FILE]...'),
2682 _(b'[OPTION]... [FILE]...'),
2683 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2683 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2684 intents={INTENT_READONLY},
2684 intents={INTENT_READONLY},
2685 )
2685 )
2686 def files(ui, repo, *pats, **opts):
2686 def files(ui, repo, *pats, **opts):
2687 """list tracked files
2687 """list tracked files
2688
2688
2689 Print files under Mercurial control in the working directory or
2689 Print files under Mercurial control in the working directory or
2690 specified revision for given files (excluding removed files).
2690 specified revision for given files (excluding removed files).
2691 Files can be specified as filenames or filesets.
2691 Files can be specified as filenames or filesets.
2692
2692
2693 If no files are given to match, this command prints the names
2693 If no files are given to match, this command prints the names
2694 of all files under Mercurial control.
2694 of all files under Mercurial control.
2695
2695
2696 .. container:: verbose
2696 .. container:: verbose
2697
2697
2698 Template:
2698 Template:
2699
2699
2700 The following keywords are supported in addition to the common template
2700 The following keywords are supported in addition to the common template
2701 keywords and functions. See also :hg:`help templates`.
2701 keywords and functions. See also :hg:`help templates`.
2702
2702
2703 :flags: String. Character denoting file's symlink and executable bits.
2703 :flags: String. Character denoting file's symlink and executable bits.
2704 :path: String. Repository-absolute path of the file.
2704 :path: String. Repository-absolute path of the file.
2705 :size: Integer. Size of the file in bytes.
2705 :size: Integer. Size of the file in bytes.
2706
2706
2707 Examples:
2707 Examples:
2708
2708
2709 - list all files under the current directory::
2709 - list all files under the current directory::
2710
2710
2711 hg files .
2711 hg files .
2712
2712
2713 - shows sizes and flags for current revision::
2713 - shows sizes and flags for current revision::
2714
2714
2715 hg files -vr .
2715 hg files -vr .
2716
2716
2717 - list all files named README::
2717 - list all files named README::
2718
2718
2719 hg files -I "**/README"
2719 hg files -I "**/README"
2720
2720
2721 - list all binary files::
2721 - list all binary files::
2722
2722
2723 hg files "set:binary()"
2723 hg files "set:binary()"
2724
2724
2725 - find files containing a regular expression::
2725 - find files containing a regular expression::
2726
2726
2727 hg files "set:grep('bob')"
2727 hg files "set:grep('bob')"
2728
2728
2729 - search tracked file contents with xargs and grep::
2729 - search tracked file contents with xargs and grep::
2730
2730
2731 hg files -0 | xargs -0 grep foo
2731 hg files -0 | xargs -0 grep foo
2732
2732
2733 See :hg:`help patterns` and :hg:`help filesets` for more information
2733 See :hg:`help patterns` and :hg:`help filesets` for more information
2734 on specifying file patterns.
2734 on specifying file patterns.
2735
2735
2736 Returns 0 if a match is found, 1 otherwise.
2736 Returns 0 if a match is found, 1 otherwise.
2737
2737
2738 """
2738 """
2739
2739
2740 opts = pycompat.byteskwargs(opts)
2740 opts = pycompat.byteskwargs(opts)
2741 rev = opts.get(b'rev')
2741 rev = opts.get(b'rev')
2742 if rev:
2742 if rev:
2743 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2743 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2744 ctx = scmutil.revsingle(repo, rev, None)
2744 ctx = scmutil.revsingle(repo, rev, None)
2745
2745
2746 end = b'\n'
2746 end = b'\n'
2747 if opts.get(b'print0'):
2747 if opts.get(b'print0'):
2748 end = b'\0'
2748 end = b'\0'
2749 fmt = b'%s' + end
2749 fmt = b'%s' + end
2750
2750
2751 m = scmutil.match(ctx, pats, opts)
2751 m = scmutil.match(ctx, pats, opts)
2752 ui.pager(b'files')
2752 ui.pager(b'files')
2753 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2753 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2754 with ui.formatter(b'files', opts) as fm:
2754 with ui.formatter(b'files', opts) as fm:
2755 return cmdutil.files(
2755 return cmdutil.files(
2756 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2756 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2757 )
2757 )
2758
2758
2759
2759
2760 @command(
2760 @command(
2761 b'forget',
2761 b'forget',
2762 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2762 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2763 + walkopts
2763 + walkopts
2764 + dryrunopts,
2764 + dryrunopts,
2765 _(b'[OPTION]... FILE...'),
2765 _(b'[OPTION]... FILE...'),
2766 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2766 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2767 helpbasic=True,
2767 helpbasic=True,
2768 inferrepo=True,
2768 inferrepo=True,
2769 )
2769 )
2770 def forget(ui, repo, *pats, **opts):
2770 def forget(ui, repo, *pats, **opts):
2771 """forget the specified files on the next commit
2771 """forget the specified files on the next commit
2772
2772
2773 Mark the specified files so they will no longer be tracked
2773 Mark the specified files so they will no longer be tracked
2774 after the next commit.
2774 after the next commit.
2775
2775
2776 This only removes files from the current branch, not from the
2776 This only removes files from the current branch, not from the
2777 entire project history, and it does not delete them from the
2777 entire project history, and it does not delete them from the
2778 working directory.
2778 working directory.
2779
2779
2780 To delete the file from the working directory, see :hg:`remove`.
2780 To delete the file from the working directory, see :hg:`remove`.
2781
2781
2782 To undo a forget before the next commit, see :hg:`add`.
2782 To undo a forget before the next commit, see :hg:`add`.
2783
2783
2784 .. container:: verbose
2784 .. container:: verbose
2785
2785
2786 Examples:
2786 Examples:
2787
2787
2788 - forget newly-added binary files::
2788 - forget newly-added binary files::
2789
2789
2790 hg forget "set:added() and binary()"
2790 hg forget "set:added() and binary()"
2791
2791
2792 - forget files that would be excluded by .hgignore::
2792 - forget files that would be excluded by .hgignore::
2793
2793
2794 hg forget "set:hgignore()"
2794 hg forget "set:hgignore()"
2795
2795
2796 Returns 0 on success.
2796 Returns 0 on success.
2797 """
2797 """
2798
2798
2799 opts = pycompat.byteskwargs(opts)
2799 opts = pycompat.byteskwargs(opts)
2800 if not pats:
2800 if not pats:
2801 raise error.Abort(_(b'no files specified'))
2801 raise error.Abort(_(b'no files specified'))
2802
2802
2803 m = scmutil.match(repo[None], pats, opts)
2803 m = scmutil.match(repo[None], pats, opts)
2804 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2804 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2805 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2805 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2806 rejected = cmdutil.forget(
2806 rejected = cmdutil.forget(
2807 ui,
2807 ui,
2808 repo,
2808 repo,
2809 m,
2809 m,
2810 prefix=b"",
2810 prefix=b"",
2811 uipathfn=uipathfn,
2811 uipathfn=uipathfn,
2812 explicitonly=False,
2812 explicitonly=False,
2813 dryrun=dryrun,
2813 dryrun=dryrun,
2814 interactive=interactive,
2814 interactive=interactive,
2815 )[0]
2815 )[0]
2816 return rejected and 1 or 0
2816 return rejected and 1 or 0
2817
2817
2818
2818
2819 @command(
2819 @command(
2820 b'graft',
2820 b'graft',
2821 [
2821 [
2822 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2822 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2823 (
2823 (
2824 b'',
2824 b'',
2825 b'base',
2825 b'base',
2826 b'',
2826 b'',
2827 _(b'base revision when doing the graft merge (ADVANCED)'),
2827 _(b'base revision when doing the graft merge (ADVANCED)'),
2828 _(b'REV'),
2828 _(b'REV'),
2829 ),
2829 ),
2830 (b'c', b'continue', False, _(b'resume interrupted graft')),
2830 (b'c', b'continue', False, _(b'resume interrupted graft')),
2831 (b'', b'stop', False, _(b'stop interrupted graft')),
2831 (b'', b'stop', False, _(b'stop interrupted graft')),
2832 (b'', b'abort', False, _(b'abort interrupted graft')),
2832 (b'', b'abort', False, _(b'abort interrupted graft')),
2833 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2833 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2834 (b'', b'log', None, _(b'append graft info to log message')),
2834 (b'', b'log', None, _(b'append graft info to log message')),
2835 (
2835 (
2836 b'',
2836 b'',
2837 b'no-commit',
2837 b'no-commit',
2838 None,
2838 None,
2839 _(b"don't commit, just apply the changes in working directory"),
2839 _(b"don't commit, just apply the changes in working directory"),
2840 ),
2840 ),
2841 (b'f', b'force', False, _(b'force graft')),
2841 (b'f', b'force', False, _(b'force graft')),
2842 (
2842 (
2843 b'D',
2843 b'D',
2844 b'currentdate',
2844 b'currentdate',
2845 False,
2845 False,
2846 _(b'record the current date as commit date'),
2846 _(b'record the current date as commit date'),
2847 ),
2847 ),
2848 (
2848 (
2849 b'U',
2849 b'U',
2850 b'currentuser',
2850 b'currentuser',
2851 False,
2851 False,
2852 _(b'record the current user as committer'),
2852 _(b'record the current user as committer'),
2853 ),
2853 ),
2854 ]
2854 ]
2855 + commitopts2
2855 + commitopts2
2856 + mergetoolopts
2856 + mergetoolopts
2857 + dryrunopts,
2857 + dryrunopts,
2858 _(b'[OPTION]... [-r REV]... REV...'),
2858 _(b'[OPTION]... [-r REV]... REV...'),
2859 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2859 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2860 )
2860 )
2861 def graft(ui, repo, *revs, **opts):
2861 def graft(ui, repo, *revs, **opts):
2862 '''copy changes from other branches onto the current branch
2862 '''copy changes from other branches onto the current branch
2863
2863
2864 This command uses Mercurial's merge logic to copy individual
2864 This command uses Mercurial's merge logic to copy individual
2865 changes from other branches without merging branches in the
2865 changes from other branches without merging branches in the
2866 history graph. This is sometimes known as 'backporting' or
2866 history graph. This is sometimes known as 'backporting' or
2867 'cherry-picking'. By default, graft will copy user, date, and
2867 'cherry-picking'. By default, graft will copy user, date, and
2868 description from the source changesets.
2868 description from the source changesets.
2869
2869
2870 Changesets that are ancestors of the current revision, that have
2870 Changesets that are ancestors of the current revision, that have
2871 already been grafted, or that are merges will be skipped.
2871 already been grafted, or that are merges will be skipped.
2872
2872
2873 If --log is specified, log messages will have a comment appended
2873 If --log is specified, log messages will have a comment appended
2874 of the form::
2874 of the form::
2875
2875
2876 (grafted from CHANGESETHASH)
2876 (grafted from CHANGESETHASH)
2877
2877
2878 If --force is specified, revisions will be grafted even if they
2878 If --force is specified, revisions will be grafted even if they
2879 are already ancestors of, or have been grafted to, the destination.
2879 are already ancestors of, or have been grafted to, the destination.
2880 This is useful when the revisions have since been backed out.
2880 This is useful when the revisions have since been backed out.
2881
2881
2882 If a graft merge results in conflicts, the graft process is
2882 If a graft merge results in conflicts, the graft process is
2883 interrupted so that the current merge can be manually resolved.
2883 interrupted so that the current merge can be manually resolved.
2884 Once all conflicts are addressed, the graft process can be
2884 Once all conflicts are addressed, the graft process can be
2885 continued with the -c/--continue option.
2885 continued with the -c/--continue option.
2886
2886
2887 The -c/--continue option reapplies all the earlier options.
2887 The -c/--continue option reapplies all the earlier options.
2888
2888
2889 .. container:: verbose
2889 .. container:: verbose
2890
2890
2891 The --base option exposes more of how graft internally uses merge with a
2891 The --base option exposes more of how graft internally uses merge with a
2892 custom base revision. --base can be used to specify another ancestor than
2892 custom base revision. --base can be used to specify another ancestor than
2893 the first and only parent.
2893 the first and only parent.
2894
2894
2895 The command::
2895 The command::
2896
2896
2897 hg graft -r 345 --base 234
2897 hg graft -r 345 --base 234
2898
2898
2899 is thus pretty much the same as::
2899 is thus pretty much the same as::
2900
2900
2901 hg diff -r 234 -r 345 | hg import
2901 hg diff -r 234 -r 345 | hg import
2902
2902
2903 but using merge to resolve conflicts and track moved files.
2903 but using merge to resolve conflicts and track moved files.
2904
2904
2905 The result of a merge can thus be backported as a single commit by
2905 The result of a merge can thus be backported as a single commit by
2906 specifying one of the merge parents as base, and thus effectively
2906 specifying one of the merge parents as base, and thus effectively
2907 grafting the changes from the other side.
2907 grafting the changes from the other side.
2908
2908
2909 It is also possible to collapse multiple changesets and clean up history
2909 It is also possible to collapse multiple changesets and clean up history
2910 by specifying another ancestor as base, much like rebase --collapse
2910 by specifying another ancestor as base, much like rebase --collapse
2911 --keep.
2911 --keep.
2912
2912
2913 The commit message can be tweaked after the fact using commit --amend .
2913 The commit message can be tweaked after the fact using commit --amend .
2914
2914
2915 For using non-ancestors as the base to backout changes, see the backout
2915 For using non-ancestors as the base to backout changes, see the backout
2916 command and the hidden --parent option.
2916 command and the hidden --parent option.
2917
2917
2918 .. container:: verbose
2918 .. container:: verbose
2919
2919
2920 Examples:
2920 Examples:
2921
2921
2922 - copy a single change to the stable branch and edit its description::
2922 - copy a single change to the stable branch and edit its description::
2923
2923
2924 hg update stable
2924 hg update stable
2925 hg graft --edit 9393
2925 hg graft --edit 9393
2926
2926
2927 - graft a range of changesets with one exception, updating dates::
2927 - graft a range of changesets with one exception, updating dates::
2928
2928
2929 hg graft -D "2085::2093 and not 2091"
2929 hg graft -D "2085::2093 and not 2091"
2930
2930
2931 - continue a graft after resolving conflicts::
2931 - continue a graft after resolving conflicts::
2932
2932
2933 hg graft -c
2933 hg graft -c
2934
2934
2935 - show the source of a grafted changeset::
2935 - show the source of a grafted changeset::
2936
2936
2937 hg log --debug -r .
2937 hg log --debug -r .
2938
2938
2939 - show revisions sorted by date::
2939 - show revisions sorted by date::
2940
2940
2941 hg log -r "sort(all(), date)"
2941 hg log -r "sort(all(), date)"
2942
2942
2943 - backport the result of a merge as a single commit::
2943 - backport the result of a merge as a single commit::
2944
2944
2945 hg graft -r 123 --base 123^
2945 hg graft -r 123 --base 123^
2946
2946
2947 - land a feature branch as one changeset::
2947 - land a feature branch as one changeset::
2948
2948
2949 hg up -cr default
2949 hg up -cr default
2950 hg graft -r featureX --base "ancestor('featureX', 'default')"
2950 hg graft -r featureX --base "ancestor('featureX', 'default')"
2951
2951
2952 See :hg:`help revisions` for more about specifying revisions.
2952 See :hg:`help revisions` for more about specifying revisions.
2953
2953
2954 Returns 0 on successful completion, 1 if there are unresolved files.
2954 Returns 0 on successful completion, 1 if there are unresolved files.
2955 '''
2955 '''
2956 with repo.wlock():
2956 with repo.wlock():
2957 return _dograft(ui, repo, *revs, **opts)
2957 return _dograft(ui, repo, *revs, **opts)
2958
2958
2959
2959
2960 def _dograft(ui, repo, *revs, **opts):
2960 def _dograft(ui, repo, *revs, **opts):
2961 opts = pycompat.byteskwargs(opts)
2961 opts = pycompat.byteskwargs(opts)
2962 if revs and opts.get(b'rev'):
2962 if revs and opts.get(b'rev'):
2963 ui.warn(
2963 ui.warn(
2964 _(
2964 _(
2965 b'warning: inconsistent use of --rev might give unexpected '
2965 b'warning: inconsistent use of --rev might give unexpected '
2966 b'revision ordering!\n'
2966 b'revision ordering!\n'
2967 )
2967 )
2968 )
2968 )
2969
2969
2970 revs = list(revs)
2970 revs = list(revs)
2971 revs.extend(opts.get(b'rev'))
2971 revs.extend(opts.get(b'rev'))
2972 # a dict of data to be stored in state file
2972 # a dict of data to be stored in state file
2973 statedata = {}
2973 statedata = {}
2974 # list of new nodes created by ongoing graft
2974 # list of new nodes created by ongoing graft
2975 statedata[b'newnodes'] = []
2975 statedata[b'newnodes'] = []
2976
2976
2977 cmdutil.resolvecommitoptions(ui, opts)
2977 cmdutil.resolvecommitoptions(ui, opts)
2978
2978
2979 editor = cmdutil.getcommiteditor(
2979 editor = cmdutil.getcommiteditor(
2980 editform=b'graft', **pycompat.strkwargs(opts)
2980 editform=b'graft', **pycompat.strkwargs(opts)
2981 )
2981 )
2982
2982
2983 cont = False
2983 cont = False
2984 if opts.get(b'no_commit'):
2984 if opts.get(b'no_commit'):
2985 if opts.get(b'edit'):
2985 if opts.get(b'edit'):
2986 raise error.Abort(
2986 raise error.Abort(
2987 _(b"cannot specify --no-commit and --edit together")
2987 _(b"cannot specify --no-commit and --edit together")
2988 )
2988 )
2989 if opts.get(b'currentuser'):
2989 if opts.get(b'currentuser'):
2990 raise error.Abort(
2990 raise error.Abort(
2991 _(b"cannot specify --no-commit and --currentuser together")
2991 _(b"cannot specify --no-commit and --currentuser together")
2992 )
2992 )
2993 if opts.get(b'currentdate'):
2993 if opts.get(b'currentdate'):
2994 raise error.Abort(
2994 raise error.Abort(
2995 _(b"cannot specify --no-commit and --currentdate together")
2995 _(b"cannot specify --no-commit and --currentdate together")
2996 )
2996 )
2997 if opts.get(b'log'):
2997 if opts.get(b'log'):
2998 raise error.Abort(
2998 raise error.Abort(
2999 _(b"cannot specify --no-commit and --log together")
2999 _(b"cannot specify --no-commit and --log together")
3000 )
3000 )
3001
3001
3002 graftstate = statemod.cmdstate(repo, b'graftstate')
3002 graftstate = statemod.cmdstate(repo, b'graftstate')
3003
3003
3004 if opts.get(b'stop'):
3004 if opts.get(b'stop'):
3005 if opts.get(b'continue'):
3005 if opts.get(b'continue'):
3006 raise error.Abort(
3006 raise error.Abort(
3007 _(b"cannot use '--continue' and '--stop' together")
3007 _(b"cannot use '--continue' and '--stop' together")
3008 )
3008 )
3009 if opts.get(b'abort'):
3009 if opts.get(b'abort'):
3010 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3010 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3011
3011
3012 if any(
3012 if any(
3013 (
3013 (
3014 opts.get(b'edit'),
3014 opts.get(b'edit'),
3015 opts.get(b'log'),
3015 opts.get(b'log'),
3016 opts.get(b'user'),
3016 opts.get(b'user'),
3017 opts.get(b'date'),
3017 opts.get(b'date'),
3018 opts.get(b'currentdate'),
3018 opts.get(b'currentdate'),
3019 opts.get(b'currentuser'),
3019 opts.get(b'currentuser'),
3020 opts.get(b'rev'),
3020 opts.get(b'rev'),
3021 )
3021 )
3022 ):
3022 ):
3023 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3023 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3024 return _stopgraft(ui, repo, graftstate)
3024 return _stopgraft(ui, repo, graftstate)
3025 elif opts.get(b'abort'):
3025 elif opts.get(b'abort'):
3026 if opts.get(b'continue'):
3026 if opts.get(b'continue'):
3027 raise error.Abort(
3027 raise error.Abort(
3028 _(b"cannot use '--continue' and '--abort' together")
3028 _(b"cannot use '--continue' and '--abort' together")
3029 )
3029 )
3030 if any(
3030 if any(
3031 (
3031 (
3032 opts.get(b'edit'),
3032 opts.get(b'edit'),
3033 opts.get(b'log'),
3033 opts.get(b'log'),
3034 opts.get(b'user'),
3034 opts.get(b'user'),
3035 opts.get(b'date'),
3035 opts.get(b'date'),
3036 opts.get(b'currentdate'),
3036 opts.get(b'currentdate'),
3037 opts.get(b'currentuser'),
3037 opts.get(b'currentuser'),
3038 opts.get(b'rev'),
3038 opts.get(b'rev'),
3039 )
3039 )
3040 ):
3040 ):
3041 raise error.Abort(
3041 raise error.Abort(
3042 _(b"cannot specify any other flag with '--abort'")
3042 _(b"cannot specify any other flag with '--abort'")
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 hg.updaterepo(repo, pctx.node(), overwrite=True)
3251 hg.updaterepo(repo, pctx.node(), overwrite=True)
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'print all revisions that match (DEPRECATED) ')),
3273 (b'', b'all', None, _(b'print all revisions that match (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 = opts.get(b'all_files') and not opts.get(b'rev')
3378 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3379 all_files = opts.get(b'all_files')
3379 all_files = opts.get(b'all_files')
3380 if plaingrep:
3380 if plaingrep:
3381 opts[b'rev'] = [b'wdir()']
3381 opts[b'rev'] = [b'wdir()']
3382
3382
3383 reflags = re.M
3383 reflags = re.M
3384 if opts.get(b'ignore_case'):
3384 if opts.get(b'ignore_case'):
3385 reflags |= re.I
3385 reflags |= re.I
3386 try:
3386 try:
3387 regexp = util.re.compile(pattern, reflags)
3387 regexp = util.re.compile(pattern, reflags)
3388 except re.error as inst:
3388 except re.error as inst:
3389 ui.warn(
3389 ui.warn(
3390 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3390 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3391 )
3391 )
3392 return 1
3392 return 1
3393 sep, eol = b':', b'\n'
3393 sep, eol = b':', b'\n'
3394 if opts.get(b'print0'):
3394 if opts.get(b'print0'):
3395 sep = eol = b'\0'
3395 sep = eol = b'\0'
3396
3396
3397 getfile = util.lrucachefunc(repo.file)
3397 getfile = util.lrucachefunc(repo.file)
3398
3398
3399 def matchlines(body):
3399 def matchlines(body):
3400 begin = 0
3400 begin = 0
3401 linenum = 0
3401 linenum = 0
3402 while begin < len(body):
3402 while begin < len(body):
3403 match = regexp.search(body, begin)
3403 match = regexp.search(body, begin)
3404 if not match:
3404 if not match:
3405 break
3405 break
3406 mstart, mend = match.span()
3406 mstart, mend = match.span()
3407 linenum += body.count(b'\n', begin, mstart) + 1
3407 linenum += body.count(b'\n', begin, mstart) + 1
3408 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3408 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3409 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3409 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3410 lend = begin - 1
3410 lend = begin - 1
3411 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3411 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3412
3412
3413 class linestate(object):
3413 class linestate(object):
3414 def __init__(self, line, linenum, colstart, colend):
3414 def __init__(self, line, linenum, colstart, colend):
3415 self.line = line
3415 self.line = line
3416 self.linenum = linenum
3416 self.linenum = linenum
3417 self.colstart = colstart
3417 self.colstart = colstart
3418 self.colend = colend
3418 self.colend = colend
3419
3419
3420 def __hash__(self):
3420 def __hash__(self):
3421 return hash((self.linenum, self.line))
3421 return hash((self.linenum, self.line))
3422
3422
3423 def __eq__(self, other):
3423 def __eq__(self, other):
3424 return self.line == other.line
3424 return self.line == other.line
3425
3425
3426 def findpos(self):
3426 def findpos(self):
3427 """Iterate all (start, end) indices of matches"""
3427 """Iterate all (start, end) indices of matches"""
3428 yield self.colstart, self.colend
3428 yield self.colstart, self.colend
3429 p = self.colend
3429 p = self.colend
3430 while p < len(self.line):
3430 while p < len(self.line):
3431 m = regexp.search(self.line, p)
3431 m = regexp.search(self.line, p)
3432 if not m:
3432 if not m:
3433 break
3433 break
3434 yield m.span()
3434 yield m.span()
3435 p = m.end()
3435 p = m.end()
3436
3436
3437 matches = {}
3437 matches = {}
3438 copies = {}
3438 copies = {}
3439
3439
3440 def grepbody(fn, rev, body):
3440 def grepbody(fn, rev, body):
3441 matches[rev].setdefault(fn, [])
3441 matches[rev].setdefault(fn, [])
3442 m = matches[rev][fn]
3442 m = matches[rev][fn]
3443 if body is None:
3443 if body is None:
3444 return
3444 return
3445
3445
3446 for lnum, cstart, cend, line in matchlines(body):
3446 for lnum, cstart, cend, line in matchlines(body):
3447 s = linestate(line, lnum, cstart, cend)
3447 s = linestate(line, lnum, cstart, cend)
3448 m.append(s)
3448 m.append(s)
3449
3449
3450 def difflinestates(a, b):
3450 def difflinestates(a, b):
3451 sm = difflib.SequenceMatcher(None, a, b)
3451 sm = difflib.SequenceMatcher(None, a, b)
3452 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3452 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3453 if tag == 'insert':
3453 if tag == 'insert':
3454 for i in pycompat.xrange(blo, bhi):
3454 for i in pycompat.xrange(blo, bhi):
3455 yield (b'+', b[i])
3455 yield (b'+', b[i])
3456 elif tag == 'delete':
3456 elif tag == 'delete':
3457 for i in pycompat.xrange(alo, ahi):
3457 for i in pycompat.xrange(alo, ahi):
3458 yield (b'-', a[i])
3458 yield (b'-', a[i])
3459 elif tag == 'replace':
3459 elif tag == 'replace':
3460 for i in pycompat.xrange(alo, ahi):
3460 for i in pycompat.xrange(alo, ahi):
3461 yield (b'-', a[i])
3461 yield (b'-', a[i])
3462 for i in pycompat.xrange(blo, bhi):
3462 for i in pycompat.xrange(blo, bhi):
3463 yield (b'+', b[i])
3463 yield (b'+', b[i])
3464
3464
3465 uipathfn = scmutil.getuipathfn(repo)
3465 uipathfn = scmutil.getuipathfn(repo)
3466
3466
3467 def display(fm, fn, ctx, pstates, states):
3467 def display(fm, fn, ctx, pstates, states):
3468 rev = scmutil.intrev(ctx)
3468 rev = scmutil.intrev(ctx)
3469 if fm.isplain():
3469 if fm.isplain():
3470 formatuser = ui.shortuser
3470 formatuser = ui.shortuser
3471 else:
3471 else:
3472 formatuser = pycompat.bytestr
3472 formatuser = pycompat.bytestr
3473 if ui.quiet:
3473 if ui.quiet:
3474 datefmt = b'%Y-%m-%d'
3474 datefmt = b'%Y-%m-%d'
3475 else:
3475 else:
3476 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3476 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3477 found = False
3477 found = False
3478
3478
3479 @util.cachefunc
3479 @util.cachefunc
3480 def binary():
3480 def binary():
3481 flog = getfile(fn)
3481 flog = getfile(fn)
3482 try:
3482 try:
3483 return stringutil.binary(flog.read(ctx.filenode(fn)))
3483 return stringutil.binary(flog.read(ctx.filenode(fn)))
3484 except error.WdirUnsupported:
3484 except error.WdirUnsupported:
3485 return ctx[fn].isbinary()
3485 return ctx[fn].isbinary()
3486
3486
3487 fieldnamemap = {b'linenumber': b'lineno'}
3487 fieldnamemap = {b'linenumber': b'lineno'}
3488 if diff:
3488 if diff:
3489 iter = difflinestates(pstates, states)
3489 iter = difflinestates(pstates, states)
3490 else:
3490 else:
3491 iter = [(b'', l) for l in states]
3491 iter = [(b'', l) for l in states]
3492 for change, l in iter:
3492 for change, l in iter:
3493 fm.startitem()
3493 fm.startitem()
3494 fm.context(ctx=ctx)
3494 fm.context(ctx=ctx)
3495 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3495 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3496 fm.plain(uipathfn(fn), label=b'grep.filename')
3496 fm.plain(uipathfn(fn), label=b'grep.filename')
3497
3497
3498 cols = [
3498 cols = [
3499 (b'rev', b'%d', rev, not plaingrep, b''),
3499 (b'rev', b'%d', rev, not plaingrep, b''),
3500 (
3500 (
3501 b'linenumber',
3501 b'linenumber',
3502 b'%d',
3502 b'%d',
3503 l.linenum,
3503 l.linenum,
3504 opts.get(b'line_number'),
3504 opts.get(b'line_number'),
3505 b'',
3505 b'',
3506 ),
3506 ),
3507 ]
3507 ]
3508 if diff:
3508 if diff:
3509 cols.append(
3509 cols.append(
3510 (
3510 (
3511 b'change',
3511 b'change',
3512 b'%s',
3512 b'%s',
3513 change,
3513 change,
3514 True,
3514 True,
3515 b'grep.inserted '
3515 b'grep.inserted '
3516 if change == b'+'
3516 if change == b'+'
3517 else b'grep.deleted ',
3517 else b'grep.deleted ',
3518 )
3518 )
3519 )
3519 )
3520 cols.extend(
3520 cols.extend(
3521 [
3521 [
3522 (
3522 (
3523 b'user',
3523 b'user',
3524 b'%s',
3524 b'%s',
3525 formatuser(ctx.user()),
3525 formatuser(ctx.user()),
3526 opts.get(b'user'),
3526 opts.get(b'user'),
3527 b'',
3527 b'',
3528 ),
3528 ),
3529 (
3529 (
3530 b'date',
3530 b'date',
3531 b'%s',
3531 b'%s',
3532 fm.formatdate(ctx.date(), datefmt),
3532 fm.formatdate(ctx.date(), datefmt),
3533 opts.get(b'date'),
3533 opts.get(b'date'),
3534 b'',
3534 b'',
3535 ),
3535 ),
3536 ]
3536 ]
3537 )
3537 )
3538 for name, fmt, data, cond, extra_label in cols:
3538 for name, fmt, data, cond, extra_label in cols:
3539 if cond:
3539 if cond:
3540 fm.plain(sep, label=b'grep.sep')
3540 fm.plain(sep, label=b'grep.sep')
3541 field = fieldnamemap.get(name, name)
3541 field = fieldnamemap.get(name, name)
3542 label = extra_label + (b'grep.%s' % name)
3542 label = extra_label + (b'grep.%s' % name)
3543 fm.condwrite(cond, field, fmt, data, label=label)
3543 fm.condwrite(cond, field, fmt, data, label=label)
3544 if not opts.get(b'files_with_matches'):
3544 if not opts.get(b'files_with_matches'):
3545 fm.plain(sep, label=b'grep.sep')
3545 fm.plain(sep, label=b'grep.sep')
3546 if not opts.get(b'text') and binary():
3546 if not opts.get(b'text') and binary():
3547 fm.plain(_(b" Binary file matches"))
3547 fm.plain(_(b" Binary file matches"))
3548 else:
3548 else:
3549 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3549 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3550 fm.plain(eol)
3550 fm.plain(eol)
3551 found = True
3551 found = True
3552 if opts.get(b'files_with_matches'):
3552 if opts.get(b'files_with_matches'):
3553 break
3553 break
3554 return found
3554 return found
3555
3555
3556 def displaymatches(fm, l):
3556 def displaymatches(fm, l):
3557 p = 0
3557 p = 0
3558 for s, e in l.findpos():
3558 for s, e in l.findpos():
3559 if p < s:
3559 if p < s:
3560 fm.startitem()
3560 fm.startitem()
3561 fm.write(b'text', b'%s', l.line[p:s])
3561 fm.write(b'text', b'%s', l.line[p:s])
3562 fm.data(matched=False)
3562 fm.data(matched=False)
3563 fm.startitem()
3563 fm.startitem()
3564 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3564 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3565 fm.data(matched=True)
3565 fm.data(matched=True)
3566 p = e
3566 p = e
3567 if p < len(l.line):
3567 if p < len(l.line):
3568 fm.startitem()
3568 fm.startitem()
3569 fm.write(b'text', b'%s', l.line[p:])
3569 fm.write(b'text', b'%s', l.line[p:])
3570 fm.data(matched=False)
3570 fm.data(matched=False)
3571 fm.end()
3571 fm.end()
3572
3572
3573 skip = set()
3573 skip = set()
3574 revfiles = {}
3574 revfiles = {}
3575 match = scmutil.match(repo[None], pats, opts)
3575 match = scmutil.match(repo[None], pats, opts)
3576 found = False
3576 found = False
3577 follow = opts.get(b'follow')
3577 follow = opts.get(b'follow')
3578
3578
3579 getrenamed = scmutil.getrenamedfn(repo)
3579 getrenamed = scmutil.getrenamedfn(repo)
3580
3580
3581 def get_file_content(filename, filelog, filenode, context, revision):
3581 def get_file_content(filename, filelog, filenode, context, revision):
3582 try:
3582 try:
3583 content = filelog.read(filenode)
3583 content = filelog.read(filenode)
3584 except error.WdirUnsupported:
3584 except error.WdirUnsupported:
3585 content = context[filename].data()
3585 content = context[filename].data()
3586 except error.CensoredNodeError:
3586 except error.CensoredNodeError:
3587 content = None
3587 content = None
3588 ui.warn(
3588 ui.warn(
3589 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3589 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3590 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3590 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3591 )
3591 )
3592 return content
3592 return content
3593
3593
3594 def prep(ctx, fns):
3594 def prep(ctx, fns):
3595 rev = ctx.rev()
3595 rev = ctx.rev()
3596 pctx = ctx.p1()
3596 pctx = ctx.p1()
3597 parent = pctx.rev()
3597 parent = pctx.rev()
3598 matches.setdefault(rev, {})
3598 matches.setdefault(rev, {})
3599 matches.setdefault(parent, {})
3599 matches.setdefault(parent, {})
3600 files = revfiles.setdefault(rev, [])
3600 files = revfiles.setdefault(rev, [])
3601 for fn in fns:
3601 for fn in fns:
3602 flog = getfile(fn)
3602 flog = getfile(fn)
3603 try:
3603 try:
3604 fnode = ctx.filenode(fn)
3604 fnode = ctx.filenode(fn)
3605 except error.LookupError:
3605 except error.LookupError:
3606 continue
3606 continue
3607
3607
3608 copy = None
3608 copy = None
3609 if follow:
3609 if follow:
3610 copy = getrenamed(fn, rev)
3610 copy = getrenamed(fn, rev)
3611 if copy:
3611 if copy:
3612 copies.setdefault(rev, {})[fn] = copy
3612 copies.setdefault(rev, {})[fn] = copy
3613 if fn in skip:
3613 if fn in skip:
3614 skip.add(copy)
3614 skip.add(copy)
3615 if fn in skip:
3615 if fn in skip:
3616 continue
3616 continue
3617 files.append(fn)
3617 files.append(fn)
3618
3618
3619 if fn not in matches[rev]:
3619 if fn not in matches[rev]:
3620 content = get_file_content(fn, flog, fnode, ctx, rev)
3620 content = get_file_content(fn, flog, fnode, ctx, rev)
3621 grepbody(fn, rev, content)
3621 grepbody(fn, rev, content)
3622
3622
3623 pfn = copy or fn
3623 pfn = copy or fn
3624 if pfn not in matches[parent]:
3624 if pfn not in matches[parent]:
3625 try:
3625 try:
3626 pfnode = pctx.filenode(pfn)
3626 pfnode = pctx.filenode(pfn)
3627 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3627 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3628 grepbody(pfn, parent, pcontent)
3628 grepbody(pfn, parent, pcontent)
3629 except error.LookupError:
3629 except error.LookupError:
3630 pass
3630 pass
3631
3631
3632 ui.pager(b'grep')
3632 ui.pager(b'grep')
3633 fm = ui.formatter(b'grep', opts)
3633 fm = ui.formatter(b'grep', opts)
3634 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3634 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3635 rev = ctx.rev()
3635 rev = ctx.rev()
3636 parent = ctx.p1().rev()
3636 parent = ctx.p1().rev()
3637 for fn in sorted(revfiles.get(rev, [])):
3637 for fn in sorted(revfiles.get(rev, [])):
3638 states = matches[rev][fn]
3638 states = matches[rev][fn]
3639 copy = copies.get(rev, {}).get(fn)
3639 copy = copies.get(rev, {}).get(fn)
3640 if fn in skip:
3640 if fn in skip:
3641 if copy:
3641 if copy:
3642 skip.add(copy)
3642 skip.add(copy)
3643 continue
3643 continue
3644 pstates = matches.get(parent, {}).get(copy or fn, [])
3644 pstates = matches.get(parent, {}).get(copy or fn, [])
3645 if pstates or states:
3645 if pstates or states:
3646 r = display(fm, fn, ctx, pstates, states)
3646 r = display(fm, fn, ctx, pstates, states)
3647 found = found or r
3647 found = found or r
3648 if r and not diff and not all_files:
3648 if r and not diff and not all_files:
3649 skip.add(fn)
3649 skip.add(fn)
3650 if copy:
3650 if copy:
3651 skip.add(copy)
3651 skip.add(copy)
3652 del revfiles[rev]
3652 del revfiles[rev]
3653 # We will keep the matches dict for the duration of the window
3653 # We will keep the matches dict for the duration of the window
3654 # clear the matches dict once the window is over
3654 # clear the matches dict once the window is over
3655 if not revfiles:
3655 if not revfiles:
3656 matches.clear()
3656 matches.clear()
3657 fm.end()
3657 fm.end()
3658
3658
3659 return not found
3659 return not found
3660
3660
3661
3661
3662 @command(
3662 @command(
3663 b'heads',
3663 b'heads',
3664 [
3664 [
3665 (
3665 (
3666 b'r',
3666 b'r',
3667 b'rev',
3667 b'rev',
3668 b'',
3668 b'',
3669 _(b'show only heads which are descendants of STARTREV'),
3669 _(b'show only heads which are descendants of STARTREV'),
3670 _(b'STARTREV'),
3670 _(b'STARTREV'),
3671 ),
3671 ),
3672 (b't', b'topo', False, _(b'show topological heads only')),
3672 (b't', b'topo', False, _(b'show topological heads only')),
3673 (
3673 (
3674 b'a',
3674 b'a',
3675 b'active',
3675 b'active',
3676 False,
3676 False,
3677 _(b'show active branchheads only (DEPRECATED)'),
3677 _(b'show active branchheads only (DEPRECATED)'),
3678 ),
3678 ),
3679 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3679 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3680 ]
3680 ]
3681 + templateopts,
3681 + templateopts,
3682 _(b'[-ct] [-r STARTREV] [REV]...'),
3682 _(b'[-ct] [-r STARTREV] [REV]...'),
3683 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3683 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3684 intents={INTENT_READONLY},
3684 intents={INTENT_READONLY},
3685 )
3685 )
3686 def heads(ui, repo, *branchrevs, **opts):
3686 def heads(ui, repo, *branchrevs, **opts):
3687 """show branch heads
3687 """show branch heads
3688
3688
3689 With no arguments, show all open branch heads in the repository.
3689 With no arguments, show all open branch heads in the repository.
3690 Branch heads are changesets that have no descendants on the
3690 Branch heads are changesets that have no descendants on the
3691 same branch. They are where development generally takes place and
3691 same branch. They are where development generally takes place and
3692 are the usual targets for update and merge operations.
3692 are the usual targets for update and merge operations.
3693
3693
3694 If one or more REVs are given, only open branch heads on the
3694 If one or more REVs are given, only open branch heads on the
3695 branches associated with the specified changesets are shown. This
3695 branches associated with the specified changesets are shown. This
3696 means that you can use :hg:`heads .` to see the heads on the
3696 means that you can use :hg:`heads .` to see the heads on the
3697 currently checked-out branch.
3697 currently checked-out branch.
3698
3698
3699 If -c/--closed is specified, also show branch heads marked closed
3699 If -c/--closed is specified, also show branch heads marked closed
3700 (see :hg:`commit --close-branch`).
3700 (see :hg:`commit --close-branch`).
3701
3701
3702 If STARTREV is specified, only those heads that are descendants of
3702 If STARTREV is specified, only those heads that are descendants of
3703 STARTREV will be displayed.
3703 STARTREV will be displayed.
3704
3704
3705 If -t/--topo is specified, named branch mechanics will be ignored and only
3705 If -t/--topo is specified, named branch mechanics will be ignored and only
3706 topological heads (changesets with no children) will be shown.
3706 topological heads (changesets with no children) will be shown.
3707
3707
3708 Returns 0 if matching heads are found, 1 if not.
3708 Returns 0 if matching heads are found, 1 if not.
3709 """
3709 """
3710
3710
3711 opts = pycompat.byteskwargs(opts)
3711 opts = pycompat.byteskwargs(opts)
3712 start = None
3712 start = None
3713 rev = opts.get(b'rev')
3713 rev = opts.get(b'rev')
3714 if rev:
3714 if rev:
3715 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3715 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3716 start = scmutil.revsingle(repo, rev, None).node()
3716 start = scmutil.revsingle(repo, rev, None).node()
3717
3717
3718 if opts.get(b'topo'):
3718 if opts.get(b'topo'):
3719 heads = [repo[h] for h in repo.heads(start)]
3719 heads = [repo[h] for h in repo.heads(start)]
3720 else:
3720 else:
3721 heads = []
3721 heads = []
3722 for branch in repo.branchmap():
3722 for branch in repo.branchmap():
3723 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3723 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3724 heads = [repo[h] for h in heads]
3724 heads = [repo[h] for h in heads]
3725
3725
3726 if branchrevs:
3726 if branchrevs:
3727 branches = {
3727 branches = {
3728 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3728 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3729 }
3729 }
3730 heads = [h for h in heads if h.branch() in branches]
3730 heads = [h for h in heads if h.branch() in branches]
3731
3731
3732 if opts.get(b'active') and branchrevs:
3732 if opts.get(b'active') and branchrevs:
3733 dagheads = repo.heads(start)
3733 dagheads = repo.heads(start)
3734 heads = [h for h in heads if h.node() in dagheads]
3734 heads = [h for h in heads if h.node() in dagheads]
3735
3735
3736 if branchrevs:
3736 if branchrevs:
3737 haveheads = {h.branch() for h in heads}
3737 haveheads = {h.branch() for h in heads}
3738 if branches - haveheads:
3738 if branches - haveheads:
3739 headless = b', '.join(b for b in branches - haveheads)
3739 headless = b', '.join(b for b in branches - haveheads)
3740 msg = _(b'no open branch heads found on branches %s')
3740 msg = _(b'no open branch heads found on branches %s')
3741 if opts.get(b'rev'):
3741 if opts.get(b'rev'):
3742 msg += _(b' (started at %s)') % opts[b'rev']
3742 msg += _(b' (started at %s)') % opts[b'rev']
3743 ui.warn((msg + b'\n') % headless)
3743 ui.warn((msg + b'\n') % headless)
3744
3744
3745 if not heads:
3745 if not heads:
3746 return 1
3746 return 1
3747
3747
3748 ui.pager(b'heads')
3748 ui.pager(b'heads')
3749 heads = sorted(heads, key=lambda x: -(x.rev()))
3749 heads = sorted(heads, key=lambda x: -(x.rev()))
3750 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3750 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3751 for ctx in heads:
3751 for ctx in heads:
3752 displayer.show(ctx)
3752 displayer.show(ctx)
3753 displayer.close()
3753 displayer.close()
3754
3754
3755
3755
3756 @command(
3756 @command(
3757 b'help',
3757 b'help',
3758 [
3758 [
3759 (b'e', b'extension', None, _(b'show only help for extensions')),
3759 (b'e', b'extension', None, _(b'show only help for extensions')),
3760 (b'c', b'command', None, _(b'show only help for commands')),
3760 (b'c', b'command', None, _(b'show only help for commands')),
3761 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3761 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3762 (
3762 (
3763 b's',
3763 b's',
3764 b'system',
3764 b'system',
3765 [],
3765 [],
3766 _(b'show help for specific platform(s)'),
3766 _(b'show help for specific platform(s)'),
3767 _(b'PLATFORM'),
3767 _(b'PLATFORM'),
3768 ),
3768 ),
3769 ],
3769 ],
3770 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3770 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3771 helpcategory=command.CATEGORY_HELP,
3771 helpcategory=command.CATEGORY_HELP,
3772 norepo=True,
3772 norepo=True,
3773 intents={INTENT_READONLY},
3773 intents={INTENT_READONLY},
3774 )
3774 )
3775 def help_(ui, name=None, **opts):
3775 def help_(ui, name=None, **opts):
3776 """show help for a given topic or a help overview
3776 """show help for a given topic or a help overview
3777
3777
3778 With no arguments, print a list of commands with short help messages.
3778 With no arguments, print a list of commands with short help messages.
3779
3779
3780 Given a topic, extension, or command name, print help for that
3780 Given a topic, extension, or command name, print help for that
3781 topic.
3781 topic.
3782
3782
3783 Returns 0 if successful.
3783 Returns 0 if successful.
3784 """
3784 """
3785
3785
3786 keep = opts.get('system') or []
3786 keep = opts.get('system') or []
3787 if len(keep) == 0:
3787 if len(keep) == 0:
3788 if pycompat.sysplatform.startswith(b'win'):
3788 if pycompat.sysplatform.startswith(b'win'):
3789 keep.append(b'windows')
3789 keep.append(b'windows')
3790 elif pycompat.sysplatform == b'OpenVMS':
3790 elif pycompat.sysplatform == b'OpenVMS':
3791 keep.append(b'vms')
3791 keep.append(b'vms')
3792 elif pycompat.sysplatform == b'plan9':
3792 elif pycompat.sysplatform == b'plan9':
3793 keep.append(b'plan9')
3793 keep.append(b'plan9')
3794 else:
3794 else:
3795 keep.append(b'unix')
3795 keep.append(b'unix')
3796 keep.append(pycompat.sysplatform.lower())
3796 keep.append(pycompat.sysplatform.lower())
3797 if ui.verbose:
3797 if ui.verbose:
3798 keep.append(b'verbose')
3798 keep.append(b'verbose')
3799
3799
3800 commands = sys.modules[__name__]
3800 commands = sys.modules[__name__]
3801 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3801 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3802 ui.pager(b'help')
3802 ui.pager(b'help')
3803 ui.write(formatted)
3803 ui.write(formatted)
3804
3804
3805
3805
3806 @command(
3806 @command(
3807 b'identify|id',
3807 b'identify|id',
3808 [
3808 [
3809 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3809 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3810 (b'n', b'num', None, _(b'show local revision number')),
3810 (b'n', b'num', None, _(b'show local revision number')),
3811 (b'i', b'id', None, _(b'show global revision id')),
3811 (b'i', b'id', None, _(b'show global revision id')),
3812 (b'b', b'branch', None, _(b'show branch')),
3812 (b'b', b'branch', None, _(b'show branch')),
3813 (b't', b'tags', None, _(b'show tags')),
3813 (b't', b'tags', None, _(b'show tags')),
3814 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3814 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3815 ]
3815 ]
3816 + remoteopts
3816 + remoteopts
3817 + formatteropts,
3817 + formatteropts,
3818 _(b'[-nibtB] [-r REV] [SOURCE]'),
3818 _(b'[-nibtB] [-r REV] [SOURCE]'),
3819 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3819 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3820 optionalrepo=True,
3820 optionalrepo=True,
3821 intents={INTENT_READONLY},
3821 intents={INTENT_READONLY},
3822 )
3822 )
3823 def identify(
3823 def identify(
3824 ui,
3824 ui,
3825 repo,
3825 repo,
3826 source=None,
3826 source=None,
3827 rev=None,
3827 rev=None,
3828 num=None,
3828 num=None,
3829 id=None,
3829 id=None,
3830 branch=None,
3830 branch=None,
3831 tags=None,
3831 tags=None,
3832 bookmarks=None,
3832 bookmarks=None,
3833 **opts
3833 **opts
3834 ):
3834 ):
3835 """identify the working directory or specified revision
3835 """identify the working directory or specified revision
3836
3836
3837 Print a summary identifying the repository state at REV using one or
3837 Print a summary identifying the repository state at REV using one or
3838 two parent hash identifiers, followed by a "+" if the working
3838 two parent hash identifiers, followed by a "+" if the working
3839 directory has uncommitted changes, the branch name (if not default),
3839 directory has uncommitted changes, the branch name (if not default),
3840 a list of tags, and a list of bookmarks.
3840 a list of tags, and a list of bookmarks.
3841
3841
3842 When REV is not given, print a summary of the current state of the
3842 When REV is not given, print a summary of the current state of the
3843 repository including the working directory. Specify -r. to get information
3843 repository including the working directory. Specify -r. to get information
3844 of the working directory parent without scanning uncommitted changes.
3844 of the working directory parent without scanning uncommitted changes.
3845
3845
3846 Specifying a path to a repository root or Mercurial bundle will
3846 Specifying a path to a repository root or Mercurial bundle will
3847 cause lookup to operate on that repository/bundle.
3847 cause lookup to operate on that repository/bundle.
3848
3848
3849 .. container:: verbose
3849 .. container:: verbose
3850
3850
3851 Template:
3851 Template:
3852
3852
3853 The following keywords are supported in addition to the common template
3853 The following keywords are supported in addition to the common template
3854 keywords and functions. See also :hg:`help templates`.
3854 keywords and functions. See also :hg:`help templates`.
3855
3855
3856 :dirty: String. Character ``+`` denoting if the working directory has
3856 :dirty: String. Character ``+`` denoting if the working directory has
3857 uncommitted changes.
3857 uncommitted changes.
3858 :id: String. One or two nodes, optionally followed by ``+``.
3858 :id: String. One or two nodes, optionally followed by ``+``.
3859 :parents: List of strings. Parent nodes of the changeset.
3859 :parents: List of strings. Parent nodes of the changeset.
3860
3860
3861 Examples:
3861 Examples:
3862
3862
3863 - generate a build identifier for the working directory::
3863 - generate a build identifier for the working directory::
3864
3864
3865 hg id --id > build-id.dat
3865 hg id --id > build-id.dat
3866
3866
3867 - find the revision corresponding to a tag::
3867 - find the revision corresponding to a tag::
3868
3868
3869 hg id -n -r 1.3
3869 hg id -n -r 1.3
3870
3870
3871 - check the most recent revision of a remote repository::
3871 - check the most recent revision of a remote repository::
3872
3872
3873 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3873 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3874
3874
3875 See :hg:`log` for generating more information about specific revisions,
3875 See :hg:`log` for generating more information about specific revisions,
3876 including full hash identifiers.
3876 including full hash identifiers.
3877
3877
3878 Returns 0 if successful.
3878 Returns 0 if successful.
3879 """
3879 """
3880
3880
3881 opts = pycompat.byteskwargs(opts)
3881 opts = pycompat.byteskwargs(opts)
3882 if not repo and not source:
3882 if not repo and not source:
3883 raise error.Abort(
3883 raise error.Abort(
3884 _(b"there is no Mercurial repository here (.hg not found)")
3884 _(b"there is no Mercurial repository here (.hg not found)")
3885 )
3885 )
3886
3886
3887 default = not (num or id or branch or tags or bookmarks)
3887 default = not (num or id or branch or tags or bookmarks)
3888 output = []
3888 output = []
3889 revs = []
3889 revs = []
3890
3890
3891 if source:
3891 if source:
3892 source, branches = hg.parseurl(ui.expandpath(source))
3892 source, branches = hg.parseurl(ui.expandpath(source))
3893 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3893 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3894 repo = peer.local()
3894 repo = peer.local()
3895 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3895 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3896
3896
3897 fm = ui.formatter(b'identify', opts)
3897 fm = ui.formatter(b'identify', opts)
3898 fm.startitem()
3898 fm.startitem()
3899
3899
3900 if not repo:
3900 if not repo:
3901 if num or branch or tags:
3901 if num or branch or tags:
3902 raise error.Abort(
3902 raise error.Abort(
3903 _(b"can't query remote revision number, branch, or tags")
3903 _(b"can't query remote revision number, branch, or tags")
3904 )
3904 )
3905 if not rev and revs:
3905 if not rev and revs:
3906 rev = revs[0]
3906 rev = revs[0]
3907 if not rev:
3907 if not rev:
3908 rev = b"tip"
3908 rev = b"tip"
3909
3909
3910 remoterev = peer.lookup(rev)
3910 remoterev = peer.lookup(rev)
3911 hexrev = fm.hexfunc(remoterev)
3911 hexrev = fm.hexfunc(remoterev)
3912 if default or id:
3912 if default or id:
3913 output = [hexrev]
3913 output = [hexrev]
3914 fm.data(id=hexrev)
3914 fm.data(id=hexrev)
3915
3915
3916 @util.cachefunc
3916 @util.cachefunc
3917 def getbms():
3917 def getbms():
3918 bms = []
3918 bms = []
3919
3919
3920 if b'bookmarks' in peer.listkeys(b'namespaces'):
3920 if b'bookmarks' in peer.listkeys(b'namespaces'):
3921 hexremoterev = hex(remoterev)
3921 hexremoterev = hex(remoterev)
3922 bms = [
3922 bms = [
3923 bm
3923 bm
3924 for bm, bmr in pycompat.iteritems(
3924 for bm, bmr in pycompat.iteritems(
3925 peer.listkeys(b'bookmarks')
3925 peer.listkeys(b'bookmarks')
3926 )
3926 )
3927 if bmr == hexremoterev
3927 if bmr == hexremoterev
3928 ]
3928 ]
3929
3929
3930 return sorted(bms)
3930 return sorted(bms)
3931
3931
3932 if fm.isplain():
3932 if fm.isplain():
3933 if bookmarks:
3933 if bookmarks:
3934 output.extend(getbms())
3934 output.extend(getbms())
3935 elif default and not ui.quiet:
3935 elif default and not ui.quiet:
3936 # multiple bookmarks for a single parent separated by '/'
3936 # multiple bookmarks for a single parent separated by '/'
3937 bm = b'/'.join(getbms())
3937 bm = b'/'.join(getbms())
3938 if bm:
3938 if bm:
3939 output.append(bm)
3939 output.append(bm)
3940 else:
3940 else:
3941 fm.data(node=hex(remoterev))
3941 fm.data(node=hex(remoterev))
3942 if bookmarks or b'bookmarks' in fm.datahint():
3942 if bookmarks or b'bookmarks' in fm.datahint():
3943 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3943 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3944 else:
3944 else:
3945 if rev:
3945 if rev:
3946 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3946 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3947 ctx = scmutil.revsingle(repo, rev, None)
3947 ctx = scmutil.revsingle(repo, rev, None)
3948
3948
3949 if ctx.rev() is None:
3949 if ctx.rev() is None:
3950 ctx = repo[None]
3950 ctx = repo[None]
3951 parents = ctx.parents()
3951 parents = ctx.parents()
3952 taglist = []
3952 taglist = []
3953 for p in parents:
3953 for p in parents:
3954 taglist.extend(p.tags())
3954 taglist.extend(p.tags())
3955
3955
3956 dirty = b""
3956 dirty = b""
3957 if ctx.dirty(missing=True, merge=False, branch=False):
3957 if ctx.dirty(missing=True, merge=False, branch=False):
3958 dirty = b'+'
3958 dirty = b'+'
3959 fm.data(dirty=dirty)
3959 fm.data(dirty=dirty)
3960
3960
3961 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3961 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3962 if default or id:
3962 if default or id:
3963 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3963 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3964 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3964 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3965
3965
3966 if num:
3966 if num:
3967 numoutput = [b"%d" % p.rev() for p in parents]
3967 numoutput = [b"%d" % p.rev() for p in parents]
3968 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3968 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3969
3969
3970 fm.data(
3970 fm.data(
3971 parents=fm.formatlist(
3971 parents=fm.formatlist(
3972 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3972 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3973 )
3973 )
3974 )
3974 )
3975 else:
3975 else:
3976 hexoutput = fm.hexfunc(ctx.node())
3976 hexoutput = fm.hexfunc(ctx.node())
3977 if default or id:
3977 if default or id:
3978 output = [hexoutput]
3978 output = [hexoutput]
3979 fm.data(id=hexoutput)
3979 fm.data(id=hexoutput)
3980
3980
3981 if num:
3981 if num:
3982 output.append(pycompat.bytestr(ctx.rev()))
3982 output.append(pycompat.bytestr(ctx.rev()))
3983 taglist = ctx.tags()
3983 taglist = ctx.tags()
3984
3984
3985 if default and not ui.quiet:
3985 if default and not ui.quiet:
3986 b = ctx.branch()
3986 b = ctx.branch()
3987 if b != b'default':
3987 if b != b'default':
3988 output.append(b"(%s)" % b)
3988 output.append(b"(%s)" % b)
3989
3989
3990 # multiple tags for a single parent separated by '/'
3990 # multiple tags for a single parent separated by '/'
3991 t = b'/'.join(taglist)
3991 t = b'/'.join(taglist)
3992 if t:
3992 if t:
3993 output.append(t)
3993 output.append(t)
3994
3994
3995 # multiple bookmarks for a single parent separated by '/'
3995 # multiple bookmarks for a single parent separated by '/'
3996 bm = b'/'.join(ctx.bookmarks())
3996 bm = b'/'.join(ctx.bookmarks())
3997 if bm:
3997 if bm:
3998 output.append(bm)
3998 output.append(bm)
3999 else:
3999 else:
4000 if branch:
4000 if branch:
4001 output.append(ctx.branch())
4001 output.append(ctx.branch())
4002
4002
4003 if tags:
4003 if tags:
4004 output.extend(taglist)
4004 output.extend(taglist)
4005
4005
4006 if bookmarks:
4006 if bookmarks:
4007 output.extend(ctx.bookmarks())
4007 output.extend(ctx.bookmarks())
4008
4008
4009 fm.data(node=ctx.hex())
4009 fm.data(node=ctx.hex())
4010 fm.data(branch=ctx.branch())
4010 fm.data(branch=ctx.branch())
4011 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4011 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4012 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4012 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4013 fm.context(ctx=ctx)
4013 fm.context(ctx=ctx)
4014
4014
4015 fm.plain(b"%s\n" % b' '.join(output))
4015 fm.plain(b"%s\n" % b' '.join(output))
4016 fm.end()
4016 fm.end()
4017
4017
4018
4018
4019 @command(
4019 @command(
4020 b'import|patch',
4020 b'import|patch',
4021 [
4021 [
4022 (
4022 (
4023 b'p',
4023 b'p',
4024 b'strip',
4024 b'strip',
4025 1,
4025 1,
4026 _(
4026 _(
4027 b'directory strip option for patch. This has the same '
4027 b'directory strip option for patch. This has the same '
4028 b'meaning as the corresponding patch option'
4028 b'meaning as the corresponding patch option'
4029 ),
4029 ),
4030 _(b'NUM'),
4030 _(b'NUM'),
4031 ),
4031 ),
4032 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4032 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4033 (b'', b'secret', None, _(b'use the secret phase for committing')),
4033 (b'', b'secret', None, _(b'use the secret phase for committing')),
4034 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4034 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4035 (
4035 (
4036 b'f',
4036 b'f',
4037 b'force',
4037 b'force',
4038 None,
4038 None,
4039 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4039 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4040 ),
4040 ),
4041 (
4041 (
4042 b'',
4042 b'',
4043 b'no-commit',
4043 b'no-commit',
4044 None,
4044 None,
4045 _(b"don't commit, just update the working directory"),
4045 _(b"don't commit, just update the working directory"),
4046 ),
4046 ),
4047 (
4047 (
4048 b'',
4048 b'',
4049 b'bypass',
4049 b'bypass',
4050 None,
4050 None,
4051 _(b"apply patch without touching the working directory"),
4051 _(b"apply patch without touching the working directory"),
4052 ),
4052 ),
4053 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4053 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4054 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4054 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4055 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4055 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4056 (
4056 (
4057 b'',
4057 b'',
4058 b'import-branch',
4058 b'import-branch',
4059 None,
4059 None,
4060 _(b'use any branch information in patch (implied by --exact)'),
4060 _(b'use any branch information in patch (implied by --exact)'),
4061 ),
4061 ),
4062 ]
4062 ]
4063 + commitopts
4063 + commitopts
4064 + commitopts2
4064 + commitopts2
4065 + similarityopts,
4065 + similarityopts,
4066 _(b'[OPTION]... PATCH...'),
4066 _(b'[OPTION]... PATCH...'),
4067 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4067 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4068 )
4068 )
4069 def import_(ui, repo, patch1=None, *patches, **opts):
4069 def import_(ui, repo, patch1=None, *patches, **opts):
4070 """import an ordered set of patches
4070 """import an ordered set of patches
4071
4071
4072 Import a list of patches and commit them individually (unless
4072 Import a list of patches and commit them individually (unless
4073 --no-commit is specified).
4073 --no-commit is specified).
4074
4074
4075 To read a patch from standard input (stdin), use "-" as the patch
4075 To read a patch from standard input (stdin), use "-" as the patch
4076 name. If a URL is specified, the patch will be downloaded from
4076 name. If a URL is specified, the patch will be downloaded from
4077 there.
4077 there.
4078
4078
4079 Import first applies changes to the working directory (unless
4079 Import first applies changes to the working directory (unless
4080 --bypass is specified), import will abort if there are outstanding
4080 --bypass is specified), import will abort if there are outstanding
4081 changes.
4081 changes.
4082
4082
4083 Use --bypass to apply and commit patches directly to the
4083 Use --bypass to apply and commit patches directly to the
4084 repository, without affecting the working directory. Without
4084 repository, without affecting the working directory. Without
4085 --exact, patches will be applied on top of the working directory
4085 --exact, patches will be applied on top of the working directory
4086 parent revision.
4086 parent revision.
4087
4087
4088 You can import a patch straight from a mail message. Even patches
4088 You can import a patch straight from a mail message. Even patches
4089 as attachments work (to use the body part, it must have type
4089 as attachments work (to use the body part, it must have type
4090 text/plain or text/x-patch). From and Subject headers of email
4090 text/plain or text/x-patch). From and Subject headers of email
4091 message are used as default committer and commit message. All
4091 message are used as default committer and commit message. All
4092 text/plain body parts before first diff are added to the commit
4092 text/plain body parts before first diff are added to the commit
4093 message.
4093 message.
4094
4094
4095 If the imported patch was generated by :hg:`export`, user and
4095 If the imported patch was generated by :hg:`export`, user and
4096 description from patch override values from message headers and
4096 description from patch override values from message headers and
4097 body. Values given on command line with -m/--message and -u/--user
4097 body. Values given on command line with -m/--message and -u/--user
4098 override these.
4098 override these.
4099
4099
4100 If --exact is specified, import will set the working directory to
4100 If --exact is specified, import will set the working directory to
4101 the parent of each patch before applying it, and will abort if the
4101 the parent of each patch before applying it, and will abort if the
4102 resulting changeset has a different ID than the one recorded in
4102 resulting changeset has a different ID than the one recorded in
4103 the patch. This will guard against various ways that portable
4103 the patch. This will guard against various ways that portable
4104 patch formats and mail systems might fail to transfer Mercurial
4104 patch formats and mail systems might fail to transfer Mercurial
4105 data or metadata. See :hg:`bundle` for lossless transmission.
4105 data or metadata. See :hg:`bundle` for lossless transmission.
4106
4106
4107 Use --partial to ensure a changeset will be created from the patch
4107 Use --partial to ensure a changeset will be created from the patch
4108 even if some hunks fail to apply. Hunks that fail to apply will be
4108 even if some hunks fail to apply. Hunks that fail to apply will be
4109 written to a <target-file>.rej file. Conflicts can then be resolved
4109 written to a <target-file>.rej file. Conflicts can then be resolved
4110 by hand before :hg:`commit --amend` is run to update the created
4110 by hand before :hg:`commit --amend` is run to update the created
4111 changeset. This flag exists to let people import patches that
4111 changeset. This flag exists to let people import patches that
4112 partially apply without losing the associated metadata (author,
4112 partially apply without losing the associated metadata (author,
4113 date, description, ...).
4113 date, description, ...).
4114
4114
4115 .. note::
4115 .. note::
4116
4116
4117 When no hunks apply cleanly, :hg:`import --partial` will create
4117 When no hunks apply cleanly, :hg:`import --partial` will create
4118 an empty changeset, importing only the patch metadata.
4118 an empty changeset, importing only the patch metadata.
4119
4119
4120 With -s/--similarity, hg will attempt to discover renames and
4120 With -s/--similarity, hg will attempt to discover renames and
4121 copies in the patch in the same way as :hg:`addremove`.
4121 copies in the patch in the same way as :hg:`addremove`.
4122
4122
4123 It is possible to use external patch programs to perform the patch
4123 It is possible to use external patch programs to perform the patch
4124 by setting the ``ui.patch`` configuration option. For the default
4124 by setting the ``ui.patch`` configuration option. For the default
4125 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4125 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4126 See :hg:`help config` for more information about configuration
4126 See :hg:`help config` for more information about configuration
4127 files and how to use these options.
4127 files and how to use these options.
4128
4128
4129 See :hg:`help dates` for a list of formats valid for -d/--date.
4129 See :hg:`help dates` for a list of formats valid for -d/--date.
4130
4130
4131 .. container:: verbose
4131 .. container:: verbose
4132
4132
4133 Examples:
4133 Examples:
4134
4134
4135 - import a traditional patch from a website and detect renames::
4135 - import a traditional patch from a website and detect renames::
4136
4136
4137 hg import -s 80 http://example.com/bugfix.patch
4137 hg import -s 80 http://example.com/bugfix.patch
4138
4138
4139 - import a changeset from an hgweb server::
4139 - import a changeset from an hgweb server::
4140
4140
4141 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4141 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4142
4142
4143 - import all the patches in an Unix-style mbox::
4143 - import all the patches in an Unix-style mbox::
4144
4144
4145 hg import incoming-patches.mbox
4145 hg import incoming-patches.mbox
4146
4146
4147 - import patches from stdin::
4147 - import patches from stdin::
4148
4148
4149 hg import -
4149 hg import -
4150
4150
4151 - attempt to exactly restore an exported changeset (not always
4151 - attempt to exactly restore an exported changeset (not always
4152 possible)::
4152 possible)::
4153
4153
4154 hg import --exact proposed-fix.patch
4154 hg import --exact proposed-fix.patch
4155
4155
4156 - use an external tool to apply a patch which is too fuzzy for
4156 - use an external tool to apply a patch which is too fuzzy for
4157 the default internal tool.
4157 the default internal tool.
4158
4158
4159 hg import --config ui.patch="patch --merge" fuzzy.patch
4159 hg import --config ui.patch="patch --merge" fuzzy.patch
4160
4160
4161 - change the default fuzzing from 2 to a less strict 7
4161 - change the default fuzzing from 2 to a less strict 7
4162
4162
4163 hg import --config ui.fuzz=7 fuzz.patch
4163 hg import --config ui.fuzz=7 fuzz.patch
4164
4164
4165 Returns 0 on success, 1 on partial success (see --partial).
4165 Returns 0 on success, 1 on partial success (see --partial).
4166 """
4166 """
4167
4167
4168 opts = pycompat.byteskwargs(opts)
4168 opts = pycompat.byteskwargs(opts)
4169 if not patch1:
4169 if not patch1:
4170 raise error.Abort(_(b'need at least one patch to import'))
4170 raise error.Abort(_(b'need at least one patch to import'))
4171
4171
4172 patches = (patch1,) + patches
4172 patches = (patch1,) + patches
4173
4173
4174 date = opts.get(b'date')
4174 date = opts.get(b'date')
4175 if date:
4175 if date:
4176 opts[b'date'] = dateutil.parsedate(date)
4176 opts[b'date'] = dateutil.parsedate(date)
4177
4177
4178 exact = opts.get(b'exact')
4178 exact = opts.get(b'exact')
4179 update = not opts.get(b'bypass')
4179 update = not opts.get(b'bypass')
4180 if not update and opts.get(b'no_commit'):
4180 if not update and opts.get(b'no_commit'):
4181 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4181 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4182 if opts.get(b'secret') and opts.get(b'no_commit'):
4182 if opts.get(b'secret') and opts.get(b'no_commit'):
4183 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4183 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4184 try:
4184 try:
4185 sim = float(opts.get(b'similarity') or 0)
4185 sim = float(opts.get(b'similarity') or 0)
4186 except ValueError:
4186 except ValueError:
4187 raise error.Abort(_(b'similarity must be a number'))
4187 raise error.Abort(_(b'similarity must be a number'))
4188 if sim < 0 or sim > 100:
4188 if sim < 0 or sim > 100:
4189 raise error.Abort(_(b'similarity must be between 0 and 100'))
4189 raise error.Abort(_(b'similarity must be between 0 and 100'))
4190 if sim and not update:
4190 if sim and not update:
4191 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4191 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4192 if exact:
4192 if exact:
4193 if opts.get(b'edit'):
4193 if opts.get(b'edit'):
4194 raise error.Abort(_(b'cannot use --exact with --edit'))
4194 raise error.Abort(_(b'cannot use --exact with --edit'))
4195 if opts.get(b'prefix'):
4195 if opts.get(b'prefix'):
4196 raise error.Abort(_(b'cannot use --exact with --prefix'))
4196 raise error.Abort(_(b'cannot use --exact with --prefix'))
4197
4197
4198 base = opts[b"base"]
4198 base = opts[b"base"]
4199 msgs = []
4199 msgs = []
4200 ret = 0
4200 ret = 0
4201
4201
4202 with repo.wlock():
4202 with repo.wlock():
4203 if update:
4203 if update:
4204 cmdutil.checkunfinished(repo)
4204 cmdutil.checkunfinished(repo)
4205 if exact or not opts.get(b'force'):
4205 if exact or not opts.get(b'force'):
4206 cmdutil.bailifchanged(repo)
4206 cmdutil.bailifchanged(repo)
4207
4207
4208 if not opts.get(b'no_commit'):
4208 if not opts.get(b'no_commit'):
4209 lock = repo.lock
4209 lock = repo.lock
4210 tr = lambda: repo.transaction(b'import')
4210 tr = lambda: repo.transaction(b'import')
4211 dsguard = util.nullcontextmanager
4211 dsguard = util.nullcontextmanager
4212 else:
4212 else:
4213 lock = util.nullcontextmanager
4213 lock = util.nullcontextmanager
4214 tr = util.nullcontextmanager
4214 tr = util.nullcontextmanager
4215 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4215 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4216 with lock(), tr(), dsguard():
4216 with lock(), tr(), dsguard():
4217 parents = repo[None].parents()
4217 parents = repo[None].parents()
4218 for patchurl in patches:
4218 for patchurl in patches:
4219 if patchurl == b'-':
4219 if patchurl == b'-':
4220 ui.status(_(b'applying patch from stdin\n'))
4220 ui.status(_(b'applying patch from stdin\n'))
4221 patchfile = ui.fin
4221 patchfile = ui.fin
4222 patchurl = b'stdin' # for error message
4222 patchurl = b'stdin' # for error message
4223 else:
4223 else:
4224 patchurl = os.path.join(base, patchurl)
4224 patchurl = os.path.join(base, patchurl)
4225 ui.status(_(b'applying %s\n') % patchurl)
4225 ui.status(_(b'applying %s\n') % patchurl)
4226 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4226 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4227
4227
4228 haspatch = False
4228 haspatch = False
4229 for hunk in patch.split(patchfile):
4229 for hunk in patch.split(patchfile):
4230 with patch.extract(ui, hunk) as patchdata:
4230 with patch.extract(ui, hunk) as patchdata:
4231 msg, node, rej = cmdutil.tryimportone(
4231 msg, node, rej = cmdutil.tryimportone(
4232 ui, repo, patchdata, parents, opts, msgs, hg.clean
4232 ui, repo, patchdata, parents, opts, msgs, hg.clean
4233 )
4233 )
4234 if msg:
4234 if msg:
4235 haspatch = True
4235 haspatch = True
4236 ui.note(msg + b'\n')
4236 ui.note(msg + b'\n')
4237 if update or exact:
4237 if update or exact:
4238 parents = repo[None].parents()
4238 parents = repo[None].parents()
4239 else:
4239 else:
4240 parents = [repo[node]]
4240 parents = [repo[node]]
4241 if rej:
4241 if rej:
4242 ui.write_err(_(b"patch applied partially\n"))
4242 ui.write_err(_(b"patch applied partially\n"))
4243 ui.write_err(
4243 ui.write_err(
4244 _(
4244 _(
4245 b"(fix the .rej files and run "
4245 b"(fix the .rej files and run "
4246 b"`hg commit --amend`)\n"
4246 b"`hg commit --amend`)\n"
4247 )
4247 )
4248 )
4248 )
4249 ret = 1
4249 ret = 1
4250 break
4250 break
4251
4251
4252 if not haspatch:
4252 if not haspatch:
4253 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4253 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4254
4254
4255 if msgs:
4255 if msgs:
4256 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4256 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4257 return ret
4257 return ret
4258
4258
4259
4259
4260 @command(
4260 @command(
4261 b'incoming|in',
4261 b'incoming|in',
4262 [
4262 [
4263 (
4263 (
4264 b'f',
4264 b'f',
4265 b'force',
4265 b'force',
4266 None,
4266 None,
4267 _(b'run even if remote repository is unrelated'),
4267 _(b'run even if remote repository is unrelated'),
4268 ),
4268 ),
4269 (b'n', b'newest-first', None, _(b'show newest record first')),
4269 (b'n', b'newest-first', None, _(b'show newest record first')),
4270 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4270 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4271 (
4271 (
4272 b'r',
4272 b'r',
4273 b'rev',
4273 b'rev',
4274 [],
4274 [],
4275 _(b'a remote changeset intended to be added'),
4275 _(b'a remote changeset intended to be added'),
4276 _(b'REV'),
4276 _(b'REV'),
4277 ),
4277 ),
4278 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4278 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4279 (
4279 (
4280 b'b',
4280 b'b',
4281 b'branch',
4281 b'branch',
4282 [],
4282 [],
4283 _(b'a specific branch you would like to pull'),
4283 _(b'a specific branch you would like to pull'),
4284 _(b'BRANCH'),
4284 _(b'BRANCH'),
4285 ),
4285 ),
4286 ]
4286 ]
4287 + logopts
4287 + logopts
4288 + remoteopts
4288 + remoteopts
4289 + subrepoopts,
4289 + subrepoopts,
4290 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4290 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4291 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4291 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4292 )
4292 )
4293 def incoming(ui, repo, source=b"default", **opts):
4293 def incoming(ui, repo, source=b"default", **opts):
4294 """show new changesets found in source
4294 """show new changesets found in source
4295
4295
4296 Show new changesets found in the specified path/URL or the default
4296 Show new changesets found in the specified path/URL or the default
4297 pull location. These are the changesets that would have been pulled
4297 pull location. These are the changesets that would have been pulled
4298 by :hg:`pull` at the time you issued this command.
4298 by :hg:`pull` at the time you issued this command.
4299
4299
4300 See pull for valid source format details.
4300 See pull for valid source format details.
4301
4301
4302 .. container:: verbose
4302 .. container:: verbose
4303
4303
4304 With -B/--bookmarks, the result of bookmark comparison between
4304 With -B/--bookmarks, the result of bookmark comparison between
4305 local and remote repositories is displayed. With -v/--verbose,
4305 local and remote repositories is displayed. With -v/--verbose,
4306 status is also displayed for each bookmark like below::
4306 status is also displayed for each bookmark like below::
4307
4307
4308 BM1 01234567890a added
4308 BM1 01234567890a added
4309 BM2 1234567890ab advanced
4309 BM2 1234567890ab advanced
4310 BM3 234567890abc diverged
4310 BM3 234567890abc diverged
4311 BM4 34567890abcd changed
4311 BM4 34567890abcd changed
4312
4312
4313 The action taken locally when pulling depends on the
4313 The action taken locally when pulling depends on the
4314 status of each bookmark:
4314 status of each bookmark:
4315
4315
4316 :``added``: pull will create it
4316 :``added``: pull will create it
4317 :``advanced``: pull will update it
4317 :``advanced``: pull will update it
4318 :``diverged``: pull will create a divergent bookmark
4318 :``diverged``: pull will create a divergent bookmark
4319 :``changed``: result depends on remote changesets
4319 :``changed``: result depends on remote changesets
4320
4320
4321 From the point of view of pulling behavior, bookmark
4321 From the point of view of pulling behavior, bookmark
4322 existing only in the remote repository are treated as ``added``,
4322 existing only in the remote repository are treated as ``added``,
4323 even if it is in fact locally deleted.
4323 even if it is in fact locally deleted.
4324
4324
4325 .. container:: verbose
4325 .. container:: verbose
4326
4326
4327 For remote repository, using --bundle avoids downloading the
4327 For remote repository, using --bundle avoids downloading the
4328 changesets twice if the incoming is followed by a pull.
4328 changesets twice if the incoming is followed by a pull.
4329
4329
4330 Examples:
4330 Examples:
4331
4331
4332 - show incoming changes with patches and full description::
4332 - show incoming changes with patches and full description::
4333
4333
4334 hg incoming -vp
4334 hg incoming -vp
4335
4335
4336 - show incoming changes excluding merges, store a bundle::
4336 - show incoming changes excluding merges, store a bundle::
4337
4337
4338 hg in -vpM --bundle incoming.hg
4338 hg in -vpM --bundle incoming.hg
4339 hg pull incoming.hg
4339 hg pull incoming.hg
4340
4340
4341 - briefly list changes inside a bundle::
4341 - briefly list changes inside a bundle::
4342
4342
4343 hg in changes.hg -T "{desc|firstline}\\n"
4343 hg in changes.hg -T "{desc|firstline}\\n"
4344
4344
4345 Returns 0 if there are incoming changes, 1 otherwise.
4345 Returns 0 if there are incoming changes, 1 otherwise.
4346 """
4346 """
4347 opts = pycompat.byteskwargs(opts)
4347 opts = pycompat.byteskwargs(opts)
4348 if opts.get(b'graph'):
4348 if opts.get(b'graph'):
4349 logcmdutil.checkunsupportedgraphflags([], opts)
4349 logcmdutil.checkunsupportedgraphflags([], opts)
4350
4350
4351 def display(other, chlist, displayer):
4351 def display(other, chlist, displayer):
4352 revdag = logcmdutil.graphrevs(other, chlist, opts)
4352 revdag = logcmdutil.graphrevs(other, chlist, opts)
4353 logcmdutil.displaygraph(
4353 logcmdutil.displaygraph(
4354 ui, repo, revdag, displayer, graphmod.asciiedges
4354 ui, repo, revdag, displayer, graphmod.asciiedges
4355 )
4355 )
4356
4356
4357 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4357 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4358 return 0
4358 return 0
4359
4359
4360 if opts.get(b'bundle') and opts.get(b'subrepos'):
4360 if opts.get(b'bundle') and opts.get(b'subrepos'):
4361 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4361 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4362
4362
4363 if opts.get(b'bookmarks'):
4363 if opts.get(b'bookmarks'):
4364 source, branches = hg.parseurl(
4364 source, branches = hg.parseurl(
4365 ui.expandpath(source), opts.get(b'branch')
4365 ui.expandpath(source), opts.get(b'branch')
4366 )
4366 )
4367 other = hg.peer(repo, opts, source)
4367 other = hg.peer(repo, opts, source)
4368 if b'bookmarks' not in other.listkeys(b'namespaces'):
4368 if b'bookmarks' not in other.listkeys(b'namespaces'):
4369 ui.warn(_(b"remote doesn't support bookmarks\n"))
4369 ui.warn(_(b"remote doesn't support bookmarks\n"))
4370 return 0
4370 return 0
4371 ui.pager(b'incoming')
4371 ui.pager(b'incoming')
4372 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4372 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4373 return bookmarks.incoming(ui, repo, other)
4373 return bookmarks.incoming(ui, repo, other)
4374
4374
4375 repo._subtoppath = ui.expandpath(source)
4375 repo._subtoppath = ui.expandpath(source)
4376 try:
4376 try:
4377 return hg.incoming(ui, repo, source, opts)
4377 return hg.incoming(ui, repo, source, opts)
4378 finally:
4378 finally:
4379 del repo._subtoppath
4379 del repo._subtoppath
4380
4380
4381
4381
4382 @command(
4382 @command(
4383 b'init',
4383 b'init',
4384 remoteopts,
4384 remoteopts,
4385 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4385 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4386 helpcategory=command.CATEGORY_REPO_CREATION,
4386 helpcategory=command.CATEGORY_REPO_CREATION,
4387 helpbasic=True,
4387 helpbasic=True,
4388 norepo=True,
4388 norepo=True,
4389 )
4389 )
4390 def init(ui, dest=b".", **opts):
4390 def init(ui, dest=b".", **opts):
4391 """create a new repository in the given directory
4391 """create a new repository in the given directory
4392
4392
4393 Initialize a new repository in the given directory. If the given
4393 Initialize a new repository in the given directory. If the given
4394 directory does not exist, it will be created.
4394 directory does not exist, it will be created.
4395
4395
4396 If no directory is given, the current directory is used.
4396 If no directory is given, the current directory is used.
4397
4397
4398 It is possible to specify an ``ssh://`` URL as the destination.
4398 It is possible to specify an ``ssh://`` URL as the destination.
4399 See :hg:`help urls` for more information.
4399 See :hg:`help urls` for more information.
4400
4400
4401 Returns 0 on success.
4401 Returns 0 on success.
4402 """
4402 """
4403 opts = pycompat.byteskwargs(opts)
4403 opts = pycompat.byteskwargs(opts)
4404 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4404 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4405
4405
4406
4406
4407 @command(
4407 @command(
4408 b'locate',
4408 b'locate',
4409 [
4409 [
4410 (
4410 (
4411 b'r',
4411 b'r',
4412 b'rev',
4412 b'rev',
4413 b'',
4413 b'',
4414 _(b'search the repository as it is in REV'),
4414 _(b'search the repository as it is in REV'),
4415 _(b'REV'),
4415 _(b'REV'),
4416 ),
4416 ),
4417 (
4417 (
4418 b'0',
4418 b'0',
4419 b'print0',
4419 b'print0',
4420 None,
4420 None,
4421 _(b'end filenames with NUL, for use with xargs'),
4421 _(b'end filenames with NUL, for use with xargs'),
4422 ),
4422 ),
4423 (
4423 (
4424 b'f',
4424 b'f',
4425 b'fullpath',
4425 b'fullpath',
4426 None,
4426 None,
4427 _(b'print complete paths from the filesystem root'),
4427 _(b'print complete paths from the filesystem root'),
4428 ),
4428 ),
4429 ]
4429 ]
4430 + walkopts,
4430 + walkopts,
4431 _(b'[OPTION]... [PATTERN]...'),
4431 _(b'[OPTION]... [PATTERN]...'),
4432 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4432 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4433 )
4433 )
4434 def locate(ui, repo, *pats, **opts):
4434 def locate(ui, repo, *pats, **opts):
4435 """locate files matching specific patterns (DEPRECATED)
4435 """locate files matching specific patterns (DEPRECATED)
4436
4436
4437 Print files under Mercurial control in the working directory whose
4437 Print files under Mercurial control in the working directory whose
4438 names match the given patterns.
4438 names match the given patterns.
4439
4439
4440 By default, this command searches all directories in the working
4440 By default, this command searches all directories in the working
4441 directory. To search just the current directory and its
4441 directory. To search just the current directory and its
4442 subdirectories, use "--include .".
4442 subdirectories, use "--include .".
4443
4443
4444 If no patterns are given to match, this command prints the names
4444 If no patterns are given to match, this command prints the names
4445 of all files under Mercurial control in the working directory.
4445 of all files under Mercurial control in the working directory.
4446
4446
4447 If you want to feed the output of this command into the "xargs"
4447 If you want to feed the output of this command into the "xargs"
4448 command, use the -0 option to both this command and "xargs". This
4448 command, use the -0 option to both this command and "xargs". This
4449 will avoid the problem of "xargs" treating single filenames that
4449 will avoid the problem of "xargs" treating single filenames that
4450 contain whitespace as multiple filenames.
4450 contain whitespace as multiple filenames.
4451
4451
4452 See :hg:`help files` for a more versatile command.
4452 See :hg:`help files` for a more versatile command.
4453
4453
4454 Returns 0 if a match is found, 1 otherwise.
4454 Returns 0 if a match is found, 1 otherwise.
4455 """
4455 """
4456 opts = pycompat.byteskwargs(opts)
4456 opts = pycompat.byteskwargs(opts)
4457 if opts.get(b'print0'):
4457 if opts.get(b'print0'):
4458 end = b'\0'
4458 end = b'\0'
4459 else:
4459 else:
4460 end = b'\n'
4460 end = b'\n'
4461 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4461 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4462
4462
4463 ret = 1
4463 ret = 1
4464 m = scmutil.match(
4464 m = scmutil.match(
4465 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4465 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4466 )
4466 )
4467
4467
4468 ui.pager(b'locate')
4468 ui.pager(b'locate')
4469 if ctx.rev() is None:
4469 if ctx.rev() is None:
4470 # When run on the working copy, "locate" includes removed files, so
4470 # When run on the working copy, "locate" includes removed files, so
4471 # we get the list of files from the dirstate.
4471 # we get the list of files from the dirstate.
4472 filesgen = sorted(repo.dirstate.matches(m))
4472 filesgen = sorted(repo.dirstate.matches(m))
4473 else:
4473 else:
4474 filesgen = ctx.matches(m)
4474 filesgen = ctx.matches(m)
4475 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4475 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4476 for abs in filesgen:
4476 for abs in filesgen:
4477 if opts.get(b'fullpath'):
4477 if opts.get(b'fullpath'):
4478 ui.write(repo.wjoin(abs), end)
4478 ui.write(repo.wjoin(abs), end)
4479 else:
4479 else:
4480 ui.write(uipathfn(abs), end)
4480 ui.write(uipathfn(abs), end)
4481 ret = 0
4481 ret = 0
4482
4482
4483 return ret
4483 return ret
4484
4484
4485
4485
4486 @command(
4486 @command(
4487 b'log|history',
4487 b'log|history',
4488 [
4488 [
4489 (
4489 (
4490 b'f',
4490 b'f',
4491 b'follow',
4491 b'follow',
4492 None,
4492 None,
4493 _(
4493 _(
4494 b'follow changeset history, or file history across copies and renames'
4494 b'follow changeset history, or file history across copies and renames'
4495 ),
4495 ),
4496 ),
4496 ),
4497 (
4497 (
4498 b'',
4498 b'',
4499 b'follow-first',
4499 b'follow-first',
4500 None,
4500 None,
4501 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4501 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4502 ),
4502 ),
4503 (
4503 (
4504 b'd',
4504 b'd',
4505 b'date',
4505 b'date',
4506 b'',
4506 b'',
4507 _(b'show revisions matching date spec'),
4507 _(b'show revisions matching date spec'),
4508 _(b'DATE'),
4508 _(b'DATE'),
4509 ),
4509 ),
4510 (b'C', b'copies', None, _(b'show copied files')),
4510 (b'C', b'copies', None, _(b'show copied files')),
4511 (
4511 (
4512 b'k',
4512 b'k',
4513 b'keyword',
4513 b'keyword',
4514 [],
4514 [],
4515 _(b'do case-insensitive search for a given text'),
4515 _(b'do case-insensitive search for a given text'),
4516 _(b'TEXT'),
4516 _(b'TEXT'),
4517 ),
4517 ),
4518 (
4518 (
4519 b'r',
4519 b'r',
4520 b'rev',
4520 b'rev',
4521 [],
4521 [],
4522 _(b'show the specified revision or revset'),
4522 _(b'show the specified revision or revset'),
4523 _(b'REV'),
4523 _(b'REV'),
4524 ),
4524 ),
4525 (
4525 (
4526 b'L',
4526 b'L',
4527 b'line-range',
4527 b'line-range',
4528 [],
4528 [],
4529 _(b'follow line range of specified file (EXPERIMENTAL)'),
4529 _(b'follow line range of specified file (EXPERIMENTAL)'),
4530 _(b'FILE,RANGE'),
4530 _(b'FILE,RANGE'),
4531 ),
4531 ),
4532 (
4532 (
4533 b'',
4533 b'',
4534 b'removed',
4534 b'removed',
4535 None,
4535 None,
4536 _(b'include revisions where files were removed'),
4536 _(b'include revisions where files were removed'),
4537 ),
4537 ),
4538 (
4538 (
4539 b'm',
4539 b'm',
4540 b'only-merges',
4540 b'only-merges',
4541 None,
4541 None,
4542 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4542 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4543 ),
4543 ),
4544 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4544 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4545 (
4545 (
4546 b'',
4546 b'',
4547 b'only-branch',
4547 b'only-branch',
4548 [],
4548 [],
4549 _(
4549 _(
4550 b'show only changesets within the given named branch (DEPRECATED)'
4550 b'show only changesets within the given named branch (DEPRECATED)'
4551 ),
4551 ),
4552 _(b'BRANCH'),
4552 _(b'BRANCH'),
4553 ),
4553 ),
4554 (
4554 (
4555 b'b',
4555 b'b',
4556 b'branch',
4556 b'branch',
4557 [],
4557 [],
4558 _(b'show changesets within the given named branch'),
4558 _(b'show changesets within the given named branch'),
4559 _(b'BRANCH'),
4559 _(b'BRANCH'),
4560 ),
4560 ),
4561 (
4561 (
4562 b'P',
4562 b'P',
4563 b'prune',
4563 b'prune',
4564 [],
4564 [],
4565 _(b'do not display revision or any of its ancestors'),
4565 _(b'do not display revision or any of its ancestors'),
4566 _(b'REV'),
4566 _(b'REV'),
4567 ),
4567 ),
4568 ]
4568 ]
4569 + logopts
4569 + logopts
4570 + walkopts,
4570 + walkopts,
4571 _(b'[OPTION]... [FILE]'),
4571 _(b'[OPTION]... [FILE]'),
4572 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4572 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4573 helpbasic=True,
4573 helpbasic=True,
4574 inferrepo=True,
4574 inferrepo=True,
4575 intents={INTENT_READONLY},
4575 intents={INTENT_READONLY},
4576 )
4576 )
4577 def log(ui, repo, *pats, **opts):
4577 def log(ui, repo, *pats, **opts):
4578 """show revision history of entire repository or files
4578 """show revision history of entire repository or files
4579
4579
4580 Print the revision history of the specified files or the entire
4580 Print the revision history of the specified files or the entire
4581 project.
4581 project.
4582
4582
4583 If no revision range is specified, the default is ``tip:0`` unless
4583 If no revision range is specified, the default is ``tip:0`` unless
4584 --follow is set, in which case the working directory parent is
4584 --follow is set, in which case the working directory parent is
4585 used as the starting revision.
4585 used as the starting revision.
4586
4586
4587 File history is shown without following rename or copy history of
4587 File history is shown without following rename or copy history of
4588 files. Use -f/--follow with a filename to follow history across
4588 files. Use -f/--follow with a filename to follow history across
4589 renames and copies. --follow without a filename will only show
4589 renames and copies. --follow without a filename will only show
4590 ancestors of the starting revision.
4590 ancestors of the starting revision.
4591
4591
4592 By default this command prints revision number and changeset id,
4592 By default this command prints revision number and changeset id,
4593 tags, non-trivial parents, user, date and time, and a summary for
4593 tags, non-trivial parents, user, date and time, and a summary for
4594 each commit. When the -v/--verbose switch is used, the list of
4594 each commit. When the -v/--verbose switch is used, the list of
4595 changed files and full commit message are shown.
4595 changed files and full commit message are shown.
4596
4596
4597 With --graph the revisions are shown as an ASCII art DAG with the most
4597 With --graph the revisions are shown as an ASCII art DAG with the most
4598 recent changeset at the top.
4598 recent changeset at the top.
4599 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4599 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4600 involved in an unresolved merge conflict, '_' closes a branch,
4600 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4601 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4601 changeset from the lines below is a parent of the 'o' merge on the same
4602 changeset from the lines below is a parent of the 'o' merge on the same
4602 line.
4603 line.
4603 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4604 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4604 of a '|' indicates one or more revisions in a path are omitted.
4605 of a '|' indicates one or more revisions in a path are omitted.
4605
4606
4606 .. container:: verbose
4607 .. container:: verbose
4607
4608
4608 Use -L/--line-range FILE,M:N options to follow the history of lines
4609 Use -L/--line-range FILE,M:N options to follow the history of lines
4609 from M to N in FILE. With -p/--patch only diff hunks affecting
4610 from M to N in FILE. With -p/--patch only diff hunks affecting
4610 specified line range will be shown. This option requires --follow;
4611 specified line range will be shown. This option requires --follow;
4611 it can be specified multiple times. Currently, this option is not
4612 it can be specified multiple times. Currently, this option is not
4612 compatible with --graph. This option is experimental.
4613 compatible with --graph. This option is experimental.
4613
4614
4614 .. note::
4615 .. note::
4615
4616
4616 :hg:`log --patch` may generate unexpected diff output for merge
4617 :hg:`log --patch` may generate unexpected diff output for merge
4617 changesets, as it will only compare the merge changeset against
4618 changesets, as it will only compare the merge changeset against
4618 its first parent. Also, only files different from BOTH parents
4619 its first parent. Also, only files different from BOTH parents
4619 will appear in files:.
4620 will appear in files:.
4620
4621
4621 .. note::
4622 .. note::
4622
4623
4623 For performance reasons, :hg:`log FILE` may omit duplicate changes
4624 For performance reasons, :hg:`log FILE` may omit duplicate changes
4624 made on branches and will not show removals or mode changes. To
4625 made on branches and will not show removals or mode changes. To
4625 see all such changes, use the --removed switch.
4626 see all such changes, use the --removed switch.
4626
4627
4627 .. container:: verbose
4628 .. container:: verbose
4628
4629
4629 .. note::
4630 .. note::
4630
4631
4631 The history resulting from -L/--line-range options depends on diff
4632 The history resulting from -L/--line-range options depends on diff
4632 options; for instance if white-spaces are ignored, respective changes
4633 options; for instance if white-spaces are ignored, respective changes
4633 with only white-spaces in specified line range will not be listed.
4634 with only white-spaces in specified line range will not be listed.
4634
4635
4635 .. container:: verbose
4636 .. container:: verbose
4636
4637
4637 Some examples:
4638 Some examples:
4638
4639
4639 - changesets with full descriptions and file lists::
4640 - changesets with full descriptions and file lists::
4640
4641
4641 hg log -v
4642 hg log -v
4642
4643
4643 - changesets ancestral to the working directory::
4644 - changesets ancestral to the working directory::
4644
4645
4645 hg log -f
4646 hg log -f
4646
4647
4647 - last 10 commits on the current branch::
4648 - last 10 commits on the current branch::
4648
4649
4649 hg log -l 10 -b .
4650 hg log -l 10 -b .
4650
4651
4651 - changesets showing all modifications of a file, including removals::
4652 - changesets showing all modifications of a file, including removals::
4652
4653
4653 hg log --removed file.c
4654 hg log --removed file.c
4654
4655
4655 - all changesets that touch a directory, with diffs, excluding merges::
4656 - all changesets that touch a directory, with diffs, excluding merges::
4656
4657
4657 hg log -Mp lib/
4658 hg log -Mp lib/
4658
4659
4659 - all revision numbers that match a keyword::
4660 - all revision numbers that match a keyword::
4660
4661
4661 hg log -k bug --template "{rev}\\n"
4662 hg log -k bug --template "{rev}\\n"
4662
4663
4663 - the full hash identifier of the working directory parent::
4664 - the full hash identifier of the working directory parent::
4664
4665
4665 hg log -r . --template "{node}\\n"
4666 hg log -r . --template "{node}\\n"
4666
4667
4667 - list available log templates::
4668 - list available log templates::
4668
4669
4669 hg log -T list
4670 hg log -T list
4670
4671
4671 - check if a given changeset is included in a tagged release::
4672 - check if a given changeset is included in a tagged release::
4672
4673
4673 hg log -r "a21ccf and ancestor(1.9)"
4674 hg log -r "a21ccf and ancestor(1.9)"
4674
4675
4675 - find all changesets by some user in a date range::
4676 - find all changesets by some user in a date range::
4676
4677
4677 hg log -k alice -d "may 2008 to jul 2008"
4678 hg log -k alice -d "may 2008 to jul 2008"
4678
4679
4679 - summary of all changesets after the last tag::
4680 - summary of all changesets after the last tag::
4680
4681
4681 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4682 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4682
4683
4683 - changesets touching lines 13 to 23 for file.c::
4684 - changesets touching lines 13 to 23 for file.c::
4684
4685
4685 hg log -L file.c,13:23
4686 hg log -L file.c,13:23
4686
4687
4687 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4688 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4688 main.c with patch::
4689 main.c with patch::
4689
4690
4690 hg log -L file.c,13:23 -L main.c,2:6 -p
4691 hg log -L file.c,13:23 -L main.c,2:6 -p
4691
4692
4692 See :hg:`help dates` for a list of formats valid for -d/--date.
4693 See :hg:`help dates` for a list of formats valid for -d/--date.
4693
4694
4694 See :hg:`help revisions` for more about specifying and ordering
4695 See :hg:`help revisions` for more about specifying and ordering
4695 revisions.
4696 revisions.
4696
4697
4697 See :hg:`help templates` for more about pre-packaged styles and
4698 See :hg:`help templates` for more about pre-packaged styles and
4698 specifying custom templates. The default template used by the log
4699 specifying custom templates. The default template used by the log
4699 command can be customized via the ``ui.logtemplate`` configuration
4700 command can be customized via the ``ui.logtemplate`` configuration
4700 setting.
4701 setting.
4701
4702
4702 Returns 0 on success.
4703 Returns 0 on success.
4703
4704
4704 """
4705 """
4705 opts = pycompat.byteskwargs(opts)
4706 opts = pycompat.byteskwargs(opts)
4706 linerange = opts.get(b'line_range')
4707 linerange = opts.get(b'line_range')
4707
4708
4708 if linerange and not opts.get(b'follow'):
4709 if linerange and not opts.get(b'follow'):
4709 raise error.Abort(_(b'--line-range requires --follow'))
4710 raise error.Abort(_(b'--line-range requires --follow'))
4710
4711
4711 if linerange and pats:
4712 if linerange and pats:
4712 # TODO: take pats as patterns with no line-range filter
4713 # TODO: take pats as patterns with no line-range filter
4713 raise error.Abort(
4714 raise error.Abort(
4714 _(b'FILE arguments are not compatible with --line-range option')
4715 _(b'FILE arguments are not compatible with --line-range option')
4715 )
4716 )
4716
4717
4717 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4718 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4718 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4719 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4719 if linerange:
4720 if linerange:
4720 # TODO: should follow file history from logcmdutil._initialrevs(),
4721 # TODO: should follow file history from logcmdutil._initialrevs(),
4721 # then filter the result by logcmdutil._makerevset() and --limit
4722 # then filter the result by logcmdutil._makerevset() and --limit
4722 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4723 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4723
4724
4724 getcopies = None
4725 getcopies = None
4725 if opts.get(b'copies'):
4726 if opts.get(b'copies'):
4726 endrev = None
4727 endrev = None
4727 if revs:
4728 if revs:
4728 endrev = revs.max() + 1
4729 endrev = revs.max() + 1
4729 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4730 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4730
4731
4731 ui.pager(b'log')
4732 ui.pager(b'log')
4732 displayer = logcmdutil.changesetdisplayer(
4733 displayer = logcmdutil.changesetdisplayer(
4733 ui, repo, opts, differ, buffered=True
4734 ui, repo, opts, differ, buffered=True
4734 )
4735 )
4735 if opts.get(b'graph'):
4736 if opts.get(b'graph'):
4736 displayfn = logcmdutil.displaygraphrevs
4737 displayfn = logcmdutil.displaygraphrevs
4737 else:
4738 else:
4738 displayfn = logcmdutil.displayrevs
4739 displayfn = logcmdutil.displayrevs
4739 displayfn(ui, repo, revs, displayer, getcopies)
4740 displayfn(ui, repo, revs, displayer, getcopies)
4740
4741
4741
4742
4742 @command(
4743 @command(
4743 b'manifest',
4744 b'manifest',
4744 [
4745 [
4745 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4746 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4746 (b'', b'all', False, _(b"list files from all revisions")),
4747 (b'', b'all', False, _(b"list files from all revisions")),
4747 ]
4748 ]
4748 + formatteropts,
4749 + formatteropts,
4749 _(b'[-r REV]'),
4750 _(b'[-r REV]'),
4750 helpcategory=command.CATEGORY_MAINTENANCE,
4751 helpcategory=command.CATEGORY_MAINTENANCE,
4751 intents={INTENT_READONLY},
4752 intents={INTENT_READONLY},
4752 )
4753 )
4753 def manifest(ui, repo, node=None, rev=None, **opts):
4754 def manifest(ui, repo, node=None, rev=None, **opts):
4754 """output the current or given revision of the project manifest
4755 """output the current or given revision of the project manifest
4755
4756
4756 Print a list of version controlled files for the given revision.
4757 Print a list of version controlled files for the given revision.
4757 If no revision is given, the first parent of the working directory
4758 If no revision is given, the first parent of the working directory
4758 is used, or the null revision if no revision is checked out.
4759 is used, or the null revision if no revision is checked out.
4759
4760
4760 With -v, print file permissions, symlink and executable bits.
4761 With -v, print file permissions, symlink and executable bits.
4761 With --debug, print file revision hashes.
4762 With --debug, print file revision hashes.
4762
4763
4763 If option --all is specified, the list of all files from all revisions
4764 If option --all is specified, the list of all files from all revisions
4764 is printed. This includes deleted and renamed files.
4765 is printed. This includes deleted and renamed files.
4765
4766
4766 Returns 0 on success.
4767 Returns 0 on success.
4767 """
4768 """
4768 opts = pycompat.byteskwargs(opts)
4769 opts = pycompat.byteskwargs(opts)
4769 fm = ui.formatter(b'manifest', opts)
4770 fm = ui.formatter(b'manifest', opts)
4770
4771
4771 if opts.get(b'all'):
4772 if opts.get(b'all'):
4772 if rev or node:
4773 if rev or node:
4773 raise error.Abort(_(b"can't specify a revision with --all"))
4774 raise error.Abort(_(b"can't specify a revision with --all"))
4774
4775
4775 res = set()
4776 res = set()
4776 for rev in repo:
4777 for rev in repo:
4777 ctx = repo[rev]
4778 ctx = repo[rev]
4778 res |= set(ctx.files())
4779 res |= set(ctx.files())
4779
4780
4780 ui.pager(b'manifest')
4781 ui.pager(b'manifest')
4781 for f in sorted(res):
4782 for f in sorted(res):
4782 fm.startitem()
4783 fm.startitem()
4783 fm.write(b"path", b'%s\n', f)
4784 fm.write(b"path", b'%s\n', f)
4784 fm.end()
4785 fm.end()
4785 return
4786 return
4786
4787
4787 if rev and node:
4788 if rev and node:
4788 raise error.Abort(_(b"please specify just one revision"))
4789 raise error.Abort(_(b"please specify just one revision"))
4789
4790
4790 if not node:
4791 if not node:
4791 node = rev
4792 node = rev
4792
4793
4793 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4794 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4794 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4795 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4795 if node:
4796 if node:
4796 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4797 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4797 ctx = scmutil.revsingle(repo, node)
4798 ctx = scmutil.revsingle(repo, node)
4798 mf = ctx.manifest()
4799 mf = ctx.manifest()
4799 ui.pager(b'manifest')
4800 ui.pager(b'manifest')
4800 for f in ctx:
4801 for f in ctx:
4801 fm.startitem()
4802 fm.startitem()
4802 fm.context(ctx=ctx)
4803 fm.context(ctx=ctx)
4803 fl = ctx[f].flags()
4804 fl = ctx[f].flags()
4804 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4805 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4805 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4806 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4806 fm.write(b'path', b'%s\n', f)
4807 fm.write(b'path', b'%s\n', f)
4807 fm.end()
4808 fm.end()
4808
4809
4809
4810
4810 @command(
4811 @command(
4811 b'merge',
4812 b'merge',
4812 [
4813 [
4813 (
4814 (
4814 b'f',
4815 b'f',
4815 b'force',
4816 b'force',
4816 None,
4817 None,
4817 _(b'force a merge including outstanding changes (DEPRECATED)'),
4818 _(b'force a merge including outstanding changes (DEPRECATED)'),
4818 ),
4819 ),
4819 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4820 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4820 (
4821 (
4821 b'P',
4822 b'P',
4822 b'preview',
4823 b'preview',
4823 None,
4824 None,
4824 _(b'review revisions to merge (no merge is performed)'),
4825 _(b'review revisions to merge (no merge is performed)'),
4825 ),
4826 ),
4826 (b'', b'abort', None, _(b'abort the ongoing merge')),
4827 (b'', b'abort', None, _(b'abort the ongoing merge')),
4827 ]
4828 ]
4828 + mergetoolopts,
4829 + mergetoolopts,
4829 _(b'[-P] [[-r] REV]'),
4830 _(b'[-P] [[-r] REV]'),
4830 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4831 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4831 helpbasic=True,
4832 helpbasic=True,
4832 )
4833 )
4833 def merge(ui, repo, node=None, **opts):
4834 def merge(ui, repo, node=None, **opts):
4834 """merge another revision into working directory
4835 """merge another revision into working directory
4835
4836
4836 The current working directory is updated with all changes made in
4837 The current working directory is updated with all changes made in
4837 the requested revision since the last common predecessor revision.
4838 the requested revision since the last common predecessor revision.
4838
4839
4839 Files that changed between either parent are marked as changed for
4840 Files that changed between either parent are marked as changed for
4840 the next commit and a commit must be performed before any further
4841 the next commit and a commit must be performed before any further
4841 updates to the repository are allowed. The next commit will have
4842 updates to the repository are allowed. The next commit will have
4842 two parents.
4843 two parents.
4843
4844
4844 ``--tool`` can be used to specify the merge tool used for file
4845 ``--tool`` can be used to specify the merge tool used for file
4845 merges. It overrides the HGMERGE environment variable and your
4846 merges. It overrides the HGMERGE environment variable and your
4846 configuration files. See :hg:`help merge-tools` for options.
4847 configuration files. See :hg:`help merge-tools` for options.
4847
4848
4848 If no revision is specified, the working directory's parent is a
4849 If no revision is specified, the working directory's parent is a
4849 head revision, and the current branch contains exactly one other
4850 head revision, and the current branch contains exactly one other
4850 head, the other head is merged with by default. Otherwise, an
4851 head, the other head is merged with by default. Otherwise, an
4851 explicit revision with which to merge must be provided.
4852 explicit revision with which to merge must be provided.
4852
4853
4853 See :hg:`help resolve` for information on handling file conflicts.
4854 See :hg:`help resolve` for information on handling file conflicts.
4854
4855
4855 To undo an uncommitted merge, use :hg:`merge --abort` which
4856 To undo an uncommitted merge, use :hg:`merge --abort` which
4856 will check out a clean copy of the original merge parent, losing
4857 will check out a clean copy of the original merge parent, losing
4857 all changes.
4858 all changes.
4858
4859
4859 Returns 0 on success, 1 if there are unresolved files.
4860 Returns 0 on success, 1 if there are unresolved files.
4860 """
4861 """
4861
4862
4862 opts = pycompat.byteskwargs(opts)
4863 opts = pycompat.byteskwargs(opts)
4863 abort = opts.get(b'abort')
4864 abort = opts.get(b'abort')
4864 if abort and repo.dirstate.p2() == nullid:
4865 if abort and repo.dirstate.p2() == nullid:
4865 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4866 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4866 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4867 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4867 if abort:
4868 if abort:
4868 state = cmdutil.getunfinishedstate(repo)
4869 state = cmdutil.getunfinishedstate(repo)
4869 if state and state._opname != b'merge':
4870 if state and state._opname != b'merge':
4870 raise error.Abort(
4871 raise error.Abort(
4871 _(b'cannot abort merge with %s in progress') % (state._opname),
4872 _(b'cannot abort merge with %s in progress') % (state._opname),
4872 hint=state.hint(),
4873 hint=state.hint(),
4873 )
4874 )
4874 if node:
4875 if node:
4875 raise error.Abort(_(b"cannot specify a node with --abort"))
4876 raise error.Abort(_(b"cannot specify a node with --abort"))
4876 return hg.abortmerge(repo.ui, repo)
4877 return hg.abortmerge(repo.ui, repo)
4877
4878
4878 if opts.get(b'rev') and node:
4879 if opts.get(b'rev') and node:
4879 raise error.Abort(_(b"please specify just one revision"))
4880 raise error.Abort(_(b"please specify just one revision"))
4880 if not node:
4881 if not node:
4881 node = opts.get(b'rev')
4882 node = opts.get(b'rev')
4882
4883
4883 if node:
4884 if node:
4884 ctx = scmutil.revsingle(repo, node)
4885 ctx = scmutil.revsingle(repo, node)
4885 else:
4886 else:
4886 if ui.configbool(b'commands', b'merge.require-rev'):
4887 if ui.configbool(b'commands', b'merge.require-rev'):
4887 raise error.Abort(
4888 raise error.Abort(
4888 _(
4889 _(
4889 b'configuration requires specifying revision to merge '
4890 b'configuration requires specifying revision to merge '
4890 b'with'
4891 b'with'
4891 )
4892 )
4892 )
4893 )
4893 ctx = repo[destutil.destmerge(repo)]
4894 ctx = repo[destutil.destmerge(repo)]
4894
4895
4895 if ctx.node() is None:
4896 if ctx.node() is None:
4896 raise error.Abort(_(b'merging with the working copy has no effect'))
4897 raise error.Abort(_(b'merging with the working copy has no effect'))
4897
4898
4898 if opts.get(b'preview'):
4899 if opts.get(b'preview'):
4899 # find nodes that are ancestors of p2 but not of p1
4900 # find nodes that are ancestors of p2 but not of p1
4900 p1 = repo[b'.'].node()
4901 p1 = repo[b'.'].node()
4901 p2 = ctx.node()
4902 p2 = ctx.node()
4902 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4903 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4903
4904
4904 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4905 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4905 for node in nodes:
4906 for node in nodes:
4906 displayer.show(repo[node])
4907 displayer.show(repo[node])
4907 displayer.close()
4908 displayer.close()
4908 return 0
4909 return 0
4909
4910
4910 # ui.forcemerge is an internal variable, do not document
4911 # ui.forcemerge is an internal variable, do not document
4911 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4912 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4912 with ui.configoverride(overrides, b'merge'):
4913 with ui.configoverride(overrides, b'merge'):
4913 force = opts.get(b'force')
4914 force = opts.get(b'force')
4914 labels = [b'working copy', b'merge rev']
4915 labels = [b'working copy', b'merge rev']
4915 return hg.merge(ctx, force=force, labels=labels)
4916 return hg.merge(ctx, force=force, labels=labels)
4916
4917
4917
4918
4918 statemod.addunfinished(
4919 statemod.addunfinished(
4919 b'merge',
4920 b'merge',
4920 fname=None,
4921 fname=None,
4921 clearable=True,
4922 clearable=True,
4922 allowcommit=True,
4923 allowcommit=True,
4923 cmdmsg=_(b'outstanding uncommitted merge'),
4924 cmdmsg=_(b'outstanding uncommitted merge'),
4924 abortfunc=hg.abortmerge,
4925 abortfunc=hg.abortmerge,
4925 statushint=_(
4926 statushint=_(
4926 b'To continue: hg commit\nTo abort: hg merge --abort'
4927 b'To continue: hg commit\nTo abort: hg merge --abort'
4927 ),
4928 ),
4928 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4929 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4929 )
4930 )
4930
4931
4931
4932
4932 @command(
4933 @command(
4933 b'outgoing|out',
4934 b'outgoing|out',
4934 [
4935 [
4935 (
4936 (
4936 b'f',
4937 b'f',
4937 b'force',
4938 b'force',
4938 None,
4939 None,
4939 _(b'run even when the destination is unrelated'),
4940 _(b'run even when the destination is unrelated'),
4940 ),
4941 ),
4941 (
4942 (
4942 b'r',
4943 b'r',
4943 b'rev',
4944 b'rev',
4944 [],
4945 [],
4945 _(b'a changeset intended to be included in the destination'),
4946 _(b'a changeset intended to be included in the destination'),
4946 _(b'REV'),
4947 _(b'REV'),
4947 ),
4948 ),
4948 (b'n', b'newest-first', None, _(b'show newest record first')),
4949 (b'n', b'newest-first', None, _(b'show newest record first')),
4949 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4950 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4950 (
4951 (
4951 b'b',
4952 b'b',
4952 b'branch',
4953 b'branch',
4953 [],
4954 [],
4954 _(b'a specific branch you would like to push'),
4955 _(b'a specific branch you would like to push'),
4955 _(b'BRANCH'),
4956 _(b'BRANCH'),
4956 ),
4957 ),
4957 ]
4958 ]
4958 + logopts
4959 + logopts
4959 + remoteopts
4960 + remoteopts
4960 + subrepoopts,
4961 + subrepoopts,
4961 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4962 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4962 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4963 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4963 )
4964 )
4964 def outgoing(ui, repo, dest=None, **opts):
4965 def outgoing(ui, repo, dest=None, **opts):
4965 """show changesets not found in the destination
4966 """show changesets not found in the destination
4966
4967
4967 Show changesets not found in the specified destination repository
4968 Show changesets not found in the specified destination repository
4968 or the default push location. These are the changesets that would
4969 or the default push location. These are the changesets that would
4969 be pushed if a push was requested.
4970 be pushed if a push was requested.
4970
4971
4971 See pull for details of valid destination formats.
4972 See pull for details of valid destination formats.
4972
4973
4973 .. container:: verbose
4974 .. container:: verbose
4974
4975
4975 With -B/--bookmarks, the result of bookmark comparison between
4976 With -B/--bookmarks, the result of bookmark comparison between
4976 local and remote repositories is displayed. With -v/--verbose,
4977 local and remote repositories is displayed. With -v/--verbose,
4977 status is also displayed for each bookmark like below::
4978 status is also displayed for each bookmark like below::
4978
4979
4979 BM1 01234567890a added
4980 BM1 01234567890a added
4980 BM2 deleted
4981 BM2 deleted
4981 BM3 234567890abc advanced
4982 BM3 234567890abc advanced
4982 BM4 34567890abcd diverged
4983 BM4 34567890abcd diverged
4983 BM5 4567890abcde changed
4984 BM5 4567890abcde changed
4984
4985
4985 The action taken when pushing depends on the
4986 The action taken when pushing depends on the
4986 status of each bookmark:
4987 status of each bookmark:
4987
4988
4988 :``added``: push with ``-B`` will create it
4989 :``added``: push with ``-B`` will create it
4989 :``deleted``: push with ``-B`` will delete it
4990 :``deleted``: push with ``-B`` will delete it
4990 :``advanced``: push will update it
4991 :``advanced``: push will update it
4991 :``diverged``: push with ``-B`` will update it
4992 :``diverged``: push with ``-B`` will update it
4992 :``changed``: push with ``-B`` will update it
4993 :``changed``: push with ``-B`` will update it
4993
4994
4994 From the point of view of pushing behavior, bookmarks
4995 From the point of view of pushing behavior, bookmarks
4995 existing only in the remote repository are treated as
4996 existing only in the remote repository are treated as
4996 ``deleted``, even if it is in fact added remotely.
4997 ``deleted``, even if it is in fact added remotely.
4997
4998
4998 Returns 0 if there are outgoing changes, 1 otherwise.
4999 Returns 0 if there are outgoing changes, 1 otherwise.
4999 """
5000 """
5000 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5001 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5001 # style URLs, so don't overwrite dest.
5002 # style URLs, so don't overwrite dest.
5002 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5003 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5003 if not path:
5004 if not path:
5004 raise error.Abort(
5005 raise error.Abort(
5005 _(b'default repository not configured!'),
5006 _(b'default repository not configured!'),
5006 hint=_(b"see 'hg help config.paths'"),
5007 hint=_(b"see 'hg help config.paths'"),
5007 )
5008 )
5008
5009
5009 opts = pycompat.byteskwargs(opts)
5010 opts = pycompat.byteskwargs(opts)
5010 if opts.get(b'graph'):
5011 if opts.get(b'graph'):
5011 logcmdutil.checkunsupportedgraphflags([], opts)
5012 logcmdutil.checkunsupportedgraphflags([], opts)
5012 o, other = hg._outgoing(ui, repo, dest, opts)
5013 o, other = hg._outgoing(ui, repo, dest, opts)
5013 if not o:
5014 if not o:
5014 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5015 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5015 return
5016 return
5016
5017
5017 revdag = logcmdutil.graphrevs(repo, o, opts)
5018 revdag = logcmdutil.graphrevs(repo, o, opts)
5018 ui.pager(b'outgoing')
5019 ui.pager(b'outgoing')
5019 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5020 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5020 logcmdutil.displaygraph(
5021 logcmdutil.displaygraph(
5021 ui, repo, revdag, displayer, graphmod.asciiedges
5022 ui, repo, revdag, displayer, graphmod.asciiedges
5022 )
5023 )
5023 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5024 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5024 return 0
5025 return 0
5025
5026
5026 if opts.get(b'bookmarks'):
5027 if opts.get(b'bookmarks'):
5027 dest = path.pushloc or path.loc
5028 dest = path.pushloc or path.loc
5028 other = hg.peer(repo, opts, dest)
5029 other = hg.peer(repo, opts, dest)
5029 if b'bookmarks' not in other.listkeys(b'namespaces'):
5030 if b'bookmarks' not in other.listkeys(b'namespaces'):
5030 ui.warn(_(b"remote doesn't support bookmarks\n"))
5031 ui.warn(_(b"remote doesn't support bookmarks\n"))
5031 return 0
5032 return 0
5032 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5033 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5033 ui.pager(b'outgoing')
5034 ui.pager(b'outgoing')
5034 return bookmarks.outgoing(ui, repo, other)
5035 return bookmarks.outgoing(ui, repo, other)
5035
5036
5036 repo._subtoppath = path.pushloc or path.loc
5037 repo._subtoppath = path.pushloc or path.loc
5037 try:
5038 try:
5038 return hg.outgoing(ui, repo, dest, opts)
5039 return hg.outgoing(ui, repo, dest, opts)
5039 finally:
5040 finally:
5040 del repo._subtoppath
5041 del repo._subtoppath
5041
5042
5042
5043
5043 @command(
5044 @command(
5044 b'parents',
5045 b'parents',
5045 [
5046 [
5046 (
5047 (
5047 b'r',
5048 b'r',
5048 b'rev',
5049 b'rev',
5049 b'',
5050 b'',
5050 _(b'show parents of the specified revision'),
5051 _(b'show parents of the specified revision'),
5051 _(b'REV'),
5052 _(b'REV'),
5052 ),
5053 ),
5053 ]
5054 ]
5054 + templateopts,
5055 + templateopts,
5055 _(b'[-r REV] [FILE]'),
5056 _(b'[-r REV] [FILE]'),
5056 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5057 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5057 inferrepo=True,
5058 inferrepo=True,
5058 )
5059 )
5059 def parents(ui, repo, file_=None, **opts):
5060 def parents(ui, repo, file_=None, **opts):
5060 """show the parents of the working directory or revision (DEPRECATED)
5061 """show the parents of the working directory or revision (DEPRECATED)
5061
5062
5062 Print the working directory's parent revisions. If a revision is
5063 Print the working directory's parent revisions. If a revision is
5063 given via -r/--rev, the parent of that revision will be printed.
5064 given via -r/--rev, the parent of that revision will be printed.
5064 If a file argument is given, the revision in which the file was
5065 If a file argument is given, the revision in which the file was
5065 last changed (before the working directory revision or the
5066 last changed (before the working directory revision or the
5066 argument to --rev if given) is printed.
5067 argument to --rev if given) is printed.
5067
5068
5068 This command is equivalent to::
5069 This command is equivalent to::
5069
5070
5070 hg log -r "p1()+p2()" or
5071 hg log -r "p1()+p2()" or
5071 hg log -r "p1(REV)+p2(REV)" or
5072 hg log -r "p1(REV)+p2(REV)" or
5072 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5073 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5073 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5074 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5074
5075
5075 See :hg:`summary` and :hg:`help revsets` for related information.
5076 See :hg:`summary` and :hg:`help revsets` for related information.
5076
5077
5077 Returns 0 on success.
5078 Returns 0 on success.
5078 """
5079 """
5079
5080
5080 opts = pycompat.byteskwargs(opts)
5081 opts = pycompat.byteskwargs(opts)
5081 rev = opts.get(b'rev')
5082 rev = opts.get(b'rev')
5082 if rev:
5083 if rev:
5083 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5084 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5084 ctx = scmutil.revsingle(repo, rev, None)
5085 ctx = scmutil.revsingle(repo, rev, None)
5085
5086
5086 if file_:
5087 if file_:
5087 m = scmutil.match(ctx, (file_,), opts)
5088 m = scmutil.match(ctx, (file_,), opts)
5088 if m.anypats() or len(m.files()) != 1:
5089 if m.anypats() or len(m.files()) != 1:
5089 raise error.Abort(_(b'can only specify an explicit filename'))
5090 raise error.Abort(_(b'can only specify an explicit filename'))
5090 file_ = m.files()[0]
5091 file_ = m.files()[0]
5091 filenodes = []
5092 filenodes = []
5092 for cp in ctx.parents():
5093 for cp in ctx.parents():
5093 if not cp:
5094 if not cp:
5094 continue
5095 continue
5095 try:
5096 try:
5096 filenodes.append(cp.filenode(file_))
5097 filenodes.append(cp.filenode(file_))
5097 except error.LookupError:
5098 except error.LookupError:
5098 pass
5099 pass
5099 if not filenodes:
5100 if not filenodes:
5100 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5101 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5101 p = []
5102 p = []
5102 for fn in filenodes:
5103 for fn in filenodes:
5103 fctx = repo.filectx(file_, fileid=fn)
5104 fctx = repo.filectx(file_, fileid=fn)
5104 p.append(fctx.node())
5105 p.append(fctx.node())
5105 else:
5106 else:
5106 p = [cp.node() for cp in ctx.parents()]
5107 p = [cp.node() for cp in ctx.parents()]
5107
5108
5108 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5109 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5109 for n in p:
5110 for n in p:
5110 if n != nullid:
5111 if n != nullid:
5111 displayer.show(repo[n])
5112 displayer.show(repo[n])
5112 displayer.close()
5113 displayer.close()
5113
5114
5114
5115
5115 @command(
5116 @command(
5116 b'paths',
5117 b'paths',
5117 formatteropts,
5118 formatteropts,
5118 _(b'[NAME]'),
5119 _(b'[NAME]'),
5119 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5120 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5120 optionalrepo=True,
5121 optionalrepo=True,
5121 intents={INTENT_READONLY},
5122 intents={INTENT_READONLY},
5122 )
5123 )
5123 def paths(ui, repo, search=None, **opts):
5124 def paths(ui, repo, search=None, **opts):
5124 """show aliases for remote repositories
5125 """show aliases for remote repositories
5125
5126
5126 Show definition of symbolic path name NAME. If no name is given,
5127 Show definition of symbolic path name NAME. If no name is given,
5127 show definition of all available names.
5128 show definition of all available names.
5128
5129
5129 Option -q/--quiet suppresses all output when searching for NAME
5130 Option -q/--quiet suppresses all output when searching for NAME
5130 and shows only the path names when listing all definitions.
5131 and shows only the path names when listing all definitions.
5131
5132
5132 Path names are defined in the [paths] section of your
5133 Path names are defined in the [paths] section of your
5133 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5134 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5134 repository, ``.hg/hgrc`` is used, too.
5135 repository, ``.hg/hgrc`` is used, too.
5135
5136
5136 The path names ``default`` and ``default-push`` have a special
5137 The path names ``default`` and ``default-push`` have a special
5137 meaning. When performing a push or pull operation, they are used
5138 meaning. When performing a push or pull operation, they are used
5138 as fallbacks if no location is specified on the command-line.
5139 as fallbacks if no location is specified on the command-line.
5139 When ``default-push`` is set, it will be used for push and
5140 When ``default-push`` is set, it will be used for push and
5140 ``default`` will be used for pull; otherwise ``default`` is used
5141 ``default`` will be used for pull; otherwise ``default`` is used
5141 as the fallback for both. When cloning a repository, the clone
5142 as the fallback for both. When cloning a repository, the clone
5142 source is written as ``default`` in ``.hg/hgrc``.
5143 source is written as ``default`` in ``.hg/hgrc``.
5143
5144
5144 .. note::
5145 .. note::
5145
5146
5146 ``default`` and ``default-push`` apply to all inbound (e.g.
5147 ``default`` and ``default-push`` apply to all inbound (e.g.
5147 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5148 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5148 and :hg:`bundle`) operations.
5149 and :hg:`bundle`) operations.
5149
5150
5150 See :hg:`help urls` for more information.
5151 See :hg:`help urls` for more information.
5151
5152
5152 .. container:: verbose
5153 .. container:: verbose
5153
5154
5154 Template:
5155 Template:
5155
5156
5156 The following keywords are supported. See also :hg:`help templates`.
5157 The following keywords are supported. See also :hg:`help templates`.
5157
5158
5158 :name: String. Symbolic name of the path alias.
5159 :name: String. Symbolic name of the path alias.
5159 :pushurl: String. URL for push operations.
5160 :pushurl: String. URL for push operations.
5160 :url: String. URL or directory path for the other operations.
5161 :url: String. URL or directory path for the other operations.
5161
5162
5162 Returns 0 on success.
5163 Returns 0 on success.
5163 """
5164 """
5164
5165
5165 opts = pycompat.byteskwargs(opts)
5166 opts = pycompat.byteskwargs(opts)
5166 ui.pager(b'paths')
5167 ui.pager(b'paths')
5167 if search:
5168 if search:
5168 pathitems = [
5169 pathitems = [
5169 (name, path)
5170 (name, path)
5170 for name, path in pycompat.iteritems(ui.paths)
5171 for name, path in pycompat.iteritems(ui.paths)
5171 if name == search
5172 if name == search
5172 ]
5173 ]
5173 else:
5174 else:
5174 pathitems = sorted(pycompat.iteritems(ui.paths))
5175 pathitems = sorted(pycompat.iteritems(ui.paths))
5175
5176
5176 fm = ui.formatter(b'paths', opts)
5177 fm = ui.formatter(b'paths', opts)
5177 if fm.isplain():
5178 if fm.isplain():
5178 hidepassword = util.hidepassword
5179 hidepassword = util.hidepassword
5179 else:
5180 else:
5180 hidepassword = bytes
5181 hidepassword = bytes
5181 if ui.quiet:
5182 if ui.quiet:
5182 namefmt = b'%s\n'
5183 namefmt = b'%s\n'
5183 else:
5184 else:
5184 namefmt = b'%s = '
5185 namefmt = b'%s = '
5185 showsubopts = not search and not ui.quiet
5186 showsubopts = not search and not ui.quiet
5186
5187
5187 for name, path in pathitems:
5188 for name, path in pathitems:
5188 fm.startitem()
5189 fm.startitem()
5189 fm.condwrite(not search, b'name', namefmt, name)
5190 fm.condwrite(not search, b'name', namefmt, name)
5190 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5191 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5191 for subopt, value in sorted(path.suboptions.items()):
5192 for subopt, value in sorted(path.suboptions.items()):
5192 assert subopt not in (b'name', b'url')
5193 assert subopt not in (b'name', b'url')
5193 if showsubopts:
5194 if showsubopts:
5194 fm.plain(b'%s:%s = ' % (name, subopt))
5195 fm.plain(b'%s:%s = ' % (name, subopt))
5195 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5196 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5196
5197
5197 fm.end()
5198 fm.end()
5198
5199
5199 if search and not pathitems:
5200 if search and not pathitems:
5200 if not ui.quiet:
5201 if not ui.quiet:
5201 ui.warn(_(b"not found!\n"))
5202 ui.warn(_(b"not found!\n"))
5202 return 1
5203 return 1
5203 else:
5204 else:
5204 return 0
5205 return 0
5205
5206
5206
5207
5207 @command(
5208 @command(
5208 b'phase',
5209 b'phase',
5209 [
5210 [
5210 (b'p', b'public', False, _(b'set changeset phase to public')),
5211 (b'p', b'public', False, _(b'set changeset phase to public')),
5211 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5212 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5212 (b's', b'secret', False, _(b'set changeset phase to secret')),
5213 (b's', b'secret', False, _(b'set changeset phase to secret')),
5213 (b'f', b'force', False, _(b'allow to move boundary backward')),
5214 (b'f', b'force', False, _(b'allow to move boundary backward')),
5214 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5215 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5215 ],
5216 ],
5216 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5217 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5217 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5218 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5218 )
5219 )
5219 def phase(ui, repo, *revs, **opts):
5220 def phase(ui, repo, *revs, **opts):
5220 """set or show the current phase name
5221 """set or show the current phase name
5221
5222
5222 With no argument, show the phase name of the current revision(s).
5223 With no argument, show the phase name of the current revision(s).
5223
5224
5224 With one of -p/--public, -d/--draft or -s/--secret, change the
5225 With one of -p/--public, -d/--draft or -s/--secret, change the
5225 phase value of the specified revisions.
5226 phase value of the specified revisions.
5226
5227
5227 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5228 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5228 lower phase to a higher phase. Phases are ordered as follows::
5229 lower phase to a higher phase. Phases are ordered as follows::
5229
5230
5230 public < draft < secret
5231 public < draft < secret
5231
5232
5232 Returns 0 on success, 1 if some phases could not be changed.
5233 Returns 0 on success, 1 if some phases could not be changed.
5233
5234
5234 (For more information about the phases concept, see :hg:`help phases`.)
5235 (For more information about the phases concept, see :hg:`help phases`.)
5235 """
5236 """
5236 opts = pycompat.byteskwargs(opts)
5237 opts = pycompat.byteskwargs(opts)
5237 # search for a unique phase argument
5238 # search for a unique phase argument
5238 targetphase = None
5239 targetphase = None
5239 for idx, name in enumerate(phases.cmdphasenames):
5240 for idx, name in enumerate(phases.cmdphasenames):
5240 if opts[name]:
5241 if opts[name]:
5241 if targetphase is not None:
5242 if targetphase is not None:
5242 raise error.Abort(_(b'only one phase can be specified'))
5243 raise error.Abort(_(b'only one phase can be specified'))
5243 targetphase = idx
5244 targetphase = idx
5244
5245
5245 # look for specified revision
5246 # look for specified revision
5246 revs = list(revs)
5247 revs = list(revs)
5247 revs.extend(opts[b'rev'])
5248 revs.extend(opts[b'rev'])
5248 if not revs:
5249 if not revs:
5249 # display both parents as the second parent phase can influence
5250 # display both parents as the second parent phase can influence
5250 # the phase of a merge commit
5251 # the phase of a merge commit
5251 revs = [c.rev() for c in repo[None].parents()]
5252 revs = [c.rev() for c in repo[None].parents()]
5252
5253
5253 revs = scmutil.revrange(repo, revs)
5254 revs = scmutil.revrange(repo, revs)
5254
5255
5255 ret = 0
5256 ret = 0
5256 if targetphase is None:
5257 if targetphase is None:
5257 # display
5258 # display
5258 for r in revs:
5259 for r in revs:
5259 ctx = repo[r]
5260 ctx = repo[r]
5260 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5261 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5261 else:
5262 else:
5262 with repo.lock(), repo.transaction(b"phase") as tr:
5263 with repo.lock(), repo.transaction(b"phase") as tr:
5263 # set phase
5264 # set phase
5264 if not revs:
5265 if not revs:
5265 raise error.Abort(_(b'empty revision set'))
5266 raise error.Abort(_(b'empty revision set'))
5266 nodes = [repo[r].node() for r in revs]
5267 nodes = [repo[r].node() for r in revs]
5267 # moving revision from public to draft may hide them
5268 # moving revision from public to draft may hide them
5268 # We have to check result on an unfiltered repository
5269 # We have to check result on an unfiltered repository
5269 unfi = repo.unfiltered()
5270 unfi = repo.unfiltered()
5270 getphase = unfi._phasecache.phase
5271 getphase = unfi._phasecache.phase
5271 olddata = [getphase(unfi, r) for r in unfi]
5272 olddata = [getphase(unfi, r) for r in unfi]
5272 phases.advanceboundary(repo, tr, targetphase, nodes)
5273 phases.advanceboundary(repo, tr, targetphase, nodes)
5273 if opts[b'force']:
5274 if opts[b'force']:
5274 phases.retractboundary(repo, tr, targetphase, nodes)
5275 phases.retractboundary(repo, tr, targetphase, nodes)
5275 getphase = unfi._phasecache.phase
5276 getphase = unfi._phasecache.phase
5276 newdata = [getphase(unfi, r) for r in unfi]
5277 newdata = [getphase(unfi, r) for r in unfi]
5277 changes = sum(newdata[r] != olddata[r] for r in unfi)
5278 changes = sum(newdata[r] != olddata[r] for r in unfi)
5278 cl = unfi.changelog
5279 cl = unfi.changelog
5279 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5280 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5280 if rejected:
5281 if rejected:
5281 ui.warn(
5282 ui.warn(
5282 _(
5283 _(
5283 b'cannot move %i changesets to a higher '
5284 b'cannot move %i changesets to a higher '
5284 b'phase, use --force\n'
5285 b'phase, use --force\n'
5285 )
5286 )
5286 % len(rejected)
5287 % len(rejected)
5287 )
5288 )
5288 ret = 1
5289 ret = 1
5289 if changes:
5290 if changes:
5290 msg = _(b'phase changed for %i changesets\n') % changes
5291 msg = _(b'phase changed for %i changesets\n') % changes
5291 if ret:
5292 if ret:
5292 ui.status(msg)
5293 ui.status(msg)
5293 else:
5294 else:
5294 ui.note(msg)
5295 ui.note(msg)
5295 else:
5296 else:
5296 ui.warn(_(b'no phases changed\n'))
5297 ui.warn(_(b'no phases changed\n'))
5297 return ret
5298 return ret
5298
5299
5299
5300
5300 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5301 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5301 """Run after a changegroup has been added via pull/unbundle
5302 """Run after a changegroup has been added via pull/unbundle
5302
5303
5303 This takes arguments below:
5304 This takes arguments below:
5304
5305
5305 :modheads: change of heads by pull/unbundle
5306 :modheads: change of heads by pull/unbundle
5306 :optupdate: updating working directory is needed or not
5307 :optupdate: updating working directory is needed or not
5307 :checkout: update destination revision (or None to default destination)
5308 :checkout: update destination revision (or None to default destination)
5308 :brev: a name, which might be a bookmark to be activated after updating
5309 :brev: a name, which might be a bookmark to be activated after updating
5309 """
5310 """
5310 if modheads == 0:
5311 if modheads == 0:
5311 return
5312 return
5312 if optupdate:
5313 if optupdate:
5313 try:
5314 try:
5314 return hg.updatetotally(ui, repo, checkout, brev)
5315 return hg.updatetotally(ui, repo, checkout, brev)
5315 except error.UpdateAbort as inst:
5316 except error.UpdateAbort as inst:
5316 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5317 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5317 hint = inst.hint
5318 hint = inst.hint
5318 raise error.UpdateAbort(msg, hint=hint)
5319 raise error.UpdateAbort(msg, hint=hint)
5319 if modheads is not None and modheads > 1:
5320 if modheads is not None and modheads > 1:
5320 currentbranchheads = len(repo.branchheads())
5321 currentbranchheads = len(repo.branchheads())
5321 if currentbranchheads == modheads:
5322 if currentbranchheads == modheads:
5322 ui.status(
5323 ui.status(
5323 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5324 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5324 )
5325 )
5325 elif currentbranchheads > 1:
5326 elif currentbranchheads > 1:
5326 ui.status(
5327 ui.status(
5327 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5328 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5328 )
5329 )
5329 else:
5330 else:
5330 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5331 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5331 elif not ui.configbool(b'commands', b'update.requiredest'):
5332 elif not ui.configbool(b'commands', b'update.requiredest'):
5332 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5333 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5333
5334
5334
5335
5335 @command(
5336 @command(
5336 b'pull',
5337 b'pull',
5337 [
5338 [
5338 (
5339 (
5339 b'u',
5340 b'u',
5340 b'update',
5341 b'update',
5341 None,
5342 None,
5342 _(b'update to new branch head if new descendants were pulled'),
5343 _(b'update to new branch head if new descendants were pulled'),
5343 ),
5344 ),
5344 (
5345 (
5345 b'f',
5346 b'f',
5346 b'force',
5347 b'force',
5347 None,
5348 None,
5348 _(b'run even when remote repository is unrelated'),
5349 _(b'run even when remote repository is unrelated'),
5349 ),
5350 ),
5350 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5351 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5351 (
5352 (
5352 b'r',
5353 b'r',
5353 b'rev',
5354 b'rev',
5354 [],
5355 [],
5355 _(b'a remote changeset intended to be added'),
5356 _(b'a remote changeset intended to be added'),
5356 _(b'REV'),
5357 _(b'REV'),
5357 ),
5358 ),
5358 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5359 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5359 (
5360 (
5360 b'b',
5361 b'b',
5361 b'branch',
5362 b'branch',
5362 [],
5363 [],
5363 _(b'a specific branch you would like to pull'),
5364 _(b'a specific branch you would like to pull'),
5364 _(b'BRANCH'),
5365 _(b'BRANCH'),
5365 ),
5366 ),
5366 ]
5367 ]
5367 + remoteopts,
5368 + remoteopts,
5368 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5369 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5369 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5370 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5370 helpbasic=True,
5371 helpbasic=True,
5371 )
5372 )
5372 def pull(ui, repo, source=b"default", **opts):
5373 def pull(ui, repo, source=b"default", **opts):
5373 """pull changes from the specified source
5374 """pull changes from the specified source
5374
5375
5375 Pull changes from a remote repository to a local one.
5376 Pull changes from a remote repository to a local one.
5376
5377
5377 This finds all changes from the repository at the specified path
5378 This finds all changes from the repository at the specified path
5378 or URL and adds them to a local repository (the current one unless
5379 or URL and adds them to a local repository (the current one unless
5379 -R is specified). By default, this does not update the copy of the
5380 -R is specified). By default, this does not update the copy of the
5380 project in the working directory.
5381 project in the working directory.
5381
5382
5382 When cloning from servers that support it, Mercurial may fetch
5383 When cloning from servers that support it, Mercurial may fetch
5383 pre-generated data. When this is done, hooks operating on incoming
5384 pre-generated data. When this is done, hooks operating on incoming
5384 changesets and changegroups may fire more than once, once for each
5385 changesets and changegroups may fire more than once, once for each
5385 pre-generated bundle and as well as for any additional remaining
5386 pre-generated bundle and as well as for any additional remaining
5386 data. See :hg:`help -e clonebundles` for more.
5387 data. See :hg:`help -e clonebundles` for more.
5387
5388
5388 Use :hg:`incoming` if you want to see what would have been added
5389 Use :hg:`incoming` if you want to see what would have been added
5389 by a pull at the time you issued this command. If you then decide
5390 by a pull at the time you issued this command. If you then decide
5390 to add those changes to the repository, you should use :hg:`pull
5391 to add those changes to the repository, you should use :hg:`pull
5391 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5392 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5392
5393
5393 If SOURCE is omitted, the 'default' path will be used.
5394 If SOURCE is omitted, the 'default' path will be used.
5394 See :hg:`help urls` for more information.
5395 See :hg:`help urls` for more information.
5395
5396
5396 Specifying bookmark as ``.`` is equivalent to specifying the active
5397 Specifying bookmark as ``.`` is equivalent to specifying the active
5397 bookmark's name.
5398 bookmark's name.
5398
5399
5399 Returns 0 on success, 1 if an update had unresolved files.
5400 Returns 0 on success, 1 if an update had unresolved files.
5400 """
5401 """
5401
5402
5402 opts = pycompat.byteskwargs(opts)
5403 opts = pycompat.byteskwargs(opts)
5403 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5404 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5404 b'update'
5405 b'update'
5405 ):
5406 ):
5406 msg = _(b'update destination required by configuration')
5407 msg = _(b'update destination required by configuration')
5407 hint = _(b'use hg pull followed by hg update DEST')
5408 hint = _(b'use hg pull followed by hg update DEST')
5408 raise error.Abort(msg, hint=hint)
5409 raise error.Abort(msg, hint=hint)
5409
5410
5410 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5411 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5411 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5412 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5412 other = hg.peer(repo, opts, source)
5413 other = hg.peer(repo, opts, source)
5413 try:
5414 try:
5414 revs, checkout = hg.addbranchrevs(
5415 revs, checkout = hg.addbranchrevs(
5415 repo, other, branches, opts.get(b'rev')
5416 repo, other, branches, opts.get(b'rev')
5416 )
5417 )
5417
5418
5418 pullopargs = {}
5419 pullopargs = {}
5419
5420
5420 nodes = None
5421 nodes = None
5421 if opts.get(b'bookmark') or revs:
5422 if opts.get(b'bookmark') or revs:
5422 # The list of bookmark used here is the same used to actually update
5423 # The list of bookmark used here is the same used to actually update
5423 # the bookmark names, to avoid the race from issue 4689 and we do
5424 # the bookmark names, to avoid the race from issue 4689 and we do
5424 # all lookup and bookmark queries in one go so they see the same
5425 # all lookup and bookmark queries in one go so they see the same
5425 # version of the server state (issue 4700).
5426 # version of the server state (issue 4700).
5426 nodes = []
5427 nodes = []
5427 fnodes = []
5428 fnodes = []
5428 revs = revs or []
5429 revs = revs or []
5429 if revs and not other.capable(b'lookup'):
5430 if revs and not other.capable(b'lookup'):
5430 err = _(
5431 err = _(
5431 b"other repository doesn't support revision lookup, "
5432 b"other repository doesn't support revision lookup, "
5432 b"so a rev cannot be specified."
5433 b"so a rev cannot be specified."
5433 )
5434 )
5434 raise error.Abort(err)
5435 raise error.Abort(err)
5435 with other.commandexecutor() as e:
5436 with other.commandexecutor() as e:
5436 fremotebookmarks = e.callcommand(
5437 fremotebookmarks = e.callcommand(
5437 b'listkeys', {b'namespace': b'bookmarks'}
5438 b'listkeys', {b'namespace': b'bookmarks'}
5438 )
5439 )
5439 for r in revs:
5440 for r in revs:
5440 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5441 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5441 remotebookmarks = fremotebookmarks.result()
5442 remotebookmarks = fremotebookmarks.result()
5442 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5443 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5443 pullopargs[b'remotebookmarks'] = remotebookmarks
5444 pullopargs[b'remotebookmarks'] = remotebookmarks
5444 for b in opts.get(b'bookmark', []):
5445 for b in opts.get(b'bookmark', []):
5445 b = repo._bookmarks.expandname(b)
5446 b = repo._bookmarks.expandname(b)
5446 if b not in remotebookmarks:
5447 if b not in remotebookmarks:
5447 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5448 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5448 nodes.append(remotebookmarks[b])
5449 nodes.append(remotebookmarks[b])
5449 for i, rev in enumerate(revs):
5450 for i, rev in enumerate(revs):
5450 node = fnodes[i].result()
5451 node = fnodes[i].result()
5451 nodes.append(node)
5452 nodes.append(node)
5452 if rev == checkout:
5453 if rev == checkout:
5453 checkout = node
5454 checkout = node
5454
5455
5455 wlock = util.nullcontextmanager()
5456 wlock = util.nullcontextmanager()
5456 if opts.get(b'update'):
5457 if opts.get(b'update'):
5457 wlock = repo.wlock()
5458 wlock = repo.wlock()
5458 with wlock:
5459 with wlock:
5459 pullopargs.update(opts.get(b'opargs', {}))
5460 pullopargs.update(opts.get(b'opargs', {}))
5460 modheads = exchange.pull(
5461 modheads = exchange.pull(
5461 repo,
5462 repo,
5462 other,
5463 other,
5463 heads=nodes,
5464 heads=nodes,
5464 force=opts.get(b'force'),
5465 force=opts.get(b'force'),
5465 bookmarks=opts.get(b'bookmark', ()),
5466 bookmarks=opts.get(b'bookmark', ()),
5466 opargs=pullopargs,
5467 opargs=pullopargs,
5467 confirm=opts.get(b'confirm'),
5468 confirm=opts.get(b'confirm'),
5468 ).cgresult
5469 ).cgresult
5469
5470
5470 # brev is a name, which might be a bookmark to be activated at
5471 # brev is a name, which might be a bookmark to be activated at
5471 # the end of the update. In other words, it is an explicit
5472 # the end of the update. In other words, it is an explicit
5472 # destination of the update
5473 # destination of the update
5473 brev = None
5474 brev = None
5474
5475
5475 if checkout:
5476 if checkout:
5476 checkout = repo.unfiltered().changelog.rev(checkout)
5477 checkout = repo.unfiltered().changelog.rev(checkout)
5477
5478
5478 # order below depends on implementation of
5479 # order below depends on implementation of
5479 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5480 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5480 # because 'checkout' is determined without it.
5481 # because 'checkout' is determined without it.
5481 if opts.get(b'rev'):
5482 if opts.get(b'rev'):
5482 brev = opts[b'rev'][0]
5483 brev = opts[b'rev'][0]
5483 elif opts.get(b'branch'):
5484 elif opts.get(b'branch'):
5484 brev = opts[b'branch'][0]
5485 brev = opts[b'branch'][0]
5485 else:
5486 else:
5486 brev = branches[0]
5487 brev = branches[0]
5487 repo._subtoppath = source
5488 repo._subtoppath = source
5488 try:
5489 try:
5489 ret = postincoming(
5490 ret = postincoming(
5490 ui, repo, modheads, opts.get(b'update'), checkout, brev
5491 ui, repo, modheads, opts.get(b'update'), checkout, brev
5491 )
5492 )
5492 except error.FilteredRepoLookupError as exc:
5493 except error.FilteredRepoLookupError as exc:
5493 msg = _(b'cannot update to target: %s') % exc.args[0]
5494 msg = _(b'cannot update to target: %s') % exc.args[0]
5494 exc.args = (msg,) + exc.args[1:]
5495 exc.args = (msg,) + exc.args[1:]
5495 raise
5496 raise
5496 finally:
5497 finally:
5497 del repo._subtoppath
5498 del repo._subtoppath
5498
5499
5499 finally:
5500 finally:
5500 other.close()
5501 other.close()
5501 return ret
5502 return ret
5502
5503
5503
5504
5504 @command(
5505 @command(
5505 b'push',
5506 b'push',
5506 [
5507 [
5507 (b'f', b'force', None, _(b'force push')),
5508 (b'f', b'force', None, _(b'force push')),
5508 (
5509 (
5509 b'r',
5510 b'r',
5510 b'rev',
5511 b'rev',
5511 [],
5512 [],
5512 _(b'a changeset intended to be included in the destination'),
5513 _(b'a changeset intended to be included in the destination'),
5513 _(b'REV'),
5514 _(b'REV'),
5514 ),
5515 ),
5515 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5516 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5516 (
5517 (
5517 b'b',
5518 b'b',
5518 b'branch',
5519 b'branch',
5519 [],
5520 [],
5520 _(b'a specific branch you would like to push'),
5521 _(b'a specific branch you would like to push'),
5521 _(b'BRANCH'),
5522 _(b'BRANCH'),
5522 ),
5523 ),
5523 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5524 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5524 (
5525 (
5525 b'',
5526 b'',
5526 b'pushvars',
5527 b'pushvars',
5527 [],
5528 [],
5528 _(b'variables that can be sent to server (ADVANCED)'),
5529 _(b'variables that can be sent to server (ADVANCED)'),
5529 ),
5530 ),
5530 (
5531 (
5531 b'',
5532 b'',
5532 b'publish',
5533 b'publish',
5533 False,
5534 False,
5534 _(b'push the changeset as public (EXPERIMENTAL)'),
5535 _(b'push the changeset as public (EXPERIMENTAL)'),
5535 ),
5536 ),
5536 ]
5537 ]
5537 + remoteopts,
5538 + remoteopts,
5538 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5539 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5539 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5540 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5540 helpbasic=True,
5541 helpbasic=True,
5541 )
5542 )
5542 def push(ui, repo, dest=None, **opts):
5543 def push(ui, repo, dest=None, **opts):
5543 """push changes to the specified destination
5544 """push changes to the specified destination
5544
5545
5545 Push changesets from the local repository to the specified
5546 Push changesets from the local repository to the specified
5546 destination.
5547 destination.
5547
5548
5548 This operation is symmetrical to pull: it is identical to a pull
5549 This operation is symmetrical to pull: it is identical to a pull
5549 in the destination repository from the current one.
5550 in the destination repository from the current one.
5550
5551
5551 By default, push will not allow creation of new heads at the
5552 By default, push will not allow creation of new heads at the
5552 destination, since multiple heads would make it unclear which head
5553 destination, since multiple heads would make it unclear which head
5553 to use. In this situation, it is recommended to pull and merge
5554 to use. In this situation, it is recommended to pull and merge
5554 before pushing.
5555 before pushing.
5555
5556
5556 Use --new-branch if you want to allow push to create a new named
5557 Use --new-branch if you want to allow push to create a new named
5557 branch that is not present at the destination. This allows you to
5558 branch that is not present at the destination. This allows you to
5558 only create a new branch without forcing other changes.
5559 only create a new branch without forcing other changes.
5559
5560
5560 .. note::
5561 .. note::
5561
5562
5562 Extra care should be taken with the -f/--force option,
5563 Extra care should be taken with the -f/--force option,
5563 which will push all new heads on all branches, an action which will
5564 which will push all new heads on all branches, an action which will
5564 almost always cause confusion for collaborators.
5565 almost always cause confusion for collaborators.
5565
5566
5566 If -r/--rev is used, the specified revision and all its ancestors
5567 If -r/--rev is used, the specified revision and all its ancestors
5567 will be pushed to the remote repository.
5568 will be pushed to the remote repository.
5568
5569
5569 If -B/--bookmark is used, the specified bookmarked revision, its
5570 If -B/--bookmark is used, the specified bookmarked revision, its
5570 ancestors, and the bookmark will be pushed to the remote
5571 ancestors, and the bookmark will be pushed to the remote
5571 repository. Specifying ``.`` is equivalent to specifying the active
5572 repository. Specifying ``.`` is equivalent to specifying the active
5572 bookmark's name.
5573 bookmark's name.
5573
5574
5574 Please see :hg:`help urls` for important details about ``ssh://``
5575 Please see :hg:`help urls` for important details about ``ssh://``
5575 URLs. If DESTINATION is omitted, a default path will be used.
5576 URLs. If DESTINATION is omitted, a default path will be used.
5576
5577
5577 .. container:: verbose
5578 .. container:: verbose
5578
5579
5579 The --pushvars option sends strings to the server that become
5580 The --pushvars option sends strings to the server that become
5580 environment variables prepended with ``HG_USERVAR_``. For example,
5581 environment variables prepended with ``HG_USERVAR_``. For example,
5581 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5582 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5582 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5583 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5583
5584
5584 pushvars can provide for user-overridable hooks as well as set debug
5585 pushvars can provide for user-overridable hooks as well as set debug
5585 levels. One example is having a hook that blocks commits containing
5586 levels. One example is having a hook that blocks commits containing
5586 conflict markers, but enables the user to override the hook if the file
5587 conflict markers, but enables the user to override the hook if the file
5587 is using conflict markers for testing purposes or the file format has
5588 is using conflict markers for testing purposes or the file format has
5588 strings that look like conflict markers.
5589 strings that look like conflict markers.
5589
5590
5590 By default, servers will ignore `--pushvars`. To enable it add the
5591 By default, servers will ignore `--pushvars`. To enable it add the
5591 following to your configuration file::
5592 following to your configuration file::
5592
5593
5593 [push]
5594 [push]
5594 pushvars.server = true
5595 pushvars.server = true
5595
5596
5596 Returns 0 if push was successful, 1 if nothing to push.
5597 Returns 0 if push was successful, 1 if nothing to push.
5597 """
5598 """
5598
5599
5599 opts = pycompat.byteskwargs(opts)
5600 opts = pycompat.byteskwargs(opts)
5600 if opts.get(b'bookmark'):
5601 if opts.get(b'bookmark'):
5601 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5602 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5602 for b in opts[b'bookmark']:
5603 for b in opts[b'bookmark']:
5603 # translate -B options to -r so changesets get pushed
5604 # translate -B options to -r so changesets get pushed
5604 b = repo._bookmarks.expandname(b)
5605 b = repo._bookmarks.expandname(b)
5605 if b in repo._bookmarks:
5606 if b in repo._bookmarks:
5606 opts.setdefault(b'rev', []).append(b)
5607 opts.setdefault(b'rev', []).append(b)
5607 else:
5608 else:
5608 # if we try to push a deleted bookmark, translate it to null
5609 # if we try to push a deleted bookmark, translate it to null
5609 # this lets simultaneous -r, -b options continue working
5610 # this lets simultaneous -r, -b options continue working
5610 opts.setdefault(b'rev', []).append(b"null")
5611 opts.setdefault(b'rev', []).append(b"null")
5611
5612
5612 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5613 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5613 if not path:
5614 if not path:
5614 raise error.Abort(
5615 raise error.Abort(
5615 _(b'default repository not configured!'),
5616 _(b'default repository not configured!'),
5616 hint=_(b"see 'hg help config.paths'"),
5617 hint=_(b"see 'hg help config.paths'"),
5617 )
5618 )
5618 dest = path.pushloc or path.loc
5619 dest = path.pushloc or path.loc
5619 branches = (path.branch, opts.get(b'branch') or [])
5620 branches = (path.branch, opts.get(b'branch') or [])
5620 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5621 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5621 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5622 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5622 other = hg.peer(repo, opts, dest)
5623 other = hg.peer(repo, opts, dest)
5623
5624
5624 if revs:
5625 if revs:
5625 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5626 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5626 if not revs:
5627 if not revs:
5627 raise error.Abort(
5628 raise error.Abort(
5628 _(b"specified revisions evaluate to an empty set"),
5629 _(b"specified revisions evaluate to an empty set"),
5629 hint=_(b"use different revision arguments"),
5630 hint=_(b"use different revision arguments"),
5630 )
5631 )
5631 elif path.pushrev:
5632 elif path.pushrev:
5632 # It doesn't make any sense to specify ancestor revisions. So limit
5633 # It doesn't make any sense to specify ancestor revisions. So limit
5633 # to DAG heads to make discovery simpler.
5634 # to DAG heads to make discovery simpler.
5634 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5635 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5635 revs = scmutil.revrange(repo, [expr])
5636 revs = scmutil.revrange(repo, [expr])
5636 revs = [repo[rev].node() for rev in revs]
5637 revs = [repo[rev].node() for rev in revs]
5637 if not revs:
5638 if not revs:
5638 raise error.Abort(
5639 raise error.Abort(
5639 _(b'default push revset for path evaluates to an empty set')
5640 _(b'default push revset for path evaluates to an empty set')
5640 )
5641 )
5641 elif ui.configbool(b'commands', b'push.require-revs'):
5642 elif ui.configbool(b'commands', b'push.require-revs'):
5642 raise error.Abort(
5643 raise error.Abort(
5643 _(b'no revisions specified to push'),
5644 _(b'no revisions specified to push'),
5644 hint=_(b'did you mean "hg push -r ."?'),
5645 hint=_(b'did you mean "hg push -r ."?'),
5645 )
5646 )
5646
5647
5647 repo._subtoppath = dest
5648 repo._subtoppath = dest
5648 try:
5649 try:
5649 # push subrepos depth-first for coherent ordering
5650 # push subrepos depth-first for coherent ordering
5650 c = repo[b'.']
5651 c = repo[b'.']
5651 subs = c.substate # only repos that are committed
5652 subs = c.substate # only repos that are committed
5652 for s in sorted(subs):
5653 for s in sorted(subs):
5653 result = c.sub(s).push(opts)
5654 result = c.sub(s).push(opts)
5654 if result == 0:
5655 if result == 0:
5655 return not result
5656 return not result
5656 finally:
5657 finally:
5657 del repo._subtoppath
5658 del repo._subtoppath
5658
5659
5659 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5660 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5660 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5661 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5661
5662
5662 pushop = exchange.push(
5663 pushop = exchange.push(
5663 repo,
5664 repo,
5664 other,
5665 other,
5665 opts.get(b'force'),
5666 opts.get(b'force'),
5666 revs=revs,
5667 revs=revs,
5667 newbranch=opts.get(b'new_branch'),
5668 newbranch=opts.get(b'new_branch'),
5668 bookmarks=opts.get(b'bookmark', ()),
5669 bookmarks=opts.get(b'bookmark', ()),
5669 publish=opts.get(b'publish'),
5670 publish=opts.get(b'publish'),
5670 opargs=opargs,
5671 opargs=opargs,
5671 )
5672 )
5672
5673
5673 result = not pushop.cgresult
5674 result = not pushop.cgresult
5674
5675
5675 if pushop.bkresult is not None:
5676 if pushop.bkresult is not None:
5676 if pushop.bkresult == 2:
5677 if pushop.bkresult == 2:
5677 result = 2
5678 result = 2
5678 elif not result and pushop.bkresult:
5679 elif not result and pushop.bkresult:
5679 result = 2
5680 result = 2
5680
5681
5681 return result
5682 return result
5682
5683
5683
5684
5684 @command(
5685 @command(
5685 b'recover',
5686 b'recover',
5686 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5687 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5687 helpcategory=command.CATEGORY_MAINTENANCE,
5688 helpcategory=command.CATEGORY_MAINTENANCE,
5688 )
5689 )
5689 def recover(ui, repo, **opts):
5690 def recover(ui, repo, **opts):
5690 """roll back an interrupted transaction
5691 """roll back an interrupted transaction
5691
5692
5692 Recover from an interrupted commit or pull.
5693 Recover from an interrupted commit or pull.
5693
5694
5694 This command tries to fix the repository status after an
5695 This command tries to fix the repository status after an
5695 interrupted operation. It should only be necessary when Mercurial
5696 interrupted operation. It should only be necessary when Mercurial
5696 suggests it.
5697 suggests it.
5697
5698
5698 Returns 0 if successful, 1 if nothing to recover or verify fails.
5699 Returns 0 if successful, 1 if nothing to recover or verify fails.
5699 """
5700 """
5700 ret = repo.recover()
5701 ret = repo.recover()
5701 if ret:
5702 if ret:
5702 if opts['verify']:
5703 if opts['verify']:
5703 return hg.verify(repo)
5704 return hg.verify(repo)
5704 else:
5705 else:
5705 msg = _(
5706 msg = _(
5706 b"(verify step skipped, run `hg verify` to check your "
5707 b"(verify step skipped, run `hg verify` to check your "
5707 b"repository content)\n"
5708 b"repository content)\n"
5708 )
5709 )
5709 ui.warn(msg)
5710 ui.warn(msg)
5710 return 0
5711 return 0
5711 return 1
5712 return 1
5712
5713
5713
5714
5714 @command(
5715 @command(
5715 b'remove|rm',
5716 b'remove|rm',
5716 [
5717 [
5717 (b'A', b'after', None, _(b'record delete for missing files')),
5718 (b'A', b'after', None, _(b'record delete for missing files')),
5718 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5719 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5719 ]
5720 ]
5720 + subrepoopts
5721 + subrepoopts
5721 + walkopts
5722 + walkopts
5722 + dryrunopts,
5723 + dryrunopts,
5723 _(b'[OPTION]... FILE...'),
5724 _(b'[OPTION]... FILE...'),
5724 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5725 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5725 helpbasic=True,
5726 helpbasic=True,
5726 inferrepo=True,
5727 inferrepo=True,
5727 )
5728 )
5728 def remove(ui, repo, *pats, **opts):
5729 def remove(ui, repo, *pats, **opts):
5729 """remove the specified files on the next commit
5730 """remove the specified files on the next commit
5730
5731
5731 Schedule the indicated files for removal from the current branch.
5732 Schedule the indicated files for removal from the current branch.
5732
5733
5733 This command schedules the files to be removed at the next commit.
5734 This command schedules the files to be removed at the next commit.
5734 To undo a remove before that, see :hg:`revert`. To undo added
5735 To undo a remove before that, see :hg:`revert`. To undo added
5735 files, see :hg:`forget`.
5736 files, see :hg:`forget`.
5736
5737
5737 .. container:: verbose
5738 .. container:: verbose
5738
5739
5739 -A/--after can be used to remove only files that have already
5740 -A/--after can be used to remove only files that have already
5740 been deleted, -f/--force can be used to force deletion, and -Af
5741 been deleted, -f/--force can be used to force deletion, and -Af
5741 can be used to remove files from the next revision without
5742 can be used to remove files from the next revision without
5742 deleting them from the working directory.
5743 deleting them from the working directory.
5743
5744
5744 The following table details the behavior of remove for different
5745 The following table details the behavior of remove for different
5745 file states (columns) and option combinations (rows). The file
5746 file states (columns) and option combinations (rows). The file
5746 states are Added [A], Clean [C], Modified [M] and Missing [!]
5747 states are Added [A], Clean [C], Modified [M] and Missing [!]
5747 (as reported by :hg:`status`). The actions are Warn, Remove
5748 (as reported by :hg:`status`). The actions are Warn, Remove
5748 (from branch) and Delete (from disk):
5749 (from branch) and Delete (from disk):
5749
5750
5750 ========= == == == ==
5751 ========= == == == ==
5751 opt/state A C M !
5752 opt/state A C M !
5752 ========= == == == ==
5753 ========= == == == ==
5753 none W RD W R
5754 none W RD W R
5754 -f R RD RD R
5755 -f R RD RD R
5755 -A W W W R
5756 -A W W W R
5756 -Af R R R R
5757 -Af R R R R
5757 ========= == == == ==
5758 ========= == == == ==
5758
5759
5759 .. note::
5760 .. note::
5760
5761
5761 :hg:`remove` never deletes files in Added [A] state from the
5762 :hg:`remove` never deletes files in Added [A] state from the
5762 working directory, not even if ``--force`` is specified.
5763 working directory, not even if ``--force`` is specified.
5763
5764
5764 Returns 0 on success, 1 if any warnings encountered.
5765 Returns 0 on success, 1 if any warnings encountered.
5765 """
5766 """
5766
5767
5767 opts = pycompat.byteskwargs(opts)
5768 opts = pycompat.byteskwargs(opts)
5768 after, force = opts.get(b'after'), opts.get(b'force')
5769 after, force = opts.get(b'after'), opts.get(b'force')
5769 dryrun = opts.get(b'dry_run')
5770 dryrun = opts.get(b'dry_run')
5770 if not pats and not after:
5771 if not pats and not after:
5771 raise error.Abort(_(b'no files specified'))
5772 raise error.Abort(_(b'no files specified'))
5772
5773
5773 m = scmutil.match(repo[None], pats, opts)
5774 m = scmutil.match(repo[None], pats, opts)
5774 subrepos = opts.get(b'subrepos')
5775 subrepos = opts.get(b'subrepos')
5775 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5776 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5776 return cmdutil.remove(
5777 return cmdutil.remove(
5777 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5778 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5778 )
5779 )
5779
5780
5780
5781
5781 @command(
5782 @command(
5782 b'rename|move|mv',
5783 b'rename|move|mv',
5783 [
5784 [
5784 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5785 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5785 (
5786 (
5786 b'f',
5787 b'f',
5787 b'force',
5788 b'force',
5788 None,
5789 None,
5789 _(b'forcibly move over an existing managed file'),
5790 _(b'forcibly move over an existing managed file'),
5790 ),
5791 ),
5791 ]
5792 ]
5792 + walkopts
5793 + walkopts
5793 + dryrunopts,
5794 + dryrunopts,
5794 _(b'[OPTION]... SOURCE... DEST'),
5795 _(b'[OPTION]... SOURCE... DEST'),
5795 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5796 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5796 )
5797 )
5797 def rename(ui, repo, *pats, **opts):
5798 def rename(ui, repo, *pats, **opts):
5798 """rename files; equivalent of copy + remove
5799 """rename files; equivalent of copy + remove
5799
5800
5800 Mark dest as copies of sources; mark sources for deletion. If dest
5801 Mark dest as copies of sources; mark sources for deletion. If dest
5801 is a directory, copies are put in that directory. If dest is a
5802 is a directory, copies are put in that directory. If dest is a
5802 file, there can only be one source.
5803 file, there can only be one source.
5803
5804
5804 By default, this command copies the contents of files as they
5805 By default, this command copies the contents of files as they
5805 exist in the working directory. If invoked with -A/--after, the
5806 exist in the working directory. If invoked with -A/--after, the
5806 operation is recorded, but no copying is performed.
5807 operation is recorded, but no copying is performed.
5807
5808
5808 This command takes effect at the next commit. To undo a rename
5809 This command takes effect at the next commit. To undo a rename
5809 before that, see :hg:`revert`.
5810 before that, see :hg:`revert`.
5810
5811
5811 Returns 0 on success, 1 if errors are encountered.
5812 Returns 0 on success, 1 if errors are encountered.
5812 """
5813 """
5813 opts = pycompat.byteskwargs(opts)
5814 opts = pycompat.byteskwargs(opts)
5814 with repo.wlock(False):
5815 with repo.wlock(False):
5815 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5816 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5816
5817
5817
5818
5818 @command(
5819 @command(
5819 b'resolve',
5820 b'resolve',
5820 [
5821 [
5821 (b'a', b'all', None, _(b'select all unresolved files')),
5822 (b'a', b'all', None, _(b'select all unresolved files')),
5822 (b'l', b'list', None, _(b'list state of files needing merge')),
5823 (b'l', b'list', None, _(b'list state of files needing merge')),
5823 (b'm', b'mark', None, _(b'mark files as resolved')),
5824 (b'm', b'mark', None, _(b'mark files as resolved')),
5824 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5825 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5825 (b'n', b'no-status', None, _(b'hide status prefix')),
5826 (b'n', b'no-status', None, _(b'hide status prefix')),
5826 (b'', b're-merge', None, _(b're-merge files')),
5827 (b'', b're-merge', None, _(b're-merge files')),
5827 ]
5828 ]
5828 + mergetoolopts
5829 + mergetoolopts
5829 + walkopts
5830 + walkopts
5830 + formatteropts,
5831 + formatteropts,
5831 _(b'[OPTION]... [FILE]...'),
5832 _(b'[OPTION]... [FILE]...'),
5832 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5833 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5833 inferrepo=True,
5834 inferrepo=True,
5834 )
5835 )
5835 def resolve(ui, repo, *pats, **opts):
5836 def resolve(ui, repo, *pats, **opts):
5836 """redo merges or set/view the merge status of files
5837 """redo merges or set/view the merge status of files
5837
5838
5838 Merges with unresolved conflicts are often the result of
5839 Merges with unresolved conflicts are often the result of
5839 non-interactive merging using the ``internal:merge`` configuration
5840 non-interactive merging using the ``internal:merge`` configuration
5840 setting, or a command-line merge tool like ``diff3``. The resolve
5841 setting, or a command-line merge tool like ``diff3``. The resolve
5841 command is used to manage the files involved in a merge, after
5842 command is used to manage the files involved in a merge, after
5842 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5843 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5843 working directory must have two parents). See :hg:`help
5844 working directory must have two parents). See :hg:`help
5844 merge-tools` for information on configuring merge tools.
5845 merge-tools` for information on configuring merge tools.
5845
5846
5846 The resolve command can be used in the following ways:
5847 The resolve command can be used in the following ways:
5847
5848
5848 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5849 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5849 the specified files, discarding any previous merge attempts. Re-merging
5850 the specified files, discarding any previous merge attempts. Re-merging
5850 is not performed for files already marked as resolved. Use ``--all/-a``
5851 is not performed for files already marked as resolved. Use ``--all/-a``
5851 to select all unresolved files. ``--tool`` can be used to specify
5852 to select all unresolved files. ``--tool`` can be used to specify
5852 the merge tool used for the given files. It overrides the HGMERGE
5853 the merge tool used for the given files. It overrides the HGMERGE
5853 environment variable and your configuration files. Previous file
5854 environment variable and your configuration files. Previous file
5854 contents are saved with a ``.orig`` suffix.
5855 contents are saved with a ``.orig`` suffix.
5855
5856
5856 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5857 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5857 (e.g. after having manually fixed-up the files). The default is
5858 (e.g. after having manually fixed-up the files). The default is
5858 to mark all unresolved files.
5859 to mark all unresolved files.
5859
5860
5860 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5861 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5861 default is to mark all resolved files.
5862 default is to mark all resolved files.
5862
5863
5863 - :hg:`resolve -l`: list files which had or still have conflicts.
5864 - :hg:`resolve -l`: list files which had or still have conflicts.
5864 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5865 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5865 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5866 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5866 the list. See :hg:`help filesets` for details.
5867 the list. See :hg:`help filesets` for details.
5867
5868
5868 .. note::
5869 .. note::
5869
5870
5870 Mercurial will not let you commit files with unresolved merge
5871 Mercurial will not let you commit files with unresolved merge
5871 conflicts. You must use :hg:`resolve -m ...` before you can
5872 conflicts. You must use :hg:`resolve -m ...` before you can
5872 commit after a conflicting merge.
5873 commit after a conflicting merge.
5873
5874
5874 .. container:: verbose
5875 .. container:: verbose
5875
5876
5876 Template:
5877 Template:
5877
5878
5878 The following keywords are supported in addition to the common template
5879 The following keywords are supported in addition to the common template
5879 keywords and functions. See also :hg:`help templates`.
5880 keywords and functions. See also :hg:`help templates`.
5880
5881
5881 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5882 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5882 :path: String. Repository-absolute path of the file.
5883 :path: String. Repository-absolute path of the file.
5883
5884
5884 Returns 0 on success, 1 if any files fail a resolve attempt.
5885 Returns 0 on success, 1 if any files fail a resolve attempt.
5885 """
5886 """
5886
5887
5887 opts = pycompat.byteskwargs(opts)
5888 opts = pycompat.byteskwargs(opts)
5888 confirm = ui.configbool(b'commands', b'resolve.confirm')
5889 confirm = ui.configbool(b'commands', b'resolve.confirm')
5889 flaglist = b'all mark unmark list no_status re_merge'.split()
5890 flaglist = b'all mark unmark list no_status re_merge'.split()
5890 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5891 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5891
5892
5892 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5893 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5893 if actioncount > 1:
5894 if actioncount > 1:
5894 raise error.Abort(_(b"too many actions specified"))
5895 raise error.Abort(_(b"too many actions specified"))
5895 elif actioncount == 0 and ui.configbool(
5896 elif actioncount == 0 and ui.configbool(
5896 b'commands', b'resolve.explicit-re-merge'
5897 b'commands', b'resolve.explicit-re-merge'
5897 ):
5898 ):
5898 hint = _(b'use --mark, --unmark, --list or --re-merge')
5899 hint = _(b'use --mark, --unmark, --list or --re-merge')
5899 raise error.Abort(_(b'no action specified'), hint=hint)
5900 raise error.Abort(_(b'no action specified'), hint=hint)
5900 if pats and all:
5901 if pats and all:
5901 raise error.Abort(_(b"can't specify --all and patterns"))
5902 raise error.Abort(_(b"can't specify --all and patterns"))
5902 if not (all or pats or show or mark or unmark):
5903 if not (all or pats or show or mark or unmark):
5903 raise error.Abort(
5904 raise error.Abort(
5904 _(b'no files or directories specified'),
5905 _(b'no files or directories specified'),
5905 hint=b'use --all to re-merge all unresolved files',
5906 hint=b'use --all to re-merge all unresolved files',
5906 )
5907 )
5907
5908
5908 if confirm:
5909 if confirm:
5909 if all:
5910 if all:
5910 if ui.promptchoice(
5911 if ui.promptchoice(
5911 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5912 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5912 ):
5913 ):
5913 raise error.Abort(_(b'user quit'))
5914 raise error.Abort(_(b'user quit'))
5914 if mark and not pats:
5915 if mark and not pats:
5915 if ui.promptchoice(
5916 if ui.promptchoice(
5916 _(
5917 _(
5917 b'mark all unresolved files as resolved (yn)?'
5918 b'mark all unresolved files as resolved (yn)?'
5918 b'$$ &Yes $$ &No'
5919 b'$$ &Yes $$ &No'
5919 )
5920 )
5920 ):
5921 ):
5921 raise error.Abort(_(b'user quit'))
5922 raise error.Abort(_(b'user quit'))
5922 if unmark and not pats:
5923 if unmark and not pats:
5923 if ui.promptchoice(
5924 if ui.promptchoice(
5924 _(
5925 _(
5925 b'mark all resolved files as unresolved (yn)?'
5926 b'mark all resolved files as unresolved (yn)?'
5926 b'$$ &Yes $$ &No'
5927 b'$$ &Yes $$ &No'
5927 )
5928 )
5928 ):
5929 ):
5929 raise error.Abort(_(b'user quit'))
5930 raise error.Abort(_(b'user quit'))
5930
5931
5931 uipathfn = scmutil.getuipathfn(repo)
5932 uipathfn = scmutil.getuipathfn(repo)
5932
5933
5933 if show:
5934 if show:
5934 ui.pager(b'resolve')
5935 ui.pager(b'resolve')
5935 fm = ui.formatter(b'resolve', opts)
5936 fm = ui.formatter(b'resolve', opts)
5936 ms = mergemod.mergestate.read(repo)
5937 ms = mergemod.mergestate.read(repo)
5937 wctx = repo[None]
5938 wctx = repo[None]
5938 m = scmutil.match(wctx, pats, opts)
5939 m = scmutil.match(wctx, pats, opts)
5939
5940
5940 # Labels and keys based on merge state. Unresolved path conflicts show
5941 # Labels and keys based on merge state. Unresolved path conflicts show
5941 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5942 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5942 # resolved conflicts.
5943 # resolved conflicts.
5943 mergestateinfo = {
5944 mergestateinfo = {
5944 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5945 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5945 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5946 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5946 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5947 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5947 b'resolve.unresolved',
5948 b'resolve.unresolved',
5948 b'P',
5949 b'P',
5949 ),
5950 ),
5950 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5951 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5951 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5952 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5952 b'resolve.driverresolved',
5953 b'resolve.driverresolved',
5953 b'D',
5954 b'D',
5954 ),
5955 ),
5955 }
5956 }
5956
5957
5957 for f in ms:
5958 for f in ms:
5958 if not m(f):
5959 if not m(f):
5959 continue
5960 continue
5960
5961
5961 if ms[f] == mergemod.MERGE_RECORD_MERGED_OTHER:
5962 if ms[f] == mergemod.MERGE_RECORD_MERGED_OTHER:
5962 continue
5963 continue
5963 label, key = mergestateinfo[ms[f]]
5964 label, key = mergestateinfo[ms[f]]
5964 fm.startitem()
5965 fm.startitem()
5965 fm.context(ctx=wctx)
5966 fm.context(ctx=wctx)
5966 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5967 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5967 fm.data(path=f)
5968 fm.data(path=f)
5968 fm.plain(b'%s\n' % uipathfn(f), label=label)
5969 fm.plain(b'%s\n' % uipathfn(f), label=label)
5969 fm.end()
5970 fm.end()
5970 return 0
5971 return 0
5971
5972
5972 with repo.wlock():
5973 with repo.wlock():
5973 ms = mergemod.mergestate.read(repo)
5974 ms = mergemod.mergestate.read(repo)
5974
5975
5975 if not (ms.active() or repo.dirstate.p2() != nullid):
5976 if not (ms.active() or repo.dirstate.p2() != nullid):
5976 raise error.Abort(
5977 raise error.Abort(
5977 _(b'resolve command not applicable when not merging')
5978 _(b'resolve command not applicable when not merging')
5978 )
5979 )
5979
5980
5980 wctx = repo[None]
5981 wctx = repo[None]
5981
5982
5982 if (
5983 if (
5983 ms.mergedriver
5984 ms.mergedriver
5984 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5985 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5985 ):
5986 ):
5986 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5987 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5987 ms.commit()
5988 ms.commit()
5988 # allow mark and unmark to go through
5989 # allow mark and unmark to go through
5989 if not mark and not unmark and not proceed:
5990 if not mark and not unmark and not proceed:
5990 return 1
5991 return 1
5991
5992
5992 m = scmutil.match(wctx, pats, opts)
5993 m = scmutil.match(wctx, pats, opts)
5993 ret = 0
5994 ret = 0
5994 didwork = False
5995 didwork = False
5995 runconclude = False
5996 runconclude = False
5996
5997
5997 tocomplete = []
5998 tocomplete = []
5998 hasconflictmarkers = []
5999 hasconflictmarkers = []
5999 if mark:
6000 if mark:
6000 markcheck = ui.config(b'commands', b'resolve.mark-check')
6001 markcheck = ui.config(b'commands', b'resolve.mark-check')
6001 if markcheck not in [b'warn', b'abort']:
6002 if markcheck not in [b'warn', b'abort']:
6002 # Treat all invalid / unrecognized values as 'none'.
6003 # Treat all invalid / unrecognized values as 'none'.
6003 markcheck = False
6004 markcheck = False
6004 for f in ms:
6005 for f in ms:
6005 if not m(f):
6006 if not m(f):
6006 continue
6007 continue
6007
6008
6008 didwork = True
6009 didwork = True
6009
6010
6010 if ms[f] == mergemod.MERGE_RECORD_MERGED_OTHER:
6011 if ms[f] == mergemod.MERGE_RECORD_MERGED_OTHER:
6011 continue
6012 continue
6012
6013
6013 # don't let driver-resolved files be marked, and run the conclude
6014 # don't let driver-resolved files be marked, and run the conclude
6014 # step if asked to resolve
6015 # step if asked to resolve
6015 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6016 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6016 exact = m.exact(f)
6017 exact = m.exact(f)
6017 if mark:
6018 if mark:
6018 if exact:
6019 if exact:
6019 ui.warn(
6020 ui.warn(
6020 _(b'not marking %s as it is driver-resolved\n')
6021 _(b'not marking %s as it is driver-resolved\n')
6021 % uipathfn(f)
6022 % uipathfn(f)
6022 )
6023 )
6023 elif unmark:
6024 elif unmark:
6024 if exact:
6025 if exact:
6025 ui.warn(
6026 ui.warn(
6026 _(b'not unmarking %s as it is driver-resolved\n')
6027 _(b'not unmarking %s as it is driver-resolved\n')
6027 % uipathfn(f)
6028 % uipathfn(f)
6028 )
6029 )
6029 else:
6030 else:
6030 runconclude = True
6031 runconclude = True
6031 continue
6032 continue
6032
6033
6033 # path conflicts must be resolved manually
6034 # path conflicts must be resolved manually
6034 if ms[f] in (
6035 if ms[f] in (
6035 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6036 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6036 mergemod.MERGE_RECORD_RESOLVED_PATH,
6037 mergemod.MERGE_RECORD_RESOLVED_PATH,
6037 ):
6038 ):
6038 if mark:
6039 if mark:
6039 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6040 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6040 elif unmark:
6041 elif unmark:
6041 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6042 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6042 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6043 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6043 ui.warn(
6044 ui.warn(
6044 _(b'%s: path conflict must be resolved manually\n')
6045 _(b'%s: path conflict must be resolved manually\n')
6045 % uipathfn(f)
6046 % uipathfn(f)
6046 )
6047 )
6047 continue
6048 continue
6048
6049
6049 if mark:
6050 if mark:
6050 if markcheck:
6051 if markcheck:
6051 fdata = repo.wvfs.tryread(f)
6052 fdata = repo.wvfs.tryread(f)
6052 if (
6053 if (
6053 filemerge.hasconflictmarkers(fdata)
6054 filemerge.hasconflictmarkers(fdata)
6054 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6055 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6055 ):
6056 ):
6056 hasconflictmarkers.append(f)
6057 hasconflictmarkers.append(f)
6057 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6058 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6058 elif unmark:
6059 elif unmark:
6059 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6060 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6060 else:
6061 else:
6061 # backup pre-resolve (merge uses .orig for its own purposes)
6062 # backup pre-resolve (merge uses .orig for its own purposes)
6062 a = repo.wjoin(f)
6063 a = repo.wjoin(f)
6063 try:
6064 try:
6064 util.copyfile(a, a + b".resolve")
6065 util.copyfile(a, a + b".resolve")
6065 except (IOError, OSError) as inst:
6066 except (IOError, OSError) as inst:
6066 if inst.errno != errno.ENOENT:
6067 if inst.errno != errno.ENOENT:
6067 raise
6068 raise
6068
6069
6069 try:
6070 try:
6070 # preresolve file
6071 # preresolve file
6071 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6072 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6072 with ui.configoverride(overrides, b'resolve'):
6073 with ui.configoverride(overrides, b'resolve'):
6073 complete, r = ms.preresolve(f, wctx)
6074 complete, r = ms.preresolve(f, wctx)
6074 if not complete:
6075 if not complete:
6075 tocomplete.append(f)
6076 tocomplete.append(f)
6076 elif r:
6077 elif r:
6077 ret = 1
6078 ret = 1
6078 finally:
6079 finally:
6079 ms.commit()
6080 ms.commit()
6080
6081
6081 # replace filemerge's .orig file with our resolve file, but only
6082 # replace filemerge's .orig file with our resolve file, but only
6082 # for merges that are complete
6083 # for merges that are complete
6083 if complete:
6084 if complete:
6084 try:
6085 try:
6085 util.rename(
6086 util.rename(
6086 a + b".resolve", scmutil.backuppath(ui, repo, f)
6087 a + b".resolve", scmutil.backuppath(ui, repo, f)
6087 )
6088 )
6088 except OSError as inst:
6089 except OSError as inst:
6089 if inst.errno != errno.ENOENT:
6090 if inst.errno != errno.ENOENT:
6090 raise
6091 raise
6091
6092
6092 if hasconflictmarkers:
6093 if hasconflictmarkers:
6093 ui.warn(
6094 ui.warn(
6094 _(
6095 _(
6095 b'warning: the following files still have conflict '
6096 b'warning: the following files still have conflict '
6096 b'markers:\n'
6097 b'markers:\n'
6097 )
6098 )
6098 + b''.join(
6099 + b''.join(
6099 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6100 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6100 )
6101 )
6101 )
6102 )
6102 if markcheck == b'abort' and not all and not pats:
6103 if markcheck == b'abort' and not all and not pats:
6103 raise error.Abort(
6104 raise error.Abort(
6104 _(b'conflict markers detected'),
6105 _(b'conflict markers detected'),
6105 hint=_(b'use --all to mark anyway'),
6106 hint=_(b'use --all to mark anyway'),
6106 )
6107 )
6107
6108
6108 for f in tocomplete:
6109 for f in tocomplete:
6109 try:
6110 try:
6110 # resolve file
6111 # resolve file
6111 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6112 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6112 with ui.configoverride(overrides, b'resolve'):
6113 with ui.configoverride(overrides, b'resolve'):
6113 r = ms.resolve(f, wctx)
6114 r = ms.resolve(f, wctx)
6114 if r:
6115 if r:
6115 ret = 1
6116 ret = 1
6116 finally:
6117 finally:
6117 ms.commit()
6118 ms.commit()
6118
6119
6119 # replace filemerge's .orig file with our resolve file
6120 # replace filemerge's .orig file with our resolve file
6120 a = repo.wjoin(f)
6121 a = repo.wjoin(f)
6121 try:
6122 try:
6122 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6123 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6123 except OSError as inst:
6124 except OSError as inst:
6124 if inst.errno != errno.ENOENT:
6125 if inst.errno != errno.ENOENT:
6125 raise
6126 raise
6126
6127
6127 ms.commit()
6128 ms.commit()
6128 ms.recordactions()
6129 ms.recordactions()
6129
6130
6130 if not didwork and pats:
6131 if not didwork and pats:
6131 hint = None
6132 hint = None
6132 if not any([p for p in pats if p.find(b':') >= 0]):
6133 if not any([p for p in pats if p.find(b':') >= 0]):
6133 pats = [b'path:%s' % p for p in pats]
6134 pats = [b'path:%s' % p for p in pats]
6134 m = scmutil.match(wctx, pats, opts)
6135 m = scmutil.match(wctx, pats, opts)
6135 for f in ms:
6136 for f in ms:
6136 if not m(f):
6137 if not m(f):
6137 continue
6138 continue
6138
6139
6139 def flag(o):
6140 def flag(o):
6140 if o == b're_merge':
6141 if o == b're_merge':
6141 return b'--re-merge '
6142 return b'--re-merge '
6142 return b'-%s ' % o[0:1]
6143 return b'-%s ' % o[0:1]
6143
6144
6144 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6145 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6145 hint = _(b"(try: hg resolve %s%s)\n") % (
6146 hint = _(b"(try: hg resolve %s%s)\n") % (
6146 flags,
6147 flags,
6147 b' '.join(pats),
6148 b' '.join(pats),
6148 )
6149 )
6149 break
6150 break
6150 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6151 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6151 if hint:
6152 if hint:
6152 ui.warn(hint)
6153 ui.warn(hint)
6153 elif ms.mergedriver and ms.mdstate() != b's':
6154 elif ms.mergedriver and ms.mdstate() != b's':
6154 # run conclude step when either a driver-resolved file is requested
6155 # run conclude step when either a driver-resolved file is requested
6155 # or there are no driver-resolved files
6156 # or there are no driver-resolved files
6156 # we can't use 'ret' to determine whether any files are unresolved
6157 # we can't use 'ret' to determine whether any files are unresolved
6157 # because we might not have tried to resolve some
6158 # because we might not have tried to resolve some
6158 if (runconclude or not list(ms.driverresolved())) and not list(
6159 if (runconclude or not list(ms.driverresolved())) and not list(
6159 ms.unresolved()
6160 ms.unresolved()
6160 ):
6161 ):
6161 proceed = mergemod.driverconclude(repo, ms, wctx)
6162 proceed = mergemod.driverconclude(repo, ms, wctx)
6162 ms.commit()
6163 ms.commit()
6163 if not proceed:
6164 if not proceed:
6164 return 1
6165 return 1
6165
6166
6166 # Nudge users into finishing an unfinished operation
6167 # Nudge users into finishing an unfinished operation
6167 unresolvedf = list(ms.unresolved())
6168 unresolvedf = list(ms.unresolved())
6168 driverresolvedf = list(ms.driverresolved())
6169 driverresolvedf = list(ms.driverresolved())
6169 if not unresolvedf and not driverresolvedf:
6170 if not unresolvedf and not driverresolvedf:
6170 ui.status(_(b'(no more unresolved files)\n'))
6171 ui.status(_(b'(no more unresolved files)\n'))
6171 cmdutil.checkafterresolved(repo)
6172 cmdutil.checkafterresolved(repo)
6172 elif not unresolvedf:
6173 elif not unresolvedf:
6173 ui.status(
6174 ui.status(
6174 _(
6175 _(
6175 b'(no more unresolved files -- '
6176 b'(no more unresolved files -- '
6176 b'run "hg resolve --all" to conclude)\n'
6177 b'run "hg resolve --all" to conclude)\n'
6177 )
6178 )
6178 )
6179 )
6179
6180
6180 return ret
6181 return ret
6181
6182
6182
6183
6183 @command(
6184 @command(
6184 b'revert',
6185 b'revert',
6185 [
6186 [
6186 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6187 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6187 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6188 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6188 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6189 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6189 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6190 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6190 (b'i', b'interactive', None, _(b'interactively select the changes')),
6191 (b'i', b'interactive', None, _(b'interactively select the changes')),
6191 ]
6192 ]
6192 + walkopts
6193 + walkopts
6193 + dryrunopts,
6194 + dryrunopts,
6194 _(b'[OPTION]... [-r REV] [NAME]...'),
6195 _(b'[OPTION]... [-r REV] [NAME]...'),
6195 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6196 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6196 )
6197 )
6197 def revert(ui, repo, *pats, **opts):
6198 def revert(ui, repo, *pats, **opts):
6198 """restore files to their checkout state
6199 """restore files to their checkout state
6199
6200
6200 .. note::
6201 .. note::
6201
6202
6202 To check out earlier revisions, you should use :hg:`update REV`.
6203 To check out earlier revisions, you should use :hg:`update REV`.
6203 To cancel an uncommitted merge (and lose your changes),
6204 To cancel an uncommitted merge (and lose your changes),
6204 use :hg:`merge --abort`.
6205 use :hg:`merge --abort`.
6205
6206
6206 With no revision specified, revert the specified files or directories
6207 With no revision specified, revert the specified files or directories
6207 to the contents they had in the parent of the working directory.
6208 to the contents they had in the parent of the working directory.
6208 This restores the contents of files to an unmodified
6209 This restores the contents of files to an unmodified
6209 state and unschedules adds, removes, copies, and renames. If the
6210 state and unschedules adds, removes, copies, and renames. If the
6210 working directory has two parents, you must explicitly specify a
6211 working directory has two parents, you must explicitly specify a
6211 revision.
6212 revision.
6212
6213
6213 Using the -r/--rev or -d/--date options, revert the given files or
6214 Using the -r/--rev or -d/--date options, revert the given files or
6214 directories to their states as of a specific revision. Because
6215 directories to their states as of a specific revision. Because
6215 revert does not change the working directory parents, this will
6216 revert does not change the working directory parents, this will
6216 cause these files to appear modified. This can be helpful to "back
6217 cause these files to appear modified. This can be helpful to "back
6217 out" some or all of an earlier change. See :hg:`backout` for a
6218 out" some or all of an earlier change. See :hg:`backout` for a
6218 related method.
6219 related method.
6219
6220
6220 Modified files are saved with a .orig suffix before reverting.
6221 Modified files are saved with a .orig suffix before reverting.
6221 To disable these backups, use --no-backup. It is possible to store
6222 To disable these backups, use --no-backup. It is possible to store
6222 the backup files in a custom directory relative to the root of the
6223 the backup files in a custom directory relative to the root of the
6223 repository by setting the ``ui.origbackuppath`` configuration
6224 repository by setting the ``ui.origbackuppath`` configuration
6224 option.
6225 option.
6225
6226
6226 See :hg:`help dates` for a list of formats valid for -d/--date.
6227 See :hg:`help dates` for a list of formats valid for -d/--date.
6227
6228
6228 See :hg:`help backout` for a way to reverse the effect of an
6229 See :hg:`help backout` for a way to reverse the effect of an
6229 earlier changeset.
6230 earlier changeset.
6230
6231
6231 Returns 0 on success.
6232 Returns 0 on success.
6232 """
6233 """
6233
6234
6234 opts = pycompat.byteskwargs(opts)
6235 opts = pycompat.byteskwargs(opts)
6235 if opts.get(b"date"):
6236 if opts.get(b"date"):
6236 if opts.get(b"rev"):
6237 if opts.get(b"rev"):
6237 raise error.Abort(_(b"you can't specify a revision and a date"))
6238 raise error.Abort(_(b"you can't specify a revision and a date"))
6238 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6239 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6239
6240
6240 parent, p2 = repo.dirstate.parents()
6241 parent, p2 = repo.dirstate.parents()
6241 if not opts.get(b'rev') and p2 != nullid:
6242 if not opts.get(b'rev') and p2 != nullid:
6242 # revert after merge is a trap for new users (issue2915)
6243 # revert after merge is a trap for new users (issue2915)
6243 raise error.Abort(
6244 raise error.Abort(
6244 _(b'uncommitted merge with no revision specified'),
6245 _(b'uncommitted merge with no revision specified'),
6245 hint=_(b"use 'hg update' or see 'hg help revert'"),
6246 hint=_(b"use 'hg update' or see 'hg help revert'"),
6246 )
6247 )
6247
6248
6248 rev = opts.get(b'rev')
6249 rev = opts.get(b'rev')
6249 if rev:
6250 if rev:
6250 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6251 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6251 ctx = scmutil.revsingle(repo, rev)
6252 ctx = scmutil.revsingle(repo, rev)
6252
6253
6253 if not (
6254 if not (
6254 pats
6255 pats
6255 or opts.get(b'include')
6256 or opts.get(b'include')
6256 or opts.get(b'exclude')
6257 or opts.get(b'exclude')
6257 or opts.get(b'all')
6258 or opts.get(b'all')
6258 or opts.get(b'interactive')
6259 or opts.get(b'interactive')
6259 ):
6260 ):
6260 msg = _(b"no files or directories specified")
6261 msg = _(b"no files or directories specified")
6261 if p2 != nullid:
6262 if p2 != nullid:
6262 hint = _(
6263 hint = _(
6263 b"uncommitted merge, use --all to discard all changes,"
6264 b"uncommitted merge, use --all to discard all changes,"
6264 b" or 'hg update -C .' to abort the merge"
6265 b" or 'hg update -C .' to abort the merge"
6265 )
6266 )
6266 raise error.Abort(msg, hint=hint)
6267 raise error.Abort(msg, hint=hint)
6267 dirty = any(repo.status())
6268 dirty = any(repo.status())
6268 node = ctx.node()
6269 node = ctx.node()
6269 if node != parent:
6270 if node != parent:
6270 if dirty:
6271 if dirty:
6271 hint = (
6272 hint = (
6272 _(
6273 _(
6273 b"uncommitted changes, use --all to discard all"
6274 b"uncommitted changes, use --all to discard all"
6274 b" changes, or 'hg update %d' to update"
6275 b" changes, or 'hg update %d' to update"
6275 )
6276 )
6276 % ctx.rev()
6277 % ctx.rev()
6277 )
6278 )
6278 else:
6279 else:
6279 hint = (
6280 hint = (
6280 _(
6281 _(
6281 b"use --all to revert all files,"
6282 b"use --all to revert all files,"
6282 b" or 'hg update %d' to update"
6283 b" or 'hg update %d' to update"
6283 )
6284 )
6284 % ctx.rev()
6285 % ctx.rev()
6285 )
6286 )
6286 elif dirty:
6287 elif dirty:
6287 hint = _(b"uncommitted changes, use --all to discard all changes")
6288 hint = _(b"uncommitted changes, use --all to discard all changes")
6288 else:
6289 else:
6289 hint = _(b"use --all to revert all files")
6290 hint = _(b"use --all to revert all files")
6290 raise error.Abort(msg, hint=hint)
6291 raise error.Abort(msg, hint=hint)
6291
6292
6292 return cmdutil.revert(
6293 return cmdutil.revert(
6293 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6294 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6294 )
6295 )
6295
6296
6296
6297
6297 @command(
6298 @command(
6298 b'rollback',
6299 b'rollback',
6299 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6300 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6300 helpcategory=command.CATEGORY_MAINTENANCE,
6301 helpcategory=command.CATEGORY_MAINTENANCE,
6301 )
6302 )
6302 def rollback(ui, repo, **opts):
6303 def rollback(ui, repo, **opts):
6303 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6304 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6304
6305
6305 Please use :hg:`commit --amend` instead of rollback to correct
6306 Please use :hg:`commit --amend` instead of rollback to correct
6306 mistakes in the last commit.
6307 mistakes in the last commit.
6307
6308
6308 This command should be used with care. There is only one level of
6309 This command should be used with care. There is only one level of
6309 rollback, and there is no way to undo a rollback. It will also
6310 rollback, and there is no way to undo a rollback. It will also
6310 restore the dirstate at the time of the last transaction, losing
6311 restore the dirstate at the time of the last transaction, losing
6311 any dirstate changes since that time. This command does not alter
6312 any dirstate changes since that time. This command does not alter
6312 the working directory.
6313 the working directory.
6313
6314
6314 Transactions are used to encapsulate the effects of all commands
6315 Transactions are used to encapsulate the effects of all commands
6315 that create new changesets or propagate existing changesets into a
6316 that create new changesets or propagate existing changesets into a
6316 repository.
6317 repository.
6317
6318
6318 .. container:: verbose
6319 .. container:: verbose
6319
6320
6320 For example, the following commands are transactional, and their
6321 For example, the following commands are transactional, and their
6321 effects can be rolled back:
6322 effects can be rolled back:
6322
6323
6323 - commit
6324 - commit
6324 - import
6325 - import
6325 - pull
6326 - pull
6326 - push (with this repository as the destination)
6327 - push (with this repository as the destination)
6327 - unbundle
6328 - unbundle
6328
6329
6329 To avoid permanent data loss, rollback will refuse to rollback a
6330 To avoid permanent data loss, rollback will refuse to rollback a
6330 commit transaction if it isn't checked out. Use --force to
6331 commit transaction if it isn't checked out. Use --force to
6331 override this protection.
6332 override this protection.
6332
6333
6333 The rollback command can be entirely disabled by setting the
6334 The rollback command can be entirely disabled by setting the
6334 ``ui.rollback`` configuration setting to false. If you're here
6335 ``ui.rollback`` configuration setting to false. If you're here
6335 because you want to use rollback and it's disabled, you can
6336 because you want to use rollback and it's disabled, you can
6336 re-enable the command by setting ``ui.rollback`` to true.
6337 re-enable the command by setting ``ui.rollback`` to true.
6337
6338
6338 This command is not intended for use on public repositories. Once
6339 This command is not intended for use on public repositories. Once
6339 changes are visible for pull by other users, rolling a transaction
6340 changes are visible for pull by other users, rolling a transaction
6340 back locally is ineffective (someone else may already have pulled
6341 back locally is ineffective (someone else may already have pulled
6341 the changes). Furthermore, a race is possible with readers of the
6342 the changes). Furthermore, a race is possible with readers of the
6342 repository; for example an in-progress pull from the repository
6343 repository; for example an in-progress pull from the repository
6343 may fail if a rollback is performed.
6344 may fail if a rollback is performed.
6344
6345
6345 Returns 0 on success, 1 if no rollback data is available.
6346 Returns 0 on success, 1 if no rollback data is available.
6346 """
6347 """
6347 if not ui.configbool(b'ui', b'rollback'):
6348 if not ui.configbool(b'ui', b'rollback'):
6348 raise error.Abort(
6349 raise error.Abort(
6349 _(b'rollback is disabled because it is unsafe'),
6350 _(b'rollback is disabled because it is unsafe'),
6350 hint=b'see `hg help -v rollback` for information',
6351 hint=b'see `hg help -v rollback` for information',
6351 )
6352 )
6352 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6353 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6353
6354
6354
6355
6355 @command(
6356 @command(
6356 b'root',
6357 b'root',
6357 [] + formatteropts,
6358 [] + formatteropts,
6358 intents={INTENT_READONLY},
6359 intents={INTENT_READONLY},
6359 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6360 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6360 )
6361 )
6361 def root(ui, repo, **opts):
6362 def root(ui, repo, **opts):
6362 """print the root (top) of the current working directory
6363 """print the root (top) of the current working directory
6363
6364
6364 Print the root directory of the current repository.
6365 Print the root directory of the current repository.
6365
6366
6366 .. container:: verbose
6367 .. container:: verbose
6367
6368
6368 Template:
6369 Template:
6369
6370
6370 The following keywords are supported in addition to the common template
6371 The following keywords are supported in addition to the common template
6371 keywords and functions. See also :hg:`help templates`.
6372 keywords and functions. See also :hg:`help templates`.
6372
6373
6373 :hgpath: String. Path to the .hg directory.
6374 :hgpath: String. Path to the .hg directory.
6374 :storepath: String. Path to the directory holding versioned data.
6375 :storepath: String. Path to the directory holding versioned data.
6375
6376
6376 Returns 0 on success.
6377 Returns 0 on success.
6377 """
6378 """
6378 opts = pycompat.byteskwargs(opts)
6379 opts = pycompat.byteskwargs(opts)
6379 with ui.formatter(b'root', opts) as fm:
6380 with ui.formatter(b'root', opts) as fm:
6380 fm.startitem()
6381 fm.startitem()
6381 fm.write(b'reporoot', b'%s\n', repo.root)
6382 fm.write(b'reporoot', b'%s\n', repo.root)
6382 fm.data(hgpath=repo.path, storepath=repo.spath)
6383 fm.data(hgpath=repo.path, storepath=repo.spath)
6383
6384
6384
6385
6385 @command(
6386 @command(
6386 b'serve',
6387 b'serve',
6387 [
6388 [
6388 (
6389 (
6389 b'A',
6390 b'A',
6390 b'accesslog',
6391 b'accesslog',
6391 b'',
6392 b'',
6392 _(b'name of access log file to write to'),
6393 _(b'name of access log file to write to'),
6393 _(b'FILE'),
6394 _(b'FILE'),
6394 ),
6395 ),
6395 (b'd', b'daemon', None, _(b'run server in background')),
6396 (b'd', b'daemon', None, _(b'run server in background')),
6396 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6397 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6397 (
6398 (
6398 b'E',
6399 b'E',
6399 b'errorlog',
6400 b'errorlog',
6400 b'',
6401 b'',
6401 _(b'name of error log file to write to'),
6402 _(b'name of error log file to write to'),
6402 _(b'FILE'),
6403 _(b'FILE'),
6403 ),
6404 ),
6404 # use string type, then we can check if something was passed
6405 # use string type, then we can check if something was passed
6405 (
6406 (
6406 b'p',
6407 b'p',
6407 b'port',
6408 b'port',
6408 b'',
6409 b'',
6409 _(b'port to listen on (default: 8000)'),
6410 _(b'port to listen on (default: 8000)'),
6410 _(b'PORT'),
6411 _(b'PORT'),
6411 ),
6412 ),
6412 (
6413 (
6413 b'a',
6414 b'a',
6414 b'address',
6415 b'address',
6415 b'',
6416 b'',
6416 _(b'address to listen on (default: all interfaces)'),
6417 _(b'address to listen on (default: all interfaces)'),
6417 _(b'ADDR'),
6418 _(b'ADDR'),
6418 ),
6419 ),
6419 (
6420 (
6420 b'',
6421 b'',
6421 b'prefix',
6422 b'prefix',
6422 b'',
6423 b'',
6423 _(b'prefix path to serve from (default: server root)'),
6424 _(b'prefix path to serve from (default: server root)'),
6424 _(b'PREFIX'),
6425 _(b'PREFIX'),
6425 ),
6426 ),
6426 (
6427 (
6427 b'n',
6428 b'n',
6428 b'name',
6429 b'name',
6429 b'',
6430 b'',
6430 _(b'name to show in web pages (default: working directory)'),
6431 _(b'name to show in web pages (default: working directory)'),
6431 _(b'NAME'),
6432 _(b'NAME'),
6432 ),
6433 ),
6433 (
6434 (
6434 b'',
6435 b'',
6435 b'web-conf',
6436 b'web-conf',
6436 b'',
6437 b'',
6437 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6438 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6438 _(b'FILE'),
6439 _(b'FILE'),
6439 ),
6440 ),
6440 (
6441 (
6441 b'',
6442 b'',
6442 b'webdir-conf',
6443 b'webdir-conf',
6443 b'',
6444 b'',
6444 _(b'name of the hgweb config file (DEPRECATED)'),
6445 _(b'name of the hgweb config file (DEPRECATED)'),
6445 _(b'FILE'),
6446 _(b'FILE'),
6446 ),
6447 ),
6447 (
6448 (
6448 b'',
6449 b'',
6449 b'pid-file',
6450 b'pid-file',
6450 b'',
6451 b'',
6451 _(b'name of file to write process ID to'),
6452 _(b'name of file to write process ID to'),
6452 _(b'FILE'),
6453 _(b'FILE'),
6453 ),
6454 ),
6454 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6455 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6455 (
6456 (
6456 b'',
6457 b'',
6457 b'cmdserver',
6458 b'cmdserver',
6458 b'',
6459 b'',
6459 _(b'for remote clients (ADVANCED)'),
6460 _(b'for remote clients (ADVANCED)'),
6460 _(b'MODE'),
6461 _(b'MODE'),
6461 ),
6462 ),
6462 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6463 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6463 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6464 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6464 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6465 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6465 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6466 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6466 (b'', b'print-url', None, _(b'start and print only the URL')),
6467 (b'', b'print-url', None, _(b'start and print only the URL')),
6467 ]
6468 ]
6468 + subrepoopts,
6469 + subrepoopts,
6469 _(b'[OPTION]...'),
6470 _(b'[OPTION]...'),
6470 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6471 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6471 helpbasic=True,
6472 helpbasic=True,
6472 optionalrepo=True,
6473 optionalrepo=True,
6473 )
6474 )
6474 def serve(ui, repo, **opts):
6475 def serve(ui, repo, **opts):
6475 """start stand-alone webserver
6476 """start stand-alone webserver
6476
6477
6477 Start a local HTTP repository browser and pull server. You can use
6478 Start a local HTTP repository browser and pull server. You can use
6478 this for ad-hoc sharing and browsing of repositories. It is
6479 this for ad-hoc sharing and browsing of repositories. It is
6479 recommended to use a real web server to serve a repository for
6480 recommended to use a real web server to serve a repository for
6480 longer periods of time.
6481 longer periods of time.
6481
6482
6482 Please note that the server does not implement access control.
6483 Please note that the server does not implement access control.
6483 This means that, by default, anybody can read from the server and
6484 This means that, by default, anybody can read from the server and
6484 nobody can write to it by default. Set the ``web.allow-push``
6485 nobody can write to it by default. Set the ``web.allow-push``
6485 option to ``*`` to allow everybody to push to the server. You
6486 option to ``*`` to allow everybody to push to the server. You
6486 should use a real web server if you need to authenticate users.
6487 should use a real web server if you need to authenticate users.
6487
6488
6488 By default, the server logs accesses to stdout and errors to
6489 By default, the server logs accesses to stdout and errors to
6489 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6490 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6490 files.
6491 files.
6491
6492
6492 To have the server choose a free port number to listen on, specify
6493 To have the server choose a free port number to listen on, specify
6493 a port number of 0; in this case, the server will print the port
6494 a port number of 0; in this case, the server will print the port
6494 number it uses.
6495 number it uses.
6495
6496
6496 Returns 0 on success.
6497 Returns 0 on success.
6497 """
6498 """
6498
6499
6499 opts = pycompat.byteskwargs(opts)
6500 opts = pycompat.byteskwargs(opts)
6500 if opts[b"stdio"] and opts[b"cmdserver"]:
6501 if opts[b"stdio"] and opts[b"cmdserver"]:
6501 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6502 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6502 if opts[b"print_url"] and ui.verbose:
6503 if opts[b"print_url"] and ui.verbose:
6503 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6504 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6504
6505
6505 if opts[b"stdio"]:
6506 if opts[b"stdio"]:
6506 if repo is None:
6507 if repo is None:
6507 raise error.RepoError(
6508 raise error.RepoError(
6508 _(b"there is no Mercurial repository here (.hg not found)")
6509 _(b"there is no Mercurial repository here (.hg not found)")
6509 )
6510 )
6510 s = wireprotoserver.sshserver(ui, repo)
6511 s = wireprotoserver.sshserver(ui, repo)
6511 s.serve_forever()
6512 s.serve_forever()
6512
6513
6513 service = server.createservice(ui, repo, opts)
6514 service = server.createservice(ui, repo, opts)
6514 return server.runservice(opts, initfn=service.init, runfn=service.run)
6515 return server.runservice(opts, initfn=service.init, runfn=service.run)
6515
6516
6516
6517
6517 @command(
6518 @command(
6518 b'shelve',
6519 b'shelve',
6519 [
6520 [
6520 (
6521 (
6521 b'A',
6522 b'A',
6522 b'addremove',
6523 b'addremove',
6523 None,
6524 None,
6524 _(b'mark new/missing files as added/removed before shelving'),
6525 _(b'mark new/missing files as added/removed before shelving'),
6525 ),
6526 ),
6526 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6527 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6527 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6528 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6528 (
6529 (
6529 b'',
6530 b'',
6530 b'date',
6531 b'date',
6531 b'',
6532 b'',
6532 _(b'shelve with the specified commit date'),
6533 _(b'shelve with the specified commit date'),
6533 _(b'DATE'),
6534 _(b'DATE'),
6534 ),
6535 ),
6535 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6536 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6536 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6537 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6537 (
6538 (
6538 b'k',
6539 b'k',
6539 b'keep',
6540 b'keep',
6540 False,
6541 False,
6541 _(b'shelve, but keep changes in the working directory'),
6542 _(b'shelve, but keep changes in the working directory'),
6542 ),
6543 ),
6543 (b'l', b'list', None, _(b'list current shelves')),
6544 (b'l', b'list', None, _(b'list current shelves')),
6544 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6545 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6545 (
6546 (
6546 b'n',
6547 b'n',
6547 b'name',
6548 b'name',
6548 b'',
6549 b'',
6549 _(b'use the given name for the shelved commit'),
6550 _(b'use the given name for the shelved commit'),
6550 _(b'NAME'),
6551 _(b'NAME'),
6551 ),
6552 ),
6552 (
6553 (
6553 b'p',
6554 b'p',
6554 b'patch',
6555 b'patch',
6555 None,
6556 None,
6556 _(
6557 _(
6557 b'output patches for changes (provide the names of the shelved '
6558 b'output patches for changes (provide the names of the shelved '
6558 b'changes as positional arguments)'
6559 b'changes as positional arguments)'
6559 ),
6560 ),
6560 ),
6561 ),
6561 (b'i', b'interactive', None, _(b'interactive mode')),
6562 (b'i', b'interactive', None, _(b'interactive mode')),
6562 (
6563 (
6563 b'',
6564 b'',
6564 b'stat',
6565 b'stat',
6565 None,
6566 None,
6566 _(
6567 _(
6567 b'output diffstat-style summary of changes (provide the names of '
6568 b'output diffstat-style summary of changes (provide the names of '
6568 b'the shelved changes as positional arguments)'
6569 b'the shelved changes as positional arguments)'
6569 ),
6570 ),
6570 ),
6571 ),
6571 ]
6572 ]
6572 + cmdutil.walkopts,
6573 + cmdutil.walkopts,
6573 _(b'hg shelve [OPTION]... [FILE]...'),
6574 _(b'hg shelve [OPTION]... [FILE]...'),
6574 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6575 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6575 )
6576 )
6576 def shelve(ui, repo, *pats, **opts):
6577 def shelve(ui, repo, *pats, **opts):
6577 '''save and set aside changes from the working directory
6578 '''save and set aside changes from the working directory
6578
6579
6579 Shelving takes files that "hg status" reports as not clean, saves
6580 Shelving takes files that "hg status" reports as not clean, saves
6580 the modifications to a bundle (a shelved change), and reverts the
6581 the modifications to a bundle (a shelved change), and reverts the
6581 files so that their state in the working directory becomes clean.
6582 files so that their state in the working directory becomes clean.
6582
6583
6583 To restore these changes to the working directory, using "hg
6584 To restore these changes to the working directory, using "hg
6584 unshelve"; this will work even if you switch to a different
6585 unshelve"; this will work even if you switch to a different
6585 commit.
6586 commit.
6586
6587
6587 When no files are specified, "hg shelve" saves all not-clean
6588 When no files are specified, "hg shelve" saves all not-clean
6588 files. If specific files or directories are named, only changes to
6589 files. If specific files or directories are named, only changes to
6589 those files are shelved.
6590 those files are shelved.
6590
6591
6591 In bare shelve (when no files are specified, without interactive,
6592 In bare shelve (when no files are specified, without interactive,
6592 include and exclude option), shelving remembers information if the
6593 include and exclude option), shelving remembers information if the
6593 working directory was on newly created branch, in other words working
6594 working directory was on newly created branch, in other words working
6594 directory was on different branch than its first parent. In this
6595 directory was on different branch than its first parent. In this
6595 situation unshelving restores branch information to the working directory.
6596 situation unshelving restores branch information to the working directory.
6596
6597
6597 Each shelved change has a name that makes it easier to find later.
6598 Each shelved change has a name that makes it easier to find later.
6598 The name of a shelved change defaults to being based on the active
6599 The name of a shelved change defaults to being based on the active
6599 bookmark, or if there is no active bookmark, the current named
6600 bookmark, or if there is no active bookmark, the current named
6600 branch. To specify a different name, use ``--name``.
6601 branch. To specify a different name, use ``--name``.
6601
6602
6602 To see a list of existing shelved changes, use the ``--list``
6603 To see a list of existing shelved changes, use the ``--list``
6603 option. For each shelved change, this will print its name, age,
6604 option. For each shelved change, this will print its name, age,
6604 and description; use ``--patch`` or ``--stat`` for more details.
6605 and description; use ``--patch`` or ``--stat`` for more details.
6605
6606
6606 To delete specific shelved changes, use ``--delete``. To delete
6607 To delete specific shelved changes, use ``--delete``. To delete
6607 all shelved changes, use ``--cleanup``.
6608 all shelved changes, use ``--cleanup``.
6608 '''
6609 '''
6609 opts = pycompat.byteskwargs(opts)
6610 opts = pycompat.byteskwargs(opts)
6610 allowables = [
6611 allowables = [
6611 (b'addremove', {b'create'}), # 'create' is pseudo action
6612 (b'addremove', {b'create'}), # 'create' is pseudo action
6612 (b'unknown', {b'create'}),
6613 (b'unknown', {b'create'}),
6613 (b'cleanup', {b'cleanup'}),
6614 (b'cleanup', {b'cleanup'}),
6614 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6615 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6615 (b'delete', {b'delete'}),
6616 (b'delete', {b'delete'}),
6616 (b'edit', {b'create'}),
6617 (b'edit', {b'create'}),
6617 (b'keep', {b'create'}),
6618 (b'keep', {b'create'}),
6618 (b'list', {b'list'}),
6619 (b'list', {b'list'}),
6619 (b'message', {b'create'}),
6620 (b'message', {b'create'}),
6620 (b'name', {b'create'}),
6621 (b'name', {b'create'}),
6621 (b'patch', {b'patch', b'list'}),
6622 (b'patch', {b'patch', b'list'}),
6622 (b'stat', {b'stat', b'list'}),
6623 (b'stat', {b'stat', b'list'}),
6623 ]
6624 ]
6624
6625
6625 def checkopt(opt):
6626 def checkopt(opt):
6626 if opts.get(opt):
6627 if opts.get(opt):
6627 for i, allowable in allowables:
6628 for i, allowable in allowables:
6628 if opts[i] and opt not in allowable:
6629 if opts[i] and opt not in allowable:
6629 raise error.Abort(
6630 raise error.Abort(
6630 _(
6631 _(
6631 b"options '--%s' and '--%s' may not be "
6632 b"options '--%s' and '--%s' may not be "
6632 b"used together"
6633 b"used together"
6633 )
6634 )
6634 % (opt, i)
6635 % (opt, i)
6635 )
6636 )
6636 return True
6637 return True
6637
6638
6638 if checkopt(b'cleanup'):
6639 if checkopt(b'cleanup'):
6639 if pats:
6640 if pats:
6640 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6641 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6641 return shelvemod.cleanupcmd(ui, repo)
6642 return shelvemod.cleanupcmd(ui, repo)
6642 elif checkopt(b'delete'):
6643 elif checkopt(b'delete'):
6643 return shelvemod.deletecmd(ui, repo, pats)
6644 return shelvemod.deletecmd(ui, repo, pats)
6644 elif checkopt(b'list'):
6645 elif checkopt(b'list'):
6645 return shelvemod.listcmd(ui, repo, pats, opts)
6646 return shelvemod.listcmd(ui, repo, pats, opts)
6646 elif checkopt(b'patch') or checkopt(b'stat'):
6647 elif checkopt(b'patch') or checkopt(b'stat'):
6647 return shelvemod.patchcmds(ui, repo, pats, opts)
6648 return shelvemod.patchcmds(ui, repo, pats, opts)
6648 else:
6649 else:
6649 return shelvemod.createcmd(ui, repo, pats, opts)
6650 return shelvemod.createcmd(ui, repo, pats, opts)
6650
6651
6651
6652
6652 _NOTTERSE = b'nothing'
6653 _NOTTERSE = b'nothing'
6653
6654
6654
6655
6655 @command(
6656 @command(
6656 b'status|st',
6657 b'status|st',
6657 [
6658 [
6658 (b'A', b'all', None, _(b'show status of all files')),
6659 (b'A', b'all', None, _(b'show status of all files')),
6659 (b'm', b'modified', None, _(b'show only modified files')),
6660 (b'm', b'modified', None, _(b'show only modified files')),
6660 (b'a', b'added', None, _(b'show only added files')),
6661 (b'a', b'added', None, _(b'show only added files')),
6661 (b'r', b'removed', None, _(b'show only removed files')),
6662 (b'r', b'removed', None, _(b'show only removed files')),
6662 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6663 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6663 (b'c', b'clean', None, _(b'show only files without changes')),
6664 (b'c', b'clean', None, _(b'show only files without changes')),
6664 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6665 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6665 (b'i', b'ignored', None, _(b'show only ignored files')),
6666 (b'i', b'ignored', None, _(b'show only ignored files')),
6666 (b'n', b'no-status', None, _(b'hide status prefix')),
6667 (b'n', b'no-status', None, _(b'hide status prefix')),
6667 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6668 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6668 (
6669 (
6669 b'C',
6670 b'C',
6670 b'copies',
6671 b'copies',
6671 None,
6672 None,
6672 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6673 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6673 ),
6674 ),
6674 (
6675 (
6675 b'0',
6676 b'0',
6676 b'print0',
6677 b'print0',
6677 None,
6678 None,
6678 _(b'end filenames with NUL, for use with xargs'),
6679 _(b'end filenames with NUL, for use with xargs'),
6679 ),
6680 ),
6680 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6681 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6681 (
6682 (
6682 b'',
6683 b'',
6683 b'change',
6684 b'change',
6684 b'',
6685 b'',
6685 _(b'list the changed files of a revision'),
6686 _(b'list the changed files of a revision'),
6686 _(b'REV'),
6687 _(b'REV'),
6687 ),
6688 ),
6688 ]
6689 ]
6689 + walkopts
6690 + walkopts
6690 + subrepoopts
6691 + subrepoopts
6691 + formatteropts,
6692 + formatteropts,
6692 _(b'[OPTION]... [FILE]...'),
6693 _(b'[OPTION]... [FILE]...'),
6693 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6694 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6694 helpbasic=True,
6695 helpbasic=True,
6695 inferrepo=True,
6696 inferrepo=True,
6696 intents={INTENT_READONLY},
6697 intents={INTENT_READONLY},
6697 )
6698 )
6698 def status(ui, repo, *pats, **opts):
6699 def status(ui, repo, *pats, **opts):
6699 """show changed files in the working directory
6700 """show changed files in the working directory
6700
6701
6701 Show status of files in the repository. If names are given, only
6702 Show status of files in the repository. If names are given, only
6702 files that match are shown. Files that are clean or ignored or
6703 files that match are shown. Files that are clean or ignored or
6703 the source of a copy/move operation, are not listed unless
6704 the source of a copy/move operation, are not listed unless
6704 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6705 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6705 Unless options described with "show only ..." are given, the
6706 Unless options described with "show only ..." are given, the
6706 options -mardu are used.
6707 options -mardu are used.
6707
6708
6708 Option -q/--quiet hides untracked (unknown and ignored) files
6709 Option -q/--quiet hides untracked (unknown and ignored) files
6709 unless explicitly requested with -u/--unknown or -i/--ignored.
6710 unless explicitly requested with -u/--unknown or -i/--ignored.
6710
6711
6711 .. note::
6712 .. note::
6712
6713
6713 :hg:`status` may appear to disagree with diff if permissions have
6714 :hg:`status` may appear to disagree with diff if permissions have
6714 changed or a merge has occurred. The standard diff format does
6715 changed or a merge has occurred. The standard diff format does
6715 not report permission changes and diff only reports changes
6716 not report permission changes and diff only reports changes
6716 relative to one merge parent.
6717 relative to one merge parent.
6717
6718
6718 If one revision is given, it is used as the base revision.
6719 If one revision is given, it is used as the base revision.
6719 If two revisions are given, the differences between them are
6720 If two revisions are given, the differences between them are
6720 shown. The --change option can also be used as a shortcut to list
6721 shown. The --change option can also be used as a shortcut to list
6721 the changed files of a revision from its first parent.
6722 the changed files of a revision from its first parent.
6722
6723
6723 The codes used to show the status of files are::
6724 The codes used to show the status of files are::
6724
6725
6725 M = modified
6726 M = modified
6726 A = added
6727 A = added
6727 R = removed
6728 R = removed
6728 C = clean
6729 C = clean
6729 ! = missing (deleted by non-hg command, but still tracked)
6730 ! = missing (deleted by non-hg command, but still tracked)
6730 ? = not tracked
6731 ? = not tracked
6731 I = ignored
6732 I = ignored
6732 = origin of the previous file (with --copies)
6733 = origin of the previous file (with --copies)
6733
6734
6734 .. container:: verbose
6735 .. container:: verbose
6735
6736
6736 The -t/--terse option abbreviates the output by showing only the directory
6737 The -t/--terse option abbreviates the output by showing only the directory
6737 name if all the files in it share the same status. The option takes an
6738 name if all the files in it share the same status. The option takes an
6738 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6739 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6739 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6740 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6740 for 'ignored' and 'c' for clean.
6741 for 'ignored' and 'c' for clean.
6741
6742
6742 It abbreviates only those statuses which are passed. Note that clean and
6743 It abbreviates only those statuses which are passed. Note that clean and
6743 ignored files are not displayed with '--terse ic' unless the -c/--clean
6744 ignored files are not displayed with '--terse ic' unless the -c/--clean
6744 and -i/--ignored options are also used.
6745 and -i/--ignored options are also used.
6745
6746
6746 The -v/--verbose option shows information when the repository is in an
6747 The -v/--verbose option shows information when the repository is in an
6747 unfinished merge, shelve, rebase state etc. You can have this behavior
6748 unfinished merge, shelve, rebase state etc. You can have this behavior
6748 turned on by default by enabling the ``commands.status.verbose`` option.
6749 turned on by default by enabling the ``commands.status.verbose`` option.
6749
6750
6750 You can skip displaying some of these states by setting
6751 You can skip displaying some of these states by setting
6751 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6752 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6752 'histedit', 'merge', 'rebase', or 'unshelve'.
6753 'histedit', 'merge', 'rebase', or 'unshelve'.
6753
6754
6754 Template:
6755 Template:
6755
6756
6756 The following keywords are supported in addition to the common template
6757 The following keywords are supported in addition to the common template
6757 keywords and functions. See also :hg:`help templates`.
6758 keywords and functions. See also :hg:`help templates`.
6758
6759
6759 :path: String. Repository-absolute path of the file.
6760 :path: String. Repository-absolute path of the file.
6760 :source: String. Repository-absolute path of the file originated from.
6761 :source: String. Repository-absolute path of the file originated from.
6761 Available if ``--copies`` is specified.
6762 Available if ``--copies`` is specified.
6762 :status: String. Character denoting file's status.
6763 :status: String. Character denoting file's status.
6763
6764
6764 Examples:
6765 Examples:
6765
6766
6766 - show changes in the working directory relative to a
6767 - show changes in the working directory relative to a
6767 changeset::
6768 changeset::
6768
6769
6769 hg status --rev 9353
6770 hg status --rev 9353
6770
6771
6771 - show changes in the working directory relative to the
6772 - show changes in the working directory relative to the
6772 current directory (see :hg:`help patterns` for more information)::
6773 current directory (see :hg:`help patterns` for more information)::
6773
6774
6774 hg status re:
6775 hg status re:
6775
6776
6776 - show all changes including copies in an existing changeset::
6777 - show all changes including copies in an existing changeset::
6777
6778
6778 hg status --copies --change 9353
6779 hg status --copies --change 9353
6779
6780
6780 - get a NUL separated list of added files, suitable for xargs::
6781 - get a NUL separated list of added files, suitable for xargs::
6781
6782
6782 hg status -an0
6783 hg status -an0
6783
6784
6784 - show more information about the repository status, abbreviating
6785 - show more information about the repository status, abbreviating
6785 added, removed, modified, deleted, and untracked paths::
6786 added, removed, modified, deleted, and untracked paths::
6786
6787
6787 hg status -v -t mardu
6788 hg status -v -t mardu
6788
6789
6789 Returns 0 on success.
6790 Returns 0 on success.
6790
6791
6791 """
6792 """
6792
6793
6793 opts = pycompat.byteskwargs(opts)
6794 opts = pycompat.byteskwargs(opts)
6794 revs = opts.get(b'rev')
6795 revs = opts.get(b'rev')
6795 change = opts.get(b'change')
6796 change = opts.get(b'change')
6796 terse = opts.get(b'terse')
6797 terse = opts.get(b'terse')
6797 if terse is _NOTTERSE:
6798 if terse is _NOTTERSE:
6798 if revs:
6799 if revs:
6799 terse = b''
6800 terse = b''
6800 else:
6801 else:
6801 terse = ui.config(b'commands', b'status.terse')
6802 terse = ui.config(b'commands', b'status.terse')
6802
6803
6803 if revs and change:
6804 if revs and change:
6804 msg = _(b'cannot specify --rev and --change at the same time')
6805 msg = _(b'cannot specify --rev and --change at the same time')
6805 raise error.Abort(msg)
6806 raise error.Abort(msg)
6806 elif revs and terse:
6807 elif revs and terse:
6807 msg = _(b'cannot use --terse with --rev')
6808 msg = _(b'cannot use --terse with --rev')
6808 raise error.Abort(msg)
6809 raise error.Abort(msg)
6809 elif change:
6810 elif change:
6810 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6811 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6811 ctx2 = scmutil.revsingle(repo, change, None)
6812 ctx2 = scmutil.revsingle(repo, change, None)
6812 ctx1 = ctx2.p1()
6813 ctx1 = ctx2.p1()
6813 else:
6814 else:
6814 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6815 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6815 ctx1, ctx2 = scmutil.revpair(repo, revs)
6816 ctx1, ctx2 = scmutil.revpair(repo, revs)
6816
6817
6817 forcerelativevalue = None
6818 forcerelativevalue = None
6818 if ui.hasconfig(b'commands', b'status.relative'):
6819 if ui.hasconfig(b'commands', b'status.relative'):
6819 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6820 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6820 uipathfn = scmutil.getuipathfn(
6821 uipathfn = scmutil.getuipathfn(
6821 repo,
6822 repo,
6822 legacyrelativevalue=bool(pats),
6823 legacyrelativevalue=bool(pats),
6823 forcerelativevalue=forcerelativevalue,
6824 forcerelativevalue=forcerelativevalue,
6824 )
6825 )
6825
6826
6826 if opts.get(b'print0'):
6827 if opts.get(b'print0'):
6827 end = b'\0'
6828 end = b'\0'
6828 else:
6829 else:
6829 end = b'\n'
6830 end = b'\n'
6830 states = b'modified added removed deleted unknown ignored clean'.split()
6831 states = b'modified added removed deleted unknown ignored clean'.split()
6831 show = [k for k in states if opts.get(k)]
6832 show = [k for k in states if opts.get(k)]
6832 if opts.get(b'all'):
6833 if opts.get(b'all'):
6833 show += ui.quiet and (states[:4] + [b'clean']) or states
6834 show += ui.quiet and (states[:4] + [b'clean']) or states
6834
6835
6835 if not show:
6836 if not show:
6836 if ui.quiet:
6837 if ui.quiet:
6837 show = states[:4]
6838 show = states[:4]
6838 else:
6839 else:
6839 show = states[:5]
6840 show = states[:5]
6840
6841
6841 m = scmutil.match(ctx2, pats, opts)
6842 m = scmutil.match(ctx2, pats, opts)
6842 if terse:
6843 if terse:
6843 # we need to compute clean and unknown to terse
6844 # we need to compute clean and unknown to terse
6844 stat = repo.status(
6845 stat = repo.status(
6845 ctx1.node(),
6846 ctx1.node(),
6846 ctx2.node(),
6847 ctx2.node(),
6847 m,
6848 m,
6848 b'ignored' in show or b'i' in terse,
6849 b'ignored' in show or b'i' in terse,
6849 clean=True,
6850 clean=True,
6850 unknown=True,
6851 unknown=True,
6851 listsubrepos=opts.get(b'subrepos'),
6852 listsubrepos=opts.get(b'subrepos'),
6852 )
6853 )
6853
6854
6854 stat = cmdutil.tersedir(stat, terse)
6855 stat = cmdutil.tersedir(stat, terse)
6855 else:
6856 else:
6856 stat = repo.status(
6857 stat = repo.status(
6857 ctx1.node(),
6858 ctx1.node(),
6858 ctx2.node(),
6859 ctx2.node(),
6859 m,
6860 m,
6860 b'ignored' in show,
6861 b'ignored' in show,
6861 b'clean' in show,
6862 b'clean' in show,
6862 b'unknown' in show,
6863 b'unknown' in show,
6863 opts.get(b'subrepos'),
6864 opts.get(b'subrepos'),
6864 )
6865 )
6865
6866
6866 changestates = zip(
6867 changestates = zip(
6867 states,
6868 states,
6868 pycompat.iterbytestr(b'MAR!?IC'),
6869 pycompat.iterbytestr(b'MAR!?IC'),
6869 [getattr(stat, s.decode('utf8')) for s in states],
6870 [getattr(stat, s.decode('utf8')) for s in states],
6870 )
6871 )
6871
6872
6872 copy = {}
6873 copy = {}
6873 if (
6874 if (
6874 opts.get(b'all')
6875 opts.get(b'all')
6875 or opts.get(b'copies')
6876 or opts.get(b'copies')
6876 or ui.configbool(b'ui', b'statuscopies')
6877 or ui.configbool(b'ui', b'statuscopies')
6877 ) and not opts.get(b'no_status'):
6878 ) and not opts.get(b'no_status'):
6878 copy = copies.pathcopies(ctx1, ctx2, m)
6879 copy = copies.pathcopies(ctx1, ctx2, m)
6879
6880
6880 morestatus = None
6881 morestatus = None
6881 if (
6882 if (
6882 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6883 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6883 ) and not ui.plain():
6884 ) and not ui.plain():
6884 morestatus = cmdutil.readmorestatus(repo)
6885 morestatus = cmdutil.readmorestatus(repo)
6885
6886
6886 ui.pager(b'status')
6887 ui.pager(b'status')
6887 fm = ui.formatter(b'status', opts)
6888 fm = ui.formatter(b'status', opts)
6888 fmt = b'%s' + end
6889 fmt = b'%s' + end
6889 showchar = not opts.get(b'no_status')
6890 showchar = not opts.get(b'no_status')
6890
6891
6891 for state, char, files in changestates:
6892 for state, char, files in changestates:
6892 if state in show:
6893 if state in show:
6893 label = b'status.' + state
6894 label = b'status.' + state
6894 for f in files:
6895 for f in files:
6895 fm.startitem()
6896 fm.startitem()
6896 fm.context(ctx=ctx2)
6897 fm.context(ctx=ctx2)
6897 fm.data(itemtype=b'file', path=f)
6898 fm.data(itemtype=b'file', path=f)
6898 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6899 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6899 fm.plain(fmt % uipathfn(f), label=label)
6900 fm.plain(fmt % uipathfn(f), label=label)
6900 if f in copy:
6901 if f in copy:
6901 fm.data(source=copy[f])
6902 fm.data(source=copy[f])
6902 fm.plain(
6903 fm.plain(
6903 (b' %s' + end) % uipathfn(copy[f]),
6904 (b' %s' + end) % uipathfn(copy[f]),
6904 label=b'status.copied',
6905 label=b'status.copied',
6905 )
6906 )
6906 if morestatus:
6907 if morestatus:
6907 morestatus.formatfile(f, fm)
6908 morestatus.formatfile(f, fm)
6908
6909
6909 if morestatus:
6910 if morestatus:
6910 morestatus.formatfooter(fm)
6911 morestatus.formatfooter(fm)
6911 fm.end()
6912 fm.end()
6912
6913
6913
6914
6914 @command(
6915 @command(
6915 b'summary|sum',
6916 b'summary|sum',
6916 [(b'', b'remote', None, _(b'check for push and pull'))],
6917 [(b'', b'remote', None, _(b'check for push and pull'))],
6917 b'[--remote]',
6918 b'[--remote]',
6918 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6919 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6919 helpbasic=True,
6920 helpbasic=True,
6920 intents={INTENT_READONLY},
6921 intents={INTENT_READONLY},
6921 )
6922 )
6922 def summary(ui, repo, **opts):
6923 def summary(ui, repo, **opts):
6923 """summarize working directory state
6924 """summarize working directory state
6924
6925
6925 This generates a brief summary of the working directory state,
6926 This generates a brief summary of the working directory state,
6926 including parents, branch, commit status, phase and available updates.
6927 including parents, branch, commit status, phase and available updates.
6927
6928
6928 With the --remote option, this will check the default paths for
6929 With the --remote option, this will check the default paths for
6929 incoming and outgoing changes. This can be time-consuming.
6930 incoming and outgoing changes. This can be time-consuming.
6930
6931
6931 Returns 0 on success.
6932 Returns 0 on success.
6932 """
6933 """
6933
6934
6934 opts = pycompat.byteskwargs(opts)
6935 opts = pycompat.byteskwargs(opts)
6935 ui.pager(b'summary')
6936 ui.pager(b'summary')
6936 ctx = repo[None]
6937 ctx = repo[None]
6937 parents = ctx.parents()
6938 parents = ctx.parents()
6938 pnode = parents[0].node()
6939 pnode = parents[0].node()
6939 marks = []
6940 marks = []
6940
6941
6941 try:
6942 try:
6942 ms = mergemod.mergestate.read(repo)
6943 ms = mergemod.mergestate.read(repo)
6943 except error.UnsupportedMergeRecords as e:
6944 except error.UnsupportedMergeRecords as e:
6944 s = b' '.join(e.recordtypes)
6945 s = b' '.join(e.recordtypes)
6945 ui.warn(
6946 ui.warn(
6946 _(b'warning: merge state has unsupported record types: %s\n') % s
6947 _(b'warning: merge state has unsupported record types: %s\n') % s
6947 )
6948 )
6948 unresolved = []
6949 unresolved = []
6949 else:
6950 else:
6950 unresolved = list(ms.unresolved())
6951 unresolved = list(ms.unresolved())
6951
6952
6952 for p in parents:
6953 for p in parents:
6953 # label with log.changeset (instead of log.parent) since this
6954 # label with log.changeset (instead of log.parent) since this
6954 # shows a working directory parent *changeset*:
6955 # shows a working directory parent *changeset*:
6955 # i18n: column positioning for "hg summary"
6956 # i18n: column positioning for "hg summary"
6956 ui.write(
6957 ui.write(
6957 _(b'parent: %d:%s ') % (p.rev(), p),
6958 _(b'parent: %d:%s ') % (p.rev(), p),
6958 label=logcmdutil.changesetlabels(p),
6959 label=logcmdutil.changesetlabels(p),
6959 )
6960 )
6960 ui.write(b' '.join(p.tags()), label=b'log.tag')
6961 ui.write(b' '.join(p.tags()), label=b'log.tag')
6961 if p.bookmarks():
6962 if p.bookmarks():
6962 marks.extend(p.bookmarks())
6963 marks.extend(p.bookmarks())
6963 if p.rev() == -1:
6964 if p.rev() == -1:
6964 if not len(repo):
6965 if not len(repo):
6965 ui.write(_(b' (empty repository)'))
6966 ui.write(_(b' (empty repository)'))
6966 else:
6967 else:
6967 ui.write(_(b' (no revision checked out)'))
6968 ui.write(_(b' (no revision checked out)'))
6968 if p.obsolete():
6969 if p.obsolete():
6969 ui.write(_(b' (obsolete)'))
6970 ui.write(_(b' (obsolete)'))
6970 if p.isunstable():
6971 if p.isunstable():
6971 instabilities = (
6972 instabilities = (
6972 ui.label(instability, b'trouble.%s' % instability)
6973 ui.label(instability, b'trouble.%s' % instability)
6973 for instability in p.instabilities()
6974 for instability in p.instabilities()
6974 )
6975 )
6975 ui.write(b' (' + b', '.join(instabilities) + b')')
6976 ui.write(b' (' + b', '.join(instabilities) + b')')
6976 ui.write(b'\n')
6977 ui.write(b'\n')
6977 if p.description():
6978 if p.description():
6978 ui.status(
6979 ui.status(
6979 b' ' + p.description().splitlines()[0].strip() + b'\n',
6980 b' ' + p.description().splitlines()[0].strip() + b'\n',
6980 label=b'log.summary',
6981 label=b'log.summary',
6981 )
6982 )
6982
6983
6983 branch = ctx.branch()
6984 branch = ctx.branch()
6984 bheads = repo.branchheads(branch)
6985 bheads = repo.branchheads(branch)
6985 # i18n: column positioning for "hg summary"
6986 # i18n: column positioning for "hg summary"
6986 m = _(b'branch: %s\n') % branch
6987 m = _(b'branch: %s\n') % branch
6987 if branch != b'default':
6988 if branch != b'default':
6988 ui.write(m, label=b'log.branch')
6989 ui.write(m, label=b'log.branch')
6989 else:
6990 else:
6990 ui.status(m, label=b'log.branch')
6991 ui.status(m, label=b'log.branch')
6991
6992
6992 if marks:
6993 if marks:
6993 active = repo._activebookmark
6994 active = repo._activebookmark
6994 # i18n: column positioning for "hg summary"
6995 # i18n: column positioning for "hg summary"
6995 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6996 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6996 if active is not None:
6997 if active is not None:
6997 if active in marks:
6998 if active in marks:
6998 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6999 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6999 marks.remove(active)
7000 marks.remove(active)
7000 else:
7001 else:
7001 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7002 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7002 for m in marks:
7003 for m in marks:
7003 ui.write(b' ' + m, label=b'log.bookmark')
7004 ui.write(b' ' + m, label=b'log.bookmark')
7004 ui.write(b'\n', label=b'log.bookmark')
7005 ui.write(b'\n', label=b'log.bookmark')
7005
7006
7006 status = repo.status(unknown=True)
7007 status = repo.status(unknown=True)
7007
7008
7008 c = repo.dirstate.copies()
7009 c = repo.dirstate.copies()
7009 copied, renamed = [], []
7010 copied, renamed = [], []
7010 for d, s in pycompat.iteritems(c):
7011 for d, s in pycompat.iteritems(c):
7011 if s in status.removed:
7012 if s in status.removed:
7012 status.removed.remove(s)
7013 status.removed.remove(s)
7013 renamed.append(d)
7014 renamed.append(d)
7014 else:
7015 else:
7015 copied.append(d)
7016 copied.append(d)
7016 if d in status.added:
7017 if d in status.added:
7017 status.added.remove(d)
7018 status.added.remove(d)
7018
7019
7019 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7020 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7020
7021
7021 labels = [
7022 labels = [
7022 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7023 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7023 (ui.label(_(b'%d added'), b'status.added'), status.added),
7024 (ui.label(_(b'%d added'), b'status.added'), status.added),
7024 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7025 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7025 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7026 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7026 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7027 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7027 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7028 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7028 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7029 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7029 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7030 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7030 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7031 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7031 ]
7032 ]
7032 t = []
7033 t = []
7033 for l, s in labels:
7034 for l, s in labels:
7034 if s:
7035 if s:
7035 t.append(l % len(s))
7036 t.append(l % len(s))
7036
7037
7037 t = b', '.join(t)
7038 t = b', '.join(t)
7038 cleanworkdir = False
7039 cleanworkdir = False
7039
7040
7040 if repo.vfs.exists(b'graftstate'):
7041 if repo.vfs.exists(b'graftstate'):
7041 t += _(b' (graft in progress)')
7042 t += _(b' (graft in progress)')
7042 if repo.vfs.exists(b'updatestate'):
7043 if repo.vfs.exists(b'updatestate'):
7043 t += _(b' (interrupted update)')
7044 t += _(b' (interrupted update)')
7044 elif len(parents) > 1:
7045 elif len(parents) > 1:
7045 t += _(b' (merge)')
7046 t += _(b' (merge)')
7046 elif branch != parents[0].branch():
7047 elif branch != parents[0].branch():
7047 t += _(b' (new branch)')
7048 t += _(b' (new branch)')
7048 elif parents[0].closesbranch() and pnode in repo.branchheads(
7049 elif parents[0].closesbranch() and pnode in repo.branchheads(
7049 branch, closed=True
7050 branch, closed=True
7050 ):
7051 ):
7051 t += _(b' (head closed)')
7052 t += _(b' (head closed)')
7052 elif not (
7053 elif not (
7053 status.modified
7054 status.modified
7054 or status.added
7055 or status.added
7055 or status.removed
7056 or status.removed
7056 or renamed
7057 or renamed
7057 or copied
7058 or copied
7058 or subs
7059 or subs
7059 ):
7060 ):
7060 t += _(b' (clean)')
7061 t += _(b' (clean)')
7061 cleanworkdir = True
7062 cleanworkdir = True
7062 elif pnode not in bheads:
7063 elif pnode not in bheads:
7063 t += _(b' (new branch head)')
7064 t += _(b' (new branch head)')
7064
7065
7065 if parents:
7066 if parents:
7066 pendingphase = max(p.phase() for p in parents)
7067 pendingphase = max(p.phase() for p in parents)
7067 else:
7068 else:
7068 pendingphase = phases.public
7069 pendingphase = phases.public
7069
7070
7070 if pendingphase > phases.newcommitphase(ui):
7071 if pendingphase > phases.newcommitphase(ui):
7071 t += b' (%s)' % phases.phasenames[pendingphase]
7072 t += b' (%s)' % phases.phasenames[pendingphase]
7072
7073
7073 if cleanworkdir:
7074 if cleanworkdir:
7074 # i18n: column positioning for "hg summary"
7075 # i18n: column positioning for "hg summary"
7075 ui.status(_(b'commit: %s\n') % t.strip())
7076 ui.status(_(b'commit: %s\n') % t.strip())
7076 else:
7077 else:
7077 # i18n: column positioning for "hg summary"
7078 # i18n: column positioning for "hg summary"
7078 ui.write(_(b'commit: %s\n') % t.strip())
7079 ui.write(_(b'commit: %s\n') % t.strip())
7079
7080
7080 # all ancestors of branch heads - all ancestors of parent = new csets
7081 # all ancestors of branch heads - all ancestors of parent = new csets
7081 new = len(
7082 new = len(
7082 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7083 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7083 )
7084 )
7084
7085
7085 if new == 0:
7086 if new == 0:
7086 # i18n: column positioning for "hg summary"
7087 # i18n: column positioning for "hg summary"
7087 ui.status(_(b'update: (current)\n'))
7088 ui.status(_(b'update: (current)\n'))
7088 elif pnode not in bheads:
7089 elif pnode not in bheads:
7089 # i18n: column positioning for "hg summary"
7090 # i18n: column positioning for "hg summary"
7090 ui.write(_(b'update: %d new changesets (update)\n') % new)
7091 ui.write(_(b'update: %d new changesets (update)\n') % new)
7091 else:
7092 else:
7092 # i18n: column positioning for "hg summary"
7093 # i18n: column positioning for "hg summary"
7093 ui.write(
7094 ui.write(
7094 _(b'update: %d new changesets, %d branch heads (merge)\n')
7095 _(b'update: %d new changesets, %d branch heads (merge)\n')
7095 % (new, len(bheads))
7096 % (new, len(bheads))
7096 )
7097 )
7097
7098
7098 t = []
7099 t = []
7099 draft = len(repo.revs(b'draft()'))
7100 draft = len(repo.revs(b'draft()'))
7100 if draft:
7101 if draft:
7101 t.append(_(b'%d draft') % draft)
7102 t.append(_(b'%d draft') % draft)
7102 secret = len(repo.revs(b'secret()'))
7103 secret = len(repo.revs(b'secret()'))
7103 if secret:
7104 if secret:
7104 t.append(_(b'%d secret') % secret)
7105 t.append(_(b'%d secret') % secret)
7105
7106
7106 if draft or secret:
7107 if draft or secret:
7107 ui.status(_(b'phases: %s\n') % b', '.join(t))
7108 ui.status(_(b'phases: %s\n') % b', '.join(t))
7108
7109
7109 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7110 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7110 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7111 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7111 numtrouble = len(repo.revs(trouble + b"()"))
7112 numtrouble = len(repo.revs(trouble + b"()"))
7112 # We write all the possibilities to ease translation
7113 # We write all the possibilities to ease translation
7113 troublemsg = {
7114 troublemsg = {
7114 b"orphan": _(b"orphan: %d changesets"),
7115 b"orphan": _(b"orphan: %d changesets"),
7115 b"contentdivergent": _(b"content-divergent: %d changesets"),
7116 b"contentdivergent": _(b"content-divergent: %d changesets"),
7116 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7117 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7117 }
7118 }
7118 if numtrouble > 0:
7119 if numtrouble > 0:
7119 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7120 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7120
7121
7121 cmdutil.summaryhooks(ui, repo)
7122 cmdutil.summaryhooks(ui, repo)
7122
7123
7123 if opts.get(b'remote'):
7124 if opts.get(b'remote'):
7124 needsincoming, needsoutgoing = True, True
7125 needsincoming, needsoutgoing = True, True
7125 else:
7126 else:
7126 needsincoming, needsoutgoing = False, False
7127 needsincoming, needsoutgoing = False, False
7127 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7128 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7128 if i:
7129 if i:
7129 needsincoming = True
7130 needsincoming = True
7130 if o:
7131 if o:
7131 needsoutgoing = True
7132 needsoutgoing = True
7132 if not needsincoming and not needsoutgoing:
7133 if not needsincoming and not needsoutgoing:
7133 return
7134 return
7134
7135
7135 def getincoming():
7136 def getincoming():
7136 source, branches = hg.parseurl(ui.expandpath(b'default'))
7137 source, branches = hg.parseurl(ui.expandpath(b'default'))
7137 sbranch = branches[0]
7138 sbranch = branches[0]
7138 try:
7139 try:
7139 other = hg.peer(repo, {}, source)
7140 other = hg.peer(repo, {}, source)
7140 except error.RepoError:
7141 except error.RepoError:
7141 if opts.get(b'remote'):
7142 if opts.get(b'remote'):
7142 raise
7143 raise
7143 return source, sbranch, None, None, None
7144 return source, sbranch, None, None, None
7144 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7145 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7145 if revs:
7146 if revs:
7146 revs = [other.lookup(rev) for rev in revs]
7147 revs = [other.lookup(rev) for rev in revs]
7147 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7148 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7148 repo.ui.pushbuffer()
7149 repo.ui.pushbuffer()
7149 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7150 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7150 repo.ui.popbuffer()
7151 repo.ui.popbuffer()
7151 return source, sbranch, other, commoninc, commoninc[1]
7152 return source, sbranch, other, commoninc, commoninc[1]
7152
7153
7153 if needsincoming:
7154 if needsincoming:
7154 source, sbranch, sother, commoninc, incoming = getincoming()
7155 source, sbranch, sother, commoninc, incoming = getincoming()
7155 else:
7156 else:
7156 source = sbranch = sother = commoninc = incoming = None
7157 source = sbranch = sother = commoninc = incoming = None
7157
7158
7158 def getoutgoing():
7159 def getoutgoing():
7159 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7160 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7160 dbranch = branches[0]
7161 dbranch = branches[0]
7161 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7162 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7162 if source != dest:
7163 if source != dest:
7163 try:
7164 try:
7164 dother = hg.peer(repo, {}, dest)
7165 dother = hg.peer(repo, {}, dest)
7165 except error.RepoError:
7166 except error.RepoError:
7166 if opts.get(b'remote'):
7167 if opts.get(b'remote'):
7167 raise
7168 raise
7168 return dest, dbranch, None, None
7169 return dest, dbranch, None, None
7169 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7170 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7170 elif sother is None:
7171 elif sother is None:
7171 # there is no explicit destination peer, but source one is invalid
7172 # there is no explicit destination peer, but source one is invalid
7172 return dest, dbranch, None, None
7173 return dest, dbranch, None, None
7173 else:
7174 else:
7174 dother = sother
7175 dother = sother
7175 if source != dest or (sbranch is not None and sbranch != dbranch):
7176 if source != dest or (sbranch is not None and sbranch != dbranch):
7176 common = None
7177 common = None
7177 else:
7178 else:
7178 common = commoninc
7179 common = commoninc
7179 if revs:
7180 if revs:
7180 revs = [repo.lookup(rev) for rev in revs]
7181 revs = [repo.lookup(rev) for rev in revs]
7181 repo.ui.pushbuffer()
7182 repo.ui.pushbuffer()
7182 outgoing = discovery.findcommonoutgoing(
7183 outgoing = discovery.findcommonoutgoing(
7183 repo, dother, onlyheads=revs, commoninc=common
7184 repo, dother, onlyheads=revs, commoninc=common
7184 )
7185 )
7185 repo.ui.popbuffer()
7186 repo.ui.popbuffer()
7186 return dest, dbranch, dother, outgoing
7187 return dest, dbranch, dother, outgoing
7187
7188
7188 if needsoutgoing:
7189 if needsoutgoing:
7189 dest, dbranch, dother, outgoing = getoutgoing()
7190 dest, dbranch, dother, outgoing = getoutgoing()
7190 else:
7191 else:
7191 dest = dbranch = dother = outgoing = None
7192 dest = dbranch = dother = outgoing = None
7192
7193
7193 if opts.get(b'remote'):
7194 if opts.get(b'remote'):
7194 t = []
7195 t = []
7195 if incoming:
7196 if incoming:
7196 t.append(_(b'1 or more incoming'))
7197 t.append(_(b'1 or more incoming'))
7197 o = outgoing.missing
7198 o = outgoing.missing
7198 if o:
7199 if o:
7199 t.append(_(b'%d outgoing') % len(o))
7200 t.append(_(b'%d outgoing') % len(o))
7200 other = dother or sother
7201 other = dother or sother
7201 if b'bookmarks' in other.listkeys(b'namespaces'):
7202 if b'bookmarks' in other.listkeys(b'namespaces'):
7202 counts = bookmarks.summary(repo, other)
7203 counts = bookmarks.summary(repo, other)
7203 if counts[0] > 0:
7204 if counts[0] > 0:
7204 t.append(_(b'%d incoming bookmarks') % counts[0])
7205 t.append(_(b'%d incoming bookmarks') % counts[0])
7205 if counts[1] > 0:
7206 if counts[1] > 0:
7206 t.append(_(b'%d outgoing bookmarks') % counts[1])
7207 t.append(_(b'%d outgoing bookmarks') % counts[1])
7207
7208
7208 if t:
7209 if t:
7209 # i18n: column positioning for "hg summary"
7210 # i18n: column positioning for "hg summary"
7210 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7211 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7211 else:
7212 else:
7212 # i18n: column positioning for "hg summary"
7213 # i18n: column positioning for "hg summary"
7213 ui.status(_(b'remote: (synced)\n'))
7214 ui.status(_(b'remote: (synced)\n'))
7214
7215
7215 cmdutil.summaryremotehooks(
7216 cmdutil.summaryremotehooks(
7216 ui,
7217 ui,
7217 repo,
7218 repo,
7218 opts,
7219 opts,
7219 (
7220 (
7220 (source, sbranch, sother, commoninc),
7221 (source, sbranch, sother, commoninc),
7221 (dest, dbranch, dother, outgoing),
7222 (dest, dbranch, dother, outgoing),
7222 ),
7223 ),
7223 )
7224 )
7224
7225
7225
7226
7226 @command(
7227 @command(
7227 b'tag',
7228 b'tag',
7228 [
7229 [
7229 (b'f', b'force', None, _(b'force tag')),
7230 (b'f', b'force', None, _(b'force tag')),
7230 (b'l', b'local', None, _(b'make the tag local')),
7231 (b'l', b'local', None, _(b'make the tag local')),
7231 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7232 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7232 (b'', b'remove', None, _(b'remove a tag')),
7233 (b'', b'remove', None, _(b'remove a tag')),
7233 # -l/--local is already there, commitopts cannot be used
7234 # -l/--local is already there, commitopts cannot be used
7234 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7235 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7235 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7236 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7236 ]
7237 ]
7237 + commitopts2,
7238 + commitopts2,
7238 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7239 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7239 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7240 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7240 )
7241 )
7241 def tag(ui, repo, name1, *names, **opts):
7242 def tag(ui, repo, name1, *names, **opts):
7242 """add one or more tags for the current or given revision
7243 """add one or more tags for the current or given revision
7243
7244
7244 Name a particular revision using <name>.
7245 Name a particular revision using <name>.
7245
7246
7246 Tags are used to name particular revisions of the repository and are
7247 Tags are used to name particular revisions of the repository and are
7247 very useful to compare different revisions, to go back to significant
7248 very useful to compare different revisions, to go back to significant
7248 earlier versions or to mark branch points as releases, etc. Changing
7249 earlier versions or to mark branch points as releases, etc. Changing
7249 an existing tag is normally disallowed; use -f/--force to override.
7250 an existing tag is normally disallowed; use -f/--force to override.
7250
7251
7251 If no revision is given, the parent of the working directory is
7252 If no revision is given, the parent of the working directory is
7252 used.
7253 used.
7253
7254
7254 To facilitate version control, distribution, and merging of tags,
7255 To facilitate version control, distribution, and merging of tags,
7255 they are stored as a file named ".hgtags" which is managed similarly
7256 they are stored as a file named ".hgtags" which is managed similarly
7256 to other project files and can be hand-edited if necessary. This
7257 to other project files and can be hand-edited if necessary. This
7257 also means that tagging creates a new commit. The file
7258 also means that tagging creates a new commit. The file
7258 ".hg/localtags" is used for local tags (not shared among
7259 ".hg/localtags" is used for local tags (not shared among
7259 repositories).
7260 repositories).
7260
7261
7261 Tag commits are usually made at the head of a branch. If the parent
7262 Tag commits are usually made at the head of a branch. If the parent
7262 of the working directory is not a branch head, :hg:`tag` aborts; use
7263 of the working directory is not a branch head, :hg:`tag` aborts; use
7263 -f/--force to force the tag commit to be based on a non-head
7264 -f/--force to force the tag commit to be based on a non-head
7264 changeset.
7265 changeset.
7265
7266
7266 See :hg:`help dates` for a list of formats valid for -d/--date.
7267 See :hg:`help dates` for a list of formats valid for -d/--date.
7267
7268
7268 Since tag names have priority over branch names during revision
7269 Since tag names have priority over branch names during revision
7269 lookup, using an existing branch name as a tag name is discouraged.
7270 lookup, using an existing branch name as a tag name is discouraged.
7270
7271
7271 Returns 0 on success.
7272 Returns 0 on success.
7272 """
7273 """
7273 opts = pycompat.byteskwargs(opts)
7274 opts = pycompat.byteskwargs(opts)
7274 with repo.wlock(), repo.lock():
7275 with repo.wlock(), repo.lock():
7275 rev_ = b"."
7276 rev_ = b"."
7276 names = [t.strip() for t in (name1,) + names]
7277 names = [t.strip() for t in (name1,) + names]
7277 if len(names) != len(set(names)):
7278 if len(names) != len(set(names)):
7278 raise error.Abort(_(b'tag names must be unique'))
7279 raise error.Abort(_(b'tag names must be unique'))
7279 for n in names:
7280 for n in names:
7280 scmutil.checknewlabel(repo, n, b'tag')
7281 scmutil.checknewlabel(repo, n, b'tag')
7281 if not n:
7282 if not n:
7282 raise error.Abort(
7283 raise error.Abort(
7283 _(b'tag names cannot consist entirely of whitespace')
7284 _(b'tag names cannot consist entirely of whitespace')
7284 )
7285 )
7285 if opts.get(b'rev') and opts.get(b'remove'):
7286 if opts.get(b'rev') and opts.get(b'remove'):
7286 raise error.Abort(_(b"--rev and --remove are incompatible"))
7287 raise error.Abort(_(b"--rev and --remove are incompatible"))
7287 if opts.get(b'rev'):
7288 if opts.get(b'rev'):
7288 rev_ = opts[b'rev']
7289 rev_ = opts[b'rev']
7289 message = opts.get(b'message')
7290 message = opts.get(b'message')
7290 if opts.get(b'remove'):
7291 if opts.get(b'remove'):
7291 if opts.get(b'local'):
7292 if opts.get(b'local'):
7292 expectedtype = b'local'
7293 expectedtype = b'local'
7293 else:
7294 else:
7294 expectedtype = b'global'
7295 expectedtype = b'global'
7295
7296
7296 for n in names:
7297 for n in names:
7297 if repo.tagtype(n) == b'global':
7298 if repo.tagtype(n) == b'global':
7298 alltags = tagsmod.findglobaltags(ui, repo)
7299 alltags = tagsmod.findglobaltags(ui, repo)
7299 if alltags[n][0] == nullid:
7300 if alltags[n][0] == nullid:
7300 raise error.Abort(_(b"tag '%s' is already removed") % n)
7301 raise error.Abort(_(b"tag '%s' is already removed") % n)
7301 if not repo.tagtype(n):
7302 if not repo.tagtype(n):
7302 raise error.Abort(_(b"tag '%s' does not exist") % n)
7303 raise error.Abort(_(b"tag '%s' does not exist") % n)
7303 if repo.tagtype(n) != expectedtype:
7304 if repo.tagtype(n) != expectedtype:
7304 if expectedtype == b'global':
7305 if expectedtype == b'global':
7305 raise error.Abort(
7306 raise error.Abort(
7306 _(b"tag '%s' is not a global tag") % n
7307 _(b"tag '%s' is not a global tag") % n
7307 )
7308 )
7308 else:
7309 else:
7309 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7310 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7310 rev_ = b'null'
7311 rev_ = b'null'
7311 if not message:
7312 if not message:
7312 # we don't translate commit messages
7313 # we don't translate commit messages
7313 message = b'Removed tag %s' % b', '.join(names)
7314 message = b'Removed tag %s' % b', '.join(names)
7314 elif not opts.get(b'force'):
7315 elif not opts.get(b'force'):
7315 for n in names:
7316 for n in names:
7316 if n in repo.tags():
7317 if n in repo.tags():
7317 raise error.Abort(
7318 raise error.Abort(
7318 _(b"tag '%s' already exists (use -f to force)") % n
7319 _(b"tag '%s' already exists (use -f to force)") % n
7319 )
7320 )
7320 if not opts.get(b'local'):
7321 if not opts.get(b'local'):
7321 p1, p2 = repo.dirstate.parents()
7322 p1, p2 = repo.dirstate.parents()
7322 if p2 != nullid:
7323 if p2 != nullid:
7323 raise error.Abort(_(b'uncommitted merge'))
7324 raise error.Abort(_(b'uncommitted merge'))
7324 bheads = repo.branchheads()
7325 bheads = repo.branchheads()
7325 if not opts.get(b'force') and bheads and p1 not in bheads:
7326 if not opts.get(b'force') and bheads and p1 not in bheads:
7326 raise error.Abort(
7327 raise error.Abort(
7327 _(
7328 _(
7328 b'working directory is not at a branch head '
7329 b'working directory is not at a branch head '
7329 b'(use -f to force)'
7330 b'(use -f to force)'
7330 )
7331 )
7331 )
7332 )
7332 node = scmutil.revsingle(repo, rev_).node()
7333 node = scmutil.revsingle(repo, rev_).node()
7333
7334
7334 if not message:
7335 if not message:
7335 # we don't translate commit messages
7336 # we don't translate commit messages
7336 message = b'Added tag %s for changeset %s' % (
7337 message = b'Added tag %s for changeset %s' % (
7337 b', '.join(names),
7338 b', '.join(names),
7338 short(node),
7339 short(node),
7339 )
7340 )
7340
7341
7341 date = opts.get(b'date')
7342 date = opts.get(b'date')
7342 if date:
7343 if date:
7343 date = dateutil.parsedate(date)
7344 date = dateutil.parsedate(date)
7344
7345
7345 if opts.get(b'remove'):
7346 if opts.get(b'remove'):
7346 editform = b'tag.remove'
7347 editform = b'tag.remove'
7347 else:
7348 else:
7348 editform = b'tag.add'
7349 editform = b'tag.add'
7349 editor = cmdutil.getcommiteditor(
7350 editor = cmdutil.getcommiteditor(
7350 editform=editform, **pycompat.strkwargs(opts)
7351 editform=editform, **pycompat.strkwargs(opts)
7351 )
7352 )
7352
7353
7353 # don't allow tagging the null rev
7354 # don't allow tagging the null rev
7354 if (
7355 if (
7355 not opts.get(b'remove')
7356 not opts.get(b'remove')
7356 and scmutil.revsingle(repo, rev_).rev() == nullrev
7357 and scmutil.revsingle(repo, rev_).rev() == nullrev
7357 ):
7358 ):
7358 raise error.Abort(_(b"cannot tag null revision"))
7359 raise error.Abort(_(b"cannot tag null revision"))
7359
7360
7360 tagsmod.tag(
7361 tagsmod.tag(
7361 repo,
7362 repo,
7362 names,
7363 names,
7363 node,
7364 node,
7364 message,
7365 message,
7365 opts.get(b'local'),
7366 opts.get(b'local'),
7366 opts.get(b'user'),
7367 opts.get(b'user'),
7367 date,
7368 date,
7368 editor=editor,
7369 editor=editor,
7369 )
7370 )
7370
7371
7371
7372
7372 @command(
7373 @command(
7373 b'tags',
7374 b'tags',
7374 formatteropts,
7375 formatteropts,
7375 b'',
7376 b'',
7376 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7377 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7377 intents={INTENT_READONLY},
7378 intents={INTENT_READONLY},
7378 )
7379 )
7379 def tags(ui, repo, **opts):
7380 def tags(ui, repo, **opts):
7380 """list repository tags
7381 """list repository tags
7381
7382
7382 This lists both regular and local tags. When the -v/--verbose
7383 This lists both regular and local tags. When the -v/--verbose
7383 switch is used, a third column "local" is printed for local tags.
7384 switch is used, a third column "local" is printed for local tags.
7384 When the -q/--quiet switch is used, only the tag name is printed.
7385 When the -q/--quiet switch is used, only the tag name is printed.
7385
7386
7386 .. container:: verbose
7387 .. container:: verbose
7387
7388
7388 Template:
7389 Template:
7389
7390
7390 The following keywords are supported in addition to the common template
7391 The following keywords are supported in addition to the common template
7391 keywords and functions such as ``{tag}``. See also
7392 keywords and functions such as ``{tag}``. See also
7392 :hg:`help templates`.
7393 :hg:`help templates`.
7393
7394
7394 :type: String. ``local`` for local tags.
7395 :type: String. ``local`` for local tags.
7395
7396
7396 Returns 0 on success.
7397 Returns 0 on success.
7397 """
7398 """
7398
7399
7399 opts = pycompat.byteskwargs(opts)
7400 opts = pycompat.byteskwargs(opts)
7400 ui.pager(b'tags')
7401 ui.pager(b'tags')
7401 fm = ui.formatter(b'tags', opts)
7402 fm = ui.formatter(b'tags', opts)
7402 hexfunc = fm.hexfunc
7403 hexfunc = fm.hexfunc
7403
7404
7404 for t, n in reversed(repo.tagslist()):
7405 for t, n in reversed(repo.tagslist()):
7405 hn = hexfunc(n)
7406 hn = hexfunc(n)
7406 label = b'tags.normal'
7407 label = b'tags.normal'
7407 tagtype = b''
7408 tagtype = b''
7408 if repo.tagtype(t) == b'local':
7409 if repo.tagtype(t) == b'local':
7409 label = b'tags.local'
7410 label = b'tags.local'
7410 tagtype = b'local'
7411 tagtype = b'local'
7411
7412
7412 fm.startitem()
7413 fm.startitem()
7413 fm.context(repo=repo)
7414 fm.context(repo=repo)
7414 fm.write(b'tag', b'%s', t, label=label)
7415 fm.write(b'tag', b'%s', t, label=label)
7415 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7416 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7416 fm.condwrite(
7417 fm.condwrite(
7417 not ui.quiet,
7418 not ui.quiet,
7418 b'rev node',
7419 b'rev node',
7419 fmt,
7420 fmt,
7420 repo.changelog.rev(n),
7421 repo.changelog.rev(n),
7421 hn,
7422 hn,
7422 label=label,
7423 label=label,
7423 )
7424 )
7424 fm.condwrite(
7425 fm.condwrite(
7425 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7426 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7426 )
7427 )
7427 fm.plain(b'\n')
7428 fm.plain(b'\n')
7428 fm.end()
7429 fm.end()
7429
7430
7430
7431
7431 @command(
7432 @command(
7432 b'tip',
7433 b'tip',
7433 [
7434 [
7434 (b'p', b'patch', None, _(b'show patch')),
7435 (b'p', b'patch', None, _(b'show patch')),
7435 (b'g', b'git', None, _(b'use git extended diff format')),
7436 (b'g', b'git', None, _(b'use git extended diff format')),
7436 ]
7437 ]
7437 + templateopts,
7438 + templateopts,
7438 _(b'[-p] [-g]'),
7439 _(b'[-p] [-g]'),
7439 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7440 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7440 )
7441 )
7441 def tip(ui, repo, **opts):
7442 def tip(ui, repo, **opts):
7442 """show the tip revision (DEPRECATED)
7443 """show the tip revision (DEPRECATED)
7443
7444
7444 The tip revision (usually just called the tip) is the changeset
7445 The tip revision (usually just called the tip) is the changeset
7445 most recently added to the repository (and therefore the most
7446 most recently added to the repository (and therefore the most
7446 recently changed head).
7447 recently changed head).
7447
7448
7448 If you have just made a commit, that commit will be the tip. If
7449 If you have just made a commit, that commit will be the tip. If
7449 you have just pulled changes from another repository, the tip of
7450 you have just pulled changes from another repository, the tip of
7450 that repository becomes the current tip. The "tip" tag is special
7451 that repository becomes the current tip. The "tip" tag is special
7451 and cannot be renamed or assigned to a different changeset.
7452 and cannot be renamed or assigned to a different changeset.
7452
7453
7453 This command is deprecated, please use :hg:`heads` instead.
7454 This command is deprecated, please use :hg:`heads` instead.
7454
7455
7455 Returns 0 on success.
7456 Returns 0 on success.
7456 """
7457 """
7457 opts = pycompat.byteskwargs(opts)
7458 opts = pycompat.byteskwargs(opts)
7458 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7459 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7459 displayer.show(repo[b'tip'])
7460 displayer.show(repo[b'tip'])
7460 displayer.close()
7461 displayer.close()
7461
7462
7462
7463
7463 @command(
7464 @command(
7464 b'unbundle',
7465 b'unbundle',
7465 [
7466 [
7466 (
7467 (
7467 b'u',
7468 b'u',
7468 b'update',
7469 b'update',
7469 None,
7470 None,
7470 _(b'update to new branch head if changesets were unbundled'),
7471 _(b'update to new branch head if changesets were unbundled'),
7471 )
7472 )
7472 ],
7473 ],
7473 _(b'[-u] FILE...'),
7474 _(b'[-u] FILE...'),
7474 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7475 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7475 )
7476 )
7476 def unbundle(ui, repo, fname1, *fnames, **opts):
7477 def unbundle(ui, repo, fname1, *fnames, **opts):
7477 """apply one or more bundle files
7478 """apply one or more bundle files
7478
7479
7479 Apply one or more bundle files generated by :hg:`bundle`.
7480 Apply one or more bundle files generated by :hg:`bundle`.
7480
7481
7481 Returns 0 on success, 1 if an update has unresolved files.
7482 Returns 0 on success, 1 if an update has unresolved files.
7482 """
7483 """
7483 fnames = (fname1,) + fnames
7484 fnames = (fname1,) + fnames
7484
7485
7485 with repo.lock():
7486 with repo.lock():
7486 for fname in fnames:
7487 for fname in fnames:
7487 f = hg.openpath(ui, fname)
7488 f = hg.openpath(ui, fname)
7488 gen = exchange.readbundle(ui, f, fname)
7489 gen = exchange.readbundle(ui, f, fname)
7489 if isinstance(gen, streamclone.streamcloneapplier):
7490 if isinstance(gen, streamclone.streamcloneapplier):
7490 raise error.Abort(
7491 raise error.Abort(
7491 _(
7492 _(
7492 b'packed bundles cannot be applied with '
7493 b'packed bundles cannot be applied with '
7493 b'"hg unbundle"'
7494 b'"hg unbundle"'
7494 ),
7495 ),
7495 hint=_(b'use "hg debugapplystreamclonebundle"'),
7496 hint=_(b'use "hg debugapplystreamclonebundle"'),
7496 )
7497 )
7497 url = b'bundle:' + fname
7498 url = b'bundle:' + fname
7498 try:
7499 try:
7499 txnname = b'unbundle'
7500 txnname = b'unbundle'
7500 if not isinstance(gen, bundle2.unbundle20):
7501 if not isinstance(gen, bundle2.unbundle20):
7501 txnname = b'unbundle\n%s' % util.hidepassword(url)
7502 txnname = b'unbundle\n%s' % util.hidepassword(url)
7502 with repo.transaction(txnname) as tr:
7503 with repo.transaction(txnname) as tr:
7503 op = bundle2.applybundle(
7504 op = bundle2.applybundle(
7504 repo, gen, tr, source=b'unbundle', url=url
7505 repo, gen, tr, source=b'unbundle', url=url
7505 )
7506 )
7506 except error.BundleUnknownFeatureError as exc:
7507 except error.BundleUnknownFeatureError as exc:
7507 raise error.Abort(
7508 raise error.Abort(
7508 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7509 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7509 hint=_(
7510 hint=_(
7510 b"see https://mercurial-scm.org/"
7511 b"see https://mercurial-scm.org/"
7511 b"wiki/BundleFeature for more "
7512 b"wiki/BundleFeature for more "
7512 b"information"
7513 b"information"
7513 ),
7514 ),
7514 )
7515 )
7515 modheads = bundle2.combinechangegroupresults(op)
7516 modheads = bundle2.combinechangegroupresults(op)
7516
7517
7517 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7518 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7518
7519
7519
7520
7520 @command(
7521 @command(
7521 b'unshelve',
7522 b'unshelve',
7522 [
7523 [
7523 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7524 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7524 (
7525 (
7525 b'c',
7526 b'c',
7526 b'continue',
7527 b'continue',
7527 None,
7528 None,
7528 _(b'continue an incomplete unshelve operation'),
7529 _(b'continue an incomplete unshelve operation'),
7529 ),
7530 ),
7530 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7531 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7531 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7532 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7532 (
7533 (
7533 b'n',
7534 b'n',
7534 b'name',
7535 b'name',
7535 b'',
7536 b'',
7536 _(b'restore shelved change with given name'),
7537 _(b'restore shelved change with given name'),
7537 _(b'NAME'),
7538 _(b'NAME'),
7538 ),
7539 ),
7539 (b't', b'tool', b'', _(b'specify merge tool')),
7540 (b't', b'tool', b'', _(b'specify merge tool')),
7540 (
7541 (
7541 b'',
7542 b'',
7542 b'date',
7543 b'date',
7543 b'',
7544 b'',
7544 _(b'set date for temporary commits (DEPRECATED)'),
7545 _(b'set date for temporary commits (DEPRECATED)'),
7545 _(b'DATE'),
7546 _(b'DATE'),
7546 ),
7547 ),
7547 ],
7548 ],
7548 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7549 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7549 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7550 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7550 )
7551 )
7551 def unshelve(ui, repo, *shelved, **opts):
7552 def unshelve(ui, repo, *shelved, **opts):
7552 """restore a shelved change to the working directory
7553 """restore a shelved change to the working directory
7553
7554
7554 This command accepts an optional name of a shelved change to
7555 This command accepts an optional name of a shelved change to
7555 restore. If none is given, the most recent shelved change is used.
7556 restore. If none is given, the most recent shelved change is used.
7556
7557
7557 If a shelved change is applied successfully, the bundle that
7558 If a shelved change is applied successfully, the bundle that
7558 contains the shelved changes is moved to a backup location
7559 contains the shelved changes is moved to a backup location
7559 (.hg/shelve-backup).
7560 (.hg/shelve-backup).
7560
7561
7561 Since you can restore a shelved change on top of an arbitrary
7562 Since you can restore a shelved change on top of an arbitrary
7562 commit, it is possible that unshelving will result in a conflict
7563 commit, it is possible that unshelving will result in a conflict
7563 between your changes and the commits you are unshelving onto. If
7564 between your changes and the commits you are unshelving onto. If
7564 this occurs, you must resolve the conflict, then use
7565 this occurs, you must resolve the conflict, then use
7565 ``--continue`` to complete the unshelve operation. (The bundle
7566 ``--continue`` to complete the unshelve operation. (The bundle
7566 will not be moved until you successfully complete the unshelve.)
7567 will not be moved until you successfully complete the unshelve.)
7567
7568
7568 (Alternatively, you can use ``--abort`` to abandon an unshelve
7569 (Alternatively, you can use ``--abort`` to abandon an unshelve
7569 that causes a conflict. This reverts the unshelved changes, and
7570 that causes a conflict. This reverts the unshelved changes, and
7570 leaves the bundle in place.)
7571 leaves the bundle in place.)
7571
7572
7572 If bare shelved change (without interactive, include and exclude
7573 If bare shelved change (without interactive, include and exclude
7573 option) was done on newly created branch it would restore branch
7574 option) was done on newly created branch it would restore branch
7574 information to the working directory.
7575 information to the working directory.
7575
7576
7576 After a successful unshelve, the shelved changes are stored in a
7577 After a successful unshelve, the shelved changes are stored in a
7577 backup directory. Only the N most recent backups are kept. N
7578 backup directory. Only the N most recent backups are kept. N
7578 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7579 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7579 configuration option.
7580 configuration option.
7580
7581
7581 .. container:: verbose
7582 .. container:: verbose
7582
7583
7583 Timestamp in seconds is used to decide order of backups. More
7584 Timestamp in seconds is used to decide order of backups. More
7584 than ``maxbackups`` backups are kept, if same timestamp
7585 than ``maxbackups`` backups are kept, if same timestamp
7585 prevents from deciding exact order of them, for safety.
7586 prevents from deciding exact order of them, for safety.
7586
7587
7587 Selected changes can be unshelved with ``--interactive`` flag.
7588 Selected changes can be unshelved with ``--interactive`` flag.
7588 The working directory is updated with the selected changes, and
7589 The working directory is updated with the selected changes, and
7589 only the unselected changes remain shelved.
7590 only the unselected changes remain shelved.
7590 Note: The whole shelve is applied to working directory first before
7591 Note: The whole shelve is applied to working directory first before
7591 running interactively. So, this will bring up all the conflicts between
7592 running interactively. So, this will bring up all the conflicts between
7592 working directory and the shelve, irrespective of which changes will be
7593 working directory and the shelve, irrespective of which changes will be
7593 unshelved.
7594 unshelved.
7594 """
7595 """
7595 with repo.wlock():
7596 with repo.wlock():
7596 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7597 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7597
7598
7598
7599
7599 statemod.addunfinished(
7600 statemod.addunfinished(
7600 b'unshelve',
7601 b'unshelve',
7601 fname=b'shelvedstate',
7602 fname=b'shelvedstate',
7602 continueflag=True,
7603 continueflag=True,
7603 abortfunc=shelvemod.hgabortunshelve,
7604 abortfunc=shelvemod.hgabortunshelve,
7604 continuefunc=shelvemod.hgcontinueunshelve,
7605 continuefunc=shelvemod.hgcontinueunshelve,
7605 cmdmsg=_(b'unshelve already in progress'),
7606 cmdmsg=_(b'unshelve already in progress'),
7606 )
7607 )
7607
7608
7608
7609
7609 @command(
7610 @command(
7610 b'update|up|checkout|co',
7611 b'update|up|checkout|co',
7611 [
7612 [
7612 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7613 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7613 (b'c', b'check', None, _(b'require clean working directory')),
7614 (b'c', b'check', None, _(b'require clean working directory')),
7614 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7615 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7615 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7616 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7616 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7617 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7617 ]
7618 ]
7618 + mergetoolopts,
7619 + mergetoolopts,
7619 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7620 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7620 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7621 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7621 helpbasic=True,
7622 helpbasic=True,
7622 )
7623 )
7623 def update(ui, repo, node=None, **opts):
7624 def update(ui, repo, node=None, **opts):
7624 """update working directory (or switch revisions)
7625 """update working directory (or switch revisions)
7625
7626
7626 Update the repository's working directory to the specified
7627 Update the repository's working directory to the specified
7627 changeset. If no changeset is specified, update to the tip of the
7628 changeset. If no changeset is specified, update to the tip of the
7628 current named branch and move the active bookmark (see :hg:`help
7629 current named branch and move the active bookmark (see :hg:`help
7629 bookmarks`).
7630 bookmarks`).
7630
7631
7631 Update sets the working directory's parent revision to the specified
7632 Update sets the working directory's parent revision to the specified
7632 changeset (see :hg:`help parents`).
7633 changeset (see :hg:`help parents`).
7633
7634
7634 If the changeset is not a descendant or ancestor of the working
7635 If the changeset is not a descendant or ancestor of the working
7635 directory's parent and there are uncommitted changes, the update is
7636 directory's parent and there are uncommitted changes, the update is
7636 aborted. With the -c/--check option, the working directory is checked
7637 aborted. With the -c/--check option, the working directory is checked
7637 for uncommitted changes; if none are found, the working directory is
7638 for uncommitted changes; if none are found, the working directory is
7638 updated to the specified changeset.
7639 updated to the specified changeset.
7639
7640
7640 .. container:: verbose
7641 .. container:: verbose
7641
7642
7642 The -C/--clean, -c/--check, and -m/--merge options control what
7643 The -C/--clean, -c/--check, and -m/--merge options control what
7643 happens if the working directory contains uncommitted changes.
7644 happens if the working directory contains uncommitted changes.
7644 At most of one of them can be specified.
7645 At most of one of them can be specified.
7645
7646
7646 1. If no option is specified, and if
7647 1. If no option is specified, and if
7647 the requested changeset is an ancestor or descendant of
7648 the requested changeset is an ancestor or descendant of
7648 the working directory's parent, the uncommitted changes
7649 the working directory's parent, the uncommitted changes
7649 are merged into the requested changeset and the merged
7650 are merged into the requested changeset and the merged
7650 result is left uncommitted. If the requested changeset is
7651 result is left uncommitted. If the requested changeset is
7651 not an ancestor or descendant (that is, it is on another
7652 not an ancestor or descendant (that is, it is on another
7652 branch), the update is aborted and the uncommitted changes
7653 branch), the update is aborted and the uncommitted changes
7653 are preserved.
7654 are preserved.
7654
7655
7655 2. With the -m/--merge option, the update is allowed even if the
7656 2. With the -m/--merge option, the update is allowed even if the
7656 requested changeset is not an ancestor or descendant of
7657 requested changeset is not an ancestor or descendant of
7657 the working directory's parent.
7658 the working directory's parent.
7658
7659
7659 3. With the -c/--check option, the update is aborted and the
7660 3. With the -c/--check option, the update is aborted and the
7660 uncommitted changes are preserved.
7661 uncommitted changes are preserved.
7661
7662
7662 4. With the -C/--clean option, uncommitted changes are discarded and
7663 4. With the -C/--clean option, uncommitted changes are discarded and
7663 the working directory is updated to the requested changeset.
7664 the working directory is updated to the requested changeset.
7664
7665
7665 To cancel an uncommitted merge (and lose your changes), use
7666 To cancel an uncommitted merge (and lose your changes), use
7666 :hg:`merge --abort`.
7667 :hg:`merge --abort`.
7667
7668
7668 Use null as the changeset to remove the working directory (like
7669 Use null as the changeset to remove the working directory (like
7669 :hg:`clone -U`).
7670 :hg:`clone -U`).
7670
7671
7671 If you want to revert just one file to an older revision, use
7672 If you want to revert just one file to an older revision, use
7672 :hg:`revert [-r REV] NAME`.
7673 :hg:`revert [-r REV] NAME`.
7673
7674
7674 See :hg:`help dates` for a list of formats valid for -d/--date.
7675 See :hg:`help dates` for a list of formats valid for -d/--date.
7675
7676
7676 Returns 0 on success, 1 if there are unresolved files.
7677 Returns 0 on success, 1 if there are unresolved files.
7677 """
7678 """
7678 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7679 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7679 rev = opts.get('rev')
7680 rev = opts.get('rev')
7680 date = opts.get('date')
7681 date = opts.get('date')
7681 clean = opts.get('clean')
7682 clean = opts.get('clean')
7682 check = opts.get('check')
7683 check = opts.get('check')
7683 merge = opts.get('merge')
7684 merge = opts.get('merge')
7684 if rev and node:
7685 if rev and node:
7685 raise error.Abort(_(b"please specify just one revision"))
7686 raise error.Abort(_(b"please specify just one revision"))
7686
7687
7687 if ui.configbool(b'commands', b'update.requiredest'):
7688 if ui.configbool(b'commands', b'update.requiredest'):
7688 if not node and not rev and not date:
7689 if not node and not rev and not date:
7689 raise error.Abort(
7690 raise error.Abort(
7690 _(b'you must specify a destination'),
7691 _(b'you must specify a destination'),
7691 hint=_(b'for example: hg update ".::"'),
7692 hint=_(b'for example: hg update ".::"'),
7692 )
7693 )
7693
7694
7694 if rev is None or rev == b'':
7695 if rev is None or rev == b'':
7695 rev = node
7696 rev = node
7696
7697
7697 if date and rev is not None:
7698 if date and rev is not None:
7698 raise error.Abort(_(b"you can't specify a revision and a date"))
7699 raise error.Abort(_(b"you can't specify a revision and a date"))
7699
7700
7700 updatecheck = None
7701 updatecheck = None
7701 if check:
7702 if check:
7702 updatecheck = b'abort'
7703 updatecheck = b'abort'
7703 elif merge:
7704 elif merge:
7704 updatecheck = b'none'
7705 updatecheck = b'none'
7705
7706
7706 with repo.wlock():
7707 with repo.wlock():
7707 cmdutil.clearunfinished(repo)
7708 cmdutil.clearunfinished(repo)
7708 if date:
7709 if date:
7709 rev = cmdutil.finddate(ui, repo, date)
7710 rev = cmdutil.finddate(ui, repo, date)
7710
7711
7711 # if we defined a bookmark, we have to remember the original name
7712 # if we defined a bookmark, we have to remember the original name
7712 brev = rev
7713 brev = rev
7713 if rev:
7714 if rev:
7714 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7715 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7715 ctx = scmutil.revsingle(repo, rev, default=None)
7716 ctx = scmutil.revsingle(repo, rev, default=None)
7716 rev = ctx.rev()
7717 rev = ctx.rev()
7717 hidden = ctx.hidden()
7718 hidden = ctx.hidden()
7718 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7719 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7719 with ui.configoverride(overrides, b'update'):
7720 with ui.configoverride(overrides, b'update'):
7720 ret = hg.updatetotally(
7721 ret = hg.updatetotally(
7721 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7722 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7722 )
7723 )
7723 if hidden:
7724 if hidden:
7724 ctxstr = ctx.hex()[:12]
7725 ctxstr = ctx.hex()[:12]
7725 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7726 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7726
7727
7727 if ctx.obsolete():
7728 if ctx.obsolete():
7728 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7729 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7729 ui.warn(b"(%s)\n" % obsfatemsg)
7730 ui.warn(b"(%s)\n" % obsfatemsg)
7730 return ret
7731 return ret
7731
7732
7732
7733
7733 @command(
7734 @command(
7734 b'verify',
7735 b'verify',
7735 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7736 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7736 helpcategory=command.CATEGORY_MAINTENANCE,
7737 helpcategory=command.CATEGORY_MAINTENANCE,
7737 )
7738 )
7738 def verify(ui, repo, **opts):
7739 def verify(ui, repo, **opts):
7739 """verify the integrity of the repository
7740 """verify the integrity of the repository
7740
7741
7741 Verify the integrity of the current repository.
7742 Verify the integrity of the current repository.
7742
7743
7743 This will perform an extensive check of the repository's
7744 This will perform an extensive check of the repository's
7744 integrity, validating the hashes and checksums of each entry in
7745 integrity, validating the hashes and checksums of each entry in
7745 the changelog, manifest, and tracked files, as well as the
7746 the changelog, manifest, and tracked files, as well as the
7746 integrity of their crosslinks and indices.
7747 integrity of their crosslinks and indices.
7747
7748
7748 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7749 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7749 for more information about recovery from corruption of the
7750 for more information about recovery from corruption of the
7750 repository.
7751 repository.
7751
7752
7752 Returns 0 on success, 1 if errors are encountered.
7753 Returns 0 on success, 1 if errors are encountered.
7753 """
7754 """
7754 opts = pycompat.byteskwargs(opts)
7755 opts = pycompat.byteskwargs(opts)
7755
7756
7756 level = None
7757 level = None
7757 if opts[b'full']:
7758 if opts[b'full']:
7758 level = verifymod.VERIFY_FULL
7759 level = verifymod.VERIFY_FULL
7759 return hg.verify(repo, level)
7760 return hg.verify(repo, level)
7760
7761
7761
7762
7762 @command(
7763 @command(
7763 b'version',
7764 b'version',
7764 [] + formatteropts,
7765 [] + formatteropts,
7765 helpcategory=command.CATEGORY_HELP,
7766 helpcategory=command.CATEGORY_HELP,
7766 norepo=True,
7767 norepo=True,
7767 intents={INTENT_READONLY},
7768 intents={INTENT_READONLY},
7768 )
7769 )
7769 def version_(ui, **opts):
7770 def version_(ui, **opts):
7770 """output version and copyright information
7771 """output version and copyright information
7771
7772
7772 .. container:: verbose
7773 .. container:: verbose
7773
7774
7774 Template:
7775 Template:
7775
7776
7776 The following keywords are supported. See also :hg:`help templates`.
7777 The following keywords are supported. See also :hg:`help templates`.
7777
7778
7778 :extensions: List of extensions.
7779 :extensions: List of extensions.
7779 :ver: String. Version number.
7780 :ver: String. Version number.
7780
7781
7781 And each entry of ``{extensions}`` provides the following sub-keywords
7782 And each entry of ``{extensions}`` provides the following sub-keywords
7782 in addition to ``{ver}``.
7783 in addition to ``{ver}``.
7783
7784
7784 :bundled: Boolean. True if included in the release.
7785 :bundled: Boolean. True if included in the release.
7785 :name: String. Extension name.
7786 :name: String. Extension name.
7786 """
7787 """
7787 opts = pycompat.byteskwargs(opts)
7788 opts = pycompat.byteskwargs(opts)
7788 if ui.verbose:
7789 if ui.verbose:
7789 ui.pager(b'version')
7790 ui.pager(b'version')
7790 fm = ui.formatter(b"version", opts)
7791 fm = ui.formatter(b"version", opts)
7791 fm.startitem()
7792 fm.startitem()
7792 fm.write(
7793 fm.write(
7793 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7794 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7794 )
7795 )
7795 license = _(
7796 license = _(
7796 b"(see https://mercurial-scm.org for more information)\n"
7797 b"(see https://mercurial-scm.org for more information)\n"
7797 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7798 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7798 b"This is free software; see the source for copying conditions. "
7799 b"This is free software; see the source for copying conditions. "
7799 b"There is NO\nwarranty; "
7800 b"There is NO\nwarranty; "
7800 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7801 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7801 )
7802 )
7802 if not ui.quiet:
7803 if not ui.quiet:
7803 fm.plain(license)
7804 fm.plain(license)
7804
7805
7805 if ui.verbose:
7806 if ui.verbose:
7806 fm.plain(_(b"\nEnabled extensions:\n\n"))
7807 fm.plain(_(b"\nEnabled extensions:\n\n"))
7807 # format names and versions into columns
7808 # format names and versions into columns
7808 names = []
7809 names = []
7809 vers = []
7810 vers = []
7810 isinternals = []
7811 isinternals = []
7811 for name, module in extensions.extensions():
7812 for name, module in extensions.extensions():
7812 names.append(name)
7813 names.append(name)
7813 vers.append(extensions.moduleversion(module) or None)
7814 vers.append(extensions.moduleversion(module) or None)
7814 isinternals.append(extensions.ismoduleinternal(module))
7815 isinternals.append(extensions.ismoduleinternal(module))
7815 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7816 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7816 if names:
7817 if names:
7817 namefmt = b" %%-%ds " % max(len(n) for n in names)
7818 namefmt = b" %%-%ds " % max(len(n) for n in names)
7818 places = [_(b"external"), _(b"internal")]
7819 places = [_(b"external"), _(b"internal")]
7819 for n, v, p in zip(names, vers, isinternals):
7820 for n, v, p in zip(names, vers, isinternals):
7820 fn.startitem()
7821 fn.startitem()
7821 fn.condwrite(ui.verbose, b"name", namefmt, n)
7822 fn.condwrite(ui.verbose, b"name", namefmt, n)
7822 if ui.verbose:
7823 if ui.verbose:
7823 fn.plain(b"%s " % places[p])
7824 fn.plain(b"%s " % places[p])
7824 fn.data(bundled=p)
7825 fn.data(bundled=p)
7825 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7826 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7826 if ui.verbose:
7827 if ui.verbose:
7827 fn.plain(b"\n")
7828 fn.plain(b"\n")
7828 fn.end()
7829 fn.end()
7829 fm.end()
7830 fm.end()
7830
7831
7831
7832
7832 def loadcmdtable(ui, name, cmdtable):
7833 def loadcmdtable(ui, name, cmdtable):
7833 """Load command functions from specified cmdtable
7834 """Load command functions from specified cmdtable
7834 """
7835 """
7835 overrides = [cmd for cmd in cmdtable if cmd in table]
7836 overrides = [cmd for cmd in cmdtable if cmd in table]
7836 if overrides:
7837 if overrides:
7837 ui.warn(
7838 ui.warn(
7838 _(b"extension '%s' overrides commands: %s\n")
7839 _(b"extension '%s' overrides commands: %s\n")
7839 % (name, b" ".join(overrides))
7840 % (name, b" ".join(overrides))
7840 )
7841 )
7841 table.update(cmdtable)
7842 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now