##// END OF EJS Templates
export: use cmdutil.check_at_most_one_arg()...
Martin von Zweigbergk -
r44347:287556e7 default
parent child Browse files
Show More
@@ -1,7837 +1,7836 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' for x in l])
562 formats.append([b'%s' for x in 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, hex(repo.changelog.tip()))
879 return hg.merge(repo, hex(repo.changelog.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 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1229 selactions = [k for k in [b'delete', b'rename', b'list'] if opts.get(k)]
1230 if len(selactions) > 1:
1230 if len(selactions) > 1:
1231 raise error.Abort(
1231 raise error.Abort(
1232 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1232 _(b'--%s and --%s are incompatible') % tuple(selactions[:2])
1233 )
1233 )
1234 if selactions:
1234 if selactions:
1235 action = selactions[0]
1235 action = selactions[0]
1236 elif names or rev:
1236 elif names or rev:
1237 action = b'add'
1237 action = b'add'
1238 elif inactive:
1238 elif inactive:
1239 action = b'inactive' # meaning deactivate
1239 action = b'inactive' # meaning deactivate
1240 else:
1240 else:
1241 action = b'list'
1241 action = b'list'
1242
1242
1243 if rev and action in {b'delete', b'rename', b'list'}:
1243 if rev and action in {b'delete', b'rename', b'list'}:
1244 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1244 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1245 if inactive and action in {b'delete', b'list'}:
1245 if inactive and action in {b'delete', b'list'}:
1246 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1246 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1247 if not names and action in {b'add', b'delete'}:
1247 if not names and action in {b'add', b'delete'}:
1248 raise error.Abort(_(b"bookmark name required"))
1248 raise error.Abort(_(b"bookmark name required"))
1249
1249
1250 if action in {b'add', b'delete', b'rename', b'inactive'}:
1250 if action in {b'add', b'delete', b'rename', b'inactive'}:
1251 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1251 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1252 if action == b'delete':
1252 if action == b'delete':
1253 names = pycompat.maplist(repo._bookmarks.expandname, names)
1253 names = pycompat.maplist(repo._bookmarks.expandname, names)
1254 bookmarks.delete(repo, tr, names)
1254 bookmarks.delete(repo, tr, names)
1255 elif action == b'rename':
1255 elif action == b'rename':
1256 if not names:
1256 if not names:
1257 raise error.Abort(_(b"new bookmark name required"))
1257 raise error.Abort(_(b"new bookmark name required"))
1258 elif len(names) > 1:
1258 elif len(names) > 1:
1259 raise error.Abort(_(b"only one new bookmark name allowed"))
1259 raise error.Abort(_(b"only one new bookmark name allowed"))
1260 oldname = repo._bookmarks.expandname(opts[b'rename'])
1260 oldname = repo._bookmarks.expandname(opts[b'rename'])
1261 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1261 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1262 elif action == b'add':
1262 elif action == b'add':
1263 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1263 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1264 elif action == b'inactive':
1264 elif action == b'inactive':
1265 if len(repo._bookmarks) == 0:
1265 if len(repo._bookmarks) == 0:
1266 ui.status(_(b"no bookmarks set\n"))
1266 ui.status(_(b"no bookmarks set\n"))
1267 elif not repo._activebookmark:
1267 elif not repo._activebookmark:
1268 ui.status(_(b"no active bookmark\n"))
1268 ui.status(_(b"no active bookmark\n"))
1269 else:
1269 else:
1270 bookmarks.deactivate(repo)
1270 bookmarks.deactivate(repo)
1271 elif action == b'list':
1271 elif action == b'list':
1272 names = pycompat.maplist(repo._bookmarks.expandname, names)
1272 names = pycompat.maplist(repo._bookmarks.expandname, names)
1273 with ui.formatter(b'bookmarks', opts) as fm:
1273 with ui.formatter(b'bookmarks', opts) as fm:
1274 bookmarks.printbookmarks(ui, repo, fm, names)
1274 bookmarks.printbookmarks(ui, repo, fm, names)
1275 else:
1275 else:
1276 raise error.ProgrammingError(b'invalid action: %s' % action)
1276 raise error.ProgrammingError(b'invalid action: %s' % action)
1277
1277
1278
1278
1279 @command(
1279 @command(
1280 b'branch',
1280 b'branch',
1281 [
1281 [
1282 (
1282 (
1283 b'f',
1283 b'f',
1284 b'force',
1284 b'force',
1285 None,
1285 None,
1286 _(b'set branch name even if it shadows an existing branch'),
1286 _(b'set branch name even if it shadows an existing branch'),
1287 ),
1287 ),
1288 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1288 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1289 (
1289 (
1290 b'r',
1290 b'r',
1291 b'rev',
1291 b'rev',
1292 [],
1292 [],
1293 _(b'change branches of the given revs (EXPERIMENTAL)'),
1293 _(b'change branches of the given revs (EXPERIMENTAL)'),
1294 ),
1294 ),
1295 ],
1295 ],
1296 _(b'[-fC] [NAME]'),
1296 _(b'[-fC] [NAME]'),
1297 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1297 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1298 )
1298 )
1299 def branch(ui, repo, label=None, **opts):
1299 def branch(ui, repo, label=None, **opts):
1300 """set or show the current branch name
1300 """set or show the current branch name
1301
1301
1302 .. note::
1302 .. note::
1303
1303
1304 Branch names are permanent and global. Use :hg:`bookmark` to create a
1304 Branch names are permanent and global. Use :hg:`bookmark` to create a
1305 light-weight bookmark instead. See :hg:`help glossary` for more
1305 light-weight bookmark instead. See :hg:`help glossary` for more
1306 information about named branches and bookmarks.
1306 information about named branches and bookmarks.
1307
1307
1308 With no argument, show the current branch name. With one argument,
1308 With no argument, show the current branch name. With one argument,
1309 set the working directory branch name (the branch will not exist
1309 set the working directory branch name (the branch will not exist
1310 in the repository until the next commit). Standard practice
1310 in the repository until the next commit). Standard practice
1311 recommends that primary development take place on the 'default'
1311 recommends that primary development take place on the 'default'
1312 branch.
1312 branch.
1313
1313
1314 Unless -f/--force is specified, branch will not let you set a
1314 Unless -f/--force is specified, branch will not let you set a
1315 branch name that already exists.
1315 branch name that already exists.
1316
1316
1317 Use -C/--clean to reset the working directory branch to that of
1317 Use -C/--clean to reset the working directory branch to that of
1318 the parent of the working directory, negating a previous branch
1318 the parent of the working directory, negating a previous branch
1319 change.
1319 change.
1320
1320
1321 Use the command :hg:`update` to switch to an existing branch. Use
1321 Use the command :hg:`update` to switch to an existing branch. Use
1322 :hg:`commit --close-branch` to mark this branch head as closed.
1322 :hg:`commit --close-branch` to mark this branch head as closed.
1323 When all heads of a branch are closed, the branch will be
1323 When all heads of a branch are closed, the branch will be
1324 considered closed.
1324 considered closed.
1325
1325
1326 Returns 0 on success.
1326 Returns 0 on success.
1327 """
1327 """
1328 opts = pycompat.byteskwargs(opts)
1328 opts = pycompat.byteskwargs(opts)
1329 revs = opts.get(b'rev')
1329 revs = opts.get(b'rev')
1330 if label:
1330 if label:
1331 label = label.strip()
1331 label = label.strip()
1332
1332
1333 if not opts.get(b'clean') and not label:
1333 if not opts.get(b'clean') and not label:
1334 if revs:
1334 if revs:
1335 raise error.Abort(_(b"no branch name specified for the revisions"))
1335 raise error.Abort(_(b"no branch name specified for the revisions"))
1336 ui.write(b"%s\n" % repo.dirstate.branch())
1336 ui.write(b"%s\n" % repo.dirstate.branch())
1337 return
1337 return
1338
1338
1339 with repo.wlock():
1339 with repo.wlock():
1340 if opts.get(b'clean'):
1340 if opts.get(b'clean'):
1341 label = repo[b'.'].branch()
1341 label = repo[b'.'].branch()
1342 repo.dirstate.setbranch(label)
1342 repo.dirstate.setbranch(label)
1343 ui.status(_(b'reset working directory to branch %s\n') % label)
1343 ui.status(_(b'reset working directory to branch %s\n') % label)
1344 elif label:
1344 elif label:
1345
1345
1346 scmutil.checknewlabel(repo, label, b'branch')
1346 scmutil.checknewlabel(repo, label, b'branch')
1347 if revs:
1347 if revs:
1348 return cmdutil.changebranch(ui, repo, revs, label)
1348 return cmdutil.changebranch(ui, repo, revs, label)
1349
1349
1350 if not opts.get(b'force') and label in repo.branchmap():
1350 if not opts.get(b'force') and label in repo.branchmap():
1351 if label not in [p.branch() for p in repo[None].parents()]:
1351 if label not in [p.branch() for p in repo[None].parents()]:
1352 raise error.Abort(
1352 raise error.Abort(
1353 _(b'a branch of the same name already exists'),
1353 _(b'a branch of the same name already exists'),
1354 # i18n: "it" refers to an existing branch
1354 # i18n: "it" refers to an existing branch
1355 hint=_(b"use 'hg update' to switch to it"),
1355 hint=_(b"use 'hg update' to switch to it"),
1356 )
1356 )
1357
1357
1358 repo.dirstate.setbranch(label)
1358 repo.dirstate.setbranch(label)
1359 ui.status(_(b'marked working directory as branch %s\n') % label)
1359 ui.status(_(b'marked working directory as branch %s\n') % label)
1360
1360
1361 # find any open named branches aside from default
1361 # find any open named branches aside from default
1362 for n, h, t, c in repo.branchmap().iterbranches():
1362 for n, h, t, c in repo.branchmap().iterbranches():
1363 if n != b"default" and not c:
1363 if n != b"default" and not c:
1364 return 0
1364 return 0
1365 ui.status(
1365 ui.status(
1366 _(
1366 _(
1367 b'(branches are permanent and global, '
1367 b'(branches are permanent and global, '
1368 b'did you want a bookmark?)\n'
1368 b'did you want a bookmark?)\n'
1369 )
1369 )
1370 )
1370 )
1371
1371
1372
1372
1373 @command(
1373 @command(
1374 b'branches',
1374 b'branches',
1375 [
1375 [
1376 (
1376 (
1377 b'a',
1377 b'a',
1378 b'active',
1378 b'active',
1379 False,
1379 False,
1380 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1380 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1381 ),
1381 ),
1382 (b'c', b'closed', False, _(b'show normal and closed branches')),
1382 (b'c', b'closed', False, _(b'show normal and closed branches')),
1383 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1383 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1384 ]
1384 ]
1385 + formatteropts,
1385 + formatteropts,
1386 _(b'[-c]'),
1386 _(b'[-c]'),
1387 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1387 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1388 intents={INTENT_READONLY},
1388 intents={INTENT_READONLY},
1389 )
1389 )
1390 def branches(ui, repo, active=False, closed=False, **opts):
1390 def branches(ui, repo, active=False, closed=False, **opts):
1391 """list repository named branches
1391 """list repository named branches
1392
1392
1393 List the repository's named branches, indicating which ones are
1393 List the repository's named branches, indicating which ones are
1394 inactive. If -c/--closed is specified, also list branches which have
1394 inactive. If -c/--closed is specified, also list branches which have
1395 been marked closed (see :hg:`commit --close-branch`).
1395 been marked closed (see :hg:`commit --close-branch`).
1396
1396
1397 Use the command :hg:`update` to switch to an existing branch.
1397 Use the command :hg:`update` to switch to an existing branch.
1398
1398
1399 .. container:: verbose
1399 .. container:: verbose
1400
1400
1401 Template:
1401 Template:
1402
1402
1403 The following keywords are supported in addition to the common template
1403 The following keywords are supported in addition to the common template
1404 keywords and functions such as ``{branch}``. See also
1404 keywords and functions such as ``{branch}``. See also
1405 :hg:`help templates`.
1405 :hg:`help templates`.
1406
1406
1407 :active: Boolean. True if the branch is active.
1407 :active: Boolean. True if the branch is active.
1408 :closed: Boolean. True if the branch is closed.
1408 :closed: Boolean. True if the branch is closed.
1409 :current: Boolean. True if it is the current branch.
1409 :current: Boolean. True if it is the current branch.
1410
1410
1411 Returns 0.
1411 Returns 0.
1412 """
1412 """
1413
1413
1414 opts = pycompat.byteskwargs(opts)
1414 opts = pycompat.byteskwargs(opts)
1415 revs = opts.get(b'rev')
1415 revs = opts.get(b'rev')
1416 selectedbranches = None
1416 selectedbranches = None
1417 if revs:
1417 if revs:
1418 revs = scmutil.revrange(repo, revs)
1418 revs = scmutil.revrange(repo, revs)
1419 getbi = repo.revbranchcache().branchinfo
1419 getbi = repo.revbranchcache().branchinfo
1420 selectedbranches = {getbi(r)[0] for r in revs}
1420 selectedbranches = {getbi(r)[0] for r in revs}
1421
1421
1422 ui.pager(b'branches')
1422 ui.pager(b'branches')
1423 fm = ui.formatter(b'branches', opts)
1423 fm = ui.formatter(b'branches', opts)
1424 hexfunc = fm.hexfunc
1424 hexfunc = fm.hexfunc
1425
1425
1426 allheads = set(repo.heads())
1426 allheads = set(repo.heads())
1427 branches = []
1427 branches = []
1428 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1428 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1429 if selectedbranches is not None and tag not in selectedbranches:
1429 if selectedbranches is not None and tag not in selectedbranches:
1430 continue
1430 continue
1431 isactive = False
1431 isactive = False
1432 if not isclosed:
1432 if not isclosed:
1433 openheads = set(repo.branchmap().iteropen(heads))
1433 openheads = set(repo.branchmap().iteropen(heads))
1434 isactive = bool(openheads & allheads)
1434 isactive = bool(openheads & allheads)
1435 branches.append((tag, repo[tip], isactive, not isclosed))
1435 branches.append((tag, repo[tip], isactive, not isclosed))
1436 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1436 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1437
1437
1438 for tag, ctx, isactive, isopen in branches:
1438 for tag, ctx, isactive, isopen in branches:
1439 if active and not isactive:
1439 if active and not isactive:
1440 continue
1440 continue
1441 if isactive:
1441 if isactive:
1442 label = b'branches.active'
1442 label = b'branches.active'
1443 notice = b''
1443 notice = b''
1444 elif not isopen:
1444 elif not isopen:
1445 if not closed:
1445 if not closed:
1446 continue
1446 continue
1447 label = b'branches.closed'
1447 label = b'branches.closed'
1448 notice = _(b' (closed)')
1448 notice = _(b' (closed)')
1449 else:
1449 else:
1450 label = b'branches.inactive'
1450 label = b'branches.inactive'
1451 notice = _(b' (inactive)')
1451 notice = _(b' (inactive)')
1452 current = tag == repo.dirstate.branch()
1452 current = tag == repo.dirstate.branch()
1453 if current:
1453 if current:
1454 label = b'branches.current'
1454 label = b'branches.current'
1455
1455
1456 fm.startitem()
1456 fm.startitem()
1457 fm.write(b'branch', b'%s', tag, label=label)
1457 fm.write(b'branch', b'%s', tag, label=label)
1458 rev = ctx.rev()
1458 rev = ctx.rev()
1459 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1459 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1460 fmt = b' ' * padsize + b' %d:%s'
1460 fmt = b' ' * padsize + b' %d:%s'
1461 fm.condwrite(
1461 fm.condwrite(
1462 not ui.quiet,
1462 not ui.quiet,
1463 b'rev node',
1463 b'rev node',
1464 fmt,
1464 fmt,
1465 rev,
1465 rev,
1466 hexfunc(ctx.node()),
1466 hexfunc(ctx.node()),
1467 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1467 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1468 )
1468 )
1469 fm.context(ctx=ctx)
1469 fm.context(ctx=ctx)
1470 fm.data(active=isactive, closed=not isopen, current=current)
1470 fm.data(active=isactive, closed=not isopen, current=current)
1471 if not ui.quiet:
1471 if not ui.quiet:
1472 fm.plain(notice)
1472 fm.plain(notice)
1473 fm.plain(b'\n')
1473 fm.plain(b'\n')
1474 fm.end()
1474 fm.end()
1475
1475
1476
1476
1477 @command(
1477 @command(
1478 b'bundle',
1478 b'bundle',
1479 [
1479 [
1480 (
1480 (
1481 b'f',
1481 b'f',
1482 b'force',
1482 b'force',
1483 None,
1483 None,
1484 _(b'run even when the destination is unrelated'),
1484 _(b'run even when the destination is unrelated'),
1485 ),
1485 ),
1486 (
1486 (
1487 b'r',
1487 b'r',
1488 b'rev',
1488 b'rev',
1489 [],
1489 [],
1490 _(b'a changeset intended to be added to the destination'),
1490 _(b'a changeset intended to be added to the destination'),
1491 _(b'REV'),
1491 _(b'REV'),
1492 ),
1492 ),
1493 (
1493 (
1494 b'b',
1494 b'b',
1495 b'branch',
1495 b'branch',
1496 [],
1496 [],
1497 _(b'a specific branch you would like to bundle'),
1497 _(b'a specific branch you would like to bundle'),
1498 _(b'BRANCH'),
1498 _(b'BRANCH'),
1499 ),
1499 ),
1500 (
1500 (
1501 b'',
1501 b'',
1502 b'base',
1502 b'base',
1503 [],
1503 [],
1504 _(b'a base changeset assumed to be available at the destination'),
1504 _(b'a base changeset assumed to be available at the destination'),
1505 _(b'REV'),
1505 _(b'REV'),
1506 ),
1506 ),
1507 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1507 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1508 (
1508 (
1509 b't',
1509 b't',
1510 b'type',
1510 b'type',
1511 b'bzip2',
1511 b'bzip2',
1512 _(b'bundle compression type to use'),
1512 _(b'bundle compression type to use'),
1513 _(b'TYPE'),
1513 _(b'TYPE'),
1514 ),
1514 ),
1515 ]
1515 ]
1516 + remoteopts,
1516 + remoteopts,
1517 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1517 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1518 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1518 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1519 )
1519 )
1520 def bundle(ui, repo, fname, dest=None, **opts):
1520 def bundle(ui, repo, fname, dest=None, **opts):
1521 """create a bundle file
1521 """create a bundle file
1522
1522
1523 Generate a bundle file containing data to be transferred to another
1523 Generate a bundle file containing data to be transferred to another
1524 repository.
1524 repository.
1525
1525
1526 To create a bundle containing all changesets, use -a/--all
1526 To create a bundle containing all changesets, use -a/--all
1527 (or --base null). Otherwise, hg assumes the destination will have
1527 (or --base null). Otherwise, hg assumes the destination will have
1528 all the nodes you specify with --base parameters. Otherwise, hg
1528 all the nodes you specify with --base parameters. Otherwise, hg
1529 will assume the repository has all the nodes in destination, or
1529 will assume the repository has all the nodes in destination, or
1530 default-push/default if no destination is specified, where destination
1530 default-push/default if no destination is specified, where destination
1531 is the repository you provide through DEST option.
1531 is the repository you provide through DEST option.
1532
1532
1533 You can change bundle format with the -t/--type option. See
1533 You can change bundle format with the -t/--type option. See
1534 :hg:`help bundlespec` for documentation on this format. By default,
1534 :hg:`help bundlespec` for documentation on this format. By default,
1535 the most appropriate format is used and compression defaults to
1535 the most appropriate format is used and compression defaults to
1536 bzip2.
1536 bzip2.
1537
1537
1538 The bundle file can then be transferred using conventional means
1538 The bundle file can then be transferred using conventional means
1539 and applied to another repository with the unbundle or pull
1539 and applied to another repository with the unbundle or pull
1540 command. This is useful when direct push and pull are not
1540 command. This is useful when direct push and pull are not
1541 available or when exporting an entire repository is undesirable.
1541 available or when exporting an entire repository is undesirable.
1542
1542
1543 Applying bundles preserves all changeset contents including
1543 Applying bundles preserves all changeset contents including
1544 permissions, copy/rename information, and revision history.
1544 permissions, copy/rename information, and revision history.
1545
1545
1546 Returns 0 on success, 1 if no changes found.
1546 Returns 0 on success, 1 if no changes found.
1547 """
1547 """
1548 opts = pycompat.byteskwargs(opts)
1548 opts = pycompat.byteskwargs(opts)
1549 revs = None
1549 revs = None
1550 if b'rev' in opts:
1550 if b'rev' in opts:
1551 revstrings = opts[b'rev']
1551 revstrings = opts[b'rev']
1552 revs = scmutil.revrange(repo, revstrings)
1552 revs = scmutil.revrange(repo, revstrings)
1553 if revstrings and not revs:
1553 if revstrings and not revs:
1554 raise error.Abort(_(b'no commits to bundle'))
1554 raise error.Abort(_(b'no commits to bundle'))
1555
1555
1556 bundletype = opts.get(b'type', b'bzip2').lower()
1556 bundletype = opts.get(b'type', b'bzip2').lower()
1557 try:
1557 try:
1558 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1558 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1559 except error.UnsupportedBundleSpecification as e:
1559 except error.UnsupportedBundleSpecification as e:
1560 raise error.Abort(
1560 raise error.Abort(
1561 pycompat.bytestr(e),
1561 pycompat.bytestr(e),
1562 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1562 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1563 )
1563 )
1564 cgversion = bundlespec.contentopts[b"cg.version"]
1564 cgversion = bundlespec.contentopts[b"cg.version"]
1565
1565
1566 # Packed bundles are a pseudo bundle format for now.
1566 # Packed bundles are a pseudo bundle format for now.
1567 if cgversion == b's1':
1567 if cgversion == b's1':
1568 raise error.Abort(
1568 raise error.Abort(
1569 _(b'packed bundles cannot be produced by "hg bundle"'),
1569 _(b'packed bundles cannot be produced by "hg bundle"'),
1570 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1570 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1571 )
1571 )
1572
1572
1573 if opts.get(b'all'):
1573 if opts.get(b'all'):
1574 if dest:
1574 if dest:
1575 raise error.Abort(
1575 raise error.Abort(
1576 _(b"--all is incompatible with specifying a destination")
1576 _(b"--all is incompatible with specifying a destination")
1577 )
1577 )
1578 if opts.get(b'base'):
1578 if opts.get(b'base'):
1579 ui.warn(_(b"ignoring --base because --all was specified\n"))
1579 ui.warn(_(b"ignoring --base because --all was specified\n"))
1580 base = [nullrev]
1580 base = [nullrev]
1581 else:
1581 else:
1582 base = scmutil.revrange(repo, opts.get(b'base'))
1582 base = scmutil.revrange(repo, opts.get(b'base'))
1583 if cgversion not in changegroup.supportedoutgoingversions(repo):
1583 if cgversion not in changegroup.supportedoutgoingversions(repo):
1584 raise error.Abort(
1584 raise error.Abort(
1585 _(b"repository does not support bundle version %s") % cgversion
1585 _(b"repository does not support bundle version %s") % cgversion
1586 )
1586 )
1587
1587
1588 if base:
1588 if base:
1589 if dest:
1589 if dest:
1590 raise error.Abort(
1590 raise error.Abort(
1591 _(b"--base is incompatible with specifying a destination")
1591 _(b"--base is incompatible with specifying a destination")
1592 )
1592 )
1593 common = [repo[rev].node() for rev in base]
1593 common = [repo[rev].node() for rev in base]
1594 heads = [repo[r].node() for r in revs] if revs else None
1594 heads = [repo[r].node() for r in revs] if revs else None
1595 outgoing = discovery.outgoing(repo, common, heads)
1595 outgoing = discovery.outgoing(repo, common, heads)
1596 else:
1596 else:
1597 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1597 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1598 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1598 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1599 other = hg.peer(repo, opts, dest)
1599 other = hg.peer(repo, opts, dest)
1600 revs = [repo[r].hex() for r in revs]
1600 revs = [repo[r].hex() for r in revs]
1601 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1601 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1602 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1602 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1603 outgoing = discovery.findcommonoutgoing(
1603 outgoing = discovery.findcommonoutgoing(
1604 repo,
1604 repo,
1605 other,
1605 other,
1606 onlyheads=heads,
1606 onlyheads=heads,
1607 force=opts.get(b'force'),
1607 force=opts.get(b'force'),
1608 portable=True,
1608 portable=True,
1609 )
1609 )
1610
1610
1611 if not outgoing.missing:
1611 if not outgoing.missing:
1612 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1612 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1613 return 1
1613 return 1
1614
1614
1615 if cgversion == b'01': # bundle1
1615 if cgversion == b'01': # bundle1
1616 bversion = b'HG10' + bundlespec.wirecompression
1616 bversion = b'HG10' + bundlespec.wirecompression
1617 bcompression = None
1617 bcompression = None
1618 elif cgversion in (b'02', b'03'):
1618 elif cgversion in (b'02', b'03'):
1619 bversion = b'HG20'
1619 bversion = b'HG20'
1620 bcompression = bundlespec.wirecompression
1620 bcompression = bundlespec.wirecompression
1621 else:
1621 else:
1622 raise error.ProgrammingError(
1622 raise error.ProgrammingError(
1623 b'bundle: unexpected changegroup version %s' % cgversion
1623 b'bundle: unexpected changegroup version %s' % cgversion
1624 )
1624 )
1625
1625
1626 # TODO compression options should be derived from bundlespec parsing.
1626 # TODO compression options should be derived from bundlespec parsing.
1627 # This is a temporary hack to allow adjusting bundle compression
1627 # This is a temporary hack to allow adjusting bundle compression
1628 # level without a) formalizing the bundlespec changes to declare it
1628 # level without a) formalizing the bundlespec changes to declare it
1629 # b) introducing a command flag.
1629 # b) introducing a command flag.
1630 compopts = {}
1630 compopts = {}
1631 complevel = ui.configint(
1631 complevel = ui.configint(
1632 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1632 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1633 )
1633 )
1634 if complevel is None:
1634 if complevel is None:
1635 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1635 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1636 if complevel is not None:
1636 if complevel is not None:
1637 compopts[b'level'] = complevel
1637 compopts[b'level'] = complevel
1638
1638
1639 # Allow overriding the bundling of obsmarker in phases through
1639 # Allow overriding the bundling of obsmarker in phases through
1640 # configuration while we don't have a bundle version that include them
1640 # configuration while we don't have a bundle version that include them
1641 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1641 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1642 bundlespec.contentopts[b'obsolescence'] = True
1642 bundlespec.contentopts[b'obsolescence'] = True
1643 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1643 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1644 bundlespec.contentopts[b'phases'] = True
1644 bundlespec.contentopts[b'phases'] = True
1645
1645
1646 bundle2.writenewbundle(
1646 bundle2.writenewbundle(
1647 ui,
1647 ui,
1648 repo,
1648 repo,
1649 b'bundle',
1649 b'bundle',
1650 fname,
1650 fname,
1651 bversion,
1651 bversion,
1652 outgoing,
1652 outgoing,
1653 bundlespec.contentopts,
1653 bundlespec.contentopts,
1654 compression=bcompression,
1654 compression=bcompression,
1655 compopts=compopts,
1655 compopts=compopts,
1656 )
1656 )
1657
1657
1658
1658
1659 @command(
1659 @command(
1660 b'cat',
1660 b'cat',
1661 [
1661 [
1662 (
1662 (
1663 b'o',
1663 b'o',
1664 b'output',
1664 b'output',
1665 b'',
1665 b'',
1666 _(b'print output to file with formatted name'),
1666 _(b'print output to file with formatted name'),
1667 _(b'FORMAT'),
1667 _(b'FORMAT'),
1668 ),
1668 ),
1669 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1669 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1670 (b'', b'decode', None, _(b'apply any matching decode filter')),
1670 (b'', b'decode', None, _(b'apply any matching decode filter')),
1671 ]
1671 ]
1672 + walkopts
1672 + walkopts
1673 + formatteropts,
1673 + formatteropts,
1674 _(b'[OPTION]... FILE...'),
1674 _(b'[OPTION]... FILE...'),
1675 helpcategory=command.CATEGORY_FILE_CONTENTS,
1675 helpcategory=command.CATEGORY_FILE_CONTENTS,
1676 inferrepo=True,
1676 inferrepo=True,
1677 intents={INTENT_READONLY},
1677 intents={INTENT_READONLY},
1678 )
1678 )
1679 def cat(ui, repo, file1, *pats, **opts):
1679 def cat(ui, repo, file1, *pats, **opts):
1680 """output the current or given revision of files
1680 """output the current or given revision of files
1681
1681
1682 Print the specified files as they were at the given revision. If
1682 Print the specified files as they were at the given revision. If
1683 no revision is given, the parent of the working directory is used.
1683 no revision is given, the parent of the working directory is used.
1684
1684
1685 Output may be to a file, in which case the name of the file is
1685 Output may be to a file, in which case the name of the file is
1686 given using a template string. See :hg:`help templates`. In addition
1686 given using a template string. See :hg:`help templates`. In addition
1687 to the common template keywords, the following formatting rules are
1687 to the common template keywords, the following formatting rules are
1688 supported:
1688 supported:
1689
1689
1690 :``%%``: literal "%" character
1690 :``%%``: literal "%" character
1691 :``%s``: basename of file being printed
1691 :``%s``: basename of file being printed
1692 :``%d``: dirname of file being printed, or '.' if in repository root
1692 :``%d``: dirname of file being printed, or '.' if in repository root
1693 :``%p``: root-relative path name of file being printed
1693 :``%p``: root-relative path name of file being printed
1694 :``%H``: changeset hash (40 hexadecimal digits)
1694 :``%H``: changeset hash (40 hexadecimal digits)
1695 :``%R``: changeset revision number
1695 :``%R``: changeset revision number
1696 :``%h``: short-form changeset hash (12 hexadecimal digits)
1696 :``%h``: short-form changeset hash (12 hexadecimal digits)
1697 :``%r``: zero-padded changeset revision number
1697 :``%r``: zero-padded changeset revision number
1698 :``%b``: basename of the exporting repository
1698 :``%b``: basename of the exporting repository
1699 :``\\``: literal "\\" character
1699 :``\\``: literal "\\" character
1700
1700
1701 .. container:: verbose
1701 .. container:: verbose
1702
1702
1703 Template:
1703 Template:
1704
1704
1705 The following keywords are supported in addition to the common template
1705 The following keywords are supported in addition to the common template
1706 keywords and functions. See also :hg:`help templates`.
1706 keywords and functions. See also :hg:`help templates`.
1707
1707
1708 :data: String. File content.
1708 :data: String. File content.
1709 :path: String. Repository-absolute path of the file.
1709 :path: String. Repository-absolute path of the file.
1710
1710
1711 Returns 0 on success.
1711 Returns 0 on success.
1712 """
1712 """
1713 opts = pycompat.byteskwargs(opts)
1713 opts = pycompat.byteskwargs(opts)
1714 rev = opts.get(b'rev')
1714 rev = opts.get(b'rev')
1715 if rev:
1715 if rev:
1716 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1716 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1717 ctx = scmutil.revsingle(repo, rev)
1717 ctx = scmutil.revsingle(repo, rev)
1718 m = scmutil.match(ctx, (file1,) + pats, opts)
1718 m = scmutil.match(ctx, (file1,) + pats, opts)
1719 fntemplate = opts.pop(b'output', b'')
1719 fntemplate = opts.pop(b'output', b'')
1720 if cmdutil.isstdiofilename(fntemplate):
1720 if cmdutil.isstdiofilename(fntemplate):
1721 fntemplate = b''
1721 fntemplate = b''
1722
1722
1723 if fntemplate:
1723 if fntemplate:
1724 fm = formatter.nullformatter(ui, b'cat', opts)
1724 fm = formatter.nullformatter(ui, b'cat', opts)
1725 else:
1725 else:
1726 ui.pager(b'cat')
1726 ui.pager(b'cat')
1727 fm = ui.formatter(b'cat', opts)
1727 fm = ui.formatter(b'cat', opts)
1728 with fm:
1728 with fm:
1729 return cmdutil.cat(
1729 return cmdutil.cat(
1730 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1730 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1731 )
1731 )
1732
1732
1733
1733
1734 @command(
1734 @command(
1735 b'clone',
1735 b'clone',
1736 [
1736 [
1737 (
1737 (
1738 b'U',
1738 b'U',
1739 b'noupdate',
1739 b'noupdate',
1740 None,
1740 None,
1741 _(
1741 _(
1742 b'the clone will include an empty working '
1742 b'the clone will include an empty working '
1743 b'directory (only a repository)'
1743 b'directory (only a repository)'
1744 ),
1744 ),
1745 ),
1745 ),
1746 (
1746 (
1747 b'u',
1747 b'u',
1748 b'updaterev',
1748 b'updaterev',
1749 b'',
1749 b'',
1750 _(b'revision, tag, or branch to check out'),
1750 _(b'revision, tag, or branch to check out'),
1751 _(b'REV'),
1751 _(b'REV'),
1752 ),
1752 ),
1753 (
1753 (
1754 b'r',
1754 b'r',
1755 b'rev',
1755 b'rev',
1756 [],
1756 [],
1757 _(
1757 _(
1758 b'do not clone everything, but include this changeset'
1758 b'do not clone everything, but include this changeset'
1759 b' and its ancestors'
1759 b' and its ancestors'
1760 ),
1760 ),
1761 _(b'REV'),
1761 _(b'REV'),
1762 ),
1762 ),
1763 (
1763 (
1764 b'b',
1764 b'b',
1765 b'branch',
1765 b'branch',
1766 [],
1766 [],
1767 _(
1767 _(
1768 b'do not clone everything, but include this branch\'s'
1768 b'do not clone everything, but include this branch\'s'
1769 b' changesets and their ancestors'
1769 b' changesets and their ancestors'
1770 ),
1770 ),
1771 _(b'BRANCH'),
1771 _(b'BRANCH'),
1772 ),
1772 ),
1773 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1773 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1774 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1774 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1775 (b'', b'stream', None, _(b'clone with minimal data processing')),
1775 (b'', b'stream', None, _(b'clone with minimal data processing')),
1776 ]
1776 ]
1777 + remoteopts,
1777 + remoteopts,
1778 _(b'[OPTION]... SOURCE [DEST]'),
1778 _(b'[OPTION]... SOURCE [DEST]'),
1779 helpcategory=command.CATEGORY_REPO_CREATION,
1779 helpcategory=command.CATEGORY_REPO_CREATION,
1780 helpbasic=True,
1780 helpbasic=True,
1781 norepo=True,
1781 norepo=True,
1782 )
1782 )
1783 def clone(ui, source, dest=None, **opts):
1783 def clone(ui, source, dest=None, **opts):
1784 """make a copy of an existing repository
1784 """make a copy of an existing repository
1785
1785
1786 Create a copy of an existing repository in a new directory.
1786 Create a copy of an existing repository in a new directory.
1787
1787
1788 If no destination directory name is specified, it defaults to the
1788 If no destination directory name is specified, it defaults to the
1789 basename of the source.
1789 basename of the source.
1790
1790
1791 The location of the source is added to the new repository's
1791 The location of the source is added to the new repository's
1792 ``.hg/hgrc`` file, as the default to be used for future pulls.
1792 ``.hg/hgrc`` file, as the default to be used for future pulls.
1793
1793
1794 Only local paths and ``ssh://`` URLs are supported as
1794 Only local paths and ``ssh://`` URLs are supported as
1795 destinations. For ``ssh://`` destinations, no working directory or
1795 destinations. For ``ssh://`` destinations, no working directory or
1796 ``.hg/hgrc`` will be created on the remote side.
1796 ``.hg/hgrc`` will be created on the remote side.
1797
1797
1798 If the source repository has a bookmark called '@' set, that
1798 If the source repository has a bookmark called '@' set, that
1799 revision will be checked out in the new repository by default.
1799 revision will be checked out in the new repository by default.
1800
1800
1801 To check out a particular version, use -u/--update, or
1801 To check out a particular version, use -u/--update, or
1802 -U/--noupdate to create a clone with no working directory.
1802 -U/--noupdate to create a clone with no working directory.
1803
1803
1804 To pull only a subset of changesets, specify one or more revisions
1804 To pull only a subset of changesets, specify one or more revisions
1805 identifiers with -r/--rev or branches with -b/--branch. The
1805 identifiers with -r/--rev or branches with -b/--branch. The
1806 resulting clone will contain only the specified changesets and
1806 resulting clone will contain only the specified changesets and
1807 their ancestors. These options (or 'clone src#rev dest') imply
1807 their ancestors. These options (or 'clone src#rev dest') imply
1808 --pull, even for local source repositories.
1808 --pull, even for local source repositories.
1809
1809
1810 In normal clone mode, the remote normalizes repository data into a common
1810 In normal clone mode, the remote normalizes repository data into a common
1811 exchange format and the receiving end translates this data into its local
1811 exchange format and the receiving end translates this data into its local
1812 storage format. --stream activates a different clone mode that essentially
1812 storage format. --stream activates a different clone mode that essentially
1813 copies repository files from the remote with minimal data processing. This
1813 copies repository files from the remote with minimal data processing. This
1814 significantly reduces the CPU cost of a clone both remotely and locally.
1814 significantly reduces the CPU cost of a clone both remotely and locally.
1815 However, it often increases the transferred data size by 30-40%. This can
1815 However, it often increases the transferred data size by 30-40%. This can
1816 result in substantially faster clones where I/O throughput is plentiful,
1816 result in substantially faster clones where I/O throughput is plentiful,
1817 especially for larger repositories. A side-effect of --stream clones is
1817 especially for larger repositories. A side-effect of --stream clones is
1818 that storage settings and requirements on the remote are applied locally:
1818 that storage settings and requirements on the remote are applied locally:
1819 a modern client may inherit legacy or inefficient storage used by the
1819 a modern client may inherit legacy or inefficient storage used by the
1820 remote or a legacy Mercurial client may not be able to clone from a
1820 remote or a legacy Mercurial client may not be able to clone from a
1821 modern Mercurial remote.
1821 modern Mercurial remote.
1822
1822
1823 .. note::
1823 .. note::
1824
1824
1825 Specifying a tag will include the tagged changeset but not the
1825 Specifying a tag will include the tagged changeset but not the
1826 changeset containing the tag.
1826 changeset containing the tag.
1827
1827
1828 .. container:: verbose
1828 .. container:: verbose
1829
1829
1830 For efficiency, hardlinks are used for cloning whenever the
1830 For efficiency, hardlinks are used for cloning whenever the
1831 source and destination are on the same filesystem (note this
1831 source and destination are on the same filesystem (note this
1832 applies only to the repository data, not to the working
1832 applies only to the repository data, not to the working
1833 directory). Some filesystems, such as AFS, implement hardlinking
1833 directory). Some filesystems, such as AFS, implement hardlinking
1834 incorrectly, but do not report errors. In these cases, use the
1834 incorrectly, but do not report errors. In these cases, use the
1835 --pull option to avoid hardlinking.
1835 --pull option to avoid hardlinking.
1836
1836
1837 Mercurial will update the working directory to the first applicable
1837 Mercurial will update the working directory to the first applicable
1838 revision from this list:
1838 revision from this list:
1839
1839
1840 a) null if -U or the source repository has no changesets
1840 a) null if -U or the source repository has no changesets
1841 b) if -u . and the source repository is local, the first parent of
1841 b) if -u . and the source repository is local, the first parent of
1842 the source repository's working directory
1842 the source repository's working directory
1843 c) the changeset specified with -u (if a branch name, this means the
1843 c) the changeset specified with -u (if a branch name, this means the
1844 latest head of that branch)
1844 latest head of that branch)
1845 d) the changeset specified with -r
1845 d) the changeset specified with -r
1846 e) the tipmost head specified with -b
1846 e) the tipmost head specified with -b
1847 f) the tipmost head specified with the url#branch source syntax
1847 f) the tipmost head specified with the url#branch source syntax
1848 g) the revision marked with the '@' bookmark, if present
1848 g) the revision marked with the '@' bookmark, if present
1849 h) the tipmost head of the default branch
1849 h) the tipmost head of the default branch
1850 i) tip
1850 i) tip
1851
1851
1852 When cloning from servers that support it, Mercurial may fetch
1852 When cloning from servers that support it, Mercurial may fetch
1853 pre-generated data from a server-advertised URL or inline from the
1853 pre-generated data from a server-advertised URL or inline from the
1854 same stream. When this is done, hooks operating on incoming changesets
1854 same stream. When this is done, hooks operating on incoming changesets
1855 and changegroups may fire more than once, once for each pre-generated
1855 and changegroups may fire more than once, once for each pre-generated
1856 bundle and as well as for any additional remaining data. In addition,
1856 bundle and as well as for any additional remaining data. In addition,
1857 if an error occurs, the repository may be rolled back to a partial
1857 if an error occurs, the repository may be rolled back to a partial
1858 clone. This behavior may change in future releases.
1858 clone. This behavior may change in future releases.
1859 See :hg:`help -e clonebundles` for more.
1859 See :hg:`help -e clonebundles` for more.
1860
1860
1861 Examples:
1861 Examples:
1862
1862
1863 - clone a remote repository to a new directory named hg/::
1863 - clone a remote repository to a new directory named hg/::
1864
1864
1865 hg clone https://www.mercurial-scm.org/repo/hg/
1865 hg clone https://www.mercurial-scm.org/repo/hg/
1866
1866
1867 - create a lightweight local clone::
1867 - create a lightweight local clone::
1868
1868
1869 hg clone project/ project-feature/
1869 hg clone project/ project-feature/
1870
1870
1871 - clone from an absolute path on an ssh server (note double-slash)::
1871 - clone from an absolute path on an ssh server (note double-slash)::
1872
1872
1873 hg clone ssh://user@server//home/projects/alpha/
1873 hg clone ssh://user@server//home/projects/alpha/
1874
1874
1875 - do a streaming clone while checking out a specified version::
1875 - do a streaming clone while checking out a specified version::
1876
1876
1877 hg clone --stream http://server/repo -u 1.5
1877 hg clone --stream http://server/repo -u 1.5
1878
1878
1879 - create a repository without changesets after a particular revision::
1879 - create a repository without changesets after a particular revision::
1880
1880
1881 hg clone -r 04e544 experimental/ good/
1881 hg clone -r 04e544 experimental/ good/
1882
1882
1883 - clone (and track) a particular named branch::
1883 - clone (and track) a particular named branch::
1884
1884
1885 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1885 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1886
1886
1887 See :hg:`help urls` for details on specifying URLs.
1887 See :hg:`help urls` for details on specifying URLs.
1888
1888
1889 Returns 0 on success.
1889 Returns 0 on success.
1890 """
1890 """
1891 opts = pycompat.byteskwargs(opts)
1891 opts = pycompat.byteskwargs(opts)
1892 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1892 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1893
1893
1894 # --include/--exclude can come from narrow or sparse.
1894 # --include/--exclude can come from narrow or sparse.
1895 includepats, excludepats = None, None
1895 includepats, excludepats = None, None
1896
1896
1897 # hg.clone() differentiates between None and an empty set. So make sure
1897 # hg.clone() differentiates between None and an empty set. So make sure
1898 # patterns are sets if narrow is requested without patterns.
1898 # patterns are sets if narrow is requested without patterns.
1899 if opts.get(b'narrow'):
1899 if opts.get(b'narrow'):
1900 includepats = set()
1900 includepats = set()
1901 excludepats = set()
1901 excludepats = set()
1902
1902
1903 if opts.get(b'include'):
1903 if opts.get(b'include'):
1904 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1904 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1905 if opts.get(b'exclude'):
1905 if opts.get(b'exclude'):
1906 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1906 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1907
1907
1908 r = hg.clone(
1908 r = hg.clone(
1909 ui,
1909 ui,
1910 opts,
1910 opts,
1911 source,
1911 source,
1912 dest,
1912 dest,
1913 pull=opts.get(b'pull'),
1913 pull=opts.get(b'pull'),
1914 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1914 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1915 revs=opts.get(b'rev'),
1915 revs=opts.get(b'rev'),
1916 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1916 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1917 branch=opts.get(b'branch'),
1917 branch=opts.get(b'branch'),
1918 shareopts=opts.get(b'shareopts'),
1918 shareopts=opts.get(b'shareopts'),
1919 storeincludepats=includepats,
1919 storeincludepats=includepats,
1920 storeexcludepats=excludepats,
1920 storeexcludepats=excludepats,
1921 depth=opts.get(b'depth') or None,
1921 depth=opts.get(b'depth') or None,
1922 )
1922 )
1923
1923
1924 return r is None
1924 return r is None
1925
1925
1926
1926
1927 @command(
1927 @command(
1928 b'commit|ci',
1928 b'commit|ci',
1929 [
1929 [
1930 (
1930 (
1931 b'A',
1931 b'A',
1932 b'addremove',
1932 b'addremove',
1933 None,
1933 None,
1934 _(b'mark new/missing files as added/removed before committing'),
1934 _(b'mark new/missing files as added/removed before committing'),
1935 ),
1935 ),
1936 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1936 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1937 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1937 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1938 (b's', b'secret', None, _(b'use the secret phase for committing')),
1938 (b's', b'secret', None, _(b'use the secret phase for committing')),
1939 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1939 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1940 (
1940 (
1941 b'',
1941 b'',
1942 b'force-close-branch',
1942 b'force-close-branch',
1943 None,
1943 None,
1944 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1944 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1945 ),
1945 ),
1946 (b'i', b'interactive', None, _(b'use interactive mode')),
1946 (b'i', b'interactive', None, _(b'use interactive mode')),
1947 ]
1947 ]
1948 + walkopts
1948 + walkopts
1949 + commitopts
1949 + commitopts
1950 + commitopts2
1950 + commitopts2
1951 + subrepoopts,
1951 + subrepoopts,
1952 _(b'[OPTION]... [FILE]...'),
1952 _(b'[OPTION]... [FILE]...'),
1953 helpcategory=command.CATEGORY_COMMITTING,
1953 helpcategory=command.CATEGORY_COMMITTING,
1954 helpbasic=True,
1954 helpbasic=True,
1955 inferrepo=True,
1955 inferrepo=True,
1956 )
1956 )
1957 def commit(ui, repo, *pats, **opts):
1957 def commit(ui, repo, *pats, **opts):
1958 """commit the specified files or all outstanding changes
1958 """commit the specified files or all outstanding changes
1959
1959
1960 Commit changes to the given files into the repository. Unlike a
1960 Commit changes to the given files into the repository. Unlike a
1961 centralized SCM, this operation is a local operation. See
1961 centralized SCM, this operation is a local operation. See
1962 :hg:`push` for a way to actively distribute your changes.
1962 :hg:`push` for a way to actively distribute your changes.
1963
1963
1964 If a list of files is omitted, all changes reported by :hg:`status`
1964 If a list of files is omitted, all changes reported by :hg:`status`
1965 will be committed.
1965 will be committed.
1966
1966
1967 If you are committing the result of a merge, do not provide any
1967 If you are committing the result of a merge, do not provide any
1968 filenames or -I/-X filters.
1968 filenames or -I/-X filters.
1969
1969
1970 If no commit message is specified, Mercurial starts your
1970 If no commit message is specified, Mercurial starts your
1971 configured editor where you can enter a message. In case your
1971 configured editor where you can enter a message. In case your
1972 commit fails, you will find a backup of your message in
1972 commit fails, you will find a backup of your message in
1973 ``.hg/last-message.txt``.
1973 ``.hg/last-message.txt``.
1974
1974
1975 The --close-branch flag can be used to mark the current branch
1975 The --close-branch flag can be used to mark the current branch
1976 head closed. When all heads of a branch are closed, the branch
1976 head closed. When all heads of a branch are closed, the branch
1977 will be considered closed and no longer listed.
1977 will be considered closed and no longer listed.
1978
1978
1979 The --amend flag can be used to amend the parent of the
1979 The --amend flag can be used to amend the parent of the
1980 working directory with a new commit that contains the changes
1980 working directory with a new commit that contains the changes
1981 in the parent in addition to those currently reported by :hg:`status`,
1981 in the parent in addition to those currently reported by :hg:`status`,
1982 if there are any. The old commit is stored in a backup bundle in
1982 if there are any. The old commit is stored in a backup bundle in
1983 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1983 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1984 on how to restore it).
1984 on how to restore it).
1985
1985
1986 Message, user and date are taken from the amended commit unless
1986 Message, user and date are taken from the amended commit unless
1987 specified. When a message isn't specified on the command line,
1987 specified. When a message isn't specified on the command line,
1988 the editor will open with the message of the amended commit.
1988 the editor will open with the message of the amended commit.
1989
1989
1990 It is not possible to amend public changesets (see :hg:`help phases`)
1990 It is not possible to amend public changesets (see :hg:`help phases`)
1991 or changesets that have children.
1991 or changesets that have children.
1992
1992
1993 See :hg:`help dates` for a list of formats valid for -d/--date.
1993 See :hg:`help dates` for a list of formats valid for -d/--date.
1994
1994
1995 Returns 0 on success, 1 if nothing changed.
1995 Returns 0 on success, 1 if nothing changed.
1996
1996
1997 .. container:: verbose
1997 .. container:: verbose
1998
1998
1999 Examples:
1999 Examples:
2000
2000
2001 - commit all files ending in .py::
2001 - commit all files ending in .py::
2002
2002
2003 hg commit --include "set:**.py"
2003 hg commit --include "set:**.py"
2004
2004
2005 - commit all non-binary files::
2005 - commit all non-binary files::
2006
2006
2007 hg commit --exclude "set:binary()"
2007 hg commit --exclude "set:binary()"
2008
2008
2009 - amend the current commit and set the date to now::
2009 - amend the current commit and set the date to now::
2010
2010
2011 hg commit --amend --date now
2011 hg commit --amend --date now
2012 """
2012 """
2013 with repo.wlock(), repo.lock():
2013 with repo.wlock(), repo.lock():
2014 return _docommit(ui, repo, *pats, **opts)
2014 return _docommit(ui, repo, *pats, **opts)
2015
2015
2016
2016
2017 def _docommit(ui, repo, *pats, **opts):
2017 def _docommit(ui, repo, *pats, **opts):
2018 if opts.get('interactive'):
2018 if opts.get('interactive'):
2019 opts.pop('interactive')
2019 opts.pop('interactive')
2020 ret = cmdutil.dorecord(
2020 ret = cmdutil.dorecord(
2021 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2021 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2022 )
2022 )
2023 # ret can be 0 (no changes to record) or the value returned by
2023 # ret can be 0 (no changes to record) or the value returned by
2024 # commit(), 1 if nothing changed or None on success.
2024 # commit(), 1 if nothing changed or None on success.
2025 return 1 if ret == 0 else ret
2025 return 1 if ret == 0 else ret
2026
2026
2027 opts = pycompat.byteskwargs(opts)
2027 opts = pycompat.byteskwargs(opts)
2028 if opts.get(b'subrepos'):
2028 if opts.get(b'subrepos'):
2029 if opts.get(b'amend'):
2029 if opts.get(b'amend'):
2030 raise error.Abort(_(b'cannot amend with --subrepos'))
2030 raise error.Abort(_(b'cannot amend with --subrepos'))
2031 # Let --subrepos on the command line override config setting.
2031 # Let --subrepos on the command line override config setting.
2032 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2032 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2033
2033
2034 cmdutil.checkunfinished(repo, commit=True)
2034 cmdutil.checkunfinished(repo, commit=True)
2035
2035
2036 branch = repo[None].branch()
2036 branch = repo[None].branch()
2037 bheads = repo.branchheads(branch)
2037 bheads = repo.branchheads(branch)
2038
2038
2039 extra = {}
2039 extra = {}
2040 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2040 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2041 extra[b'close'] = b'1'
2041 extra[b'close'] = b'1'
2042
2042
2043 if repo[b'.'].closesbranch():
2043 if repo[b'.'].closesbranch():
2044 raise error.Abort(
2044 raise error.Abort(
2045 _(b'current revision is already a branch closing head')
2045 _(b'current revision is already a branch closing head')
2046 )
2046 )
2047 elif not bheads:
2047 elif not bheads:
2048 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2048 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2049 elif (
2049 elif (
2050 branch == repo[b'.'].branch()
2050 branch == repo[b'.'].branch()
2051 and repo[b'.'].node() not in bheads
2051 and repo[b'.'].node() not in bheads
2052 and not opts.get(b'force_close_branch')
2052 and not opts.get(b'force_close_branch')
2053 ):
2053 ):
2054 hint = _(
2054 hint = _(
2055 b'use --force-close-branch to close branch from a non-head'
2055 b'use --force-close-branch to close branch from a non-head'
2056 b' changeset'
2056 b' changeset'
2057 )
2057 )
2058 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2058 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2059 elif opts.get(b'amend'):
2059 elif opts.get(b'amend'):
2060 if (
2060 if (
2061 repo[b'.'].p1().branch() != branch
2061 repo[b'.'].p1().branch() != branch
2062 and repo[b'.'].p2().branch() != branch
2062 and repo[b'.'].p2().branch() != branch
2063 ):
2063 ):
2064 raise error.Abort(_(b'can only close branch heads'))
2064 raise error.Abort(_(b'can only close branch heads'))
2065
2065
2066 if opts.get(b'amend'):
2066 if opts.get(b'amend'):
2067 if ui.configbool(b'ui', b'commitsubrepos'):
2067 if ui.configbool(b'ui', b'commitsubrepos'):
2068 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2068 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2069
2069
2070 old = repo[b'.']
2070 old = repo[b'.']
2071 rewriteutil.precheck(repo, [old.rev()], b'amend')
2071 rewriteutil.precheck(repo, [old.rev()], b'amend')
2072
2072
2073 # Currently histedit gets confused if an amend happens while histedit
2073 # Currently histedit gets confused if an amend happens while histedit
2074 # is in progress. Since we have a checkunfinished command, we are
2074 # is in progress. Since we have a checkunfinished command, we are
2075 # temporarily honoring it.
2075 # temporarily honoring it.
2076 #
2076 #
2077 # Note: eventually this guard will be removed. Please do not expect
2077 # Note: eventually this guard will be removed. Please do not expect
2078 # this behavior to remain.
2078 # this behavior to remain.
2079 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2079 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2080 cmdutil.checkunfinished(repo)
2080 cmdutil.checkunfinished(repo)
2081
2081
2082 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2082 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2083 if node == old.node():
2083 if node == old.node():
2084 ui.status(_(b"nothing changed\n"))
2084 ui.status(_(b"nothing changed\n"))
2085 return 1
2085 return 1
2086 else:
2086 else:
2087
2087
2088 def commitfunc(ui, repo, message, match, opts):
2088 def commitfunc(ui, repo, message, match, opts):
2089 overrides = {}
2089 overrides = {}
2090 if opts.get(b'secret'):
2090 if opts.get(b'secret'):
2091 overrides[(b'phases', b'new-commit')] = b'secret'
2091 overrides[(b'phases', b'new-commit')] = b'secret'
2092
2092
2093 baseui = repo.baseui
2093 baseui = repo.baseui
2094 with baseui.configoverride(overrides, b'commit'):
2094 with baseui.configoverride(overrides, b'commit'):
2095 with ui.configoverride(overrides, b'commit'):
2095 with ui.configoverride(overrides, b'commit'):
2096 editform = cmdutil.mergeeditform(
2096 editform = cmdutil.mergeeditform(
2097 repo[None], b'commit.normal'
2097 repo[None], b'commit.normal'
2098 )
2098 )
2099 editor = cmdutil.getcommiteditor(
2099 editor = cmdutil.getcommiteditor(
2100 editform=editform, **pycompat.strkwargs(opts)
2100 editform=editform, **pycompat.strkwargs(opts)
2101 )
2101 )
2102 return repo.commit(
2102 return repo.commit(
2103 message,
2103 message,
2104 opts.get(b'user'),
2104 opts.get(b'user'),
2105 opts.get(b'date'),
2105 opts.get(b'date'),
2106 match,
2106 match,
2107 editor=editor,
2107 editor=editor,
2108 extra=extra,
2108 extra=extra,
2109 )
2109 )
2110
2110
2111 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2111 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2112
2112
2113 if not node:
2113 if not node:
2114 stat = cmdutil.postcommitstatus(repo, pats, opts)
2114 stat = cmdutil.postcommitstatus(repo, pats, opts)
2115 if stat.deleted:
2115 if stat.deleted:
2116 ui.status(
2116 ui.status(
2117 _(
2117 _(
2118 b"nothing changed (%d missing files, see "
2118 b"nothing changed (%d missing files, see "
2119 b"'hg status')\n"
2119 b"'hg status')\n"
2120 )
2120 )
2121 % len(stat.deleted)
2121 % len(stat.deleted)
2122 )
2122 )
2123 else:
2123 else:
2124 ui.status(_(b"nothing changed\n"))
2124 ui.status(_(b"nothing changed\n"))
2125 return 1
2125 return 1
2126
2126
2127 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2127 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2128
2128
2129 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2129 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2130 status(
2130 status(
2131 ui,
2131 ui,
2132 repo,
2132 repo,
2133 modified=True,
2133 modified=True,
2134 added=True,
2134 added=True,
2135 removed=True,
2135 removed=True,
2136 deleted=True,
2136 deleted=True,
2137 unknown=True,
2137 unknown=True,
2138 subrepos=opts.get(b'subrepos'),
2138 subrepos=opts.get(b'subrepos'),
2139 )
2139 )
2140
2140
2141
2141
2142 @command(
2142 @command(
2143 b'config|showconfig|debugconfig',
2143 b'config|showconfig|debugconfig',
2144 [
2144 [
2145 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2145 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2146 (b'e', b'edit', None, _(b'edit user config')),
2146 (b'e', b'edit', None, _(b'edit user config')),
2147 (b'l', b'local', None, _(b'edit repository config')),
2147 (b'l', b'local', None, _(b'edit repository config')),
2148 (b'g', b'global', None, _(b'edit global config')),
2148 (b'g', b'global', None, _(b'edit global config')),
2149 ]
2149 ]
2150 + formatteropts,
2150 + formatteropts,
2151 _(b'[-u] [NAME]...'),
2151 _(b'[-u] [NAME]...'),
2152 helpcategory=command.CATEGORY_HELP,
2152 helpcategory=command.CATEGORY_HELP,
2153 optionalrepo=True,
2153 optionalrepo=True,
2154 intents={INTENT_READONLY},
2154 intents={INTENT_READONLY},
2155 )
2155 )
2156 def config(ui, repo, *values, **opts):
2156 def config(ui, repo, *values, **opts):
2157 """show combined config settings from all hgrc files
2157 """show combined config settings from all hgrc files
2158
2158
2159 With no arguments, print names and values of all config items.
2159 With no arguments, print names and values of all config items.
2160
2160
2161 With one argument of the form section.name, print just the value
2161 With one argument of the form section.name, print just the value
2162 of that config item.
2162 of that config item.
2163
2163
2164 With multiple arguments, print names and values of all config
2164 With multiple arguments, print names and values of all config
2165 items with matching section names or section.names.
2165 items with matching section names or section.names.
2166
2166
2167 With --edit, start an editor on the user-level config file. With
2167 With --edit, start an editor on the user-level config file. With
2168 --global, edit the system-wide config file. With --local, edit the
2168 --global, edit the system-wide config file. With --local, edit the
2169 repository-level config file.
2169 repository-level config file.
2170
2170
2171 With --debug, the source (filename and line number) is printed
2171 With --debug, the source (filename and line number) is printed
2172 for each config item.
2172 for each config item.
2173
2173
2174 See :hg:`help config` for more information about config files.
2174 See :hg:`help config` for more information about config files.
2175
2175
2176 .. container:: verbose
2176 .. container:: verbose
2177
2177
2178 Template:
2178 Template:
2179
2179
2180 The following keywords are supported. See also :hg:`help templates`.
2180 The following keywords are supported. See also :hg:`help templates`.
2181
2181
2182 :name: String. Config name.
2182 :name: String. Config name.
2183 :source: String. Filename and line number where the item is defined.
2183 :source: String. Filename and line number where the item is defined.
2184 :value: String. Config value.
2184 :value: String. Config value.
2185
2185
2186 Returns 0 on success, 1 if NAME does not exist.
2186 Returns 0 on success, 1 if NAME does not exist.
2187
2187
2188 """
2188 """
2189
2189
2190 opts = pycompat.byteskwargs(opts)
2190 opts = pycompat.byteskwargs(opts)
2191 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2191 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2192 if opts.get(b'local') and opts.get(b'global'):
2192 if opts.get(b'local') and opts.get(b'global'):
2193 raise error.Abort(_(b"can't use --local and --global together"))
2193 raise error.Abort(_(b"can't use --local and --global together"))
2194
2194
2195 if opts.get(b'local'):
2195 if opts.get(b'local'):
2196 if not repo:
2196 if not repo:
2197 raise error.Abort(_(b"can't use --local outside a repository"))
2197 raise error.Abort(_(b"can't use --local outside a repository"))
2198 paths = [repo.vfs.join(b'hgrc')]
2198 paths = [repo.vfs.join(b'hgrc')]
2199 elif opts.get(b'global'):
2199 elif opts.get(b'global'):
2200 paths = rcutil.systemrcpath()
2200 paths = rcutil.systemrcpath()
2201 else:
2201 else:
2202 paths = rcutil.userrcpath()
2202 paths = rcutil.userrcpath()
2203
2203
2204 for f in paths:
2204 for f in paths:
2205 if os.path.exists(f):
2205 if os.path.exists(f):
2206 break
2206 break
2207 else:
2207 else:
2208 if opts.get(b'global'):
2208 if opts.get(b'global'):
2209 samplehgrc = uimod.samplehgrcs[b'global']
2209 samplehgrc = uimod.samplehgrcs[b'global']
2210 elif opts.get(b'local'):
2210 elif opts.get(b'local'):
2211 samplehgrc = uimod.samplehgrcs[b'local']
2211 samplehgrc = uimod.samplehgrcs[b'local']
2212 else:
2212 else:
2213 samplehgrc = uimod.samplehgrcs[b'user']
2213 samplehgrc = uimod.samplehgrcs[b'user']
2214
2214
2215 f = paths[0]
2215 f = paths[0]
2216 fp = open(f, b"wb")
2216 fp = open(f, b"wb")
2217 fp.write(util.tonativeeol(samplehgrc))
2217 fp.write(util.tonativeeol(samplehgrc))
2218 fp.close()
2218 fp.close()
2219
2219
2220 editor = ui.geteditor()
2220 editor = ui.geteditor()
2221 ui.system(
2221 ui.system(
2222 b"%s \"%s\"" % (editor, f),
2222 b"%s \"%s\"" % (editor, f),
2223 onerr=error.Abort,
2223 onerr=error.Abort,
2224 errprefix=_(b"edit failed"),
2224 errprefix=_(b"edit failed"),
2225 blockedtag=b'config_edit',
2225 blockedtag=b'config_edit',
2226 )
2226 )
2227 return
2227 return
2228 ui.pager(b'config')
2228 ui.pager(b'config')
2229 fm = ui.formatter(b'config', opts)
2229 fm = ui.formatter(b'config', opts)
2230 for t, f in rcutil.rccomponents():
2230 for t, f in rcutil.rccomponents():
2231 if t == b'path':
2231 if t == b'path':
2232 ui.debug(b'read config from: %s\n' % f)
2232 ui.debug(b'read config from: %s\n' % f)
2233 elif t == b'items':
2233 elif t == b'items':
2234 for section, name, value, source in f:
2234 for section, name, value, source in f:
2235 ui.debug(b'set config by: %s\n' % source)
2235 ui.debug(b'set config by: %s\n' % source)
2236 else:
2236 else:
2237 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2237 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2238 untrusted = bool(opts.get(b'untrusted'))
2238 untrusted = bool(opts.get(b'untrusted'))
2239
2239
2240 selsections = selentries = []
2240 selsections = selentries = []
2241 if values:
2241 if values:
2242 selsections = [v for v in values if b'.' not in v]
2242 selsections = [v for v in values if b'.' not in v]
2243 selentries = [v for v in values if b'.' in v]
2243 selentries = [v for v in values if b'.' in v]
2244 uniquesel = len(selentries) == 1 and not selsections
2244 uniquesel = len(selentries) == 1 and not selsections
2245 selsections = set(selsections)
2245 selsections = set(selsections)
2246 selentries = set(selentries)
2246 selentries = set(selentries)
2247
2247
2248 matched = False
2248 matched = False
2249 for section, name, value in ui.walkconfig(untrusted=untrusted):
2249 for section, name, value in ui.walkconfig(untrusted=untrusted):
2250 source = ui.configsource(section, name, untrusted)
2250 source = ui.configsource(section, name, untrusted)
2251 value = pycompat.bytestr(value)
2251 value = pycompat.bytestr(value)
2252 defaultvalue = ui.configdefault(section, name)
2252 defaultvalue = ui.configdefault(section, name)
2253 if fm.isplain():
2253 if fm.isplain():
2254 source = source or b'none'
2254 source = source or b'none'
2255 value = value.replace(b'\n', b'\\n')
2255 value = value.replace(b'\n', b'\\n')
2256 entryname = section + b'.' + name
2256 entryname = section + b'.' + name
2257 if values and not (section in selsections or entryname in selentries):
2257 if values and not (section in selsections or entryname in selentries):
2258 continue
2258 continue
2259 fm.startitem()
2259 fm.startitem()
2260 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2260 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2261 if uniquesel:
2261 if uniquesel:
2262 fm.data(name=entryname)
2262 fm.data(name=entryname)
2263 fm.write(b'value', b'%s\n', value)
2263 fm.write(b'value', b'%s\n', value)
2264 else:
2264 else:
2265 fm.write(b'name value', b'%s=%s\n', entryname, value)
2265 fm.write(b'name value', b'%s=%s\n', entryname, value)
2266 if formatter.isprintable(defaultvalue):
2266 if formatter.isprintable(defaultvalue):
2267 fm.data(defaultvalue=defaultvalue)
2267 fm.data(defaultvalue=defaultvalue)
2268 elif isinstance(defaultvalue, list) and all(
2268 elif isinstance(defaultvalue, list) and all(
2269 formatter.isprintable(e) for e in defaultvalue
2269 formatter.isprintable(e) for e in defaultvalue
2270 ):
2270 ):
2271 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2271 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2272 # TODO: no idea how to process unsupported defaultvalue types
2272 # TODO: no idea how to process unsupported defaultvalue types
2273 matched = True
2273 matched = True
2274 fm.end()
2274 fm.end()
2275 if matched:
2275 if matched:
2276 return 0
2276 return 0
2277 return 1
2277 return 1
2278
2278
2279
2279
2280 @command(
2280 @command(
2281 b'continue',
2281 b'continue',
2282 dryrunopts,
2282 dryrunopts,
2283 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2283 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2284 helpbasic=True,
2284 helpbasic=True,
2285 )
2285 )
2286 def continuecmd(ui, repo, **opts):
2286 def continuecmd(ui, repo, **opts):
2287 """resumes an interrupted operation (EXPERIMENTAL)
2287 """resumes an interrupted operation (EXPERIMENTAL)
2288
2288
2289 Finishes a multistep operation like graft, histedit, rebase, merge,
2289 Finishes a multistep operation like graft, histedit, rebase, merge,
2290 and unshelve if they are in an interrupted state.
2290 and unshelve if they are in an interrupted state.
2291
2291
2292 use --dry-run/-n to dry run the command.
2292 use --dry-run/-n to dry run the command.
2293 """
2293 """
2294 dryrun = opts.get('dry_run')
2294 dryrun = opts.get('dry_run')
2295 contstate = cmdutil.getunfinishedstate(repo)
2295 contstate = cmdutil.getunfinishedstate(repo)
2296 if not contstate:
2296 if not contstate:
2297 raise error.Abort(_(b'no operation in progress'))
2297 raise error.Abort(_(b'no operation in progress'))
2298 if not contstate.continuefunc:
2298 if not contstate.continuefunc:
2299 raise error.Abort(
2299 raise error.Abort(
2300 (
2300 (
2301 _(b"%s in progress but does not support 'hg continue'")
2301 _(b"%s in progress but does not support 'hg continue'")
2302 % (contstate._opname)
2302 % (contstate._opname)
2303 ),
2303 ),
2304 hint=contstate.continuemsg(),
2304 hint=contstate.continuemsg(),
2305 )
2305 )
2306 if dryrun:
2306 if dryrun:
2307 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2307 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2308 return
2308 return
2309 return contstate.continuefunc(ui, repo)
2309 return contstate.continuefunc(ui, repo)
2310
2310
2311
2311
2312 @command(
2312 @command(
2313 b'copy|cp',
2313 b'copy|cp',
2314 [
2314 [
2315 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2315 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2316 (
2316 (
2317 b'f',
2317 b'f',
2318 b'force',
2318 b'force',
2319 None,
2319 None,
2320 _(b'forcibly copy over an existing managed file'),
2320 _(b'forcibly copy over an existing managed file'),
2321 ),
2321 ),
2322 ]
2322 ]
2323 + walkopts
2323 + walkopts
2324 + dryrunopts,
2324 + dryrunopts,
2325 _(b'[OPTION]... SOURCE... DEST'),
2325 _(b'[OPTION]... SOURCE... DEST'),
2326 helpcategory=command.CATEGORY_FILE_CONTENTS,
2326 helpcategory=command.CATEGORY_FILE_CONTENTS,
2327 )
2327 )
2328 def copy(ui, repo, *pats, **opts):
2328 def copy(ui, repo, *pats, **opts):
2329 """mark files as copied for the next commit
2329 """mark files as copied for the next commit
2330
2330
2331 Mark dest as having copies of source files. If dest is a
2331 Mark dest as having copies of source files. If dest is a
2332 directory, copies are put in that directory. If dest is a file,
2332 directory, copies are put in that directory. If dest is a file,
2333 the source must be a single file.
2333 the source must be a single file.
2334
2334
2335 By default, this command copies the contents of files as they
2335 By default, this command copies the contents of files as they
2336 exist in the working directory. If invoked with -A/--after, the
2336 exist in the working directory. If invoked with -A/--after, the
2337 operation is recorded, but no copying is performed.
2337 operation is recorded, but no copying is performed.
2338
2338
2339 This command takes effect with the next commit. To undo a copy
2339 This command takes effect with the next commit. To undo a copy
2340 before that, see :hg:`revert`.
2340 before that, see :hg:`revert`.
2341
2341
2342 Returns 0 on success, 1 if errors are encountered.
2342 Returns 0 on success, 1 if errors are encountered.
2343 """
2343 """
2344 opts = pycompat.byteskwargs(opts)
2344 opts = pycompat.byteskwargs(opts)
2345 with repo.wlock(False):
2345 with repo.wlock(False):
2346 return cmdutil.copy(ui, repo, pats, opts)
2346 return cmdutil.copy(ui, repo, pats, opts)
2347
2347
2348
2348
2349 @command(
2349 @command(
2350 b'debugcommands',
2350 b'debugcommands',
2351 [],
2351 [],
2352 _(b'[COMMAND]'),
2352 _(b'[COMMAND]'),
2353 helpcategory=command.CATEGORY_HELP,
2353 helpcategory=command.CATEGORY_HELP,
2354 norepo=True,
2354 norepo=True,
2355 )
2355 )
2356 def debugcommands(ui, cmd=b'', *args):
2356 def debugcommands(ui, cmd=b'', *args):
2357 """list all available commands and options"""
2357 """list all available commands and options"""
2358 for cmd, vals in sorted(pycompat.iteritems(table)):
2358 for cmd, vals in sorted(pycompat.iteritems(table)):
2359 cmd = cmd.split(b'|')[0]
2359 cmd = cmd.split(b'|')[0]
2360 opts = b', '.join([i[1] for i in vals[1]])
2360 opts = b', '.join([i[1] for i in vals[1]])
2361 ui.write(b'%s: %s\n' % (cmd, opts))
2361 ui.write(b'%s: %s\n' % (cmd, opts))
2362
2362
2363
2363
2364 @command(
2364 @command(
2365 b'debugcomplete',
2365 b'debugcomplete',
2366 [(b'o', b'options', None, _(b'show the command options'))],
2366 [(b'o', b'options', None, _(b'show the command options'))],
2367 _(b'[-o] CMD'),
2367 _(b'[-o] CMD'),
2368 helpcategory=command.CATEGORY_HELP,
2368 helpcategory=command.CATEGORY_HELP,
2369 norepo=True,
2369 norepo=True,
2370 )
2370 )
2371 def debugcomplete(ui, cmd=b'', **opts):
2371 def debugcomplete(ui, cmd=b'', **opts):
2372 """returns the completion list associated with the given command"""
2372 """returns the completion list associated with the given command"""
2373
2373
2374 if opts.get('options'):
2374 if opts.get('options'):
2375 options = []
2375 options = []
2376 otables = [globalopts]
2376 otables = [globalopts]
2377 if cmd:
2377 if cmd:
2378 aliases, entry = cmdutil.findcmd(cmd, table, False)
2378 aliases, entry = cmdutil.findcmd(cmd, table, False)
2379 otables.append(entry[1])
2379 otables.append(entry[1])
2380 for t in otables:
2380 for t in otables:
2381 for o in t:
2381 for o in t:
2382 if b"(DEPRECATED)" in o[3]:
2382 if b"(DEPRECATED)" in o[3]:
2383 continue
2383 continue
2384 if o[0]:
2384 if o[0]:
2385 options.append(b'-%s' % o[0])
2385 options.append(b'-%s' % o[0])
2386 options.append(b'--%s' % o[1])
2386 options.append(b'--%s' % o[1])
2387 ui.write(b"%s\n" % b"\n".join(options))
2387 ui.write(b"%s\n" % b"\n".join(options))
2388 return
2388 return
2389
2389
2390 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2390 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2391 if ui.verbose:
2391 if ui.verbose:
2392 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2392 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2393 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2393 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2394
2394
2395
2395
2396 @command(
2396 @command(
2397 b'diff',
2397 b'diff',
2398 [
2398 [
2399 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2399 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2400 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2400 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2401 ]
2401 ]
2402 + diffopts
2402 + diffopts
2403 + diffopts2
2403 + diffopts2
2404 + walkopts
2404 + walkopts
2405 + subrepoopts,
2405 + subrepoopts,
2406 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2406 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2407 helpcategory=command.CATEGORY_FILE_CONTENTS,
2407 helpcategory=command.CATEGORY_FILE_CONTENTS,
2408 helpbasic=True,
2408 helpbasic=True,
2409 inferrepo=True,
2409 inferrepo=True,
2410 intents={INTENT_READONLY},
2410 intents={INTENT_READONLY},
2411 )
2411 )
2412 def diff(ui, repo, *pats, **opts):
2412 def diff(ui, repo, *pats, **opts):
2413 """diff repository (or selected files)
2413 """diff repository (or selected files)
2414
2414
2415 Show differences between revisions for the specified files.
2415 Show differences between revisions for the specified files.
2416
2416
2417 Differences between files are shown using the unified diff format.
2417 Differences between files are shown using the unified diff format.
2418
2418
2419 .. note::
2419 .. note::
2420
2420
2421 :hg:`diff` may generate unexpected results for merges, as it will
2421 :hg:`diff` may generate unexpected results for merges, as it will
2422 default to comparing against the working directory's first
2422 default to comparing against the working directory's first
2423 parent changeset if no revisions are specified.
2423 parent changeset if no revisions are specified.
2424
2424
2425 When two revision arguments are given, then changes are shown
2425 When two revision arguments are given, then changes are shown
2426 between those revisions. If only one revision is specified then
2426 between those revisions. If only one revision is specified then
2427 that revision is compared to the working directory, and, when no
2427 that revision is compared to the working directory, and, when no
2428 revisions are specified, the working directory files are compared
2428 revisions are specified, the working directory files are compared
2429 to its first parent.
2429 to its first parent.
2430
2430
2431 Alternatively you can specify -c/--change with a revision to see
2431 Alternatively you can specify -c/--change with a revision to see
2432 the changes in that changeset relative to its first parent.
2432 the changes in that changeset relative to its first parent.
2433
2433
2434 Without the -a/--text option, diff will avoid generating diffs of
2434 Without the -a/--text option, diff will avoid generating diffs of
2435 files it detects as binary. With -a, diff will generate a diff
2435 files it detects as binary. With -a, diff will generate a diff
2436 anyway, probably with undesirable results.
2436 anyway, probably with undesirable results.
2437
2437
2438 Use the -g/--git option to generate diffs in the git extended diff
2438 Use the -g/--git option to generate diffs in the git extended diff
2439 format. For more information, read :hg:`help diffs`.
2439 format. For more information, read :hg:`help diffs`.
2440
2440
2441 .. container:: verbose
2441 .. container:: verbose
2442
2442
2443 Examples:
2443 Examples:
2444
2444
2445 - compare a file in the current working directory to its parent::
2445 - compare a file in the current working directory to its parent::
2446
2446
2447 hg diff foo.c
2447 hg diff foo.c
2448
2448
2449 - compare two historical versions of a directory, with rename info::
2449 - compare two historical versions of a directory, with rename info::
2450
2450
2451 hg diff --git -r 1.0:1.2 lib/
2451 hg diff --git -r 1.0:1.2 lib/
2452
2452
2453 - get change stats relative to the last change on some date::
2453 - get change stats relative to the last change on some date::
2454
2454
2455 hg diff --stat -r "date('may 2')"
2455 hg diff --stat -r "date('may 2')"
2456
2456
2457 - diff all newly-added files that contain a keyword::
2457 - diff all newly-added files that contain a keyword::
2458
2458
2459 hg diff "set:added() and grep(GNU)"
2459 hg diff "set:added() and grep(GNU)"
2460
2460
2461 - compare a revision and its parents::
2461 - compare a revision and its parents::
2462
2462
2463 hg diff -c 9353 # compare against first parent
2463 hg diff -c 9353 # compare against first parent
2464 hg diff -r 9353^:9353 # same using revset syntax
2464 hg diff -r 9353^:9353 # same using revset syntax
2465 hg diff -r 9353^2:9353 # compare against the second parent
2465 hg diff -r 9353^2:9353 # compare against the second parent
2466
2466
2467 Returns 0 on success.
2467 Returns 0 on success.
2468 """
2468 """
2469
2469
2470 opts = pycompat.byteskwargs(opts)
2470 opts = pycompat.byteskwargs(opts)
2471 revs = opts.get(b'rev')
2471 revs = opts.get(b'rev')
2472 change = opts.get(b'change')
2472 change = opts.get(b'change')
2473 stat = opts.get(b'stat')
2473 stat = opts.get(b'stat')
2474 reverse = opts.get(b'reverse')
2474 reverse = opts.get(b'reverse')
2475
2475
2476 if revs and change:
2476 if revs and change:
2477 msg = _(b'cannot specify --rev and --change at the same time')
2477 msg = _(b'cannot specify --rev and --change at the same time')
2478 raise error.Abort(msg)
2478 raise error.Abort(msg)
2479 elif change:
2479 elif change:
2480 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2480 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2481 ctx2 = scmutil.revsingle(repo, change, None)
2481 ctx2 = scmutil.revsingle(repo, change, None)
2482 ctx1 = ctx2.p1()
2482 ctx1 = ctx2.p1()
2483 else:
2483 else:
2484 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2484 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2485 ctx1, ctx2 = scmutil.revpair(repo, revs)
2485 ctx1, ctx2 = scmutil.revpair(repo, revs)
2486 node1, node2 = ctx1.node(), ctx2.node()
2486 node1, node2 = ctx1.node(), ctx2.node()
2487
2487
2488 if reverse:
2488 if reverse:
2489 node1, node2 = node2, node1
2489 node1, node2 = node2, node1
2490
2490
2491 diffopts = patch.diffallopts(ui, opts)
2491 diffopts = patch.diffallopts(ui, opts)
2492 m = scmutil.match(ctx2, pats, opts)
2492 m = scmutil.match(ctx2, pats, opts)
2493 m = repo.narrowmatch(m)
2493 m = repo.narrowmatch(m)
2494 ui.pager(b'diff')
2494 ui.pager(b'diff')
2495 logcmdutil.diffordiffstat(
2495 logcmdutil.diffordiffstat(
2496 ui,
2496 ui,
2497 repo,
2497 repo,
2498 diffopts,
2498 diffopts,
2499 node1,
2499 node1,
2500 node2,
2500 node2,
2501 m,
2501 m,
2502 stat=stat,
2502 stat=stat,
2503 listsubrepos=opts.get(b'subrepos'),
2503 listsubrepos=opts.get(b'subrepos'),
2504 root=opts.get(b'root'),
2504 root=opts.get(b'root'),
2505 )
2505 )
2506
2506
2507
2507
2508 @command(
2508 @command(
2509 b'export',
2509 b'export',
2510 [
2510 [
2511 (
2511 (
2512 b'B',
2512 b'B',
2513 b'bookmark',
2513 b'bookmark',
2514 b'',
2514 b'',
2515 _(b'export changes only reachable by given bookmark'),
2515 _(b'export changes only reachable by given bookmark'),
2516 _(b'BOOKMARK'),
2516 _(b'BOOKMARK'),
2517 ),
2517 ),
2518 (
2518 (
2519 b'o',
2519 b'o',
2520 b'output',
2520 b'output',
2521 b'',
2521 b'',
2522 _(b'print output to file with formatted name'),
2522 _(b'print output to file with formatted name'),
2523 _(b'FORMAT'),
2523 _(b'FORMAT'),
2524 ),
2524 ),
2525 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2525 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2526 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2526 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2527 ]
2527 ]
2528 + diffopts
2528 + diffopts
2529 + formatteropts,
2529 + formatteropts,
2530 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2530 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2531 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2531 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2532 helpbasic=True,
2532 helpbasic=True,
2533 intents={INTENT_READONLY},
2533 intents={INTENT_READONLY},
2534 )
2534 )
2535 def export(ui, repo, *changesets, **opts):
2535 def export(ui, repo, *changesets, **opts):
2536 """dump the header and diffs for one or more changesets
2536 """dump the header and diffs for one or more changesets
2537
2537
2538 Print the changeset header and diffs for one or more revisions.
2538 Print the changeset header and diffs for one or more revisions.
2539 If no revision is given, the parent of the working directory is used.
2539 If no revision is given, the parent of the working directory is used.
2540
2540
2541 The information shown in the changeset header is: author, date,
2541 The information shown in the changeset header is: author, date,
2542 branch name (if non-default), changeset hash, parent(s) and commit
2542 branch name (if non-default), changeset hash, parent(s) and commit
2543 comment.
2543 comment.
2544
2544
2545 .. note::
2545 .. note::
2546
2546
2547 :hg:`export` may generate unexpected diff output for merge
2547 :hg:`export` may generate unexpected diff output for merge
2548 changesets, as it will compare the merge changeset against its
2548 changesets, as it will compare the merge changeset against its
2549 first parent only.
2549 first parent only.
2550
2550
2551 Output may be to a file, in which case the name of the file is
2551 Output may be to a file, in which case the name of the file is
2552 given using a template string. See :hg:`help templates`. In addition
2552 given using a template string. See :hg:`help templates`. In addition
2553 to the common template keywords, the following formatting rules are
2553 to the common template keywords, the following formatting rules are
2554 supported:
2554 supported:
2555
2555
2556 :``%%``: literal "%" character
2556 :``%%``: literal "%" character
2557 :``%H``: changeset hash (40 hexadecimal digits)
2557 :``%H``: changeset hash (40 hexadecimal digits)
2558 :``%N``: number of patches being generated
2558 :``%N``: number of patches being generated
2559 :``%R``: changeset revision number
2559 :``%R``: changeset revision number
2560 :``%b``: basename of the exporting repository
2560 :``%b``: basename of the exporting repository
2561 :``%h``: short-form changeset hash (12 hexadecimal digits)
2561 :``%h``: short-form changeset hash (12 hexadecimal digits)
2562 :``%m``: first line of the commit message (only alphanumeric characters)
2562 :``%m``: first line of the commit message (only alphanumeric characters)
2563 :``%n``: zero-padded sequence number, starting at 1
2563 :``%n``: zero-padded sequence number, starting at 1
2564 :``%r``: zero-padded changeset revision number
2564 :``%r``: zero-padded changeset revision number
2565 :``\\``: literal "\\" character
2565 :``\\``: literal "\\" character
2566
2566
2567 Without the -a/--text option, export will avoid generating diffs
2567 Without the -a/--text option, export will avoid generating diffs
2568 of files it detects as binary. With -a, export will generate a
2568 of files it detects as binary. With -a, export will generate a
2569 diff anyway, probably with undesirable results.
2569 diff anyway, probably with undesirable results.
2570
2570
2571 With -B/--bookmark changesets reachable by the given bookmark are
2571 With -B/--bookmark changesets reachable by the given bookmark are
2572 selected.
2572 selected.
2573
2573
2574 Use the -g/--git option to generate diffs in the git extended diff
2574 Use the -g/--git option to generate diffs in the git extended diff
2575 format. See :hg:`help diffs` for more information.
2575 format. See :hg:`help diffs` for more information.
2576
2576
2577 With the --switch-parent option, the diff will be against the
2577 With the --switch-parent option, the diff will be against the
2578 second parent. It can be useful to review a merge.
2578 second parent. It can be useful to review a merge.
2579
2579
2580 .. container:: verbose
2580 .. container:: verbose
2581
2581
2582 Template:
2582 Template:
2583
2583
2584 The following keywords are supported in addition to the common template
2584 The following keywords are supported in addition to the common template
2585 keywords and functions. See also :hg:`help templates`.
2585 keywords and functions. See also :hg:`help templates`.
2586
2586
2587 :diff: String. Diff content.
2587 :diff: String. Diff content.
2588 :parents: List of strings. Parent nodes of the changeset.
2588 :parents: List of strings. Parent nodes of the changeset.
2589
2589
2590 Examples:
2590 Examples:
2591
2591
2592 - use export and import to transplant a bugfix to the current
2592 - use export and import to transplant a bugfix to the current
2593 branch::
2593 branch::
2594
2594
2595 hg export -r 9353 | hg import -
2595 hg export -r 9353 | hg import -
2596
2596
2597 - export all the changesets between two revisions to a file with
2597 - export all the changesets between two revisions to a file with
2598 rename information::
2598 rename information::
2599
2599
2600 hg export --git -r 123:150 > changes.txt
2600 hg export --git -r 123:150 > changes.txt
2601
2601
2602 - split outgoing changes into a series of patches with
2602 - split outgoing changes into a series of patches with
2603 descriptive names::
2603 descriptive names::
2604
2604
2605 hg export -r "outgoing()" -o "%n-%m.patch"
2605 hg export -r "outgoing()" -o "%n-%m.patch"
2606
2606
2607 Returns 0 on success.
2607 Returns 0 on success.
2608 """
2608 """
2609 opts = pycompat.byteskwargs(opts)
2609 opts = pycompat.byteskwargs(opts)
2610 bookmark = opts.get(b'bookmark')
2610 bookmark = opts.get(b'bookmark')
2611 changesets += tuple(opts.get(b'rev', []))
2611 changesets += tuple(opts.get(b'rev', []))
2612
2612
2613 if bookmark and changesets:
2613 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2614 raise error.Abort(_(b"-r and -B are mutually exclusive"))
2615
2614
2616 if bookmark:
2615 if bookmark:
2617 if bookmark not in repo._bookmarks:
2616 if bookmark not in repo._bookmarks:
2618 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2617 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2619
2618
2620 revs = scmutil.bookmarkrevs(repo, bookmark)
2619 revs = scmutil.bookmarkrevs(repo, bookmark)
2621 else:
2620 else:
2622 if not changesets:
2621 if not changesets:
2623 changesets = [b'.']
2622 changesets = [b'.']
2624
2623
2625 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2624 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2626 revs = scmutil.revrange(repo, changesets)
2625 revs = scmutil.revrange(repo, changesets)
2627
2626
2628 if not revs:
2627 if not revs:
2629 raise error.Abort(_(b"export requires at least one changeset"))
2628 raise error.Abort(_(b"export requires at least one changeset"))
2630 if len(revs) > 1:
2629 if len(revs) > 1:
2631 ui.note(_(b'exporting patches:\n'))
2630 ui.note(_(b'exporting patches:\n'))
2632 else:
2631 else:
2633 ui.note(_(b'exporting patch:\n'))
2632 ui.note(_(b'exporting patch:\n'))
2634
2633
2635 fntemplate = opts.get(b'output')
2634 fntemplate = opts.get(b'output')
2636 if cmdutil.isstdiofilename(fntemplate):
2635 if cmdutil.isstdiofilename(fntemplate):
2637 fntemplate = b''
2636 fntemplate = b''
2638
2637
2639 if fntemplate:
2638 if fntemplate:
2640 fm = formatter.nullformatter(ui, b'export', opts)
2639 fm = formatter.nullformatter(ui, b'export', opts)
2641 else:
2640 else:
2642 ui.pager(b'export')
2641 ui.pager(b'export')
2643 fm = ui.formatter(b'export', opts)
2642 fm = ui.formatter(b'export', opts)
2644 with fm:
2643 with fm:
2645 cmdutil.export(
2644 cmdutil.export(
2646 repo,
2645 repo,
2647 revs,
2646 revs,
2648 fm,
2647 fm,
2649 fntemplate=fntemplate,
2648 fntemplate=fntemplate,
2650 switch_parent=opts.get(b'switch_parent'),
2649 switch_parent=opts.get(b'switch_parent'),
2651 opts=patch.diffallopts(ui, opts),
2650 opts=patch.diffallopts(ui, opts),
2652 )
2651 )
2653
2652
2654
2653
2655 @command(
2654 @command(
2656 b'files',
2655 b'files',
2657 [
2656 [
2658 (
2657 (
2659 b'r',
2658 b'r',
2660 b'rev',
2659 b'rev',
2661 b'',
2660 b'',
2662 _(b'search the repository as it is in REV'),
2661 _(b'search the repository as it is in REV'),
2663 _(b'REV'),
2662 _(b'REV'),
2664 ),
2663 ),
2665 (
2664 (
2666 b'0',
2665 b'0',
2667 b'print0',
2666 b'print0',
2668 None,
2667 None,
2669 _(b'end filenames with NUL, for use with xargs'),
2668 _(b'end filenames with NUL, for use with xargs'),
2670 ),
2669 ),
2671 ]
2670 ]
2672 + walkopts
2671 + walkopts
2673 + formatteropts
2672 + formatteropts
2674 + subrepoopts,
2673 + subrepoopts,
2675 _(b'[OPTION]... [FILE]...'),
2674 _(b'[OPTION]... [FILE]...'),
2676 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2675 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2677 intents={INTENT_READONLY},
2676 intents={INTENT_READONLY},
2678 )
2677 )
2679 def files(ui, repo, *pats, **opts):
2678 def files(ui, repo, *pats, **opts):
2680 """list tracked files
2679 """list tracked files
2681
2680
2682 Print files under Mercurial control in the working directory or
2681 Print files under Mercurial control in the working directory or
2683 specified revision for given files (excluding removed files).
2682 specified revision for given files (excluding removed files).
2684 Files can be specified as filenames or filesets.
2683 Files can be specified as filenames or filesets.
2685
2684
2686 If no files are given to match, this command prints the names
2685 If no files are given to match, this command prints the names
2687 of all files under Mercurial control.
2686 of all files under Mercurial control.
2688
2687
2689 .. container:: verbose
2688 .. container:: verbose
2690
2689
2691 Template:
2690 Template:
2692
2691
2693 The following keywords are supported in addition to the common template
2692 The following keywords are supported in addition to the common template
2694 keywords and functions. See also :hg:`help templates`.
2693 keywords and functions. See also :hg:`help templates`.
2695
2694
2696 :flags: String. Character denoting file's symlink and executable bits.
2695 :flags: String. Character denoting file's symlink and executable bits.
2697 :path: String. Repository-absolute path of the file.
2696 :path: String. Repository-absolute path of the file.
2698 :size: Integer. Size of the file in bytes.
2697 :size: Integer. Size of the file in bytes.
2699
2698
2700 Examples:
2699 Examples:
2701
2700
2702 - list all files under the current directory::
2701 - list all files under the current directory::
2703
2702
2704 hg files .
2703 hg files .
2705
2704
2706 - shows sizes and flags for current revision::
2705 - shows sizes and flags for current revision::
2707
2706
2708 hg files -vr .
2707 hg files -vr .
2709
2708
2710 - list all files named README::
2709 - list all files named README::
2711
2710
2712 hg files -I "**/README"
2711 hg files -I "**/README"
2713
2712
2714 - list all binary files::
2713 - list all binary files::
2715
2714
2716 hg files "set:binary()"
2715 hg files "set:binary()"
2717
2716
2718 - find files containing a regular expression::
2717 - find files containing a regular expression::
2719
2718
2720 hg files "set:grep('bob')"
2719 hg files "set:grep('bob')"
2721
2720
2722 - search tracked file contents with xargs and grep::
2721 - search tracked file contents with xargs and grep::
2723
2722
2724 hg files -0 | xargs -0 grep foo
2723 hg files -0 | xargs -0 grep foo
2725
2724
2726 See :hg:`help patterns` and :hg:`help filesets` for more information
2725 See :hg:`help patterns` and :hg:`help filesets` for more information
2727 on specifying file patterns.
2726 on specifying file patterns.
2728
2727
2729 Returns 0 if a match is found, 1 otherwise.
2728 Returns 0 if a match is found, 1 otherwise.
2730
2729
2731 """
2730 """
2732
2731
2733 opts = pycompat.byteskwargs(opts)
2732 opts = pycompat.byteskwargs(opts)
2734 rev = opts.get(b'rev')
2733 rev = opts.get(b'rev')
2735 if rev:
2734 if rev:
2736 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2735 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2737 ctx = scmutil.revsingle(repo, rev, None)
2736 ctx = scmutil.revsingle(repo, rev, None)
2738
2737
2739 end = b'\n'
2738 end = b'\n'
2740 if opts.get(b'print0'):
2739 if opts.get(b'print0'):
2741 end = b'\0'
2740 end = b'\0'
2742 fmt = b'%s' + end
2741 fmt = b'%s' + end
2743
2742
2744 m = scmutil.match(ctx, pats, opts)
2743 m = scmutil.match(ctx, pats, opts)
2745 ui.pager(b'files')
2744 ui.pager(b'files')
2746 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2745 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2747 with ui.formatter(b'files', opts) as fm:
2746 with ui.formatter(b'files', opts) as fm:
2748 return cmdutil.files(
2747 return cmdutil.files(
2749 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2748 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2750 )
2749 )
2751
2750
2752
2751
2753 @command(
2752 @command(
2754 b'forget',
2753 b'forget',
2755 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2754 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2756 + walkopts
2755 + walkopts
2757 + dryrunopts,
2756 + dryrunopts,
2758 _(b'[OPTION]... FILE...'),
2757 _(b'[OPTION]... FILE...'),
2759 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2758 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2760 helpbasic=True,
2759 helpbasic=True,
2761 inferrepo=True,
2760 inferrepo=True,
2762 )
2761 )
2763 def forget(ui, repo, *pats, **opts):
2762 def forget(ui, repo, *pats, **opts):
2764 """forget the specified files on the next commit
2763 """forget the specified files on the next commit
2765
2764
2766 Mark the specified files so they will no longer be tracked
2765 Mark the specified files so they will no longer be tracked
2767 after the next commit.
2766 after the next commit.
2768
2767
2769 This only removes files from the current branch, not from the
2768 This only removes files from the current branch, not from the
2770 entire project history, and it does not delete them from the
2769 entire project history, and it does not delete them from the
2771 working directory.
2770 working directory.
2772
2771
2773 To delete the file from the working directory, see :hg:`remove`.
2772 To delete the file from the working directory, see :hg:`remove`.
2774
2773
2775 To undo a forget before the next commit, see :hg:`add`.
2774 To undo a forget before the next commit, see :hg:`add`.
2776
2775
2777 .. container:: verbose
2776 .. container:: verbose
2778
2777
2779 Examples:
2778 Examples:
2780
2779
2781 - forget newly-added binary files::
2780 - forget newly-added binary files::
2782
2781
2783 hg forget "set:added() and binary()"
2782 hg forget "set:added() and binary()"
2784
2783
2785 - forget files that would be excluded by .hgignore::
2784 - forget files that would be excluded by .hgignore::
2786
2785
2787 hg forget "set:hgignore()"
2786 hg forget "set:hgignore()"
2788
2787
2789 Returns 0 on success.
2788 Returns 0 on success.
2790 """
2789 """
2791
2790
2792 opts = pycompat.byteskwargs(opts)
2791 opts = pycompat.byteskwargs(opts)
2793 if not pats:
2792 if not pats:
2794 raise error.Abort(_(b'no files specified'))
2793 raise error.Abort(_(b'no files specified'))
2795
2794
2796 m = scmutil.match(repo[None], pats, opts)
2795 m = scmutil.match(repo[None], pats, opts)
2797 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2796 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2798 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2797 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2799 rejected = cmdutil.forget(
2798 rejected = cmdutil.forget(
2800 ui,
2799 ui,
2801 repo,
2800 repo,
2802 m,
2801 m,
2803 prefix=b"",
2802 prefix=b"",
2804 uipathfn=uipathfn,
2803 uipathfn=uipathfn,
2805 explicitonly=False,
2804 explicitonly=False,
2806 dryrun=dryrun,
2805 dryrun=dryrun,
2807 interactive=interactive,
2806 interactive=interactive,
2808 )[0]
2807 )[0]
2809 return rejected and 1 or 0
2808 return rejected and 1 or 0
2810
2809
2811
2810
2812 @command(
2811 @command(
2813 b'graft',
2812 b'graft',
2814 [
2813 [
2815 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2814 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2816 (
2815 (
2817 b'',
2816 b'',
2818 b'base',
2817 b'base',
2819 b'',
2818 b'',
2820 _(b'base revision when doing the graft merge (ADVANCED)'),
2819 _(b'base revision when doing the graft merge (ADVANCED)'),
2821 _(b'REV'),
2820 _(b'REV'),
2822 ),
2821 ),
2823 (b'c', b'continue', False, _(b'resume interrupted graft')),
2822 (b'c', b'continue', False, _(b'resume interrupted graft')),
2824 (b'', b'stop', False, _(b'stop interrupted graft')),
2823 (b'', b'stop', False, _(b'stop interrupted graft')),
2825 (b'', b'abort', False, _(b'abort interrupted graft')),
2824 (b'', b'abort', False, _(b'abort interrupted graft')),
2826 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2825 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2827 (b'', b'log', None, _(b'append graft info to log message')),
2826 (b'', b'log', None, _(b'append graft info to log message')),
2828 (
2827 (
2829 b'',
2828 b'',
2830 b'no-commit',
2829 b'no-commit',
2831 None,
2830 None,
2832 _(b"don't commit, just apply the changes in working directory"),
2831 _(b"don't commit, just apply the changes in working directory"),
2833 ),
2832 ),
2834 (b'f', b'force', False, _(b'force graft')),
2833 (b'f', b'force', False, _(b'force graft')),
2835 (
2834 (
2836 b'D',
2835 b'D',
2837 b'currentdate',
2836 b'currentdate',
2838 False,
2837 False,
2839 _(b'record the current date as commit date'),
2838 _(b'record the current date as commit date'),
2840 ),
2839 ),
2841 (
2840 (
2842 b'U',
2841 b'U',
2843 b'currentuser',
2842 b'currentuser',
2844 False,
2843 False,
2845 _(b'record the current user as committer'),
2844 _(b'record the current user as committer'),
2846 ),
2845 ),
2847 ]
2846 ]
2848 + commitopts2
2847 + commitopts2
2849 + mergetoolopts
2848 + mergetoolopts
2850 + dryrunopts,
2849 + dryrunopts,
2851 _(b'[OPTION]... [-r REV]... REV...'),
2850 _(b'[OPTION]... [-r REV]... REV...'),
2852 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2851 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2853 )
2852 )
2854 def graft(ui, repo, *revs, **opts):
2853 def graft(ui, repo, *revs, **opts):
2855 '''copy changes from other branches onto the current branch
2854 '''copy changes from other branches onto the current branch
2856
2855
2857 This command uses Mercurial's merge logic to copy individual
2856 This command uses Mercurial's merge logic to copy individual
2858 changes from other branches without merging branches in the
2857 changes from other branches without merging branches in the
2859 history graph. This is sometimes known as 'backporting' or
2858 history graph. This is sometimes known as 'backporting' or
2860 'cherry-picking'. By default, graft will copy user, date, and
2859 'cherry-picking'. By default, graft will copy user, date, and
2861 description from the source changesets.
2860 description from the source changesets.
2862
2861
2863 Changesets that are ancestors of the current revision, that have
2862 Changesets that are ancestors of the current revision, that have
2864 already been grafted, or that are merges will be skipped.
2863 already been grafted, or that are merges will be skipped.
2865
2864
2866 If --log is specified, log messages will have a comment appended
2865 If --log is specified, log messages will have a comment appended
2867 of the form::
2866 of the form::
2868
2867
2869 (grafted from CHANGESETHASH)
2868 (grafted from CHANGESETHASH)
2870
2869
2871 If --force is specified, revisions will be grafted even if they
2870 If --force is specified, revisions will be grafted even if they
2872 are already ancestors of, or have been grafted to, the destination.
2871 are already ancestors of, or have been grafted to, the destination.
2873 This is useful when the revisions have since been backed out.
2872 This is useful when the revisions have since been backed out.
2874
2873
2875 If a graft merge results in conflicts, the graft process is
2874 If a graft merge results in conflicts, the graft process is
2876 interrupted so that the current merge can be manually resolved.
2875 interrupted so that the current merge can be manually resolved.
2877 Once all conflicts are addressed, the graft process can be
2876 Once all conflicts are addressed, the graft process can be
2878 continued with the -c/--continue option.
2877 continued with the -c/--continue option.
2879
2878
2880 The -c/--continue option reapplies all the earlier options.
2879 The -c/--continue option reapplies all the earlier options.
2881
2880
2882 .. container:: verbose
2881 .. container:: verbose
2883
2882
2884 The --base option exposes more of how graft internally uses merge with a
2883 The --base option exposes more of how graft internally uses merge with a
2885 custom base revision. --base can be used to specify another ancestor than
2884 custom base revision. --base can be used to specify another ancestor than
2886 the first and only parent.
2885 the first and only parent.
2887
2886
2888 The command::
2887 The command::
2889
2888
2890 hg graft -r 345 --base 234
2889 hg graft -r 345 --base 234
2891
2890
2892 is thus pretty much the same as::
2891 is thus pretty much the same as::
2893
2892
2894 hg diff -r 234 -r 345 | hg import
2893 hg diff -r 234 -r 345 | hg import
2895
2894
2896 but using merge to resolve conflicts and track moved files.
2895 but using merge to resolve conflicts and track moved files.
2897
2896
2898 The result of a merge can thus be backported as a single commit by
2897 The result of a merge can thus be backported as a single commit by
2899 specifying one of the merge parents as base, and thus effectively
2898 specifying one of the merge parents as base, and thus effectively
2900 grafting the changes from the other side.
2899 grafting the changes from the other side.
2901
2900
2902 It is also possible to collapse multiple changesets and clean up history
2901 It is also possible to collapse multiple changesets and clean up history
2903 by specifying another ancestor as base, much like rebase --collapse
2902 by specifying another ancestor as base, much like rebase --collapse
2904 --keep.
2903 --keep.
2905
2904
2906 The commit message can be tweaked after the fact using commit --amend .
2905 The commit message can be tweaked after the fact using commit --amend .
2907
2906
2908 For using non-ancestors as the base to backout changes, see the backout
2907 For using non-ancestors as the base to backout changes, see the backout
2909 command and the hidden --parent option.
2908 command and the hidden --parent option.
2910
2909
2911 .. container:: verbose
2910 .. container:: verbose
2912
2911
2913 Examples:
2912 Examples:
2914
2913
2915 - copy a single change to the stable branch and edit its description::
2914 - copy a single change to the stable branch and edit its description::
2916
2915
2917 hg update stable
2916 hg update stable
2918 hg graft --edit 9393
2917 hg graft --edit 9393
2919
2918
2920 - graft a range of changesets with one exception, updating dates::
2919 - graft a range of changesets with one exception, updating dates::
2921
2920
2922 hg graft -D "2085::2093 and not 2091"
2921 hg graft -D "2085::2093 and not 2091"
2923
2922
2924 - continue a graft after resolving conflicts::
2923 - continue a graft after resolving conflicts::
2925
2924
2926 hg graft -c
2925 hg graft -c
2927
2926
2928 - show the source of a grafted changeset::
2927 - show the source of a grafted changeset::
2929
2928
2930 hg log --debug -r .
2929 hg log --debug -r .
2931
2930
2932 - show revisions sorted by date::
2931 - show revisions sorted by date::
2933
2932
2934 hg log -r "sort(all(), date)"
2933 hg log -r "sort(all(), date)"
2935
2934
2936 - backport the result of a merge as a single commit::
2935 - backport the result of a merge as a single commit::
2937
2936
2938 hg graft -r 123 --base 123^
2937 hg graft -r 123 --base 123^
2939
2938
2940 - land a feature branch as one changeset::
2939 - land a feature branch as one changeset::
2941
2940
2942 hg up -cr default
2941 hg up -cr default
2943 hg graft -r featureX --base "ancestor('featureX', 'default')"
2942 hg graft -r featureX --base "ancestor('featureX', 'default')"
2944
2943
2945 See :hg:`help revisions` for more about specifying revisions.
2944 See :hg:`help revisions` for more about specifying revisions.
2946
2945
2947 Returns 0 on successful completion.
2946 Returns 0 on successful completion.
2948 '''
2947 '''
2949 with repo.wlock():
2948 with repo.wlock():
2950 return _dograft(ui, repo, *revs, **opts)
2949 return _dograft(ui, repo, *revs, **opts)
2951
2950
2952
2951
2953 def _dograft(ui, repo, *revs, **opts):
2952 def _dograft(ui, repo, *revs, **opts):
2954 opts = pycompat.byteskwargs(opts)
2953 opts = pycompat.byteskwargs(opts)
2955 if revs and opts.get(b'rev'):
2954 if revs and opts.get(b'rev'):
2956 ui.warn(
2955 ui.warn(
2957 _(
2956 _(
2958 b'warning: inconsistent use of --rev might give unexpected '
2957 b'warning: inconsistent use of --rev might give unexpected '
2959 b'revision ordering!\n'
2958 b'revision ordering!\n'
2960 )
2959 )
2961 )
2960 )
2962
2961
2963 revs = list(revs)
2962 revs = list(revs)
2964 revs.extend(opts.get(b'rev'))
2963 revs.extend(opts.get(b'rev'))
2965 basectx = None
2964 basectx = None
2966 if opts.get(b'base'):
2965 if opts.get(b'base'):
2967 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2966 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2968 # a dict of data to be stored in state file
2967 # a dict of data to be stored in state file
2969 statedata = {}
2968 statedata = {}
2970 # list of new nodes created by ongoing graft
2969 # list of new nodes created by ongoing graft
2971 statedata[b'newnodes'] = []
2970 statedata[b'newnodes'] = []
2972
2971
2973 cmdutil.resolvecommitoptions(ui, opts)
2972 cmdutil.resolvecommitoptions(ui, opts)
2974
2973
2975 editor = cmdutil.getcommiteditor(
2974 editor = cmdutil.getcommiteditor(
2976 editform=b'graft', **pycompat.strkwargs(opts)
2975 editform=b'graft', **pycompat.strkwargs(opts)
2977 )
2976 )
2978
2977
2979 cont = False
2978 cont = False
2980 if opts.get(b'no_commit'):
2979 if opts.get(b'no_commit'):
2981 if opts.get(b'edit'):
2980 if opts.get(b'edit'):
2982 raise error.Abort(
2981 raise error.Abort(
2983 _(b"cannot specify --no-commit and --edit together")
2982 _(b"cannot specify --no-commit and --edit together")
2984 )
2983 )
2985 if opts.get(b'currentuser'):
2984 if opts.get(b'currentuser'):
2986 raise error.Abort(
2985 raise error.Abort(
2987 _(b"cannot specify --no-commit and --currentuser together")
2986 _(b"cannot specify --no-commit and --currentuser together")
2988 )
2987 )
2989 if opts.get(b'currentdate'):
2988 if opts.get(b'currentdate'):
2990 raise error.Abort(
2989 raise error.Abort(
2991 _(b"cannot specify --no-commit and --currentdate together")
2990 _(b"cannot specify --no-commit and --currentdate together")
2992 )
2991 )
2993 if opts.get(b'log'):
2992 if opts.get(b'log'):
2994 raise error.Abort(
2993 raise error.Abort(
2995 _(b"cannot specify --no-commit and --log together")
2994 _(b"cannot specify --no-commit and --log together")
2996 )
2995 )
2997
2996
2998 graftstate = statemod.cmdstate(repo, b'graftstate')
2997 graftstate = statemod.cmdstate(repo, b'graftstate')
2999
2998
3000 if opts.get(b'stop'):
2999 if opts.get(b'stop'):
3001 if opts.get(b'continue'):
3000 if opts.get(b'continue'):
3002 raise error.Abort(
3001 raise error.Abort(
3003 _(b"cannot use '--continue' and '--stop' together")
3002 _(b"cannot use '--continue' and '--stop' together")
3004 )
3003 )
3005 if opts.get(b'abort'):
3004 if opts.get(b'abort'):
3006 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3005 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3007
3006
3008 if any(
3007 if any(
3009 (
3008 (
3010 opts.get(b'edit'),
3009 opts.get(b'edit'),
3011 opts.get(b'log'),
3010 opts.get(b'log'),
3012 opts.get(b'user'),
3011 opts.get(b'user'),
3013 opts.get(b'date'),
3012 opts.get(b'date'),
3014 opts.get(b'currentdate'),
3013 opts.get(b'currentdate'),
3015 opts.get(b'currentuser'),
3014 opts.get(b'currentuser'),
3016 opts.get(b'rev'),
3015 opts.get(b'rev'),
3017 )
3016 )
3018 ):
3017 ):
3019 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3018 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3020 return _stopgraft(ui, repo, graftstate)
3019 return _stopgraft(ui, repo, graftstate)
3021 elif opts.get(b'abort'):
3020 elif opts.get(b'abort'):
3022 if opts.get(b'continue'):
3021 if opts.get(b'continue'):
3023 raise error.Abort(
3022 raise error.Abort(
3024 _(b"cannot use '--continue' and '--abort' together")
3023 _(b"cannot use '--continue' and '--abort' together")
3025 )
3024 )
3026 if any(
3025 if any(
3027 (
3026 (
3028 opts.get(b'edit'),
3027 opts.get(b'edit'),
3029 opts.get(b'log'),
3028 opts.get(b'log'),
3030 opts.get(b'user'),
3029 opts.get(b'user'),
3031 opts.get(b'date'),
3030 opts.get(b'date'),
3032 opts.get(b'currentdate'),
3031 opts.get(b'currentdate'),
3033 opts.get(b'currentuser'),
3032 opts.get(b'currentuser'),
3034 opts.get(b'rev'),
3033 opts.get(b'rev'),
3035 )
3034 )
3036 ):
3035 ):
3037 raise error.Abort(
3036 raise error.Abort(
3038 _(b"cannot specify any other flag with '--abort'")
3037 _(b"cannot specify any other flag with '--abort'")
3039 )
3038 )
3040
3039
3041 return cmdutil.abortgraft(ui, repo, graftstate)
3040 return cmdutil.abortgraft(ui, repo, graftstate)
3042 elif opts.get(b'continue'):
3041 elif opts.get(b'continue'):
3043 cont = True
3042 cont = True
3044 if revs:
3043 if revs:
3045 raise error.Abort(_(b"can't specify --continue and revisions"))
3044 raise error.Abort(_(b"can't specify --continue and revisions"))
3046 # read in unfinished revisions
3045 # read in unfinished revisions
3047 if graftstate.exists():
3046 if graftstate.exists():
3048 statedata = cmdutil.readgraftstate(repo, graftstate)
3047 statedata = cmdutil.readgraftstate(repo, graftstate)
3049 if statedata.get(b'date'):
3048 if statedata.get(b'date'):
3050 opts[b'date'] = statedata[b'date']
3049 opts[b'date'] = statedata[b'date']
3051 if statedata.get(b'user'):
3050 if statedata.get(b'user'):
3052 opts[b'user'] = statedata[b'user']
3051 opts[b'user'] = statedata[b'user']
3053 if statedata.get(b'log'):
3052 if statedata.get(b'log'):
3054 opts[b'log'] = True
3053 opts[b'log'] = True
3055 if statedata.get(b'no_commit'):
3054 if statedata.get(b'no_commit'):
3056 opts[b'no_commit'] = statedata.get(b'no_commit')
3055 opts[b'no_commit'] = statedata.get(b'no_commit')
3057 nodes = statedata[b'nodes']
3056 nodes = statedata[b'nodes']
3058 revs = [repo[node].rev() for node in nodes]
3057 revs = [repo[node].rev() for node in nodes]
3059 else:
3058 else:
3060 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3059 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3061 else:
3060 else:
3062 if not revs:
3061 if not revs:
3063 raise error.Abort(_(b'no revisions specified'))
3062 raise error.Abort(_(b'no revisions specified'))
3064 cmdutil.checkunfinished(repo)
3063 cmdutil.checkunfinished(repo)
3065 cmdutil.bailifchanged(repo)
3064 cmdutil.bailifchanged(repo)
3066 revs = scmutil.revrange(repo, revs)
3065 revs = scmutil.revrange(repo, revs)
3067
3066
3068 skipped = set()
3067 skipped = set()
3069 if basectx is None:
3068 if basectx is None:
3070 # check for merges
3069 # check for merges
3071 for rev in repo.revs(b'%ld and merge()', revs):
3070 for rev in repo.revs(b'%ld and merge()', revs):
3072 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3071 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3073 skipped.add(rev)
3072 skipped.add(rev)
3074 revs = [r for r in revs if r not in skipped]
3073 revs = [r for r in revs if r not in skipped]
3075 if not revs:
3074 if not revs:
3076 return -1
3075 return -1
3077 if basectx is not None and len(revs) != 1:
3076 if basectx is not None and len(revs) != 1:
3078 raise error.Abort(_(b'only one revision allowed with --base '))
3077 raise error.Abort(_(b'only one revision allowed with --base '))
3079
3078
3080 # Don't check in the --continue case, in effect retaining --force across
3079 # Don't check in the --continue case, in effect retaining --force across
3081 # --continues. That's because without --force, any revisions we decided to
3080 # --continues. That's because without --force, any revisions we decided to
3082 # skip would have been filtered out here, so they wouldn't have made their
3081 # skip would have been filtered out here, so they wouldn't have made their
3083 # way to the graftstate. With --force, any revisions we would have otherwise
3082 # way to the graftstate. With --force, any revisions we would have otherwise
3084 # skipped would not have been filtered out, and if they hadn't been applied
3083 # skipped would not have been filtered out, and if they hadn't been applied
3085 # already, they'd have been in the graftstate.
3084 # already, they'd have been in the graftstate.
3086 if not (cont or opts.get(b'force')) and basectx is None:
3085 if not (cont or opts.get(b'force')) and basectx is None:
3087 # check for ancestors of dest branch
3086 # check for ancestors of dest branch
3088 crev = repo[b'.'].rev()
3087 crev = repo[b'.'].rev()
3089 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3088 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3090 # XXX make this lazy in the future
3089 # XXX make this lazy in the future
3091 # don't mutate while iterating, create a copy
3090 # don't mutate while iterating, create a copy
3092 for rev in list(revs):
3091 for rev in list(revs):
3093 if rev in ancestors:
3092 if rev in ancestors:
3094 ui.warn(
3093 ui.warn(
3095 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3094 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3096 )
3095 )
3097 # XXX remove on list is slow
3096 # XXX remove on list is slow
3098 revs.remove(rev)
3097 revs.remove(rev)
3099 if not revs:
3098 if not revs:
3100 return -1
3099 return -1
3101
3100
3102 # analyze revs for earlier grafts
3101 # analyze revs for earlier grafts
3103 ids = {}
3102 ids = {}
3104 for ctx in repo.set(b"%ld", revs):
3103 for ctx in repo.set(b"%ld", revs):
3105 ids[ctx.hex()] = ctx.rev()
3104 ids[ctx.hex()] = ctx.rev()
3106 n = ctx.extra().get(b'source')
3105 n = ctx.extra().get(b'source')
3107 if n:
3106 if n:
3108 ids[n] = ctx.rev()
3107 ids[n] = ctx.rev()
3109
3108
3110 # check ancestors for earlier grafts
3109 # check ancestors for earlier grafts
3111 ui.debug(b'scanning for duplicate grafts\n')
3110 ui.debug(b'scanning for duplicate grafts\n')
3112
3111
3113 # The only changesets we can be sure doesn't contain grafts of any
3112 # The only changesets we can be sure doesn't contain grafts of any
3114 # revs, are the ones that are common ancestors of *all* revs:
3113 # revs, are the ones that are common ancestors of *all* revs:
3115 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3114 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3116 ctx = repo[rev]
3115 ctx = repo[rev]
3117 n = ctx.extra().get(b'source')
3116 n = ctx.extra().get(b'source')
3118 if n in ids:
3117 if n in ids:
3119 try:
3118 try:
3120 r = repo[n].rev()
3119 r = repo[n].rev()
3121 except error.RepoLookupError:
3120 except error.RepoLookupError:
3122 r = None
3121 r = None
3123 if r in revs:
3122 if r in revs:
3124 ui.warn(
3123 ui.warn(
3125 _(
3124 _(
3126 b'skipping revision %d:%s '
3125 b'skipping revision %d:%s '
3127 b'(already grafted to %d:%s)\n'
3126 b'(already grafted to %d:%s)\n'
3128 )
3127 )
3129 % (r, repo[r], rev, ctx)
3128 % (r, repo[r], rev, ctx)
3130 )
3129 )
3131 revs.remove(r)
3130 revs.remove(r)
3132 elif ids[n] in revs:
3131 elif ids[n] in revs:
3133 if r is None:
3132 if r is None:
3134 ui.warn(
3133 ui.warn(
3135 _(
3134 _(
3136 b'skipping already grafted revision %d:%s '
3135 b'skipping already grafted revision %d:%s '
3137 b'(%d:%s also has unknown origin %s)\n'
3136 b'(%d:%s also has unknown origin %s)\n'
3138 )
3137 )
3139 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3138 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3140 )
3139 )
3141 else:
3140 else:
3142 ui.warn(
3141 ui.warn(
3143 _(
3142 _(
3144 b'skipping already grafted revision %d:%s '
3143 b'skipping already grafted revision %d:%s '
3145 b'(%d:%s also has origin %d:%s)\n'
3144 b'(%d:%s also has origin %d:%s)\n'
3146 )
3145 )
3147 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3146 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3148 )
3147 )
3149 revs.remove(ids[n])
3148 revs.remove(ids[n])
3150 elif ctx.hex() in ids:
3149 elif ctx.hex() in ids:
3151 r = ids[ctx.hex()]
3150 r = ids[ctx.hex()]
3152 if r in revs:
3151 if r in revs:
3153 ui.warn(
3152 ui.warn(
3154 _(
3153 _(
3155 b'skipping already grafted revision %d:%s '
3154 b'skipping already grafted revision %d:%s '
3156 b'(was grafted from %d:%s)\n'
3155 b'(was grafted from %d:%s)\n'
3157 )
3156 )
3158 % (r, repo[r], rev, ctx)
3157 % (r, repo[r], rev, ctx)
3159 )
3158 )
3160 revs.remove(r)
3159 revs.remove(r)
3161 if not revs:
3160 if not revs:
3162 return -1
3161 return -1
3163
3162
3164 if opts.get(b'no_commit'):
3163 if opts.get(b'no_commit'):
3165 statedata[b'no_commit'] = True
3164 statedata[b'no_commit'] = True
3166 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3165 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3167 desc = b'%d:%s "%s"' % (
3166 desc = b'%d:%s "%s"' % (
3168 ctx.rev(),
3167 ctx.rev(),
3169 ctx,
3168 ctx,
3170 ctx.description().split(b'\n', 1)[0],
3169 ctx.description().split(b'\n', 1)[0],
3171 )
3170 )
3172 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3171 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3173 if names:
3172 if names:
3174 desc += b' (%s)' % b' '.join(names)
3173 desc += b' (%s)' % b' '.join(names)
3175 ui.status(_(b'grafting %s\n') % desc)
3174 ui.status(_(b'grafting %s\n') % desc)
3176 if opts.get(b'dry_run'):
3175 if opts.get(b'dry_run'):
3177 continue
3176 continue
3178
3177
3179 source = ctx.extra().get(b'source')
3178 source = ctx.extra().get(b'source')
3180 extra = {}
3179 extra = {}
3181 if source:
3180 if source:
3182 extra[b'source'] = source
3181 extra[b'source'] = source
3183 extra[b'intermediate-source'] = ctx.hex()
3182 extra[b'intermediate-source'] = ctx.hex()
3184 else:
3183 else:
3185 extra[b'source'] = ctx.hex()
3184 extra[b'source'] = ctx.hex()
3186 user = ctx.user()
3185 user = ctx.user()
3187 if opts.get(b'user'):
3186 if opts.get(b'user'):
3188 user = opts[b'user']
3187 user = opts[b'user']
3189 statedata[b'user'] = user
3188 statedata[b'user'] = user
3190 date = ctx.date()
3189 date = ctx.date()
3191 if opts.get(b'date'):
3190 if opts.get(b'date'):
3192 date = opts[b'date']
3191 date = opts[b'date']
3193 statedata[b'date'] = date
3192 statedata[b'date'] = date
3194 message = ctx.description()
3193 message = ctx.description()
3195 if opts.get(b'log'):
3194 if opts.get(b'log'):
3196 message += b'\n(grafted from %s)' % ctx.hex()
3195 message += b'\n(grafted from %s)' % ctx.hex()
3197 statedata[b'log'] = True
3196 statedata[b'log'] = True
3198
3197
3199 # we don't merge the first commit when continuing
3198 # we don't merge the first commit when continuing
3200 if not cont:
3199 if not cont:
3201 # perform the graft merge with p1(rev) as 'ancestor'
3200 # perform the graft merge with p1(rev) as 'ancestor'
3202 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3201 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3203 base = ctx.p1() if basectx is None else basectx
3202 base = ctx.p1() if basectx is None else basectx
3204 with ui.configoverride(overrides, b'graft'):
3203 with ui.configoverride(overrides, b'graft'):
3205 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3204 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3206 # report any conflicts
3205 # report any conflicts
3207 if stats.unresolvedcount > 0:
3206 if stats.unresolvedcount > 0:
3208 # write out state for --continue
3207 # write out state for --continue
3209 nodes = [repo[rev].hex() for rev in revs[pos:]]
3208 nodes = [repo[rev].hex() for rev in revs[pos:]]
3210 statedata[b'nodes'] = nodes
3209 statedata[b'nodes'] = nodes
3211 stateversion = 1
3210 stateversion = 1
3212 graftstate.save(stateversion, statedata)
3211 graftstate.save(stateversion, statedata)
3213 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3212 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3214 raise error.Abort(
3213 raise error.Abort(
3215 _(b"unresolved conflicts, can't continue"), hint=hint
3214 _(b"unresolved conflicts, can't continue"), hint=hint
3216 )
3215 )
3217 else:
3216 else:
3218 cont = False
3217 cont = False
3219
3218
3220 # commit if --no-commit is false
3219 # commit if --no-commit is false
3221 if not opts.get(b'no_commit'):
3220 if not opts.get(b'no_commit'):
3222 node = repo.commit(
3221 node = repo.commit(
3223 text=message, user=user, date=date, extra=extra, editor=editor
3222 text=message, user=user, date=date, extra=extra, editor=editor
3224 )
3223 )
3225 if node is None:
3224 if node is None:
3226 ui.warn(
3225 ui.warn(
3227 _(b'note: graft of %d:%s created no changes to commit\n')
3226 _(b'note: graft of %d:%s created no changes to commit\n')
3228 % (ctx.rev(), ctx)
3227 % (ctx.rev(), ctx)
3229 )
3228 )
3230 # checking that newnodes exist because old state files won't have it
3229 # checking that newnodes exist because old state files won't have it
3231 elif statedata.get(b'newnodes') is not None:
3230 elif statedata.get(b'newnodes') is not None:
3232 statedata[b'newnodes'].append(node)
3231 statedata[b'newnodes'].append(node)
3233
3232
3234 # remove state when we complete successfully
3233 # remove state when we complete successfully
3235 if not opts.get(b'dry_run'):
3234 if not opts.get(b'dry_run'):
3236 graftstate.delete()
3235 graftstate.delete()
3237
3236
3238 return 0
3237 return 0
3239
3238
3240
3239
3241 def _stopgraft(ui, repo, graftstate):
3240 def _stopgraft(ui, repo, graftstate):
3242 """stop the interrupted graft"""
3241 """stop the interrupted graft"""
3243 if not graftstate.exists():
3242 if not graftstate.exists():
3244 raise error.Abort(_(b"no interrupted graft found"))
3243 raise error.Abort(_(b"no interrupted graft found"))
3245 pctx = repo[b'.']
3244 pctx = repo[b'.']
3246 hg.updaterepo(repo, pctx.node(), overwrite=True)
3245 hg.updaterepo(repo, pctx.node(), overwrite=True)
3247 graftstate.delete()
3246 graftstate.delete()
3248 ui.status(_(b"stopped the interrupted graft\n"))
3247 ui.status(_(b"stopped the interrupted graft\n"))
3249 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3248 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3250 return 0
3249 return 0
3251
3250
3252
3251
3253 statemod.addunfinished(
3252 statemod.addunfinished(
3254 b'graft',
3253 b'graft',
3255 fname=b'graftstate',
3254 fname=b'graftstate',
3256 clearable=True,
3255 clearable=True,
3257 stopflag=True,
3256 stopflag=True,
3258 continueflag=True,
3257 continueflag=True,
3259 abortfunc=cmdutil.hgabortgraft,
3258 abortfunc=cmdutil.hgabortgraft,
3260 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3259 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3261 )
3260 )
3262
3261
3263
3262
3264 @command(
3263 @command(
3265 b'grep',
3264 b'grep',
3266 [
3265 [
3267 (b'0', b'print0', None, _(b'end fields with NUL')),
3266 (b'0', b'print0', None, _(b'end fields with NUL')),
3268 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3267 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3269 (
3268 (
3270 b'',
3269 b'',
3271 b'diff',
3270 b'diff',
3272 None,
3271 None,
3273 _(
3272 _(
3274 b'search revision differences for when the pattern was added '
3273 b'search revision differences for when the pattern was added '
3275 b'or removed'
3274 b'or removed'
3276 ),
3275 ),
3277 ),
3276 ),
3278 (b'a', b'text', None, _(b'treat all files as text')),
3277 (b'a', b'text', None, _(b'treat all files as text')),
3279 (
3278 (
3280 b'f',
3279 b'f',
3281 b'follow',
3280 b'follow',
3282 None,
3281 None,
3283 _(
3282 _(
3284 b'follow changeset history,'
3283 b'follow changeset history,'
3285 b' or file history across copies and renames'
3284 b' or file history across copies and renames'
3286 ),
3285 ),
3287 ),
3286 ),
3288 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3287 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3289 (
3288 (
3290 b'l',
3289 b'l',
3291 b'files-with-matches',
3290 b'files-with-matches',
3292 None,
3291 None,
3293 _(b'print only filenames and revisions that match'),
3292 _(b'print only filenames and revisions that match'),
3294 ),
3293 ),
3295 (b'n', b'line-number', None, _(b'print matching line numbers')),
3294 (b'n', b'line-number', None, _(b'print matching line numbers')),
3296 (
3295 (
3297 b'r',
3296 b'r',
3298 b'rev',
3297 b'rev',
3299 [],
3298 [],
3300 _(b'search files changed within revision range'),
3299 _(b'search files changed within revision range'),
3301 _(b'REV'),
3300 _(b'REV'),
3302 ),
3301 ),
3303 (
3302 (
3304 b'',
3303 b'',
3305 b'all-files',
3304 b'all-files',
3306 None,
3305 None,
3307 _(
3306 _(
3308 b'include all files in the changeset while grepping (DEPRECATED)'
3307 b'include all files in the changeset while grepping (DEPRECATED)'
3309 ),
3308 ),
3310 ),
3309 ),
3311 (b'u', b'user', None, _(b'list the author (long with -v)')),
3310 (b'u', b'user', None, _(b'list the author (long with -v)')),
3312 (b'd', b'date', None, _(b'list the date (short with -q)')),
3311 (b'd', b'date', None, _(b'list the date (short with -q)')),
3313 ]
3312 ]
3314 + formatteropts
3313 + formatteropts
3315 + walkopts,
3314 + walkopts,
3316 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3315 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3317 helpcategory=command.CATEGORY_FILE_CONTENTS,
3316 helpcategory=command.CATEGORY_FILE_CONTENTS,
3318 inferrepo=True,
3317 inferrepo=True,
3319 intents={INTENT_READONLY},
3318 intents={INTENT_READONLY},
3320 )
3319 )
3321 def grep(ui, repo, pattern, *pats, **opts):
3320 def grep(ui, repo, pattern, *pats, **opts):
3322 """search for a pattern in specified files
3321 """search for a pattern in specified files
3323
3322
3324 Search the working directory or revision history for a regular
3323 Search the working directory or revision history for a regular
3325 expression in the specified files for the entire repository.
3324 expression in the specified files for the entire repository.
3326
3325
3327 By default, grep searches the repository files in the working
3326 By default, grep searches the repository files in the working
3328 directory and prints the files where it finds a match. To specify
3327 directory and prints the files where it finds a match. To specify
3329 historical revisions instead of the working directory, use the
3328 historical revisions instead of the working directory, use the
3330 --rev flag.
3329 --rev flag.
3331
3330
3332 To search instead historical revision differences that contains a
3331 To search instead historical revision differences that contains a
3333 change in match status ("-" for a match that becomes a non-match,
3332 change in match status ("-" for a match that becomes a non-match,
3334 or "+" for a non-match that becomes a match), use the --diff flag.
3333 or "+" for a non-match that becomes a match), use the --diff flag.
3335
3334
3336 PATTERN can be any Python (roughly Perl-compatible) regular
3335 PATTERN can be any Python (roughly Perl-compatible) regular
3337 expression.
3336 expression.
3338
3337
3339 If no FILEs are specified and the --rev flag isn't supplied, all
3338 If no FILEs are specified and the --rev flag isn't supplied, all
3340 files in the working directory are searched. When using the --rev
3339 files in the working directory are searched. When using the --rev
3341 flag and specifying FILEs, use the --follow argument to also
3340 flag and specifying FILEs, use the --follow argument to also
3342 follow the specified FILEs across renames and copies.
3341 follow the specified FILEs across renames and copies.
3343
3342
3344 .. container:: verbose
3343 .. container:: verbose
3345
3344
3346 Template:
3345 Template:
3347
3346
3348 The following keywords are supported in addition to the common template
3347 The following keywords are supported in addition to the common template
3349 keywords and functions. See also :hg:`help templates`.
3348 keywords and functions. See also :hg:`help templates`.
3350
3349
3351 :change: String. Character denoting insertion ``+`` or removal ``-``.
3350 :change: String. Character denoting insertion ``+`` or removal ``-``.
3352 Available if ``--diff`` is specified.
3351 Available if ``--diff`` is specified.
3353 :lineno: Integer. Line number of the match.
3352 :lineno: Integer. Line number of the match.
3354 :path: String. Repository-absolute path of the file.
3353 :path: String. Repository-absolute path of the file.
3355 :texts: List of text chunks.
3354 :texts: List of text chunks.
3356
3355
3357 And each entry of ``{texts}`` provides the following sub-keywords.
3356 And each entry of ``{texts}`` provides the following sub-keywords.
3358
3357
3359 :matched: Boolean. True if the chunk matches the specified pattern.
3358 :matched: Boolean. True if the chunk matches the specified pattern.
3360 :text: String. Chunk content.
3359 :text: String. Chunk content.
3361
3360
3362 See :hg:`help templates.operators` for the list expansion syntax.
3361 See :hg:`help templates.operators` for the list expansion syntax.
3363
3362
3364 Returns 0 if a match is found, 1 otherwise.
3363 Returns 0 if a match is found, 1 otherwise.
3365
3364
3366 """
3365 """
3367 opts = pycompat.byteskwargs(opts)
3366 opts = pycompat.byteskwargs(opts)
3368 diff = opts.get(b'all') or opts.get(b'diff')
3367 diff = opts.get(b'all') or opts.get(b'diff')
3369 if diff and opts.get(b'all_files'):
3368 if diff and opts.get(b'all_files'):
3370 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3369 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3371 if opts.get(b'all_files') is None and not diff:
3370 if opts.get(b'all_files') is None and not diff:
3372 opts[b'all_files'] = True
3371 opts[b'all_files'] = True
3373 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3372 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3374 all_files = opts.get(b'all_files')
3373 all_files = opts.get(b'all_files')
3375 if plaingrep:
3374 if plaingrep:
3376 opts[b'rev'] = [b'wdir()']
3375 opts[b'rev'] = [b'wdir()']
3377
3376
3378 reflags = re.M
3377 reflags = re.M
3379 if opts.get(b'ignore_case'):
3378 if opts.get(b'ignore_case'):
3380 reflags |= re.I
3379 reflags |= re.I
3381 try:
3380 try:
3382 regexp = util.re.compile(pattern, reflags)
3381 regexp = util.re.compile(pattern, reflags)
3383 except re.error as inst:
3382 except re.error as inst:
3384 ui.warn(
3383 ui.warn(
3385 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3384 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3386 )
3385 )
3387 return 1
3386 return 1
3388 sep, eol = b':', b'\n'
3387 sep, eol = b':', b'\n'
3389 if opts.get(b'print0'):
3388 if opts.get(b'print0'):
3390 sep = eol = b'\0'
3389 sep = eol = b'\0'
3391
3390
3392 getfile = util.lrucachefunc(repo.file)
3391 getfile = util.lrucachefunc(repo.file)
3393
3392
3394 def matchlines(body):
3393 def matchlines(body):
3395 begin = 0
3394 begin = 0
3396 linenum = 0
3395 linenum = 0
3397 while begin < len(body):
3396 while begin < len(body):
3398 match = regexp.search(body, begin)
3397 match = regexp.search(body, begin)
3399 if not match:
3398 if not match:
3400 break
3399 break
3401 mstart, mend = match.span()
3400 mstart, mend = match.span()
3402 linenum += body.count(b'\n', begin, mstart) + 1
3401 linenum += body.count(b'\n', begin, mstart) + 1
3403 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3402 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3404 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3403 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3405 lend = begin - 1
3404 lend = begin - 1
3406 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3405 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3407
3406
3408 class linestate(object):
3407 class linestate(object):
3409 def __init__(self, line, linenum, colstart, colend):
3408 def __init__(self, line, linenum, colstart, colend):
3410 self.line = line
3409 self.line = line
3411 self.linenum = linenum
3410 self.linenum = linenum
3412 self.colstart = colstart
3411 self.colstart = colstart
3413 self.colend = colend
3412 self.colend = colend
3414
3413
3415 def __hash__(self):
3414 def __hash__(self):
3416 return hash((self.linenum, self.line))
3415 return hash((self.linenum, self.line))
3417
3416
3418 def __eq__(self, other):
3417 def __eq__(self, other):
3419 return self.line == other.line
3418 return self.line == other.line
3420
3419
3421 def findpos(self):
3420 def findpos(self):
3422 """Iterate all (start, end) indices of matches"""
3421 """Iterate all (start, end) indices of matches"""
3423 yield self.colstart, self.colend
3422 yield self.colstart, self.colend
3424 p = self.colend
3423 p = self.colend
3425 while p < len(self.line):
3424 while p < len(self.line):
3426 m = regexp.search(self.line, p)
3425 m = regexp.search(self.line, p)
3427 if not m:
3426 if not m:
3428 break
3427 break
3429 yield m.span()
3428 yield m.span()
3430 p = m.end()
3429 p = m.end()
3431
3430
3432 matches = {}
3431 matches = {}
3433 copies = {}
3432 copies = {}
3434
3433
3435 def grepbody(fn, rev, body):
3434 def grepbody(fn, rev, body):
3436 matches[rev].setdefault(fn, [])
3435 matches[rev].setdefault(fn, [])
3437 m = matches[rev][fn]
3436 m = matches[rev][fn]
3438 if body is None:
3437 if body is None:
3439 return
3438 return
3440
3439
3441 for lnum, cstart, cend, line in matchlines(body):
3440 for lnum, cstart, cend, line in matchlines(body):
3442 s = linestate(line, lnum, cstart, cend)
3441 s = linestate(line, lnum, cstart, cend)
3443 m.append(s)
3442 m.append(s)
3444
3443
3445 def difflinestates(a, b):
3444 def difflinestates(a, b):
3446 sm = difflib.SequenceMatcher(None, a, b)
3445 sm = difflib.SequenceMatcher(None, a, b)
3447 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3446 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3448 if tag == 'insert':
3447 if tag == 'insert':
3449 for i in pycompat.xrange(blo, bhi):
3448 for i in pycompat.xrange(blo, bhi):
3450 yield (b'+', b[i])
3449 yield (b'+', b[i])
3451 elif tag == 'delete':
3450 elif tag == 'delete':
3452 for i in pycompat.xrange(alo, ahi):
3451 for i in pycompat.xrange(alo, ahi):
3453 yield (b'-', a[i])
3452 yield (b'-', a[i])
3454 elif tag == 'replace':
3453 elif tag == 'replace':
3455 for i in pycompat.xrange(alo, ahi):
3454 for i in pycompat.xrange(alo, ahi):
3456 yield (b'-', a[i])
3455 yield (b'-', a[i])
3457 for i in pycompat.xrange(blo, bhi):
3456 for i in pycompat.xrange(blo, bhi):
3458 yield (b'+', b[i])
3457 yield (b'+', b[i])
3459
3458
3460 uipathfn = scmutil.getuipathfn(repo)
3459 uipathfn = scmutil.getuipathfn(repo)
3461
3460
3462 def display(fm, fn, ctx, pstates, states):
3461 def display(fm, fn, ctx, pstates, states):
3463 rev = scmutil.intrev(ctx)
3462 rev = scmutil.intrev(ctx)
3464 if fm.isplain():
3463 if fm.isplain():
3465 formatuser = ui.shortuser
3464 formatuser = ui.shortuser
3466 else:
3465 else:
3467 formatuser = pycompat.bytestr
3466 formatuser = pycompat.bytestr
3468 if ui.quiet:
3467 if ui.quiet:
3469 datefmt = b'%Y-%m-%d'
3468 datefmt = b'%Y-%m-%d'
3470 else:
3469 else:
3471 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3470 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3472 found = False
3471 found = False
3473
3472
3474 @util.cachefunc
3473 @util.cachefunc
3475 def binary():
3474 def binary():
3476 flog = getfile(fn)
3475 flog = getfile(fn)
3477 try:
3476 try:
3478 return stringutil.binary(flog.read(ctx.filenode(fn)))
3477 return stringutil.binary(flog.read(ctx.filenode(fn)))
3479 except error.WdirUnsupported:
3478 except error.WdirUnsupported:
3480 return ctx[fn].isbinary()
3479 return ctx[fn].isbinary()
3481
3480
3482 fieldnamemap = {b'linenumber': b'lineno'}
3481 fieldnamemap = {b'linenumber': b'lineno'}
3483 if diff:
3482 if diff:
3484 iter = difflinestates(pstates, states)
3483 iter = difflinestates(pstates, states)
3485 else:
3484 else:
3486 iter = [(b'', l) for l in states]
3485 iter = [(b'', l) for l in states]
3487 for change, l in iter:
3486 for change, l in iter:
3488 fm.startitem()
3487 fm.startitem()
3489 fm.context(ctx=ctx)
3488 fm.context(ctx=ctx)
3490 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3489 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3491 fm.plain(uipathfn(fn), label=b'grep.filename')
3490 fm.plain(uipathfn(fn), label=b'grep.filename')
3492
3491
3493 cols = [
3492 cols = [
3494 (b'rev', b'%d', rev, not plaingrep, b''),
3493 (b'rev', b'%d', rev, not plaingrep, b''),
3495 (
3494 (
3496 b'linenumber',
3495 b'linenumber',
3497 b'%d',
3496 b'%d',
3498 l.linenum,
3497 l.linenum,
3499 opts.get(b'line_number'),
3498 opts.get(b'line_number'),
3500 b'',
3499 b'',
3501 ),
3500 ),
3502 ]
3501 ]
3503 if diff:
3502 if diff:
3504 cols.append(
3503 cols.append(
3505 (
3504 (
3506 b'change',
3505 b'change',
3507 b'%s',
3506 b'%s',
3508 change,
3507 change,
3509 True,
3508 True,
3510 b'grep.inserted '
3509 b'grep.inserted '
3511 if change == b'+'
3510 if change == b'+'
3512 else b'grep.deleted ',
3511 else b'grep.deleted ',
3513 )
3512 )
3514 )
3513 )
3515 cols.extend(
3514 cols.extend(
3516 [
3515 [
3517 (
3516 (
3518 b'user',
3517 b'user',
3519 b'%s',
3518 b'%s',
3520 formatuser(ctx.user()),
3519 formatuser(ctx.user()),
3521 opts.get(b'user'),
3520 opts.get(b'user'),
3522 b'',
3521 b'',
3523 ),
3522 ),
3524 (
3523 (
3525 b'date',
3524 b'date',
3526 b'%s',
3525 b'%s',
3527 fm.formatdate(ctx.date(), datefmt),
3526 fm.formatdate(ctx.date(), datefmt),
3528 opts.get(b'date'),
3527 opts.get(b'date'),
3529 b'',
3528 b'',
3530 ),
3529 ),
3531 ]
3530 ]
3532 )
3531 )
3533 for name, fmt, data, cond, extra_label in cols:
3532 for name, fmt, data, cond, extra_label in cols:
3534 if cond:
3533 if cond:
3535 fm.plain(sep, label=b'grep.sep')
3534 fm.plain(sep, label=b'grep.sep')
3536 field = fieldnamemap.get(name, name)
3535 field = fieldnamemap.get(name, name)
3537 label = extra_label + (b'grep.%s' % name)
3536 label = extra_label + (b'grep.%s' % name)
3538 fm.condwrite(cond, field, fmt, data, label=label)
3537 fm.condwrite(cond, field, fmt, data, label=label)
3539 if not opts.get(b'files_with_matches'):
3538 if not opts.get(b'files_with_matches'):
3540 fm.plain(sep, label=b'grep.sep')
3539 fm.plain(sep, label=b'grep.sep')
3541 if not opts.get(b'text') and binary():
3540 if not opts.get(b'text') and binary():
3542 fm.plain(_(b" Binary file matches"))
3541 fm.plain(_(b" Binary file matches"))
3543 else:
3542 else:
3544 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3543 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3545 fm.plain(eol)
3544 fm.plain(eol)
3546 found = True
3545 found = True
3547 if opts.get(b'files_with_matches'):
3546 if opts.get(b'files_with_matches'):
3548 break
3547 break
3549 return found
3548 return found
3550
3549
3551 def displaymatches(fm, l):
3550 def displaymatches(fm, l):
3552 p = 0
3551 p = 0
3553 for s, e in l.findpos():
3552 for s, e in l.findpos():
3554 if p < s:
3553 if p < s:
3555 fm.startitem()
3554 fm.startitem()
3556 fm.write(b'text', b'%s', l.line[p:s])
3555 fm.write(b'text', b'%s', l.line[p:s])
3557 fm.data(matched=False)
3556 fm.data(matched=False)
3558 fm.startitem()
3557 fm.startitem()
3559 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3558 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3560 fm.data(matched=True)
3559 fm.data(matched=True)
3561 p = e
3560 p = e
3562 if p < len(l.line):
3561 if p < len(l.line):
3563 fm.startitem()
3562 fm.startitem()
3564 fm.write(b'text', b'%s', l.line[p:])
3563 fm.write(b'text', b'%s', l.line[p:])
3565 fm.data(matched=False)
3564 fm.data(matched=False)
3566 fm.end()
3565 fm.end()
3567
3566
3568 skip = set()
3567 skip = set()
3569 revfiles = {}
3568 revfiles = {}
3570 match = scmutil.match(repo[None], pats, opts)
3569 match = scmutil.match(repo[None], pats, opts)
3571 found = False
3570 found = False
3572 follow = opts.get(b'follow')
3571 follow = opts.get(b'follow')
3573
3572
3574 getrenamed = scmutil.getrenamedfn(repo)
3573 getrenamed = scmutil.getrenamedfn(repo)
3575
3574
3576 def get_file_content(filename, filelog, filenode, context, revision):
3575 def get_file_content(filename, filelog, filenode, context, revision):
3577 try:
3576 try:
3578 content = filelog.read(filenode)
3577 content = filelog.read(filenode)
3579 except error.WdirUnsupported:
3578 except error.WdirUnsupported:
3580 content = context[filename].data()
3579 content = context[filename].data()
3581 except error.CensoredNodeError:
3580 except error.CensoredNodeError:
3582 content = None
3581 content = None
3583 ui.warn(
3582 ui.warn(
3584 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3583 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3585 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3584 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3586 )
3585 )
3587 return content
3586 return content
3588
3587
3589 def prep(ctx, fns):
3588 def prep(ctx, fns):
3590 rev = ctx.rev()
3589 rev = ctx.rev()
3591 pctx = ctx.p1()
3590 pctx = ctx.p1()
3592 parent = pctx.rev()
3591 parent = pctx.rev()
3593 matches.setdefault(rev, {})
3592 matches.setdefault(rev, {})
3594 matches.setdefault(parent, {})
3593 matches.setdefault(parent, {})
3595 files = revfiles.setdefault(rev, [])
3594 files = revfiles.setdefault(rev, [])
3596 for fn in fns:
3595 for fn in fns:
3597 flog = getfile(fn)
3596 flog = getfile(fn)
3598 try:
3597 try:
3599 fnode = ctx.filenode(fn)
3598 fnode = ctx.filenode(fn)
3600 except error.LookupError:
3599 except error.LookupError:
3601 continue
3600 continue
3602
3601
3603 copy = None
3602 copy = None
3604 if follow:
3603 if follow:
3605 copy = getrenamed(fn, rev)
3604 copy = getrenamed(fn, rev)
3606 if copy:
3605 if copy:
3607 copies.setdefault(rev, {})[fn] = copy
3606 copies.setdefault(rev, {})[fn] = copy
3608 if fn in skip:
3607 if fn in skip:
3609 skip.add(copy)
3608 skip.add(copy)
3610 if fn in skip:
3609 if fn in skip:
3611 continue
3610 continue
3612 files.append(fn)
3611 files.append(fn)
3613
3612
3614 if fn not in matches[rev]:
3613 if fn not in matches[rev]:
3615 content = get_file_content(fn, flog, fnode, ctx, rev)
3614 content = get_file_content(fn, flog, fnode, ctx, rev)
3616 grepbody(fn, rev, content)
3615 grepbody(fn, rev, content)
3617
3616
3618 pfn = copy or fn
3617 pfn = copy or fn
3619 if pfn not in matches[parent]:
3618 if pfn not in matches[parent]:
3620 try:
3619 try:
3621 pfnode = pctx.filenode(pfn)
3620 pfnode = pctx.filenode(pfn)
3622 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3621 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3623 grepbody(pfn, parent, pcontent)
3622 grepbody(pfn, parent, pcontent)
3624 except error.LookupError:
3623 except error.LookupError:
3625 pass
3624 pass
3626
3625
3627 ui.pager(b'grep')
3626 ui.pager(b'grep')
3628 fm = ui.formatter(b'grep', opts)
3627 fm = ui.formatter(b'grep', opts)
3629 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3628 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3630 rev = ctx.rev()
3629 rev = ctx.rev()
3631 parent = ctx.p1().rev()
3630 parent = ctx.p1().rev()
3632 for fn in sorted(revfiles.get(rev, [])):
3631 for fn in sorted(revfiles.get(rev, [])):
3633 states = matches[rev][fn]
3632 states = matches[rev][fn]
3634 copy = copies.get(rev, {}).get(fn)
3633 copy = copies.get(rev, {}).get(fn)
3635 if fn in skip:
3634 if fn in skip:
3636 if copy:
3635 if copy:
3637 skip.add(copy)
3636 skip.add(copy)
3638 continue
3637 continue
3639 pstates = matches.get(parent, {}).get(copy or fn, [])
3638 pstates = matches.get(parent, {}).get(copy or fn, [])
3640 if pstates or states:
3639 if pstates or states:
3641 r = display(fm, fn, ctx, pstates, states)
3640 r = display(fm, fn, ctx, pstates, states)
3642 found = found or r
3641 found = found or r
3643 if r and not diff and not all_files:
3642 if r and not diff and not all_files:
3644 skip.add(fn)
3643 skip.add(fn)
3645 if copy:
3644 if copy:
3646 skip.add(copy)
3645 skip.add(copy)
3647 del revfiles[rev]
3646 del revfiles[rev]
3648 # We will keep the matches dict for the duration of the window
3647 # We will keep the matches dict for the duration of the window
3649 # clear the matches dict once the window is over
3648 # clear the matches dict once the window is over
3650 if not revfiles:
3649 if not revfiles:
3651 matches.clear()
3650 matches.clear()
3652 fm.end()
3651 fm.end()
3653
3652
3654 return not found
3653 return not found
3655
3654
3656
3655
3657 @command(
3656 @command(
3658 b'heads',
3657 b'heads',
3659 [
3658 [
3660 (
3659 (
3661 b'r',
3660 b'r',
3662 b'rev',
3661 b'rev',
3663 b'',
3662 b'',
3664 _(b'show only heads which are descendants of STARTREV'),
3663 _(b'show only heads which are descendants of STARTREV'),
3665 _(b'STARTREV'),
3664 _(b'STARTREV'),
3666 ),
3665 ),
3667 (b't', b'topo', False, _(b'show topological heads only')),
3666 (b't', b'topo', False, _(b'show topological heads only')),
3668 (
3667 (
3669 b'a',
3668 b'a',
3670 b'active',
3669 b'active',
3671 False,
3670 False,
3672 _(b'show active branchheads only (DEPRECATED)'),
3671 _(b'show active branchheads only (DEPRECATED)'),
3673 ),
3672 ),
3674 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3673 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3675 ]
3674 ]
3676 + templateopts,
3675 + templateopts,
3677 _(b'[-ct] [-r STARTREV] [REV]...'),
3676 _(b'[-ct] [-r STARTREV] [REV]...'),
3678 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3677 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3679 intents={INTENT_READONLY},
3678 intents={INTENT_READONLY},
3680 )
3679 )
3681 def heads(ui, repo, *branchrevs, **opts):
3680 def heads(ui, repo, *branchrevs, **opts):
3682 """show branch heads
3681 """show branch heads
3683
3682
3684 With no arguments, show all open branch heads in the repository.
3683 With no arguments, show all open branch heads in the repository.
3685 Branch heads are changesets that have no descendants on the
3684 Branch heads are changesets that have no descendants on the
3686 same branch. They are where development generally takes place and
3685 same branch. They are where development generally takes place and
3687 are the usual targets for update and merge operations.
3686 are the usual targets for update and merge operations.
3688
3687
3689 If one or more REVs are given, only open branch heads on the
3688 If one or more REVs are given, only open branch heads on the
3690 branches associated with the specified changesets are shown. This
3689 branches associated with the specified changesets are shown. This
3691 means that you can use :hg:`heads .` to see the heads on the
3690 means that you can use :hg:`heads .` to see the heads on the
3692 currently checked-out branch.
3691 currently checked-out branch.
3693
3692
3694 If -c/--closed is specified, also show branch heads marked closed
3693 If -c/--closed is specified, also show branch heads marked closed
3695 (see :hg:`commit --close-branch`).
3694 (see :hg:`commit --close-branch`).
3696
3695
3697 If STARTREV is specified, only those heads that are descendants of
3696 If STARTREV is specified, only those heads that are descendants of
3698 STARTREV will be displayed.
3697 STARTREV will be displayed.
3699
3698
3700 If -t/--topo is specified, named branch mechanics will be ignored and only
3699 If -t/--topo is specified, named branch mechanics will be ignored and only
3701 topological heads (changesets with no children) will be shown.
3700 topological heads (changesets with no children) will be shown.
3702
3701
3703 Returns 0 if matching heads are found, 1 if not.
3702 Returns 0 if matching heads are found, 1 if not.
3704 """
3703 """
3705
3704
3706 opts = pycompat.byteskwargs(opts)
3705 opts = pycompat.byteskwargs(opts)
3707 start = None
3706 start = None
3708 rev = opts.get(b'rev')
3707 rev = opts.get(b'rev')
3709 if rev:
3708 if rev:
3710 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3711 start = scmutil.revsingle(repo, rev, None).node()
3710 start = scmutil.revsingle(repo, rev, None).node()
3712
3711
3713 if opts.get(b'topo'):
3712 if opts.get(b'topo'):
3714 heads = [repo[h] for h in repo.heads(start)]
3713 heads = [repo[h] for h in repo.heads(start)]
3715 else:
3714 else:
3716 heads = []
3715 heads = []
3717 for branch in repo.branchmap():
3716 for branch in repo.branchmap():
3718 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3717 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3719 heads = [repo[h] for h in heads]
3718 heads = [repo[h] for h in heads]
3720
3719
3721 if branchrevs:
3720 if branchrevs:
3722 branches = set(
3721 branches = set(
3723 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3722 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3724 )
3723 )
3725 heads = [h for h in heads if h.branch() in branches]
3724 heads = [h for h in heads if h.branch() in branches]
3726
3725
3727 if opts.get(b'active') and branchrevs:
3726 if opts.get(b'active') and branchrevs:
3728 dagheads = repo.heads(start)
3727 dagheads = repo.heads(start)
3729 heads = [h for h in heads if h.node() in dagheads]
3728 heads = [h for h in heads if h.node() in dagheads]
3730
3729
3731 if branchrevs:
3730 if branchrevs:
3732 haveheads = set(h.branch() for h in heads)
3731 haveheads = set(h.branch() for h in heads)
3733 if branches - haveheads:
3732 if branches - haveheads:
3734 headless = b', '.join(b for b in branches - haveheads)
3733 headless = b', '.join(b for b in branches - haveheads)
3735 msg = _(b'no open branch heads found on branches %s')
3734 msg = _(b'no open branch heads found on branches %s')
3736 if opts.get(b'rev'):
3735 if opts.get(b'rev'):
3737 msg += _(b' (started at %s)') % opts[b'rev']
3736 msg += _(b' (started at %s)') % opts[b'rev']
3738 ui.warn((msg + b'\n') % headless)
3737 ui.warn((msg + b'\n') % headless)
3739
3738
3740 if not heads:
3739 if not heads:
3741 return 1
3740 return 1
3742
3741
3743 ui.pager(b'heads')
3742 ui.pager(b'heads')
3744 heads = sorted(heads, key=lambda x: -(x.rev()))
3743 heads = sorted(heads, key=lambda x: -(x.rev()))
3745 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3744 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3746 for ctx in heads:
3745 for ctx in heads:
3747 displayer.show(ctx)
3746 displayer.show(ctx)
3748 displayer.close()
3747 displayer.close()
3749
3748
3750
3749
3751 @command(
3750 @command(
3752 b'help',
3751 b'help',
3753 [
3752 [
3754 (b'e', b'extension', None, _(b'show only help for extensions')),
3753 (b'e', b'extension', None, _(b'show only help for extensions')),
3755 (b'c', b'command', None, _(b'show only help for commands')),
3754 (b'c', b'command', None, _(b'show only help for commands')),
3756 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3755 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3757 (
3756 (
3758 b's',
3757 b's',
3759 b'system',
3758 b'system',
3760 [],
3759 [],
3761 _(b'show help for specific platform(s)'),
3760 _(b'show help for specific platform(s)'),
3762 _(b'PLATFORM'),
3761 _(b'PLATFORM'),
3763 ),
3762 ),
3764 ],
3763 ],
3765 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3764 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3766 helpcategory=command.CATEGORY_HELP,
3765 helpcategory=command.CATEGORY_HELP,
3767 norepo=True,
3766 norepo=True,
3768 intents={INTENT_READONLY},
3767 intents={INTENT_READONLY},
3769 )
3768 )
3770 def help_(ui, name=None, **opts):
3769 def help_(ui, name=None, **opts):
3771 """show help for a given topic or a help overview
3770 """show help for a given topic or a help overview
3772
3771
3773 With no arguments, print a list of commands with short help messages.
3772 With no arguments, print a list of commands with short help messages.
3774
3773
3775 Given a topic, extension, or command name, print help for that
3774 Given a topic, extension, or command name, print help for that
3776 topic.
3775 topic.
3777
3776
3778 Returns 0 if successful.
3777 Returns 0 if successful.
3779 """
3778 """
3780
3779
3781 keep = opts.get('system') or []
3780 keep = opts.get('system') or []
3782 if len(keep) == 0:
3781 if len(keep) == 0:
3783 if pycompat.sysplatform.startswith(b'win'):
3782 if pycompat.sysplatform.startswith(b'win'):
3784 keep.append(b'windows')
3783 keep.append(b'windows')
3785 elif pycompat.sysplatform == b'OpenVMS':
3784 elif pycompat.sysplatform == b'OpenVMS':
3786 keep.append(b'vms')
3785 keep.append(b'vms')
3787 elif pycompat.sysplatform == b'plan9':
3786 elif pycompat.sysplatform == b'plan9':
3788 keep.append(b'plan9')
3787 keep.append(b'plan9')
3789 else:
3788 else:
3790 keep.append(b'unix')
3789 keep.append(b'unix')
3791 keep.append(pycompat.sysplatform.lower())
3790 keep.append(pycompat.sysplatform.lower())
3792 if ui.verbose:
3791 if ui.verbose:
3793 keep.append(b'verbose')
3792 keep.append(b'verbose')
3794
3793
3795 commands = sys.modules[__name__]
3794 commands = sys.modules[__name__]
3796 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3795 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3797 ui.pager(b'help')
3796 ui.pager(b'help')
3798 ui.write(formatted)
3797 ui.write(formatted)
3799
3798
3800
3799
3801 @command(
3800 @command(
3802 b'identify|id',
3801 b'identify|id',
3803 [
3802 [
3804 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3803 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3805 (b'n', b'num', None, _(b'show local revision number')),
3804 (b'n', b'num', None, _(b'show local revision number')),
3806 (b'i', b'id', None, _(b'show global revision id')),
3805 (b'i', b'id', None, _(b'show global revision id')),
3807 (b'b', b'branch', None, _(b'show branch')),
3806 (b'b', b'branch', None, _(b'show branch')),
3808 (b't', b'tags', None, _(b'show tags')),
3807 (b't', b'tags', None, _(b'show tags')),
3809 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3808 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3810 ]
3809 ]
3811 + remoteopts
3810 + remoteopts
3812 + formatteropts,
3811 + formatteropts,
3813 _(b'[-nibtB] [-r REV] [SOURCE]'),
3812 _(b'[-nibtB] [-r REV] [SOURCE]'),
3814 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3813 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3815 optionalrepo=True,
3814 optionalrepo=True,
3816 intents={INTENT_READONLY},
3815 intents={INTENT_READONLY},
3817 )
3816 )
3818 def identify(
3817 def identify(
3819 ui,
3818 ui,
3820 repo,
3819 repo,
3821 source=None,
3820 source=None,
3822 rev=None,
3821 rev=None,
3823 num=None,
3822 num=None,
3824 id=None,
3823 id=None,
3825 branch=None,
3824 branch=None,
3826 tags=None,
3825 tags=None,
3827 bookmarks=None,
3826 bookmarks=None,
3828 **opts
3827 **opts
3829 ):
3828 ):
3830 """identify the working directory or specified revision
3829 """identify the working directory or specified revision
3831
3830
3832 Print a summary identifying the repository state at REV using one or
3831 Print a summary identifying the repository state at REV using one or
3833 two parent hash identifiers, followed by a "+" if the working
3832 two parent hash identifiers, followed by a "+" if the working
3834 directory has uncommitted changes, the branch name (if not default),
3833 directory has uncommitted changes, the branch name (if not default),
3835 a list of tags, and a list of bookmarks.
3834 a list of tags, and a list of bookmarks.
3836
3835
3837 When REV is not given, print a summary of the current state of the
3836 When REV is not given, print a summary of the current state of the
3838 repository including the working directory. Specify -r. to get information
3837 repository including the working directory. Specify -r. to get information
3839 of the working directory parent without scanning uncommitted changes.
3838 of the working directory parent without scanning uncommitted changes.
3840
3839
3841 Specifying a path to a repository root or Mercurial bundle will
3840 Specifying a path to a repository root or Mercurial bundle will
3842 cause lookup to operate on that repository/bundle.
3841 cause lookup to operate on that repository/bundle.
3843
3842
3844 .. container:: verbose
3843 .. container:: verbose
3845
3844
3846 Template:
3845 Template:
3847
3846
3848 The following keywords are supported in addition to the common template
3847 The following keywords are supported in addition to the common template
3849 keywords and functions. See also :hg:`help templates`.
3848 keywords and functions. See also :hg:`help templates`.
3850
3849
3851 :dirty: String. Character ``+`` denoting if the working directory has
3850 :dirty: String. Character ``+`` denoting if the working directory has
3852 uncommitted changes.
3851 uncommitted changes.
3853 :id: String. One or two nodes, optionally followed by ``+``.
3852 :id: String. One or two nodes, optionally followed by ``+``.
3854 :parents: List of strings. Parent nodes of the changeset.
3853 :parents: List of strings. Parent nodes of the changeset.
3855
3854
3856 Examples:
3855 Examples:
3857
3856
3858 - generate a build identifier for the working directory::
3857 - generate a build identifier for the working directory::
3859
3858
3860 hg id --id > build-id.dat
3859 hg id --id > build-id.dat
3861
3860
3862 - find the revision corresponding to a tag::
3861 - find the revision corresponding to a tag::
3863
3862
3864 hg id -n -r 1.3
3863 hg id -n -r 1.3
3865
3864
3866 - check the most recent revision of a remote repository::
3865 - check the most recent revision of a remote repository::
3867
3866
3868 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3867 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3869
3868
3870 See :hg:`log` for generating more information about specific revisions,
3869 See :hg:`log` for generating more information about specific revisions,
3871 including full hash identifiers.
3870 including full hash identifiers.
3872
3871
3873 Returns 0 if successful.
3872 Returns 0 if successful.
3874 """
3873 """
3875
3874
3876 opts = pycompat.byteskwargs(opts)
3875 opts = pycompat.byteskwargs(opts)
3877 if not repo and not source:
3876 if not repo and not source:
3878 raise error.Abort(
3877 raise error.Abort(
3879 _(b"there is no Mercurial repository here (.hg not found)")
3878 _(b"there is no Mercurial repository here (.hg not found)")
3880 )
3879 )
3881
3880
3882 default = not (num or id or branch or tags or bookmarks)
3881 default = not (num or id or branch or tags or bookmarks)
3883 output = []
3882 output = []
3884 revs = []
3883 revs = []
3885
3884
3886 if source:
3885 if source:
3887 source, branches = hg.parseurl(ui.expandpath(source))
3886 source, branches = hg.parseurl(ui.expandpath(source))
3888 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3887 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3889 repo = peer.local()
3888 repo = peer.local()
3890 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3889 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3891
3890
3892 fm = ui.formatter(b'identify', opts)
3891 fm = ui.formatter(b'identify', opts)
3893 fm.startitem()
3892 fm.startitem()
3894
3893
3895 if not repo:
3894 if not repo:
3896 if num or branch or tags:
3895 if num or branch or tags:
3897 raise error.Abort(
3896 raise error.Abort(
3898 _(b"can't query remote revision number, branch, or tags")
3897 _(b"can't query remote revision number, branch, or tags")
3899 )
3898 )
3900 if not rev and revs:
3899 if not rev and revs:
3901 rev = revs[0]
3900 rev = revs[0]
3902 if not rev:
3901 if not rev:
3903 rev = b"tip"
3902 rev = b"tip"
3904
3903
3905 remoterev = peer.lookup(rev)
3904 remoterev = peer.lookup(rev)
3906 hexrev = fm.hexfunc(remoterev)
3905 hexrev = fm.hexfunc(remoterev)
3907 if default or id:
3906 if default or id:
3908 output = [hexrev]
3907 output = [hexrev]
3909 fm.data(id=hexrev)
3908 fm.data(id=hexrev)
3910
3909
3911 @util.cachefunc
3910 @util.cachefunc
3912 def getbms():
3911 def getbms():
3913 bms = []
3912 bms = []
3914
3913
3915 if b'bookmarks' in peer.listkeys(b'namespaces'):
3914 if b'bookmarks' in peer.listkeys(b'namespaces'):
3916 hexremoterev = hex(remoterev)
3915 hexremoterev = hex(remoterev)
3917 bms = [
3916 bms = [
3918 bm
3917 bm
3919 for bm, bmr in pycompat.iteritems(
3918 for bm, bmr in pycompat.iteritems(
3920 peer.listkeys(b'bookmarks')
3919 peer.listkeys(b'bookmarks')
3921 )
3920 )
3922 if bmr == hexremoterev
3921 if bmr == hexremoterev
3923 ]
3922 ]
3924
3923
3925 return sorted(bms)
3924 return sorted(bms)
3926
3925
3927 if fm.isplain():
3926 if fm.isplain():
3928 if bookmarks:
3927 if bookmarks:
3929 output.extend(getbms())
3928 output.extend(getbms())
3930 elif default and not ui.quiet:
3929 elif default and not ui.quiet:
3931 # multiple bookmarks for a single parent separated by '/'
3930 # multiple bookmarks for a single parent separated by '/'
3932 bm = b'/'.join(getbms())
3931 bm = b'/'.join(getbms())
3933 if bm:
3932 if bm:
3934 output.append(bm)
3933 output.append(bm)
3935 else:
3934 else:
3936 fm.data(node=hex(remoterev))
3935 fm.data(node=hex(remoterev))
3937 if bookmarks or b'bookmarks' in fm.datahint():
3936 if bookmarks or b'bookmarks' in fm.datahint():
3938 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3937 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3939 else:
3938 else:
3940 if rev:
3939 if rev:
3941 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3940 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3942 ctx = scmutil.revsingle(repo, rev, None)
3941 ctx = scmutil.revsingle(repo, rev, None)
3943
3942
3944 if ctx.rev() is None:
3943 if ctx.rev() is None:
3945 ctx = repo[None]
3944 ctx = repo[None]
3946 parents = ctx.parents()
3945 parents = ctx.parents()
3947 taglist = []
3946 taglist = []
3948 for p in parents:
3947 for p in parents:
3949 taglist.extend(p.tags())
3948 taglist.extend(p.tags())
3950
3949
3951 dirty = b""
3950 dirty = b""
3952 if ctx.dirty(missing=True, merge=False, branch=False):
3951 if ctx.dirty(missing=True, merge=False, branch=False):
3953 dirty = b'+'
3952 dirty = b'+'
3954 fm.data(dirty=dirty)
3953 fm.data(dirty=dirty)
3955
3954
3956 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3955 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3957 if default or id:
3956 if default or id:
3958 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3957 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3959 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3958 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3960
3959
3961 if num:
3960 if num:
3962 numoutput = [b"%d" % p.rev() for p in parents]
3961 numoutput = [b"%d" % p.rev() for p in parents]
3963 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3962 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3964
3963
3965 fm.data(
3964 fm.data(
3966 parents=fm.formatlist(
3965 parents=fm.formatlist(
3967 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3966 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3968 )
3967 )
3969 )
3968 )
3970 else:
3969 else:
3971 hexoutput = fm.hexfunc(ctx.node())
3970 hexoutput = fm.hexfunc(ctx.node())
3972 if default or id:
3971 if default or id:
3973 output = [hexoutput]
3972 output = [hexoutput]
3974 fm.data(id=hexoutput)
3973 fm.data(id=hexoutput)
3975
3974
3976 if num:
3975 if num:
3977 output.append(pycompat.bytestr(ctx.rev()))
3976 output.append(pycompat.bytestr(ctx.rev()))
3978 taglist = ctx.tags()
3977 taglist = ctx.tags()
3979
3978
3980 if default and not ui.quiet:
3979 if default and not ui.quiet:
3981 b = ctx.branch()
3980 b = ctx.branch()
3982 if b != b'default':
3981 if b != b'default':
3983 output.append(b"(%s)" % b)
3982 output.append(b"(%s)" % b)
3984
3983
3985 # multiple tags for a single parent separated by '/'
3984 # multiple tags for a single parent separated by '/'
3986 t = b'/'.join(taglist)
3985 t = b'/'.join(taglist)
3987 if t:
3986 if t:
3988 output.append(t)
3987 output.append(t)
3989
3988
3990 # multiple bookmarks for a single parent separated by '/'
3989 # multiple bookmarks for a single parent separated by '/'
3991 bm = b'/'.join(ctx.bookmarks())
3990 bm = b'/'.join(ctx.bookmarks())
3992 if bm:
3991 if bm:
3993 output.append(bm)
3992 output.append(bm)
3994 else:
3993 else:
3995 if branch:
3994 if branch:
3996 output.append(ctx.branch())
3995 output.append(ctx.branch())
3997
3996
3998 if tags:
3997 if tags:
3999 output.extend(taglist)
3998 output.extend(taglist)
4000
3999
4001 if bookmarks:
4000 if bookmarks:
4002 output.extend(ctx.bookmarks())
4001 output.extend(ctx.bookmarks())
4003
4002
4004 fm.data(node=ctx.hex())
4003 fm.data(node=ctx.hex())
4005 fm.data(branch=ctx.branch())
4004 fm.data(branch=ctx.branch())
4006 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4005 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4007 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4006 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4008 fm.context(ctx=ctx)
4007 fm.context(ctx=ctx)
4009
4008
4010 fm.plain(b"%s\n" % b' '.join(output))
4009 fm.plain(b"%s\n" % b' '.join(output))
4011 fm.end()
4010 fm.end()
4012
4011
4013
4012
4014 @command(
4013 @command(
4015 b'import|patch',
4014 b'import|patch',
4016 [
4015 [
4017 (
4016 (
4018 b'p',
4017 b'p',
4019 b'strip',
4018 b'strip',
4020 1,
4019 1,
4021 _(
4020 _(
4022 b'directory strip option for patch. This has the same '
4021 b'directory strip option for patch. This has the same '
4023 b'meaning as the corresponding patch option'
4022 b'meaning as the corresponding patch option'
4024 ),
4023 ),
4025 _(b'NUM'),
4024 _(b'NUM'),
4026 ),
4025 ),
4027 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4026 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4028 (b'', b'secret', None, _(b'use the secret phase for committing')),
4027 (b'', b'secret', None, _(b'use the secret phase for committing')),
4029 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4028 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4030 (
4029 (
4031 b'f',
4030 b'f',
4032 b'force',
4031 b'force',
4033 None,
4032 None,
4034 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4033 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4035 ),
4034 ),
4036 (
4035 (
4037 b'',
4036 b'',
4038 b'no-commit',
4037 b'no-commit',
4039 None,
4038 None,
4040 _(b"don't commit, just update the working directory"),
4039 _(b"don't commit, just update the working directory"),
4041 ),
4040 ),
4042 (
4041 (
4043 b'',
4042 b'',
4044 b'bypass',
4043 b'bypass',
4045 None,
4044 None,
4046 _(b"apply patch without touching the working directory"),
4045 _(b"apply patch without touching the working directory"),
4047 ),
4046 ),
4048 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4047 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4049 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4048 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4050 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4049 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4051 (
4050 (
4052 b'',
4051 b'',
4053 b'import-branch',
4052 b'import-branch',
4054 None,
4053 None,
4055 _(b'use any branch information in patch (implied by --exact)'),
4054 _(b'use any branch information in patch (implied by --exact)'),
4056 ),
4055 ),
4057 ]
4056 ]
4058 + commitopts
4057 + commitopts
4059 + commitopts2
4058 + commitopts2
4060 + similarityopts,
4059 + similarityopts,
4061 _(b'[OPTION]... PATCH...'),
4060 _(b'[OPTION]... PATCH...'),
4062 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4061 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4063 )
4062 )
4064 def import_(ui, repo, patch1=None, *patches, **opts):
4063 def import_(ui, repo, patch1=None, *patches, **opts):
4065 """import an ordered set of patches
4064 """import an ordered set of patches
4066
4065
4067 Import a list of patches and commit them individually (unless
4066 Import a list of patches and commit them individually (unless
4068 --no-commit is specified).
4067 --no-commit is specified).
4069
4068
4070 To read a patch from standard input (stdin), use "-" as the patch
4069 To read a patch from standard input (stdin), use "-" as the patch
4071 name. If a URL is specified, the patch will be downloaded from
4070 name. If a URL is specified, the patch will be downloaded from
4072 there.
4071 there.
4073
4072
4074 Import first applies changes to the working directory (unless
4073 Import first applies changes to the working directory (unless
4075 --bypass is specified), import will abort if there are outstanding
4074 --bypass is specified), import will abort if there are outstanding
4076 changes.
4075 changes.
4077
4076
4078 Use --bypass to apply and commit patches directly to the
4077 Use --bypass to apply and commit patches directly to the
4079 repository, without affecting the working directory. Without
4078 repository, without affecting the working directory. Without
4080 --exact, patches will be applied on top of the working directory
4079 --exact, patches will be applied on top of the working directory
4081 parent revision.
4080 parent revision.
4082
4081
4083 You can import a patch straight from a mail message. Even patches
4082 You can import a patch straight from a mail message. Even patches
4084 as attachments work (to use the body part, it must have type
4083 as attachments work (to use the body part, it must have type
4085 text/plain or text/x-patch). From and Subject headers of email
4084 text/plain or text/x-patch). From and Subject headers of email
4086 message are used as default committer and commit message. All
4085 message are used as default committer and commit message. All
4087 text/plain body parts before first diff are added to the commit
4086 text/plain body parts before first diff are added to the commit
4088 message.
4087 message.
4089
4088
4090 If the imported patch was generated by :hg:`export`, user and
4089 If the imported patch was generated by :hg:`export`, user and
4091 description from patch override values from message headers and
4090 description from patch override values from message headers and
4092 body. Values given on command line with -m/--message and -u/--user
4091 body. Values given on command line with -m/--message and -u/--user
4093 override these.
4092 override these.
4094
4093
4095 If --exact is specified, import will set the working directory to
4094 If --exact is specified, import will set the working directory to
4096 the parent of each patch before applying it, and will abort if the
4095 the parent of each patch before applying it, and will abort if the
4097 resulting changeset has a different ID than the one recorded in
4096 resulting changeset has a different ID than the one recorded in
4098 the patch. This will guard against various ways that portable
4097 the patch. This will guard against various ways that portable
4099 patch formats and mail systems might fail to transfer Mercurial
4098 patch formats and mail systems might fail to transfer Mercurial
4100 data or metadata. See :hg:`bundle` for lossless transmission.
4099 data or metadata. See :hg:`bundle` for lossless transmission.
4101
4100
4102 Use --partial to ensure a changeset will be created from the patch
4101 Use --partial to ensure a changeset will be created from the patch
4103 even if some hunks fail to apply. Hunks that fail to apply will be
4102 even if some hunks fail to apply. Hunks that fail to apply will be
4104 written to a <target-file>.rej file. Conflicts can then be resolved
4103 written to a <target-file>.rej file. Conflicts can then be resolved
4105 by hand before :hg:`commit --amend` is run to update the created
4104 by hand before :hg:`commit --amend` is run to update the created
4106 changeset. This flag exists to let people import patches that
4105 changeset. This flag exists to let people import patches that
4107 partially apply without losing the associated metadata (author,
4106 partially apply without losing the associated metadata (author,
4108 date, description, ...).
4107 date, description, ...).
4109
4108
4110 .. note::
4109 .. note::
4111
4110
4112 When no hunks apply cleanly, :hg:`import --partial` will create
4111 When no hunks apply cleanly, :hg:`import --partial` will create
4113 an empty changeset, importing only the patch metadata.
4112 an empty changeset, importing only the patch metadata.
4114
4113
4115 With -s/--similarity, hg will attempt to discover renames and
4114 With -s/--similarity, hg will attempt to discover renames and
4116 copies in the patch in the same way as :hg:`addremove`.
4115 copies in the patch in the same way as :hg:`addremove`.
4117
4116
4118 It is possible to use external patch programs to perform the patch
4117 It is possible to use external patch programs to perform the patch
4119 by setting the ``ui.patch`` configuration option. For the default
4118 by setting the ``ui.patch`` configuration option. For the default
4120 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4119 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4121 See :hg:`help config` for more information about configuration
4120 See :hg:`help config` for more information about configuration
4122 files and how to use these options.
4121 files and how to use these options.
4123
4122
4124 See :hg:`help dates` for a list of formats valid for -d/--date.
4123 See :hg:`help dates` for a list of formats valid for -d/--date.
4125
4124
4126 .. container:: verbose
4125 .. container:: verbose
4127
4126
4128 Examples:
4127 Examples:
4129
4128
4130 - import a traditional patch from a website and detect renames::
4129 - import a traditional patch from a website and detect renames::
4131
4130
4132 hg import -s 80 http://example.com/bugfix.patch
4131 hg import -s 80 http://example.com/bugfix.patch
4133
4132
4134 - import a changeset from an hgweb server::
4133 - import a changeset from an hgweb server::
4135
4134
4136 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4135 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4137
4136
4138 - import all the patches in an Unix-style mbox::
4137 - import all the patches in an Unix-style mbox::
4139
4138
4140 hg import incoming-patches.mbox
4139 hg import incoming-patches.mbox
4141
4140
4142 - import patches from stdin::
4141 - import patches from stdin::
4143
4142
4144 hg import -
4143 hg import -
4145
4144
4146 - attempt to exactly restore an exported changeset (not always
4145 - attempt to exactly restore an exported changeset (not always
4147 possible)::
4146 possible)::
4148
4147
4149 hg import --exact proposed-fix.patch
4148 hg import --exact proposed-fix.patch
4150
4149
4151 - use an external tool to apply a patch which is too fuzzy for
4150 - use an external tool to apply a patch which is too fuzzy for
4152 the default internal tool.
4151 the default internal tool.
4153
4152
4154 hg import --config ui.patch="patch --merge" fuzzy.patch
4153 hg import --config ui.patch="patch --merge" fuzzy.patch
4155
4154
4156 - change the default fuzzing from 2 to a less strict 7
4155 - change the default fuzzing from 2 to a less strict 7
4157
4156
4158 hg import --config ui.fuzz=7 fuzz.patch
4157 hg import --config ui.fuzz=7 fuzz.patch
4159
4158
4160 Returns 0 on success, 1 on partial success (see --partial).
4159 Returns 0 on success, 1 on partial success (see --partial).
4161 """
4160 """
4162
4161
4163 opts = pycompat.byteskwargs(opts)
4162 opts = pycompat.byteskwargs(opts)
4164 if not patch1:
4163 if not patch1:
4165 raise error.Abort(_(b'need at least one patch to import'))
4164 raise error.Abort(_(b'need at least one patch to import'))
4166
4165
4167 patches = (patch1,) + patches
4166 patches = (patch1,) + patches
4168
4167
4169 date = opts.get(b'date')
4168 date = opts.get(b'date')
4170 if date:
4169 if date:
4171 opts[b'date'] = dateutil.parsedate(date)
4170 opts[b'date'] = dateutil.parsedate(date)
4172
4171
4173 exact = opts.get(b'exact')
4172 exact = opts.get(b'exact')
4174 update = not opts.get(b'bypass')
4173 update = not opts.get(b'bypass')
4175 if not update and opts.get(b'no_commit'):
4174 if not update and opts.get(b'no_commit'):
4176 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4175 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4177 if opts.get(b'secret') and opts.get(b'no_commit'):
4176 if opts.get(b'secret') and opts.get(b'no_commit'):
4178 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4177 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4179 try:
4178 try:
4180 sim = float(opts.get(b'similarity') or 0)
4179 sim = float(opts.get(b'similarity') or 0)
4181 except ValueError:
4180 except ValueError:
4182 raise error.Abort(_(b'similarity must be a number'))
4181 raise error.Abort(_(b'similarity must be a number'))
4183 if sim < 0 or sim > 100:
4182 if sim < 0 or sim > 100:
4184 raise error.Abort(_(b'similarity must be between 0 and 100'))
4183 raise error.Abort(_(b'similarity must be between 0 and 100'))
4185 if sim and not update:
4184 if sim and not update:
4186 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4185 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4187 if exact:
4186 if exact:
4188 if opts.get(b'edit'):
4187 if opts.get(b'edit'):
4189 raise error.Abort(_(b'cannot use --exact with --edit'))
4188 raise error.Abort(_(b'cannot use --exact with --edit'))
4190 if opts.get(b'prefix'):
4189 if opts.get(b'prefix'):
4191 raise error.Abort(_(b'cannot use --exact with --prefix'))
4190 raise error.Abort(_(b'cannot use --exact with --prefix'))
4192
4191
4193 base = opts[b"base"]
4192 base = opts[b"base"]
4194 msgs = []
4193 msgs = []
4195 ret = 0
4194 ret = 0
4196
4195
4197 with repo.wlock():
4196 with repo.wlock():
4198 if update:
4197 if update:
4199 cmdutil.checkunfinished(repo)
4198 cmdutil.checkunfinished(repo)
4200 if exact or not opts.get(b'force'):
4199 if exact or not opts.get(b'force'):
4201 cmdutil.bailifchanged(repo)
4200 cmdutil.bailifchanged(repo)
4202
4201
4203 if not opts.get(b'no_commit'):
4202 if not opts.get(b'no_commit'):
4204 lock = repo.lock
4203 lock = repo.lock
4205 tr = lambda: repo.transaction(b'import')
4204 tr = lambda: repo.transaction(b'import')
4206 dsguard = util.nullcontextmanager
4205 dsguard = util.nullcontextmanager
4207 else:
4206 else:
4208 lock = util.nullcontextmanager
4207 lock = util.nullcontextmanager
4209 tr = util.nullcontextmanager
4208 tr = util.nullcontextmanager
4210 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4209 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4211 with lock(), tr(), dsguard():
4210 with lock(), tr(), dsguard():
4212 parents = repo[None].parents()
4211 parents = repo[None].parents()
4213 for patchurl in patches:
4212 for patchurl in patches:
4214 if patchurl == b'-':
4213 if patchurl == b'-':
4215 ui.status(_(b'applying patch from stdin\n'))
4214 ui.status(_(b'applying patch from stdin\n'))
4216 patchfile = ui.fin
4215 patchfile = ui.fin
4217 patchurl = b'stdin' # for error message
4216 patchurl = b'stdin' # for error message
4218 else:
4217 else:
4219 patchurl = os.path.join(base, patchurl)
4218 patchurl = os.path.join(base, patchurl)
4220 ui.status(_(b'applying %s\n') % patchurl)
4219 ui.status(_(b'applying %s\n') % patchurl)
4221 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4220 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4222
4221
4223 haspatch = False
4222 haspatch = False
4224 for hunk in patch.split(patchfile):
4223 for hunk in patch.split(patchfile):
4225 with patch.extract(ui, hunk) as patchdata:
4224 with patch.extract(ui, hunk) as patchdata:
4226 msg, node, rej = cmdutil.tryimportone(
4225 msg, node, rej = cmdutil.tryimportone(
4227 ui, repo, patchdata, parents, opts, msgs, hg.clean
4226 ui, repo, patchdata, parents, opts, msgs, hg.clean
4228 )
4227 )
4229 if msg:
4228 if msg:
4230 haspatch = True
4229 haspatch = True
4231 ui.note(msg + b'\n')
4230 ui.note(msg + b'\n')
4232 if update or exact:
4231 if update or exact:
4233 parents = repo[None].parents()
4232 parents = repo[None].parents()
4234 else:
4233 else:
4235 parents = [repo[node]]
4234 parents = [repo[node]]
4236 if rej:
4235 if rej:
4237 ui.write_err(_(b"patch applied partially\n"))
4236 ui.write_err(_(b"patch applied partially\n"))
4238 ui.write_err(
4237 ui.write_err(
4239 _(
4238 _(
4240 b"(fix the .rej files and run "
4239 b"(fix the .rej files and run "
4241 b"`hg commit --amend`)\n"
4240 b"`hg commit --amend`)\n"
4242 )
4241 )
4243 )
4242 )
4244 ret = 1
4243 ret = 1
4245 break
4244 break
4246
4245
4247 if not haspatch:
4246 if not haspatch:
4248 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4247 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4249
4248
4250 if msgs:
4249 if msgs:
4251 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4250 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4252 return ret
4251 return ret
4253
4252
4254
4253
4255 @command(
4254 @command(
4256 b'incoming|in',
4255 b'incoming|in',
4257 [
4256 [
4258 (
4257 (
4259 b'f',
4258 b'f',
4260 b'force',
4259 b'force',
4261 None,
4260 None,
4262 _(b'run even if remote repository is unrelated'),
4261 _(b'run even if remote repository is unrelated'),
4263 ),
4262 ),
4264 (b'n', b'newest-first', None, _(b'show newest record first')),
4263 (b'n', b'newest-first', None, _(b'show newest record first')),
4265 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4264 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4266 (
4265 (
4267 b'r',
4266 b'r',
4268 b'rev',
4267 b'rev',
4269 [],
4268 [],
4270 _(b'a remote changeset intended to be added'),
4269 _(b'a remote changeset intended to be added'),
4271 _(b'REV'),
4270 _(b'REV'),
4272 ),
4271 ),
4273 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4272 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4274 (
4273 (
4275 b'b',
4274 b'b',
4276 b'branch',
4275 b'branch',
4277 [],
4276 [],
4278 _(b'a specific branch you would like to pull'),
4277 _(b'a specific branch you would like to pull'),
4279 _(b'BRANCH'),
4278 _(b'BRANCH'),
4280 ),
4279 ),
4281 ]
4280 ]
4282 + logopts
4281 + logopts
4283 + remoteopts
4282 + remoteopts
4284 + subrepoopts,
4283 + subrepoopts,
4285 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4284 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4286 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4285 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4287 )
4286 )
4288 def incoming(ui, repo, source=b"default", **opts):
4287 def incoming(ui, repo, source=b"default", **opts):
4289 """show new changesets found in source
4288 """show new changesets found in source
4290
4289
4291 Show new changesets found in the specified path/URL or the default
4290 Show new changesets found in the specified path/URL or the default
4292 pull location. These are the changesets that would have been pulled
4291 pull location. These are the changesets that would have been pulled
4293 by :hg:`pull` at the time you issued this command.
4292 by :hg:`pull` at the time you issued this command.
4294
4293
4295 See pull for valid source format details.
4294 See pull for valid source format details.
4296
4295
4297 .. container:: verbose
4296 .. container:: verbose
4298
4297
4299 With -B/--bookmarks, the result of bookmark comparison between
4298 With -B/--bookmarks, the result of bookmark comparison between
4300 local and remote repositories is displayed. With -v/--verbose,
4299 local and remote repositories is displayed. With -v/--verbose,
4301 status is also displayed for each bookmark like below::
4300 status is also displayed for each bookmark like below::
4302
4301
4303 BM1 01234567890a added
4302 BM1 01234567890a added
4304 BM2 1234567890ab advanced
4303 BM2 1234567890ab advanced
4305 BM3 234567890abc diverged
4304 BM3 234567890abc diverged
4306 BM4 34567890abcd changed
4305 BM4 34567890abcd changed
4307
4306
4308 The action taken locally when pulling depends on the
4307 The action taken locally when pulling depends on the
4309 status of each bookmark:
4308 status of each bookmark:
4310
4309
4311 :``added``: pull will create it
4310 :``added``: pull will create it
4312 :``advanced``: pull will update it
4311 :``advanced``: pull will update it
4313 :``diverged``: pull will create a divergent bookmark
4312 :``diverged``: pull will create a divergent bookmark
4314 :``changed``: result depends on remote changesets
4313 :``changed``: result depends on remote changesets
4315
4314
4316 From the point of view of pulling behavior, bookmark
4315 From the point of view of pulling behavior, bookmark
4317 existing only in the remote repository are treated as ``added``,
4316 existing only in the remote repository are treated as ``added``,
4318 even if it is in fact locally deleted.
4317 even if it is in fact locally deleted.
4319
4318
4320 .. container:: verbose
4319 .. container:: verbose
4321
4320
4322 For remote repository, using --bundle avoids downloading the
4321 For remote repository, using --bundle avoids downloading the
4323 changesets twice if the incoming is followed by a pull.
4322 changesets twice if the incoming is followed by a pull.
4324
4323
4325 Examples:
4324 Examples:
4326
4325
4327 - show incoming changes with patches and full description::
4326 - show incoming changes with patches and full description::
4328
4327
4329 hg incoming -vp
4328 hg incoming -vp
4330
4329
4331 - show incoming changes excluding merges, store a bundle::
4330 - show incoming changes excluding merges, store a bundle::
4332
4331
4333 hg in -vpM --bundle incoming.hg
4332 hg in -vpM --bundle incoming.hg
4334 hg pull incoming.hg
4333 hg pull incoming.hg
4335
4334
4336 - briefly list changes inside a bundle::
4335 - briefly list changes inside a bundle::
4337
4336
4338 hg in changes.hg -T "{desc|firstline}\\n"
4337 hg in changes.hg -T "{desc|firstline}\\n"
4339
4338
4340 Returns 0 if there are incoming changes, 1 otherwise.
4339 Returns 0 if there are incoming changes, 1 otherwise.
4341 """
4340 """
4342 opts = pycompat.byteskwargs(opts)
4341 opts = pycompat.byteskwargs(opts)
4343 if opts.get(b'graph'):
4342 if opts.get(b'graph'):
4344 logcmdutil.checkunsupportedgraphflags([], opts)
4343 logcmdutil.checkunsupportedgraphflags([], opts)
4345
4344
4346 def display(other, chlist, displayer):
4345 def display(other, chlist, displayer):
4347 revdag = logcmdutil.graphrevs(other, chlist, opts)
4346 revdag = logcmdutil.graphrevs(other, chlist, opts)
4348 logcmdutil.displaygraph(
4347 logcmdutil.displaygraph(
4349 ui, repo, revdag, displayer, graphmod.asciiedges
4348 ui, repo, revdag, displayer, graphmod.asciiedges
4350 )
4349 )
4351
4350
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4351 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4353 return 0
4352 return 0
4354
4353
4355 if opts.get(b'bundle') and opts.get(b'subrepos'):
4354 if opts.get(b'bundle') and opts.get(b'subrepos'):
4356 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4355 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4357
4356
4358 if opts.get(b'bookmarks'):
4357 if opts.get(b'bookmarks'):
4359 source, branches = hg.parseurl(
4358 source, branches = hg.parseurl(
4360 ui.expandpath(source), opts.get(b'branch')
4359 ui.expandpath(source), opts.get(b'branch')
4361 )
4360 )
4362 other = hg.peer(repo, opts, source)
4361 other = hg.peer(repo, opts, source)
4363 if b'bookmarks' not in other.listkeys(b'namespaces'):
4362 if b'bookmarks' not in other.listkeys(b'namespaces'):
4364 ui.warn(_(b"remote doesn't support bookmarks\n"))
4363 ui.warn(_(b"remote doesn't support bookmarks\n"))
4365 return 0
4364 return 0
4366 ui.pager(b'incoming')
4365 ui.pager(b'incoming')
4367 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4366 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4368 return bookmarks.incoming(ui, repo, other)
4367 return bookmarks.incoming(ui, repo, other)
4369
4368
4370 repo._subtoppath = ui.expandpath(source)
4369 repo._subtoppath = ui.expandpath(source)
4371 try:
4370 try:
4372 return hg.incoming(ui, repo, source, opts)
4371 return hg.incoming(ui, repo, source, opts)
4373 finally:
4372 finally:
4374 del repo._subtoppath
4373 del repo._subtoppath
4375
4374
4376
4375
4377 @command(
4376 @command(
4378 b'init',
4377 b'init',
4379 remoteopts,
4378 remoteopts,
4380 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4379 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4381 helpcategory=command.CATEGORY_REPO_CREATION,
4380 helpcategory=command.CATEGORY_REPO_CREATION,
4382 helpbasic=True,
4381 helpbasic=True,
4383 norepo=True,
4382 norepo=True,
4384 )
4383 )
4385 def init(ui, dest=b".", **opts):
4384 def init(ui, dest=b".", **opts):
4386 """create a new repository in the given directory
4385 """create a new repository in the given directory
4387
4386
4388 Initialize a new repository in the given directory. If the given
4387 Initialize a new repository in the given directory. If the given
4389 directory does not exist, it will be created.
4388 directory does not exist, it will be created.
4390
4389
4391 If no directory is given, the current directory is used.
4390 If no directory is given, the current directory is used.
4392
4391
4393 It is possible to specify an ``ssh://`` URL as the destination.
4392 It is possible to specify an ``ssh://`` URL as the destination.
4394 See :hg:`help urls` for more information.
4393 See :hg:`help urls` for more information.
4395
4394
4396 Returns 0 on success.
4395 Returns 0 on success.
4397 """
4396 """
4398 opts = pycompat.byteskwargs(opts)
4397 opts = pycompat.byteskwargs(opts)
4399 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4398 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4400
4399
4401
4400
4402 @command(
4401 @command(
4403 b'locate',
4402 b'locate',
4404 [
4403 [
4405 (
4404 (
4406 b'r',
4405 b'r',
4407 b'rev',
4406 b'rev',
4408 b'',
4407 b'',
4409 _(b'search the repository as it is in REV'),
4408 _(b'search the repository as it is in REV'),
4410 _(b'REV'),
4409 _(b'REV'),
4411 ),
4410 ),
4412 (
4411 (
4413 b'0',
4412 b'0',
4414 b'print0',
4413 b'print0',
4415 None,
4414 None,
4416 _(b'end filenames with NUL, for use with xargs'),
4415 _(b'end filenames with NUL, for use with xargs'),
4417 ),
4416 ),
4418 (
4417 (
4419 b'f',
4418 b'f',
4420 b'fullpath',
4419 b'fullpath',
4421 None,
4420 None,
4422 _(b'print complete paths from the filesystem root'),
4421 _(b'print complete paths from the filesystem root'),
4423 ),
4422 ),
4424 ]
4423 ]
4425 + walkopts,
4424 + walkopts,
4426 _(b'[OPTION]... [PATTERN]...'),
4425 _(b'[OPTION]... [PATTERN]...'),
4427 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4426 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4428 )
4427 )
4429 def locate(ui, repo, *pats, **opts):
4428 def locate(ui, repo, *pats, **opts):
4430 """locate files matching specific patterns (DEPRECATED)
4429 """locate files matching specific patterns (DEPRECATED)
4431
4430
4432 Print files under Mercurial control in the working directory whose
4431 Print files under Mercurial control in the working directory whose
4433 names match the given patterns.
4432 names match the given patterns.
4434
4433
4435 By default, this command searches all directories in the working
4434 By default, this command searches all directories in the working
4436 directory. To search just the current directory and its
4435 directory. To search just the current directory and its
4437 subdirectories, use "--include .".
4436 subdirectories, use "--include .".
4438
4437
4439 If no patterns are given to match, this command prints the names
4438 If no patterns are given to match, this command prints the names
4440 of all files under Mercurial control in the working directory.
4439 of all files under Mercurial control in the working directory.
4441
4440
4442 If you want to feed the output of this command into the "xargs"
4441 If you want to feed the output of this command into the "xargs"
4443 command, use the -0 option to both this command and "xargs". This
4442 command, use the -0 option to both this command and "xargs". This
4444 will avoid the problem of "xargs" treating single filenames that
4443 will avoid the problem of "xargs" treating single filenames that
4445 contain whitespace as multiple filenames.
4444 contain whitespace as multiple filenames.
4446
4445
4447 See :hg:`help files` for a more versatile command.
4446 See :hg:`help files` for a more versatile command.
4448
4447
4449 Returns 0 if a match is found, 1 otherwise.
4448 Returns 0 if a match is found, 1 otherwise.
4450 """
4449 """
4451 opts = pycompat.byteskwargs(opts)
4450 opts = pycompat.byteskwargs(opts)
4452 if opts.get(b'print0'):
4451 if opts.get(b'print0'):
4453 end = b'\0'
4452 end = b'\0'
4454 else:
4453 else:
4455 end = b'\n'
4454 end = b'\n'
4456 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4455 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4457
4456
4458 ret = 1
4457 ret = 1
4459 m = scmutil.match(
4458 m = scmutil.match(
4460 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4459 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4461 )
4460 )
4462
4461
4463 ui.pager(b'locate')
4462 ui.pager(b'locate')
4464 if ctx.rev() is None:
4463 if ctx.rev() is None:
4465 # When run on the working copy, "locate" includes removed files, so
4464 # When run on the working copy, "locate" includes removed files, so
4466 # we get the list of files from the dirstate.
4465 # we get the list of files from the dirstate.
4467 filesgen = sorted(repo.dirstate.matches(m))
4466 filesgen = sorted(repo.dirstate.matches(m))
4468 else:
4467 else:
4469 filesgen = ctx.matches(m)
4468 filesgen = ctx.matches(m)
4470 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4469 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4471 for abs in filesgen:
4470 for abs in filesgen:
4472 if opts.get(b'fullpath'):
4471 if opts.get(b'fullpath'):
4473 ui.write(repo.wjoin(abs), end)
4472 ui.write(repo.wjoin(abs), end)
4474 else:
4473 else:
4475 ui.write(uipathfn(abs), end)
4474 ui.write(uipathfn(abs), end)
4476 ret = 0
4475 ret = 0
4477
4476
4478 return ret
4477 return ret
4479
4478
4480
4479
4481 @command(
4480 @command(
4482 b'log|history',
4481 b'log|history',
4483 [
4482 [
4484 (
4483 (
4485 b'f',
4484 b'f',
4486 b'follow',
4485 b'follow',
4487 None,
4486 None,
4488 _(
4487 _(
4489 b'follow changeset history, or file history across copies and renames'
4488 b'follow changeset history, or file history across copies and renames'
4490 ),
4489 ),
4491 ),
4490 ),
4492 (
4491 (
4493 b'',
4492 b'',
4494 b'follow-first',
4493 b'follow-first',
4495 None,
4494 None,
4496 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4495 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4497 ),
4496 ),
4498 (
4497 (
4499 b'd',
4498 b'd',
4500 b'date',
4499 b'date',
4501 b'',
4500 b'',
4502 _(b'show revisions matching date spec'),
4501 _(b'show revisions matching date spec'),
4503 _(b'DATE'),
4502 _(b'DATE'),
4504 ),
4503 ),
4505 (b'C', b'copies', None, _(b'show copied files')),
4504 (b'C', b'copies', None, _(b'show copied files')),
4506 (
4505 (
4507 b'k',
4506 b'k',
4508 b'keyword',
4507 b'keyword',
4509 [],
4508 [],
4510 _(b'do case-insensitive search for a given text'),
4509 _(b'do case-insensitive search for a given text'),
4511 _(b'TEXT'),
4510 _(b'TEXT'),
4512 ),
4511 ),
4513 (
4512 (
4514 b'r',
4513 b'r',
4515 b'rev',
4514 b'rev',
4516 [],
4515 [],
4517 _(b'show the specified revision or revset'),
4516 _(b'show the specified revision or revset'),
4518 _(b'REV'),
4517 _(b'REV'),
4519 ),
4518 ),
4520 (
4519 (
4521 b'L',
4520 b'L',
4522 b'line-range',
4521 b'line-range',
4523 [],
4522 [],
4524 _(b'follow line range of specified file (EXPERIMENTAL)'),
4523 _(b'follow line range of specified file (EXPERIMENTAL)'),
4525 _(b'FILE,RANGE'),
4524 _(b'FILE,RANGE'),
4526 ),
4525 ),
4527 (
4526 (
4528 b'',
4527 b'',
4529 b'removed',
4528 b'removed',
4530 None,
4529 None,
4531 _(b'include revisions where files were removed'),
4530 _(b'include revisions where files were removed'),
4532 ),
4531 ),
4533 (
4532 (
4534 b'm',
4533 b'm',
4535 b'only-merges',
4534 b'only-merges',
4536 None,
4535 None,
4537 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4536 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4538 ),
4537 ),
4539 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4538 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4540 (
4539 (
4541 b'',
4540 b'',
4542 b'only-branch',
4541 b'only-branch',
4543 [],
4542 [],
4544 _(
4543 _(
4545 b'show only changesets within the given named branch (DEPRECATED)'
4544 b'show only changesets within the given named branch (DEPRECATED)'
4546 ),
4545 ),
4547 _(b'BRANCH'),
4546 _(b'BRANCH'),
4548 ),
4547 ),
4549 (
4548 (
4550 b'b',
4549 b'b',
4551 b'branch',
4550 b'branch',
4552 [],
4551 [],
4553 _(b'show changesets within the given named branch'),
4552 _(b'show changesets within the given named branch'),
4554 _(b'BRANCH'),
4553 _(b'BRANCH'),
4555 ),
4554 ),
4556 (
4555 (
4557 b'P',
4556 b'P',
4558 b'prune',
4557 b'prune',
4559 [],
4558 [],
4560 _(b'do not display revision or any of its ancestors'),
4559 _(b'do not display revision or any of its ancestors'),
4561 _(b'REV'),
4560 _(b'REV'),
4562 ),
4561 ),
4563 ]
4562 ]
4564 + logopts
4563 + logopts
4565 + walkopts,
4564 + walkopts,
4566 _(b'[OPTION]... [FILE]'),
4565 _(b'[OPTION]... [FILE]'),
4567 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4566 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4568 helpbasic=True,
4567 helpbasic=True,
4569 inferrepo=True,
4568 inferrepo=True,
4570 intents={INTENT_READONLY},
4569 intents={INTENT_READONLY},
4571 )
4570 )
4572 def log(ui, repo, *pats, **opts):
4571 def log(ui, repo, *pats, **opts):
4573 """show revision history of entire repository or files
4572 """show revision history of entire repository or files
4574
4573
4575 Print the revision history of the specified files or the entire
4574 Print the revision history of the specified files or the entire
4576 project.
4575 project.
4577
4576
4578 If no revision range is specified, the default is ``tip:0`` unless
4577 If no revision range is specified, the default is ``tip:0`` unless
4579 --follow is set, in which case the working directory parent is
4578 --follow is set, in which case the working directory parent is
4580 used as the starting revision.
4579 used as the starting revision.
4581
4580
4582 File history is shown without following rename or copy history of
4581 File history is shown without following rename or copy history of
4583 files. Use -f/--follow with a filename to follow history across
4582 files. Use -f/--follow with a filename to follow history across
4584 renames and copies. --follow without a filename will only show
4583 renames and copies. --follow without a filename will only show
4585 ancestors of the starting revision.
4584 ancestors of the starting revision.
4586
4585
4587 By default this command prints revision number and changeset id,
4586 By default this command prints revision number and changeset id,
4588 tags, non-trivial parents, user, date and time, and a summary for
4587 tags, non-trivial parents, user, date and time, and a summary for
4589 each commit. When the -v/--verbose switch is used, the list of
4588 each commit. When the -v/--verbose switch is used, the list of
4590 changed files and full commit message are shown.
4589 changed files and full commit message are shown.
4591
4590
4592 With --graph the revisions are shown as an ASCII art DAG with the most
4591 With --graph the revisions are shown as an ASCII art DAG with the most
4593 recent changeset at the top.
4592 recent changeset at the top.
4594 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4593 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4595 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4594 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4596 changeset from the lines below is a parent of the 'o' merge on the same
4595 changeset from the lines below is a parent of the 'o' merge on the same
4597 line.
4596 line.
4598 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4597 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4599 of a '|' indicates one or more revisions in a path are omitted.
4598 of a '|' indicates one or more revisions in a path are omitted.
4600
4599
4601 .. container:: verbose
4600 .. container:: verbose
4602
4601
4603 Use -L/--line-range FILE,M:N options to follow the history of lines
4602 Use -L/--line-range FILE,M:N options to follow the history of lines
4604 from M to N in FILE. With -p/--patch only diff hunks affecting
4603 from M to N in FILE. With -p/--patch only diff hunks affecting
4605 specified line range will be shown. This option requires --follow;
4604 specified line range will be shown. This option requires --follow;
4606 it can be specified multiple times. Currently, this option is not
4605 it can be specified multiple times. Currently, this option is not
4607 compatible with --graph. This option is experimental.
4606 compatible with --graph. This option is experimental.
4608
4607
4609 .. note::
4608 .. note::
4610
4609
4611 :hg:`log --patch` may generate unexpected diff output for merge
4610 :hg:`log --patch` may generate unexpected diff output for merge
4612 changesets, as it will only compare the merge changeset against
4611 changesets, as it will only compare the merge changeset against
4613 its first parent. Also, only files different from BOTH parents
4612 its first parent. Also, only files different from BOTH parents
4614 will appear in files:.
4613 will appear in files:.
4615
4614
4616 .. note::
4615 .. note::
4617
4616
4618 For performance reasons, :hg:`log FILE` may omit duplicate changes
4617 For performance reasons, :hg:`log FILE` may omit duplicate changes
4619 made on branches and will not show removals or mode changes. To
4618 made on branches and will not show removals or mode changes. To
4620 see all such changes, use the --removed switch.
4619 see all such changes, use the --removed switch.
4621
4620
4622 .. container:: verbose
4621 .. container:: verbose
4623
4622
4624 .. note::
4623 .. note::
4625
4624
4626 The history resulting from -L/--line-range options depends on diff
4625 The history resulting from -L/--line-range options depends on diff
4627 options; for instance if white-spaces are ignored, respective changes
4626 options; for instance if white-spaces are ignored, respective changes
4628 with only white-spaces in specified line range will not be listed.
4627 with only white-spaces in specified line range will not be listed.
4629
4628
4630 .. container:: verbose
4629 .. container:: verbose
4631
4630
4632 Some examples:
4631 Some examples:
4633
4632
4634 - changesets with full descriptions and file lists::
4633 - changesets with full descriptions and file lists::
4635
4634
4636 hg log -v
4635 hg log -v
4637
4636
4638 - changesets ancestral to the working directory::
4637 - changesets ancestral to the working directory::
4639
4638
4640 hg log -f
4639 hg log -f
4641
4640
4642 - last 10 commits on the current branch::
4641 - last 10 commits on the current branch::
4643
4642
4644 hg log -l 10 -b .
4643 hg log -l 10 -b .
4645
4644
4646 - changesets showing all modifications of a file, including removals::
4645 - changesets showing all modifications of a file, including removals::
4647
4646
4648 hg log --removed file.c
4647 hg log --removed file.c
4649
4648
4650 - all changesets that touch a directory, with diffs, excluding merges::
4649 - all changesets that touch a directory, with diffs, excluding merges::
4651
4650
4652 hg log -Mp lib/
4651 hg log -Mp lib/
4653
4652
4654 - all revision numbers that match a keyword::
4653 - all revision numbers that match a keyword::
4655
4654
4656 hg log -k bug --template "{rev}\\n"
4655 hg log -k bug --template "{rev}\\n"
4657
4656
4658 - the full hash identifier of the working directory parent::
4657 - the full hash identifier of the working directory parent::
4659
4658
4660 hg log -r . --template "{node}\\n"
4659 hg log -r . --template "{node}\\n"
4661
4660
4662 - list available log templates::
4661 - list available log templates::
4663
4662
4664 hg log -T list
4663 hg log -T list
4665
4664
4666 - check if a given changeset is included in a tagged release::
4665 - check if a given changeset is included in a tagged release::
4667
4666
4668 hg log -r "a21ccf and ancestor(1.9)"
4667 hg log -r "a21ccf and ancestor(1.9)"
4669
4668
4670 - find all changesets by some user in a date range::
4669 - find all changesets by some user in a date range::
4671
4670
4672 hg log -k alice -d "may 2008 to jul 2008"
4671 hg log -k alice -d "may 2008 to jul 2008"
4673
4672
4674 - summary of all changesets after the last tag::
4673 - summary of all changesets after the last tag::
4675
4674
4676 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4675 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4677
4676
4678 - changesets touching lines 13 to 23 for file.c::
4677 - changesets touching lines 13 to 23 for file.c::
4679
4678
4680 hg log -L file.c,13:23
4679 hg log -L file.c,13:23
4681
4680
4682 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4681 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4683 main.c with patch::
4682 main.c with patch::
4684
4683
4685 hg log -L file.c,13:23 -L main.c,2:6 -p
4684 hg log -L file.c,13:23 -L main.c,2:6 -p
4686
4685
4687 See :hg:`help dates` for a list of formats valid for -d/--date.
4686 See :hg:`help dates` for a list of formats valid for -d/--date.
4688
4687
4689 See :hg:`help revisions` for more about specifying and ordering
4688 See :hg:`help revisions` for more about specifying and ordering
4690 revisions.
4689 revisions.
4691
4690
4692 See :hg:`help templates` for more about pre-packaged styles and
4691 See :hg:`help templates` for more about pre-packaged styles and
4693 specifying custom templates. The default template used by the log
4692 specifying custom templates. The default template used by the log
4694 command can be customized via the ``ui.logtemplate`` configuration
4693 command can be customized via the ``ui.logtemplate`` configuration
4695 setting.
4694 setting.
4696
4695
4697 Returns 0 on success.
4696 Returns 0 on success.
4698
4697
4699 """
4698 """
4700 opts = pycompat.byteskwargs(opts)
4699 opts = pycompat.byteskwargs(opts)
4701 linerange = opts.get(b'line_range')
4700 linerange = opts.get(b'line_range')
4702
4701
4703 if linerange and not opts.get(b'follow'):
4702 if linerange and not opts.get(b'follow'):
4704 raise error.Abort(_(b'--line-range requires --follow'))
4703 raise error.Abort(_(b'--line-range requires --follow'))
4705
4704
4706 if linerange and pats:
4705 if linerange and pats:
4707 # TODO: take pats as patterns with no line-range filter
4706 # TODO: take pats as patterns with no line-range filter
4708 raise error.Abort(
4707 raise error.Abort(
4709 _(b'FILE arguments are not compatible with --line-range option')
4708 _(b'FILE arguments are not compatible with --line-range option')
4710 )
4709 )
4711
4710
4712 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4711 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4713 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4712 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4714 if linerange:
4713 if linerange:
4715 # TODO: should follow file history from logcmdutil._initialrevs(),
4714 # TODO: should follow file history from logcmdutil._initialrevs(),
4716 # then filter the result by logcmdutil._makerevset() and --limit
4715 # then filter the result by logcmdutil._makerevset() and --limit
4717 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4716 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4718
4717
4719 getcopies = None
4718 getcopies = None
4720 if opts.get(b'copies'):
4719 if opts.get(b'copies'):
4721 endrev = None
4720 endrev = None
4722 if revs:
4721 if revs:
4723 endrev = revs.max() + 1
4722 endrev = revs.max() + 1
4724 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4723 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4725
4724
4726 ui.pager(b'log')
4725 ui.pager(b'log')
4727 displayer = logcmdutil.changesetdisplayer(
4726 displayer = logcmdutil.changesetdisplayer(
4728 ui, repo, opts, differ, buffered=True
4727 ui, repo, opts, differ, buffered=True
4729 )
4728 )
4730 if opts.get(b'graph'):
4729 if opts.get(b'graph'):
4731 displayfn = logcmdutil.displaygraphrevs
4730 displayfn = logcmdutil.displaygraphrevs
4732 else:
4731 else:
4733 displayfn = logcmdutil.displayrevs
4732 displayfn = logcmdutil.displayrevs
4734 displayfn(ui, repo, revs, displayer, getcopies)
4733 displayfn(ui, repo, revs, displayer, getcopies)
4735
4734
4736
4735
4737 @command(
4736 @command(
4738 b'manifest',
4737 b'manifest',
4739 [
4738 [
4740 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4739 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4741 (b'', b'all', False, _(b"list files from all revisions")),
4740 (b'', b'all', False, _(b"list files from all revisions")),
4742 ]
4741 ]
4743 + formatteropts,
4742 + formatteropts,
4744 _(b'[-r REV]'),
4743 _(b'[-r REV]'),
4745 helpcategory=command.CATEGORY_MAINTENANCE,
4744 helpcategory=command.CATEGORY_MAINTENANCE,
4746 intents={INTENT_READONLY},
4745 intents={INTENT_READONLY},
4747 )
4746 )
4748 def manifest(ui, repo, node=None, rev=None, **opts):
4747 def manifest(ui, repo, node=None, rev=None, **opts):
4749 """output the current or given revision of the project manifest
4748 """output the current or given revision of the project manifest
4750
4749
4751 Print a list of version controlled files for the given revision.
4750 Print a list of version controlled files for the given revision.
4752 If no revision is given, the first parent of the working directory
4751 If no revision is given, the first parent of the working directory
4753 is used, or the null revision if no revision is checked out.
4752 is used, or the null revision if no revision is checked out.
4754
4753
4755 With -v, print file permissions, symlink and executable bits.
4754 With -v, print file permissions, symlink and executable bits.
4756 With --debug, print file revision hashes.
4755 With --debug, print file revision hashes.
4757
4756
4758 If option --all is specified, the list of all files from all revisions
4757 If option --all is specified, the list of all files from all revisions
4759 is printed. This includes deleted and renamed files.
4758 is printed. This includes deleted and renamed files.
4760
4759
4761 Returns 0 on success.
4760 Returns 0 on success.
4762 """
4761 """
4763 opts = pycompat.byteskwargs(opts)
4762 opts = pycompat.byteskwargs(opts)
4764 fm = ui.formatter(b'manifest', opts)
4763 fm = ui.formatter(b'manifest', opts)
4765
4764
4766 if opts.get(b'all'):
4765 if opts.get(b'all'):
4767 if rev or node:
4766 if rev or node:
4768 raise error.Abort(_(b"can't specify a revision with --all"))
4767 raise error.Abort(_(b"can't specify a revision with --all"))
4769
4768
4770 res = set()
4769 res = set()
4771 for rev in repo:
4770 for rev in repo:
4772 ctx = repo[rev]
4771 ctx = repo[rev]
4773 res |= set(ctx.files())
4772 res |= set(ctx.files())
4774
4773
4775 ui.pager(b'manifest')
4774 ui.pager(b'manifest')
4776 for f in sorted(res):
4775 for f in sorted(res):
4777 fm.startitem()
4776 fm.startitem()
4778 fm.write(b"path", b'%s\n', f)
4777 fm.write(b"path", b'%s\n', f)
4779 fm.end()
4778 fm.end()
4780 return
4779 return
4781
4780
4782 if rev and node:
4781 if rev and node:
4783 raise error.Abort(_(b"please specify just one revision"))
4782 raise error.Abort(_(b"please specify just one revision"))
4784
4783
4785 if not node:
4784 if not node:
4786 node = rev
4785 node = rev
4787
4786
4788 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4787 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4789 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4788 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4790 if node:
4789 if node:
4791 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4790 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4792 ctx = scmutil.revsingle(repo, node)
4791 ctx = scmutil.revsingle(repo, node)
4793 mf = ctx.manifest()
4792 mf = ctx.manifest()
4794 ui.pager(b'manifest')
4793 ui.pager(b'manifest')
4795 for f in ctx:
4794 for f in ctx:
4796 fm.startitem()
4795 fm.startitem()
4797 fm.context(ctx=ctx)
4796 fm.context(ctx=ctx)
4798 fl = ctx[f].flags()
4797 fl = ctx[f].flags()
4799 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4798 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4800 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4799 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4801 fm.write(b'path', b'%s\n', f)
4800 fm.write(b'path', b'%s\n', f)
4802 fm.end()
4801 fm.end()
4803
4802
4804
4803
4805 @command(
4804 @command(
4806 b'merge',
4805 b'merge',
4807 [
4806 [
4808 (
4807 (
4809 b'f',
4808 b'f',
4810 b'force',
4809 b'force',
4811 None,
4810 None,
4812 _(b'force a merge including outstanding changes (DEPRECATED)'),
4811 _(b'force a merge including outstanding changes (DEPRECATED)'),
4813 ),
4812 ),
4814 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4813 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4815 (
4814 (
4816 b'P',
4815 b'P',
4817 b'preview',
4816 b'preview',
4818 None,
4817 None,
4819 _(b'review revisions to merge (no merge is performed)'),
4818 _(b'review revisions to merge (no merge is performed)'),
4820 ),
4819 ),
4821 (b'', b'abort', None, _(b'abort the ongoing merge')),
4820 (b'', b'abort', None, _(b'abort the ongoing merge')),
4822 ]
4821 ]
4823 + mergetoolopts,
4822 + mergetoolopts,
4824 _(b'[-P] [[-r] REV]'),
4823 _(b'[-P] [[-r] REV]'),
4825 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4824 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4826 helpbasic=True,
4825 helpbasic=True,
4827 )
4826 )
4828 def merge(ui, repo, node=None, **opts):
4827 def merge(ui, repo, node=None, **opts):
4829 """merge another revision into working directory
4828 """merge another revision into working directory
4830
4829
4831 The current working directory is updated with all changes made in
4830 The current working directory is updated with all changes made in
4832 the requested revision since the last common predecessor revision.
4831 the requested revision since the last common predecessor revision.
4833
4832
4834 Files that changed between either parent are marked as changed for
4833 Files that changed between either parent are marked as changed for
4835 the next commit and a commit must be performed before any further
4834 the next commit and a commit must be performed before any further
4836 updates to the repository are allowed. The next commit will have
4835 updates to the repository are allowed. The next commit will have
4837 two parents.
4836 two parents.
4838
4837
4839 ``--tool`` can be used to specify the merge tool used for file
4838 ``--tool`` can be used to specify the merge tool used for file
4840 merges. It overrides the HGMERGE environment variable and your
4839 merges. It overrides the HGMERGE environment variable and your
4841 configuration files. See :hg:`help merge-tools` for options.
4840 configuration files. See :hg:`help merge-tools` for options.
4842
4841
4843 If no revision is specified, the working directory's parent is a
4842 If no revision is specified, the working directory's parent is a
4844 head revision, and the current branch contains exactly one other
4843 head revision, and the current branch contains exactly one other
4845 head, the other head is merged with by default. Otherwise, an
4844 head, the other head is merged with by default. Otherwise, an
4846 explicit revision with which to merge must be provided.
4845 explicit revision with which to merge must be provided.
4847
4846
4848 See :hg:`help resolve` for information on handling file conflicts.
4847 See :hg:`help resolve` for information on handling file conflicts.
4849
4848
4850 To undo an uncommitted merge, use :hg:`merge --abort` which
4849 To undo an uncommitted merge, use :hg:`merge --abort` which
4851 will check out a clean copy of the original merge parent, losing
4850 will check out a clean copy of the original merge parent, losing
4852 all changes.
4851 all changes.
4853
4852
4854 Returns 0 on success, 1 if there are unresolved files.
4853 Returns 0 on success, 1 if there are unresolved files.
4855 """
4854 """
4856
4855
4857 opts = pycompat.byteskwargs(opts)
4856 opts = pycompat.byteskwargs(opts)
4858 abort = opts.get(b'abort')
4857 abort = opts.get(b'abort')
4859 if abort and repo.dirstate.p2() == nullid:
4858 if abort and repo.dirstate.p2() == nullid:
4860 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4859 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4861 if abort:
4860 if abort:
4862 state = cmdutil.getunfinishedstate(repo)
4861 state = cmdutil.getunfinishedstate(repo)
4863 if state and state._opname != b'merge':
4862 if state and state._opname != b'merge':
4864 raise error.Abort(
4863 raise error.Abort(
4865 _(b'cannot abort merge with %s in progress') % (state._opname),
4864 _(b'cannot abort merge with %s in progress') % (state._opname),
4866 hint=state.hint(),
4865 hint=state.hint(),
4867 )
4866 )
4868 if node:
4867 if node:
4869 raise error.Abort(_(b"cannot specify a node with --abort"))
4868 raise error.Abort(_(b"cannot specify a node with --abort"))
4870 if opts.get(b'rev'):
4869 if opts.get(b'rev'):
4871 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4870 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4872 if opts.get(b'preview'):
4871 if opts.get(b'preview'):
4873 raise error.Abort(_(b"cannot specify --preview with --abort"))
4872 raise error.Abort(_(b"cannot specify --preview with --abort"))
4874 if opts.get(b'rev') and node:
4873 if opts.get(b'rev') and node:
4875 raise error.Abort(_(b"please specify just one revision"))
4874 raise error.Abort(_(b"please specify just one revision"))
4876 if not node:
4875 if not node:
4877 node = opts.get(b'rev')
4876 node = opts.get(b'rev')
4878
4877
4879 if node:
4878 if node:
4880 node = scmutil.revsingle(repo, node).node()
4879 node = scmutil.revsingle(repo, node).node()
4881
4880
4882 if not node and not abort:
4881 if not node and not abort:
4883 if ui.configbool(b'commands', b'merge.require-rev'):
4882 if ui.configbool(b'commands', b'merge.require-rev'):
4884 raise error.Abort(
4883 raise error.Abort(
4885 _(
4884 _(
4886 b'configuration requires specifying revision to merge '
4885 b'configuration requires specifying revision to merge '
4887 b'with'
4886 b'with'
4888 )
4887 )
4889 )
4888 )
4890 node = repo[destutil.destmerge(repo)].node()
4889 node = repo[destutil.destmerge(repo)].node()
4891
4890
4892 if opts.get(b'preview'):
4891 if opts.get(b'preview'):
4893 # find nodes that are ancestors of p2 but not of p1
4892 # find nodes that are ancestors of p2 but not of p1
4894 p1 = repo.lookup(b'.')
4893 p1 = repo.lookup(b'.')
4895 p2 = node
4894 p2 = node
4896 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4895 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4897
4896
4898 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4897 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4899 for node in nodes:
4898 for node in nodes:
4900 displayer.show(repo[node])
4899 displayer.show(repo[node])
4901 displayer.close()
4900 displayer.close()
4902 return 0
4901 return 0
4903
4902
4904 # ui.forcemerge is an internal variable, do not document
4903 # ui.forcemerge is an internal variable, do not document
4905 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4904 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4906 with ui.configoverride(overrides, b'merge'):
4905 with ui.configoverride(overrides, b'merge'):
4907 force = opts.get(b'force')
4906 force = opts.get(b'force')
4908 labels = [b'working copy', b'merge rev']
4907 labels = [b'working copy', b'merge rev']
4909 return hg.merge(
4908 return hg.merge(
4910 repo,
4909 repo,
4911 node,
4910 node,
4912 force=force,
4911 force=force,
4913 mergeforce=force,
4912 mergeforce=force,
4914 labels=labels,
4913 labels=labels,
4915 abort=abort,
4914 abort=abort,
4916 )
4915 )
4917
4916
4918
4917
4919 statemod.addunfinished(
4918 statemod.addunfinished(
4920 b'merge',
4919 b'merge',
4921 fname=None,
4920 fname=None,
4922 clearable=True,
4921 clearable=True,
4923 allowcommit=True,
4922 allowcommit=True,
4924 cmdmsg=_(b'outstanding uncommitted merge'),
4923 cmdmsg=_(b'outstanding uncommitted merge'),
4925 abortfunc=hg.abortmerge,
4924 abortfunc=hg.abortmerge,
4926 statushint=_(
4925 statushint=_(
4927 b'To continue: hg commit\nTo abort: hg merge --abort'
4926 b'To continue: hg commit\nTo abort: hg merge --abort'
4928 ),
4927 ),
4929 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4928 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4930 )
4929 )
4931
4930
4932
4931
4933 @command(
4932 @command(
4934 b'outgoing|out',
4933 b'outgoing|out',
4935 [
4934 [
4936 (
4935 (
4937 b'f',
4936 b'f',
4938 b'force',
4937 b'force',
4939 None,
4938 None,
4940 _(b'run even when the destination is unrelated'),
4939 _(b'run even when the destination is unrelated'),
4941 ),
4940 ),
4942 (
4941 (
4943 b'r',
4942 b'r',
4944 b'rev',
4943 b'rev',
4945 [],
4944 [],
4946 _(b'a changeset intended to be included in the destination'),
4945 _(b'a changeset intended to be included in the destination'),
4947 _(b'REV'),
4946 _(b'REV'),
4948 ),
4947 ),
4949 (b'n', b'newest-first', None, _(b'show newest record first')),
4948 (b'n', b'newest-first', None, _(b'show newest record first')),
4950 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4949 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4951 (
4950 (
4952 b'b',
4951 b'b',
4953 b'branch',
4952 b'branch',
4954 [],
4953 [],
4955 _(b'a specific branch you would like to push'),
4954 _(b'a specific branch you would like to push'),
4956 _(b'BRANCH'),
4955 _(b'BRANCH'),
4957 ),
4956 ),
4958 ]
4957 ]
4959 + logopts
4958 + logopts
4960 + remoteopts
4959 + remoteopts
4961 + subrepoopts,
4960 + subrepoopts,
4962 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4961 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4963 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4962 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4964 )
4963 )
4965 def outgoing(ui, repo, dest=None, **opts):
4964 def outgoing(ui, repo, dest=None, **opts):
4966 """show changesets not found in the destination
4965 """show changesets not found in the destination
4967
4966
4968 Show changesets not found in the specified destination repository
4967 Show changesets not found in the specified destination repository
4969 or the default push location. These are the changesets that would
4968 or the default push location. These are the changesets that would
4970 be pushed if a push was requested.
4969 be pushed if a push was requested.
4971
4970
4972 See pull for details of valid destination formats.
4971 See pull for details of valid destination formats.
4973
4972
4974 .. container:: verbose
4973 .. container:: verbose
4975
4974
4976 With -B/--bookmarks, the result of bookmark comparison between
4975 With -B/--bookmarks, the result of bookmark comparison between
4977 local and remote repositories is displayed. With -v/--verbose,
4976 local and remote repositories is displayed. With -v/--verbose,
4978 status is also displayed for each bookmark like below::
4977 status is also displayed for each bookmark like below::
4979
4978
4980 BM1 01234567890a added
4979 BM1 01234567890a added
4981 BM2 deleted
4980 BM2 deleted
4982 BM3 234567890abc advanced
4981 BM3 234567890abc advanced
4983 BM4 34567890abcd diverged
4982 BM4 34567890abcd diverged
4984 BM5 4567890abcde changed
4983 BM5 4567890abcde changed
4985
4984
4986 The action taken when pushing depends on the
4985 The action taken when pushing depends on the
4987 status of each bookmark:
4986 status of each bookmark:
4988
4987
4989 :``added``: push with ``-B`` will create it
4988 :``added``: push with ``-B`` will create it
4990 :``deleted``: push with ``-B`` will delete it
4989 :``deleted``: push with ``-B`` will delete it
4991 :``advanced``: push will update it
4990 :``advanced``: push will update it
4992 :``diverged``: push with ``-B`` will update it
4991 :``diverged``: push with ``-B`` will update it
4993 :``changed``: push with ``-B`` will update it
4992 :``changed``: push with ``-B`` will update it
4994
4993
4995 From the point of view of pushing behavior, bookmarks
4994 From the point of view of pushing behavior, bookmarks
4996 existing only in the remote repository are treated as
4995 existing only in the remote repository are treated as
4997 ``deleted``, even if it is in fact added remotely.
4996 ``deleted``, even if it is in fact added remotely.
4998
4997
4999 Returns 0 if there are outgoing changes, 1 otherwise.
4998 Returns 0 if there are outgoing changes, 1 otherwise.
5000 """
4999 """
5001 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5000 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5002 # style URLs, so don't overwrite dest.
5001 # style URLs, so don't overwrite dest.
5003 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5002 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5004 if not path:
5003 if not path:
5005 raise error.Abort(
5004 raise error.Abort(
5006 _(b'default repository not configured!'),
5005 _(b'default repository not configured!'),
5007 hint=_(b"see 'hg help config.paths'"),
5006 hint=_(b"see 'hg help config.paths'"),
5008 )
5007 )
5009
5008
5010 opts = pycompat.byteskwargs(opts)
5009 opts = pycompat.byteskwargs(opts)
5011 if opts.get(b'graph'):
5010 if opts.get(b'graph'):
5012 logcmdutil.checkunsupportedgraphflags([], opts)
5011 logcmdutil.checkunsupportedgraphflags([], opts)
5013 o, other = hg._outgoing(ui, repo, dest, opts)
5012 o, other = hg._outgoing(ui, repo, dest, opts)
5014 if not o:
5013 if not o:
5015 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5014 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5016 return
5015 return
5017
5016
5018 revdag = logcmdutil.graphrevs(repo, o, opts)
5017 revdag = logcmdutil.graphrevs(repo, o, opts)
5019 ui.pager(b'outgoing')
5018 ui.pager(b'outgoing')
5020 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5019 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5021 logcmdutil.displaygraph(
5020 logcmdutil.displaygraph(
5022 ui, repo, revdag, displayer, graphmod.asciiedges
5021 ui, repo, revdag, displayer, graphmod.asciiedges
5023 )
5022 )
5024 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5023 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5025 return 0
5024 return 0
5026
5025
5027 if opts.get(b'bookmarks'):
5026 if opts.get(b'bookmarks'):
5028 dest = path.pushloc or path.loc
5027 dest = path.pushloc or path.loc
5029 other = hg.peer(repo, opts, dest)
5028 other = hg.peer(repo, opts, dest)
5030 if b'bookmarks' not in other.listkeys(b'namespaces'):
5029 if b'bookmarks' not in other.listkeys(b'namespaces'):
5031 ui.warn(_(b"remote doesn't support bookmarks\n"))
5030 ui.warn(_(b"remote doesn't support bookmarks\n"))
5032 return 0
5031 return 0
5033 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5032 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5034 ui.pager(b'outgoing')
5033 ui.pager(b'outgoing')
5035 return bookmarks.outgoing(ui, repo, other)
5034 return bookmarks.outgoing(ui, repo, other)
5036
5035
5037 repo._subtoppath = path.pushloc or path.loc
5036 repo._subtoppath = path.pushloc or path.loc
5038 try:
5037 try:
5039 return hg.outgoing(ui, repo, dest, opts)
5038 return hg.outgoing(ui, repo, dest, opts)
5040 finally:
5039 finally:
5041 del repo._subtoppath
5040 del repo._subtoppath
5042
5041
5043
5042
5044 @command(
5043 @command(
5045 b'parents',
5044 b'parents',
5046 [
5045 [
5047 (
5046 (
5048 b'r',
5047 b'r',
5049 b'rev',
5048 b'rev',
5050 b'',
5049 b'',
5051 _(b'show parents of the specified revision'),
5050 _(b'show parents of the specified revision'),
5052 _(b'REV'),
5051 _(b'REV'),
5053 ),
5052 ),
5054 ]
5053 ]
5055 + templateopts,
5054 + templateopts,
5056 _(b'[-r REV] [FILE]'),
5055 _(b'[-r REV] [FILE]'),
5057 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5056 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5058 inferrepo=True,
5057 inferrepo=True,
5059 )
5058 )
5060 def parents(ui, repo, file_=None, **opts):
5059 def parents(ui, repo, file_=None, **opts):
5061 """show the parents of the working directory or revision (DEPRECATED)
5060 """show the parents of the working directory or revision (DEPRECATED)
5062
5061
5063 Print the working directory's parent revisions. If a revision is
5062 Print the working directory's parent revisions. If a revision is
5064 given via -r/--rev, the parent of that revision will be printed.
5063 given via -r/--rev, the parent of that revision will be printed.
5065 If a file argument is given, the revision in which the file was
5064 If a file argument is given, the revision in which the file was
5066 last changed (before the working directory revision or the
5065 last changed (before the working directory revision or the
5067 argument to --rev if given) is printed.
5066 argument to --rev if given) is printed.
5068
5067
5069 This command is equivalent to::
5068 This command is equivalent to::
5070
5069
5071 hg log -r "p1()+p2()" or
5070 hg log -r "p1()+p2()" or
5072 hg log -r "p1(REV)+p2(REV)" or
5071 hg log -r "p1(REV)+p2(REV)" or
5073 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5072 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5074 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5073 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5075
5074
5076 See :hg:`summary` and :hg:`help revsets` for related information.
5075 See :hg:`summary` and :hg:`help revsets` for related information.
5077
5076
5078 Returns 0 on success.
5077 Returns 0 on success.
5079 """
5078 """
5080
5079
5081 opts = pycompat.byteskwargs(opts)
5080 opts = pycompat.byteskwargs(opts)
5082 rev = opts.get(b'rev')
5081 rev = opts.get(b'rev')
5083 if rev:
5082 if rev:
5084 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5083 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5085 ctx = scmutil.revsingle(repo, rev, None)
5084 ctx = scmutil.revsingle(repo, rev, None)
5086
5085
5087 if file_:
5086 if file_:
5088 m = scmutil.match(ctx, (file_,), opts)
5087 m = scmutil.match(ctx, (file_,), opts)
5089 if m.anypats() or len(m.files()) != 1:
5088 if m.anypats() or len(m.files()) != 1:
5090 raise error.Abort(_(b'can only specify an explicit filename'))
5089 raise error.Abort(_(b'can only specify an explicit filename'))
5091 file_ = m.files()[0]
5090 file_ = m.files()[0]
5092 filenodes = []
5091 filenodes = []
5093 for cp in ctx.parents():
5092 for cp in ctx.parents():
5094 if not cp:
5093 if not cp:
5095 continue
5094 continue
5096 try:
5095 try:
5097 filenodes.append(cp.filenode(file_))
5096 filenodes.append(cp.filenode(file_))
5098 except error.LookupError:
5097 except error.LookupError:
5099 pass
5098 pass
5100 if not filenodes:
5099 if not filenodes:
5101 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5100 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5102 p = []
5101 p = []
5103 for fn in filenodes:
5102 for fn in filenodes:
5104 fctx = repo.filectx(file_, fileid=fn)
5103 fctx = repo.filectx(file_, fileid=fn)
5105 p.append(fctx.node())
5104 p.append(fctx.node())
5106 else:
5105 else:
5107 p = [cp.node() for cp in ctx.parents()]
5106 p = [cp.node() for cp in ctx.parents()]
5108
5107
5109 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5108 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5110 for n in p:
5109 for n in p:
5111 if n != nullid:
5110 if n != nullid:
5112 displayer.show(repo[n])
5111 displayer.show(repo[n])
5113 displayer.close()
5112 displayer.close()
5114
5113
5115
5114
5116 @command(
5115 @command(
5117 b'paths',
5116 b'paths',
5118 formatteropts,
5117 formatteropts,
5119 _(b'[NAME]'),
5118 _(b'[NAME]'),
5120 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5119 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5121 optionalrepo=True,
5120 optionalrepo=True,
5122 intents={INTENT_READONLY},
5121 intents={INTENT_READONLY},
5123 )
5122 )
5124 def paths(ui, repo, search=None, **opts):
5123 def paths(ui, repo, search=None, **opts):
5125 """show aliases for remote repositories
5124 """show aliases for remote repositories
5126
5125
5127 Show definition of symbolic path name NAME. If no name is given,
5126 Show definition of symbolic path name NAME. If no name is given,
5128 show definition of all available names.
5127 show definition of all available names.
5129
5128
5130 Option -q/--quiet suppresses all output when searching for NAME
5129 Option -q/--quiet suppresses all output when searching for NAME
5131 and shows only the path names when listing all definitions.
5130 and shows only the path names when listing all definitions.
5132
5131
5133 Path names are defined in the [paths] section of your
5132 Path names are defined in the [paths] section of your
5134 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5133 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5135 repository, ``.hg/hgrc`` is used, too.
5134 repository, ``.hg/hgrc`` is used, too.
5136
5135
5137 The path names ``default`` and ``default-push`` have a special
5136 The path names ``default`` and ``default-push`` have a special
5138 meaning. When performing a push or pull operation, they are used
5137 meaning. When performing a push or pull operation, they are used
5139 as fallbacks if no location is specified on the command-line.
5138 as fallbacks if no location is specified on the command-line.
5140 When ``default-push`` is set, it will be used for push and
5139 When ``default-push`` is set, it will be used for push and
5141 ``default`` will be used for pull; otherwise ``default`` is used
5140 ``default`` will be used for pull; otherwise ``default`` is used
5142 as the fallback for both. When cloning a repository, the clone
5141 as the fallback for both. When cloning a repository, the clone
5143 source is written as ``default`` in ``.hg/hgrc``.
5142 source is written as ``default`` in ``.hg/hgrc``.
5144
5143
5145 .. note::
5144 .. note::
5146
5145
5147 ``default`` and ``default-push`` apply to all inbound (e.g.
5146 ``default`` and ``default-push`` apply to all inbound (e.g.
5148 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5147 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5149 and :hg:`bundle`) operations.
5148 and :hg:`bundle`) operations.
5150
5149
5151 See :hg:`help urls` for more information.
5150 See :hg:`help urls` for more information.
5152
5151
5153 .. container:: verbose
5152 .. container:: verbose
5154
5153
5155 Template:
5154 Template:
5156
5155
5157 The following keywords are supported. See also :hg:`help templates`.
5156 The following keywords are supported. See also :hg:`help templates`.
5158
5157
5159 :name: String. Symbolic name of the path alias.
5158 :name: String. Symbolic name of the path alias.
5160 :pushurl: String. URL for push operations.
5159 :pushurl: String. URL for push operations.
5161 :url: String. URL or directory path for the other operations.
5160 :url: String. URL or directory path for the other operations.
5162
5161
5163 Returns 0 on success.
5162 Returns 0 on success.
5164 """
5163 """
5165
5164
5166 opts = pycompat.byteskwargs(opts)
5165 opts = pycompat.byteskwargs(opts)
5167 ui.pager(b'paths')
5166 ui.pager(b'paths')
5168 if search:
5167 if search:
5169 pathitems = [
5168 pathitems = [
5170 (name, path)
5169 (name, path)
5171 for name, path in pycompat.iteritems(ui.paths)
5170 for name, path in pycompat.iteritems(ui.paths)
5172 if name == search
5171 if name == search
5173 ]
5172 ]
5174 else:
5173 else:
5175 pathitems = sorted(pycompat.iteritems(ui.paths))
5174 pathitems = sorted(pycompat.iteritems(ui.paths))
5176
5175
5177 fm = ui.formatter(b'paths', opts)
5176 fm = ui.formatter(b'paths', opts)
5178 if fm.isplain():
5177 if fm.isplain():
5179 hidepassword = util.hidepassword
5178 hidepassword = util.hidepassword
5180 else:
5179 else:
5181 hidepassword = bytes
5180 hidepassword = bytes
5182 if ui.quiet:
5181 if ui.quiet:
5183 namefmt = b'%s\n'
5182 namefmt = b'%s\n'
5184 else:
5183 else:
5185 namefmt = b'%s = '
5184 namefmt = b'%s = '
5186 showsubopts = not search and not ui.quiet
5185 showsubopts = not search and not ui.quiet
5187
5186
5188 for name, path in pathitems:
5187 for name, path in pathitems:
5189 fm.startitem()
5188 fm.startitem()
5190 fm.condwrite(not search, b'name', namefmt, name)
5189 fm.condwrite(not search, b'name', namefmt, name)
5191 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5190 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5192 for subopt, value in sorted(path.suboptions.items()):
5191 for subopt, value in sorted(path.suboptions.items()):
5193 assert subopt not in (b'name', b'url')
5192 assert subopt not in (b'name', b'url')
5194 if showsubopts:
5193 if showsubopts:
5195 fm.plain(b'%s:%s = ' % (name, subopt))
5194 fm.plain(b'%s:%s = ' % (name, subopt))
5196 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5195 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5197
5196
5198 fm.end()
5197 fm.end()
5199
5198
5200 if search and not pathitems:
5199 if search and not pathitems:
5201 if not ui.quiet:
5200 if not ui.quiet:
5202 ui.warn(_(b"not found!\n"))
5201 ui.warn(_(b"not found!\n"))
5203 return 1
5202 return 1
5204 else:
5203 else:
5205 return 0
5204 return 0
5206
5205
5207
5206
5208 @command(
5207 @command(
5209 b'phase',
5208 b'phase',
5210 [
5209 [
5211 (b'p', b'public', False, _(b'set changeset phase to public')),
5210 (b'p', b'public', False, _(b'set changeset phase to public')),
5212 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5211 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5213 (b's', b'secret', False, _(b'set changeset phase to secret')),
5212 (b's', b'secret', False, _(b'set changeset phase to secret')),
5214 (b'f', b'force', False, _(b'allow to move boundary backward')),
5213 (b'f', b'force', False, _(b'allow to move boundary backward')),
5215 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5214 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5216 ],
5215 ],
5217 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5216 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5218 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5217 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5219 )
5218 )
5220 def phase(ui, repo, *revs, **opts):
5219 def phase(ui, repo, *revs, **opts):
5221 """set or show the current phase name
5220 """set or show the current phase name
5222
5221
5223 With no argument, show the phase name of the current revision(s).
5222 With no argument, show the phase name of the current revision(s).
5224
5223
5225 With one of -p/--public, -d/--draft or -s/--secret, change the
5224 With one of -p/--public, -d/--draft or -s/--secret, change the
5226 phase value of the specified revisions.
5225 phase value of the specified revisions.
5227
5226
5228 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5227 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5229 lower phase to a higher phase. Phases are ordered as follows::
5228 lower phase to a higher phase. Phases are ordered as follows::
5230
5229
5231 public < draft < secret
5230 public < draft < secret
5232
5231
5233 Returns 0 on success, 1 if some phases could not be changed.
5232 Returns 0 on success, 1 if some phases could not be changed.
5234
5233
5235 (For more information about the phases concept, see :hg:`help phases`.)
5234 (For more information about the phases concept, see :hg:`help phases`.)
5236 """
5235 """
5237 opts = pycompat.byteskwargs(opts)
5236 opts = pycompat.byteskwargs(opts)
5238 # search for a unique phase argument
5237 # search for a unique phase argument
5239 targetphase = None
5238 targetphase = None
5240 for idx, name in enumerate(phases.cmdphasenames):
5239 for idx, name in enumerate(phases.cmdphasenames):
5241 if opts[name]:
5240 if opts[name]:
5242 if targetphase is not None:
5241 if targetphase is not None:
5243 raise error.Abort(_(b'only one phase can be specified'))
5242 raise error.Abort(_(b'only one phase can be specified'))
5244 targetphase = idx
5243 targetphase = idx
5245
5244
5246 # look for specified revision
5245 # look for specified revision
5247 revs = list(revs)
5246 revs = list(revs)
5248 revs.extend(opts[b'rev'])
5247 revs.extend(opts[b'rev'])
5249 if not revs:
5248 if not revs:
5250 # display both parents as the second parent phase can influence
5249 # display both parents as the second parent phase can influence
5251 # the phase of a merge commit
5250 # the phase of a merge commit
5252 revs = [c.rev() for c in repo[None].parents()]
5251 revs = [c.rev() for c in repo[None].parents()]
5253
5252
5254 revs = scmutil.revrange(repo, revs)
5253 revs = scmutil.revrange(repo, revs)
5255
5254
5256 ret = 0
5255 ret = 0
5257 if targetphase is None:
5256 if targetphase is None:
5258 # display
5257 # display
5259 for r in revs:
5258 for r in revs:
5260 ctx = repo[r]
5259 ctx = repo[r]
5261 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5260 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5262 else:
5261 else:
5263 with repo.lock(), repo.transaction(b"phase") as tr:
5262 with repo.lock(), repo.transaction(b"phase") as tr:
5264 # set phase
5263 # set phase
5265 if not revs:
5264 if not revs:
5266 raise error.Abort(_(b'empty revision set'))
5265 raise error.Abort(_(b'empty revision set'))
5267 nodes = [repo[r].node() for r in revs]
5266 nodes = [repo[r].node() for r in revs]
5268 # moving revision from public to draft may hide them
5267 # moving revision from public to draft may hide them
5269 # We have to check result on an unfiltered repository
5268 # We have to check result on an unfiltered repository
5270 unfi = repo.unfiltered()
5269 unfi = repo.unfiltered()
5271 getphase = unfi._phasecache.phase
5270 getphase = unfi._phasecache.phase
5272 olddata = [getphase(unfi, r) for r in unfi]
5271 olddata = [getphase(unfi, r) for r in unfi]
5273 phases.advanceboundary(repo, tr, targetphase, nodes)
5272 phases.advanceboundary(repo, tr, targetphase, nodes)
5274 if opts[b'force']:
5273 if opts[b'force']:
5275 phases.retractboundary(repo, tr, targetphase, nodes)
5274 phases.retractboundary(repo, tr, targetphase, nodes)
5276 getphase = unfi._phasecache.phase
5275 getphase = unfi._phasecache.phase
5277 newdata = [getphase(unfi, r) for r in unfi]
5276 newdata = [getphase(unfi, r) for r in unfi]
5278 changes = sum(newdata[r] != olddata[r] for r in unfi)
5277 changes = sum(newdata[r] != olddata[r] for r in unfi)
5279 cl = unfi.changelog
5278 cl = unfi.changelog
5280 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5279 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5281 if rejected:
5280 if rejected:
5282 ui.warn(
5281 ui.warn(
5283 _(
5282 _(
5284 b'cannot move %i changesets to a higher '
5283 b'cannot move %i changesets to a higher '
5285 b'phase, use --force\n'
5284 b'phase, use --force\n'
5286 )
5285 )
5287 % len(rejected)
5286 % len(rejected)
5288 )
5287 )
5289 ret = 1
5288 ret = 1
5290 if changes:
5289 if changes:
5291 msg = _(b'phase changed for %i changesets\n') % changes
5290 msg = _(b'phase changed for %i changesets\n') % changes
5292 if ret:
5291 if ret:
5293 ui.status(msg)
5292 ui.status(msg)
5294 else:
5293 else:
5295 ui.note(msg)
5294 ui.note(msg)
5296 else:
5295 else:
5297 ui.warn(_(b'no phases changed\n'))
5296 ui.warn(_(b'no phases changed\n'))
5298 return ret
5297 return ret
5299
5298
5300
5299
5301 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5300 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5302 """Run after a changegroup has been added via pull/unbundle
5301 """Run after a changegroup has been added via pull/unbundle
5303
5302
5304 This takes arguments below:
5303 This takes arguments below:
5305
5304
5306 :modheads: change of heads by pull/unbundle
5305 :modheads: change of heads by pull/unbundle
5307 :optupdate: updating working directory is needed or not
5306 :optupdate: updating working directory is needed or not
5308 :checkout: update destination revision (or None to default destination)
5307 :checkout: update destination revision (or None to default destination)
5309 :brev: a name, which might be a bookmark to be activated after updating
5308 :brev: a name, which might be a bookmark to be activated after updating
5310 """
5309 """
5311 if modheads == 0:
5310 if modheads == 0:
5312 return
5311 return
5313 if optupdate:
5312 if optupdate:
5314 try:
5313 try:
5315 return hg.updatetotally(ui, repo, checkout, brev)
5314 return hg.updatetotally(ui, repo, checkout, brev)
5316 except error.UpdateAbort as inst:
5315 except error.UpdateAbort as inst:
5317 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5316 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5318 hint = inst.hint
5317 hint = inst.hint
5319 raise error.UpdateAbort(msg, hint=hint)
5318 raise error.UpdateAbort(msg, hint=hint)
5320 if modheads is not None and modheads > 1:
5319 if modheads is not None and modheads > 1:
5321 currentbranchheads = len(repo.branchheads())
5320 currentbranchheads = len(repo.branchheads())
5322 if currentbranchheads == modheads:
5321 if currentbranchheads == modheads:
5323 ui.status(
5322 ui.status(
5324 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5323 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5325 )
5324 )
5326 elif currentbranchheads > 1:
5325 elif currentbranchheads > 1:
5327 ui.status(
5326 ui.status(
5328 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5327 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5329 )
5328 )
5330 else:
5329 else:
5331 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5330 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5332 elif not ui.configbool(b'commands', b'update.requiredest'):
5331 elif not ui.configbool(b'commands', b'update.requiredest'):
5333 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5332 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5334
5333
5335
5334
5336 @command(
5335 @command(
5337 b'pull',
5336 b'pull',
5338 [
5337 [
5339 (
5338 (
5340 b'u',
5339 b'u',
5341 b'update',
5340 b'update',
5342 None,
5341 None,
5343 _(b'update to new branch head if new descendants were pulled'),
5342 _(b'update to new branch head if new descendants were pulled'),
5344 ),
5343 ),
5345 (
5344 (
5346 b'f',
5345 b'f',
5347 b'force',
5346 b'force',
5348 None,
5347 None,
5349 _(b'run even when remote repository is unrelated'),
5348 _(b'run even when remote repository is unrelated'),
5350 ),
5349 ),
5351 (
5350 (
5352 b'r',
5351 b'r',
5353 b'rev',
5352 b'rev',
5354 [],
5353 [],
5355 _(b'a remote changeset intended to be added'),
5354 _(b'a remote changeset intended to be added'),
5356 _(b'REV'),
5355 _(b'REV'),
5357 ),
5356 ),
5358 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5357 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5359 (
5358 (
5360 b'b',
5359 b'b',
5361 b'branch',
5360 b'branch',
5362 [],
5361 [],
5363 _(b'a specific branch you would like to pull'),
5362 _(b'a specific branch you would like to pull'),
5364 _(b'BRANCH'),
5363 _(b'BRANCH'),
5365 ),
5364 ),
5366 ]
5365 ]
5367 + remoteopts,
5366 + remoteopts,
5368 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5367 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5369 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5368 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5370 helpbasic=True,
5369 helpbasic=True,
5371 )
5370 )
5372 def pull(ui, repo, source=b"default", **opts):
5371 def pull(ui, repo, source=b"default", **opts):
5373 """pull changes from the specified source
5372 """pull changes from the specified source
5374
5373
5375 Pull changes from a remote repository to a local one.
5374 Pull changes from a remote repository to a local one.
5376
5375
5377 This finds all changes from the repository at the specified path
5376 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
5377 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
5378 -R is specified). By default, this does not update the copy of the
5380 project in the working directory.
5379 project in the working directory.
5381
5380
5382 When cloning from servers that support it, Mercurial may fetch
5381 When cloning from servers that support it, Mercurial may fetch
5383 pre-generated data. When this is done, hooks operating on incoming
5382 pre-generated data. When this is done, hooks operating on incoming
5384 changesets and changegroups may fire more than once, once for each
5383 changesets and changegroups may fire more than once, once for each
5385 pre-generated bundle and as well as for any additional remaining
5384 pre-generated bundle and as well as for any additional remaining
5386 data. See :hg:`help -e clonebundles` for more.
5385 data. See :hg:`help -e clonebundles` for more.
5387
5386
5388 Use :hg:`incoming` if you want to see what would have been added
5387 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
5388 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
5389 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`.
5390 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5392
5391
5393 If SOURCE is omitted, the 'default' path will be used.
5392 If SOURCE is omitted, the 'default' path will be used.
5394 See :hg:`help urls` for more information.
5393 See :hg:`help urls` for more information.
5395
5394
5396 Specifying bookmark as ``.`` is equivalent to specifying the active
5395 Specifying bookmark as ``.`` is equivalent to specifying the active
5397 bookmark's name.
5396 bookmark's name.
5398
5397
5399 Returns 0 on success, 1 if an update had unresolved files.
5398 Returns 0 on success, 1 if an update had unresolved files.
5400 """
5399 """
5401
5400
5402 opts = pycompat.byteskwargs(opts)
5401 opts = pycompat.byteskwargs(opts)
5403 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5402 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5404 b'update'
5403 b'update'
5405 ):
5404 ):
5406 msg = _(b'update destination required by configuration')
5405 msg = _(b'update destination required by configuration')
5407 hint = _(b'use hg pull followed by hg update DEST')
5406 hint = _(b'use hg pull followed by hg update DEST')
5408 raise error.Abort(msg, hint=hint)
5407 raise error.Abort(msg, hint=hint)
5409
5408
5410 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5409 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5411 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5410 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5412 other = hg.peer(repo, opts, source)
5411 other = hg.peer(repo, opts, source)
5413 try:
5412 try:
5414 revs, checkout = hg.addbranchrevs(
5413 revs, checkout = hg.addbranchrevs(
5415 repo, other, branches, opts.get(b'rev')
5414 repo, other, branches, opts.get(b'rev')
5416 )
5415 )
5417
5416
5418 pullopargs = {}
5417 pullopargs = {}
5419
5418
5420 nodes = None
5419 nodes = None
5421 if opts.get(b'bookmark') or revs:
5420 if opts.get(b'bookmark') or revs:
5422 # The list of bookmark used here is the same used to actually update
5421 # 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
5422 # 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
5423 # all lookup and bookmark queries in one go so they see the same
5425 # version of the server state (issue 4700).
5424 # version of the server state (issue 4700).
5426 nodes = []
5425 nodes = []
5427 fnodes = []
5426 fnodes = []
5428 revs = revs or []
5427 revs = revs or []
5429 if revs and not other.capable(b'lookup'):
5428 if revs and not other.capable(b'lookup'):
5430 err = _(
5429 err = _(
5431 b"other repository doesn't support revision lookup, "
5430 b"other repository doesn't support revision lookup, "
5432 b"so a rev cannot be specified."
5431 b"so a rev cannot be specified."
5433 )
5432 )
5434 raise error.Abort(err)
5433 raise error.Abort(err)
5435 with other.commandexecutor() as e:
5434 with other.commandexecutor() as e:
5436 fremotebookmarks = e.callcommand(
5435 fremotebookmarks = e.callcommand(
5437 b'listkeys', {b'namespace': b'bookmarks'}
5436 b'listkeys', {b'namespace': b'bookmarks'}
5438 )
5437 )
5439 for r in revs:
5438 for r in revs:
5440 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5439 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5441 remotebookmarks = fremotebookmarks.result()
5440 remotebookmarks = fremotebookmarks.result()
5442 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5441 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5443 pullopargs[b'remotebookmarks'] = remotebookmarks
5442 pullopargs[b'remotebookmarks'] = remotebookmarks
5444 for b in opts.get(b'bookmark', []):
5443 for b in opts.get(b'bookmark', []):
5445 b = repo._bookmarks.expandname(b)
5444 b = repo._bookmarks.expandname(b)
5446 if b not in remotebookmarks:
5445 if b not in remotebookmarks:
5447 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5446 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5448 nodes.append(remotebookmarks[b])
5447 nodes.append(remotebookmarks[b])
5449 for i, rev in enumerate(revs):
5448 for i, rev in enumerate(revs):
5450 node = fnodes[i].result()
5449 node = fnodes[i].result()
5451 nodes.append(node)
5450 nodes.append(node)
5452 if rev == checkout:
5451 if rev == checkout:
5453 checkout = node
5452 checkout = node
5454
5453
5455 wlock = util.nullcontextmanager()
5454 wlock = util.nullcontextmanager()
5456 if opts.get(b'update'):
5455 if opts.get(b'update'):
5457 wlock = repo.wlock()
5456 wlock = repo.wlock()
5458 with wlock:
5457 with wlock:
5459 pullopargs.update(opts.get(b'opargs', {}))
5458 pullopargs.update(opts.get(b'opargs', {}))
5460 modheads = exchange.pull(
5459 modheads = exchange.pull(
5461 repo,
5460 repo,
5462 other,
5461 other,
5463 heads=nodes,
5462 heads=nodes,
5464 force=opts.get(b'force'),
5463 force=opts.get(b'force'),
5465 bookmarks=opts.get(b'bookmark', ()),
5464 bookmarks=opts.get(b'bookmark', ()),
5466 opargs=pullopargs,
5465 opargs=pullopargs,
5467 ).cgresult
5466 ).cgresult
5468
5467
5469 # brev is a name, which might be a bookmark to be activated at
5468 # brev is a name, which might be a bookmark to be activated at
5470 # the end of the update. In other words, it is an explicit
5469 # the end of the update. In other words, it is an explicit
5471 # destination of the update
5470 # destination of the update
5472 brev = None
5471 brev = None
5473
5472
5474 if checkout:
5473 if checkout:
5475 checkout = repo.unfiltered().changelog.rev(checkout)
5474 checkout = repo.unfiltered().changelog.rev(checkout)
5476
5475
5477 # order below depends on implementation of
5476 # order below depends on implementation of
5478 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5477 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5479 # because 'checkout' is determined without it.
5478 # because 'checkout' is determined without it.
5480 if opts.get(b'rev'):
5479 if opts.get(b'rev'):
5481 brev = opts[b'rev'][0]
5480 brev = opts[b'rev'][0]
5482 elif opts.get(b'branch'):
5481 elif opts.get(b'branch'):
5483 brev = opts[b'branch'][0]
5482 brev = opts[b'branch'][0]
5484 else:
5483 else:
5485 brev = branches[0]
5484 brev = branches[0]
5486 repo._subtoppath = source
5485 repo._subtoppath = source
5487 try:
5486 try:
5488 ret = postincoming(
5487 ret = postincoming(
5489 ui, repo, modheads, opts.get(b'update'), checkout, brev
5488 ui, repo, modheads, opts.get(b'update'), checkout, brev
5490 )
5489 )
5491 except error.FilteredRepoLookupError as exc:
5490 except error.FilteredRepoLookupError as exc:
5492 msg = _(b'cannot update to target: %s') % exc.args[0]
5491 msg = _(b'cannot update to target: %s') % exc.args[0]
5493 exc.args = (msg,) + exc.args[1:]
5492 exc.args = (msg,) + exc.args[1:]
5494 raise
5493 raise
5495 finally:
5494 finally:
5496 del repo._subtoppath
5495 del repo._subtoppath
5497
5496
5498 finally:
5497 finally:
5499 other.close()
5498 other.close()
5500 return ret
5499 return ret
5501
5500
5502
5501
5503 @command(
5502 @command(
5504 b'push',
5503 b'push',
5505 [
5504 [
5506 (b'f', b'force', None, _(b'force push')),
5505 (b'f', b'force', None, _(b'force push')),
5507 (
5506 (
5508 b'r',
5507 b'r',
5509 b'rev',
5508 b'rev',
5510 [],
5509 [],
5511 _(b'a changeset intended to be included in the destination'),
5510 _(b'a changeset intended to be included in the destination'),
5512 _(b'REV'),
5511 _(b'REV'),
5513 ),
5512 ),
5514 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5513 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5515 (
5514 (
5516 b'b',
5515 b'b',
5517 b'branch',
5516 b'branch',
5518 [],
5517 [],
5519 _(b'a specific branch you would like to push'),
5518 _(b'a specific branch you would like to push'),
5520 _(b'BRANCH'),
5519 _(b'BRANCH'),
5521 ),
5520 ),
5522 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5521 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5523 (
5522 (
5524 b'',
5523 b'',
5525 b'pushvars',
5524 b'pushvars',
5526 [],
5525 [],
5527 _(b'variables that can be sent to server (ADVANCED)'),
5526 _(b'variables that can be sent to server (ADVANCED)'),
5528 ),
5527 ),
5529 (
5528 (
5530 b'',
5529 b'',
5531 b'publish',
5530 b'publish',
5532 False,
5531 False,
5533 _(b'push the changeset as public (EXPERIMENTAL)'),
5532 _(b'push the changeset as public (EXPERIMENTAL)'),
5534 ),
5533 ),
5535 ]
5534 ]
5536 + remoteopts,
5535 + remoteopts,
5537 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5536 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5538 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5537 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5539 helpbasic=True,
5538 helpbasic=True,
5540 )
5539 )
5541 def push(ui, repo, dest=None, **opts):
5540 def push(ui, repo, dest=None, **opts):
5542 """push changes to the specified destination
5541 """push changes to the specified destination
5543
5542
5544 Push changesets from the local repository to the specified
5543 Push changesets from the local repository to the specified
5545 destination.
5544 destination.
5546
5545
5547 This operation is symmetrical to pull: it is identical to a pull
5546 This operation is symmetrical to pull: it is identical to a pull
5548 in the destination repository from the current one.
5547 in the destination repository from the current one.
5549
5548
5550 By default, push will not allow creation of new heads at the
5549 By default, push will not allow creation of new heads at the
5551 destination, since multiple heads would make it unclear which head
5550 destination, since multiple heads would make it unclear which head
5552 to use. In this situation, it is recommended to pull and merge
5551 to use. In this situation, it is recommended to pull and merge
5553 before pushing.
5552 before pushing.
5554
5553
5555 Use --new-branch if you want to allow push to create a new named
5554 Use --new-branch if you want to allow push to create a new named
5556 branch that is not present at the destination. This allows you to
5555 branch that is not present at the destination. This allows you to
5557 only create a new branch without forcing other changes.
5556 only create a new branch without forcing other changes.
5558
5557
5559 .. note::
5558 .. note::
5560
5559
5561 Extra care should be taken with the -f/--force option,
5560 Extra care should be taken with the -f/--force option,
5562 which will push all new heads on all branches, an action which will
5561 which will push all new heads on all branches, an action which will
5563 almost always cause confusion for collaborators.
5562 almost always cause confusion for collaborators.
5564
5563
5565 If -r/--rev is used, the specified revision and all its ancestors
5564 If -r/--rev is used, the specified revision and all its ancestors
5566 will be pushed to the remote repository.
5565 will be pushed to the remote repository.
5567
5566
5568 If -B/--bookmark is used, the specified bookmarked revision, its
5567 If -B/--bookmark is used, the specified bookmarked revision, its
5569 ancestors, and the bookmark will be pushed to the remote
5568 ancestors, and the bookmark will be pushed to the remote
5570 repository. Specifying ``.`` is equivalent to specifying the active
5569 repository. Specifying ``.`` is equivalent to specifying the active
5571 bookmark's name.
5570 bookmark's name.
5572
5571
5573 Please see :hg:`help urls` for important details about ``ssh://``
5572 Please see :hg:`help urls` for important details about ``ssh://``
5574 URLs. If DESTINATION is omitted, a default path will be used.
5573 URLs. If DESTINATION is omitted, a default path will be used.
5575
5574
5576 .. container:: verbose
5575 .. container:: verbose
5577
5576
5578 The --pushvars option sends strings to the server that become
5577 The --pushvars option sends strings to the server that become
5579 environment variables prepended with ``HG_USERVAR_``. For example,
5578 environment variables prepended with ``HG_USERVAR_``. For example,
5580 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5579 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5581 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5580 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5582
5581
5583 pushvars can provide for user-overridable hooks as well as set debug
5582 pushvars can provide for user-overridable hooks as well as set debug
5584 levels. One example is having a hook that blocks commits containing
5583 levels. One example is having a hook that blocks commits containing
5585 conflict markers, but enables the user to override the hook if the file
5584 conflict markers, but enables the user to override the hook if the file
5586 is using conflict markers for testing purposes or the file format has
5585 is using conflict markers for testing purposes or the file format has
5587 strings that look like conflict markers.
5586 strings that look like conflict markers.
5588
5587
5589 By default, servers will ignore `--pushvars`. To enable it add the
5588 By default, servers will ignore `--pushvars`. To enable it add the
5590 following to your configuration file::
5589 following to your configuration file::
5591
5590
5592 [push]
5591 [push]
5593 pushvars.server = true
5592 pushvars.server = true
5594
5593
5595 Returns 0 if push was successful, 1 if nothing to push.
5594 Returns 0 if push was successful, 1 if nothing to push.
5596 """
5595 """
5597
5596
5598 opts = pycompat.byteskwargs(opts)
5597 opts = pycompat.byteskwargs(opts)
5599 if opts.get(b'bookmark'):
5598 if opts.get(b'bookmark'):
5600 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5599 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5601 for b in opts[b'bookmark']:
5600 for b in opts[b'bookmark']:
5602 # translate -B options to -r so changesets get pushed
5601 # translate -B options to -r so changesets get pushed
5603 b = repo._bookmarks.expandname(b)
5602 b = repo._bookmarks.expandname(b)
5604 if b in repo._bookmarks:
5603 if b in repo._bookmarks:
5605 opts.setdefault(b'rev', []).append(b)
5604 opts.setdefault(b'rev', []).append(b)
5606 else:
5605 else:
5607 # if we try to push a deleted bookmark, translate it to null
5606 # if we try to push a deleted bookmark, translate it to null
5608 # this lets simultaneous -r, -b options continue working
5607 # this lets simultaneous -r, -b options continue working
5609 opts.setdefault(b'rev', []).append(b"null")
5608 opts.setdefault(b'rev', []).append(b"null")
5610
5609
5611 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5610 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5612 if not path:
5611 if not path:
5613 raise error.Abort(
5612 raise error.Abort(
5614 _(b'default repository not configured!'),
5613 _(b'default repository not configured!'),
5615 hint=_(b"see 'hg help config.paths'"),
5614 hint=_(b"see 'hg help config.paths'"),
5616 )
5615 )
5617 dest = path.pushloc or path.loc
5616 dest = path.pushloc or path.loc
5618 branches = (path.branch, opts.get(b'branch') or [])
5617 branches = (path.branch, opts.get(b'branch') or [])
5619 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5618 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5620 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5619 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5621 other = hg.peer(repo, opts, dest)
5620 other = hg.peer(repo, opts, dest)
5622
5621
5623 if revs:
5622 if revs:
5624 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5623 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5625 if not revs:
5624 if not revs:
5626 raise error.Abort(
5625 raise error.Abort(
5627 _(b"specified revisions evaluate to an empty set"),
5626 _(b"specified revisions evaluate to an empty set"),
5628 hint=_(b"use different revision arguments"),
5627 hint=_(b"use different revision arguments"),
5629 )
5628 )
5630 elif path.pushrev:
5629 elif path.pushrev:
5631 # It doesn't make any sense to specify ancestor revisions. So limit
5630 # It doesn't make any sense to specify ancestor revisions. So limit
5632 # to DAG heads to make discovery simpler.
5631 # to DAG heads to make discovery simpler.
5633 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5632 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5634 revs = scmutil.revrange(repo, [expr])
5633 revs = scmutil.revrange(repo, [expr])
5635 revs = [repo[rev].node() for rev in revs]
5634 revs = [repo[rev].node() for rev in revs]
5636 if not revs:
5635 if not revs:
5637 raise error.Abort(
5636 raise error.Abort(
5638 _(b'default push revset for path evaluates to an empty set')
5637 _(b'default push revset for path evaluates to an empty set')
5639 )
5638 )
5640 elif ui.configbool(b'commands', b'push.require-revs'):
5639 elif ui.configbool(b'commands', b'push.require-revs'):
5641 raise error.Abort(
5640 raise error.Abort(
5642 _(b'no revisions specified to push'),
5641 _(b'no revisions specified to push'),
5643 hint=_(b'did you mean "hg push -r ."?'),
5642 hint=_(b'did you mean "hg push -r ."?'),
5644 )
5643 )
5645
5644
5646 repo._subtoppath = dest
5645 repo._subtoppath = dest
5647 try:
5646 try:
5648 # push subrepos depth-first for coherent ordering
5647 # push subrepos depth-first for coherent ordering
5649 c = repo[b'.']
5648 c = repo[b'.']
5650 subs = c.substate # only repos that are committed
5649 subs = c.substate # only repos that are committed
5651 for s in sorted(subs):
5650 for s in sorted(subs):
5652 result = c.sub(s).push(opts)
5651 result = c.sub(s).push(opts)
5653 if result == 0:
5652 if result == 0:
5654 return not result
5653 return not result
5655 finally:
5654 finally:
5656 del repo._subtoppath
5655 del repo._subtoppath
5657
5656
5658 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5657 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5659 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5658 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5660
5659
5661 pushop = exchange.push(
5660 pushop = exchange.push(
5662 repo,
5661 repo,
5663 other,
5662 other,
5664 opts.get(b'force'),
5663 opts.get(b'force'),
5665 revs=revs,
5664 revs=revs,
5666 newbranch=opts.get(b'new_branch'),
5665 newbranch=opts.get(b'new_branch'),
5667 bookmarks=opts.get(b'bookmark', ()),
5666 bookmarks=opts.get(b'bookmark', ()),
5668 publish=opts.get(b'publish'),
5667 publish=opts.get(b'publish'),
5669 opargs=opargs,
5668 opargs=opargs,
5670 )
5669 )
5671
5670
5672 result = not pushop.cgresult
5671 result = not pushop.cgresult
5673
5672
5674 if pushop.bkresult is not None:
5673 if pushop.bkresult is not None:
5675 if pushop.bkresult == 2:
5674 if pushop.bkresult == 2:
5676 result = 2
5675 result = 2
5677 elif not result and pushop.bkresult:
5676 elif not result and pushop.bkresult:
5678 result = 2
5677 result = 2
5679
5678
5680 return result
5679 return result
5681
5680
5682
5681
5683 @command(
5682 @command(
5684 b'recover',
5683 b'recover',
5685 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5684 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5686 helpcategory=command.CATEGORY_MAINTENANCE,
5685 helpcategory=command.CATEGORY_MAINTENANCE,
5687 )
5686 )
5688 def recover(ui, repo, **opts):
5687 def recover(ui, repo, **opts):
5689 """roll back an interrupted transaction
5688 """roll back an interrupted transaction
5690
5689
5691 Recover from an interrupted commit or pull.
5690 Recover from an interrupted commit or pull.
5692
5691
5693 This command tries to fix the repository status after an
5692 This command tries to fix the repository status after an
5694 interrupted operation. It should only be necessary when Mercurial
5693 interrupted operation. It should only be necessary when Mercurial
5695 suggests it.
5694 suggests it.
5696
5695
5697 Returns 0 if successful, 1 if nothing to recover or verify fails.
5696 Returns 0 if successful, 1 if nothing to recover or verify fails.
5698 """
5697 """
5699 ret = repo.recover()
5698 ret = repo.recover()
5700 if ret:
5699 if ret:
5701 if opts['verify']:
5700 if opts['verify']:
5702 return hg.verify(repo)
5701 return hg.verify(repo)
5703 else:
5702 else:
5704 msg = _(
5703 msg = _(
5705 b"(verify step skipped, run `hg verify` to check your "
5704 b"(verify step skipped, run `hg verify` to check your "
5706 b"repository content)\n"
5705 b"repository content)\n"
5707 )
5706 )
5708 ui.warn(msg)
5707 ui.warn(msg)
5709 return 0
5708 return 0
5710 return 1
5709 return 1
5711
5710
5712
5711
5713 @command(
5712 @command(
5714 b'remove|rm',
5713 b'remove|rm',
5715 [
5714 [
5716 (b'A', b'after', None, _(b'record delete for missing files')),
5715 (b'A', b'after', None, _(b'record delete for missing files')),
5717 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5716 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5718 ]
5717 ]
5719 + subrepoopts
5718 + subrepoopts
5720 + walkopts
5719 + walkopts
5721 + dryrunopts,
5720 + dryrunopts,
5722 _(b'[OPTION]... FILE...'),
5721 _(b'[OPTION]... FILE...'),
5723 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5722 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5724 helpbasic=True,
5723 helpbasic=True,
5725 inferrepo=True,
5724 inferrepo=True,
5726 )
5725 )
5727 def remove(ui, repo, *pats, **opts):
5726 def remove(ui, repo, *pats, **opts):
5728 """remove the specified files on the next commit
5727 """remove the specified files on the next commit
5729
5728
5730 Schedule the indicated files for removal from the current branch.
5729 Schedule the indicated files for removal from the current branch.
5731
5730
5732 This command schedules the files to be removed at the next commit.
5731 This command schedules the files to be removed at the next commit.
5733 To undo a remove before that, see :hg:`revert`. To undo added
5732 To undo a remove before that, see :hg:`revert`. To undo added
5734 files, see :hg:`forget`.
5733 files, see :hg:`forget`.
5735
5734
5736 .. container:: verbose
5735 .. container:: verbose
5737
5736
5738 -A/--after can be used to remove only files that have already
5737 -A/--after can be used to remove only files that have already
5739 been deleted, -f/--force can be used to force deletion, and -Af
5738 been deleted, -f/--force can be used to force deletion, and -Af
5740 can be used to remove files from the next revision without
5739 can be used to remove files from the next revision without
5741 deleting them from the working directory.
5740 deleting them from the working directory.
5742
5741
5743 The following table details the behavior of remove for different
5742 The following table details the behavior of remove for different
5744 file states (columns) and option combinations (rows). The file
5743 file states (columns) and option combinations (rows). The file
5745 states are Added [A], Clean [C], Modified [M] and Missing [!]
5744 states are Added [A], Clean [C], Modified [M] and Missing [!]
5746 (as reported by :hg:`status`). The actions are Warn, Remove
5745 (as reported by :hg:`status`). The actions are Warn, Remove
5747 (from branch) and Delete (from disk):
5746 (from branch) and Delete (from disk):
5748
5747
5749 ========= == == == ==
5748 ========= == == == ==
5750 opt/state A C M !
5749 opt/state A C M !
5751 ========= == == == ==
5750 ========= == == == ==
5752 none W RD W R
5751 none W RD W R
5753 -f R RD RD R
5752 -f R RD RD R
5754 -A W W W R
5753 -A W W W R
5755 -Af R R R R
5754 -Af R R R R
5756 ========= == == == ==
5755 ========= == == == ==
5757
5756
5758 .. note::
5757 .. note::
5759
5758
5760 :hg:`remove` never deletes files in Added [A] state from the
5759 :hg:`remove` never deletes files in Added [A] state from the
5761 working directory, not even if ``--force`` is specified.
5760 working directory, not even if ``--force`` is specified.
5762
5761
5763 Returns 0 on success, 1 if any warnings encountered.
5762 Returns 0 on success, 1 if any warnings encountered.
5764 """
5763 """
5765
5764
5766 opts = pycompat.byteskwargs(opts)
5765 opts = pycompat.byteskwargs(opts)
5767 after, force = opts.get(b'after'), opts.get(b'force')
5766 after, force = opts.get(b'after'), opts.get(b'force')
5768 dryrun = opts.get(b'dry_run')
5767 dryrun = opts.get(b'dry_run')
5769 if not pats and not after:
5768 if not pats and not after:
5770 raise error.Abort(_(b'no files specified'))
5769 raise error.Abort(_(b'no files specified'))
5771
5770
5772 m = scmutil.match(repo[None], pats, opts)
5771 m = scmutil.match(repo[None], pats, opts)
5773 subrepos = opts.get(b'subrepos')
5772 subrepos = opts.get(b'subrepos')
5774 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5773 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5775 return cmdutil.remove(
5774 return cmdutil.remove(
5776 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5775 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5777 )
5776 )
5778
5777
5779
5778
5780 @command(
5779 @command(
5781 b'rename|move|mv',
5780 b'rename|move|mv',
5782 [
5781 [
5783 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5782 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5784 (
5783 (
5785 b'f',
5784 b'f',
5786 b'force',
5785 b'force',
5787 None,
5786 None,
5788 _(b'forcibly move over an existing managed file'),
5787 _(b'forcibly move over an existing managed file'),
5789 ),
5788 ),
5790 ]
5789 ]
5791 + walkopts
5790 + walkopts
5792 + dryrunopts,
5791 + dryrunopts,
5793 _(b'[OPTION]... SOURCE... DEST'),
5792 _(b'[OPTION]... SOURCE... DEST'),
5794 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5793 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5795 )
5794 )
5796 def rename(ui, repo, *pats, **opts):
5795 def rename(ui, repo, *pats, **opts):
5797 """rename files; equivalent of copy + remove
5796 """rename files; equivalent of copy + remove
5798
5797
5799 Mark dest as copies of sources; mark sources for deletion. If dest
5798 Mark dest as copies of sources; mark sources for deletion. If dest
5800 is a directory, copies are put in that directory. If dest is a
5799 is a directory, copies are put in that directory. If dest is a
5801 file, there can only be one source.
5800 file, there can only be one source.
5802
5801
5803 By default, this command copies the contents of files as they
5802 By default, this command copies the contents of files as they
5804 exist in the working directory. If invoked with -A/--after, the
5803 exist in the working directory. If invoked with -A/--after, the
5805 operation is recorded, but no copying is performed.
5804 operation is recorded, but no copying is performed.
5806
5805
5807 This command takes effect at the next commit. To undo a rename
5806 This command takes effect at the next commit. To undo a rename
5808 before that, see :hg:`revert`.
5807 before that, see :hg:`revert`.
5809
5808
5810 Returns 0 on success, 1 if errors are encountered.
5809 Returns 0 on success, 1 if errors are encountered.
5811 """
5810 """
5812 opts = pycompat.byteskwargs(opts)
5811 opts = pycompat.byteskwargs(opts)
5813 with repo.wlock(False):
5812 with repo.wlock(False):
5814 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5813 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5815
5814
5816
5815
5817 @command(
5816 @command(
5818 b'resolve',
5817 b'resolve',
5819 [
5818 [
5820 (b'a', b'all', None, _(b'select all unresolved files')),
5819 (b'a', b'all', None, _(b'select all unresolved files')),
5821 (b'l', b'list', None, _(b'list state of files needing merge')),
5820 (b'l', b'list', None, _(b'list state of files needing merge')),
5822 (b'm', b'mark', None, _(b'mark files as resolved')),
5821 (b'm', b'mark', None, _(b'mark files as resolved')),
5823 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5822 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5824 (b'n', b'no-status', None, _(b'hide status prefix')),
5823 (b'n', b'no-status', None, _(b'hide status prefix')),
5825 (b'', b're-merge', None, _(b're-merge files')),
5824 (b'', b're-merge', None, _(b're-merge files')),
5826 ]
5825 ]
5827 + mergetoolopts
5826 + mergetoolopts
5828 + walkopts
5827 + walkopts
5829 + formatteropts,
5828 + formatteropts,
5830 _(b'[OPTION]... [FILE]...'),
5829 _(b'[OPTION]... [FILE]...'),
5831 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5830 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5832 inferrepo=True,
5831 inferrepo=True,
5833 )
5832 )
5834 def resolve(ui, repo, *pats, **opts):
5833 def resolve(ui, repo, *pats, **opts):
5835 """redo merges or set/view the merge status of files
5834 """redo merges or set/view the merge status of files
5836
5835
5837 Merges with unresolved conflicts are often the result of
5836 Merges with unresolved conflicts are often the result of
5838 non-interactive merging using the ``internal:merge`` configuration
5837 non-interactive merging using the ``internal:merge`` configuration
5839 setting, or a command-line merge tool like ``diff3``. The resolve
5838 setting, or a command-line merge tool like ``diff3``. The resolve
5840 command is used to manage the files involved in a merge, after
5839 command is used to manage the files involved in a merge, after
5841 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5840 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5842 working directory must have two parents). See :hg:`help
5841 working directory must have two parents). See :hg:`help
5843 merge-tools` for information on configuring merge tools.
5842 merge-tools` for information on configuring merge tools.
5844
5843
5845 The resolve command can be used in the following ways:
5844 The resolve command can be used in the following ways:
5846
5845
5847 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5846 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5848 the specified files, discarding any previous merge attempts. Re-merging
5847 the specified files, discarding any previous merge attempts. Re-merging
5849 is not performed for files already marked as resolved. Use ``--all/-a``
5848 is not performed for files already marked as resolved. Use ``--all/-a``
5850 to select all unresolved files. ``--tool`` can be used to specify
5849 to select all unresolved files. ``--tool`` can be used to specify
5851 the merge tool used for the given files. It overrides the HGMERGE
5850 the merge tool used for the given files. It overrides the HGMERGE
5852 environment variable and your configuration files. Previous file
5851 environment variable and your configuration files. Previous file
5853 contents are saved with a ``.orig`` suffix.
5852 contents are saved with a ``.orig`` suffix.
5854
5853
5855 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5854 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5856 (e.g. after having manually fixed-up the files). The default is
5855 (e.g. after having manually fixed-up the files). The default is
5857 to mark all unresolved files.
5856 to mark all unresolved files.
5858
5857
5859 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5858 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5860 default is to mark all resolved files.
5859 default is to mark all resolved files.
5861
5860
5862 - :hg:`resolve -l`: list files which had or still have conflicts.
5861 - :hg:`resolve -l`: list files which had or still have conflicts.
5863 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5862 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5864 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5863 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5865 the list. See :hg:`help filesets` for details.
5864 the list. See :hg:`help filesets` for details.
5866
5865
5867 .. note::
5866 .. note::
5868
5867
5869 Mercurial will not let you commit files with unresolved merge
5868 Mercurial will not let you commit files with unresolved merge
5870 conflicts. You must use :hg:`resolve -m ...` before you can
5869 conflicts. You must use :hg:`resolve -m ...` before you can
5871 commit after a conflicting merge.
5870 commit after a conflicting merge.
5872
5871
5873 .. container:: verbose
5872 .. container:: verbose
5874
5873
5875 Template:
5874 Template:
5876
5875
5877 The following keywords are supported in addition to the common template
5876 The following keywords are supported in addition to the common template
5878 keywords and functions. See also :hg:`help templates`.
5877 keywords and functions. See also :hg:`help templates`.
5879
5878
5880 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5879 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5881 :path: String. Repository-absolute path of the file.
5880 :path: String. Repository-absolute path of the file.
5882
5881
5883 Returns 0 on success, 1 if any files fail a resolve attempt.
5882 Returns 0 on success, 1 if any files fail a resolve attempt.
5884 """
5883 """
5885
5884
5886 opts = pycompat.byteskwargs(opts)
5885 opts = pycompat.byteskwargs(opts)
5887 confirm = ui.configbool(b'commands', b'resolve.confirm')
5886 confirm = ui.configbool(b'commands', b'resolve.confirm')
5888 flaglist = b'all mark unmark list no_status re_merge'.split()
5887 flaglist = b'all mark unmark list no_status re_merge'.split()
5889 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5888 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5890
5889
5891 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5890 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5892 if actioncount > 1:
5891 if actioncount > 1:
5893 raise error.Abort(_(b"too many actions specified"))
5892 raise error.Abort(_(b"too many actions specified"))
5894 elif actioncount == 0 and ui.configbool(
5893 elif actioncount == 0 and ui.configbool(
5895 b'commands', b'resolve.explicit-re-merge'
5894 b'commands', b'resolve.explicit-re-merge'
5896 ):
5895 ):
5897 hint = _(b'use --mark, --unmark, --list or --re-merge')
5896 hint = _(b'use --mark, --unmark, --list or --re-merge')
5898 raise error.Abort(_(b'no action specified'), hint=hint)
5897 raise error.Abort(_(b'no action specified'), hint=hint)
5899 if pats and all:
5898 if pats and all:
5900 raise error.Abort(_(b"can't specify --all and patterns"))
5899 raise error.Abort(_(b"can't specify --all and patterns"))
5901 if not (all or pats or show or mark or unmark):
5900 if not (all or pats or show or mark or unmark):
5902 raise error.Abort(
5901 raise error.Abort(
5903 _(b'no files or directories specified'),
5902 _(b'no files or directories specified'),
5904 hint=b'use --all to re-merge all unresolved files',
5903 hint=b'use --all to re-merge all unresolved files',
5905 )
5904 )
5906
5905
5907 if confirm:
5906 if confirm:
5908 if all:
5907 if all:
5909 if ui.promptchoice(
5908 if ui.promptchoice(
5910 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5909 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5911 ):
5910 ):
5912 raise error.Abort(_(b'user quit'))
5911 raise error.Abort(_(b'user quit'))
5913 if mark and not pats:
5912 if mark and not pats:
5914 if ui.promptchoice(
5913 if ui.promptchoice(
5915 _(
5914 _(
5916 b'mark all unresolved files as resolved (yn)?'
5915 b'mark all unresolved files as resolved (yn)?'
5917 b'$$ &Yes $$ &No'
5916 b'$$ &Yes $$ &No'
5918 )
5917 )
5919 ):
5918 ):
5920 raise error.Abort(_(b'user quit'))
5919 raise error.Abort(_(b'user quit'))
5921 if unmark and not pats:
5920 if unmark and not pats:
5922 if ui.promptchoice(
5921 if ui.promptchoice(
5923 _(
5922 _(
5924 b'mark all resolved files as unresolved (yn)?'
5923 b'mark all resolved files as unresolved (yn)?'
5925 b'$$ &Yes $$ &No'
5924 b'$$ &Yes $$ &No'
5926 )
5925 )
5927 ):
5926 ):
5928 raise error.Abort(_(b'user quit'))
5927 raise error.Abort(_(b'user quit'))
5929
5928
5930 uipathfn = scmutil.getuipathfn(repo)
5929 uipathfn = scmutil.getuipathfn(repo)
5931
5930
5932 if show:
5931 if show:
5933 ui.pager(b'resolve')
5932 ui.pager(b'resolve')
5934 fm = ui.formatter(b'resolve', opts)
5933 fm = ui.formatter(b'resolve', opts)
5935 ms = mergemod.mergestate.read(repo)
5934 ms = mergemod.mergestate.read(repo)
5936 wctx = repo[None]
5935 wctx = repo[None]
5937 m = scmutil.match(wctx, pats, opts)
5936 m = scmutil.match(wctx, pats, opts)
5938
5937
5939 # Labels and keys based on merge state. Unresolved path conflicts show
5938 # Labels and keys based on merge state. Unresolved path conflicts show
5940 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5939 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5941 # resolved conflicts.
5940 # resolved conflicts.
5942 mergestateinfo = {
5941 mergestateinfo = {
5943 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5942 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5944 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5943 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5945 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5944 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5946 b'resolve.unresolved',
5945 b'resolve.unresolved',
5947 b'P',
5946 b'P',
5948 ),
5947 ),
5949 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5948 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5950 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5949 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5951 b'resolve.driverresolved',
5950 b'resolve.driverresolved',
5952 b'D',
5951 b'D',
5953 ),
5952 ),
5954 }
5953 }
5955
5954
5956 for f in ms:
5955 for f in ms:
5957 if not m(f):
5956 if not m(f):
5958 continue
5957 continue
5959
5958
5960 label, key = mergestateinfo[ms[f]]
5959 label, key = mergestateinfo[ms[f]]
5961 fm.startitem()
5960 fm.startitem()
5962 fm.context(ctx=wctx)
5961 fm.context(ctx=wctx)
5963 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5962 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5964 fm.data(path=f)
5963 fm.data(path=f)
5965 fm.plain(b'%s\n' % uipathfn(f), label=label)
5964 fm.plain(b'%s\n' % uipathfn(f), label=label)
5966 fm.end()
5965 fm.end()
5967 return 0
5966 return 0
5968
5967
5969 with repo.wlock():
5968 with repo.wlock():
5970 ms = mergemod.mergestate.read(repo)
5969 ms = mergemod.mergestate.read(repo)
5971
5970
5972 if not (ms.active() or repo.dirstate.p2() != nullid):
5971 if not (ms.active() or repo.dirstate.p2() != nullid):
5973 raise error.Abort(
5972 raise error.Abort(
5974 _(b'resolve command not applicable when not merging')
5973 _(b'resolve command not applicable when not merging')
5975 )
5974 )
5976
5975
5977 wctx = repo[None]
5976 wctx = repo[None]
5978
5977
5979 if (
5978 if (
5980 ms.mergedriver
5979 ms.mergedriver
5981 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5980 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5982 ):
5981 ):
5983 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5982 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5984 ms.commit()
5983 ms.commit()
5985 # allow mark and unmark to go through
5984 # allow mark and unmark to go through
5986 if not mark and not unmark and not proceed:
5985 if not mark and not unmark and not proceed:
5987 return 1
5986 return 1
5988
5987
5989 m = scmutil.match(wctx, pats, opts)
5988 m = scmutil.match(wctx, pats, opts)
5990 ret = 0
5989 ret = 0
5991 didwork = False
5990 didwork = False
5992 runconclude = False
5991 runconclude = False
5993
5992
5994 tocomplete = []
5993 tocomplete = []
5995 hasconflictmarkers = []
5994 hasconflictmarkers = []
5996 if mark:
5995 if mark:
5997 markcheck = ui.config(b'commands', b'resolve.mark-check')
5996 markcheck = ui.config(b'commands', b'resolve.mark-check')
5998 if markcheck not in [b'warn', b'abort']:
5997 if markcheck not in [b'warn', b'abort']:
5999 # Treat all invalid / unrecognized values as 'none'.
5998 # Treat all invalid / unrecognized values as 'none'.
6000 markcheck = False
5999 markcheck = False
6001 for f in ms:
6000 for f in ms:
6002 if not m(f):
6001 if not m(f):
6003 continue
6002 continue
6004
6003
6005 didwork = True
6004 didwork = True
6006
6005
6007 # don't let driver-resolved files be marked, and run the conclude
6006 # don't let driver-resolved files be marked, and run the conclude
6008 # step if asked to resolve
6007 # step if asked to resolve
6009 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6008 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6010 exact = m.exact(f)
6009 exact = m.exact(f)
6011 if mark:
6010 if mark:
6012 if exact:
6011 if exact:
6013 ui.warn(
6012 ui.warn(
6014 _(b'not marking %s as it is driver-resolved\n')
6013 _(b'not marking %s as it is driver-resolved\n')
6015 % uipathfn(f)
6014 % uipathfn(f)
6016 )
6015 )
6017 elif unmark:
6016 elif unmark:
6018 if exact:
6017 if exact:
6019 ui.warn(
6018 ui.warn(
6020 _(b'not unmarking %s as it is driver-resolved\n')
6019 _(b'not unmarking %s as it is driver-resolved\n')
6021 % uipathfn(f)
6020 % uipathfn(f)
6022 )
6021 )
6023 else:
6022 else:
6024 runconclude = True
6023 runconclude = True
6025 continue
6024 continue
6026
6025
6027 # path conflicts must be resolved manually
6026 # path conflicts must be resolved manually
6028 if ms[f] in (
6027 if ms[f] in (
6029 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6028 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6030 mergemod.MERGE_RECORD_RESOLVED_PATH,
6029 mergemod.MERGE_RECORD_RESOLVED_PATH,
6031 ):
6030 ):
6032 if mark:
6031 if mark:
6033 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6032 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6034 elif unmark:
6033 elif unmark:
6035 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6034 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6036 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6035 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6037 ui.warn(
6036 ui.warn(
6038 _(b'%s: path conflict must be resolved manually\n')
6037 _(b'%s: path conflict must be resolved manually\n')
6039 % uipathfn(f)
6038 % uipathfn(f)
6040 )
6039 )
6041 continue
6040 continue
6042
6041
6043 if mark:
6042 if mark:
6044 if markcheck:
6043 if markcheck:
6045 fdata = repo.wvfs.tryread(f)
6044 fdata = repo.wvfs.tryread(f)
6046 if (
6045 if (
6047 filemerge.hasconflictmarkers(fdata)
6046 filemerge.hasconflictmarkers(fdata)
6048 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6047 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6049 ):
6048 ):
6050 hasconflictmarkers.append(f)
6049 hasconflictmarkers.append(f)
6051 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6050 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6052 elif unmark:
6051 elif unmark:
6053 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6052 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6054 else:
6053 else:
6055 # backup pre-resolve (merge uses .orig for its own purposes)
6054 # backup pre-resolve (merge uses .orig for its own purposes)
6056 a = repo.wjoin(f)
6055 a = repo.wjoin(f)
6057 try:
6056 try:
6058 util.copyfile(a, a + b".resolve")
6057 util.copyfile(a, a + b".resolve")
6059 except (IOError, OSError) as inst:
6058 except (IOError, OSError) as inst:
6060 if inst.errno != errno.ENOENT:
6059 if inst.errno != errno.ENOENT:
6061 raise
6060 raise
6062
6061
6063 try:
6062 try:
6064 # preresolve file
6063 # preresolve file
6065 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6064 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6066 with ui.configoverride(overrides, b'resolve'):
6065 with ui.configoverride(overrides, b'resolve'):
6067 complete, r = ms.preresolve(f, wctx)
6066 complete, r = ms.preresolve(f, wctx)
6068 if not complete:
6067 if not complete:
6069 tocomplete.append(f)
6068 tocomplete.append(f)
6070 elif r:
6069 elif r:
6071 ret = 1
6070 ret = 1
6072 finally:
6071 finally:
6073 ms.commit()
6072 ms.commit()
6074
6073
6075 # replace filemerge's .orig file with our resolve file, but only
6074 # replace filemerge's .orig file with our resolve file, but only
6076 # for merges that are complete
6075 # for merges that are complete
6077 if complete:
6076 if complete:
6078 try:
6077 try:
6079 util.rename(
6078 util.rename(
6080 a + b".resolve", scmutil.backuppath(ui, repo, f)
6079 a + b".resolve", scmutil.backuppath(ui, repo, f)
6081 )
6080 )
6082 except OSError as inst:
6081 except OSError as inst:
6083 if inst.errno != errno.ENOENT:
6082 if inst.errno != errno.ENOENT:
6084 raise
6083 raise
6085
6084
6086 if hasconflictmarkers:
6085 if hasconflictmarkers:
6087 ui.warn(
6086 ui.warn(
6088 _(
6087 _(
6089 b'warning: the following files still have conflict '
6088 b'warning: the following files still have conflict '
6090 b'markers:\n'
6089 b'markers:\n'
6091 )
6090 )
6092 + b''.join(
6091 + b''.join(
6093 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6092 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6094 )
6093 )
6095 )
6094 )
6096 if markcheck == b'abort' and not all and not pats:
6095 if markcheck == b'abort' and not all and not pats:
6097 raise error.Abort(
6096 raise error.Abort(
6098 _(b'conflict markers detected'),
6097 _(b'conflict markers detected'),
6099 hint=_(b'use --all to mark anyway'),
6098 hint=_(b'use --all to mark anyway'),
6100 )
6099 )
6101
6100
6102 for f in tocomplete:
6101 for f in tocomplete:
6103 try:
6102 try:
6104 # resolve file
6103 # resolve file
6105 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6104 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6106 with ui.configoverride(overrides, b'resolve'):
6105 with ui.configoverride(overrides, b'resolve'):
6107 r = ms.resolve(f, wctx)
6106 r = ms.resolve(f, wctx)
6108 if r:
6107 if r:
6109 ret = 1
6108 ret = 1
6110 finally:
6109 finally:
6111 ms.commit()
6110 ms.commit()
6112
6111
6113 # replace filemerge's .orig file with our resolve file
6112 # replace filemerge's .orig file with our resolve file
6114 a = repo.wjoin(f)
6113 a = repo.wjoin(f)
6115 try:
6114 try:
6116 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6115 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6117 except OSError as inst:
6116 except OSError as inst:
6118 if inst.errno != errno.ENOENT:
6117 if inst.errno != errno.ENOENT:
6119 raise
6118 raise
6120
6119
6121 ms.commit()
6120 ms.commit()
6122 ms.recordactions()
6121 ms.recordactions()
6123
6122
6124 if not didwork and pats:
6123 if not didwork and pats:
6125 hint = None
6124 hint = None
6126 if not any([p for p in pats if p.find(b':') >= 0]):
6125 if not any([p for p in pats if p.find(b':') >= 0]):
6127 pats = [b'path:%s' % p for p in pats]
6126 pats = [b'path:%s' % p for p in pats]
6128 m = scmutil.match(wctx, pats, opts)
6127 m = scmutil.match(wctx, pats, opts)
6129 for f in ms:
6128 for f in ms:
6130 if not m(f):
6129 if not m(f):
6131 continue
6130 continue
6132
6131
6133 def flag(o):
6132 def flag(o):
6134 if o == b're_merge':
6133 if o == b're_merge':
6135 return b'--re-merge '
6134 return b'--re-merge '
6136 return b'-%s ' % o[0:1]
6135 return b'-%s ' % o[0:1]
6137
6136
6138 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6137 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6139 hint = _(b"(try: hg resolve %s%s)\n") % (
6138 hint = _(b"(try: hg resolve %s%s)\n") % (
6140 flags,
6139 flags,
6141 b' '.join(pats),
6140 b' '.join(pats),
6142 )
6141 )
6143 break
6142 break
6144 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6143 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6145 if hint:
6144 if hint:
6146 ui.warn(hint)
6145 ui.warn(hint)
6147 elif ms.mergedriver and ms.mdstate() != b's':
6146 elif ms.mergedriver and ms.mdstate() != b's':
6148 # run conclude step when either a driver-resolved file is requested
6147 # run conclude step when either a driver-resolved file is requested
6149 # or there are no driver-resolved files
6148 # or there are no driver-resolved files
6150 # we can't use 'ret' to determine whether any files are unresolved
6149 # we can't use 'ret' to determine whether any files are unresolved
6151 # because we might not have tried to resolve some
6150 # because we might not have tried to resolve some
6152 if (runconclude or not list(ms.driverresolved())) and not list(
6151 if (runconclude or not list(ms.driverresolved())) and not list(
6153 ms.unresolved()
6152 ms.unresolved()
6154 ):
6153 ):
6155 proceed = mergemod.driverconclude(repo, ms, wctx)
6154 proceed = mergemod.driverconclude(repo, ms, wctx)
6156 ms.commit()
6155 ms.commit()
6157 if not proceed:
6156 if not proceed:
6158 return 1
6157 return 1
6159
6158
6160 # Nudge users into finishing an unfinished operation
6159 # Nudge users into finishing an unfinished operation
6161 unresolvedf = list(ms.unresolved())
6160 unresolvedf = list(ms.unresolved())
6162 driverresolvedf = list(ms.driverresolved())
6161 driverresolvedf = list(ms.driverresolved())
6163 if not unresolvedf and not driverresolvedf:
6162 if not unresolvedf and not driverresolvedf:
6164 ui.status(_(b'(no more unresolved files)\n'))
6163 ui.status(_(b'(no more unresolved files)\n'))
6165 cmdutil.checkafterresolved(repo)
6164 cmdutil.checkafterresolved(repo)
6166 elif not unresolvedf:
6165 elif not unresolvedf:
6167 ui.status(
6166 ui.status(
6168 _(
6167 _(
6169 b'(no more unresolved files -- '
6168 b'(no more unresolved files -- '
6170 b'run "hg resolve --all" to conclude)\n'
6169 b'run "hg resolve --all" to conclude)\n'
6171 )
6170 )
6172 )
6171 )
6173
6172
6174 return ret
6173 return ret
6175
6174
6176
6175
6177 @command(
6176 @command(
6178 b'revert',
6177 b'revert',
6179 [
6178 [
6180 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6179 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6181 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6180 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6182 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6181 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6183 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6182 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6184 (b'i', b'interactive', None, _(b'interactively select the changes')),
6183 (b'i', b'interactive', None, _(b'interactively select the changes')),
6185 ]
6184 ]
6186 + walkopts
6185 + walkopts
6187 + dryrunopts,
6186 + dryrunopts,
6188 _(b'[OPTION]... [-r REV] [NAME]...'),
6187 _(b'[OPTION]... [-r REV] [NAME]...'),
6189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6190 )
6189 )
6191 def revert(ui, repo, *pats, **opts):
6190 def revert(ui, repo, *pats, **opts):
6192 """restore files to their checkout state
6191 """restore files to their checkout state
6193
6192
6194 .. note::
6193 .. note::
6195
6194
6196 To check out earlier revisions, you should use :hg:`update REV`.
6195 To check out earlier revisions, you should use :hg:`update REV`.
6197 To cancel an uncommitted merge (and lose your changes),
6196 To cancel an uncommitted merge (and lose your changes),
6198 use :hg:`merge --abort`.
6197 use :hg:`merge --abort`.
6199
6198
6200 With no revision specified, revert the specified files or directories
6199 With no revision specified, revert the specified files or directories
6201 to the contents they had in the parent of the working directory.
6200 to the contents they had in the parent of the working directory.
6202 This restores the contents of files to an unmodified
6201 This restores the contents of files to an unmodified
6203 state and unschedules adds, removes, copies, and renames. If the
6202 state and unschedules adds, removes, copies, and renames. If the
6204 working directory has two parents, you must explicitly specify a
6203 working directory has two parents, you must explicitly specify a
6205 revision.
6204 revision.
6206
6205
6207 Using the -r/--rev or -d/--date options, revert the given files or
6206 Using the -r/--rev or -d/--date options, revert the given files or
6208 directories to their states as of a specific revision. Because
6207 directories to their states as of a specific revision. Because
6209 revert does not change the working directory parents, this will
6208 revert does not change the working directory parents, this will
6210 cause these files to appear modified. This can be helpful to "back
6209 cause these files to appear modified. This can be helpful to "back
6211 out" some or all of an earlier change. See :hg:`backout` for a
6210 out" some or all of an earlier change. See :hg:`backout` for a
6212 related method.
6211 related method.
6213
6212
6214 Modified files are saved with a .orig suffix before reverting.
6213 Modified files are saved with a .orig suffix before reverting.
6215 To disable these backups, use --no-backup. It is possible to store
6214 To disable these backups, use --no-backup. It is possible to store
6216 the backup files in a custom directory relative to the root of the
6215 the backup files in a custom directory relative to the root of the
6217 repository by setting the ``ui.origbackuppath`` configuration
6216 repository by setting the ``ui.origbackuppath`` configuration
6218 option.
6217 option.
6219
6218
6220 See :hg:`help dates` for a list of formats valid for -d/--date.
6219 See :hg:`help dates` for a list of formats valid for -d/--date.
6221
6220
6222 See :hg:`help backout` for a way to reverse the effect of an
6221 See :hg:`help backout` for a way to reverse the effect of an
6223 earlier changeset.
6222 earlier changeset.
6224
6223
6225 Returns 0 on success.
6224 Returns 0 on success.
6226 """
6225 """
6227
6226
6228 opts = pycompat.byteskwargs(opts)
6227 opts = pycompat.byteskwargs(opts)
6229 if opts.get(b"date"):
6228 if opts.get(b"date"):
6230 if opts.get(b"rev"):
6229 if opts.get(b"rev"):
6231 raise error.Abort(_(b"you can't specify a revision and a date"))
6230 raise error.Abort(_(b"you can't specify a revision and a date"))
6232 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6231 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6233
6232
6234 parent, p2 = repo.dirstate.parents()
6233 parent, p2 = repo.dirstate.parents()
6235 if not opts.get(b'rev') and p2 != nullid:
6234 if not opts.get(b'rev') and p2 != nullid:
6236 # revert after merge is a trap for new users (issue2915)
6235 # revert after merge is a trap for new users (issue2915)
6237 raise error.Abort(
6236 raise error.Abort(
6238 _(b'uncommitted merge with no revision specified'),
6237 _(b'uncommitted merge with no revision specified'),
6239 hint=_(b"use 'hg update' or see 'hg help revert'"),
6238 hint=_(b"use 'hg update' or see 'hg help revert'"),
6240 )
6239 )
6241
6240
6242 rev = opts.get(b'rev')
6241 rev = opts.get(b'rev')
6243 if rev:
6242 if rev:
6244 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6243 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6245 ctx = scmutil.revsingle(repo, rev)
6244 ctx = scmutil.revsingle(repo, rev)
6246
6245
6247 if not (
6246 if not (
6248 pats
6247 pats
6249 or opts.get(b'include')
6248 or opts.get(b'include')
6250 or opts.get(b'exclude')
6249 or opts.get(b'exclude')
6251 or opts.get(b'all')
6250 or opts.get(b'all')
6252 or opts.get(b'interactive')
6251 or opts.get(b'interactive')
6253 ):
6252 ):
6254 msg = _(b"no files or directories specified")
6253 msg = _(b"no files or directories specified")
6255 if p2 != nullid:
6254 if p2 != nullid:
6256 hint = _(
6255 hint = _(
6257 b"uncommitted merge, use --all to discard all changes,"
6256 b"uncommitted merge, use --all to discard all changes,"
6258 b" or 'hg update -C .' to abort the merge"
6257 b" or 'hg update -C .' to abort the merge"
6259 )
6258 )
6260 raise error.Abort(msg, hint=hint)
6259 raise error.Abort(msg, hint=hint)
6261 dirty = any(repo.status())
6260 dirty = any(repo.status())
6262 node = ctx.node()
6261 node = ctx.node()
6263 if node != parent:
6262 if node != parent:
6264 if dirty:
6263 if dirty:
6265 hint = (
6264 hint = (
6266 _(
6265 _(
6267 b"uncommitted changes, use --all to discard all"
6266 b"uncommitted changes, use --all to discard all"
6268 b" changes, or 'hg update %d' to update"
6267 b" changes, or 'hg update %d' to update"
6269 )
6268 )
6270 % ctx.rev()
6269 % ctx.rev()
6271 )
6270 )
6272 else:
6271 else:
6273 hint = (
6272 hint = (
6274 _(
6273 _(
6275 b"use --all to revert all files,"
6274 b"use --all to revert all files,"
6276 b" or 'hg update %d' to update"
6275 b" or 'hg update %d' to update"
6277 )
6276 )
6278 % ctx.rev()
6277 % ctx.rev()
6279 )
6278 )
6280 elif dirty:
6279 elif dirty:
6281 hint = _(b"uncommitted changes, use --all to discard all changes")
6280 hint = _(b"uncommitted changes, use --all to discard all changes")
6282 else:
6281 else:
6283 hint = _(b"use --all to revert all files")
6282 hint = _(b"use --all to revert all files")
6284 raise error.Abort(msg, hint=hint)
6283 raise error.Abort(msg, hint=hint)
6285
6284
6286 return cmdutil.revert(
6285 return cmdutil.revert(
6287 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6286 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6288 )
6287 )
6289
6288
6290
6289
6291 @command(
6290 @command(
6292 b'rollback',
6291 b'rollback',
6293 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6292 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6294 helpcategory=command.CATEGORY_MAINTENANCE,
6293 helpcategory=command.CATEGORY_MAINTENANCE,
6295 )
6294 )
6296 def rollback(ui, repo, **opts):
6295 def rollback(ui, repo, **opts):
6297 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6296 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6298
6297
6299 Please use :hg:`commit --amend` instead of rollback to correct
6298 Please use :hg:`commit --amend` instead of rollback to correct
6300 mistakes in the last commit.
6299 mistakes in the last commit.
6301
6300
6302 This command should be used with care. There is only one level of
6301 This command should be used with care. There is only one level of
6303 rollback, and there is no way to undo a rollback. It will also
6302 rollback, and there is no way to undo a rollback. It will also
6304 restore the dirstate at the time of the last transaction, losing
6303 restore the dirstate at the time of the last transaction, losing
6305 any dirstate changes since that time. This command does not alter
6304 any dirstate changes since that time. This command does not alter
6306 the working directory.
6305 the working directory.
6307
6306
6308 Transactions are used to encapsulate the effects of all commands
6307 Transactions are used to encapsulate the effects of all commands
6309 that create new changesets or propagate existing changesets into a
6308 that create new changesets or propagate existing changesets into a
6310 repository.
6309 repository.
6311
6310
6312 .. container:: verbose
6311 .. container:: verbose
6313
6312
6314 For example, the following commands are transactional, and their
6313 For example, the following commands are transactional, and their
6315 effects can be rolled back:
6314 effects can be rolled back:
6316
6315
6317 - commit
6316 - commit
6318 - import
6317 - import
6319 - pull
6318 - pull
6320 - push (with this repository as the destination)
6319 - push (with this repository as the destination)
6321 - unbundle
6320 - unbundle
6322
6321
6323 To avoid permanent data loss, rollback will refuse to rollback a
6322 To avoid permanent data loss, rollback will refuse to rollback a
6324 commit transaction if it isn't checked out. Use --force to
6323 commit transaction if it isn't checked out. Use --force to
6325 override this protection.
6324 override this protection.
6326
6325
6327 The rollback command can be entirely disabled by setting the
6326 The rollback command can be entirely disabled by setting the
6328 ``ui.rollback`` configuration setting to false. If you're here
6327 ``ui.rollback`` configuration setting to false. If you're here
6329 because you want to use rollback and it's disabled, you can
6328 because you want to use rollback and it's disabled, you can
6330 re-enable the command by setting ``ui.rollback`` to true.
6329 re-enable the command by setting ``ui.rollback`` to true.
6331
6330
6332 This command is not intended for use on public repositories. Once
6331 This command is not intended for use on public repositories. Once
6333 changes are visible for pull by other users, rolling a transaction
6332 changes are visible for pull by other users, rolling a transaction
6334 back locally is ineffective (someone else may already have pulled
6333 back locally is ineffective (someone else may already have pulled
6335 the changes). Furthermore, a race is possible with readers of the
6334 the changes). Furthermore, a race is possible with readers of the
6336 repository; for example an in-progress pull from the repository
6335 repository; for example an in-progress pull from the repository
6337 may fail if a rollback is performed.
6336 may fail if a rollback is performed.
6338
6337
6339 Returns 0 on success, 1 if no rollback data is available.
6338 Returns 0 on success, 1 if no rollback data is available.
6340 """
6339 """
6341 if not ui.configbool(b'ui', b'rollback'):
6340 if not ui.configbool(b'ui', b'rollback'):
6342 raise error.Abort(
6341 raise error.Abort(
6343 _(b'rollback is disabled because it is unsafe'),
6342 _(b'rollback is disabled because it is unsafe'),
6344 hint=b'see `hg help -v rollback` for information',
6343 hint=b'see `hg help -v rollback` for information',
6345 )
6344 )
6346 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6345 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6347
6346
6348
6347
6349 @command(
6348 @command(
6350 b'root',
6349 b'root',
6351 [] + formatteropts,
6350 [] + formatteropts,
6352 intents={INTENT_READONLY},
6351 intents={INTENT_READONLY},
6353 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6352 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6354 )
6353 )
6355 def root(ui, repo, **opts):
6354 def root(ui, repo, **opts):
6356 """print the root (top) of the current working directory
6355 """print the root (top) of the current working directory
6357
6356
6358 Print the root directory of the current repository.
6357 Print the root directory of the current repository.
6359
6358
6360 .. container:: verbose
6359 .. container:: verbose
6361
6360
6362 Template:
6361 Template:
6363
6362
6364 The following keywords are supported in addition to the common template
6363 The following keywords are supported in addition to the common template
6365 keywords and functions. See also :hg:`help templates`.
6364 keywords and functions. See also :hg:`help templates`.
6366
6365
6367 :hgpath: String. Path to the .hg directory.
6366 :hgpath: String. Path to the .hg directory.
6368 :storepath: String. Path to the directory holding versioned data.
6367 :storepath: String. Path to the directory holding versioned data.
6369
6368
6370 Returns 0 on success.
6369 Returns 0 on success.
6371 """
6370 """
6372 opts = pycompat.byteskwargs(opts)
6371 opts = pycompat.byteskwargs(opts)
6373 with ui.formatter(b'root', opts) as fm:
6372 with ui.formatter(b'root', opts) as fm:
6374 fm.startitem()
6373 fm.startitem()
6375 fm.write(b'reporoot', b'%s\n', repo.root)
6374 fm.write(b'reporoot', b'%s\n', repo.root)
6376 fm.data(hgpath=repo.path, storepath=repo.spath)
6375 fm.data(hgpath=repo.path, storepath=repo.spath)
6377
6376
6378
6377
6379 @command(
6378 @command(
6380 b'serve',
6379 b'serve',
6381 [
6380 [
6382 (
6381 (
6383 b'A',
6382 b'A',
6384 b'accesslog',
6383 b'accesslog',
6385 b'',
6384 b'',
6386 _(b'name of access log file to write to'),
6385 _(b'name of access log file to write to'),
6387 _(b'FILE'),
6386 _(b'FILE'),
6388 ),
6387 ),
6389 (b'd', b'daemon', None, _(b'run server in background')),
6388 (b'd', b'daemon', None, _(b'run server in background')),
6390 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6389 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6391 (
6390 (
6392 b'E',
6391 b'E',
6393 b'errorlog',
6392 b'errorlog',
6394 b'',
6393 b'',
6395 _(b'name of error log file to write to'),
6394 _(b'name of error log file to write to'),
6396 _(b'FILE'),
6395 _(b'FILE'),
6397 ),
6396 ),
6398 # use string type, then we can check if something was passed
6397 # use string type, then we can check if something was passed
6399 (
6398 (
6400 b'p',
6399 b'p',
6401 b'port',
6400 b'port',
6402 b'',
6401 b'',
6403 _(b'port to listen on (default: 8000)'),
6402 _(b'port to listen on (default: 8000)'),
6404 _(b'PORT'),
6403 _(b'PORT'),
6405 ),
6404 ),
6406 (
6405 (
6407 b'a',
6406 b'a',
6408 b'address',
6407 b'address',
6409 b'',
6408 b'',
6410 _(b'address to listen on (default: all interfaces)'),
6409 _(b'address to listen on (default: all interfaces)'),
6411 _(b'ADDR'),
6410 _(b'ADDR'),
6412 ),
6411 ),
6413 (
6412 (
6414 b'',
6413 b'',
6415 b'prefix',
6414 b'prefix',
6416 b'',
6415 b'',
6417 _(b'prefix path to serve from (default: server root)'),
6416 _(b'prefix path to serve from (default: server root)'),
6418 _(b'PREFIX'),
6417 _(b'PREFIX'),
6419 ),
6418 ),
6420 (
6419 (
6421 b'n',
6420 b'n',
6422 b'name',
6421 b'name',
6423 b'',
6422 b'',
6424 _(b'name to show in web pages (default: working directory)'),
6423 _(b'name to show in web pages (default: working directory)'),
6425 _(b'NAME'),
6424 _(b'NAME'),
6426 ),
6425 ),
6427 (
6426 (
6428 b'',
6427 b'',
6429 b'web-conf',
6428 b'web-conf',
6430 b'',
6429 b'',
6431 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6430 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6432 _(b'FILE'),
6431 _(b'FILE'),
6433 ),
6432 ),
6434 (
6433 (
6435 b'',
6434 b'',
6436 b'webdir-conf',
6435 b'webdir-conf',
6437 b'',
6436 b'',
6438 _(b'name of the hgweb config file (DEPRECATED)'),
6437 _(b'name of the hgweb config file (DEPRECATED)'),
6439 _(b'FILE'),
6438 _(b'FILE'),
6440 ),
6439 ),
6441 (
6440 (
6442 b'',
6441 b'',
6443 b'pid-file',
6442 b'pid-file',
6444 b'',
6443 b'',
6445 _(b'name of file to write process ID to'),
6444 _(b'name of file to write process ID to'),
6446 _(b'FILE'),
6445 _(b'FILE'),
6447 ),
6446 ),
6448 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6447 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6449 (
6448 (
6450 b'',
6449 b'',
6451 b'cmdserver',
6450 b'cmdserver',
6452 b'',
6451 b'',
6453 _(b'for remote clients (ADVANCED)'),
6452 _(b'for remote clients (ADVANCED)'),
6454 _(b'MODE'),
6453 _(b'MODE'),
6455 ),
6454 ),
6456 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6455 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6457 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6456 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6458 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6457 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6459 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6458 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6460 (b'', b'print-url', None, _(b'start and print only the URL')),
6459 (b'', b'print-url', None, _(b'start and print only the URL')),
6461 ]
6460 ]
6462 + subrepoopts,
6461 + subrepoopts,
6463 _(b'[OPTION]...'),
6462 _(b'[OPTION]...'),
6464 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6463 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6465 helpbasic=True,
6464 helpbasic=True,
6466 optionalrepo=True,
6465 optionalrepo=True,
6467 )
6466 )
6468 def serve(ui, repo, **opts):
6467 def serve(ui, repo, **opts):
6469 """start stand-alone webserver
6468 """start stand-alone webserver
6470
6469
6471 Start a local HTTP repository browser and pull server. You can use
6470 Start a local HTTP repository browser and pull server. You can use
6472 this for ad-hoc sharing and browsing of repositories. It is
6471 this for ad-hoc sharing and browsing of repositories. It is
6473 recommended to use a real web server to serve a repository for
6472 recommended to use a real web server to serve a repository for
6474 longer periods of time.
6473 longer periods of time.
6475
6474
6476 Please note that the server does not implement access control.
6475 Please note that the server does not implement access control.
6477 This means that, by default, anybody can read from the server and
6476 This means that, by default, anybody can read from the server and
6478 nobody can write to it by default. Set the ``web.allow-push``
6477 nobody can write to it by default. Set the ``web.allow-push``
6479 option to ``*`` to allow everybody to push to the server. You
6478 option to ``*`` to allow everybody to push to the server. You
6480 should use a real web server if you need to authenticate users.
6479 should use a real web server if you need to authenticate users.
6481
6480
6482 By default, the server logs accesses to stdout and errors to
6481 By default, the server logs accesses to stdout and errors to
6483 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6482 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6484 files.
6483 files.
6485
6484
6486 To have the server choose a free port number to listen on, specify
6485 To have the server choose a free port number to listen on, specify
6487 a port number of 0; in this case, the server will print the port
6486 a port number of 0; in this case, the server will print the port
6488 number it uses.
6487 number it uses.
6489
6488
6490 Returns 0 on success.
6489 Returns 0 on success.
6491 """
6490 """
6492
6491
6493 opts = pycompat.byteskwargs(opts)
6492 opts = pycompat.byteskwargs(opts)
6494 if opts[b"stdio"] and opts[b"cmdserver"]:
6493 if opts[b"stdio"] and opts[b"cmdserver"]:
6495 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6494 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6496 if opts[b"print_url"] and ui.verbose:
6495 if opts[b"print_url"] and ui.verbose:
6497 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6496 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6498
6497
6499 if opts[b"stdio"]:
6498 if opts[b"stdio"]:
6500 if repo is None:
6499 if repo is None:
6501 raise error.RepoError(
6500 raise error.RepoError(
6502 _(b"there is no Mercurial repository here (.hg not found)")
6501 _(b"there is no Mercurial repository here (.hg not found)")
6503 )
6502 )
6504 s = wireprotoserver.sshserver(ui, repo)
6503 s = wireprotoserver.sshserver(ui, repo)
6505 s.serve_forever()
6504 s.serve_forever()
6506
6505
6507 service = server.createservice(ui, repo, opts)
6506 service = server.createservice(ui, repo, opts)
6508 return server.runservice(opts, initfn=service.init, runfn=service.run)
6507 return server.runservice(opts, initfn=service.init, runfn=service.run)
6509
6508
6510
6509
6511 @command(
6510 @command(
6512 b'shelve',
6511 b'shelve',
6513 [
6512 [
6514 (
6513 (
6515 b'A',
6514 b'A',
6516 b'addremove',
6515 b'addremove',
6517 None,
6516 None,
6518 _(b'mark new/missing files as added/removed before shelving'),
6517 _(b'mark new/missing files as added/removed before shelving'),
6519 ),
6518 ),
6520 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6519 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6521 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6520 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6522 (
6521 (
6523 b'',
6522 b'',
6524 b'date',
6523 b'date',
6525 b'',
6524 b'',
6526 _(b'shelve with the specified commit date'),
6525 _(b'shelve with the specified commit date'),
6527 _(b'DATE'),
6526 _(b'DATE'),
6528 ),
6527 ),
6529 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6528 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6530 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6529 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6531 (
6530 (
6532 b'k',
6531 b'k',
6533 b'keep',
6532 b'keep',
6534 False,
6533 False,
6535 _(b'shelve, but keep changes in the working directory'),
6534 _(b'shelve, but keep changes in the working directory'),
6536 ),
6535 ),
6537 (b'l', b'list', None, _(b'list current shelves')),
6536 (b'l', b'list', None, _(b'list current shelves')),
6538 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6537 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6539 (
6538 (
6540 b'n',
6539 b'n',
6541 b'name',
6540 b'name',
6542 b'',
6541 b'',
6543 _(b'use the given name for the shelved commit'),
6542 _(b'use the given name for the shelved commit'),
6544 _(b'NAME'),
6543 _(b'NAME'),
6545 ),
6544 ),
6546 (
6545 (
6547 b'p',
6546 b'p',
6548 b'patch',
6547 b'patch',
6549 None,
6548 None,
6550 _(
6549 _(
6551 b'output patches for changes (provide the names of the shelved '
6550 b'output patches for changes (provide the names of the shelved '
6552 b'changes as positional arguments)'
6551 b'changes as positional arguments)'
6553 ),
6552 ),
6554 ),
6553 ),
6555 (b'i', b'interactive', None, _(b'interactive mode')),
6554 (b'i', b'interactive', None, _(b'interactive mode')),
6556 (
6555 (
6557 b'',
6556 b'',
6558 b'stat',
6557 b'stat',
6559 None,
6558 None,
6560 _(
6559 _(
6561 b'output diffstat-style summary of changes (provide the names of '
6560 b'output diffstat-style summary of changes (provide the names of '
6562 b'the shelved changes as positional arguments)'
6561 b'the shelved changes as positional arguments)'
6563 ),
6562 ),
6564 ),
6563 ),
6565 ]
6564 ]
6566 + cmdutil.walkopts,
6565 + cmdutil.walkopts,
6567 _(b'hg shelve [OPTION]... [FILE]...'),
6566 _(b'hg shelve [OPTION]... [FILE]...'),
6568 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6567 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6569 )
6568 )
6570 def shelve(ui, repo, *pats, **opts):
6569 def shelve(ui, repo, *pats, **opts):
6571 '''save and set aside changes from the working directory
6570 '''save and set aside changes from the working directory
6572
6571
6573 Shelving takes files that "hg status" reports as not clean, saves
6572 Shelving takes files that "hg status" reports as not clean, saves
6574 the modifications to a bundle (a shelved change), and reverts the
6573 the modifications to a bundle (a shelved change), and reverts the
6575 files so that their state in the working directory becomes clean.
6574 files so that their state in the working directory becomes clean.
6576
6575
6577 To restore these changes to the working directory, using "hg
6576 To restore these changes to the working directory, using "hg
6578 unshelve"; this will work even if you switch to a different
6577 unshelve"; this will work even if you switch to a different
6579 commit.
6578 commit.
6580
6579
6581 When no files are specified, "hg shelve" saves all not-clean
6580 When no files are specified, "hg shelve" saves all not-clean
6582 files. If specific files or directories are named, only changes to
6581 files. If specific files or directories are named, only changes to
6583 those files are shelved.
6582 those files are shelved.
6584
6583
6585 In bare shelve (when no files are specified, without interactive,
6584 In bare shelve (when no files are specified, without interactive,
6586 include and exclude option), shelving remembers information if the
6585 include and exclude option), shelving remembers information if the
6587 working directory was on newly created branch, in other words working
6586 working directory was on newly created branch, in other words working
6588 directory was on different branch than its first parent. In this
6587 directory was on different branch than its first parent. In this
6589 situation unshelving restores branch information to the working directory.
6588 situation unshelving restores branch information to the working directory.
6590
6589
6591 Each shelved change has a name that makes it easier to find later.
6590 Each shelved change has a name that makes it easier to find later.
6592 The name of a shelved change defaults to being based on the active
6591 The name of a shelved change defaults to being based on the active
6593 bookmark, or if there is no active bookmark, the current named
6592 bookmark, or if there is no active bookmark, the current named
6594 branch. To specify a different name, use ``--name``.
6593 branch. To specify a different name, use ``--name``.
6595
6594
6596 To see a list of existing shelved changes, use the ``--list``
6595 To see a list of existing shelved changes, use the ``--list``
6597 option. For each shelved change, this will print its name, age,
6596 option. For each shelved change, this will print its name, age,
6598 and description; use ``--patch`` or ``--stat`` for more details.
6597 and description; use ``--patch`` or ``--stat`` for more details.
6599
6598
6600 To delete specific shelved changes, use ``--delete``. To delete
6599 To delete specific shelved changes, use ``--delete``. To delete
6601 all shelved changes, use ``--cleanup``.
6600 all shelved changes, use ``--cleanup``.
6602 '''
6601 '''
6603 opts = pycompat.byteskwargs(opts)
6602 opts = pycompat.byteskwargs(opts)
6604 allowables = [
6603 allowables = [
6605 (b'addremove', {b'create'}), # 'create' is pseudo action
6604 (b'addremove', {b'create'}), # 'create' is pseudo action
6606 (b'unknown', {b'create'}),
6605 (b'unknown', {b'create'}),
6607 (b'cleanup', {b'cleanup'}),
6606 (b'cleanup', {b'cleanup'}),
6608 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6607 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6609 (b'delete', {b'delete'}),
6608 (b'delete', {b'delete'}),
6610 (b'edit', {b'create'}),
6609 (b'edit', {b'create'}),
6611 (b'keep', {b'create'}),
6610 (b'keep', {b'create'}),
6612 (b'list', {b'list'}),
6611 (b'list', {b'list'}),
6613 (b'message', {b'create'}),
6612 (b'message', {b'create'}),
6614 (b'name', {b'create'}),
6613 (b'name', {b'create'}),
6615 (b'patch', {b'patch', b'list'}),
6614 (b'patch', {b'patch', b'list'}),
6616 (b'stat', {b'stat', b'list'}),
6615 (b'stat', {b'stat', b'list'}),
6617 ]
6616 ]
6618
6617
6619 def checkopt(opt):
6618 def checkopt(opt):
6620 if opts.get(opt):
6619 if opts.get(opt):
6621 for i, allowable in allowables:
6620 for i, allowable in allowables:
6622 if opts[i] and opt not in allowable:
6621 if opts[i] and opt not in allowable:
6623 raise error.Abort(
6622 raise error.Abort(
6624 _(
6623 _(
6625 b"options '--%s' and '--%s' may not be "
6624 b"options '--%s' and '--%s' may not be "
6626 b"used together"
6625 b"used together"
6627 )
6626 )
6628 % (opt, i)
6627 % (opt, i)
6629 )
6628 )
6630 return True
6629 return True
6631
6630
6632 if checkopt(b'cleanup'):
6631 if checkopt(b'cleanup'):
6633 if pats:
6632 if pats:
6634 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6633 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6635 return shelvemod.cleanupcmd(ui, repo)
6634 return shelvemod.cleanupcmd(ui, repo)
6636 elif checkopt(b'delete'):
6635 elif checkopt(b'delete'):
6637 return shelvemod.deletecmd(ui, repo, pats)
6636 return shelvemod.deletecmd(ui, repo, pats)
6638 elif checkopt(b'list'):
6637 elif checkopt(b'list'):
6639 return shelvemod.listcmd(ui, repo, pats, opts)
6638 return shelvemod.listcmd(ui, repo, pats, opts)
6640 elif checkopt(b'patch') or checkopt(b'stat'):
6639 elif checkopt(b'patch') or checkopt(b'stat'):
6641 return shelvemod.patchcmds(ui, repo, pats, opts)
6640 return shelvemod.patchcmds(ui, repo, pats, opts)
6642 else:
6641 else:
6643 return shelvemod.createcmd(ui, repo, pats, opts)
6642 return shelvemod.createcmd(ui, repo, pats, opts)
6644
6643
6645
6644
6646 _NOTTERSE = b'nothing'
6645 _NOTTERSE = b'nothing'
6647
6646
6648
6647
6649 @command(
6648 @command(
6650 b'status|st',
6649 b'status|st',
6651 [
6650 [
6652 (b'A', b'all', None, _(b'show status of all files')),
6651 (b'A', b'all', None, _(b'show status of all files')),
6653 (b'm', b'modified', None, _(b'show only modified files')),
6652 (b'm', b'modified', None, _(b'show only modified files')),
6654 (b'a', b'added', None, _(b'show only added files')),
6653 (b'a', b'added', None, _(b'show only added files')),
6655 (b'r', b'removed', None, _(b'show only removed files')),
6654 (b'r', b'removed', None, _(b'show only removed files')),
6656 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6655 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6657 (b'c', b'clean', None, _(b'show only files without changes')),
6656 (b'c', b'clean', None, _(b'show only files without changes')),
6658 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6657 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6659 (b'i', b'ignored', None, _(b'show only ignored files')),
6658 (b'i', b'ignored', None, _(b'show only ignored files')),
6660 (b'n', b'no-status', None, _(b'hide status prefix')),
6659 (b'n', b'no-status', None, _(b'hide status prefix')),
6661 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6660 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6662 (b'C', b'copies', None, _(b'show source of copied files')),
6661 (b'C', b'copies', None, _(b'show source of copied files')),
6663 (
6662 (
6664 b'0',
6663 b'0',
6665 b'print0',
6664 b'print0',
6666 None,
6665 None,
6667 _(b'end filenames with NUL, for use with xargs'),
6666 _(b'end filenames with NUL, for use with xargs'),
6668 ),
6667 ),
6669 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6668 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6670 (
6669 (
6671 b'',
6670 b'',
6672 b'change',
6671 b'change',
6673 b'',
6672 b'',
6674 _(b'list the changed files of a revision'),
6673 _(b'list the changed files of a revision'),
6675 _(b'REV'),
6674 _(b'REV'),
6676 ),
6675 ),
6677 ]
6676 ]
6678 + walkopts
6677 + walkopts
6679 + subrepoopts
6678 + subrepoopts
6680 + formatteropts,
6679 + formatteropts,
6681 _(b'[OPTION]... [FILE]...'),
6680 _(b'[OPTION]... [FILE]...'),
6682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6681 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6683 helpbasic=True,
6682 helpbasic=True,
6684 inferrepo=True,
6683 inferrepo=True,
6685 intents={INTENT_READONLY},
6684 intents={INTENT_READONLY},
6686 )
6685 )
6687 def status(ui, repo, *pats, **opts):
6686 def status(ui, repo, *pats, **opts):
6688 """show changed files in the working directory
6687 """show changed files in the working directory
6689
6688
6690 Show status of files in the repository. If names are given, only
6689 Show status of files in the repository. If names are given, only
6691 files that match are shown. Files that are clean or ignored or
6690 files that match are shown. Files that are clean or ignored or
6692 the source of a copy/move operation, are not listed unless
6691 the source of a copy/move operation, are not listed unless
6693 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6692 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6694 Unless options described with "show only ..." are given, the
6693 Unless options described with "show only ..." are given, the
6695 options -mardu are used.
6694 options -mardu are used.
6696
6695
6697 Option -q/--quiet hides untracked (unknown and ignored) files
6696 Option -q/--quiet hides untracked (unknown and ignored) files
6698 unless explicitly requested with -u/--unknown or -i/--ignored.
6697 unless explicitly requested with -u/--unknown or -i/--ignored.
6699
6698
6700 .. note::
6699 .. note::
6701
6700
6702 :hg:`status` may appear to disagree with diff if permissions have
6701 :hg:`status` may appear to disagree with diff if permissions have
6703 changed or a merge has occurred. The standard diff format does
6702 changed or a merge has occurred. The standard diff format does
6704 not report permission changes and diff only reports changes
6703 not report permission changes and diff only reports changes
6705 relative to one merge parent.
6704 relative to one merge parent.
6706
6705
6707 If one revision is given, it is used as the base revision.
6706 If one revision is given, it is used as the base revision.
6708 If two revisions are given, the differences between them are
6707 If two revisions are given, the differences between them are
6709 shown. The --change option can also be used as a shortcut to list
6708 shown. The --change option can also be used as a shortcut to list
6710 the changed files of a revision from its first parent.
6709 the changed files of a revision from its first parent.
6711
6710
6712 The codes used to show the status of files are::
6711 The codes used to show the status of files are::
6713
6712
6714 M = modified
6713 M = modified
6715 A = added
6714 A = added
6716 R = removed
6715 R = removed
6717 C = clean
6716 C = clean
6718 ! = missing (deleted by non-hg command, but still tracked)
6717 ! = missing (deleted by non-hg command, but still tracked)
6719 ? = not tracked
6718 ? = not tracked
6720 I = ignored
6719 I = ignored
6721 = origin of the previous file (with --copies)
6720 = origin of the previous file (with --copies)
6722
6721
6723 .. container:: verbose
6722 .. container:: verbose
6724
6723
6725 The -t/--terse option abbreviates the output by showing only the directory
6724 The -t/--terse option abbreviates the output by showing only the directory
6726 name if all the files in it share the same status. The option takes an
6725 name if all the files in it share the same status. The option takes an
6727 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6726 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6728 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6727 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6729 for 'ignored' and 'c' for clean.
6728 for 'ignored' and 'c' for clean.
6730
6729
6731 It abbreviates only those statuses which are passed. Note that clean and
6730 It abbreviates only those statuses which are passed. Note that clean and
6732 ignored files are not displayed with '--terse ic' unless the -c/--clean
6731 ignored files are not displayed with '--terse ic' unless the -c/--clean
6733 and -i/--ignored options are also used.
6732 and -i/--ignored options are also used.
6734
6733
6735 The -v/--verbose option shows information when the repository is in an
6734 The -v/--verbose option shows information when the repository is in an
6736 unfinished merge, shelve, rebase state etc. You can have this behavior
6735 unfinished merge, shelve, rebase state etc. You can have this behavior
6737 turned on by default by enabling the ``commands.status.verbose`` option.
6736 turned on by default by enabling the ``commands.status.verbose`` option.
6738
6737
6739 You can skip displaying some of these states by setting
6738 You can skip displaying some of these states by setting
6740 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6739 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6741 'histedit', 'merge', 'rebase', or 'unshelve'.
6740 'histedit', 'merge', 'rebase', or 'unshelve'.
6742
6741
6743 Template:
6742 Template:
6744
6743
6745 The following keywords are supported in addition to the common template
6744 The following keywords are supported in addition to the common template
6746 keywords and functions. See also :hg:`help templates`.
6745 keywords and functions. See also :hg:`help templates`.
6747
6746
6748 :path: String. Repository-absolute path of the file.
6747 :path: String. Repository-absolute path of the file.
6749 :source: String. Repository-absolute path of the file originated from.
6748 :source: String. Repository-absolute path of the file originated from.
6750 Available if ``--copies`` is specified.
6749 Available if ``--copies`` is specified.
6751 :status: String. Character denoting file's status.
6750 :status: String. Character denoting file's status.
6752
6751
6753 Examples:
6752 Examples:
6754
6753
6755 - show changes in the working directory relative to a
6754 - show changes in the working directory relative to a
6756 changeset::
6755 changeset::
6757
6756
6758 hg status --rev 9353
6757 hg status --rev 9353
6759
6758
6760 - show changes in the working directory relative to the
6759 - show changes in the working directory relative to the
6761 current directory (see :hg:`help patterns` for more information)::
6760 current directory (see :hg:`help patterns` for more information)::
6762
6761
6763 hg status re:
6762 hg status re:
6764
6763
6765 - show all changes including copies in an existing changeset::
6764 - show all changes including copies in an existing changeset::
6766
6765
6767 hg status --copies --change 9353
6766 hg status --copies --change 9353
6768
6767
6769 - get a NUL separated list of added files, suitable for xargs::
6768 - get a NUL separated list of added files, suitable for xargs::
6770
6769
6771 hg status -an0
6770 hg status -an0
6772
6771
6773 - show more information about the repository status, abbreviating
6772 - show more information about the repository status, abbreviating
6774 added, removed, modified, deleted, and untracked paths::
6773 added, removed, modified, deleted, and untracked paths::
6775
6774
6776 hg status -v -t mardu
6775 hg status -v -t mardu
6777
6776
6778 Returns 0 on success.
6777 Returns 0 on success.
6779
6778
6780 """
6779 """
6781
6780
6782 opts = pycompat.byteskwargs(opts)
6781 opts = pycompat.byteskwargs(opts)
6783 revs = opts.get(b'rev')
6782 revs = opts.get(b'rev')
6784 change = opts.get(b'change')
6783 change = opts.get(b'change')
6785 terse = opts.get(b'terse')
6784 terse = opts.get(b'terse')
6786 if terse is _NOTTERSE:
6785 if terse is _NOTTERSE:
6787 if revs:
6786 if revs:
6788 terse = b''
6787 terse = b''
6789 else:
6788 else:
6790 terse = ui.config(b'commands', b'status.terse')
6789 terse = ui.config(b'commands', b'status.terse')
6791
6790
6792 if revs and change:
6791 if revs and change:
6793 msg = _(b'cannot specify --rev and --change at the same time')
6792 msg = _(b'cannot specify --rev and --change at the same time')
6794 raise error.Abort(msg)
6793 raise error.Abort(msg)
6795 elif revs and terse:
6794 elif revs and terse:
6796 msg = _(b'cannot use --terse with --rev')
6795 msg = _(b'cannot use --terse with --rev')
6797 raise error.Abort(msg)
6796 raise error.Abort(msg)
6798 elif change:
6797 elif change:
6799 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6798 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6800 ctx2 = scmutil.revsingle(repo, change, None)
6799 ctx2 = scmutil.revsingle(repo, change, None)
6801 ctx1 = ctx2.p1()
6800 ctx1 = ctx2.p1()
6802 else:
6801 else:
6803 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6802 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6804 ctx1, ctx2 = scmutil.revpair(repo, revs)
6803 ctx1, ctx2 = scmutil.revpair(repo, revs)
6805
6804
6806 forcerelativevalue = None
6805 forcerelativevalue = None
6807 if ui.hasconfig(b'commands', b'status.relative'):
6806 if ui.hasconfig(b'commands', b'status.relative'):
6808 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6807 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6809 uipathfn = scmutil.getuipathfn(
6808 uipathfn = scmutil.getuipathfn(
6810 repo,
6809 repo,
6811 legacyrelativevalue=bool(pats),
6810 legacyrelativevalue=bool(pats),
6812 forcerelativevalue=forcerelativevalue,
6811 forcerelativevalue=forcerelativevalue,
6813 )
6812 )
6814
6813
6815 if opts.get(b'print0'):
6814 if opts.get(b'print0'):
6816 end = b'\0'
6815 end = b'\0'
6817 else:
6816 else:
6818 end = b'\n'
6817 end = b'\n'
6819 states = b'modified added removed deleted unknown ignored clean'.split()
6818 states = b'modified added removed deleted unknown ignored clean'.split()
6820 show = [k for k in states if opts.get(k)]
6819 show = [k for k in states if opts.get(k)]
6821 if opts.get(b'all'):
6820 if opts.get(b'all'):
6822 show += ui.quiet and (states[:4] + [b'clean']) or states
6821 show += ui.quiet and (states[:4] + [b'clean']) or states
6823
6822
6824 if not show:
6823 if not show:
6825 if ui.quiet:
6824 if ui.quiet:
6826 show = states[:4]
6825 show = states[:4]
6827 else:
6826 else:
6828 show = states[:5]
6827 show = states[:5]
6829
6828
6830 m = scmutil.match(ctx2, pats, opts)
6829 m = scmutil.match(ctx2, pats, opts)
6831 if terse:
6830 if terse:
6832 # we need to compute clean and unknown to terse
6831 # we need to compute clean and unknown to terse
6833 stat = repo.status(
6832 stat = repo.status(
6834 ctx1.node(),
6833 ctx1.node(),
6835 ctx2.node(),
6834 ctx2.node(),
6836 m,
6835 m,
6837 b'ignored' in show or b'i' in terse,
6836 b'ignored' in show or b'i' in terse,
6838 clean=True,
6837 clean=True,
6839 unknown=True,
6838 unknown=True,
6840 listsubrepos=opts.get(b'subrepos'),
6839 listsubrepos=opts.get(b'subrepos'),
6841 )
6840 )
6842
6841
6843 stat = cmdutil.tersedir(stat, terse)
6842 stat = cmdutil.tersedir(stat, terse)
6844 else:
6843 else:
6845 stat = repo.status(
6844 stat = repo.status(
6846 ctx1.node(),
6845 ctx1.node(),
6847 ctx2.node(),
6846 ctx2.node(),
6848 m,
6847 m,
6849 b'ignored' in show,
6848 b'ignored' in show,
6850 b'clean' in show,
6849 b'clean' in show,
6851 b'unknown' in show,
6850 b'unknown' in show,
6852 opts.get(b'subrepos'),
6851 opts.get(b'subrepos'),
6853 )
6852 )
6854
6853
6855 changestates = zip(
6854 changestates = zip(
6856 states,
6855 states,
6857 pycompat.iterbytestr(b'MAR!?IC'),
6856 pycompat.iterbytestr(b'MAR!?IC'),
6858 [getattr(stat, s.decode('utf8')) for s in states],
6857 [getattr(stat, s.decode('utf8')) for s in states],
6859 )
6858 )
6860
6859
6861 copy = {}
6860 copy = {}
6862 if (
6861 if (
6863 opts.get(b'all')
6862 opts.get(b'all')
6864 or opts.get(b'copies')
6863 or opts.get(b'copies')
6865 or ui.configbool(b'ui', b'statuscopies')
6864 or ui.configbool(b'ui', b'statuscopies')
6866 ) and not opts.get(b'no_status'):
6865 ) and not opts.get(b'no_status'):
6867 copy = copies.pathcopies(ctx1, ctx2, m)
6866 copy = copies.pathcopies(ctx1, ctx2, m)
6868
6867
6869 morestatus = None
6868 morestatus = None
6870 if (
6869 if (
6871 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6870 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6872 ) and not ui.plain():
6871 ) and not ui.plain():
6873 morestatus = cmdutil.readmorestatus(repo)
6872 morestatus = cmdutil.readmorestatus(repo)
6874
6873
6875 ui.pager(b'status')
6874 ui.pager(b'status')
6876 fm = ui.formatter(b'status', opts)
6875 fm = ui.formatter(b'status', opts)
6877 fmt = b'%s' + end
6876 fmt = b'%s' + end
6878 showchar = not opts.get(b'no_status')
6877 showchar = not opts.get(b'no_status')
6879
6878
6880 for state, char, files in changestates:
6879 for state, char, files in changestates:
6881 if state in show:
6880 if state in show:
6882 label = b'status.' + state
6881 label = b'status.' + state
6883 for f in files:
6882 for f in files:
6884 fm.startitem()
6883 fm.startitem()
6885 fm.context(ctx=ctx2)
6884 fm.context(ctx=ctx2)
6886 fm.data(itemtype=b'file', path=f)
6885 fm.data(itemtype=b'file', path=f)
6887 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6886 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6888 fm.plain(fmt % uipathfn(f), label=label)
6887 fm.plain(fmt % uipathfn(f), label=label)
6889 if f in copy:
6888 if f in copy:
6890 fm.data(source=copy[f])
6889 fm.data(source=copy[f])
6891 fm.plain(
6890 fm.plain(
6892 (b' %s' + end) % uipathfn(copy[f]),
6891 (b' %s' + end) % uipathfn(copy[f]),
6893 label=b'status.copied',
6892 label=b'status.copied',
6894 )
6893 )
6895 if morestatus:
6894 if morestatus:
6896 morestatus.formatfile(f, fm)
6895 morestatus.formatfile(f, fm)
6897
6896
6898 if morestatus:
6897 if morestatus:
6899 morestatus.formatfooter(fm)
6898 morestatus.formatfooter(fm)
6900 fm.end()
6899 fm.end()
6901
6900
6902
6901
6903 @command(
6902 @command(
6904 b'summary|sum',
6903 b'summary|sum',
6905 [(b'', b'remote', None, _(b'check for push and pull'))],
6904 [(b'', b'remote', None, _(b'check for push and pull'))],
6906 b'[--remote]',
6905 b'[--remote]',
6907 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6906 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6908 helpbasic=True,
6907 helpbasic=True,
6909 intents={INTENT_READONLY},
6908 intents={INTENT_READONLY},
6910 )
6909 )
6911 def summary(ui, repo, **opts):
6910 def summary(ui, repo, **opts):
6912 """summarize working directory state
6911 """summarize working directory state
6913
6912
6914 This generates a brief summary of the working directory state,
6913 This generates a brief summary of the working directory state,
6915 including parents, branch, commit status, phase and available updates.
6914 including parents, branch, commit status, phase and available updates.
6916
6915
6917 With the --remote option, this will check the default paths for
6916 With the --remote option, this will check the default paths for
6918 incoming and outgoing changes. This can be time-consuming.
6917 incoming and outgoing changes. This can be time-consuming.
6919
6918
6920 Returns 0 on success.
6919 Returns 0 on success.
6921 """
6920 """
6922
6921
6923 opts = pycompat.byteskwargs(opts)
6922 opts = pycompat.byteskwargs(opts)
6924 ui.pager(b'summary')
6923 ui.pager(b'summary')
6925 ctx = repo[None]
6924 ctx = repo[None]
6926 parents = ctx.parents()
6925 parents = ctx.parents()
6927 pnode = parents[0].node()
6926 pnode = parents[0].node()
6928 marks = []
6927 marks = []
6929
6928
6930 try:
6929 try:
6931 ms = mergemod.mergestate.read(repo)
6930 ms = mergemod.mergestate.read(repo)
6932 except error.UnsupportedMergeRecords as e:
6931 except error.UnsupportedMergeRecords as e:
6933 s = b' '.join(e.recordtypes)
6932 s = b' '.join(e.recordtypes)
6934 ui.warn(
6933 ui.warn(
6935 _(b'warning: merge state has unsupported record types: %s\n') % s
6934 _(b'warning: merge state has unsupported record types: %s\n') % s
6936 )
6935 )
6937 unresolved = []
6936 unresolved = []
6938 else:
6937 else:
6939 unresolved = list(ms.unresolved())
6938 unresolved = list(ms.unresolved())
6940
6939
6941 for p in parents:
6940 for p in parents:
6942 # label with log.changeset (instead of log.parent) since this
6941 # label with log.changeset (instead of log.parent) since this
6943 # shows a working directory parent *changeset*:
6942 # shows a working directory parent *changeset*:
6944 # i18n: column positioning for "hg summary"
6943 # i18n: column positioning for "hg summary"
6945 ui.write(
6944 ui.write(
6946 _(b'parent: %d:%s ') % (p.rev(), p),
6945 _(b'parent: %d:%s ') % (p.rev(), p),
6947 label=logcmdutil.changesetlabels(p),
6946 label=logcmdutil.changesetlabels(p),
6948 )
6947 )
6949 ui.write(b' '.join(p.tags()), label=b'log.tag')
6948 ui.write(b' '.join(p.tags()), label=b'log.tag')
6950 if p.bookmarks():
6949 if p.bookmarks():
6951 marks.extend(p.bookmarks())
6950 marks.extend(p.bookmarks())
6952 if p.rev() == -1:
6951 if p.rev() == -1:
6953 if not len(repo):
6952 if not len(repo):
6954 ui.write(_(b' (empty repository)'))
6953 ui.write(_(b' (empty repository)'))
6955 else:
6954 else:
6956 ui.write(_(b' (no revision checked out)'))
6955 ui.write(_(b' (no revision checked out)'))
6957 if p.obsolete():
6956 if p.obsolete():
6958 ui.write(_(b' (obsolete)'))
6957 ui.write(_(b' (obsolete)'))
6959 if p.isunstable():
6958 if p.isunstable():
6960 instabilities = (
6959 instabilities = (
6961 ui.label(instability, b'trouble.%s' % instability)
6960 ui.label(instability, b'trouble.%s' % instability)
6962 for instability in p.instabilities()
6961 for instability in p.instabilities()
6963 )
6962 )
6964 ui.write(b' (' + b', '.join(instabilities) + b')')
6963 ui.write(b' (' + b', '.join(instabilities) + b')')
6965 ui.write(b'\n')
6964 ui.write(b'\n')
6966 if p.description():
6965 if p.description():
6967 ui.status(
6966 ui.status(
6968 b' ' + p.description().splitlines()[0].strip() + b'\n',
6967 b' ' + p.description().splitlines()[0].strip() + b'\n',
6969 label=b'log.summary',
6968 label=b'log.summary',
6970 )
6969 )
6971
6970
6972 branch = ctx.branch()
6971 branch = ctx.branch()
6973 bheads = repo.branchheads(branch)
6972 bheads = repo.branchheads(branch)
6974 # i18n: column positioning for "hg summary"
6973 # i18n: column positioning for "hg summary"
6975 m = _(b'branch: %s\n') % branch
6974 m = _(b'branch: %s\n') % branch
6976 if branch != b'default':
6975 if branch != b'default':
6977 ui.write(m, label=b'log.branch')
6976 ui.write(m, label=b'log.branch')
6978 else:
6977 else:
6979 ui.status(m, label=b'log.branch')
6978 ui.status(m, label=b'log.branch')
6980
6979
6981 if marks:
6980 if marks:
6982 active = repo._activebookmark
6981 active = repo._activebookmark
6983 # i18n: column positioning for "hg summary"
6982 # i18n: column positioning for "hg summary"
6984 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6983 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6985 if active is not None:
6984 if active is not None:
6986 if active in marks:
6985 if active in marks:
6987 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6986 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6988 marks.remove(active)
6987 marks.remove(active)
6989 else:
6988 else:
6990 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6989 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6991 for m in marks:
6990 for m in marks:
6992 ui.write(b' ' + m, label=b'log.bookmark')
6991 ui.write(b' ' + m, label=b'log.bookmark')
6993 ui.write(b'\n', label=b'log.bookmark')
6992 ui.write(b'\n', label=b'log.bookmark')
6994
6993
6995 status = repo.status(unknown=True)
6994 status = repo.status(unknown=True)
6996
6995
6997 c = repo.dirstate.copies()
6996 c = repo.dirstate.copies()
6998 copied, renamed = [], []
6997 copied, renamed = [], []
6999 for d, s in pycompat.iteritems(c):
6998 for d, s in pycompat.iteritems(c):
7000 if s in status.removed:
6999 if s in status.removed:
7001 status.removed.remove(s)
7000 status.removed.remove(s)
7002 renamed.append(d)
7001 renamed.append(d)
7003 else:
7002 else:
7004 copied.append(d)
7003 copied.append(d)
7005 if d in status.added:
7004 if d in status.added:
7006 status.added.remove(d)
7005 status.added.remove(d)
7007
7006
7008 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7007 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7009
7008
7010 labels = [
7009 labels = [
7011 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7010 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7012 (ui.label(_(b'%d added'), b'status.added'), status.added),
7011 (ui.label(_(b'%d added'), b'status.added'), status.added),
7013 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7012 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7014 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7013 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7015 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7014 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7016 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7015 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7017 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7016 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7018 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7017 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7019 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7018 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7020 ]
7019 ]
7021 t = []
7020 t = []
7022 for l, s in labels:
7021 for l, s in labels:
7023 if s:
7022 if s:
7024 t.append(l % len(s))
7023 t.append(l % len(s))
7025
7024
7026 t = b', '.join(t)
7025 t = b', '.join(t)
7027 cleanworkdir = False
7026 cleanworkdir = False
7028
7027
7029 if repo.vfs.exists(b'graftstate'):
7028 if repo.vfs.exists(b'graftstate'):
7030 t += _(b' (graft in progress)')
7029 t += _(b' (graft in progress)')
7031 if repo.vfs.exists(b'updatestate'):
7030 if repo.vfs.exists(b'updatestate'):
7032 t += _(b' (interrupted update)')
7031 t += _(b' (interrupted update)')
7033 elif len(parents) > 1:
7032 elif len(parents) > 1:
7034 t += _(b' (merge)')
7033 t += _(b' (merge)')
7035 elif branch != parents[0].branch():
7034 elif branch != parents[0].branch():
7036 t += _(b' (new branch)')
7035 t += _(b' (new branch)')
7037 elif parents[0].closesbranch() and pnode in repo.branchheads(
7036 elif parents[0].closesbranch() and pnode in repo.branchheads(
7038 branch, closed=True
7037 branch, closed=True
7039 ):
7038 ):
7040 t += _(b' (head closed)')
7039 t += _(b' (head closed)')
7041 elif not (
7040 elif not (
7042 status.modified
7041 status.modified
7043 or status.added
7042 or status.added
7044 or status.removed
7043 or status.removed
7045 or renamed
7044 or renamed
7046 or copied
7045 or copied
7047 or subs
7046 or subs
7048 ):
7047 ):
7049 t += _(b' (clean)')
7048 t += _(b' (clean)')
7050 cleanworkdir = True
7049 cleanworkdir = True
7051 elif pnode not in bheads:
7050 elif pnode not in bheads:
7052 t += _(b' (new branch head)')
7051 t += _(b' (new branch head)')
7053
7052
7054 if parents:
7053 if parents:
7055 pendingphase = max(p.phase() for p in parents)
7054 pendingphase = max(p.phase() for p in parents)
7056 else:
7055 else:
7057 pendingphase = phases.public
7056 pendingphase = phases.public
7058
7057
7059 if pendingphase > phases.newcommitphase(ui):
7058 if pendingphase > phases.newcommitphase(ui):
7060 t += b' (%s)' % phases.phasenames[pendingphase]
7059 t += b' (%s)' % phases.phasenames[pendingphase]
7061
7060
7062 if cleanworkdir:
7061 if cleanworkdir:
7063 # i18n: column positioning for "hg summary"
7062 # i18n: column positioning for "hg summary"
7064 ui.status(_(b'commit: %s\n') % t.strip())
7063 ui.status(_(b'commit: %s\n') % t.strip())
7065 else:
7064 else:
7066 # i18n: column positioning for "hg summary"
7065 # i18n: column positioning for "hg summary"
7067 ui.write(_(b'commit: %s\n') % t.strip())
7066 ui.write(_(b'commit: %s\n') % t.strip())
7068
7067
7069 # all ancestors of branch heads - all ancestors of parent = new csets
7068 # all ancestors of branch heads - all ancestors of parent = new csets
7070 new = len(
7069 new = len(
7071 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7070 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7072 )
7071 )
7073
7072
7074 if new == 0:
7073 if new == 0:
7075 # i18n: column positioning for "hg summary"
7074 # i18n: column positioning for "hg summary"
7076 ui.status(_(b'update: (current)\n'))
7075 ui.status(_(b'update: (current)\n'))
7077 elif pnode not in bheads:
7076 elif pnode not in bheads:
7078 # i18n: column positioning for "hg summary"
7077 # i18n: column positioning for "hg summary"
7079 ui.write(_(b'update: %d new changesets (update)\n') % new)
7078 ui.write(_(b'update: %d new changesets (update)\n') % new)
7080 else:
7079 else:
7081 # i18n: column positioning for "hg summary"
7080 # i18n: column positioning for "hg summary"
7082 ui.write(
7081 ui.write(
7083 _(b'update: %d new changesets, %d branch heads (merge)\n')
7082 _(b'update: %d new changesets, %d branch heads (merge)\n')
7084 % (new, len(bheads))
7083 % (new, len(bheads))
7085 )
7084 )
7086
7085
7087 t = []
7086 t = []
7088 draft = len(repo.revs(b'draft()'))
7087 draft = len(repo.revs(b'draft()'))
7089 if draft:
7088 if draft:
7090 t.append(_(b'%d draft') % draft)
7089 t.append(_(b'%d draft') % draft)
7091 secret = len(repo.revs(b'secret()'))
7090 secret = len(repo.revs(b'secret()'))
7092 if secret:
7091 if secret:
7093 t.append(_(b'%d secret') % secret)
7092 t.append(_(b'%d secret') % secret)
7094
7093
7095 if draft or secret:
7094 if draft or secret:
7096 ui.status(_(b'phases: %s\n') % b', '.join(t))
7095 ui.status(_(b'phases: %s\n') % b', '.join(t))
7097
7096
7098 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7097 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7099 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7098 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7100 numtrouble = len(repo.revs(trouble + b"()"))
7099 numtrouble = len(repo.revs(trouble + b"()"))
7101 # We write all the possibilities to ease translation
7100 # We write all the possibilities to ease translation
7102 troublemsg = {
7101 troublemsg = {
7103 b"orphan": _(b"orphan: %d changesets"),
7102 b"orphan": _(b"orphan: %d changesets"),
7104 b"contentdivergent": _(b"content-divergent: %d changesets"),
7103 b"contentdivergent": _(b"content-divergent: %d changesets"),
7105 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7104 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7106 }
7105 }
7107 if numtrouble > 0:
7106 if numtrouble > 0:
7108 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7107 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7109
7108
7110 cmdutil.summaryhooks(ui, repo)
7109 cmdutil.summaryhooks(ui, repo)
7111
7110
7112 if opts.get(b'remote'):
7111 if opts.get(b'remote'):
7113 needsincoming, needsoutgoing = True, True
7112 needsincoming, needsoutgoing = True, True
7114 else:
7113 else:
7115 needsincoming, needsoutgoing = False, False
7114 needsincoming, needsoutgoing = False, False
7116 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7115 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7117 if i:
7116 if i:
7118 needsincoming = True
7117 needsincoming = True
7119 if o:
7118 if o:
7120 needsoutgoing = True
7119 needsoutgoing = True
7121 if not needsincoming and not needsoutgoing:
7120 if not needsincoming and not needsoutgoing:
7122 return
7121 return
7123
7122
7124 def getincoming():
7123 def getincoming():
7125 source, branches = hg.parseurl(ui.expandpath(b'default'))
7124 source, branches = hg.parseurl(ui.expandpath(b'default'))
7126 sbranch = branches[0]
7125 sbranch = branches[0]
7127 try:
7126 try:
7128 other = hg.peer(repo, {}, source)
7127 other = hg.peer(repo, {}, source)
7129 except error.RepoError:
7128 except error.RepoError:
7130 if opts.get(b'remote'):
7129 if opts.get(b'remote'):
7131 raise
7130 raise
7132 return source, sbranch, None, None, None
7131 return source, sbranch, None, None, None
7133 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7132 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7134 if revs:
7133 if revs:
7135 revs = [other.lookup(rev) for rev in revs]
7134 revs = [other.lookup(rev) for rev in revs]
7136 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7135 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7137 repo.ui.pushbuffer()
7136 repo.ui.pushbuffer()
7138 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7137 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7139 repo.ui.popbuffer()
7138 repo.ui.popbuffer()
7140 return source, sbranch, other, commoninc, commoninc[1]
7139 return source, sbranch, other, commoninc, commoninc[1]
7141
7140
7142 if needsincoming:
7141 if needsincoming:
7143 source, sbranch, sother, commoninc, incoming = getincoming()
7142 source, sbranch, sother, commoninc, incoming = getincoming()
7144 else:
7143 else:
7145 source = sbranch = sother = commoninc = incoming = None
7144 source = sbranch = sother = commoninc = incoming = None
7146
7145
7147 def getoutgoing():
7146 def getoutgoing():
7148 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7147 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7149 dbranch = branches[0]
7148 dbranch = branches[0]
7150 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7149 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7151 if source != dest:
7150 if source != dest:
7152 try:
7151 try:
7153 dother = hg.peer(repo, {}, dest)
7152 dother = hg.peer(repo, {}, dest)
7154 except error.RepoError:
7153 except error.RepoError:
7155 if opts.get(b'remote'):
7154 if opts.get(b'remote'):
7156 raise
7155 raise
7157 return dest, dbranch, None, None
7156 return dest, dbranch, None, None
7158 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7157 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7159 elif sother is None:
7158 elif sother is None:
7160 # there is no explicit destination peer, but source one is invalid
7159 # there is no explicit destination peer, but source one is invalid
7161 return dest, dbranch, None, None
7160 return dest, dbranch, None, None
7162 else:
7161 else:
7163 dother = sother
7162 dother = sother
7164 if source != dest or (sbranch is not None and sbranch != dbranch):
7163 if source != dest or (sbranch is not None and sbranch != dbranch):
7165 common = None
7164 common = None
7166 else:
7165 else:
7167 common = commoninc
7166 common = commoninc
7168 if revs:
7167 if revs:
7169 revs = [repo.lookup(rev) for rev in revs]
7168 revs = [repo.lookup(rev) for rev in revs]
7170 repo.ui.pushbuffer()
7169 repo.ui.pushbuffer()
7171 outgoing = discovery.findcommonoutgoing(
7170 outgoing = discovery.findcommonoutgoing(
7172 repo, dother, onlyheads=revs, commoninc=common
7171 repo, dother, onlyheads=revs, commoninc=common
7173 )
7172 )
7174 repo.ui.popbuffer()
7173 repo.ui.popbuffer()
7175 return dest, dbranch, dother, outgoing
7174 return dest, dbranch, dother, outgoing
7176
7175
7177 if needsoutgoing:
7176 if needsoutgoing:
7178 dest, dbranch, dother, outgoing = getoutgoing()
7177 dest, dbranch, dother, outgoing = getoutgoing()
7179 else:
7178 else:
7180 dest = dbranch = dother = outgoing = None
7179 dest = dbranch = dother = outgoing = None
7181
7180
7182 if opts.get(b'remote'):
7181 if opts.get(b'remote'):
7183 t = []
7182 t = []
7184 if incoming:
7183 if incoming:
7185 t.append(_(b'1 or more incoming'))
7184 t.append(_(b'1 or more incoming'))
7186 o = outgoing.missing
7185 o = outgoing.missing
7187 if o:
7186 if o:
7188 t.append(_(b'%d outgoing') % len(o))
7187 t.append(_(b'%d outgoing') % len(o))
7189 other = dother or sother
7188 other = dother or sother
7190 if b'bookmarks' in other.listkeys(b'namespaces'):
7189 if b'bookmarks' in other.listkeys(b'namespaces'):
7191 counts = bookmarks.summary(repo, other)
7190 counts = bookmarks.summary(repo, other)
7192 if counts[0] > 0:
7191 if counts[0] > 0:
7193 t.append(_(b'%d incoming bookmarks') % counts[0])
7192 t.append(_(b'%d incoming bookmarks') % counts[0])
7194 if counts[1] > 0:
7193 if counts[1] > 0:
7195 t.append(_(b'%d outgoing bookmarks') % counts[1])
7194 t.append(_(b'%d outgoing bookmarks') % counts[1])
7196
7195
7197 if t:
7196 if t:
7198 # i18n: column positioning for "hg summary"
7197 # i18n: column positioning for "hg summary"
7199 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7198 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7200 else:
7199 else:
7201 # i18n: column positioning for "hg summary"
7200 # i18n: column positioning for "hg summary"
7202 ui.status(_(b'remote: (synced)\n'))
7201 ui.status(_(b'remote: (synced)\n'))
7203
7202
7204 cmdutil.summaryremotehooks(
7203 cmdutil.summaryremotehooks(
7205 ui,
7204 ui,
7206 repo,
7205 repo,
7207 opts,
7206 opts,
7208 (
7207 (
7209 (source, sbranch, sother, commoninc),
7208 (source, sbranch, sother, commoninc),
7210 (dest, dbranch, dother, outgoing),
7209 (dest, dbranch, dother, outgoing),
7211 ),
7210 ),
7212 )
7211 )
7213
7212
7214
7213
7215 @command(
7214 @command(
7216 b'tag',
7215 b'tag',
7217 [
7216 [
7218 (b'f', b'force', None, _(b'force tag')),
7217 (b'f', b'force', None, _(b'force tag')),
7219 (b'l', b'local', None, _(b'make the tag local')),
7218 (b'l', b'local', None, _(b'make the tag local')),
7220 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7219 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7221 (b'', b'remove', None, _(b'remove a tag')),
7220 (b'', b'remove', None, _(b'remove a tag')),
7222 # -l/--local is already there, commitopts cannot be used
7221 # -l/--local is already there, commitopts cannot be used
7223 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7222 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7224 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7223 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7225 ]
7224 ]
7226 + commitopts2,
7225 + commitopts2,
7227 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7226 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7228 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7227 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7229 )
7228 )
7230 def tag(ui, repo, name1, *names, **opts):
7229 def tag(ui, repo, name1, *names, **opts):
7231 """add one or more tags for the current or given revision
7230 """add one or more tags for the current or given revision
7232
7231
7233 Name a particular revision using <name>.
7232 Name a particular revision using <name>.
7234
7233
7235 Tags are used to name particular revisions of the repository and are
7234 Tags are used to name particular revisions of the repository and are
7236 very useful to compare different revisions, to go back to significant
7235 very useful to compare different revisions, to go back to significant
7237 earlier versions or to mark branch points as releases, etc. Changing
7236 earlier versions or to mark branch points as releases, etc. Changing
7238 an existing tag is normally disallowed; use -f/--force to override.
7237 an existing tag is normally disallowed; use -f/--force to override.
7239
7238
7240 If no revision is given, the parent of the working directory is
7239 If no revision is given, the parent of the working directory is
7241 used.
7240 used.
7242
7241
7243 To facilitate version control, distribution, and merging of tags,
7242 To facilitate version control, distribution, and merging of tags,
7244 they are stored as a file named ".hgtags" which is managed similarly
7243 they are stored as a file named ".hgtags" which is managed similarly
7245 to other project files and can be hand-edited if necessary. This
7244 to other project files and can be hand-edited if necessary. This
7246 also means that tagging creates a new commit. The file
7245 also means that tagging creates a new commit. The file
7247 ".hg/localtags" is used for local tags (not shared among
7246 ".hg/localtags" is used for local tags (not shared among
7248 repositories).
7247 repositories).
7249
7248
7250 Tag commits are usually made at the head of a branch. If the parent
7249 Tag commits are usually made at the head of a branch. If the parent
7251 of the working directory is not a branch head, :hg:`tag` aborts; use
7250 of the working directory is not a branch head, :hg:`tag` aborts; use
7252 -f/--force to force the tag commit to be based on a non-head
7251 -f/--force to force the tag commit to be based on a non-head
7253 changeset.
7252 changeset.
7254
7253
7255 See :hg:`help dates` for a list of formats valid for -d/--date.
7254 See :hg:`help dates` for a list of formats valid for -d/--date.
7256
7255
7257 Since tag names have priority over branch names during revision
7256 Since tag names have priority over branch names during revision
7258 lookup, using an existing branch name as a tag name is discouraged.
7257 lookup, using an existing branch name as a tag name is discouraged.
7259
7258
7260 Returns 0 on success.
7259 Returns 0 on success.
7261 """
7260 """
7262 opts = pycompat.byteskwargs(opts)
7261 opts = pycompat.byteskwargs(opts)
7263 with repo.wlock(), repo.lock():
7262 with repo.wlock(), repo.lock():
7264 rev_ = b"."
7263 rev_ = b"."
7265 names = [t.strip() for t in (name1,) + names]
7264 names = [t.strip() for t in (name1,) + names]
7266 if len(names) != len(set(names)):
7265 if len(names) != len(set(names)):
7267 raise error.Abort(_(b'tag names must be unique'))
7266 raise error.Abort(_(b'tag names must be unique'))
7268 for n in names:
7267 for n in names:
7269 scmutil.checknewlabel(repo, n, b'tag')
7268 scmutil.checknewlabel(repo, n, b'tag')
7270 if not n:
7269 if not n:
7271 raise error.Abort(
7270 raise error.Abort(
7272 _(b'tag names cannot consist entirely of whitespace')
7271 _(b'tag names cannot consist entirely of whitespace')
7273 )
7272 )
7274 if opts.get(b'rev') and opts.get(b'remove'):
7273 if opts.get(b'rev') and opts.get(b'remove'):
7275 raise error.Abort(_(b"--rev and --remove are incompatible"))
7274 raise error.Abort(_(b"--rev and --remove are incompatible"))
7276 if opts.get(b'rev'):
7275 if opts.get(b'rev'):
7277 rev_ = opts[b'rev']
7276 rev_ = opts[b'rev']
7278 message = opts.get(b'message')
7277 message = opts.get(b'message')
7279 if opts.get(b'remove'):
7278 if opts.get(b'remove'):
7280 if opts.get(b'local'):
7279 if opts.get(b'local'):
7281 expectedtype = b'local'
7280 expectedtype = b'local'
7282 else:
7281 else:
7283 expectedtype = b'global'
7282 expectedtype = b'global'
7284
7283
7285 for n in names:
7284 for n in names:
7286 if repo.tagtype(n) == b'global':
7285 if repo.tagtype(n) == b'global':
7287 alltags = tagsmod.findglobaltags(ui, repo)
7286 alltags = tagsmod.findglobaltags(ui, repo)
7288 if alltags[n][0] == nullid:
7287 if alltags[n][0] == nullid:
7289 raise error.Abort(_(b"tag '%s' is already removed") % n)
7288 raise error.Abort(_(b"tag '%s' is already removed") % n)
7290 if not repo.tagtype(n):
7289 if not repo.tagtype(n):
7291 raise error.Abort(_(b"tag '%s' does not exist") % n)
7290 raise error.Abort(_(b"tag '%s' does not exist") % n)
7292 if repo.tagtype(n) != expectedtype:
7291 if repo.tagtype(n) != expectedtype:
7293 if expectedtype == b'global':
7292 if expectedtype == b'global':
7294 raise error.Abort(
7293 raise error.Abort(
7295 _(b"tag '%s' is not a global tag") % n
7294 _(b"tag '%s' is not a global tag") % n
7296 )
7295 )
7297 else:
7296 else:
7298 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7297 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7299 rev_ = b'null'
7298 rev_ = b'null'
7300 if not message:
7299 if not message:
7301 # we don't translate commit messages
7300 # we don't translate commit messages
7302 message = b'Removed tag %s' % b', '.join(names)
7301 message = b'Removed tag %s' % b', '.join(names)
7303 elif not opts.get(b'force'):
7302 elif not opts.get(b'force'):
7304 for n in names:
7303 for n in names:
7305 if n in repo.tags():
7304 if n in repo.tags():
7306 raise error.Abort(
7305 raise error.Abort(
7307 _(b"tag '%s' already exists (use -f to force)") % n
7306 _(b"tag '%s' already exists (use -f to force)") % n
7308 )
7307 )
7309 if not opts.get(b'local'):
7308 if not opts.get(b'local'):
7310 p1, p2 = repo.dirstate.parents()
7309 p1, p2 = repo.dirstate.parents()
7311 if p2 != nullid:
7310 if p2 != nullid:
7312 raise error.Abort(_(b'uncommitted merge'))
7311 raise error.Abort(_(b'uncommitted merge'))
7313 bheads = repo.branchheads()
7312 bheads = repo.branchheads()
7314 if not opts.get(b'force') and bheads and p1 not in bheads:
7313 if not opts.get(b'force') and bheads and p1 not in bheads:
7315 raise error.Abort(
7314 raise error.Abort(
7316 _(
7315 _(
7317 b'working directory is not at a branch head '
7316 b'working directory is not at a branch head '
7318 b'(use -f to force)'
7317 b'(use -f to force)'
7319 )
7318 )
7320 )
7319 )
7321 node = scmutil.revsingle(repo, rev_).node()
7320 node = scmutil.revsingle(repo, rev_).node()
7322
7321
7323 if not message:
7322 if not message:
7324 # we don't translate commit messages
7323 # we don't translate commit messages
7325 message = b'Added tag %s for changeset %s' % (
7324 message = b'Added tag %s for changeset %s' % (
7326 b', '.join(names),
7325 b', '.join(names),
7327 short(node),
7326 short(node),
7328 )
7327 )
7329
7328
7330 date = opts.get(b'date')
7329 date = opts.get(b'date')
7331 if date:
7330 if date:
7332 date = dateutil.parsedate(date)
7331 date = dateutil.parsedate(date)
7333
7332
7334 if opts.get(b'remove'):
7333 if opts.get(b'remove'):
7335 editform = b'tag.remove'
7334 editform = b'tag.remove'
7336 else:
7335 else:
7337 editform = b'tag.add'
7336 editform = b'tag.add'
7338 editor = cmdutil.getcommiteditor(
7337 editor = cmdutil.getcommiteditor(
7339 editform=editform, **pycompat.strkwargs(opts)
7338 editform=editform, **pycompat.strkwargs(opts)
7340 )
7339 )
7341
7340
7342 # don't allow tagging the null rev
7341 # don't allow tagging the null rev
7343 if (
7342 if (
7344 not opts.get(b'remove')
7343 not opts.get(b'remove')
7345 and scmutil.revsingle(repo, rev_).rev() == nullrev
7344 and scmutil.revsingle(repo, rev_).rev() == nullrev
7346 ):
7345 ):
7347 raise error.Abort(_(b"cannot tag null revision"))
7346 raise error.Abort(_(b"cannot tag null revision"))
7348
7347
7349 tagsmod.tag(
7348 tagsmod.tag(
7350 repo,
7349 repo,
7351 names,
7350 names,
7352 node,
7351 node,
7353 message,
7352 message,
7354 opts.get(b'local'),
7353 opts.get(b'local'),
7355 opts.get(b'user'),
7354 opts.get(b'user'),
7356 date,
7355 date,
7357 editor=editor,
7356 editor=editor,
7358 )
7357 )
7359
7358
7360
7359
7361 @command(
7360 @command(
7362 b'tags',
7361 b'tags',
7363 formatteropts,
7362 formatteropts,
7364 b'',
7363 b'',
7365 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7364 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7366 intents={INTENT_READONLY},
7365 intents={INTENT_READONLY},
7367 )
7366 )
7368 def tags(ui, repo, **opts):
7367 def tags(ui, repo, **opts):
7369 """list repository tags
7368 """list repository tags
7370
7369
7371 This lists both regular and local tags. When the -v/--verbose
7370 This lists both regular and local tags. When the -v/--verbose
7372 switch is used, a third column "local" is printed for local tags.
7371 switch is used, a third column "local" is printed for local tags.
7373 When the -q/--quiet switch is used, only the tag name is printed.
7372 When the -q/--quiet switch is used, only the tag name is printed.
7374
7373
7375 .. container:: verbose
7374 .. container:: verbose
7376
7375
7377 Template:
7376 Template:
7378
7377
7379 The following keywords are supported in addition to the common template
7378 The following keywords are supported in addition to the common template
7380 keywords and functions such as ``{tag}``. See also
7379 keywords and functions such as ``{tag}``. See also
7381 :hg:`help templates`.
7380 :hg:`help templates`.
7382
7381
7383 :type: String. ``local`` for local tags.
7382 :type: String. ``local`` for local tags.
7384
7383
7385 Returns 0 on success.
7384 Returns 0 on success.
7386 """
7385 """
7387
7386
7388 opts = pycompat.byteskwargs(opts)
7387 opts = pycompat.byteskwargs(opts)
7389 ui.pager(b'tags')
7388 ui.pager(b'tags')
7390 fm = ui.formatter(b'tags', opts)
7389 fm = ui.formatter(b'tags', opts)
7391 hexfunc = fm.hexfunc
7390 hexfunc = fm.hexfunc
7392
7391
7393 for t, n in reversed(repo.tagslist()):
7392 for t, n in reversed(repo.tagslist()):
7394 hn = hexfunc(n)
7393 hn = hexfunc(n)
7395 label = b'tags.normal'
7394 label = b'tags.normal'
7396 tagtype = b''
7395 tagtype = b''
7397 if repo.tagtype(t) == b'local':
7396 if repo.tagtype(t) == b'local':
7398 label = b'tags.local'
7397 label = b'tags.local'
7399 tagtype = b'local'
7398 tagtype = b'local'
7400
7399
7401 fm.startitem()
7400 fm.startitem()
7402 fm.context(repo=repo)
7401 fm.context(repo=repo)
7403 fm.write(b'tag', b'%s', t, label=label)
7402 fm.write(b'tag', b'%s', t, label=label)
7404 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7403 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7405 fm.condwrite(
7404 fm.condwrite(
7406 not ui.quiet,
7405 not ui.quiet,
7407 b'rev node',
7406 b'rev node',
7408 fmt,
7407 fmt,
7409 repo.changelog.rev(n),
7408 repo.changelog.rev(n),
7410 hn,
7409 hn,
7411 label=label,
7410 label=label,
7412 )
7411 )
7413 fm.condwrite(
7412 fm.condwrite(
7414 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7413 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7415 )
7414 )
7416 fm.plain(b'\n')
7415 fm.plain(b'\n')
7417 fm.end()
7416 fm.end()
7418
7417
7419
7418
7420 @command(
7419 @command(
7421 b'tip',
7420 b'tip',
7422 [
7421 [
7423 (b'p', b'patch', None, _(b'show patch')),
7422 (b'p', b'patch', None, _(b'show patch')),
7424 (b'g', b'git', None, _(b'use git extended diff format')),
7423 (b'g', b'git', None, _(b'use git extended diff format')),
7425 ]
7424 ]
7426 + templateopts,
7425 + templateopts,
7427 _(b'[-p] [-g]'),
7426 _(b'[-p] [-g]'),
7428 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7427 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7429 )
7428 )
7430 def tip(ui, repo, **opts):
7429 def tip(ui, repo, **opts):
7431 """show the tip revision (DEPRECATED)
7430 """show the tip revision (DEPRECATED)
7432
7431
7433 The tip revision (usually just called the tip) is the changeset
7432 The tip revision (usually just called the tip) is the changeset
7434 most recently added to the repository (and therefore the most
7433 most recently added to the repository (and therefore the most
7435 recently changed head).
7434 recently changed head).
7436
7435
7437 If you have just made a commit, that commit will be the tip. If
7436 If you have just made a commit, that commit will be the tip. If
7438 you have just pulled changes from another repository, the tip of
7437 you have just pulled changes from another repository, the tip of
7439 that repository becomes the current tip. The "tip" tag is special
7438 that repository becomes the current tip. The "tip" tag is special
7440 and cannot be renamed or assigned to a different changeset.
7439 and cannot be renamed or assigned to a different changeset.
7441
7440
7442 This command is deprecated, please use :hg:`heads` instead.
7441 This command is deprecated, please use :hg:`heads` instead.
7443
7442
7444 Returns 0 on success.
7443 Returns 0 on success.
7445 """
7444 """
7446 opts = pycompat.byteskwargs(opts)
7445 opts = pycompat.byteskwargs(opts)
7447 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7446 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7448 displayer.show(repo[b'tip'])
7447 displayer.show(repo[b'tip'])
7449 displayer.close()
7448 displayer.close()
7450
7449
7451
7450
7452 @command(
7451 @command(
7453 b'unbundle',
7452 b'unbundle',
7454 [
7453 [
7455 (
7454 (
7456 b'u',
7455 b'u',
7457 b'update',
7456 b'update',
7458 None,
7457 None,
7459 _(b'update to new branch head if changesets were unbundled'),
7458 _(b'update to new branch head if changesets were unbundled'),
7460 )
7459 )
7461 ],
7460 ],
7462 _(b'[-u] FILE...'),
7461 _(b'[-u] FILE...'),
7463 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7462 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7464 )
7463 )
7465 def unbundle(ui, repo, fname1, *fnames, **opts):
7464 def unbundle(ui, repo, fname1, *fnames, **opts):
7466 """apply one or more bundle files
7465 """apply one or more bundle files
7467
7466
7468 Apply one or more bundle files generated by :hg:`bundle`.
7467 Apply one or more bundle files generated by :hg:`bundle`.
7469
7468
7470 Returns 0 on success, 1 if an update has unresolved files.
7469 Returns 0 on success, 1 if an update has unresolved files.
7471 """
7470 """
7472 fnames = (fname1,) + fnames
7471 fnames = (fname1,) + fnames
7473
7472
7474 with repo.lock():
7473 with repo.lock():
7475 for fname in fnames:
7474 for fname in fnames:
7476 f = hg.openpath(ui, fname)
7475 f = hg.openpath(ui, fname)
7477 gen = exchange.readbundle(ui, f, fname)
7476 gen = exchange.readbundle(ui, f, fname)
7478 if isinstance(gen, streamclone.streamcloneapplier):
7477 if isinstance(gen, streamclone.streamcloneapplier):
7479 raise error.Abort(
7478 raise error.Abort(
7480 _(
7479 _(
7481 b'packed bundles cannot be applied with '
7480 b'packed bundles cannot be applied with '
7482 b'"hg unbundle"'
7481 b'"hg unbundle"'
7483 ),
7482 ),
7484 hint=_(b'use "hg debugapplystreamclonebundle"'),
7483 hint=_(b'use "hg debugapplystreamclonebundle"'),
7485 )
7484 )
7486 url = b'bundle:' + fname
7485 url = b'bundle:' + fname
7487 try:
7486 try:
7488 txnname = b'unbundle'
7487 txnname = b'unbundle'
7489 if not isinstance(gen, bundle2.unbundle20):
7488 if not isinstance(gen, bundle2.unbundle20):
7490 txnname = b'unbundle\n%s' % util.hidepassword(url)
7489 txnname = b'unbundle\n%s' % util.hidepassword(url)
7491 with repo.transaction(txnname) as tr:
7490 with repo.transaction(txnname) as tr:
7492 op = bundle2.applybundle(
7491 op = bundle2.applybundle(
7493 repo, gen, tr, source=b'unbundle', url=url
7492 repo, gen, tr, source=b'unbundle', url=url
7494 )
7493 )
7495 except error.BundleUnknownFeatureError as exc:
7494 except error.BundleUnknownFeatureError as exc:
7496 raise error.Abort(
7495 raise error.Abort(
7497 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7496 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7498 hint=_(
7497 hint=_(
7499 b"see https://mercurial-scm.org/"
7498 b"see https://mercurial-scm.org/"
7500 b"wiki/BundleFeature for more "
7499 b"wiki/BundleFeature for more "
7501 b"information"
7500 b"information"
7502 ),
7501 ),
7503 )
7502 )
7504 modheads = bundle2.combinechangegroupresults(op)
7503 modheads = bundle2.combinechangegroupresults(op)
7505
7504
7506 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7505 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7507
7506
7508
7507
7509 @command(
7508 @command(
7510 b'unshelve',
7509 b'unshelve',
7511 [
7510 [
7512 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7511 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7513 (
7512 (
7514 b'c',
7513 b'c',
7515 b'continue',
7514 b'continue',
7516 None,
7515 None,
7517 _(b'continue an incomplete unshelve operation'),
7516 _(b'continue an incomplete unshelve operation'),
7518 ),
7517 ),
7519 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7518 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7520 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7519 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7521 (
7520 (
7522 b'n',
7521 b'n',
7523 b'name',
7522 b'name',
7524 b'',
7523 b'',
7525 _(b'restore shelved change with given name'),
7524 _(b'restore shelved change with given name'),
7526 _(b'NAME'),
7525 _(b'NAME'),
7527 ),
7526 ),
7528 (b't', b'tool', b'', _(b'specify merge tool')),
7527 (b't', b'tool', b'', _(b'specify merge tool')),
7529 (
7528 (
7530 b'',
7529 b'',
7531 b'date',
7530 b'date',
7532 b'',
7531 b'',
7533 _(b'set date for temporary commits (DEPRECATED)'),
7532 _(b'set date for temporary commits (DEPRECATED)'),
7534 _(b'DATE'),
7533 _(b'DATE'),
7535 ),
7534 ),
7536 ],
7535 ],
7537 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7536 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7538 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7537 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7539 )
7538 )
7540 def unshelve(ui, repo, *shelved, **opts):
7539 def unshelve(ui, repo, *shelved, **opts):
7541 """restore a shelved change to the working directory
7540 """restore a shelved change to the working directory
7542
7541
7543 This command accepts an optional name of a shelved change to
7542 This command accepts an optional name of a shelved change to
7544 restore. If none is given, the most recent shelved change is used.
7543 restore. If none is given, the most recent shelved change is used.
7545
7544
7546 If a shelved change is applied successfully, the bundle that
7545 If a shelved change is applied successfully, the bundle that
7547 contains the shelved changes is moved to a backup location
7546 contains the shelved changes is moved to a backup location
7548 (.hg/shelve-backup).
7547 (.hg/shelve-backup).
7549
7548
7550 Since you can restore a shelved change on top of an arbitrary
7549 Since you can restore a shelved change on top of an arbitrary
7551 commit, it is possible that unshelving will result in a conflict
7550 commit, it is possible that unshelving will result in a conflict
7552 between your changes and the commits you are unshelving onto. If
7551 between your changes and the commits you are unshelving onto. If
7553 this occurs, you must resolve the conflict, then use
7552 this occurs, you must resolve the conflict, then use
7554 ``--continue`` to complete the unshelve operation. (The bundle
7553 ``--continue`` to complete the unshelve operation. (The bundle
7555 will not be moved until you successfully complete the unshelve.)
7554 will not be moved until you successfully complete the unshelve.)
7556
7555
7557 (Alternatively, you can use ``--abort`` to abandon an unshelve
7556 (Alternatively, you can use ``--abort`` to abandon an unshelve
7558 that causes a conflict. This reverts the unshelved changes, and
7557 that causes a conflict. This reverts the unshelved changes, and
7559 leaves the bundle in place.)
7558 leaves the bundle in place.)
7560
7559
7561 If bare shelved change (without interactive, include and exclude
7560 If bare shelved change (without interactive, include and exclude
7562 option) was done on newly created branch it would restore branch
7561 option) was done on newly created branch it would restore branch
7563 information to the working directory.
7562 information to the working directory.
7564
7563
7565 After a successful unshelve, the shelved changes are stored in a
7564 After a successful unshelve, the shelved changes are stored in a
7566 backup directory. Only the N most recent backups are kept. N
7565 backup directory. Only the N most recent backups are kept. N
7567 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7566 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7568 configuration option.
7567 configuration option.
7569
7568
7570 .. container:: verbose
7569 .. container:: verbose
7571
7570
7572 Timestamp in seconds is used to decide order of backups. More
7571 Timestamp in seconds is used to decide order of backups. More
7573 than ``maxbackups`` backups are kept, if same timestamp
7572 than ``maxbackups`` backups are kept, if same timestamp
7574 prevents from deciding exact order of them, for safety.
7573 prevents from deciding exact order of them, for safety.
7575
7574
7576 Selected changes can be unshelved with ``--interactive`` flag.
7575 Selected changes can be unshelved with ``--interactive`` flag.
7577 The working directory is updated with the selected changes, and
7576 The working directory is updated with the selected changes, and
7578 only the unselected changes remain shelved.
7577 only the unselected changes remain shelved.
7579 Note: The whole shelve is applied to working directory first before
7578 Note: The whole shelve is applied to working directory first before
7580 running interactively. So, this will bring up all the conflicts between
7579 running interactively. So, this will bring up all the conflicts between
7581 working directory and the shelve, irrespective of which changes will be
7580 working directory and the shelve, irrespective of which changes will be
7582 unshelved.
7581 unshelved.
7583 """
7582 """
7584 with repo.wlock():
7583 with repo.wlock():
7585 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7584 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7586
7585
7587
7586
7588 statemod.addunfinished(
7587 statemod.addunfinished(
7589 b'unshelve',
7588 b'unshelve',
7590 fname=b'shelvedstate',
7589 fname=b'shelvedstate',
7591 continueflag=True,
7590 continueflag=True,
7592 abortfunc=shelvemod.hgabortunshelve,
7591 abortfunc=shelvemod.hgabortunshelve,
7593 continuefunc=shelvemod.hgcontinueunshelve,
7592 continuefunc=shelvemod.hgcontinueunshelve,
7594 cmdmsg=_(b'unshelve already in progress'),
7593 cmdmsg=_(b'unshelve already in progress'),
7595 )
7594 )
7596
7595
7597
7596
7598 @command(
7597 @command(
7599 b'update|up|checkout|co',
7598 b'update|up|checkout|co',
7600 [
7599 [
7601 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7600 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7602 (b'c', b'check', None, _(b'require clean working directory')),
7601 (b'c', b'check', None, _(b'require clean working directory')),
7603 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7602 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7604 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7603 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7605 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7604 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7606 ]
7605 ]
7607 + mergetoolopts,
7606 + mergetoolopts,
7608 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7607 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7609 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7608 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7610 helpbasic=True,
7609 helpbasic=True,
7611 )
7610 )
7612 def update(ui, repo, node=None, **opts):
7611 def update(ui, repo, node=None, **opts):
7613 """update working directory (or switch revisions)
7612 """update working directory (or switch revisions)
7614
7613
7615 Update the repository's working directory to the specified
7614 Update the repository's working directory to the specified
7616 changeset. If no changeset is specified, update to the tip of the
7615 changeset. If no changeset is specified, update to the tip of the
7617 current named branch and move the active bookmark (see :hg:`help
7616 current named branch and move the active bookmark (see :hg:`help
7618 bookmarks`).
7617 bookmarks`).
7619
7618
7620 Update sets the working directory's parent revision to the specified
7619 Update sets the working directory's parent revision to the specified
7621 changeset (see :hg:`help parents`).
7620 changeset (see :hg:`help parents`).
7622
7621
7623 If the changeset is not a descendant or ancestor of the working
7622 If the changeset is not a descendant or ancestor of the working
7624 directory's parent and there are uncommitted changes, the update is
7623 directory's parent and there are uncommitted changes, the update is
7625 aborted. With the -c/--check option, the working directory is checked
7624 aborted. With the -c/--check option, the working directory is checked
7626 for uncommitted changes; if none are found, the working directory is
7625 for uncommitted changes; if none are found, the working directory is
7627 updated to the specified changeset.
7626 updated to the specified changeset.
7628
7627
7629 .. container:: verbose
7628 .. container:: verbose
7630
7629
7631 The -C/--clean, -c/--check, and -m/--merge options control what
7630 The -C/--clean, -c/--check, and -m/--merge options control what
7632 happens if the working directory contains uncommitted changes.
7631 happens if the working directory contains uncommitted changes.
7633 At most of one of them can be specified.
7632 At most of one of them can be specified.
7634
7633
7635 1. If no option is specified, and if
7634 1. If no option is specified, and if
7636 the requested changeset is an ancestor or descendant of
7635 the requested changeset is an ancestor or descendant of
7637 the working directory's parent, the uncommitted changes
7636 the working directory's parent, the uncommitted changes
7638 are merged into the requested changeset and the merged
7637 are merged into the requested changeset and the merged
7639 result is left uncommitted. If the requested changeset is
7638 result is left uncommitted. If the requested changeset is
7640 not an ancestor or descendant (that is, it is on another
7639 not an ancestor or descendant (that is, it is on another
7641 branch), the update is aborted and the uncommitted changes
7640 branch), the update is aborted and the uncommitted changes
7642 are preserved.
7641 are preserved.
7643
7642
7644 2. With the -m/--merge option, the update is allowed even if the
7643 2. With the -m/--merge option, the update is allowed even if the
7645 requested changeset is not an ancestor or descendant of
7644 requested changeset is not an ancestor or descendant of
7646 the working directory's parent.
7645 the working directory's parent.
7647
7646
7648 3. With the -c/--check option, the update is aborted and the
7647 3. With the -c/--check option, the update is aborted and the
7649 uncommitted changes are preserved.
7648 uncommitted changes are preserved.
7650
7649
7651 4. With the -C/--clean option, uncommitted changes are discarded and
7650 4. With the -C/--clean option, uncommitted changes are discarded and
7652 the working directory is updated to the requested changeset.
7651 the working directory is updated to the requested changeset.
7653
7652
7654 To cancel an uncommitted merge (and lose your changes), use
7653 To cancel an uncommitted merge (and lose your changes), use
7655 :hg:`merge --abort`.
7654 :hg:`merge --abort`.
7656
7655
7657 Use null as the changeset to remove the working directory (like
7656 Use null as the changeset to remove the working directory (like
7658 :hg:`clone -U`).
7657 :hg:`clone -U`).
7659
7658
7660 If you want to revert just one file to an older revision, use
7659 If you want to revert just one file to an older revision, use
7661 :hg:`revert [-r REV] NAME`.
7660 :hg:`revert [-r REV] NAME`.
7662
7661
7663 See :hg:`help dates` for a list of formats valid for -d/--date.
7662 See :hg:`help dates` for a list of formats valid for -d/--date.
7664
7663
7665 Returns 0 on success, 1 if there are unresolved files.
7664 Returns 0 on success, 1 if there are unresolved files.
7666 """
7665 """
7667 rev = opts.get('rev')
7666 rev = opts.get('rev')
7668 date = opts.get('date')
7667 date = opts.get('date')
7669 clean = opts.get('clean')
7668 clean = opts.get('clean')
7670 check = opts.get('check')
7669 check = opts.get('check')
7671 merge = opts.get('merge')
7670 merge = opts.get('merge')
7672 if rev and node:
7671 if rev and node:
7673 raise error.Abort(_(b"please specify just one revision"))
7672 raise error.Abort(_(b"please specify just one revision"))
7674
7673
7675 if ui.configbool(b'commands', b'update.requiredest'):
7674 if ui.configbool(b'commands', b'update.requiredest'):
7676 if not node and not rev and not date:
7675 if not node and not rev and not date:
7677 raise error.Abort(
7676 raise error.Abort(
7678 _(b'you must specify a destination'),
7677 _(b'you must specify a destination'),
7679 hint=_(b'for example: hg update ".::"'),
7678 hint=_(b'for example: hg update ".::"'),
7680 )
7679 )
7681
7680
7682 if rev is None or rev == b'':
7681 if rev is None or rev == b'':
7683 rev = node
7682 rev = node
7684
7683
7685 if date and rev is not None:
7684 if date and rev is not None:
7686 raise error.Abort(_(b"you can't specify a revision and a date"))
7685 raise error.Abort(_(b"you can't specify a revision and a date"))
7687
7686
7688 if len([x for x in (clean, check, merge) if x]) > 1:
7687 if len([x for x in (clean, check, merge) if x]) > 1:
7689 raise error.Abort(
7688 raise error.Abort(
7690 _(
7689 _(
7691 b"can only specify one of -C/--clean, -c/--check, "
7690 b"can only specify one of -C/--clean, -c/--check, "
7692 b"or -m/--merge"
7691 b"or -m/--merge"
7693 )
7692 )
7694 )
7693 )
7695
7694
7696 updatecheck = None
7695 updatecheck = None
7697 if check:
7696 if check:
7698 updatecheck = b'abort'
7697 updatecheck = b'abort'
7699 elif merge:
7698 elif merge:
7700 updatecheck = b'none'
7699 updatecheck = b'none'
7701
7700
7702 with repo.wlock():
7701 with repo.wlock():
7703 cmdutil.clearunfinished(repo)
7702 cmdutil.clearunfinished(repo)
7704 if date:
7703 if date:
7705 rev = cmdutil.finddate(ui, repo, date)
7704 rev = cmdutil.finddate(ui, repo, date)
7706
7705
7707 # if we defined a bookmark, we have to remember the original name
7706 # if we defined a bookmark, we have to remember the original name
7708 brev = rev
7707 brev = rev
7709 if rev:
7708 if rev:
7710 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7711 ctx = scmutil.revsingle(repo, rev, default=None)
7710 ctx = scmutil.revsingle(repo, rev, default=None)
7712 rev = ctx.rev()
7711 rev = ctx.rev()
7713 hidden = ctx.hidden()
7712 hidden = ctx.hidden()
7714 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7713 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7715 with ui.configoverride(overrides, b'update'):
7714 with ui.configoverride(overrides, b'update'):
7716 ret = hg.updatetotally(
7715 ret = hg.updatetotally(
7717 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7716 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7718 )
7717 )
7719 if hidden:
7718 if hidden:
7720 ctxstr = ctx.hex()[:12]
7719 ctxstr = ctx.hex()[:12]
7721 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7720 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7722
7721
7723 if ctx.obsolete():
7722 if ctx.obsolete():
7724 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7723 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7725 ui.warn(b"(%s)\n" % obsfatemsg)
7724 ui.warn(b"(%s)\n" % obsfatemsg)
7726 return ret
7725 return ret
7727
7726
7728
7727
7729 @command(
7728 @command(
7730 b'verify',
7729 b'verify',
7731 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7730 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7732 helpcategory=command.CATEGORY_MAINTENANCE,
7731 helpcategory=command.CATEGORY_MAINTENANCE,
7733 )
7732 )
7734 def verify(ui, repo, **opts):
7733 def verify(ui, repo, **opts):
7735 """verify the integrity of the repository
7734 """verify the integrity of the repository
7736
7735
7737 Verify the integrity of the current repository.
7736 Verify the integrity of the current repository.
7738
7737
7739 This will perform an extensive check of the repository's
7738 This will perform an extensive check of the repository's
7740 integrity, validating the hashes and checksums of each entry in
7739 integrity, validating the hashes and checksums of each entry in
7741 the changelog, manifest, and tracked files, as well as the
7740 the changelog, manifest, and tracked files, as well as the
7742 integrity of their crosslinks and indices.
7741 integrity of their crosslinks and indices.
7743
7742
7744 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7743 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7745 for more information about recovery from corruption of the
7744 for more information about recovery from corruption of the
7746 repository.
7745 repository.
7747
7746
7748 Returns 0 on success, 1 if errors are encountered.
7747 Returns 0 on success, 1 if errors are encountered.
7749 """
7748 """
7750 opts = pycompat.byteskwargs(opts)
7749 opts = pycompat.byteskwargs(opts)
7751
7750
7752 level = None
7751 level = None
7753 if opts[b'full']:
7752 if opts[b'full']:
7754 level = verifymod.VERIFY_FULL
7753 level = verifymod.VERIFY_FULL
7755 return hg.verify(repo, level)
7754 return hg.verify(repo, level)
7756
7755
7757
7756
7758 @command(
7757 @command(
7759 b'version',
7758 b'version',
7760 [] + formatteropts,
7759 [] + formatteropts,
7761 helpcategory=command.CATEGORY_HELP,
7760 helpcategory=command.CATEGORY_HELP,
7762 norepo=True,
7761 norepo=True,
7763 intents={INTENT_READONLY},
7762 intents={INTENT_READONLY},
7764 )
7763 )
7765 def version_(ui, **opts):
7764 def version_(ui, **opts):
7766 """output version and copyright information
7765 """output version and copyright information
7767
7766
7768 .. container:: verbose
7767 .. container:: verbose
7769
7768
7770 Template:
7769 Template:
7771
7770
7772 The following keywords are supported. See also :hg:`help templates`.
7771 The following keywords are supported. See also :hg:`help templates`.
7773
7772
7774 :extensions: List of extensions.
7773 :extensions: List of extensions.
7775 :ver: String. Version number.
7774 :ver: String. Version number.
7776
7775
7777 And each entry of ``{extensions}`` provides the following sub-keywords
7776 And each entry of ``{extensions}`` provides the following sub-keywords
7778 in addition to ``{ver}``.
7777 in addition to ``{ver}``.
7779
7778
7780 :bundled: Boolean. True if included in the release.
7779 :bundled: Boolean. True if included in the release.
7781 :name: String. Extension name.
7780 :name: String. Extension name.
7782 """
7781 """
7783 opts = pycompat.byteskwargs(opts)
7782 opts = pycompat.byteskwargs(opts)
7784 if ui.verbose:
7783 if ui.verbose:
7785 ui.pager(b'version')
7784 ui.pager(b'version')
7786 fm = ui.formatter(b"version", opts)
7785 fm = ui.formatter(b"version", opts)
7787 fm.startitem()
7786 fm.startitem()
7788 fm.write(
7787 fm.write(
7789 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7788 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7790 )
7789 )
7791 license = _(
7790 license = _(
7792 b"(see https://mercurial-scm.org for more information)\n"
7791 b"(see https://mercurial-scm.org for more information)\n"
7793 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7792 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7794 b"This is free software; see the source for copying conditions. "
7793 b"This is free software; see the source for copying conditions. "
7795 b"There is NO\nwarranty; "
7794 b"There is NO\nwarranty; "
7796 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7795 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7797 )
7796 )
7798 if not ui.quiet:
7797 if not ui.quiet:
7799 fm.plain(license)
7798 fm.plain(license)
7800
7799
7801 if ui.verbose:
7800 if ui.verbose:
7802 fm.plain(_(b"\nEnabled extensions:\n\n"))
7801 fm.plain(_(b"\nEnabled extensions:\n\n"))
7803 # format names and versions into columns
7802 # format names and versions into columns
7804 names = []
7803 names = []
7805 vers = []
7804 vers = []
7806 isinternals = []
7805 isinternals = []
7807 for name, module in extensions.extensions():
7806 for name, module in extensions.extensions():
7808 names.append(name)
7807 names.append(name)
7809 vers.append(extensions.moduleversion(module) or None)
7808 vers.append(extensions.moduleversion(module) or None)
7810 isinternals.append(extensions.ismoduleinternal(module))
7809 isinternals.append(extensions.ismoduleinternal(module))
7811 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7810 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7812 if names:
7811 if names:
7813 namefmt = b" %%-%ds " % max(len(n) for n in names)
7812 namefmt = b" %%-%ds " % max(len(n) for n in names)
7814 places = [_(b"external"), _(b"internal")]
7813 places = [_(b"external"), _(b"internal")]
7815 for n, v, p in zip(names, vers, isinternals):
7814 for n, v, p in zip(names, vers, isinternals):
7816 fn.startitem()
7815 fn.startitem()
7817 fn.condwrite(ui.verbose, b"name", namefmt, n)
7816 fn.condwrite(ui.verbose, b"name", namefmt, n)
7818 if ui.verbose:
7817 if ui.verbose:
7819 fn.plain(b"%s " % places[p])
7818 fn.plain(b"%s " % places[p])
7820 fn.data(bundled=p)
7819 fn.data(bundled=p)
7821 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7820 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7822 if ui.verbose:
7821 if ui.verbose:
7823 fn.plain(b"\n")
7822 fn.plain(b"\n")
7824 fn.end()
7823 fn.end()
7825 fm.end()
7824 fm.end()
7826
7825
7827
7826
7828 def loadcmdtable(ui, name, cmdtable):
7827 def loadcmdtable(ui, name, cmdtable):
7829 """Load command functions from specified cmdtable
7828 """Load command functions from specified cmdtable
7830 """
7829 """
7831 overrides = [cmd for cmd in cmdtable if cmd in table]
7830 overrides = [cmd for cmd in cmdtable if cmd in table]
7832 if overrides:
7831 if overrides:
7833 ui.warn(
7832 ui.warn(
7834 _(b"extension '%s' overrides commands: %s\n")
7833 _(b"extension '%s' overrides commands: %s\n")
7835 % (name, b" ".join(overrides))
7834 % (name, b" ".join(overrides))
7836 )
7835 )
7837 table.update(cmdtable)
7836 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now