##// END OF EJS Templates
config: move edition code in its own module...
marmoute -
r53314:c97e0fd2 default
parent child Browse files
Show More
@@ -0,0 +1,108
1 # Gather code related to command dealing with configuration.
2
3 from __future__ import annotations
4
5 import os
6
7 from typing import Any, Dict, Optional
8
9 from ..i18n import _
10
11 from .. import (
12 cmdutil,
13 error,
14 requirements,
15 ui as uimod,
16 util,
17 vfs as vfsmod,
18 )
19
20 from . import rcutil
21
22 EDIT_FLAG = 'edit'
23
24
25 # keep typing simple for now
26 ConfigLevelT = str
27 LEVEL_USER = 'user' # "user" is the default level and never passed explicitly
28 LEVEL_LOCAL = 'local'
29 LEVEL_GLOBAL = 'global'
30 LEVEL_SHARED = 'shared'
31 LEVEL_NON_SHARED = 'non_shared'
32 EDIT_LEVELS = (
33 LEVEL_USER,
34 LEVEL_LOCAL,
35 LEVEL_GLOBAL,
36 LEVEL_SHARED,
37 LEVEL_NON_SHARED,
38 )
39
40
41 def find_edit_level(
42 ui: uimod.ui, repo, opts: Dict[str, Any]
43 ) -> Optional[ConfigLevelT]:
44 """return the level we should edit, if any.
45
46 Parse the command option to detect when an edit is requested, and if so the
47 configuration level we should edit.
48 """
49 if opts.get(EDIT_FLAG) or any(opts.get(o) for o in EDIT_LEVELS):
50 cmdutil.check_at_most_one_arg(opts, *EDIT_LEVELS)
51 for level in EDIT_LEVELS:
52 if opts.get(level):
53 return level
54 return EDIT_LEVELS[0]
55 return None
56
57
58 def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None:
59 """let the user edit configuration file for the given level"""
60
61 if level == LEVEL_USER:
62 paths = rcutil.userrcpath()
63 elif level == LEVEL_GLOBAL:
64 paths = rcutil.systemrcpath()
65 elif level == LEVEL_LOCAL:
66 if not repo:
67 raise error.InputError(_(b"can't use --local outside a repository"))
68 paths = [repo.vfs.join(b'hgrc')]
69 elif level == LEVEL_NON_SHARED:
70 paths = [repo.vfs.join(b'hgrc-not-shared')]
71 elif level == LEVEL_SHARED:
72 if not repo.shared():
73 raise error.InputError(
74 _(b"repository is not shared; can't use --shared")
75 )
76 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
77 raise error.InputError(
78 _(
79 b"share safe feature not enabled; "
80 b"unable to edit shared source repository config"
81 )
82 )
83 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
84 else:
85 msg = 'unknown config level: %s' % level
86 raise error.ProgrammingError(msg)
87
88 for f in paths:
89 if os.path.exists(f):
90 break
91 else:
92 if LEVEL_GLOBAL:
93 samplehgrc = uimod.samplehgrcs[b'global']
94 elif LEVEL_LOCAL:
95 samplehgrc = uimod.samplehgrcs[b'local']
96 else:
97 samplehgrc = uimod.samplehgrcs[b'user']
98
99 f = paths[0]
100 util.writefile(f, util.tonativeeol(samplehgrc))
101
102 editor = ui.geteditor()
103 ui.system(
104 b"%s \"%s\"" % (editor, f),
105 onerr=error.InputError,
106 errprefix=_(b"edit failed"),
107 blockedtag=b'config_edit',
108 )
@@ -1,7759 +1,7710
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@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 annotations
8 from __future__ import annotations
9
9
10 import os
10 import os
11 import re
11 import re
12 import sys
12 import sys
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullid,
17 nullid,
18 nullrev,
18 nullrev,
19 short,
19 short,
20 wdirrev,
20 wdirrev,
21 )
21 )
22 from . import (
22 from . import (
23 admin_commands as admin_commands_mod,
23 admin_commands as admin_commands_mod,
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 bundlecaches,
27 bundlecaches,
28 changegroup,
28 changegroup,
29 cmdutil,
29 cmdutil,
30 copies,
30 copies,
31 debugcommands as debugcommandsmod,
31 debugcommands as debugcommandsmod,
32 destutil,
32 destutil,
33 diffutil,
33 diffutil,
34 discovery,
34 discovery,
35 encoding,
35 encoding,
36 error,
36 error,
37 exchange,
37 exchange,
38 extensions,
38 extensions,
39 filemerge,
39 filemerge,
40 formatter,
40 formatter,
41 graphmod,
41 graphmod,
42 grep as grepmod,
42 grep as grepmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 mergestate as mergestatemod,
48 mergestate as mergestatemod,
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 registrar,
55 registrar,
56 requirements,
57 revsetlang,
56 revsetlang,
58 rewriteutil,
57 rewriteutil,
59 scmutil,
58 scmutil,
60 server,
59 server,
61 shelve as shelvemod,
60 shelve as shelvemod,
62 state as statemod,
61 state as statemod,
63 tags as tagsmod,
62 tags as tagsmod,
64 ui as uimod,
65 util,
63 util,
66 verify as verifymod,
64 verify as verifymod,
67 vfs as vfsmod,
68 wireprotoserver,
65 wireprotoserver,
69 )
66 )
70
67
71 from .cmd_impls import graft as graft_impl
68 from .cmd_impls import graft as graft_impl
72 from .configuration import rcutil
69 from .configuration import (
70 command as config_command,
71 rcutil,
72 )
73 from .utils import (
73 from .utils import (
74 dateutil,
74 dateutil,
75 procutil,
75 procutil,
76 stringutil,
76 stringutil,
77 urlutil,
77 urlutil,
78 )
78 )
79
79
80 table = {}
80 table = {}
81 table.update(debugcommandsmod.command._table)
81 table.update(debugcommandsmod.command._table)
82 table.update(admin_commands_mod.command._table)
82 table.update(admin_commands_mod.command._table)
83
83
84 command = registrar.command(table)
84 command = registrar.command(table)
85 INTENT_READONLY = registrar.INTENT_READONLY
85 INTENT_READONLY = registrar.INTENT_READONLY
86
86
87 # common command options
87 # common command options
88
88
89 globalopts = [
89 globalopts = [
90 (
90 (
91 b'R',
91 b'R',
92 b'repository',
92 b'repository',
93 b'',
93 b'',
94 _(b'repository root directory or name of overlay bundle file'),
94 _(b'repository root directory or name of overlay bundle file'),
95 _(b'REPO'),
95 _(b'REPO'),
96 ),
96 ),
97 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
97 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
98 (
98 (
99 b'y',
99 b'y',
100 b'noninteractive',
100 b'noninteractive',
101 None,
101 None,
102 _(
102 _(
103 b'do not prompt, automatically pick the first choice for all prompts'
103 b'do not prompt, automatically pick the first choice for all prompts'
104 ),
104 ),
105 ),
105 ),
106 (b'q', b'quiet', None, _(b'suppress output')),
106 (b'q', b'quiet', None, _(b'suppress output')),
107 (b'v', b'verbose', None, _(b'enable additional output')),
107 (b'v', b'verbose', None, _(b'enable additional output')),
108 (
108 (
109 b'',
109 b'',
110 b'color',
110 b'color',
111 b'',
111 b'',
112 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
112 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
113 # and should not be translated
113 # and should not be translated
114 _(b"when to colorize (boolean, always, auto, never, or debug)"),
114 _(b"when to colorize (boolean, always, auto, never, or debug)"),
115 _(b'TYPE'),
115 _(b'TYPE'),
116 ),
116 ),
117 (
117 (
118 b'',
118 b'',
119 b'config',
119 b'config',
120 [],
120 [],
121 _(b'set/override config option (use \'section.name=value\')'),
121 _(b'set/override config option (use \'section.name=value\')'),
122 _(b'CONFIG'),
122 _(b'CONFIG'),
123 ),
123 ),
124 (b'', b'debug', None, _(b'enable debugging output')),
124 (b'', b'debug', None, _(b'enable debugging output')),
125 (b'', b'debugger', None, _(b'start debugger')),
125 (b'', b'debugger', None, _(b'start debugger')),
126 (
126 (
127 b'',
127 b'',
128 b'encoding',
128 b'encoding',
129 encoding.encoding,
129 encoding.encoding,
130 _(b'set the charset encoding'),
130 _(b'set the charset encoding'),
131 _(b'ENCODE'),
131 _(b'ENCODE'),
132 ),
132 ),
133 (
133 (
134 b'',
134 b'',
135 b'encodingmode',
135 b'encodingmode',
136 encoding.encodingmode,
136 encoding.encodingmode,
137 _(b'set the charset encoding mode'),
137 _(b'set the charset encoding mode'),
138 _(b'MODE'),
138 _(b'MODE'),
139 ),
139 ),
140 (b'', b'traceback', None, _(b'always print a traceback on exception')),
140 (b'', b'traceback', None, _(b'always print a traceback on exception')),
141 (b'', b'time', None, _(b'time how long the command takes')),
141 (b'', b'time', None, _(b'time how long the command takes')),
142 (b'', b'profile', None, _(b'print command execution profile')),
142 (b'', b'profile', None, _(b'print command execution profile')),
143 (b'', b'version', None, _(b'output version information and exit')),
143 (b'', b'version', None, _(b'output version information and exit')),
144 (b'h', b'help', None, _(b'display help and exit')),
144 (b'h', b'help', None, _(b'display help and exit')),
145 (b'', b'hidden', False, _(b'consider hidden changesets')),
145 (b'', b'hidden', False, _(b'consider hidden changesets')),
146 (
146 (
147 b'',
147 b'',
148 b'pager',
148 b'pager',
149 b'auto',
149 b'auto',
150 _(b"when to paginate (boolean, always, auto, or never)"),
150 _(b"when to paginate (boolean, always, auto, or never)"),
151 _(b'TYPE'),
151 _(b'TYPE'),
152 ),
152 ),
153 ]
153 ]
154
154
155 dryrunopts = cmdutil.dryrunopts
155 dryrunopts = cmdutil.dryrunopts
156 remoteopts = cmdutil.remoteopts
156 remoteopts = cmdutil.remoteopts
157 walkopts = cmdutil.walkopts
157 walkopts = cmdutil.walkopts
158 commitopts = cmdutil.commitopts
158 commitopts = cmdutil.commitopts
159 commitopts2 = cmdutil.commitopts2
159 commitopts2 = cmdutil.commitopts2
160 commitopts3 = cmdutil.commitopts3
160 commitopts3 = cmdutil.commitopts3
161 formatteropts = cmdutil.formatteropts
161 formatteropts = cmdutil.formatteropts
162 templateopts = cmdutil.templateopts
162 templateopts = cmdutil.templateopts
163 logopts = cmdutil.logopts
163 logopts = cmdutil.logopts
164 diffopts = cmdutil.diffopts
164 diffopts = cmdutil.diffopts
165 diffwsopts = cmdutil.diffwsopts
165 diffwsopts = cmdutil.diffwsopts
166 diffopts2 = cmdutil.diffopts2
166 diffopts2 = cmdutil.diffopts2
167 mergetoolopts = cmdutil.mergetoolopts
167 mergetoolopts = cmdutil.mergetoolopts
168 similarityopts = cmdutil.similarityopts
168 similarityopts = cmdutil.similarityopts
169 subrepoopts = cmdutil.subrepoopts
169 subrepoopts = cmdutil.subrepoopts
170 debugrevlogopts = cmdutil.debugrevlogopts
170 debugrevlogopts = cmdutil.debugrevlogopts
171
171
172 # Commands start here, listed alphabetically
172 # Commands start here, listed alphabetically
173
173
174
174
175 @command(
175 @command(
176 b'abort',
176 b'abort',
177 dryrunopts,
177 dryrunopts,
178 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
178 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
179 helpbasic=True,
179 helpbasic=True,
180 )
180 )
181 def abort(ui, repo, **opts):
181 def abort(ui, repo, **opts):
182 """abort an unfinished operation (EXPERIMENTAL)
182 """abort an unfinished operation (EXPERIMENTAL)
183
183
184 Aborts a multistep operation like graft, histedit, rebase, merge,
184 Aborts a multistep operation like graft, histedit, rebase, merge,
185 and unshelve if they are in an unfinished state.
185 and unshelve if they are in an unfinished state.
186
186
187 use --dry-run/-n to dry run the command.
187 use --dry-run/-n to dry run the command.
188 """
188 """
189 dryrun = opts.get('dry_run')
189 dryrun = opts.get('dry_run')
190 abortstate = cmdutil.getunfinishedstate(repo)
190 abortstate = cmdutil.getunfinishedstate(repo)
191 if not abortstate:
191 if not abortstate:
192 raise error.StateError(_(b'no operation in progress'))
192 raise error.StateError(_(b'no operation in progress'))
193 if not abortstate.abortfunc:
193 if not abortstate.abortfunc:
194 raise error.InputError(
194 raise error.InputError(
195 (
195 (
196 _(b"%s in progress but does not support 'hg abort'")
196 _(b"%s in progress but does not support 'hg abort'")
197 % (abortstate._opname)
197 % (abortstate._opname)
198 ),
198 ),
199 hint=abortstate.hint(),
199 hint=abortstate.hint(),
200 )
200 )
201 if dryrun:
201 if dryrun:
202 ui.status(
202 ui.status(
203 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
203 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
204 )
204 )
205 return
205 return
206 return abortstate.abortfunc(ui, repo)
206 return abortstate.abortfunc(ui, repo)
207
207
208
208
209 @command(
209 @command(
210 b'add',
210 b'add',
211 walkopts + subrepoopts + dryrunopts,
211 walkopts + subrepoopts + dryrunopts,
212 _(b'[OPTION]... [FILE]...'),
212 _(b'[OPTION]... [FILE]...'),
213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
214 helpbasic=True,
214 helpbasic=True,
215 inferrepo=True,
215 inferrepo=True,
216 )
216 )
217 def add(ui, repo, *pats, **opts):
217 def add(ui, repo, *pats, **opts):
218 """add the specified files on the next commit
218 """add the specified files on the next commit
219
219
220 Schedule files to be version controlled and added to the
220 Schedule files to be version controlled and added to the
221 repository.
221 repository.
222
222
223 The files will be added to the repository at the next commit. To
223 The files will be added to the repository at the next commit. To
224 undo an add before that, see :hg:`forget`.
224 undo an add before that, see :hg:`forget`.
225
225
226 If no names are given, add all files to the repository (except
226 If no names are given, add all files to the repository (except
227 files matching ``.hgignore``).
227 files matching ``.hgignore``).
228
228
229 .. container:: verbose
229 .. container:: verbose
230
230
231 Examples:
231 Examples:
232
232
233 - New (unknown) files are added
233 - New (unknown) files are added
234 automatically by :hg:`add`::
234 automatically by :hg:`add`::
235
235
236 $ ls
236 $ ls
237 foo.c
237 foo.c
238 $ hg status
238 $ hg status
239 ? foo.c
239 ? foo.c
240 $ hg add
240 $ hg add
241 adding foo.c
241 adding foo.c
242 $ hg status
242 $ hg status
243 A foo.c
243 A foo.c
244
244
245 - Specific files to be added can be specified::
245 - Specific files to be added can be specified::
246
246
247 $ ls
247 $ ls
248 bar.c foo.c
248 bar.c foo.c
249 $ hg status
249 $ hg status
250 ? bar.c
250 ? bar.c
251 ? foo.c
251 ? foo.c
252 $ hg add bar.c
252 $ hg add bar.c
253 $ hg status
253 $ hg status
254 A bar.c
254 A bar.c
255 ? foo.c
255 ? foo.c
256
256
257 Returns 0 if all files are successfully added.
257 Returns 0 if all files are successfully added.
258 """
258 """
259
259
260 with repo.wlock(), repo.dirstate.changing_files(repo):
260 with repo.wlock(), repo.dirstate.changing_files(repo):
261 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
261 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
262 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
262 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
263 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
263 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
264 return rejected and 1 or 0
264 return rejected and 1 or 0
265
265
266
266
267 @command(
267 @command(
268 b'addremove',
268 b'addremove',
269 similarityopts + subrepoopts + walkopts + dryrunopts,
269 similarityopts + subrepoopts + walkopts + dryrunopts,
270 _(b'[OPTION]... [FILE]...'),
270 _(b'[OPTION]... [FILE]...'),
271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
271 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
272 inferrepo=True,
272 inferrepo=True,
273 )
273 )
274 def addremove(ui, repo, *pats, **opts):
274 def addremove(ui, repo, *pats, **opts):
275 """add all new files, delete all missing files
275 """add all new files, delete all missing files
276
276
277 Add all new files and remove all missing files from the
277 Add all new files and remove all missing files from the
278 repository.
278 repository.
279
279
280 Unless names are given, new files are ignored if they match any of
280 Unless names are given, new files are ignored if they match any of
281 the patterns in ``.hgignore``. As with add, these changes take
281 the patterns in ``.hgignore``. As with add, these changes take
282 effect at the next commit.
282 effect at the next commit.
283
283
284 Use the -s/--similarity option to detect renamed files. This
284 Use the -s/--similarity option to detect renamed files. This
285 option takes a percentage between 0 (disabled) and 100 (files must
285 option takes a percentage between 0 (disabled) and 100 (files must
286 be identical) as its parameter. With a parameter greater than 0,
286 be identical) as its parameter. With a parameter greater than 0,
287 this compares every removed file with every added file and records
287 this compares every removed file with every added file and records
288 those similar enough as renames. Detecting renamed files this way
288 those similar enough as renames. Detecting renamed files this way
289 can be expensive. After using this option, :hg:`status -C` can be
289 can be expensive. After using this option, :hg:`status -C` can be
290 used to check which files were identified as moved or renamed. If
290 used to check which files were identified as moved or renamed. If
291 not specified, -s/--similarity defaults to 100 and only renames of
291 not specified, -s/--similarity defaults to 100 and only renames of
292 identical files are detected.
292 identical files are detected.
293
293
294 .. container:: verbose
294 .. container:: verbose
295
295
296 Examples:
296 Examples:
297
297
298 - A number of files (bar.c and foo.c) are new,
298 - A number of files (bar.c and foo.c) are new,
299 while foobar.c has been removed (without using :hg:`remove`)
299 while foobar.c has been removed (without using :hg:`remove`)
300 from the repository::
300 from the repository::
301
301
302 $ ls
302 $ ls
303 bar.c foo.c
303 bar.c foo.c
304 $ hg status
304 $ hg status
305 ! foobar.c
305 ! foobar.c
306 ? bar.c
306 ? bar.c
307 ? foo.c
307 ? foo.c
308 $ hg addremove
308 $ hg addremove
309 adding bar.c
309 adding bar.c
310 adding foo.c
310 adding foo.c
311 removing foobar.c
311 removing foobar.c
312 $ hg status
312 $ hg status
313 A bar.c
313 A bar.c
314 A foo.c
314 A foo.c
315 R foobar.c
315 R foobar.c
316
316
317 - A file foobar.c was moved to foo.c without using :hg:`rename`.
317 - A file foobar.c was moved to foo.c without using :hg:`rename`.
318 Afterwards, it was edited slightly::
318 Afterwards, it was edited slightly::
319
319
320 $ ls
320 $ ls
321 foo.c
321 foo.c
322 $ hg status
322 $ hg status
323 ! foobar.c
323 ! foobar.c
324 ? foo.c
324 ? foo.c
325 $ hg addremove --similarity 90
325 $ hg addremove --similarity 90
326 removing foobar.c
326 removing foobar.c
327 adding foo.c
327 adding foo.c
328 recording removal of foobar.c as rename to foo.c (94% similar)
328 recording removal of foobar.c as rename to foo.c (94% similar)
329 $ hg status -C
329 $ hg status -C
330 A foo.c
330 A foo.c
331 foobar.c
331 foobar.c
332 R foobar.c
332 R foobar.c
333
333
334 Returns 0 if all files are successfully added.
334 Returns 0 if all files are successfully added.
335 """
335 """
336 opts = pycompat.byteskwargs(opts)
336 opts = pycompat.byteskwargs(opts)
337 if not opts.get(b'similarity'):
337 if not opts.get(b'similarity'):
338 opts[b'similarity'] = b'100'
338 opts[b'similarity'] = b'100'
339 with repo.wlock(), repo.dirstate.changing_files(repo):
339 with repo.wlock(), repo.dirstate.changing_files(repo):
340 matcher = scmutil.match(repo[None], pats, opts)
340 matcher = scmutil.match(repo[None], pats, opts)
341 relative = scmutil.anypats(pats, opts)
341 relative = scmutil.anypats(pats, opts)
342 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
342 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
343 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
343 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
344
344
345
345
346 @command(
346 @command(
347 b'annotate|blame',
347 b'annotate|blame',
348 [
348 [
349 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
349 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
350 (
350 (
351 b'',
351 b'',
352 b'follow',
352 b'follow',
353 None,
353 None,
354 _(b'follow copies/renames and list the filename (DEPRECATED)'),
354 _(b'follow copies/renames and list the filename (DEPRECATED)'),
355 ),
355 ),
356 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
356 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
357 (b'a', b'text', None, _(b'treat all files as text')),
357 (b'a', b'text', None, _(b'treat all files as text')),
358 (b'u', b'user', None, _(b'list the author (long with -v)')),
358 (b'u', b'user', None, _(b'list the author (long with -v)')),
359 (b'f', b'file', None, _(b'list the filename')),
359 (b'f', b'file', None, _(b'list the filename')),
360 (b'd', b'date', None, _(b'list the date (short with -q)')),
360 (b'd', b'date', None, _(b'list the date (short with -q)')),
361 (b'n', b'number', None, _(b'list the revision number (default)')),
361 (b'n', b'number', None, _(b'list the revision number (default)')),
362 (b'c', b'changeset', None, _(b'list the changeset')),
362 (b'c', b'changeset', None, _(b'list the changeset')),
363 (
363 (
364 b'l',
364 b'l',
365 b'line-number',
365 b'line-number',
366 None,
366 None,
367 _(b'show line number at the first appearance'),
367 _(b'show line number at the first appearance'),
368 ),
368 ),
369 (
369 (
370 b'',
370 b'',
371 b'skip',
371 b'skip',
372 [],
372 [],
373 _(b'revset to not display (EXPERIMENTAL)'),
373 _(b'revset to not display (EXPERIMENTAL)'),
374 _(b'REV'),
374 _(b'REV'),
375 ),
375 ),
376 (
376 (
377 b'L',
377 b'L',
378 b'line-range',
378 b'line-range',
379 [],
379 [],
380 _(b'follow line range of specified file (EXPERIMENTAL)'),
380 _(b'follow line range of specified file (EXPERIMENTAL)'),
381 _(b'FILE,RANGE'),
381 _(b'FILE,RANGE'),
382 ),
382 ),
383 ]
383 ]
384 + diffwsopts
384 + diffwsopts
385 + walkopts
385 + walkopts
386 + formatteropts,
386 + formatteropts,
387 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
387 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
388 helpcategory=command.CATEGORY_FILE_CONTENTS,
388 helpcategory=command.CATEGORY_FILE_CONTENTS,
389 helpbasic=True,
389 helpbasic=True,
390 inferrepo=True,
390 inferrepo=True,
391 )
391 )
392 def annotate(ui, repo, *pats, **opts):
392 def annotate(ui, repo, *pats, **opts):
393 """show changeset information by line for each file
393 """show changeset information by line for each file
394
394
395 List changes in files, showing the revision id responsible for
395 List changes in files, showing the revision id responsible for
396 each line.
396 each line.
397
397
398 This command is useful for discovering when a change was made and
398 This command is useful for discovering when a change was made and
399 by whom.
399 by whom.
400
400
401 If you include --file, --user, or --date, the revision number is
401 If you include --file, --user, or --date, the revision number is
402 suppressed unless you also include --number.
402 suppressed unless you also include --number.
403
403
404 Without the -a/--text option, annotate will avoid processing files
404 Without the -a/--text option, annotate will avoid processing files
405 it detects as binary. With -a, annotate will annotate the file
405 it detects as binary. With -a, annotate will annotate the file
406 anyway, although the results will probably be neither useful
406 anyway, although the results will probably be neither useful
407 nor desirable.
407 nor desirable.
408
408
409 .. container:: verbose
409 .. container:: verbose
410
410
411 Use -L/--line-range FILE,M:N options to filter the output to the lines
411 Use -L/--line-range FILE,M:N options to filter the output to the lines
412 from M to N in FILE. This option is incompatible with --no-follow and
412 from M to N in FILE. This option is incompatible with --no-follow and
413 cannot be combined with file pattern arguments. When combined with --rev
413 cannot be combined with file pattern arguments. When combined with --rev
414 the line ranges refer to the state of the file at the requested revision.
414 the line ranges refer to the state of the file at the requested revision.
415
415
416 .. container:: verbose
416 .. container:: verbose
417
417
418 Template:
418 Template:
419
419
420 The following keywords are supported in addition to the common template
420 The following keywords are supported in addition to the common template
421 keywords and functions. See also :hg:`help templates`.
421 keywords and functions. See also :hg:`help templates`.
422
422
423 :lines: List of lines with annotation data.
423 :lines: List of lines with annotation data.
424 :path: String. Repository-absolute path of the specified file.
424 :path: String. Repository-absolute path of the specified file.
425
425
426 And each entry of ``{lines}`` provides the following sub-keywords in
426 And each entry of ``{lines}`` provides the following sub-keywords in
427 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
427 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
428
428
429 :line: String. Line content.
429 :line: String. Line content.
430 :lineno: Integer. Line number at that revision.
430 :lineno: Integer. Line number at that revision.
431 :path: String. Repository-absolute path of the file at that revision.
431 :path: String. Repository-absolute path of the file at that revision.
432
432
433 See :hg:`help templates.operators` for the list expansion syntax.
433 See :hg:`help templates.operators` for the list expansion syntax.
434
434
435 Returns 0 on success.
435 Returns 0 on success.
436 """
436 """
437 opts = pycompat.byteskwargs(opts)
437 opts = pycompat.byteskwargs(opts)
438
438
439 linerange = opts.get(b'line_range')
439 linerange = opts.get(b'line_range')
440
440
441 if linerange and opts.get(b'no_follow'):
441 if linerange and opts.get(b'no_follow'):
442 raise error.InputError(
442 raise error.InputError(
443 _(b'--line-range is incompatible with --no-follow')
443 _(b'--line-range is incompatible with --no-follow')
444 )
444 )
445
445
446 if pats and linerange:
446 if pats and linerange:
447 raise error.InputError(
447 raise error.InputError(
448 _(b'cannot combine filename or pattern and --line-range')
448 _(b'cannot combine filename or pattern and --line-range')
449 )
449 )
450
450
451 if not pats and not linerange:
451 if not pats and not linerange:
452 raise error.InputError(
452 raise error.InputError(
453 _(b'at least one filename or pattern is required')
453 _(b'at least one filename or pattern is required')
454 )
454 )
455
455
456 if opts.get(b'follow'):
456 if opts.get(b'follow'):
457 # --follow is deprecated and now just an alias for -f/--file
457 # --follow is deprecated and now just an alias for -f/--file
458 # to mimic the behavior of Mercurial before version 1.5
458 # to mimic the behavior of Mercurial before version 1.5
459 opts[b'file'] = True
459 opts[b'file'] = True
460
460
461 if (
461 if (
462 not opts.get(b'user')
462 not opts.get(b'user')
463 and not opts.get(b'changeset')
463 and not opts.get(b'changeset')
464 and not opts.get(b'date')
464 and not opts.get(b'date')
465 and not opts.get(b'file')
465 and not opts.get(b'file')
466 ):
466 ):
467 opts[b'number'] = True
467 opts[b'number'] = True
468
468
469 linenumber = opts.get(b'line_number') is not None
469 linenumber = opts.get(b'line_number') is not None
470 if (
470 if (
471 linenumber
471 linenumber
472 and (not opts.get(b'changeset'))
472 and (not opts.get(b'changeset'))
473 and (not opts.get(b'number'))
473 and (not opts.get(b'number'))
474 ):
474 ):
475 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
475 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
476
476
477 rev = opts.get(b'rev')
477 rev = opts.get(b'rev')
478 if rev:
478 if rev:
479 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
479 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
480 ctx = logcmdutil.revsingle(repo, rev)
480 ctx = logcmdutil.revsingle(repo, rev)
481
481
482 if not pats:
482 if not pats:
483 pats = [
483 pats = [
484 fname
484 fname
485 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
485 for fname, _ranges in logcmdutil._parselinerangeopt(repo, opts)
486 ]
486 ]
487
487
488 ui.pager(b'annotate')
488 ui.pager(b'annotate')
489 rootfm = ui.formatter(b'annotate', opts)
489 rootfm = ui.formatter(b'annotate', opts)
490 if ui.debugflag:
490 if ui.debugflag:
491 shorthex = pycompat.identity
491 shorthex = pycompat.identity
492 else:
492 else:
493
493
494 def shorthex(h):
494 def shorthex(h):
495 return h[:12]
495 return h[:12]
496
496
497 if ui.quiet:
497 if ui.quiet:
498 datefunc = dateutil.shortdate
498 datefunc = dateutil.shortdate
499 else:
499 else:
500 datefunc = dateutil.datestr
500 datefunc = dateutil.datestr
501 if ctx.rev() is None:
501 if ctx.rev() is None:
502 if opts.get(b'changeset'):
502 if opts.get(b'changeset'):
503 # omit "+" suffix which is appended to node hex
503 # omit "+" suffix which is appended to node hex
504 def formatrev(rev):
504 def formatrev(rev):
505 if rev == wdirrev:
505 if rev == wdirrev:
506 return b'%d' % ctx.p1().rev()
506 return b'%d' % ctx.p1().rev()
507 else:
507 else:
508 return b'%d' % rev
508 return b'%d' % rev
509
509
510 else:
510 else:
511
511
512 def formatrev(rev):
512 def formatrev(rev):
513 if rev == wdirrev:
513 if rev == wdirrev:
514 return b'%d+' % ctx.p1().rev()
514 return b'%d+' % ctx.p1().rev()
515 else:
515 else:
516 return b'%d ' % rev
516 return b'%d ' % rev
517
517
518 def formathex(h):
518 def formathex(h):
519 if h == repo.nodeconstants.wdirhex:
519 if h == repo.nodeconstants.wdirhex:
520 return b'%s+' % shorthex(hex(ctx.p1().node()))
520 return b'%s+' % shorthex(hex(ctx.p1().node()))
521 else:
521 else:
522 return b'%s ' % shorthex(h)
522 return b'%s ' % shorthex(h)
523
523
524 else:
524 else:
525 formatrev = b'%d'.__mod__
525 formatrev = b'%d'.__mod__
526 formathex = shorthex
526 formathex = shorthex
527
527
528 opmap = [
528 opmap = [
529 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
529 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
530 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
530 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
531 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
531 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
532 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
532 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
533 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
533 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
534 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
534 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
535 ]
535 ]
536 opnamemap = {
536 opnamemap = {
537 b'rev': b'number',
537 b'rev': b'number',
538 b'node': b'changeset',
538 b'node': b'changeset',
539 b'path': b'file',
539 b'path': b'file',
540 b'lineno': b'line_number',
540 b'lineno': b'line_number',
541 }
541 }
542
542
543 if rootfm.isplain():
543 if rootfm.isplain():
544
544
545 def makefunc(get, fmt):
545 def makefunc(get, fmt):
546 return lambda x: fmt(get(x))
546 return lambda x: fmt(get(x))
547
547
548 else:
548 else:
549
549
550 def makefunc(get, fmt):
550 def makefunc(get, fmt):
551 return get
551 return get
552
552
553 datahint = rootfm.datahint()
553 datahint = rootfm.datahint()
554 funcmap = [
554 funcmap = [
555 (makefunc(get, fmt), sep)
555 (makefunc(get, fmt), sep)
556 for fn, sep, get, fmt in opmap
556 for fn, sep, get, fmt in opmap
557 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
557 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
558 ]
558 ]
559 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
559 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
560 fields = b' '.join(
560 fields = b' '.join(
561 fn
561 fn
562 for fn, sep, get, fmt in opmap
562 for fn, sep, get, fmt in opmap
563 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
563 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
564 )
564 )
565
565
566 def bad(x, y):
566 def bad(x, y):
567 raise error.InputError(b"%s: %s" % (x, y))
567 raise error.InputError(b"%s: %s" % (x, y))
568
568
569 m = scmutil.match(ctx, pats, opts, badfn=bad)
569 m = scmutil.match(ctx, pats, opts, badfn=bad)
570
570
571 follow = not opts.get(b'no_follow')
571 follow = not opts.get(b'no_follow')
572 diffopts = patch.difffeatureopts(
572 diffopts = patch.difffeatureopts(
573 ui, opts, section=b'annotate', whitespace=True
573 ui, opts, section=b'annotate', whitespace=True
574 )
574 )
575 skiprevs = opts.get(b'skip')
575 skiprevs = opts.get(b'skip')
576 if skiprevs:
576 if skiprevs:
577 skiprevs = logcmdutil.revrange(repo, skiprevs)
577 skiprevs = logcmdutil.revrange(repo, skiprevs)
578
578
579 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
579 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
580 for abs in ctx.walk(m):
580 for abs in ctx.walk(m):
581 fctx = ctx[abs]
581 fctx = ctx[abs]
582 rootfm.startitem()
582 rootfm.startitem()
583 rootfm.data(path=abs)
583 rootfm.data(path=abs)
584 if not opts.get(b'text') and fctx.isbinary():
584 if not opts.get(b'text') and fctx.isbinary():
585 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
585 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
586 continue
586 continue
587
587
588 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
588 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
589 lines = fctx.annotate(
589 lines = fctx.annotate(
590 follow=follow, skiprevs=skiprevs, diffopts=diffopts
590 follow=follow, skiprevs=skiprevs, diffopts=diffopts
591 )
591 )
592 if linerange:
592 if linerange:
593 _fname, (line_start, line_end) = list(
593 _fname, (line_start, line_end) = list(
594 logcmdutil._parselinerangeopt(repo, opts)
594 logcmdutil._parselinerangeopt(repo, opts)
595 )[0]
595 )[0]
596 lines = [
596 lines = [
597 line
597 line
598 for no, line in enumerate(lines)
598 for no, line in enumerate(lines)
599 if line_start <= no < line_end
599 if line_start <= no < line_end
600 ]
600 ]
601
601
602 if not lines:
602 if not lines:
603 fm.end()
603 fm.end()
604 continue
604 continue
605 formats = []
605 formats = []
606 pieces = []
606 pieces = []
607
607
608 for f, sep in funcmap:
608 for f, sep in funcmap:
609 l = [f(n) for n in lines]
609 l = [f(n) for n in lines]
610 if fm.isplain():
610 if fm.isplain():
611 sizes = [encoding.colwidth(x) for x in l]
611 sizes = [encoding.colwidth(x) for x in l]
612 ml = max(sizes)
612 ml = max(sizes)
613 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
613 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
614 else:
614 else:
615 formats.append([b'%s'] * len(l))
615 formats.append([b'%s'] * len(l))
616 pieces.append(l)
616 pieces.append(l)
617
617
618 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
618 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
619 fm.startitem()
619 fm.startitem()
620 fm.context(fctx=n.fctx)
620 fm.context(fctx=n.fctx)
621 fm.write(fields, b"".join(f), *p)
621 fm.write(fields, b"".join(f), *p)
622 if n.skip:
622 if n.skip:
623 fmt = b"* %s"
623 fmt = b"* %s"
624 else:
624 else:
625 fmt = b": %s"
625 fmt = b": %s"
626 fm.write(b'line', fmt, n.text)
626 fm.write(b'line', fmt, n.text)
627
627
628 if not lines[-1].text.endswith(b'\n'):
628 if not lines[-1].text.endswith(b'\n'):
629 fm.plain(b'\n')
629 fm.plain(b'\n')
630 fm.end()
630 fm.end()
631
631
632 rootfm.end()
632 rootfm.end()
633
633
634
634
635 @command(
635 @command(
636 b'archive',
636 b'archive',
637 [
637 [
638 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
638 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
639 (
639 (
640 b'p',
640 b'p',
641 b'prefix',
641 b'prefix',
642 b'',
642 b'',
643 _(b'directory prefix for files in archive'),
643 _(b'directory prefix for files in archive'),
644 _(b'PREFIX'),
644 _(b'PREFIX'),
645 ),
645 ),
646 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
646 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
647 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
647 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
648 ]
648 ]
649 + subrepoopts
649 + subrepoopts
650 + walkopts,
650 + walkopts,
651 _(b'[OPTION]... DEST'),
651 _(b'[OPTION]... DEST'),
652 helpcategory=command.CATEGORY_IMPORT_EXPORT,
652 helpcategory=command.CATEGORY_IMPORT_EXPORT,
653 )
653 )
654 def archive(ui, repo, dest, **opts):
654 def archive(ui, repo, dest, **opts):
655 """create an unversioned archive of a repository revision
655 """create an unversioned archive of a repository revision
656
656
657 By default, the revision used is the parent of the working
657 By default, the revision used is the parent of the working
658 directory; use -r/--rev to specify a different revision.
658 directory; use -r/--rev to specify a different revision.
659
659
660 The archive type is automatically detected based on file
660 The archive type is automatically detected based on file
661 extension (to override, use -t/--type).
661 extension (to override, use -t/--type).
662
662
663 .. container:: verbose
663 .. container:: verbose
664
664
665 Examples:
665 Examples:
666
666
667 - create a zip file containing the 1.0 release::
667 - create a zip file containing the 1.0 release::
668
668
669 hg archive -r 1.0 project-1.0.zip
669 hg archive -r 1.0 project-1.0.zip
670
670
671 - create a tarball excluding .hg files::
671 - create a tarball excluding .hg files::
672
672
673 hg archive project.tar.gz -X ".hg*"
673 hg archive project.tar.gz -X ".hg*"
674
674
675 Valid types are:
675 Valid types are:
676
676
677 :``files``: a directory full of files (default)
677 :``files``: a directory full of files (default)
678 :``tar``: tar archive, uncompressed
678 :``tar``: tar archive, uncompressed
679 :``tbz2``: tar archive, compressed using bzip2
679 :``tbz2``: tar archive, compressed using bzip2
680 :``tgz``: tar archive, compressed using gzip
680 :``tgz``: tar archive, compressed using gzip
681 :``txz``: tar archive, compressed using lzma (only in Python 3)
681 :``txz``: tar archive, compressed using lzma (only in Python 3)
682 :``uzip``: zip archive, uncompressed
682 :``uzip``: zip archive, uncompressed
683 :``zip``: zip archive, compressed using deflate
683 :``zip``: zip archive, compressed using deflate
684
684
685 The exact name of the destination archive or directory is given
685 The exact name of the destination archive or directory is given
686 using a format string; see :hg:`help export` for details.
686 using a format string; see :hg:`help export` for details.
687
687
688 Each member added to an archive file has a directory prefix
688 Each member added to an archive file has a directory prefix
689 prepended. Use -p/--prefix to specify a format string for the
689 prepended. Use -p/--prefix to specify a format string for the
690 prefix. The default is the basename of the archive, with suffixes
690 prefix. The default is the basename of the archive, with suffixes
691 removed.
691 removed.
692
692
693 Returns 0 on success.
693 Returns 0 on success.
694 """
694 """
695
695
696 rev = opts.get('rev')
696 rev = opts.get('rev')
697 if rev:
697 if rev:
698 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
698 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
699 ctx = logcmdutil.revsingle(repo, rev)
699 ctx = logcmdutil.revsingle(repo, rev)
700 if not ctx:
700 if not ctx:
701 raise error.InputError(
701 raise error.InputError(
702 _(b'no working directory: please specify a revision')
702 _(b'no working directory: please specify a revision')
703 )
703 )
704 node = ctx.node()
704 node = ctx.node()
705 dest = cmdutil.makefilename(ctx, dest)
705 dest = cmdutil.makefilename(ctx, dest)
706 if os.path.realpath(dest) == repo.root:
706 if os.path.realpath(dest) == repo.root:
707 raise error.InputError(_(b'repository root cannot be destination'))
707 raise error.InputError(_(b'repository root cannot be destination'))
708
708
709 kind = opts.get('type') or archival.guesskind(dest) or b'files'
709 kind = opts.get('type') or archival.guesskind(dest) or b'files'
710 prefix = opts.get('prefix')
710 prefix = opts.get('prefix')
711
711
712 if dest == b'-':
712 if dest == b'-':
713 if kind == b'files':
713 if kind == b'files':
714 raise error.InputError(_(b'cannot archive plain files to stdout'))
714 raise error.InputError(_(b'cannot archive plain files to stdout'))
715 realdest = dest
715 realdest = dest
716 dest = lambda: cmdutil.makefileobj(ctx, realdest)
716 dest = lambda: cmdutil.makefileobj(ctx, realdest)
717 if not prefix:
717 if not prefix:
718 prefix = os.path.basename(repo.root) + b'-%h'
718 prefix = os.path.basename(repo.root) + b'-%h'
719
719
720 prefix = cmdutil.makefilename(ctx, prefix)
720 prefix = cmdutil.makefilename(ctx, prefix)
721 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
721 match = scmutil.match(ctx, [], pycompat.byteskwargs(opts))
722 archival.archive(
722 archival.archive(
723 repo,
723 repo,
724 dest,
724 dest,
725 node,
725 node,
726 kind,
726 kind,
727 not opts.get('no_decode'),
727 not opts.get('no_decode'),
728 match,
728 match,
729 prefix,
729 prefix,
730 subrepos=opts.get('subrepos'),
730 subrepos=opts.get('subrepos'),
731 )
731 )
732
732
733
733
734 @command(
734 @command(
735 b'backout',
735 b'backout',
736 [
736 [
737 (
737 (
738 b'',
738 b'',
739 b'merge',
739 b'merge',
740 None,
740 None,
741 _(b'merge with old dirstate parent after backout'),
741 _(b'merge with old dirstate parent after backout'),
742 ),
742 ),
743 (
743 (
744 b'',
744 b'',
745 b'commit',
745 b'commit',
746 None,
746 None,
747 _(b'commit if no conflicts were encountered (DEPRECATED)'),
747 _(b'commit if no conflicts were encountered (DEPRECATED)'),
748 ),
748 ),
749 (b'', b'no-commit', None, _(b'do not commit')),
749 (b'', b'no-commit', None, _(b'do not commit')),
750 (
750 (
751 b'',
751 b'',
752 b'parent',
752 b'parent',
753 b'',
753 b'',
754 _(b'parent to choose when backing out merge (DEPRECATED)'),
754 _(b'parent to choose when backing out merge (DEPRECATED)'),
755 _(b'REV'),
755 _(b'REV'),
756 ),
756 ),
757 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
757 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
758 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
758 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
759 ]
759 ]
760 + mergetoolopts
760 + mergetoolopts
761 + walkopts
761 + walkopts
762 + commitopts
762 + commitopts
763 + commitopts2,
763 + commitopts2,
764 _(b'[OPTION]... [-r] REV'),
764 _(b'[OPTION]... [-r] REV'),
765 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
765 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
766 )
766 )
767 def backout(ui, repo, node=None, rev=None, **opts):
767 def backout(ui, repo, node=None, rev=None, **opts):
768 """reverse effect of earlier changeset
768 """reverse effect of earlier changeset
769
769
770 Prepare a new changeset with the effect of REV undone in the
770 Prepare a new changeset with the effect of REV undone in the
771 current working directory. If no conflicts were encountered,
771 current working directory. If no conflicts were encountered,
772 it will be committed immediately.
772 it will be committed immediately.
773
773
774 If REV is the parent of the working directory, then this new changeset
774 If REV is the parent of the working directory, then this new changeset
775 is committed automatically (unless --no-commit is specified).
775 is committed automatically (unless --no-commit is specified).
776
776
777 .. note::
777 .. note::
778
778
779 :hg:`backout` cannot be used to fix either an unwanted or
779 :hg:`backout` cannot be used to fix either an unwanted or
780 incorrect merge.
780 incorrect merge.
781
781
782 .. container:: verbose
782 .. container:: verbose
783
783
784 Examples:
784 Examples:
785
785
786 - Reverse the effect of the parent of the working directory.
786 - Reverse the effect of the parent of the working directory.
787 This backout will be committed immediately::
787 This backout will be committed immediately::
788
788
789 hg backout -r .
789 hg backout -r .
790
790
791 - Reverse the effect of previous bad revision 23::
791 - Reverse the effect of previous bad revision 23::
792
792
793 hg backout -r 23
793 hg backout -r 23
794
794
795 - Reverse the effect of previous bad revision 23 and
795 - Reverse the effect of previous bad revision 23 and
796 leave changes uncommitted::
796 leave changes uncommitted::
797
797
798 hg backout -r 23 --no-commit
798 hg backout -r 23 --no-commit
799 hg commit -m "Backout revision 23"
799 hg commit -m "Backout revision 23"
800
800
801 By default, the pending changeset will have one parent,
801 By default, the pending changeset will have one parent,
802 maintaining a linear history. With --merge, the pending
802 maintaining a linear history. With --merge, the pending
803 changeset will instead have two parents: the old parent of the
803 changeset will instead have two parents: the old parent of the
804 working directory and a new child of REV that simply undoes REV.
804 working directory and a new child of REV that simply undoes REV.
805
805
806 Before version 1.7, the behavior without --merge was equivalent
806 Before version 1.7, the behavior without --merge was equivalent
807 to specifying --merge followed by :hg:`update --clean .` to
807 to specifying --merge followed by :hg:`update --clean .` to
808 cancel the merge and leave the child of REV as a head to be
808 cancel the merge and leave the child of REV as a head to be
809 merged separately.
809 merged separately.
810
810
811 See :hg:`help dates` for a list of formats valid for -d/--date.
811 See :hg:`help dates` for a list of formats valid for -d/--date.
812
812
813 See :hg:`help revert` for a way to restore files to the state
813 See :hg:`help revert` for a way to restore files to the state
814 of another revision.
814 of another revision.
815
815
816 Returns 0 on success, 1 if nothing to backout or there are unresolved
816 Returns 0 on success, 1 if nothing to backout or there are unresolved
817 files.
817 files.
818 """
818 """
819 with repo.wlock(), repo.lock():
819 with repo.wlock(), repo.lock():
820 return _dobackout(ui, repo, node, rev, **opts)
820 return _dobackout(ui, repo, node, rev, **opts)
821
821
822
822
823 def _dobackout(ui, repo, node=None, rev=None, **opts):
823 def _dobackout(ui, repo, node=None, rev=None, **opts):
824 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
824 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
825
825
826 if rev and node:
826 if rev and node:
827 raise error.InputError(_(b"please specify just one revision"))
827 raise error.InputError(_(b"please specify just one revision"))
828
828
829 if not rev:
829 if not rev:
830 rev = node
830 rev = node
831
831
832 if not rev:
832 if not rev:
833 raise error.InputError(_(b"please specify a revision to backout"))
833 raise error.InputError(_(b"please specify a revision to backout"))
834
834
835 date = opts.get('date')
835 date = opts.get('date')
836 if date:
836 if date:
837 opts['date'] = dateutil.parsedate(date)
837 opts['date'] = dateutil.parsedate(date)
838
838
839 cmdutil.checkunfinished(repo)
839 cmdutil.checkunfinished(repo)
840 cmdutil.bailifchanged(repo)
840 cmdutil.bailifchanged(repo)
841 ctx = logcmdutil.revsingle(repo, rev)
841 ctx = logcmdutil.revsingle(repo, rev)
842 node = ctx.node()
842 node = ctx.node()
843
843
844 op1, op2 = repo.dirstate.parents()
844 op1, op2 = repo.dirstate.parents()
845 if not repo.changelog.isancestor(node, op1):
845 if not repo.changelog.isancestor(node, op1):
846 raise error.InputError(
846 raise error.InputError(
847 _(b'cannot backout change that is not an ancestor')
847 _(b'cannot backout change that is not an ancestor')
848 )
848 )
849
849
850 p1, p2 = repo.changelog.parents(node)
850 p1, p2 = repo.changelog.parents(node)
851 if p1 == repo.nullid:
851 if p1 == repo.nullid:
852 raise error.InputError(_(b'cannot backout a change with no parents'))
852 raise error.InputError(_(b'cannot backout a change with no parents'))
853 if p2 != repo.nullid:
853 if p2 != repo.nullid:
854 if not opts.get('parent'):
854 if not opts.get('parent'):
855 raise error.InputError(_(b'cannot backout a merge changeset'))
855 raise error.InputError(_(b'cannot backout a merge changeset'))
856 p = repo.lookup(opts['parent'])
856 p = repo.lookup(opts['parent'])
857 if p not in (p1, p2):
857 if p not in (p1, p2):
858 raise error.InputError(
858 raise error.InputError(
859 _(b'%s is not a parent of %s') % (short(p), short(node))
859 _(b'%s is not a parent of %s') % (short(p), short(node))
860 )
860 )
861 parent = p
861 parent = p
862 else:
862 else:
863 if opts.get('parent'):
863 if opts.get('parent'):
864 raise error.InputError(
864 raise error.InputError(
865 _(b'cannot use --parent on non-merge changeset')
865 _(b'cannot use --parent on non-merge changeset')
866 )
866 )
867 parent = p1
867 parent = p1
868
868
869 # the backout should appear on the same branch
869 # the backout should appear on the same branch
870 branch = repo.dirstate.branch()
870 branch = repo.dirstate.branch()
871 bheads = repo.branchheads(branch)
871 bheads = repo.branchheads(branch)
872 rctx = scmutil.revsingle(repo, hex(parent))
872 rctx = scmutil.revsingle(repo, hex(parent))
873 if not opts.get('merge') and op1 != node:
873 if not opts.get('merge') and op1 != node:
874 with repo.transaction(b"backout"):
874 with repo.transaction(b"backout"):
875 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
875 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
876 with ui.configoverride(overrides, b'backout'):
876 with ui.configoverride(overrides, b'backout'):
877 stats = mergemod.back_out(ctx, parent=repo[parent])
877 stats = mergemod.back_out(ctx, parent=repo[parent])
878 repo.setparents(op1, op2)
878 repo.setparents(op1, op2)
879 hg._showstats(repo, stats)
879 hg._showstats(repo, stats)
880 if stats.unresolvedcount:
880 if stats.unresolvedcount:
881 repo.ui.status(
881 repo.ui.status(
882 _(b"use 'hg resolve' to retry unresolved file merges\n")
882 _(b"use 'hg resolve' to retry unresolved file merges\n")
883 )
883 )
884 return 1
884 return 1
885 else:
885 else:
886 hg.clean(repo, node, show_stats=False)
886 hg.clean(repo, node, show_stats=False)
887 repo.dirstate.setbranch(branch, repo.currenttransaction())
887 repo.dirstate.setbranch(branch, repo.currenttransaction())
888 cmdutil.revert(ui, repo, rctx)
888 cmdutil.revert(ui, repo, rctx)
889
889
890 if opts.get('no_commit'):
890 if opts.get('no_commit'):
891 msg = _(b"changeset %s backed out, don't forget to commit.\n")
891 msg = _(b"changeset %s backed out, don't forget to commit.\n")
892 ui.status(msg % short(node))
892 ui.status(msg % short(node))
893 return 0
893 return 0
894
894
895 def commitfunc(ui, repo, message, match, opts):
895 def commitfunc(ui, repo, message, match, opts):
896 editform = b'backout'
896 editform = b'backout'
897 e = cmdutil.getcommiteditor(
897 e = cmdutil.getcommiteditor(
898 editform=editform, **pycompat.strkwargs(opts)
898 editform=editform, **pycompat.strkwargs(opts)
899 )
899 )
900 if not message:
900 if not message:
901 # we don't translate commit messages
901 # we don't translate commit messages
902 message = b"Backed out changeset %s" % short(node)
902 message = b"Backed out changeset %s" % short(node)
903 e = cmdutil.getcommiteditor(edit=True, editform=editform)
903 e = cmdutil.getcommiteditor(edit=True, editform=editform)
904 return repo.commit(
904 return repo.commit(
905 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
905 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
906 )
906 )
907
907
908 # save to detect changes
908 # save to detect changes
909 tip = repo.changelog.tip()
909 tip = repo.changelog.tip()
910
910
911 newnode = cmdutil.commit(
911 newnode = cmdutil.commit(
912 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
912 ui, repo, commitfunc, [], pycompat.byteskwargs(opts)
913 )
913 )
914 if not newnode:
914 if not newnode:
915 ui.status(_(b"nothing changed\n"))
915 ui.status(_(b"nothing changed\n"))
916 return 1
916 return 1
917 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
917 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
918
918
919 def nice(node):
919 def nice(node):
920 return b'%d:%s' % (repo.changelog.rev(node), short(node))
920 return b'%d:%s' % (repo.changelog.rev(node), short(node))
921
921
922 ui.status(
922 ui.status(
923 _(b'changeset %s backs out changeset %s\n')
923 _(b'changeset %s backs out changeset %s\n')
924 % (nice(newnode), nice(node))
924 % (nice(newnode), nice(node))
925 )
925 )
926 if opts.get('merge') and op1 != node:
926 if opts.get('merge') and op1 != node:
927 hg.clean(repo, op1, show_stats=False)
927 hg.clean(repo, op1, show_stats=False)
928 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
928 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
929 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
929 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
930 with ui.configoverride(overrides, b'backout'):
930 with ui.configoverride(overrides, b'backout'):
931 return hg.merge(repo[b'tip'])
931 return hg.merge(repo[b'tip'])
932 return 0
932 return 0
933
933
934
934
935 @command(
935 @command(
936 b'bisect',
936 b'bisect',
937 [
937 [
938 (b'r', b'reset', False, _(b'reset bisect state')),
938 (b'r', b'reset', False, _(b'reset bisect state')),
939 (b'g', b'good', False, _(b'mark changeset good')),
939 (b'g', b'good', False, _(b'mark changeset good')),
940 (b'b', b'bad', False, _(b'mark changeset bad')),
940 (b'b', b'bad', False, _(b'mark changeset bad')),
941 (b's', b'skip', False, _(b'skip testing changeset')),
941 (b's', b'skip', False, _(b'skip testing changeset')),
942 (b'e', b'extend', False, _(b'extend the bisect range')),
942 (b'e', b'extend', False, _(b'extend the bisect range')),
943 (
943 (
944 b'c',
944 b'c',
945 b'command',
945 b'command',
946 b'',
946 b'',
947 _(b'use command to check changeset state'),
947 _(b'use command to check changeset state'),
948 _(b'CMD'),
948 _(b'CMD'),
949 ),
949 ),
950 (b'U', b'noupdate', False, _(b'do not update to target')),
950 (b'U', b'noupdate', False, _(b'do not update to target')),
951 ],
951 ],
952 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
952 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
953 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
953 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
954 )
954 )
955 def bisect(
955 def bisect(
956 ui,
956 ui,
957 repo,
957 repo,
958 positional_1=None,
958 positional_1=None,
959 positional_2=None,
959 positional_2=None,
960 command=None,
960 command=None,
961 reset=None,
961 reset=None,
962 good=None,
962 good=None,
963 bad=None,
963 bad=None,
964 skip=None,
964 skip=None,
965 extend=None,
965 extend=None,
966 noupdate=None,
966 noupdate=None,
967 ):
967 ):
968 """subdivision search of changesets
968 """subdivision search of changesets
969
969
970 This command helps to find changesets which introduce problems. To
970 This command helps to find changesets which introduce problems. To
971 use, mark the earliest changeset you know exhibits the problem as
971 use, mark the earliest changeset you know exhibits the problem as
972 bad, then mark the latest changeset which is free from the problem
972 bad, then mark the latest changeset which is free from the problem
973 as good. Bisect will update your working directory to a revision
973 as good. Bisect will update your working directory to a revision
974 for testing (unless the -U/--noupdate option is specified). Once
974 for testing (unless the -U/--noupdate option is specified). Once
975 you have performed tests, mark the working directory as good or
975 you have performed tests, mark the working directory as good or
976 bad, and bisect will either update to another candidate changeset
976 bad, and bisect will either update to another candidate changeset
977 or announce that it has found the bad revision.
977 or announce that it has found the bad revision.
978
978
979 As a shortcut, you can also use the revision argument to mark a
979 As a shortcut, you can also use the revision argument to mark a
980 revision as good or bad without checking it out first.
980 revision as good or bad without checking it out first.
981
981
982 If you supply a command, it will be used for automatic bisection.
982 If you supply a command, it will be used for automatic bisection.
983 The environment variable HG_NODE will contain the ID of the
983 The environment variable HG_NODE will contain the ID of the
984 changeset being tested. The exit status of the command will be
984 changeset being tested. The exit status of the command will be
985 used to mark revisions as good or bad: status 0 means good, 125
985 used to mark revisions as good or bad: status 0 means good, 125
986 means to skip the revision, 127 (command not found) will abort the
986 means to skip the revision, 127 (command not found) will abort the
987 bisection, and any other non-zero exit status means the revision
987 bisection, and any other non-zero exit status means the revision
988 is bad.
988 is bad.
989
989
990 .. container:: verbose
990 .. container:: verbose
991
991
992 Some examples:
992 Some examples:
993
993
994 - start a bisection with known bad revision 34, and good revision 12::
994 - start a bisection with known bad revision 34, and good revision 12::
995
995
996 hg bisect --bad 34
996 hg bisect --bad 34
997 hg bisect --good 12
997 hg bisect --good 12
998
998
999 - advance the current bisection by marking current revision as good or
999 - advance the current bisection by marking current revision as good or
1000 bad::
1000 bad::
1001
1001
1002 hg bisect --good
1002 hg bisect --good
1003 hg bisect --bad
1003 hg bisect --bad
1004
1004
1005 - mark the current revision, or a known revision, to be skipped (e.g. if
1005 - mark the current revision, or a known revision, to be skipped (e.g. if
1006 that revision is not usable because of another issue)::
1006 that revision is not usable because of another issue)::
1007
1007
1008 hg bisect --skip
1008 hg bisect --skip
1009 hg bisect --skip 23
1009 hg bisect --skip 23
1010
1010
1011 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1011 - skip all revisions that do not touch directories ``foo`` or ``bar``::
1012
1012
1013 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1013 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
1014
1014
1015 - forget the current bisection::
1015 - forget the current bisection::
1016
1016
1017 hg bisect --reset
1017 hg bisect --reset
1018
1018
1019 - use 'make && make tests' to automatically find the first broken
1019 - use 'make && make tests' to automatically find the first broken
1020 revision::
1020 revision::
1021
1021
1022 hg bisect --reset
1022 hg bisect --reset
1023 hg bisect --bad 34
1023 hg bisect --bad 34
1024 hg bisect --good 12
1024 hg bisect --good 12
1025 hg bisect --command "make && make tests"
1025 hg bisect --command "make && make tests"
1026
1026
1027 - see all changesets whose states are already known in the current
1027 - see all changesets whose states are already known in the current
1028 bisection::
1028 bisection::
1029
1029
1030 hg log -r "bisect(pruned)"
1030 hg log -r "bisect(pruned)"
1031
1031
1032 - see the changeset currently being bisected (especially useful
1032 - see the changeset currently being bisected (especially useful
1033 if running with -U/--noupdate)::
1033 if running with -U/--noupdate)::
1034
1034
1035 hg log -r "bisect(current)"
1035 hg log -r "bisect(current)"
1036
1036
1037 - see all changesets that took part in the current bisection::
1037 - see all changesets that took part in the current bisection::
1038
1038
1039 hg log -r "bisect(range)"
1039 hg log -r "bisect(range)"
1040
1040
1041 - you can even get a nice graph::
1041 - you can even get a nice graph::
1042
1042
1043 hg log --graph -r "bisect(range)"
1043 hg log --graph -r "bisect(range)"
1044
1044
1045 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1045 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1046
1046
1047 Returns 0 on success.
1047 Returns 0 on success.
1048 """
1048 """
1049 rev = []
1049 rev = []
1050 # backward compatibility
1050 # backward compatibility
1051 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1051 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1052 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1052 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1053 cmd = positional_1
1053 cmd = positional_1
1054 rev.append(positional_2)
1054 rev.append(positional_2)
1055 if cmd == b"good":
1055 if cmd == b"good":
1056 good = True
1056 good = True
1057 elif cmd == b"bad":
1057 elif cmd == b"bad":
1058 bad = True
1058 bad = True
1059 else:
1059 else:
1060 reset = True
1060 reset = True
1061 elif positional_2:
1061 elif positional_2:
1062 raise error.InputError(_(b'incompatible arguments'))
1062 raise error.InputError(_(b'incompatible arguments'))
1063 elif positional_1 is not None:
1063 elif positional_1 is not None:
1064 rev.append(positional_1)
1064 rev.append(positional_1)
1065
1065
1066 incompatibles = {
1066 incompatibles = {
1067 b'--bad': bad,
1067 b'--bad': bad,
1068 b'--command': bool(command),
1068 b'--command': bool(command),
1069 b'--extend': extend,
1069 b'--extend': extend,
1070 b'--good': good,
1070 b'--good': good,
1071 b'--reset': reset,
1071 b'--reset': reset,
1072 b'--skip': skip,
1072 b'--skip': skip,
1073 }
1073 }
1074
1074
1075 enabled = [x for x in incompatibles if incompatibles[x]]
1075 enabled = [x for x in incompatibles if incompatibles[x]]
1076
1076
1077 if len(enabled) > 1:
1077 if len(enabled) > 1:
1078 raise error.InputError(
1078 raise error.InputError(
1079 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1079 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1080 )
1080 )
1081
1081
1082 if reset:
1082 if reset:
1083 hbisect.resetstate(repo)
1083 hbisect.resetstate(repo)
1084 return
1084 return
1085
1085
1086 state = hbisect.load_state(repo)
1086 state = hbisect.load_state(repo)
1087
1087
1088 if rev:
1088 if rev:
1089 revs = logcmdutil.revrange(repo, rev)
1089 revs = logcmdutil.revrange(repo, rev)
1090 goodnodes = state[b'good']
1090 goodnodes = state[b'good']
1091 badnodes = state[b'bad']
1091 badnodes = state[b'bad']
1092 if goodnodes and badnodes:
1092 if goodnodes and badnodes:
1093 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1093 candidates = repo.revs(b'(%ln)::(%ln)', goodnodes, badnodes)
1094 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1094 candidates += repo.revs(b'(%ln)::(%ln)', badnodes, goodnodes)
1095 revs = candidates & revs
1095 revs = candidates & revs
1096 nodes = [repo.changelog.node(i) for i in revs]
1096 nodes = [repo.changelog.node(i) for i in revs]
1097 else:
1097 else:
1098 nodes = [repo.lookup(b'.')]
1098 nodes = [repo.lookup(b'.')]
1099
1099
1100 # update state
1100 # update state
1101 if good or bad or skip:
1101 if good or bad or skip:
1102 if good:
1102 if good:
1103 state[b'good'] += nodes
1103 state[b'good'] += nodes
1104 elif bad:
1104 elif bad:
1105 state[b'bad'] += nodes
1105 state[b'bad'] += nodes
1106 elif skip:
1106 elif skip:
1107 state[b'skip'] += nodes
1107 state[b'skip'] += nodes
1108 hbisect.save_state(repo, state)
1108 hbisect.save_state(repo, state)
1109 if not (state[b'good'] and state[b'bad']):
1109 if not (state[b'good'] and state[b'bad']):
1110 return
1110 return
1111
1111
1112 def mayupdate(repo, node, show_stats=True):
1112 def mayupdate(repo, node, show_stats=True):
1113 """common used update sequence"""
1113 """common used update sequence"""
1114 if noupdate:
1114 if noupdate:
1115 return
1115 return
1116 cmdutil.checkunfinished(repo)
1116 cmdutil.checkunfinished(repo)
1117 cmdutil.bailifchanged(repo)
1117 cmdutil.bailifchanged(repo)
1118 return hg.clean(repo, node, show_stats=show_stats)
1118 return hg.clean(repo, node, show_stats=show_stats)
1119
1119
1120 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1120 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1121
1121
1122 if command:
1122 if command:
1123 changesets = 1
1123 changesets = 1
1124 if noupdate:
1124 if noupdate:
1125 try:
1125 try:
1126 node = state[b'current'][0]
1126 node = state[b'current'][0]
1127 except LookupError:
1127 except LookupError:
1128 raise error.StateError(
1128 raise error.StateError(
1129 _(
1129 _(
1130 b'current bisect revision is unknown - '
1130 b'current bisect revision is unknown - '
1131 b'start a new bisect to fix'
1131 b'start a new bisect to fix'
1132 )
1132 )
1133 )
1133 )
1134 else:
1134 else:
1135 node, p2 = repo.dirstate.parents()
1135 node, p2 = repo.dirstate.parents()
1136 if p2 != repo.nullid:
1136 if p2 != repo.nullid:
1137 raise error.StateError(_(b'current bisect revision is a merge'))
1137 raise error.StateError(_(b'current bisect revision is a merge'))
1138 if rev:
1138 if rev:
1139 if not nodes:
1139 if not nodes:
1140 raise error.InputError(_(b'empty revision set'))
1140 raise error.InputError(_(b'empty revision set'))
1141 node = repo[nodes[-1]].node()
1141 node = repo[nodes[-1]].node()
1142 with hbisect.restore_state(repo, state, node):
1142 with hbisect.restore_state(repo, state, node):
1143 while changesets:
1143 while changesets:
1144 # update state
1144 # update state
1145 state[b'current'] = [node]
1145 state[b'current'] = [node]
1146 hbisect.save_state(repo, state)
1146 hbisect.save_state(repo, state)
1147 status = ui.system(
1147 status = ui.system(
1148 command,
1148 command,
1149 environ={b'HG_NODE': hex(node)},
1149 environ={b'HG_NODE': hex(node)},
1150 blockedtag=b'bisect_check',
1150 blockedtag=b'bisect_check',
1151 )
1151 )
1152 if status == 125:
1152 if status == 125:
1153 transition = b"skip"
1153 transition = b"skip"
1154 elif status == 0:
1154 elif status == 0:
1155 transition = b"good"
1155 transition = b"good"
1156 # status < 0 means process was killed
1156 # status < 0 means process was killed
1157 elif status == 127:
1157 elif status == 127:
1158 raise error.Abort(_(b"failed to execute %s") % command)
1158 raise error.Abort(_(b"failed to execute %s") % command)
1159 elif status < 0:
1159 elif status < 0:
1160 raise error.Abort(_(b"%s killed") % command)
1160 raise error.Abort(_(b"%s killed") % command)
1161 else:
1161 else:
1162 transition = b"bad"
1162 transition = b"bad"
1163 state[transition].append(node)
1163 state[transition].append(node)
1164 ctx = repo[node]
1164 ctx = repo[node]
1165 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1165 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1166 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1166 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1167 hbisect.checkstate(state)
1167 hbisect.checkstate(state)
1168 # bisect
1168 # bisect
1169 nodes, changesets, bgood = hbisect.bisect(repo, state)
1169 nodes, changesets, bgood = hbisect.bisect(repo, state)
1170 # update to next check
1170 # update to next check
1171 node = nodes[0]
1171 node = nodes[0]
1172 mayupdate(repo, node, show_stats=False)
1172 mayupdate(repo, node, show_stats=False)
1173 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1173 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1174 return
1174 return
1175
1175
1176 hbisect.checkstate(state)
1176 hbisect.checkstate(state)
1177
1177
1178 # actually bisect
1178 # actually bisect
1179 nodes, changesets, good = hbisect.bisect(repo, state)
1179 nodes, changesets, good = hbisect.bisect(repo, state)
1180 if extend:
1180 if extend:
1181 if not changesets:
1181 if not changesets:
1182 extendctx = hbisect.extendrange(repo, state, nodes, good)
1182 extendctx = hbisect.extendrange(repo, state, nodes, good)
1183 if extendctx is not None:
1183 if extendctx is not None:
1184 ui.write(
1184 ui.write(
1185 _(b"Extending search to changeset %s\n")
1185 _(b"Extending search to changeset %s\n")
1186 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1186 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1187 )
1187 )
1188 state[b'current'] = [extendctx.node()]
1188 state[b'current'] = [extendctx.node()]
1189 hbisect.save_state(repo, state)
1189 hbisect.save_state(repo, state)
1190 return mayupdate(repo, extendctx.node())
1190 return mayupdate(repo, extendctx.node())
1191 raise error.StateError(_(b"nothing to extend"))
1191 raise error.StateError(_(b"nothing to extend"))
1192
1192
1193 if changesets == 0:
1193 if changesets == 0:
1194 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1194 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1195 else:
1195 else:
1196 assert len(nodes) == 1 # only a single node can be tested next
1196 assert len(nodes) == 1 # only a single node can be tested next
1197 node = nodes[0]
1197 node = nodes[0]
1198 # compute the approximate number of remaining tests
1198 # compute the approximate number of remaining tests
1199 tests, size = 0, 2
1199 tests, size = 0, 2
1200 while size <= changesets:
1200 while size <= changesets:
1201 tests, size = tests + 1, size * 2
1201 tests, size = tests + 1, size * 2
1202 rev = repo.changelog.rev(node)
1202 rev = repo.changelog.rev(node)
1203 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1203 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1204 ui.write(
1204 ui.write(
1205 _(
1205 _(
1206 b"Testing changeset %s "
1206 b"Testing changeset %s "
1207 b"(%d changesets remaining, ~%d tests)\n"
1207 b"(%d changesets remaining, ~%d tests)\n"
1208 )
1208 )
1209 % (summary, changesets, tests)
1209 % (summary, changesets, tests)
1210 )
1210 )
1211 state[b'current'] = [node]
1211 state[b'current'] = [node]
1212 hbisect.save_state(repo, state)
1212 hbisect.save_state(repo, state)
1213 return mayupdate(repo, node)
1213 return mayupdate(repo, node)
1214
1214
1215
1215
1216 @command(
1216 @command(
1217 b'bookmarks|bookmark',
1217 b'bookmarks|bookmark',
1218 [
1218 [
1219 (b'f', b'force', False, _(b'force')),
1219 (b'f', b'force', False, _(b'force')),
1220 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1220 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1221 (b'd', b'delete', False, _(b'delete a given bookmark')),
1221 (b'd', b'delete', False, _(b'delete a given bookmark')),
1222 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1222 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1223 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1223 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1224 (b'l', b'list', False, _(b'list existing bookmarks')),
1224 (b'l', b'list', False, _(b'list existing bookmarks')),
1225 ]
1225 ]
1226 + formatteropts,
1226 + formatteropts,
1227 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1227 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1228 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1228 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1229 )
1229 )
1230 def bookmark(ui, repo, *names, **opts):
1230 def bookmark(ui, repo, *names, **opts):
1231 """create a new bookmark or list existing bookmarks
1231 """create a new bookmark or list existing bookmarks
1232
1232
1233 Bookmarks are labels on changesets to help track lines of development.
1233 Bookmarks are labels on changesets to help track lines of development.
1234 Bookmarks are unversioned and can be moved, renamed and deleted.
1234 Bookmarks are unversioned and can be moved, renamed and deleted.
1235 Deleting or moving a bookmark has no effect on the associated changesets.
1235 Deleting or moving a bookmark has no effect on the associated changesets.
1236
1236
1237 Creating or updating to a bookmark causes it to be marked as 'active'.
1237 Creating or updating to a bookmark causes it to be marked as 'active'.
1238 The active bookmark is indicated with a '*'.
1238 The active bookmark is indicated with a '*'.
1239 When a commit is made, the active bookmark will advance to the new commit.
1239 When a commit is made, the active bookmark will advance to the new commit.
1240 A plain :hg:`update` will also advance an active bookmark, if possible.
1240 A plain :hg:`update` will also advance an active bookmark, if possible.
1241 Updating away from a bookmark will cause it to be deactivated.
1241 Updating away from a bookmark will cause it to be deactivated.
1242
1242
1243 Bookmarks can be pushed and pulled between repositories (see
1243 Bookmarks can be pushed and pulled between repositories (see
1244 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1244 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1245 diverged, a new 'divergent bookmark' of the form 'name@path' will
1245 diverged, a new 'divergent bookmark' of the form 'name@path' will
1246 be created. Using :hg:`merge` will resolve the divergence.
1246 be created. Using :hg:`merge` will resolve the divergence.
1247
1247
1248 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1248 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1249 the active bookmark's name.
1249 the active bookmark's name.
1250
1250
1251 A bookmark named '@' has the special property that :hg:`clone` will
1251 A bookmark named '@' has the special property that :hg:`clone` will
1252 check it out by default if it exists.
1252 check it out by default if it exists.
1253
1253
1254 .. container:: verbose
1254 .. container:: verbose
1255
1255
1256 Template:
1256 Template:
1257
1257
1258 The following keywords are supported in addition to the common template
1258 The following keywords are supported in addition to the common template
1259 keywords and functions such as ``{bookmark}``. See also
1259 keywords and functions such as ``{bookmark}``. See also
1260 :hg:`help templates`.
1260 :hg:`help templates`.
1261
1261
1262 :active: Boolean. True if the bookmark is active.
1262 :active: Boolean. True if the bookmark is active.
1263
1263
1264 Examples:
1264 Examples:
1265
1265
1266 - create an active bookmark for a new line of development::
1266 - create an active bookmark for a new line of development::
1267
1267
1268 hg book new-feature
1268 hg book new-feature
1269
1269
1270 - create an inactive bookmark as a place marker::
1270 - create an inactive bookmark as a place marker::
1271
1271
1272 hg book -i reviewed
1272 hg book -i reviewed
1273
1273
1274 - create an inactive bookmark on another changeset::
1274 - create an inactive bookmark on another changeset::
1275
1275
1276 hg book -r .^ tested
1276 hg book -r .^ tested
1277
1277
1278 - rename bookmark turkey to dinner::
1278 - rename bookmark turkey to dinner::
1279
1279
1280 hg book -m turkey dinner
1280 hg book -m turkey dinner
1281
1281
1282 - move the '@' bookmark from another branch::
1282 - move the '@' bookmark from another branch::
1283
1283
1284 hg book -f @
1284 hg book -f @
1285
1285
1286 - print only the active bookmark name::
1286 - print only the active bookmark name::
1287
1287
1288 hg book -ql .
1288 hg book -ql .
1289 """
1289 """
1290 force = opts.get('force')
1290 force = opts.get('force')
1291 rev = opts.get('rev')
1291 rev = opts.get('rev')
1292 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1292 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1293
1293
1294 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1294 action = cmdutil.check_at_most_one_arg(opts, 'delete', 'rename', 'list')
1295 if action:
1295 if action:
1296 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1296 cmdutil.check_incompatible_arguments(opts, action, ['rev'])
1297 elif names or rev:
1297 elif names or rev:
1298 action = 'add'
1298 action = 'add'
1299 elif inactive:
1299 elif inactive:
1300 action = 'inactive' # meaning deactivate
1300 action = 'inactive' # meaning deactivate
1301 else:
1301 else:
1302 action = 'list'
1302 action = 'list'
1303
1303
1304 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1304 cmdutil.check_incompatible_arguments(opts, 'inactive', ['delete', 'list'])
1305 if not names and action in {'add', 'delete'}:
1305 if not names and action in {'add', 'delete'}:
1306 raise error.InputError(_(b"bookmark name required"))
1306 raise error.InputError(_(b"bookmark name required"))
1307
1307
1308 if action in {'add', 'delete', 'rename', 'inactive'}:
1308 if action in {'add', 'delete', 'rename', 'inactive'}:
1309 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1309 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1310 if action == 'delete':
1310 if action == 'delete':
1311 names = pycompat.maplist(repo._bookmarks.expandname, names)
1311 names = pycompat.maplist(repo._bookmarks.expandname, names)
1312 bookmarks.delete(repo, tr, names)
1312 bookmarks.delete(repo, tr, names)
1313 elif action == 'rename':
1313 elif action == 'rename':
1314 if not names:
1314 if not names:
1315 raise error.InputError(_(b"new bookmark name required"))
1315 raise error.InputError(_(b"new bookmark name required"))
1316 elif len(names) > 1:
1316 elif len(names) > 1:
1317 raise error.InputError(
1317 raise error.InputError(
1318 _(b"only one new bookmark name allowed")
1318 _(b"only one new bookmark name allowed")
1319 )
1319 )
1320 oldname = repo._bookmarks.expandname(opts['rename'])
1320 oldname = repo._bookmarks.expandname(opts['rename'])
1321 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1321 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1322 elif action == 'add':
1322 elif action == 'add':
1323 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1323 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1324 elif action == 'inactive':
1324 elif action == 'inactive':
1325 if len(repo._bookmarks) == 0:
1325 if len(repo._bookmarks) == 0:
1326 ui.status(_(b"no bookmarks set\n"))
1326 ui.status(_(b"no bookmarks set\n"))
1327 elif not repo._activebookmark:
1327 elif not repo._activebookmark:
1328 ui.status(_(b"no active bookmark\n"))
1328 ui.status(_(b"no active bookmark\n"))
1329 else:
1329 else:
1330 bookmarks.deactivate(repo)
1330 bookmarks.deactivate(repo)
1331 elif action == 'list':
1331 elif action == 'list':
1332 names = pycompat.maplist(repo._bookmarks.expandname, names)
1332 names = pycompat.maplist(repo._bookmarks.expandname, names)
1333 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1333 with ui.formatter(b'bookmarks', pycompat.byteskwargs(opts)) as fm:
1334 bookmarks.printbookmarks(ui, repo, fm, names)
1334 bookmarks.printbookmarks(ui, repo, fm, names)
1335 else:
1335 else:
1336 raise error.ProgrammingError(
1336 raise error.ProgrammingError(
1337 b'invalid action: %s' % pycompat.sysbytes(action)
1337 b'invalid action: %s' % pycompat.sysbytes(action)
1338 )
1338 )
1339
1339
1340
1340
1341 @command(
1341 @command(
1342 b'branch',
1342 b'branch',
1343 [
1343 [
1344 (
1344 (
1345 b'f',
1345 b'f',
1346 b'force',
1346 b'force',
1347 None,
1347 None,
1348 _(b'set branch name even if it shadows an existing branch'),
1348 _(b'set branch name even if it shadows an existing branch'),
1349 ),
1349 ),
1350 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1350 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1351 (
1351 (
1352 b'r',
1352 b'r',
1353 b'rev',
1353 b'rev',
1354 [],
1354 [],
1355 _(b'change branches of the given revs (EXPERIMENTAL)'),
1355 _(b'change branches of the given revs (EXPERIMENTAL)'),
1356 ),
1356 ),
1357 ],
1357 ],
1358 _(b'[-fC] [NAME]'),
1358 _(b'[-fC] [NAME]'),
1359 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1359 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1360 )
1360 )
1361 def branch(ui, repo, label=None, **opts):
1361 def branch(ui, repo, label=None, **opts):
1362 """set or show the current branch name
1362 """set or show the current branch name
1363
1363
1364 .. note::
1364 .. note::
1365
1365
1366 Branch names are permanent and global. Use :hg:`bookmark` to create a
1366 Branch names are permanent and global. Use :hg:`bookmark` to create a
1367 light-weight bookmark instead. See :hg:`help glossary` for more
1367 light-weight bookmark instead. See :hg:`help glossary` for more
1368 information about named branches and bookmarks.
1368 information about named branches and bookmarks.
1369
1369
1370 With no argument, show the current branch name. With one argument,
1370 With no argument, show the current branch name. With one argument,
1371 set the working directory branch name (the branch will not exist
1371 set the working directory branch name (the branch will not exist
1372 in the repository until the next commit). Standard practice
1372 in the repository until the next commit). Standard practice
1373 recommends that primary development take place on the 'default'
1373 recommends that primary development take place on the 'default'
1374 branch.
1374 branch.
1375
1375
1376 Unless -f/--force is specified, branch will not let you set a
1376 Unless -f/--force is specified, branch will not let you set a
1377 branch name that already exists.
1377 branch name that already exists.
1378
1378
1379 Use -C/--clean to reset the working directory branch to that of
1379 Use -C/--clean to reset the working directory branch to that of
1380 the parent of the working directory, negating a previous branch
1380 the parent of the working directory, negating a previous branch
1381 change.
1381 change.
1382
1382
1383 Use the command :hg:`update` to switch to an existing branch. Use
1383 Use the command :hg:`update` to switch to an existing branch. Use
1384 :hg:`commit --close-branch` to mark this branch head as closed.
1384 :hg:`commit --close-branch` to mark this branch head as closed.
1385 When all heads of a branch are closed, the branch will be
1385 When all heads of a branch are closed, the branch will be
1386 considered closed.
1386 considered closed.
1387
1387
1388 Returns 0 on success.
1388 Returns 0 on success.
1389 """
1389 """
1390 revs = opts.get('rev')
1390 revs = opts.get('rev')
1391 if label:
1391 if label:
1392 label = label.strip()
1392 label = label.strip()
1393
1393
1394 if not opts.get('clean') and not label:
1394 if not opts.get('clean') and not label:
1395 if revs:
1395 if revs:
1396 raise error.InputError(
1396 raise error.InputError(
1397 _(b"no branch name specified for the revisions")
1397 _(b"no branch name specified for the revisions")
1398 )
1398 )
1399 ui.write(b"%s\n" % repo.dirstate.branch())
1399 ui.write(b"%s\n" % repo.dirstate.branch())
1400 return
1400 return
1401
1401
1402 with repo.wlock():
1402 with repo.wlock():
1403 if opts.get('clean'):
1403 if opts.get('clean'):
1404 label = repo[b'.'].branch()
1404 label = repo[b'.'].branch()
1405 repo.dirstate.setbranch(label, repo.currenttransaction())
1405 repo.dirstate.setbranch(label, repo.currenttransaction())
1406 ui.status(_(b'reset working directory to branch %s\n') % label)
1406 ui.status(_(b'reset working directory to branch %s\n') % label)
1407 elif label:
1407 elif label:
1408 scmutil.checknewlabel(repo, label, b'branch')
1408 scmutil.checknewlabel(repo, label, b'branch')
1409 if revs:
1409 if revs:
1410 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1410 return cmdutil.changebranch(ui, repo, revs, label, **opts)
1411
1411
1412 if not opts.get('force') and label in repo.branchmap():
1412 if not opts.get('force') and label in repo.branchmap():
1413 if label not in [p.branch() for p in repo[None].parents()]:
1413 if label not in [p.branch() for p in repo[None].parents()]:
1414 raise error.InputError(
1414 raise error.InputError(
1415 _(b'a branch of the same name already exists'),
1415 _(b'a branch of the same name already exists'),
1416 # i18n: "it" refers to an existing branch
1416 # i18n: "it" refers to an existing branch
1417 hint=_(b"use 'hg update' to switch to it"),
1417 hint=_(b"use 'hg update' to switch to it"),
1418 )
1418 )
1419
1419
1420 repo.dirstate.setbranch(label, repo.currenttransaction())
1420 repo.dirstate.setbranch(label, repo.currenttransaction())
1421 ui.status(_(b'marked working directory as branch %s\n') % label)
1421 ui.status(_(b'marked working directory as branch %s\n') % label)
1422
1422
1423 # find any open named branches aside from default
1423 # find any open named branches aside from default
1424 for n, h, t, c in repo.branchmap().iterbranches():
1424 for n, h, t, c in repo.branchmap().iterbranches():
1425 if n != b"default" and not c:
1425 if n != b"default" and not c:
1426 return 0
1426 return 0
1427 ui.status(
1427 ui.status(
1428 _(
1428 _(
1429 b'(branches are permanent and global, '
1429 b'(branches are permanent and global, '
1430 b'did you want a bookmark?)\n'
1430 b'did you want a bookmark?)\n'
1431 )
1431 )
1432 )
1432 )
1433
1433
1434
1434
1435 @command(
1435 @command(
1436 b'branches',
1436 b'branches',
1437 [
1437 [
1438 (
1438 (
1439 b'a',
1439 b'a',
1440 b'active',
1440 b'active',
1441 False,
1441 False,
1442 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1442 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1443 ),
1443 ),
1444 (b'c', b'closed', False, _(b'show normal and closed branches')),
1444 (b'c', b'closed', False, _(b'show normal and closed branches')),
1445 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1445 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1446 ]
1446 ]
1447 + formatteropts,
1447 + formatteropts,
1448 _(b'[-c]'),
1448 _(b'[-c]'),
1449 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1449 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1450 intents={INTENT_READONLY},
1450 intents={INTENT_READONLY},
1451 )
1451 )
1452 def branches(ui, repo, active=False, closed=False, **opts):
1452 def branches(ui, repo, active=False, closed=False, **opts):
1453 """list repository named branches
1453 """list repository named branches
1454
1454
1455 List the repository's named branches, indicating which ones are
1455 List the repository's named branches, indicating which ones are
1456 inactive. If -c/--closed is specified, also list branches which have
1456 inactive. If -c/--closed is specified, also list branches which have
1457 been marked closed (see :hg:`commit --close-branch`).
1457 been marked closed (see :hg:`commit --close-branch`).
1458
1458
1459 Use the command :hg:`update` to switch to an existing branch.
1459 Use the command :hg:`update` to switch to an existing branch.
1460
1460
1461 .. container:: verbose
1461 .. container:: verbose
1462
1462
1463 Template:
1463 Template:
1464
1464
1465 The following keywords are supported in addition to the common template
1465 The following keywords are supported in addition to the common template
1466 keywords and functions such as ``{branch}``. See also
1466 keywords and functions such as ``{branch}``. See also
1467 :hg:`help templates`.
1467 :hg:`help templates`.
1468
1468
1469 :active: Boolean. True if the branch is active.
1469 :active: Boolean. True if the branch is active.
1470 :closed: Boolean. True if the branch is closed.
1470 :closed: Boolean. True if the branch is closed.
1471 :current: Boolean. True if it is the current branch.
1471 :current: Boolean. True if it is the current branch.
1472
1472
1473 Returns 0.
1473 Returns 0.
1474 """
1474 """
1475
1475
1476 revs = opts.get('rev')
1476 revs = opts.get('rev')
1477 selectedbranches = None
1477 selectedbranches = None
1478 if revs:
1478 if revs:
1479 revs = logcmdutil.revrange(repo, revs)
1479 revs = logcmdutil.revrange(repo, revs)
1480 getbi = repo.revbranchcache().branchinfo
1480 getbi = repo.revbranchcache().branchinfo
1481 selectedbranches = {getbi(r)[0] for r in revs}
1481 selectedbranches = {getbi(r)[0] for r in revs}
1482
1482
1483 ui.pager(b'branches')
1483 ui.pager(b'branches')
1484 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1484 fm = ui.formatter(b'branches', pycompat.byteskwargs(opts))
1485 hexfunc = fm.hexfunc
1485 hexfunc = fm.hexfunc
1486
1486
1487 allheads = set(repo.heads())
1487 allheads = set(repo.heads())
1488 branches = []
1488 branches = []
1489 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1489 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1490 if selectedbranches is not None and tag not in selectedbranches:
1490 if selectedbranches is not None and tag not in selectedbranches:
1491 continue
1491 continue
1492 isactive = False
1492 isactive = False
1493 if not isclosed:
1493 if not isclosed:
1494 openheads = set(repo.branchmap().iteropen(heads))
1494 openheads = set(repo.branchmap().iteropen(heads))
1495 isactive = bool(openheads & allheads)
1495 isactive = bool(openheads & allheads)
1496 branches.append((tag, repo[tip], isactive, not isclosed))
1496 branches.append((tag, repo[tip], isactive, not isclosed))
1497 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1497 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1498
1498
1499 for tag, ctx, isactive, isopen in branches:
1499 for tag, ctx, isactive, isopen in branches:
1500 if active and not isactive:
1500 if active and not isactive:
1501 continue
1501 continue
1502 if isactive:
1502 if isactive:
1503 label = b'branches.active'
1503 label = b'branches.active'
1504 notice = b''
1504 notice = b''
1505 elif not isopen:
1505 elif not isopen:
1506 if not closed:
1506 if not closed:
1507 continue
1507 continue
1508 label = b'branches.closed'
1508 label = b'branches.closed'
1509 notice = _(b' (closed)')
1509 notice = _(b' (closed)')
1510 else:
1510 else:
1511 label = b'branches.inactive'
1511 label = b'branches.inactive'
1512 notice = _(b' (inactive)')
1512 notice = _(b' (inactive)')
1513 current = tag == repo.dirstate.branch()
1513 current = tag == repo.dirstate.branch()
1514 if current:
1514 if current:
1515 label = b'branches.current'
1515 label = b'branches.current'
1516
1516
1517 fm.startitem()
1517 fm.startitem()
1518 fm.write(b'branch', b'%s', tag, label=label)
1518 fm.write(b'branch', b'%s', tag, label=label)
1519 rev = ctx.rev()
1519 rev = ctx.rev()
1520 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1520 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1521 fmt = b' ' * padsize + b' %d:%s'
1521 fmt = b' ' * padsize + b' %d:%s'
1522 fm.condwrite(
1522 fm.condwrite(
1523 not ui.quiet,
1523 not ui.quiet,
1524 b'rev node',
1524 b'rev node',
1525 fmt,
1525 fmt,
1526 rev,
1526 rev,
1527 hexfunc(ctx.node()),
1527 hexfunc(ctx.node()),
1528 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1528 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1529 )
1529 )
1530 fm.context(ctx=ctx)
1530 fm.context(ctx=ctx)
1531 fm.data(active=isactive, closed=not isopen, current=current)
1531 fm.data(active=isactive, closed=not isopen, current=current)
1532 if not ui.quiet:
1532 if not ui.quiet:
1533 fm.plain(notice)
1533 fm.plain(notice)
1534 fm.plain(b'\n')
1534 fm.plain(b'\n')
1535 fm.end()
1535 fm.end()
1536
1536
1537
1537
1538 @command(
1538 @command(
1539 b'bundle',
1539 b'bundle',
1540 [
1540 [
1541 (
1541 (
1542 b'',
1542 b'',
1543 b'exact',
1543 b'exact',
1544 None,
1544 None,
1545 _(b'compute the base from the revision specified'),
1545 _(b'compute the base from the revision specified'),
1546 ),
1546 ),
1547 (
1547 (
1548 b'f',
1548 b'f',
1549 b'force',
1549 b'force',
1550 None,
1550 None,
1551 _(b'run even when the destination is unrelated'),
1551 _(b'run even when the destination is unrelated'),
1552 ),
1552 ),
1553 (
1553 (
1554 b'r',
1554 b'r',
1555 b'rev',
1555 b'rev',
1556 [],
1556 [],
1557 _(b'a changeset intended to be added to the destination'),
1557 _(b'a changeset intended to be added to the destination'),
1558 _(b'REV'),
1558 _(b'REV'),
1559 ),
1559 ),
1560 (
1560 (
1561 b'b',
1561 b'b',
1562 b'branch',
1562 b'branch',
1563 [],
1563 [],
1564 _(b'a specific branch you would like to bundle'),
1564 _(b'a specific branch you would like to bundle'),
1565 _(b'BRANCH'),
1565 _(b'BRANCH'),
1566 ),
1566 ),
1567 (
1567 (
1568 b'',
1568 b'',
1569 b'base',
1569 b'base',
1570 [],
1570 [],
1571 _(b'a base changeset assumed to be available at the destination'),
1571 _(b'a base changeset assumed to be available at the destination'),
1572 _(b'REV'),
1572 _(b'REV'),
1573 ),
1573 ),
1574 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1574 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1575 (
1575 (
1576 b't',
1576 b't',
1577 b'type',
1577 b'type',
1578 b'bzip2',
1578 b'bzip2',
1579 _(b'bundle compression type to use'),
1579 _(b'bundle compression type to use'),
1580 _(b'TYPE'),
1580 _(b'TYPE'),
1581 ),
1581 ),
1582 ]
1582 ]
1583 + remoteopts,
1583 + remoteopts,
1584 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1584 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1585 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1585 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1586 )
1586 )
1587 def bundle(ui, repo, fname, *dests, **opts):
1587 def bundle(ui, repo, fname, *dests, **opts):
1588 """create a bundle file
1588 """create a bundle file
1589
1589
1590 Generate a bundle file containing data to be transferred to another
1590 Generate a bundle file containing data to be transferred to another
1591 repository.
1591 repository.
1592
1592
1593 To create a bundle containing all changesets, use -a/--all
1593 To create a bundle containing all changesets, use -a/--all
1594 (or --base null). Otherwise, hg assumes the destination will have
1594 (or --base null). Otherwise, hg assumes the destination will have
1595 all the nodes you specify with --base parameters. Otherwise, hg
1595 all the nodes you specify with --base parameters. Otherwise, hg
1596 will assume the repository has all the nodes in destination, or
1596 will assume the repository has all the nodes in destination, or
1597 default-push/default if no destination is specified, where destination
1597 default-push/default if no destination is specified, where destination
1598 is the repositories you provide through DEST option.
1598 is the repositories you provide through DEST option.
1599
1599
1600 You can change bundle format with the -t/--type option. See
1600 You can change bundle format with the -t/--type option. See
1601 :hg:`help bundlespec` for documentation on this format. By default,
1601 :hg:`help bundlespec` for documentation on this format. By default,
1602 the most appropriate format is used and compression defaults to
1602 the most appropriate format is used and compression defaults to
1603 bzip2.
1603 bzip2.
1604
1604
1605 The bundle file can then be transferred using conventional means
1605 The bundle file can then be transferred using conventional means
1606 and applied to another repository with the unbundle or pull
1606 and applied to another repository with the unbundle or pull
1607 command. This is useful when direct push and pull are not
1607 command. This is useful when direct push and pull are not
1608 available or when exporting an entire repository is undesirable.
1608 available or when exporting an entire repository is undesirable.
1609
1609
1610 Applying bundles preserves all changeset contents including
1610 Applying bundles preserves all changeset contents including
1611 permissions, copy/rename information, and revision history.
1611 permissions, copy/rename information, and revision history.
1612
1612
1613 Returns 0 on success, 1 if no changes found.
1613 Returns 0 on success, 1 if no changes found.
1614 """
1614 """
1615
1615
1616 revs = None
1616 revs = None
1617 if 'rev' in opts:
1617 if 'rev' in opts:
1618 revstrings = opts['rev']
1618 revstrings = opts['rev']
1619 revs = logcmdutil.revrange(repo, revstrings)
1619 revs = logcmdutil.revrange(repo, revstrings)
1620 if revstrings and not revs:
1620 if revstrings and not revs:
1621 raise error.InputError(_(b'no commits to bundle'))
1621 raise error.InputError(_(b'no commits to bundle'))
1622
1622
1623 bundletype = opts.get('type', b'bzip2').lower()
1623 bundletype = opts.get('type', b'bzip2').lower()
1624 try:
1624 try:
1625 bundlespec = bundlecaches.parsebundlespec(
1625 bundlespec = bundlecaches.parsebundlespec(
1626 repo, bundletype, strict=False
1626 repo, bundletype, strict=False
1627 )
1627 )
1628 except error.UnsupportedBundleSpecification as e:
1628 except error.UnsupportedBundleSpecification as e:
1629 raise error.InputError(
1629 raise error.InputError(
1630 pycompat.bytestr(e),
1630 pycompat.bytestr(e),
1631 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1631 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1632 )
1632 )
1633
1633
1634 has_changegroup = bundlespec.params.get(b"changegroup", False)
1634 has_changegroup = bundlespec.params.get(b"changegroup", False)
1635 cgversion = bundlespec.params[b"cg.version"]
1635 cgversion = bundlespec.params[b"cg.version"]
1636
1636
1637 # Packed bundles are a pseudo bundle format for now.
1637 # Packed bundles are a pseudo bundle format for now.
1638 if cgversion == b's1':
1638 if cgversion == b's1':
1639 raise error.InputError(
1639 raise error.InputError(
1640 _(b'packed bundles cannot be produced by "hg bundle"'),
1640 _(b'packed bundles cannot be produced by "hg bundle"'),
1641 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1641 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1642 )
1642 )
1643 base_opt = opts.get('base')
1643 base_opt = opts.get('base')
1644 if opts.get('all'):
1644 if opts.get('all'):
1645 if dests:
1645 if dests:
1646 raise error.InputError(
1646 raise error.InputError(
1647 _(b"--all is incompatible with specifying destinations")
1647 _(b"--all is incompatible with specifying destinations")
1648 )
1648 )
1649 if base_opt:
1649 if base_opt:
1650 ui.warn(_(b"ignoring --base because --all was specified\n"))
1650 ui.warn(_(b"ignoring --base because --all was specified\n"))
1651 if opts.get('exact'):
1651 if opts.get('exact'):
1652 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1652 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1653 base = [nullrev]
1653 base = [nullrev]
1654 elif opts.get('exact'):
1654 elif opts.get('exact'):
1655 if dests:
1655 if dests:
1656 raise error.InputError(
1656 raise error.InputError(
1657 _(b"--exact is incompatible with specifying destinations")
1657 _(b"--exact is incompatible with specifying destinations")
1658 )
1658 )
1659 if base_opt:
1659 if base_opt:
1660 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1660 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1661 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1661 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1662 if not base:
1662 if not base:
1663 base = [nullrev]
1663 base = [nullrev]
1664 elif base_opt:
1664 elif base_opt:
1665 base = logcmdutil.revrange(repo, base_opt)
1665 base = logcmdutil.revrange(repo, base_opt)
1666 if not base:
1666 if not base:
1667 # base specified, but nothing was selected
1667 # base specified, but nothing was selected
1668 base = [nullrev]
1668 base = [nullrev]
1669 else:
1669 else:
1670 base = None
1670 base = None
1671 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1671 supported_cg_versions = changegroup.supportedoutgoingversions(repo)
1672 if has_changegroup and cgversion not in supported_cg_versions:
1672 if has_changegroup and cgversion not in supported_cg_versions:
1673 raise error.Abort(
1673 raise error.Abort(
1674 _(b"repository does not support bundle version %s") % cgversion
1674 _(b"repository does not support bundle version %s") % cgversion
1675 )
1675 )
1676
1676
1677 if base is not None:
1677 if base is not None:
1678 if dests:
1678 if dests:
1679 raise error.InputError(
1679 raise error.InputError(
1680 _(b"--base is incompatible with specifying destinations")
1680 _(b"--base is incompatible with specifying destinations")
1681 )
1681 )
1682 cl = repo.changelog
1682 cl = repo.changelog
1683 common = [cl.node(rev) for rev in base]
1683 common = [cl.node(rev) for rev in base]
1684 heads = [cl.node(r) for r in revs] if revs else None
1684 heads = [cl.node(r) for r in revs] if revs else None
1685 outgoing = discovery.outgoing(repo, common, heads)
1685 outgoing = discovery.outgoing(repo, common, heads)
1686 missing = outgoing.missing
1686 missing = outgoing.missing
1687 excluded = outgoing.excluded
1687 excluded = outgoing.excluded
1688 else:
1688 else:
1689 missing = set()
1689 missing = set()
1690 excluded = set()
1690 excluded = set()
1691 for path in urlutil.get_push_paths(repo, ui, dests):
1691 for path in urlutil.get_push_paths(repo, ui, dests):
1692 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1692 other = hg.peer(repo, pycompat.byteskwargs(opts), path)
1693 if revs is not None:
1693 if revs is not None:
1694 hex_revs = [repo[r].hex() for r in revs]
1694 hex_revs = [repo[r].hex() for r in revs]
1695 else:
1695 else:
1696 hex_revs = None
1696 hex_revs = None
1697 branches = (path.branch, [])
1697 branches = (path.branch, [])
1698 head_revs, checkout = hg.addbranchrevs(
1698 head_revs, checkout = hg.addbranchrevs(
1699 repo, repo, branches, hex_revs
1699 repo, repo, branches, hex_revs
1700 )
1700 )
1701 heads = (
1701 heads = (
1702 head_revs
1702 head_revs
1703 and pycompat.maplist(repo.lookup, head_revs)
1703 and pycompat.maplist(repo.lookup, head_revs)
1704 or head_revs
1704 or head_revs
1705 )
1705 )
1706 outgoing = discovery.findcommonoutgoing(
1706 outgoing = discovery.findcommonoutgoing(
1707 repo,
1707 repo,
1708 other,
1708 other,
1709 onlyheads=heads,
1709 onlyheads=heads,
1710 force=opts.get('force'),
1710 force=opts.get('force'),
1711 portable=True,
1711 portable=True,
1712 )
1712 )
1713 missing.update(outgoing.missing)
1713 missing.update(outgoing.missing)
1714 excluded.update(outgoing.excluded)
1714 excluded.update(outgoing.excluded)
1715
1715
1716 if not missing:
1716 if not missing:
1717 scmutil.nochangesfound(ui, repo, not base and excluded)
1717 scmutil.nochangesfound(ui, repo, not base and excluded)
1718 return 1
1718 return 1
1719
1719
1720 # internal changeset are internal implementation details that should not
1720 # internal changeset are internal implementation details that should not
1721 # leave the repository. Bundling with `hg bundle` create such risk.
1721 # leave the repository. Bundling with `hg bundle` create such risk.
1722 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1722 bundled_internal = repo.revs(b"%ln and _internal()", missing)
1723 if bundled_internal:
1723 if bundled_internal:
1724 msg = _(b"cannot bundle internal changesets")
1724 msg = _(b"cannot bundle internal changesets")
1725 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1725 hint = _(b"%d internal changesets selected") % len(bundled_internal)
1726 raise error.Abort(msg, hint=hint)
1726 raise error.Abort(msg, hint=hint)
1727
1727
1728 if heads:
1728 if heads:
1729 outgoing = discovery.outgoing(
1729 outgoing = discovery.outgoing(
1730 repo, missingroots=missing, ancestorsof=heads
1730 repo, missingroots=missing, ancestorsof=heads
1731 )
1731 )
1732 else:
1732 else:
1733 outgoing = discovery.outgoing(repo, missingroots=missing)
1733 outgoing = discovery.outgoing(repo, missingroots=missing)
1734 outgoing.excluded = sorted(excluded)
1734 outgoing.excluded = sorted(excluded)
1735
1735
1736 if cgversion == b'01': # bundle1
1736 if cgversion == b'01': # bundle1
1737 bversion = b'HG10' + bundlespec.wirecompression
1737 bversion = b'HG10' + bundlespec.wirecompression
1738 bcompression = None
1738 bcompression = None
1739 elif cgversion in (b'02', b'03'):
1739 elif cgversion in (b'02', b'03'):
1740 bversion = b'HG20'
1740 bversion = b'HG20'
1741 bcompression = bundlespec.wirecompression
1741 bcompression = bundlespec.wirecompression
1742 else:
1742 else:
1743 raise error.ProgrammingError(
1743 raise error.ProgrammingError(
1744 b'bundle: unexpected changegroup version %s' % cgversion
1744 b'bundle: unexpected changegroup version %s' % cgversion
1745 )
1745 )
1746
1746
1747 # TODO compression options should be derived from bundlespec parsing.
1747 # TODO compression options should be derived from bundlespec parsing.
1748 # This is a temporary hack to allow adjusting bundle compression
1748 # This is a temporary hack to allow adjusting bundle compression
1749 # level without a) formalizing the bundlespec changes to declare it
1749 # level without a) formalizing the bundlespec changes to declare it
1750 # b) introducing a command flag.
1750 # b) introducing a command flag.
1751 compopts = {}
1751 compopts = {}
1752 complevel = ui.configint(
1752 complevel = ui.configint(
1753 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1753 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1754 )
1754 )
1755 if complevel is None:
1755 if complevel is None:
1756 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1756 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1757 if complevel is not None:
1757 if complevel is not None:
1758 compopts[b'level'] = complevel
1758 compopts[b'level'] = complevel
1759
1759
1760 compthreads = ui.configint(
1760 compthreads = ui.configint(
1761 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1761 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1762 )
1762 )
1763 if compthreads is None:
1763 if compthreads is None:
1764 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1764 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1765 if compthreads is not None:
1765 if compthreads is not None:
1766 compopts[b'threads'] = compthreads
1766 compopts[b'threads'] = compthreads
1767
1767
1768 # Bundling of obsmarker and phases is optional as not all clients
1768 # Bundling of obsmarker and phases is optional as not all clients
1769 # support the necessary features.
1769 # support the necessary features.
1770 cfg = ui.configbool
1770 cfg = ui.configbool
1771 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1771 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1772 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1772 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1773 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1773 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1774 bundlespec.set_param(
1774 bundlespec.set_param(
1775 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1775 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1776 )
1776 )
1777 if not bundlespec.params.get(b'phases', False):
1777 if not bundlespec.params.get(b'phases', False):
1778 phases_cfg = cfg(b'experimental', b'bundle-phases')
1778 phases_cfg = cfg(b'experimental', b'bundle-phases')
1779 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1779 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1780
1780
1781 bundle2.writenewbundle(
1781 bundle2.writenewbundle(
1782 ui,
1782 ui,
1783 repo,
1783 repo,
1784 b'bundle',
1784 b'bundle',
1785 fname,
1785 fname,
1786 bversion,
1786 bversion,
1787 outgoing,
1787 outgoing,
1788 bundlespec.params,
1788 bundlespec.params,
1789 compression=bcompression,
1789 compression=bcompression,
1790 compopts=compopts,
1790 compopts=compopts,
1791 )
1791 )
1792
1792
1793
1793
1794 @command(
1794 @command(
1795 b'cat',
1795 b'cat',
1796 [
1796 [
1797 (
1797 (
1798 b'o',
1798 b'o',
1799 b'output',
1799 b'output',
1800 b'',
1800 b'',
1801 _(b'print output to file with formatted name'),
1801 _(b'print output to file with formatted name'),
1802 _(b'FORMAT'),
1802 _(b'FORMAT'),
1803 ),
1803 ),
1804 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1804 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1805 (b'', b'decode', None, _(b'apply any matching decode filter')),
1805 (b'', b'decode', None, _(b'apply any matching decode filter')),
1806 ]
1806 ]
1807 + walkopts
1807 + walkopts
1808 + formatteropts,
1808 + formatteropts,
1809 _(b'[OPTION]... FILE...'),
1809 _(b'[OPTION]... FILE...'),
1810 helpcategory=command.CATEGORY_FILE_CONTENTS,
1810 helpcategory=command.CATEGORY_FILE_CONTENTS,
1811 inferrepo=True,
1811 inferrepo=True,
1812 intents={INTENT_READONLY},
1812 intents={INTENT_READONLY},
1813 )
1813 )
1814 def cat(ui, repo, file1, *pats, **opts):
1814 def cat(ui, repo, file1, *pats, **opts):
1815 """output the current or given revision of files
1815 """output the current or given revision of files
1816
1816
1817 Print the specified files as they were at the given revision. If
1817 Print the specified files as they were at the given revision. If
1818 no revision is given, the parent of the working directory is used.
1818 no revision is given, the parent of the working directory is used.
1819
1819
1820 Output may be to a file, in which case the name of the file is
1820 Output may be to a file, in which case the name of the file is
1821 given using a template string. See :hg:`help templates`. In addition
1821 given using a template string. See :hg:`help templates`. In addition
1822 to the common template keywords, the following formatting rules are
1822 to the common template keywords, the following formatting rules are
1823 supported:
1823 supported:
1824
1824
1825 :``%%``: literal "%" character
1825 :``%%``: literal "%" character
1826 :``%s``: basename of file being printed
1826 :``%s``: basename of file being printed
1827 :``%d``: dirname of file being printed, or '.' if in repository root
1827 :``%d``: dirname of file being printed, or '.' if in repository root
1828 :``%p``: root-relative path name of file being printed
1828 :``%p``: root-relative path name of file being printed
1829 :``%H``: changeset hash (40 hexadecimal digits)
1829 :``%H``: changeset hash (40 hexadecimal digits)
1830 :``%R``: changeset revision number
1830 :``%R``: changeset revision number
1831 :``%h``: short-form changeset hash (12 hexadecimal digits)
1831 :``%h``: short-form changeset hash (12 hexadecimal digits)
1832 :``%r``: zero-padded changeset revision number
1832 :``%r``: zero-padded changeset revision number
1833 :``%b``: basename of the exporting repository
1833 :``%b``: basename of the exporting repository
1834 :``\\``: literal "\\" character
1834 :``\\``: literal "\\" character
1835
1835
1836 .. container:: verbose
1836 .. container:: verbose
1837
1837
1838 Template:
1838 Template:
1839
1839
1840 The following keywords are supported in addition to the common template
1840 The following keywords are supported in addition to the common template
1841 keywords and functions. See also :hg:`help templates`.
1841 keywords and functions. See also :hg:`help templates`.
1842
1842
1843 :data: String. File content.
1843 :data: String. File content.
1844 :path: String. Repository-absolute path of the file.
1844 :path: String. Repository-absolute path of the file.
1845
1845
1846 Returns 0 on success.
1846 Returns 0 on success.
1847 """
1847 """
1848 rev = opts.get('rev')
1848 rev = opts.get('rev')
1849 if rev:
1849 if rev:
1850 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1850 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1851 ctx = logcmdutil.revsingle(repo, rev)
1851 ctx = logcmdutil.revsingle(repo, rev)
1852 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1852 m = scmutil.match(ctx, (file1,) + pats, pycompat.byteskwargs(opts))
1853 fntemplate = opts.pop('output', b'')
1853 fntemplate = opts.pop('output', b'')
1854 if cmdutil.isstdiofilename(fntemplate):
1854 if cmdutil.isstdiofilename(fntemplate):
1855 fntemplate = b''
1855 fntemplate = b''
1856
1856
1857 if fntemplate:
1857 if fntemplate:
1858 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1858 fm = formatter.nullformatter(ui, b'cat', pycompat.byteskwargs(opts))
1859 else:
1859 else:
1860 ui.pager(b'cat')
1860 ui.pager(b'cat')
1861 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1861 fm = ui.formatter(b'cat', pycompat.byteskwargs(opts))
1862 with fm:
1862 with fm:
1863 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1863 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, b'', **opts)
1864
1864
1865
1865
1866 @command(
1866 @command(
1867 b'clone',
1867 b'clone',
1868 [
1868 [
1869 (
1869 (
1870 b'U',
1870 b'U',
1871 b'noupdate',
1871 b'noupdate',
1872 None,
1872 None,
1873 _(
1873 _(
1874 b'the clone will include an empty working '
1874 b'the clone will include an empty working '
1875 b'directory (only a repository)'
1875 b'directory (only a repository)'
1876 ),
1876 ),
1877 ),
1877 ),
1878 (
1878 (
1879 b'u',
1879 b'u',
1880 b'updaterev',
1880 b'updaterev',
1881 b'',
1881 b'',
1882 _(b'revision, tag, or branch to check out'),
1882 _(b'revision, tag, or branch to check out'),
1883 _(b'REV'),
1883 _(b'REV'),
1884 ),
1884 ),
1885 (
1885 (
1886 b'r',
1886 b'r',
1887 b'rev',
1887 b'rev',
1888 [],
1888 [],
1889 _(
1889 _(
1890 b'do not clone everything, but include this changeset'
1890 b'do not clone everything, but include this changeset'
1891 b' and its ancestors'
1891 b' and its ancestors'
1892 ),
1892 ),
1893 _(b'REV'),
1893 _(b'REV'),
1894 ),
1894 ),
1895 (
1895 (
1896 b'b',
1896 b'b',
1897 b'branch',
1897 b'branch',
1898 [],
1898 [],
1899 _(
1899 _(
1900 b'do not clone everything, but include this branch\'s'
1900 b'do not clone everything, but include this branch\'s'
1901 b' changesets and their ancestors'
1901 b' changesets and their ancestors'
1902 ),
1902 ),
1903 _(b'BRANCH'),
1903 _(b'BRANCH'),
1904 ),
1904 ),
1905 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1905 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1906 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1906 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1907 (b'', b'stream', None, _(b'clone with minimal data processing')),
1907 (b'', b'stream', None, _(b'clone with minimal data processing')),
1908 ]
1908 ]
1909 + remoteopts,
1909 + remoteopts,
1910 _(b'[OPTION]... SOURCE [DEST]'),
1910 _(b'[OPTION]... SOURCE [DEST]'),
1911 helpcategory=command.CATEGORY_REPO_CREATION,
1911 helpcategory=command.CATEGORY_REPO_CREATION,
1912 helpbasic=True,
1912 helpbasic=True,
1913 norepo=True,
1913 norepo=True,
1914 )
1914 )
1915 def clone(ui, source, dest=None, **opts):
1915 def clone(ui, source, dest=None, **opts):
1916 """make a copy of an existing repository
1916 """make a copy of an existing repository
1917
1917
1918 Create a copy of an existing repository in a new directory.
1918 Create a copy of an existing repository in a new directory.
1919
1919
1920 If no destination directory name is specified, it defaults to the
1920 If no destination directory name is specified, it defaults to the
1921 basename of the source.
1921 basename of the source.
1922
1922
1923 The location of the source is added to the new repository's
1923 The location of the source is added to the new repository's
1924 ``.hg/hgrc`` file, as the default to be used for future pulls.
1924 ``.hg/hgrc`` file, as the default to be used for future pulls.
1925
1925
1926 Only local paths and ``ssh://`` URLs are supported as
1926 Only local paths and ``ssh://`` URLs are supported as
1927 destinations. For ``ssh://`` destinations, no working directory or
1927 destinations. For ``ssh://`` destinations, no working directory or
1928 ``.hg/hgrc`` will be created on the remote side.
1928 ``.hg/hgrc`` will be created on the remote side.
1929
1929
1930 If the source repository has a bookmark called '@' set, that
1930 If the source repository has a bookmark called '@' set, that
1931 revision will be checked out in the new repository by default.
1931 revision will be checked out in the new repository by default.
1932
1932
1933 To check out a particular version, use -u/--update, or
1933 To check out a particular version, use -u/--update, or
1934 -U/--noupdate to create a clone with no working directory.
1934 -U/--noupdate to create a clone with no working directory.
1935
1935
1936 To pull only a subset of changesets, specify one or more revisions
1936 To pull only a subset of changesets, specify one or more revisions
1937 identifiers with -r/--rev or branches with -b/--branch. The
1937 identifiers with -r/--rev or branches with -b/--branch. The
1938 resulting clone will contain only the specified changesets and
1938 resulting clone will contain only the specified changesets and
1939 their ancestors. These options (or 'clone src#rev dest') imply
1939 their ancestors. These options (or 'clone src#rev dest') imply
1940 --pull, even for local source repositories.
1940 --pull, even for local source repositories.
1941
1941
1942 In normal clone mode, the remote normalizes repository data into a common
1942 In normal clone mode, the remote normalizes repository data into a common
1943 exchange format and the receiving end translates this data into its local
1943 exchange format and the receiving end translates this data into its local
1944 storage format. --stream activates a different clone mode that essentially
1944 storage format. --stream activates a different clone mode that essentially
1945 copies repository files from the remote with minimal data processing. This
1945 copies repository files from the remote with minimal data processing. This
1946 significantly reduces the CPU cost of a clone both remotely and locally.
1946 significantly reduces the CPU cost of a clone both remotely and locally.
1947 However, it often increases the transferred data size by 30-40%. This can
1947 However, it often increases the transferred data size by 30-40%. This can
1948 result in substantially faster clones where I/O throughput is plentiful,
1948 result in substantially faster clones where I/O throughput is plentiful,
1949 especially for larger repositories. A side-effect of --stream clones is
1949 especially for larger repositories. A side-effect of --stream clones is
1950 that storage settings and requirements on the remote are applied locally:
1950 that storage settings and requirements on the remote are applied locally:
1951 a modern client may inherit legacy or inefficient storage used by the
1951 a modern client may inherit legacy or inefficient storage used by the
1952 remote or a legacy Mercurial client may not be able to clone from a
1952 remote or a legacy Mercurial client may not be able to clone from a
1953 modern Mercurial remote.
1953 modern Mercurial remote.
1954
1954
1955 .. note::
1955 .. note::
1956
1956
1957 Specifying a tag will include the tagged changeset but not the
1957 Specifying a tag will include the tagged changeset but not the
1958 changeset containing the tag.
1958 changeset containing the tag.
1959
1959
1960 .. container:: verbose
1960 .. container:: verbose
1961
1961
1962 For efficiency, hardlinks are used for cloning whenever the
1962 For efficiency, hardlinks are used for cloning whenever the
1963 source and destination are on the same filesystem (note this
1963 source and destination are on the same filesystem (note this
1964 applies only to the repository data, not to the working
1964 applies only to the repository data, not to the working
1965 directory). Some filesystems, such as AFS, implement hardlinking
1965 directory). Some filesystems, such as AFS, implement hardlinking
1966 incorrectly, but do not report errors. In these cases, use the
1966 incorrectly, but do not report errors. In these cases, use the
1967 --pull option to avoid hardlinking.
1967 --pull option to avoid hardlinking.
1968
1968
1969 Mercurial will update the working directory to the first applicable
1969 Mercurial will update the working directory to the first applicable
1970 revision from this list:
1970 revision from this list:
1971
1971
1972 a) null if -U or the source repository has no changesets
1972 a) null if -U or the source repository has no changesets
1973 b) if -u . and the source repository is local, the first parent of
1973 b) if -u . and the source repository is local, the first parent of
1974 the source repository's working directory
1974 the source repository's working directory
1975 c) the changeset specified with -u (if a branch name, this means the
1975 c) the changeset specified with -u (if a branch name, this means the
1976 latest head of that branch)
1976 latest head of that branch)
1977 d) the changeset specified with -r
1977 d) the changeset specified with -r
1978 e) the tipmost head specified with -b
1978 e) the tipmost head specified with -b
1979 f) the tipmost head specified with the url#branch source syntax
1979 f) the tipmost head specified with the url#branch source syntax
1980 g) the revision marked with the '@' bookmark, if present
1980 g) the revision marked with the '@' bookmark, if present
1981 h) the tipmost head of the default branch
1981 h) the tipmost head of the default branch
1982 i) tip
1982 i) tip
1983
1983
1984 When cloning from servers that support it, Mercurial may fetch
1984 When cloning from servers that support it, Mercurial may fetch
1985 pre-generated data from a server-advertised URL or inline from the
1985 pre-generated data from a server-advertised URL or inline from the
1986 same stream. When this is done, hooks operating on incoming changesets
1986 same stream. When this is done, hooks operating on incoming changesets
1987 and changegroups may fire more than once, once for each pre-generated
1987 and changegroups may fire more than once, once for each pre-generated
1988 bundle and as well as for any additional remaining data. In addition,
1988 bundle and as well as for any additional remaining data. In addition,
1989 if an error occurs, the repository may be rolled back to a partial
1989 if an error occurs, the repository may be rolled back to a partial
1990 clone. This behavior may change in future releases.
1990 clone. This behavior may change in future releases.
1991 See :hg:`help -e clonebundles` for more.
1991 See :hg:`help -e clonebundles` for more.
1992
1992
1993 Examples:
1993 Examples:
1994
1994
1995 - clone a remote repository to a new directory named hg/::
1995 - clone a remote repository to a new directory named hg/::
1996
1996
1997 hg clone https://www.mercurial-scm.org/repo/hg/
1997 hg clone https://www.mercurial-scm.org/repo/hg/
1998
1998
1999 - create a lightweight local clone::
1999 - create a lightweight local clone::
2000
2000
2001 hg clone project/ project-feature/
2001 hg clone project/ project-feature/
2002
2002
2003 - clone from an absolute path on an ssh server (note double-slash)::
2003 - clone from an absolute path on an ssh server (note double-slash)::
2004
2004
2005 hg clone ssh://user@server//home/projects/alpha/
2005 hg clone ssh://user@server//home/projects/alpha/
2006
2006
2007 - do a streaming clone while checking out a specified version::
2007 - do a streaming clone while checking out a specified version::
2008
2008
2009 hg clone --stream http://server/repo -u 1.5
2009 hg clone --stream http://server/repo -u 1.5
2010
2010
2011 - create a repository without changesets after a particular revision::
2011 - create a repository without changesets after a particular revision::
2012
2012
2013 hg clone -r 04e544 experimental/ good/
2013 hg clone -r 04e544 experimental/ good/
2014
2014
2015 - clone (and track) a particular named branch::
2015 - clone (and track) a particular named branch::
2016
2016
2017 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2017 hg clone https://www.mercurial-scm.org/repo/hg/#stable
2018
2018
2019 See :hg:`help urls` for details on specifying URLs.
2019 See :hg:`help urls` for details on specifying URLs.
2020
2020
2021 Returns 0 on success.
2021 Returns 0 on success.
2022 """
2022 """
2023 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2023 cmdutil.check_at_most_one_arg(opts, 'noupdate', 'updaterev')
2024
2024
2025 # --include/--exclude can come from narrow or sparse.
2025 # --include/--exclude can come from narrow or sparse.
2026 includepats, excludepats = None, None
2026 includepats, excludepats = None, None
2027
2027
2028 # hg.clone() differentiates between None and an empty set. So make sure
2028 # hg.clone() differentiates between None and an empty set. So make sure
2029 # patterns are sets if narrow is requested without patterns.
2029 # patterns are sets if narrow is requested without patterns.
2030 if opts.get('narrow'):
2030 if opts.get('narrow'):
2031 includepats = set()
2031 includepats = set()
2032 excludepats = set()
2032 excludepats = set()
2033
2033
2034 if opts.get('include'):
2034 if opts.get('include'):
2035 includepats = narrowspec.parsepatterns(opts.get('include'))
2035 includepats = narrowspec.parsepatterns(opts.get('include'))
2036 if opts.get('exclude'):
2036 if opts.get('exclude'):
2037 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2037 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
2038
2038
2039 r = hg.clone(
2039 r = hg.clone(
2040 ui,
2040 ui,
2041 pycompat.byteskwargs(opts),
2041 pycompat.byteskwargs(opts),
2042 source,
2042 source,
2043 dest,
2043 dest,
2044 pull=opts.get('pull'),
2044 pull=opts.get('pull'),
2045 stream=opts.get('stream') or opts.get('uncompressed'),
2045 stream=opts.get('stream') or opts.get('uncompressed'),
2046 revs=opts.get('rev'),
2046 revs=opts.get('rev'),
2047 update=opts.get('updaterev') or not opts.get('noupdate'),
2047 update=opts.get('updaterev') or not opts.get('noupdate'),
2048 branch=opts.get('branch'),
2048 branch=opts.get('branch'),
2049 shareopts=opts.get('shareopts'),
2049 shareopts=opts.get('shareopts'),
2050 storeincludepats=includepats,
2050 storeincludepats=includepats,
2051 storeexcludepats=excludepats,
2051 storeexcludepats=excludepats,
2052 depth=opts.get('depth') or None,
2052 depth=opts.get('depth') or None,
2053 )
2053 )
2054
2054
2055 return r is None
2055 return r is None
2056
2056
2057
2057
2058 @command(
2058 @command(
2059 b'commit|ci',
2059 b'commit|ci',
2060 [
2060 [
2061 (
2061 (
2062 b'A',
2062 b'A',
2063 b'addremove',
2063 b'addremove',
2064 None,
2064 None,
2065 _(b'mark new/missing files as added/removed before committing'),
2065 _(b'mark new/missing files as added/removed before committing'),
2066 ),
2066 ),
2067 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2067 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
2068 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2068 (b'', b'amend', None, _(b'amend the parent of the working directory')),
2069 (b's', b'secret', None, _(b'use the secret phase for committing')),
2069 (b's', b'secret', None, _(b'use the secret phase for committing')),
2070 (b'', b'draft', None, _(b'use the draft phase for committing')),
2070 (b'', b'draft', None, _(b'use the draft phase for committing')),
2071 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2071 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
2072 (
2072 (
2073 b'',
2073 b'',
2074 b'force-close-branch',
2074 b'force-close-branch',
2075 None,
2075 None,
2076 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2076 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
2077 ),
2077 ),
2078 (b'i', b'interactive', None, _(b'use interactive mode')),
2078 (b'i', b'interactive', None, _(b'use interactive mode')),
2079 ]
2079 ]
2080 + walkopts
2080 + walkopts
2081 + commitopts
2081 + commitopts
2082 + commitopts2
2082 + commitopts2
2083 + subrepoopts,
2083 + subrepoopts,
2084 _(b'[OPTION]... [FILE]...'),
2084 _(b'[OPTION]... [FILE]...'),
2085 helpcategory=command.CATEGORY_COMMITTING,
2085 helpcategory=command.CATEGORY_COMMITTING,
2086 helpbasic=True,
2086 helpbasic=True,
2087 inferrepo=True,
2087 inferrepo=True,
2088 )
2088 )
2089 def commit(ui, repo, *pats, **opts):
2089 def commit(ui, repo, *pats, **opts):
2090 """commit the specified files or all outstanding changes
2090 """commit the specified files or all outstanding changes
2091
2091
2092 Commit changes to the given files into the repository. Unlike a
2092 Commit changes to the given files into the repository. Unlike a
2093 centralized SCM, this operation is a local operation. See
2093 centralized SCM, this operation is a local operation. See
2094 :hg:`push` for a way to actively distribute your changes.
2094 :hg:`push` for a way to actively distribute your changes.
2095
2095
2096 If a list of files is omitted, all changes reported by :hg:`status`
2096 If a list of files is omitted, all changes reported by :hg:`status`
2097 will be committed.
2097 will be committed.
2098
2098
2099 If you are committing the result of a merge, do not provide any
2099 If you are committing the result of a merge, do not provide any
2100 filenames or -I/-X filters.
2100 filenames or -I/-X filters.
2101
2101
2102 If no commit message is specified, Mercurial starts your
2102 If no commit message is specified, Mercurial starts your
2103 configured editor where you can enter a message. In case your
2103 configured editor where you can enter a message. In case your
2104 commit fails, you will find a backup of your message in
2104 commit fails, you will find a backup of your message in
2105 ``.hg/last-message.txt``.
2105 ``.hg/last-message.txt``.
2106
2106
2107 The --close-branch flag can be used to mark the current branch
2107 The --close-branch flag can be used to mark the current branch
2108 head closed. When all heads of a branch are closed, the branch
2108 head closed. When all heads of a branch are closed, the branch
2109 will be considered closed and no longer listed.
2109 will be considered closed and no longer listed.
2110
2110
2111 The --amend flag can be used to amend the parent of the
2111 The --amend flag can be used to amend the parent of the
2112 working directory with a new commit that contains the changes
2112 working directory with a new commit that contains the changes
2113 in the parent in addition to those currently reported by :hg:`status`,
2113 in the parent in addition to those currently reported by :hg:`status`,
2114 if there are any. The old commit is stored in a backup bundle in
2114 if there are any. The old commit is stored in a backup bundle in
2115 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2115 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2116 on how to restore it).
2116 on how to restore it).
2117
2117
2118 Message, user and date are taken from the amended commit unless
2118 Message, user and date are taken from the amended commit unless
2119 specified. When a message isn't specified on the command line,
2119 specified. When a message isn't specified on the command line,
2120 the editor will open with the message of the amended commit.
2120 the editor will open with the message of the amended commit.
2121
2121
2122 It is not possible to amend public changesets (see :hg:`help phases`)
2122 It is not possible to amend public changesets (see :hg:`help phases`)
2123 or changesets that have children.
2123 or changesets that have children.
2124
2124
2125 See :hg:`help dates` for a list of formats valid for -d/--date.
2125 See :hg:`help dates` for a list of formats valid for -d/--date.
2126
2126
2127 Returns 0 on success, 1 if nothing changed.
2127 Returns 0 on success, 1 if nothing changed.
2128
2128
2129 .. container:: verbose
2129 .. container:: verbose
2130
2130
2131 Examples:
2131 Examples:
2132
2132
2133 - commit all files ending in .py::
2133 - commit all files ending in .py::
2134
2134
2135 hg commit --include "set:**.py"
2135 hg commit --include "set:**.py"
2136
2136
2137 - commit all non-binary files::
2137 - commit all non-binary files::
2138
2138
2139 hg commit --exclude "set:binary()"
2139 hg commit --exclude "set:binary()"
2140
2140
2141 - amend the current commit and set the date to now::
2141 - amend the current commit and set the date to now::
2142
2142
2143 hg commit --amend --date now
2143 hg commit --amend --date now
2144 """
2144 """
2145 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2145 cmdutil.check_at_most_one_arg(opts, 'draft', 'secret')
2146 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2146 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2147 with repo.wlock(), repo.lock():
2147 with repo.wlock(), repo.lock():
2148 return _docommit(ui, repo, *pats, **opts)
2148 return _docommit(ui, repo, *pats, **opts)
2149
2149
2150
2150
2151 def _docommit(ui, repo, *pats, **opts):
2151 def _docommit(ui, repo, *pats, **opts):
2152 if opts.get('interactive'):
2152 if opts.get('interactive'):
2153 opts.pop('interactive')
2153 opts.pop('interactive')
2154 ret = cmdutil.dorecord(
2154 ret = cmdutil.dorecord(
2155 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2155 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2156 )
2156 )
2157 # ret can be 0 (no changes to record) or the value returned by
2157 # ret can be 0 (no changes to record) or the value returned by
2158 # commit(), 1 if nothing changed or None on success.
2158 # commit(), 1 if nothing changed or None on success.
2159 return 1 if ret == 0 else ret
2159 return 1 if ret == 0 else ret
2160
2160
2161 if opts.get('subrepos'):
2161 if opts.get('subrepos'):
2162 # Let --subrepos on the command line override config setting.
2162 # Let --subrepos on the command line override config setting.
2163 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2163 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2164
2164
2165 cmdutil.checkunfinished(repo, commit=True)
2165 cmdutil.checkunfinished(repo, commit=True)
2166
2166
2167 branch = repo[None].branch()
2167 branch = repo[None].branch()
2168 bheads = repo.branchheads(branch)
2168 bheads = repo.branchheads(branch)
2169 tip = repo.changelog.tip()
2169 tip = repo.changelog.tip()
2170
2170
2171 extra = {}
2171 extra = {}
2172 if opts.get('close_branch') or opts.get('force_close_branch'):
2172 if opts.get('close_branch') or opts.get('force_close_branch'):
2173 extra[b'close'] = b'1'
2173 extra[b'close'] = b'1'
2174
2174
2175 if repo[b'.'].closesbranch():
2175 if repo[b'.'].closesbranch():
2176 # Not ideal, but let us do an extra status early to prevent early
2176 # Not ideal, but let us do an extra status early to prevent early
2177 # bail out.
2177 # bail out.
2178 matcher = scmutil.match(
2178 matcher = scmutil.match(
2179 repo[None], pats, pycompat.byteskwargs(opts)
2179 repo[None], pats, pycompat.byteskwargs(opts)
2180 )
2180 )
2181 s = repo.status(match=matcher)
2181 s = repo.status(match=matcher)
2182 if s.modified or s.added or s.removed:
2182 if s.modified or s.added or s.removed:
2183 bheads = repo.branchheads(branch, closed=True)
2183 bheads = repo.branchheads(branch, closed=True)
2184 else:
2184 else:
2185 msg = _(b'current revision is already a branch closing head')
2185 msg = _(b'current revision is already a branch closing head')
2186 raise error.InputError(msg)
2186 raise error.InputError(msg)
2187
2187
2188 if not bheads:
2188 if not bheads:
2189 raise error.InputError(
2189 raise error.InputError(
2190 _(b'branch "%s" has no heads to close') % branch
2190 _(b'branch "%s" has no heads to close') % branch
2191 )
2191 )
2192 elif (
2192 elif (
2193 branch == repo[b'.'].branch()
2193 branch == repo[b'.'].branch()
2194 and repo[b'.'].node() not in bheads
2194 and repo[b'.'].node() not in bheads
2195 and not opts.get('force_close_branch')
2195 and not opts.get('force_close_branch')
2196 ):
2196 ):
2197 hint = _(
2197 hint = _(
2198 b'use --force-close-branch to close branch from a non-head'
2198 b'use --force-close-branch to close branch from a non-head'
2199 b' changeset'
2199 b' changeset'
2200 )
2200 )
2201 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2201 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2202 elif opts.get('amend'):
2202 elif opts.get('amend'):
2203 if (
2203 if (
2204 repo[b'.'].p1().branch() != branch
2204 repo[b'.'].p1().branch() != branch
2205 and repo[b'.'].p2().branch() != branch
2205 and repo[b'.'].p2().branch() != branch
2206 ):
2206 ):
2207 raise error.InputError(_(b'can only close branch heads'))
2207 raise error.InputError(_(b'can only close branch heads'))
2208
2208
2209 if opts.get('amend'):
2209 if opts.get('amend'):
2210 if ui.configbool(b'ui', b'commitsubrepos'):
2210 if ui.configbool(b'ui', b'commitsubrepos'):
2211 raise error.InputError(
2211 raise error.InputError(
2212 _(b'cannot amend with ui.commitsubrepos enabled')
2212 _(b'cannot amend with ui.commitsubrepos enabled')
2213 )
2213 )
2214
2214
2215 old = repo[b'.']
2215 old = repo[b'.']
2216 rewriteutil.precheck(repo, [old.rev()], b'amend')
2216 rewriteutil.precheck(repo, [old.rev()], b'amend')
2217
2217
2218 # Currently histedit gets confused if an amend happens while histedit
2218 # Currently histedit gets confused if an amend happens while histedit
2219 # is in progress. Since we have a checkunfinished command, we are
2219 # is in progress. Since we have a checkunfinished command, we are
2220 # temporarily honoring it.
2220 # temporarily honoring it.
2221 #
2221 #
2222 # Note: eventually this guard will be removed. Please do not expect
2222 # Note: eventually this guard will be removed. Please do not expect
2223 # this behavior to remain.
2223 # this behavior to remain.
2224 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2224 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2225 cmdutil.checkunfinished(repo)
2225 cmdutil.checkunfinished(repo)
2226
2226
2227 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2227 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2228 if node == old.node():
2228 if node == old.node():
2229 ui.status(_(b"nothing changed\n"))
2229 ui.status(_(b"nothing changed\n"))
2230 return 1
2230 return 1
2231 else:
2231 else:
2232
2232
2233 def commitfunc(ui, repo, message, match, opts):
2233 def commitfunc(ui, repo, message, match, opts):
2234 overrides = {}
2234 overrides = {}
2235 if opts.get(b'secret'):
2235 if opts.get(b'secret'):
2236 overrides[(b'phases', b'new-commit')] = b'secret'
2236 overrides[(b'phases', b'new-commit')] = b'secret'
2237 elif opts.get(b'draft'):
2237 elif opts.get(b'draft'):
2238 overrides[(b'phases', b'new-commit')] = b'draft'
2238 overrides[(b'phases', b'new-commit')] = b'draft'
2239
2239
2240 baseui = repo.baseui
2240 baseui = repo.baseui
2241 with baseui.configoverride(overrides, b'commit'):
2241 with baseui.configoverride(overrides, b'commit'):
2242 with ui.configoverride(overrides, b'commit'):
2242 with ui.configoverride(overrides, b'commit'):
2243 editform = cmdutil.mergeeditform(
2243 editform = cmdutil.mergeeditform(
2244 repo[None], b'commit.normal'
2244 repo[None], b'commit.normal'
2245 )
2245 )
2246 editor = cmdutil.getcommiteditor(
2246 editor = cmdutil.getcommiteditor(
2247 editform=editform, **pycompat.strkwargs(opts)
2247 editform=editform, **pycompat.strkwargs(opts)
2248 )
2248 )
2249 return repo.commit(
2249 return repo.commit(
2250 message,
2250 message,
2251 opts.get(b'user'),
2251 opts.get(b'user'),
2252 opts.get(b'date'),
2252 opts.get(b'date'),
2253 match,
2253 match,
2254 editor=editor,
2254 editor=editor,
2255 extra=extra,
2255 extra=extra,
2256 )
2256 )
2257
2257
2258 node = cmdutil.commit(
2258 node = cmdutil.commit(
2259 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2259 ui, repo, commitfunc, pats, pycompat.byteskwargs(opts)
2260 )
2260 )
2261
2261
2262 if not node:
2262 if not node:
2263 stat = cmdutil.postcommitstatus(
2263 stat = cmdutil.postcommitstatus(
2264 repo, pats, pycompat.byteskwargs(opts)
2264 repo, pats, pycompat.byteskwargs(opts)
2265 )
2265 )
2266 if stat.deleted:
2266 if stat.deleted:
2267 ui.status(
2267 ui.status(
2268 _(
2268 _(
2269 b"nothing changed (%d missing files, see "
2269 b"nothing changed (%d missing files, see "
2270 b"'hg status')\n"
2270 b"'hg status')\n"
2271 )
2271 )
2272 % len(stat.deleted)
2272 % len(stat.deleted)
2273 )
2273 )
2274 else:
2274 else:
2275 ui.status(_(b"nothing changed\n"))
2275 ui.status(_(b"nothing changed\n"))
2276 return 1
2276 return 1
2277
2277
2278 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2278 cmdutil.commitstatus(repo, node, branch, bheads, tip, **opts)
2279
2279
2280 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2280 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2281 status(
2281 status(
2282 ui,
2282 ui,
2283 repo,
2283 repo,
2284 modified=True,
2284 modified=True,
2285 added=True,
2285 added=True,
2286 removed=True,
2286 removed=True,
2287 deleted=True,
2287 deleted=True,
2288 unknown=True,
2288 unknown=True,
2289 subrepos=opts.get('subrepos'),
2289 subrepos=opts.get('subrepos'),
2290 )
2290 )
2291
2291
2292
2292
2293 @command(
2293 @command(
2294 b'config|showconfig|debugconfig',
2294 b'config|showconfig|debugconfig',
2295 [
2295 [
2296 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2296 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2297 # This is experimental because we need
2297 # This is experimental because we need
2298 # * reasonable behavior around aliases,
2298 # * reasonable behavior around aliases,
2299 # * decide if we display [debug] [experimental] and [devel] section par
2299 # * decide if we display [debug] [experimental] and [devel] section par
2300 # default
2300 # default
2301 # * some way to display "generic" config entry (the one matching
2301 # * some way to display "generic" config entry (the one matching
2302 # regexp,
2302 # regexp,
2303 # * proper display of the different value type
2303 # * proper display of the different value type
2304 # * a better way to handle <DYNAMIC> values (and variable types),
2304 # * a better way to handle <DYNAMIC> values (and variable types),
2305 # * maybe some type information ?
2305 # * maybe some type information ?
2306 (
2306 (
2307 b'',
2307 b'',
2308 b'exp-all-known',
2308 b'exp-all-known',
2309 None,
2309 None,
2310 _(b'show all known config option (EXPERIMENTAL)'),
2310 _(b'show all known config option (EXPERIMENTAL)'),
2311 ),
2311 ),
2312 (b'e', b'edit', None, _(b'edit user config')),
2312 (b'e', b'edit', None, _(b'edit user config')),
2313 (b'l', b'local', None, _(b'edit repository config')),
2313 (b'l', b'local', None, _(b'edit repository config')),
2314 (b'', b'source', None, _(b'show source of configuration value')),
2314 (b'', b'source', None, _(b'show source of configuration value')),
2315 (
2315 (
2316 b'',
2316 b'',
2317 b'shared',
2317 b'shared',
2318 None,
2318 None,
2319 _(b'edit shared source repository config (EXPERIMENTAL)'),
2319 _(b'edit shared source repository config (EXPERIMENTAL)'),
2320 ),
2320 ),
2321 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2321 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2322 (b'g', b'global', None, _(b'edit global config')),
2322 (b'g', b'global', None, _(b'edit global config')),
2323 ]
2323 ]
2324 + formatteropts,
2324 + formatteropts,
2325 _(b'[-u] [NAME]...'),
2325 _(b'[-u] [NAME]...'),
2326 helpcategory=command.CATEGORY_HELP,
2326 helpcategory=command.CATEGORY_HELP,
2327 optionalrepo=True,
2327 optionalrepo=True,
2328 intents={INTENT_READONLY},
2328 intents={INTENT_READONLY},
2329 )
2329 )
2330 def config(ui, repo, *values, **opts):
2330 def config(ui, repo, *values, **opts):
2331 """show combined config settings from all hgrc files
2331 """show combined config settings from all hgrc files
2332
2332
2333 With no arguments, print names and values of all config items.
2333 With no arguments, print names and values of all config items.
2334
2334
2335 With one argument of the form section.name, print just the value
2335 With one argument of the form section.name, print just the value
2336 of that config item.
2336 of that config item.
2337
2337
2338 With multiple arguments, print names and values of all config
2338 With multiple arguments, print names and values of all config
2339 items with matching section names or section.names.
2339 items with matching section names or section.names.
2340
2340
2341 With --edit, start an editor on the user-level config file. With
2341 With --edit, start an editor on the user-level config file. With
2342 --global, edit the system-wide config file. With --local, edit the
2342 --global, edit the system-wide config file. With --local, edit the
2343 repository-level config file.
2343 repository-level config file.
2344
2344
2345 With --source, the source (filename and line number) is printed
2345 With --source, the source (filename and line number) is printed
2346 for each config item.
2346 for each config item.
2347
2347
2348 See :hg:`help config` for more information about config files.
2348 See :hg:`help config` for more information about config files.
2349
2349
2350 .. container:: verbose
2350 .. container:: verbose
2351
2351
2352 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2352 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2353 This file is not shared across shares when in share-safe mode.
2353 This file is not shared across shares when in share-safe mode.
2354
2354
2355 Template:
2355 Template:
2356
2356
2357 The following keywords are supported. See also :hg:`help templates`.
2357 The following keywords are supported. See also :hg:`help templates`.
2358
2358
2359 :name: String. Config name.
2359 :name: String. Config name.
2360 :source: String. Filename and line number where the item is defined.
2360 :source: String. Filename and line number where the item is defined.
2361 :value: String. Config value.
2361 :value: String. Config value.
2362
2362
2363 The --shared flag can be used to edit the config file of shared source
2363 The --shared flag can be used to edit the config file of shared source
2364 repository. It only works when you have shared using the experimental
2364 repository. It only works when you have shared using the experimental
2365 share safe feature.
2365 share safe feature.
2366
2366
2367 Returns 0 on success, 1 if NAME does not exist.
2367 Returns 0 on success, 1 if NAME does not exist.
2368
2368
2369 """
2369 """
2370
2370 edit_level = config_command.find_edit_level(ui, repo, opts)
2371 editopts = ('edit', 'local', 'global', 'shared', 'non_shared')
2371 if edit_level is not None:
2372 if any(opts.get(o) for o in editopts):
2372 return config_command.edit_config(ui, repo, edit_level)
2373 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2374 if opts.get('local'):
2375 if not repo:
2376 raise error.InputError(
2377 _(b"can't use --local outside a repository")
2378 )
2379 paths = [repo.vfs.join(b'hgrc')]
2380 elif opts.get('global'):
2381 paths = rcutil.systemrcpath()
2382 elif opts.get('shared'):
2383 if not repo.shared():
2384 raise error.InputError(
2385 _(b"repository is not shared; can't use --shared")
2386 )
2387 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2388 raise error.InputError(
2389 _(
2390 b"share safe feature not enabled; "
2391 b"unable to edit shared source repository config"
2392 )
2393 )
2394 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2395 elif opts.get('non_shared'):
2396 paths = [repo.vfs.join(b'hgrc-not-shared')]
2397 else:
2398 paths = rcutil.userrcpath()
2399
2400 for f in paths:
2401 if os.path.exists(f):
2402 break
2403 else:
2404 if opts.get('global'):
2405 samplehgrc = uimod.samplehgrcs[b'global']
2406 elif opts.get('local'):
2407 samplehgrc = uimod.samplehgrcs[b'local']
2408 else:
2409 samplehgrc = uimod.samplehgrcs[b'user']
2410
2411 f = paths[0]
2412 util.writefile(f, util.tonativeeol(samplehgrc))
2413
2414 editor = ui.geteditor()
2415 ui.system(
2416 b"%s \"%s\"" % (editor, f),
2417 onerr=error.InputError,
2418 errprefix=_(b"edit failed"),
2419 blockedtag=b'config_edit',
2420 )
2421 return
2422 ui.pager(b'config')
2373 ui.pager(b'config')
2423 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2374 fm = ui.formatter(b'config', pycompat.byteskwargs(opts))
2424 for t, f in rcutil.rccomponents():
2375 for t, f in rcutil.rccomponents():
2425 if t == b'path':
2376 if t == b'path':
2426 ui.debug(b'read config from: %s\n' % f)
2377 ui.debug(b'read config from: %s\n' % f)
2427 elif t == b'resource':
2378 elif t == b'resource':
2428 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2379 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2429 elif t == b'items':
2380 elif t == b'items':
2430 # Don't print anything for 'items'.
2381 # Don't print anything for 'items'.
2431 pass
2382 pass
2432 else:
2383 else:
2433 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2384 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2434 untrusted = bool(opts.get('untrusted'))
2385 untrusted = bool(opts.get('untrusted'))
2435
2386
2436 selsections = selentries = []
2387 selsections = selentries = []
2437 if values:
2388 if values:
2438 selsections = [v for v in values if b'.' not in v]
2389 selsections = [v for v in values if b'.' not in v]
2439 selentries = [v for v in values if b'.' in v]
2390 selentries = [v for v in values if b'.' in v]
2440 uniquesel = len(selentries) == 1 and not selsections
2391 uniquesel = len(selentries) == 1 and not selsections
2441 selsections = set(selsections)
2392 selsections = set(selsections)
2442 selentries = set(selentries)
2393 selentries = set(selentries)
2443
2394
2444 matched = False
2395 matched = False
2445 all_known = opts['exp_all_known']
2396 all_known = opts['exp_all_known']
2446 show_source = ui.debugflag or opts.get('source')
2397 show_source = ui.debugflag or opts.get('source')
2447 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2398 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2448 for section, name, value in entries:
2399 for section, name, value in entries:
2449 source = ui.configsource(section, name, untrusted)
2400 source = ui.configsource(section, name, untrusted)
2450 value = pycompat.bytestr(value)
2401 value = pycompat.bytestr(value)
2451 defaultvalue = ui.configdefault(section, name)
2402 defaultvalue = ui.configdefault(section, name)
2452 if fm.isplain():
2403 if fm.isplain():
2453 source = source or b'none'
2404 source = source or b'none'
2454 value = value.replace(b'\n', b'\\n')
2405 value = value.replace(b'\n', b'\\n')
2455 entryname = section + b'.' + name
2406 entryname = section + b'.' + name
2456 if values and not (section in selsections or entryname in selentries):
2407 if values and not (section in selsections or entryname in selentries):
2457 continue
2408 continue
2458 fm.startitem()
2409 fm.startitem()
2459 fm.condwrite(show_source, b'source', b'%s: ', source)
2410 fm.condwrite(show_source, b'source', b'%s: ', source)
2460 if uniquesel:
2411 if uniquesel:
2461 fm.data(name=entryname)
2412 fm.data(name=entryname)
2462 fm.write(b'value', b'%s\n', value)
2413 fm.write(b'value', b'%s\n', value)
2463 else:
2414 else:
2464 fm.write(b'name value', b'%s=%s\n', entryname, value)
2415 fm.write(b'name value', b'%s=%s\n', entryname, value)
2465 if formatter.isprintable(defaultvalue):
2416 if formatter.isprintable(defaultvalue):
2466 fm.data(defaultvalue=defaultvalue)
2417 fm.data(defaultvalue=defaultvalue)
2467 elif isinstance(defaultvalue, list) and all(
2418 elif isinstance(defaultvalue, list) and all(
2468 formatter.isprintable(e) for e in defaultvalue
2419 formatter.isprintable(e) for e in defaultvalue
2469 ):
2420 ):
2470 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2421 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2471 # TODO: no idea how to process unsupported defaultvalue types
2422 # TODO: no idea how to process unsupported defaultvalue types
2472 matched = True
2423 matched = True
2473 fm.end()
2424 fm.end()
2474 if matched:
2425 if matched:
2475 return 0
2426 return 0
2476 return 1
2427 return 1
2477
2428
2478
2429
2479 @command(
2430 @command(
2480 b'continue',
2431 b'continue',
2481 dryrunopts,
2432 dryrunopts,
2482 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2433 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2483 helpbasic=True,
2434 helpbasic=True,
2484 )
2435 )
2485 def continuecmd(ui, repo, **opts):
2436 def continuecmd(ui, repo, **opts):
2486 """resumes an interrupted operation (EXPERIMENTAL)
2437 """resumes an interrupted operation (EXPERIMENTAL)
2487
2438
2488 Finishes a multistep operation like graft, histedit, rebase, merge,
2439 Finishes a multistep operation like graft, histedit, rebase, merge,
2489 and unshelve if they are in an interrupted state.
2440 and unshelve if they are in an interrupted state.
2490
2441
2491 use --dry-run/-n to dry run the command.
2442 use --dry-run/-n to dry run the command.
2492 """
2443 """
2493 dryrun = opts.get('dry_run')
2444 dryrun = opts.get('dry_run')
2494 contstate = cmdutil.getunfinishedstate(repo)
2445 contstate = cmdutil.getunfinishedstate(repo)
2495 if not contstate:
2446 if not contstate:
2496 raise error.StateError(_(b'no operation in progress'))
2447 raise error.StateError(_(b'no operation in progress'))
2497 if not contstate.continuefunc:
2448 if not contstate.continuefunc:
2498 raise error.StateError(
2449 raise error.StateError(
2499 (
2450 (
2500 _(b"%s in progress but does not support 'hg continue'")
2451 _(b"%s in progress but does not support 'hg continue'")
2501 % (contstate._opname)
2452 % (contstate._opname)
2502 ),
2453 ),
2503 hint=contstate.continuemsg(),
2454 hint=contstate.continuemsg(),
2504 )
2455 )
2505 if dryrun:
2456 if dryrun:
2506 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2457 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2507 return
2458 return
2508 return contstate.continuefunc(ui, repo)
2459 return contstate.continuefunc(ui, repo)
2509
2460
2510
2461
2511 @command(
2462 @command(
2512 b'copy|cp',
2463 b'copy|cp',
2513 [
2464 [
2514 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2465 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2515 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2466 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2516 (
2467 (
2517 b'',
2468 b'',
2518 b'at-rev',
2469 b'at-rev',
2519 b'',
2470 b'',
2520 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2471 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2521 _(b'REV'),
2472 _(b'REV'),
2522 ),
2473 ),
2523 (
2474 (
2524 b'f',
2475 b'f',
2525 b'force',
2476 b'force',
2526 None,
2477 None,
2527 _(b'forcibly copy over an existing managed file'),
2478 _(b'forcibly copy over an existing managed file'),
2528 ),
2479 ),
2529 ]
2480 ]
2530 + walkopts
2481 + walkopts
2531 + dryrunopts,
2482 + dryrunopts,
2532 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2483 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2533 helpcategory=command.CATEGORY_FILE_CONTENTS,
2484 helpcategory=command.CATEGORY_FILE_CONTENTS,
2534 )
2485 )
2535 def copy(ui, repo, *pats, **opts):
2486 def copy(ui, repo, *pats, **opts):
2536 """mark files as copied for the next commit
2487 """mark files as copied for the next commit
2537
2488
2538 Mark dest as having copies of source files. If dest is a
2489 Mark dest as having copies of source files. If dest is a
2539 directory, copies are put in that directory. If dest is a file,
2490 directory, copies are put in that directory. If dest is a file,
2540 the source must be a single file.
2491 the source must be a single file.
2541
2492
2542 By default, this command copies the contents of files as they
2493 By default, this command copies the contents of files as they
2543 exist in the working directory. If invoked with -A/--after, the
2494 exist in the working directory. If invoked with -A/--after, the
2544 operation is recorded, but no copying is performed.
2495 operation is recorded, but no copying is performed.
2545
2496
2546 To undo marking a destination file as copied, use --forget. With that
2497 To undo marking a destination file as copied, use --forget. With that
2547 option, all given (positional) arguments are unmarked as copies. The
2498 option, all given (positional) arguments are unmarked as copies. The
2548 destination file(s) will be left in place (still tracked). Note that
2499 destination file(s) will be left in place (still tracked). Note that
2549 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2500 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2550
2501
2551 This command takes effect with the next commit by default.
2502 This command takes effect with the next commit by default.
2552
2503
2553 Returns 0 on success, 1 if errors are encountered.
2504 Returns 0 on success, 1 if errors are encountered.
2554 """
2505 """
2555
2506
2556 context = lambda repo: repo.dirstate.changing_files(repo)
2507 context = lambda repo: repo.dirstate.changing_files(repo)
2557 rev = opts.get('at_rev')
2508 rev = opts.get('at_rev')
2558
2509
2559 if rev:
2510 if rev:
2560 ctx = logcmdutil.revsingle(repo, rev)
2511 ctx = logcmdutil.revsingle(repo, rev)
2561 if ctx.rev() is not None:
2512 if ctx.rev() is not None:
2562
2513
2563 def context(repo):
2514 def context(repo):
2564 return util.nullcontextmanager()
2515 return util.nullcontextmanager()
2565
2516
2566 opts['at_rev'] = ctx.rev()
2517 opts['at_rev'] = ctx.rev()
2567 with repo.wlock(), context(repo):
2518 with repo.wlock(), context(repo):
2568 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2519 return cmdutil.copy(ui, repo, pats, pycompat.byteskwargs(opts))
2569
2520
2570
2521
2571 @command(
2522 @command(
2572 b'debugcommands',
2523 b'debugcommands',
2573 [],
2524 [],
2574 _(b'[COMMAND]'),
2525 _(b'[COMMAND]'),
2575 helpcategory=command.CATEGORY_HELP,
2526 helpcategory=command.CATEGORY_HELP,
2576 norepo=True,
2527 norepo=True,
2577 )
2528 )
2578 def debugcommands(ui, cmd=b'', *args):
2529 def debugcommands(ui, cmd=b'', *args):
2579 """list all available commands and options"""
2530 """list all available commands and options"""
2580 for cmd, vals in sorted(table.items()):
2531 for cmd, vals in sorted(table.items()):
2581 cmd = cmd.split(b'|')[0]
2532 cmd = cmd.split(b'|')[0]
2582 opts = b', '.join([i[1] for i in vals[1]])
2533 opts = b', '.join([i[1] for i in vals[1]])
2583 ui.write(b'%s: %s\n' % (cmd, opts))
2534 ui.write(b'%s: %s\n' % (cmd, opts))
2584
2535
2585
2536
2586 @command(
2537 @command(
2587 b'debugcomplete',
2538 b'debugcomplete',
2588 [(b'o', b'options', None, _(b'show the command options'))],
2539 [(b'o', b'options', None, _(b'show the command options'))],
2589 _(b'[-o] CMD'),
2540 _(b'[-o] CMD'),
2590 helpcategory=command.CATEGORY_HELP,
2541 helpcategory=command.CATEGORY_HELP,
2591 norepo=True,
2542 norepo=True,
2592 )
2543 )
2593 def debugcomplete(ui, cmd=b'', **opts):
2544 def debugcomplete(ui, cmd=b'', **opts):
2594 """returns the completion list associated with the given command"""
2545 """returns the completion list associated with the given command"""
2595
2546
2596 if opts.get('options'):
2547 if opts.get('options'):
2597 options = []
2548 options = []
2598 otables = [globalopts]
2549 otables = [globalopts]
2599 if cmd:
2550 if cmd:
2600 aliases, entry = cmdutil.findcmd(cmd, table, False)
2551 aliases, entry = cmdutil.findcmd(cmd, table, False)
2601 otables.append(entry[1])
2552 otables.append(entry[1])
2602 for t in otables:
2553 for t in otables:
2603 for o in t:
2554 for o in t:
2604 if b"(DEPRECATED)" in o[3]:
2555 if b"(DEPRECATED)" in o[3]:
2605 continue
2556 continue
2606 if o[0]:
2557 if o[0]:
2607 options.append(b'-%s' % o[0])
2558 options.append(b'-%s' % o[0])
2608 options.append(b'--%s' % o[1])
2559 options.append(b'--%s' % o[1])
2609 ui.write(b"%s\n" % b"\n".join(options))
2560 ui.write(b"%s\n" % b"\n".join(options))
2610 return
2561 return
2611
2562
2612 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2563 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2613 if ui.verbose:
2564 if ui.verbose:
2614 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2565 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2615 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2566 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2616
2567
2617
2568
2618 @command(
2569 @command(
2619 b'diff',
2570 b'diff',
2620 [
2571 [
2621 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2572 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2622 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2573 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2623 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2574 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2624 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2575 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2625 ]
2576 ]
2626 + diffopts
2577 + diffopts
2627 + diffopts2
2578 + diffopts2
2628 + walkopts
2579 + walkopts
2629 + subrepoopts,
2580 + subrepoopts,
2630 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2581 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2631 helpcategory=command.CATEGORY_FILE_CONTENTS,
2582 helpcategory=command.CATEGORY_FILE_CONTENTS,
2632 helpbasic=True,
2583 helpbasic=True,
2633 inferrepo=True,
2584 inferrepo=True,
2634 intents={INTENT_READONLY},
2585 intents={INTENT_READONLY},
2635 )
2586 )
2636 def diff(ui, repo, *pats, **opts):
2587 def diff(ui, repo, *pats, **opts):
2637 """diff repository (or selected files)
2588 """diff repository (or selected files)
2638
2589
2639 Show differences between revisions for the specified files.
2590 Show differences between revisions for the specified files.
2640
2591
2641 Differences between files are shown using the unified diff format.
2592 Differences between files are shown using the unified diff format.
2642
2593
2643 .. note::
2594 .. note::
2644
2595
2645 :hg:`diff` may generate unexpected results for merges, as it will
2596 :hg:`diff` may generate unexpected results for merges, as it will
2646 default to comparing against the working directory's first
2597 default to comparing against the working directory's first
2647 parent changeset if no revisions are specified. To diff against the
2598 parent changeset if no revisions are specified. To diff against the
2648 conflict regions, you can use `--config diff.merge=yes`.
2599 conflict regions, you can use `--config diff.merge=yes`.
2649
2600
2650 By default, the working directory files are compared to its first parent. To
2601 By default, the working directory files are compared to its first parent. To
2651 see the differences from another revision, use --from. To see the difference
2602 see the differences from another revision, use --from. To see the difference
2652 to another revision, use --to. For example, :hg:`diff --from .^` will show
2603 to another revision, use --to. For example, :hg:`diff --from .^` will show
2653 the differences from the working copy's grandparent to the working copy,
2604 the differences from the working copy's grandparent to the working copy,
2654 :hg:`diff --to .` will show the diff from the working copy to its parent
2605 :hg:`diff --to .` will show the diff from the working copy to its parent
2655 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2606 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2656 show the diff between those two revisions.
2607 show the diff between those two revisions.
2657
2608
2658 Alternatively you can specify -c/--change with a revision to see the changes
2609 Alternatively you can specify -c/--change with a revision to see the changes
2659 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2610 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2660 equivalent to :hg:`diff --from 42^ --to 42`)
2611 equivalent to :hg:`diff --from 42^ --to 42`)
2661
2612
2662 Without the -a/--text option, diff will avoid generating diffs of
2613 Without the -a/--text option, diff will avoid generating diffs of
2663 files it detects as binary. With -a, diff will generate a diff
2614 files it detects as binary. With -a, diff will generate a diff
2664 anyway, probably with undesirable results.
2615 anyway, probably with undesirable results.
2665
2616
2666 Use the -g/--git option to generate diffs in the git extended diff
2617 Use the -g/--git option to generate diffs in the git extended diff
2667 format. For more information, read :hg:`help diffs`.
2618 format. For more information, read :hg:`help diffs`.
2668
2619
2669 .. container:: verbose
2620 .. container:: verbose
2670
2621
2671 Examples:
2622 Examples:
2672
2623
2673 - compare a file in the current working directory to its parent::
2624 - compare a file in the current working directory to its parent::
2674
2625
2675 hg diff foo.c
2626 hg diff foo.c
2676
2627
2677 - compare two historical versions of a directory, with rename info::
2628 - compare two historical versions of a directory, with rename info::
2678
2629
2679 hg diff --git --from 1.0 --to 1.2 lib/
2630 hg diff --git --from 1.0 --to 1.2 lib/
2680
2631
2681 - get change stats relative to the last change on some date::
2632 - get change stats relative to the last change on some date::
2682
2633
2683 hg diff --stat --from "date('may 2')"
2634 hg diff --stat --from "date('may 2')"
2684
2635
2685 - diff all newly-added files that contain a keyword::
2636 - diff all newly-added files that contain a keyword::
2686
2637
2687 hg diff "set:added() and grep(GNU)"
2638 hg diff "set:added() and grep(GNU)"
2688
2639
2689 - compare a revision and its parents::
2640 - compare a revision and its parents::
2690
2641
2691 hg diff -c 9353 # compare against first parent
2642 hg diff -c 9353 # compare against first parent
2692 hg diff --from 9353^ --to 9353 # same using revset syntax
2643 hg diff --from 9353^ --to 9353 # same using revset syntax
2693 hg diff --from 9353^2 --to 9353 # compare against the second parent
2644 hg diff --from 9353^2 --to 9353 # compare against the second parent
2694
2645
2695 Returns 0 on success.
2646 Returns 0 on success.
2696 """
2647 """
2697
2648
2698 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2649 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2699 opts = pycompat.byteskwargs(opts)
2650 opts = pycompat.byteskwargs(opts)
2700 revs = opts.get(b'rev')
2651 revs = opts.get(b'rev')
2701 change = opts.get(b'change')
2652 change = opts.get(b'change')
2702 from_rev = opts.get(b'from')
2653 from_rev = opts.get(b'from')
2703 to_rev = opts.get(b'to')
2654 to_rev = opts.get(b'to')
2704 stat = opts.get(b'stat')
2655 stat = opts.get(b'stat')
2705 reverse = opts.get(b'reverse')
2656 reverse = opts.get(b'reverse')
2706
2657
2707 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2658 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2708 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2659 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2709 if change:
2660 if change:
2710 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2661 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2711 ctx2 = logcmdutil.revsingle(repo, change, None)
2662 ctx2 = logcmdutil.revsingle(repo, change, None)
2712 ctx1 = diffutil.diff_parent(ctx2)
2663 ctx1 = diffutil.diff_parent(ctx2)
2713 elif from_rev or to_rev:
2664 elif from_rev or to_rev:
2714 repo = scmutil.unhidehashlikerevs(
2665 repo = scmutil.unhidehashlikerevs(
2715 repo, [from_rev] + [to_rev], b'nowarn'
2666 repo, [from_rev] + [to_rev], b'nowarn'
2716 )
2667 )
2717 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2668 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2718 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2669 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2719 else:
2670 else:
2720 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2671 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2721 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2672 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2722
2673
2723 if reverse:
2674 if reverse:
2724 ctxleft = ctx2
2675 ctxleft = ctx2
2725 ctxright = ctx1
2676 ctxright = ctx1
2726 else:
2677 else:
2727 ctxleft = ctx1
2678 ctxleft = ctx1
2728 ctxright = ctx2
2679 ctxright = ctx2
2729
2680
2730 diffopts = patch.diffallopts(ui, opts)
2681 diffopts = patch.diffallopts(ui, opts)
2731 m = scmutil.match(ctx2, pats, opts)
2682 m = scmutil.match(ctx2, pats, opts)
2732 m = repo.narrowmatch(m)
2683 m = repo.narrowmatch(m)
2733 ui.pager(b'diff')
2684 ui.pager(b'diff')
2734 logcmdutil.diffordiffstat(
2685 logcmdutil.diffordiffstat(
2735 ui,
2686 ui,
2736 repo,
2687 repo,
2737 diffopts,
2688 diffopts,
2738 ctxleft,
2689 ctxleft,
2739 ctxright,
2690 ctxright,
2740 m,
2691 m,
2741 stat=stat,
2692 stat=stat,
2742 listsubrepos=opts.get(b'subrepos'),
2693 listsubrepos=opts.get(b'subrepos'),
2743 root=opts.get(b'root'),
2694 root=opts.get(b'root'),
2744 )
2695 )
2745
2696
2746
2697
2747 @command(
2698 @command(
2748 b'export',
2699 b'export',
2749 [
2700 [
2750 (
2701 (
2751 b'B',
2702 b'B',
2752 b'bookmark',
2703 b'bookmark',
2753 b'',
2704 b'',
2754 _(b'export changes only reachable by given bookmark'),
2705 _(b'export changes only reachable by given bookmark'),
2755 _(b'BOOKMARK'),
2706 _(b'BOOKMARK'),
2756 ),
2707 ),
2757 (
2708 (
2758 b'o',
2709 b'o',
2759 b'output',
2710 b'output',
2760 b'',
2711 b'',
2761 _(b'print output to file with formatted name'),
2712 _(b'print output to file with formatted name'),
2762 _(b'FORMAT'),
2713 _(b'FORMAT'),
2763 ),
2714 ),
2764 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2715 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2765 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2716 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2766 ]
2717 ]
2767 + diffopts
2718 + diffopts
2768 + formatteropts,
2719 + formatteropts,
2769 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2720 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2770 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2721 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2771 helpbasic=True,
2722 helpbasic=True,
2772 intents={INTENT_READONLY},
2723 intents={INTENT_READONLY},
2773 )
2724 )
2774 def export(ui, repo, *changesets, **opts):
2725 def export(ui, repo, *changesets, **opts):
2775 """dump the header and diffs for one or more changesets
2726 """dump the header and diffs for one or more changesets
2776
2727
2777 Print the changeset header and diffs for one or more revisions.
2728 Print the changeset header and diffs for one or more revisions.
2778 If no revision is given, the parent of the working directory is used.
2729 If no revision is given, the parent of the working directory is used.
2779
2730
2780 The information shown in the changeset header is: author, date,
2731 The information shown in the changeset header is: author, date,
2781 branch name (if non-default), changeset hash, parent(s) and commit
2732 branch name (if non-default), changeset hash, parent(s) and commit
2782 comment.
2733 comment.
2783
2734
2784 .. note::
2735 .. note::
2785
2736
2786 :hg:`export` may generate unexpected diff output for merge
2737 :hg:`export` may generate unexpected diff output for merge
2787 changesets, as it will compare the merge changeset against its
2738 changesets, as it will compare the merge changeset against its
2788 first parent only.
2739 first parent only.
2789
2740
2790 Output may be to a file, in which case the name of the file is
2741 Output may be to a file, in which case the name of the file is
2791 given using a template string. See :hg:`help templates`. In addition
2742 given using a template string. See :hg:`help templates`. In addition
2792 to the common template keywords, the following formatting rules are
2743 to the common template keywords, the following formatting rules are
2793 supported:
2744 supported:
2794
2745
2795 :``%%``: literal "%" character
2746 :``%%``: literal "%" character
2796 :``%H``: changeset hash (40 hexadecimal digits)
2747 :``%H``: changeset hash (40 hexadecimal digits)
2797 :``%N``: number of patches being generated
2748 :``%N``: number of patches being generated
2798 :``%R``: changeset revision number
2749 :``%R``: changeset revision number
2799 :``%b``: basename of the exporting repository
2750 :``%b``: basename of the exporting repository
2800 :``%h``: short-form changeset hash (12 hexadecimal digits)
2751 :``%h``: short-form changeset hash (12 hexadecimal digits)
2801 :``%m``: first line of the commit message (only alphanumeric characters)
2752 :``%m``: first line of the commit message (only alphanumeric characters)
2802 :``%n``: zero-padded sequence number, starting at 1
2753 :``%n``: zero-padded sequence number, starting at 1
2803 :``%r``: zero-padded changeset revision number
2754 :``%r``: zero-padded changeset revision number
2804 :``\\``: literal "\\" character
2755 :``\\``: literal "\\" character
2805
2756
2806 Without the -a/--text option, export will avoid generating diffs
2757 Without the -a/--text option, export will avoid generating diffs
2807 of files it detects as binary. With -a, export will generate a
2758 of files it detects as binary. With -a, export will generate a
2808 diff anyway, probably with undesirable results.
2759 diff anyway, probably with undesirable results.
2809
2760
2810 With -B/--bookmark changesets reachable by the given bookmark are
2761 With -B/--bookmark changesets reachable by the given bookmark are
2811 selected.
2762 selected.
2812
2763
2813 Use the -g/--git option to generate diffs in the git extended diff
2764 Use the -g/--git option to generate diffs in the git extended diff
2814 format. See :hg:`help diffs` for more information.
2765 format. See :hg:`help diffs` for more information.
2815
2766
2816 With the --switch-parent option, the diff will be against the
2767 With the --switch-parent option, the diff will be against the
2817 second parent. It can be useful to review a merge.
2768 second parent. It can be useful to review a merge.
2818
2769
2819 .. container:: verbose
2770 .. container:: verbose
2820
2771
2821 Template:
2772 Template:
2822
2773
2823 The following keywords are supported in addition to the common template
2774 The following keywords are supported in addition to the common template
2824 keywords and functions. See also :hg:`help templates`.
2775 keywords and functions. See also :hg:`help templates`.
2825
2776
2826 :diff: String. Diff content.
2777 :diff: String. Diff content.
2827 :parents: List of strings. Parent nodes of the changeset.
2778 :parents: List of strings. Parent nodes of the changeset.
2828
2779
2829 Examples:
2780 Examples:
2830
2781
2831 - use export and import to transplant a bugfix to the current
2782 - use export and import to transplant a bugfix to the current
2832 branch::
2783 branch::
2833
2784
2834 hg export -r 9353 | hg import -
2785 hg export -r 9353 | hg import -
2835
2786
2836 - export all the changesets between two revisions to a file with
2787 - export all the changesets between two revisions to a file with
2837 rename information::
2788 rename information::
2838
2789
2839 hg export --git -r 123:150 > changes.txt
2790 hg export --git -r 123:150 > changes.txt
2840
2791
2841 - split outgoing changes into a series of patches with
2792 - split outgoing changes into a series of patches with
2842 descriptive names::
2793 descriptive names::
2843
2794
2844 hg export -r "outgoing()" -o "%n-%m.patch"
2795 hg export -r "outgoing()" -o "%n-%m.patch"
2845
2796
2846 Returns 0 on success.
2797 Returns 0 on success.
2847 """
2798 """
2848 opts = pycompat.byteskwargs(opts)
2799 opts = pycompat.byteskwargs(opts)
2849 bookmark = opts.get(b'bookmark')
2800 bookmark = opts.get(b'bookmark')
2850 changesets += tuple(opts.get(b'rev', []))
2801 changesets += tuple(opts.get(b'rev', []))
2851
2802
2852 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2803 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2853
2804
2854 if bookmark:
2805 if bookmark:
2855 if bookmark not in repo._bookmarks:
2806 if bookmark not in repo._bookmarks:
2856 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2807 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2857
2808
2858 revs = scmutil.bookmarkrevs(repo, bookmark)
2809 revs = scmutil.bookmarkrevs(repo, bookmark)
2859 else:
2810 else:
2860 if not changesets:
2811 if not changesets:
2861 changesets = [b'.']
2812 changesets = [b'.']
2862
2813
2863 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2814 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2864 revs = logcmdutil.revrange(repo, changesets)
2815 revs = logcmdutil.revrange(repo, changesets)
2865
2816
2866 if not revs:
2817 if not revs:
2867 raise error.InputError(_(b"export requires at least one changeset"))
2818 raise error.InputError(_(b"export requires at least one changeset"))
2868 if len(revs) > 1:
2819 if len(revs) > 1:
2869 ui.note(_(b'exporting patches:\n'))
2820 ui.note(_(b'exporting patches:\n'))
2870 else:
2821 else:
2871 ui.note(_(b'exporting patch:\n'))
2822 ui.note(_(b'exporting patch:\n'))
2872
2823
2873 fntemplate = opts.get(b'output')
2824 fntemplate = opts.get(b'output')
2874 if cmdutil.isstdiofilename(fntemplate):
2825 if cmdutil.isstdiofilename(fntemplate):
2875 fntemplate = b''
2826 fntemplate = b''
2876
2827
2877 if fntemplate:
2828 if fntemplate:
2878 fm = formatter.nullformatter(ui, b'export', opts)
2829 fm = formatter.nullformatter(ui, b'export', opts)
2879 else:
2830 else:
2880 ui.pager(b'export')
2831 ui.pager(b'export')
2881 fm = ui.formatter(b'export', opts)
2832 fm = ui.formatter(b'export', opts)
2882 with fm:
2833 with fm:
2883 cmdutil.export(
2834 cmdutil.export(
2884 repo,
2835 repo,
2885 revs,
2836 revs,
2886 fm,
2837 fm,
2887 fntemplate=fntemplate,
2838 fntemplate=fntemplate,
2888 switch_parent=opts.get(b'switch_parent'),
2839 switch_parent=opts.get(b'switch_parent'),
2889 opts=patch.diffallopts(ui, opts),
2840 opts=patch.diffallopts(ui, opts),
2890 )
2841 )
2891
2842
2892
2843
2893 @command(
2844 @command(
2894 b'files',
2845 b'files',
2895 [
2846 [
2896 (
2847 (
2897 b'r',
2848 b'r',
2898 b'rev',
2849 b'rev',
2899 b'',
2850 b'',
2900 _(b'search the repository as it is in REV'),
2851 _(b'search the repository as it is in REV'),
2901 _(b'REV'),
2852 _(b'REV'),
2902 ),
2853 ),
2903 (
2854 (
2904 b'0',
2855 b'0',
2905 b'print0',
2856 b'print0',
2906 None,
2857 None,
2907 _(b'end filenames with NUL, for use with xargs'),
2858 _(b'end filenames with NUL, for use with xargs'),
2908 ),
2859 ),
2909 ]
2860 ]
2910 + walkopts
2861 + walkopts
2911 + formatteropts
2862 + formatteropts
2912 + subrepoopts,
2863 + subrepoopts,
2913 _(b'[OPTION]... [FILE]...'),
2864 _(b'[OPTION]... [FILE]...'),
2914 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2865 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2915 intents={INTENT_READONLY},
2866 intents={INTENT_READONLY},
2916 )
2867 )
2917 def files(ui, repo, *pats, **opts):
2868 def files(ui, repo, *pats, **opts):
2918 """list tracked files
2869 """list tracked files
2919
2870
2920 Print files under Mercurial control in the working directory or
2871 Print files under Mercurial control in the working directory or
2921 specified revision for given files (excluding removed files).
2872 specified revision for given files (excluding removed files).
2922 Files can be specified as filenames or filesets.
2873 Files can be specified as filenames or filesets.
2923
2874
2924 If no files are given to match, this command prints the names
2875 If no files are given to match, this command prints the names
2925 of all files under Mercurial control.
2876 of all files under Mercurial control.
2926
2877
2927 .. container:: verbose
2878 .. container:: verbose
2928
2879
2929 Template:
2880 Template:
2930
2881
2931 The following keywords are supported in addition to the common template
2882 The following keywords are supported in addition to the common template
2932 keywords and functions. See also :hg:`help templates`.
2883 keywords and functions. See also :hg:`help templates`.
2933
2884
2934 :flags: String. Character denoting file's symlink and executable bits.
2885 :flags: String. Character denoting file's symlink and executable bits.
2935 :path: String. Repository-absolute path of the file.
2886 :path: String. Repository-absolute path of the file.
2936 :size: Integer. Size of the file in bytes.
2887 :size: Integer. Size of the file in bytes.
2937
2888
2938 Examples:
2889 Examples:
2939
2890
2940 - list all files under the current directory::
2891 - list all files under the current directory::
2941
2892
2942 hg files .
2893 hg files .
2943
2894
2944 - shows sizes and flags for current revision::
2895 - shows sizes and flags for current revision::
2945
2896
2946 hg files -vr .
2897 hg files -vr .
2947
2898
2948 - list all files named README::
2899 - list all files named README::
2949
2900
2950 hg files -I "**/README"
2901 hg files -I "**/README"
2951
2902
2952 - list all binary files::
2903 - list all binary files::
2953
2904
2954 hg files "set:binary()"
2905 hg files "set:binary()"
2955
2906
2956 - find files containing a regular expression::
2907 - find files containing a regular expression::
2957
2908
2958 hg files "set:grep('bob')"
2909 hg files "set:grep('bob')"
2959
2910
2960 - search tracked file contents with xargs and grep::
2911 - search tracked file contents with xargs and grep::
2961
2912
2962 hg files -0 | xargs -0 grep foo
2913 hg files -0 | xargs -0 grep foo
2963
2914
2964 See :hg:`help patterns` and :hg:`help filesets` for more information
2915 See :hg:`help patterns` and :hg:`help filesets` for more information
2965 on specifying file patterns.
2916 on specifying file patterns.
2966
2917
2967 Returns 0 if a match is found, 1 otherwise.
2918 Returns 0 if a match is found, 1 otherwise.
2968
2919
2969 """
2920 """
2970
2921
2971 opts = pycompat.byteskwargs(opts)
2922 opts = pycompat.byteskwargs(opts)
2972 rev = opts.get(b'rev')
2923 rev = opts.get(b'rev')
2973 if rev:
2924 if rev:
2974 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2925 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2975 ctx = logcmdutil.revsingle(repo, rev, None)
2926 ctx = logcmdutil.revsingle(repo, rev, None)
2976
2927
2977 end = b'\n'
2928 end = b'\n'
2978 if opts.get(b'print0'):
2929 if opts.get(b'print0'):
2979 end = b'\0'
2930 end = b'\0'
2980 fmt = b'%s' + end
2931 fmt = b'%s' + end
2981
2932
2982 m = scmutil.match(ctx, pats, opts)
2933 m = scmutil.match(ctx, pats, opts)
2983 ui.pager(b'files')
2934 ui.pager(b'files')
2984 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2935 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2985 with ui.formatter(b'files', opts) as fm:
2936 with ui.formatter(b'files', opts) as fm:
2986 return cmdutil.files(
2937 return cmdutil.files(
2987 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2938 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2988 )
2939 )
2989
2940
2990
2941
2991 @command(
2942 @command(
2992 b'forget',
2943 b'forget',
2993 [
2944 [
2994 (b'i', b'interactive', None, _(b'use interactive mode')),
2945 (b'i', b'interactive', None, _(b'use interactive mode')),
2995 ]
2946 ]
2996 + walkopts
2947 + walkopts
2997 + dryrunopts,
2948 + dryrunopts,
2998 _(b'[OPTION]... FILE...'),
2949 _(b'[OPTION]... FILE...'),
2999 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2950 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
3000 helpbasic=True,
2951 helpbasic=True,
3001 inferrepo=True,
2952 inferrepo=True,
3002 )
2953 )
3003 def forget(ui, repo, *pats, **opts):
2954 def forget(ui, repo, *pats, **opts):
3004 """forget the specified files on the next commit
2955 """forget the specified files on the next commit
3005
2956
3006 Mark the specified files so they will no longer be tracked
2957 Mark the specified files so they will no longer be tracked
3007 after the next commit.
2958 after the next commit.
3008
2959
3009 This only removes files from the current branch, not from the
2960 This only removes files from the current branch, not from the
3010 entire project history, and it does not delete them from the
2961 entire project history, and it does not delete them from the
3011 working directory.
2962 working directory.
3012
2963
3013 To delete the file from the working directory, see :hg:`remove`.
2964 To delete the file from the working directory, see :hg:`remove`.
3014
2965
3015 To undo a forget before the next commit, see :hg:`add`.
2966 To undo a forget before the next commit, see :hg:`add`.
3016
2967
3017 .. container:: verbose
2968 .. container:: verbose
3018
2969
3019 Examples:
2970 Examples:
3020
2971
3021 - forget newly-added binary files::
2972 - forget newly-added binary files::
3022
2973
3023 hg forget "set:added() and binary()"
2974 hg forget "set:added() and binary()"
3024
2975
3025 - forget files that would be excluded by .hgignore::
2976 - forget files that would be excluded by .hgignore::
3026
2977
3027 hg forget "set:hgignore()"
2978 hg forget "set:hgignore()"
3028
2979
3029 Returns 0 on success.
2980 Returns 0 on success.
3030 """
2981 """
3031
2982
3032 if not pats:
2983 if not pats:
3033 raise error.InputError(_(b'no files specified'))
2984 raise error.InputError(_(b'no files specified'))
3034
2985
3035 with repo.wlock(), repo.dirstate.changing_files(repo):
2986 with repo.wlock(), repo.dirstate.changing_files(repo):
3036 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
2987 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
3037 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2988 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
3038 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2989 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
3039 rejected = cmdutil.forget(
2990 rejected = cmdutil.forget(
3040 ui,
2991 ui,
3041 repo,
2992 repo,
3042 m,
2993 m,
3043 prefix=b"",
2994 prefix=b"",
3044 uipathfn=uipathfn,
2995 uipathfn=uipathfn,
3045 explicitonly=False,
2996 explicitonly=False,
3046 dryrun=dryrun,
2997 dryrun=dryrun,
3047 interactive=interactive,
2998 interactive=interactive,
3048 )[0]
2999 )[0]
3049 return rejected and 1 or 0
3000 return rejected and 1 or 0
3050
3001
3051
3002
3052 @command(
3003 @command(
3053 b'graft',
3004 b'graft',
3054 [
3005 [
3055 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3006 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
3056 (
3007 (
3057 b'',
3008 b'',
3058 b'base',
3009 b'base',
3059 b'',
3010 b'',
3060 _(b'base revision when doing the graft merge (ADVANCED)'),
3011 _(b'base revision when doing the graft merge (ADVANCED)'),
3061 _(b'REV'),
3012 _(b'REV'),
3062 ),
3013 ),
3063 (b'c', b'continue', False, _(b'resume interrupted graft')),
3014 (b'c', b'continue', False, _(b'resume interrupted graft')),
3064 (b'', b'stop', False, _(b'stop interrupted graft')),
3015 (b'', b'stop', False, _(b'stop interrupted graft')),
3065 (b'', b'abort', False, _(b'abort interrupted graft')),
3016 (b'', b'abort', False, _(b'abort interrupted graft')),
3066 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3017 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3067 (b'', b'log', None, _(b'append graft info to log message')),
3018 (b'', b'log', None, _(b'append graft info to log message')),
3068 (
3019 (
3069 b'',
3020 b'',
3070 b'no-commit',
3021 b'no-commit',
3071 None,
3022 None,
3072 _(b"don't commit, just apply the changes in working directory"),
3023 _(b"don't commit, just apply the changes in working directory"),
3073 ),
3024 ),
3074 (b'f', b'force', False, _(b'force graft')),
3025 (b'f', b'force', False, _(b'force graft')),
3075 (
3026 (
3076 b'D',
3027 b'D',
3077 b'currentdate',
3028 b'currentdate',
3078 False,
3029 False,
3079 _(b'record the current date as commit date'),
3030 _(b'record the current date as commit date'),
3080 ),
3031 ),
3081 (
3032 (
3082 b'U',
3033 b'U',
3083 b'currentuser',
3034 b'currentuser',
3084 False,
3035 False,
3085 _(b'record the current user as committer'),
3036 _(b'record the current user as committer'),
3086 ),
3037 ),
3087 ]
3038 ]
3088 + commitopts2
3039 + commitopts2
3089 + mergetoolopts
3040 + mergetoolopts
3090 + dryrunopts,
3041 + dryrunopts,
3091 _(b'[OPTION]... [-r REV]... REV...'),
3042 _(b'[OPTION]... [-r REV]... REV...'),
3092 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3043 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
3093 )
3044 )
3094 def graft(ui, repo, *revs, **opts):
3045 def graft(ui, repo, *revs, **opts):
3095 """copy changes from other branches onto the current branch
3046 """copy changes from other branches onto the current branch
3096
3047
3097 This command uses Mercurial's merge logic to copy individual
3048 This command uses Mercurial's merge logic to copy individual
3098 changes from other branches without merging branches in the
3049 changes from other branches without merging branches in the
3099 history graph. This is sometimes known as 'backporting' or
3050 history graph. This is sometimes known as 'backporting' or
3100 'cherry-picking'. By default, graft will copy user, date, and
3051 'cherry-picking'. By default, graft will copy user, date, and
3101 description from the source changesets.
3052 description from the source changesets.
3102
3053
3103 Changesets that are ancestors of the current revision, that have
3054 Changesets that are ancestors of the current revision, that have
3104 already been grafted, or that are merges will be skipped.
3055 already been grafted, or that are merges will be skipped.
3105
3056
3106 If --log is specified, log messages will have a comment appended
3057 If --log is specified, log messages will have a comment appended
3107 of the form::
3058 of the form::
3108
3059
3109 (grafted from CHANGESETHASH)
3060 (grafted from CHANGESETHASH)
3110
3061
3111 If --force is specified, revisions will be grafted even if they
3062 If --force is specified, revisions will be grafted even if they
3112 are already ancestors of, or have been grafted to, the destination.
3063 are already ancestors of, or have been grafted to, the destination.
3113 This is useful when the revisions have since been backed out.
3064 This is useful when the revisions have since been backed out.
3114
3065
3115 If a graft merge results in conflicts, the graft process is
3066 If a graft merge results in conflicts, the graft process is
3116 interrupted so that the current merge can be manually resolved.
3067 interrupted so that the current merge can be manually resolved.
3117 Once all conflicts are addressed, the graft process can be
3068 Once all conflicts are addressed, the graft process can be
3118 continued with the -c/--continue option.
3069 continued with the -c/--continue option.
3119
3070
3120 The -c/--continue option reapplies all the earlier options.
3071 The -c/--continue option reapplies all the earlier options.
3121
3072
3122 .. container:: verbose
3073 .. container:: verbose
3123
3074
3124 The --base option exposes more of how graft internally uses merge with a
3075 The --base option exposes more of how graft internally uses merge with a
3125 custom base revision. --base can be used to specify another ancestor than
3076 custom base revision. --base can be used to specify another ancestor than
3126 the first and only parent.
3077 the first and only parent.
3127
3078
3128 The command::
3079 The command::
3129
3080
3130 hg graft -r 345 --base 234
3081 hg graft -r 345 --base 234
3131
3082
3132 is thus pretty much the same as::
3083 is thus pretty much the same as::
3133
3084
3134 hg diff --from 234 --to 345 | hg import
3085 hg diff --from 234 --to 345 | hg import
3135
3086
3136 but using merge to resolve conflicts and track moved files.
3087 but using merge to resolve conflicts and track moved files.
3137
3088
3138 The result of a merge can thus be backported as a single commit by
3089 The result of a merge can thus be backported as a single commit by
3139 specifying one of the merge parents as base, and thus effectively
3090 specifying one of the merge parents as base, and thus effectively
3140 grafting the changes from the other side.
3091 grafting the changes from the other side.
3141
3092
3142 It is also possible to collapse multiple changesets and clean up history
3093 It is also possible to collapse multiple changesets and clean up history
3143 by specifying another ancestor as base, much like rebase --collapse
3094 by specifying another ancestor as base, much like rebase --collapse
3144 --keep.
3095 --keep.
3145
3096
3146 The commit message can be tweaked after the fact using commit --amend .
3097 The commit message can be tweaked after the fact using commit --amend .
3147
3098
3148 For using non-ancestors as the base to backout changes, see the backout
3099 For using non-ancestors as the base to backout changes, see the backout
3149 command and the hidden --parent option.
3100 command and the hidden --parent option.
3150
3101
3151 .. container:: verbose
3102 .. container:: verbose
3152
3103
3153 Examples:
3104 Examples:
3154
3105
3155 - copy a single change to the stable branch and edit its description::
3106 - copy a single change to the stable branch and edit its description::
3156
3107
3157 hg update stable
3108 hg update stable
3158 hg graft --edit 9393
3109 hg graft --edit 9393
3159
3110
3160 - graft a range of changesets with one exception, updating dates::
3111 - graft a range of changesets with one exception, updating dates::
3161
3112
3162 hg graft -D "2085::2093 and not 2091"
3113 hg graft -D "2085::2093 and not 2091"
3163
3114
3164 - continue a graft after resolving conflicts::
3115 - continue a graft after resolving conflicts::
3165
3116
3166 hg graft -c
3117 hg graft -c
3167
3118
3168 - show the source of a grafted changeset::
3119 - show the source of a grafted changeset::
3169
3120
3170 hg log --debug -r .
3121 hg log --debug -r .
3171
3122
3172 - show revisions sorted by date::
3123 - show revisions sorted by date::
3173
3124
3174 hg log -r "sort(all(), date)"
3125 hg log -r "sort(all(), date)"
3175
3126
3176 - backport the result of a merge as a single commit::
3127 - backport the result of a merge as a single commit::
3177
3128
3178 hg graft -r 123 --base 123^
3129 hg graft -r 123 --base 123^
3179
3130
3180 - land a feature branch as one changeset::
3131 - land a feature branch as one changeset::
3181
3132
3182 hg up -cr default
3133 hg up -cr default
3183 hg graft -r featureX --base "ancestor('featureX', 'default')"
3134 hg graft -r featureX --base "ancestor('featureX', 'default')"
3184
3135
3185 See :hg:`help revisions` for more about specifying revisions.
3136 See :hg:`help revisions` for more about specifying revisions.
3186
3137
3187 Returns 0 on successful completion, 1 if there are unresolved files.
3138 Returns 0 on successful completion, 1 if there are unresolved files.
3188 """
3139 """
3189 with repo.wlock():
3140 with repo.wlock():
3190 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3141 return graft_impl.cmd_graft(ui, repo, *revs, **opts)
3191
3142
3192
3143
3193 statemod.addunfinished(
3144 statemod.addunfinished(
3194 b'graft',
3145 b'graft',
3195 fname=b'graftstate',
3146 fname=b'graftstate',
3196 clearable=True,
3147 clearable=True,
3197 stopflag=True,
3148 stopflag=True,
3198 continueflag=True,
3149 continueflag=True,
3199 abortfunc=cmdutil.hgabortgraft,
3150 abortfunc=cmdutil.hgabortgraft,
3200 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3151 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3201 )
3152 )
3202
3153
3203
3154
3204 @command(
3155 @command(
3205 b'grep',
3156 b'grep',
3206 [
3157 [
3207 (b'0', b'print0', None, _(b'end fields with NUL')),
3158 (b'0', b'print0', None, _(b'end fields with NUL')),
3208 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3159 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3209 (
3160 (
3210 b'',
3161 b'',
3211 b'diff',
3162 b'diff',
3212 None,
3163 None,
3213 _(
3164 _(
3214 b'search revision differences for when the pattern was added '
3165 b'search revision differences for when the pattern was added '
3215 b'or removed'
3166 b'or removed'
3216 ),
3167 ),
3217 ),
3168 ),
3218 (b'a', b'text', None, _(b'treat all files as text')),
3169 (b'a', b'text', None, _(b'treat all files as text')),
3219 (
3170 (
3220 b'f',
3171 b'f',
3221 b'follow',
3172 b'follow',
3222 None,
3173 None,
3223 _(
3174 _(
3224 b'follow changeset history,'
3175 b'follow changeset history,'
3225 b' or file history across copies and renames'
3176 b' or file history across copies and renames'
3226 ),
3177 ),
3227 ),
3178 ),
3228 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3179 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3229 (
3180 (
3230 b'l',
3181 b'l',
3231 b'files-with-matches',
3182 b'files-with-matches',
3232 None,
3183 None,
3233 _(b'print only filenames and revisions that match'),
3184 _(b'print only filenames and revisions that match'),
3234 ),
3185 ),
3235 (b'n', b'line-number', None, _(b'print matching line numbers')),
3186 (b'n', b'line-number', None, _(b'print matching line numbers')),
3236 (
3187 (
3237 b'r',
3188 b'r',
3238 b'rev',
3189 b'rev',
3239 [],
3190 [],
3240 _(b'search files changed within revision range'),
3191 _(b'search files changed within revision range'),
3241 _(b'REV'),
3192 _(b'REV'),
3242 ),
3193 ),
3243 (
3194 (
3244 b'',
3195 b'',
3245 b'all-files',
3196 b'all-files',
3246 None,
3197 None,
3247 _(
3198 _(
3248 b'include all files in the changeset while grepping (DEPRECATED)'
3199 b'include all files in the changeset while grepping (DEPRECATED)'
3249 ),
3200 ),
3250 ),
3201 ),
3251 (b'u', b'user', None, _(b'list the author (long with -v)')),
3202 (b'u', b'user', None, _(b'list the author (long with -v)')),
3252 (b'd', b'date', None, _(b'list the date (short with -q)')),
3203 (b'd', b'date', None, _(b'list the date (short with -q)')),
3253 ]
3204 ]
3254 + formatteropts
3205 + formatteropts
3255 + walkopts,
3206 + walkopts,
3256 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3207 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3257 helpcategory=command.CATEGORY_FILE_CONTENTS,
3208 helpcategory=command.CATEGORY_FILE_CONTENTS,
3258 inferrepo=True,
3209 inferrepo=True,
3259 intents={INTENT_READONLY},
3210 intents={INTENT_READONLY},
3260 )
3211 )
3261 def grep(ui, repo, pattern, *pats, **opts):
3212 def grep(ui, repo, pattern, *pats, **opts):
3262 """search for a pattern in specified files
3213 """search for a pattern in specified files
3263
3214
3264 Search the working directory or revision history for a regular
3215 Search the working directory or revision history for a regular
3265 expression in the specified files for the entire repository.
3216 expression in the specified files for the entire repository.
3266
3217
3267 By default, grep searches the repository files in the working
3218 By default, grep searches the repository files in the working
3268 directory and prints the files where it finds a match. To specify
3219 directory and prints the files where it finds a match. To specify
3269 historical revisions instead of the working directory, use the
3220 historical revisions instead of the working directory, use the
3270 --rev flag.
3221 --rev flag.
3271
3222
3272 To search instead historical revision differences that contains a
3223 To search instead historical revision differences that contains a
3273 change in match status ("-" for a match that becomes a non-match,
3224 change in match status ("-" for a match that becomes a non-match,
3274 or "+" for a non-match that becomes a match), use the --diff flag.
3225 or "+" for a non-match that becomes a match), use the --diff flag.
3275
3226
3276 PATTERN can be any Python (roughly Perl-compatible) regular
3227 PATTERN can be any Python (roughly Perl-compatible) regular
3277 expression.
3228 expression.
3278
3229
3279 If no FILEs are specified and the --rev flag isn't supplied, all
3230 If no FILEs are specified and the --rev flag isn't supplied, all
3280 files in the working directory are searched. When using the --rev
3231 files in the working directory are searched. When using the --rev
3281 flag and specifying FILEs, use the --follow argument to also
3232 flag and specifying FILEs, use the --follow argument to also
3282 follow the specified FILEs across renames and copies.
3233 follow the specified FILEs across renames and copies.
3283
3234
3284 .. container:: verbose
3235 .. container:: verbose
3285
3236
3286 Template:
3237 Template:
3287
3238
3288 The following keywords are supported in addition to the common template
3239 The following keywords are supported in addition to the common template
3289 keywords and functions. See also :hg:`help templates`.
3240 keywords and functions. See also :hg:`help templates`.
3290
3241
3291 :change: String. Character denoting insertion ``+`` or removal ``-``.
3242 :change: String. Character denoting insertion ``+`` or removal ``-``.
3292 Available if ``--diff`` is specified.
3243 Available if ``--diff`` is specified.
3293 :lineno: Integer. Line number of the match.
3244 :lineno: Integer. Line number of the match.
3294 :path: String. Repository-absolute path of the file.
3245 :path: String. Repository-absolute path of the file.
3295 :texts: List of text chunks.
3246 :texts: List of text chunks.
3296
3247
3297 And each entry of ``{texts}`` provides the following sub-keywords.
3248 And each entry of ``{texts}`` provides the following sub-keywords.
3298
3249
3299 :matched: Boolean. True if the chunk matches the specified pattern.
3250 :matched: Boolean. True if the chunk matches the specified pattern.
3300 :text: String. Chunk content.
3251 :text: String. Chunk content.
3301
3252
3302 See :hg:`help templates.operators` for the list expansion syntax.
3253 See :hg:`help templates.operators` for the list expansion syntax.
3303
3254
3304 Returns 0 if a match is found, 1 otherwise.
3255 Returns 0 if a match is found, 1 otherwise.
3305
3256
3306 """
3257 """
3307 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3258 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3308
3259
3309 diff = opts.get('all') or opts.get('diff')
3260 diff = opts.get('all') or opts.get('diff')
3310 follow = opts.get('follow')
3261 follow = opts.get('follow')
3311 if opts.get('all_files') is None and not diff:
3262 if opts.get('all_files') is None and not diff:
3312 opts['all_files'] = True
3263 opts['all_files'] = True
3313 plaingrep = (
3264 plaingrep = (
3314 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3265 opts.get('all_files') and not opts.get('rev') and not opts.get('follow')
3315 )
3266 )
3316 all_files = opts.get('all_files')
3267 all_files = opts.get('all_files')
3317 if plaingrep:
3268 if plaingrep:
3318 opts['rev'] = [b'wdir()']
3269 opts['rev'] = [b'wdir()']
3319
3270
3320 reflags = re.M
3271 reflags = re.M
3321 if opts.get('ignore_case'):
3272 if opts.get('ignore_case'):
3322 reflags |= re.I
3273 reflags |= re.I
3323 try:
3274 try:
3324 regexp = util.re.compile(pattern, reflags)
3275 regexp = util.re.compile(pattern, reflags)
3325 except re.error as inst:
3276 except re.error as inst:
3326 ui.warn(
3277 ui.warn(
3327 _(b"grep: invalid match pattern: %s\n")
3278 _(b"grep: invalid match pattern: %s\n")
3328 % stringutil.forcebytestr(inst)
3279 % stringutil.forcebytestr(inst)
3329 )
3280 )
3330 return 1
3281 return 1
3331 sep, eol = b':', b'\n'
3282 sep, eol = b':', b'\n'
3332 if opts.get('print0'):
3283 if opts.get('print0'):
3333 sep = eol = b'\0'
3284 sep = eol = b'\0'
3334
3285
3335 searcher = grepmod.grepsearcher(
3286 searcher = grepmod.grepsearcher(
3336 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3287 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3337 )
3288 )
3338
3289
3339 getfile = searcher._getfile
3290 getfile = searcher._getfile
3340
3291
3341 uipathfn = scmutil.getuipathfn(repo)
3292 uipathfn = scmutil.getuipathfn(repo)
3342
3293
3343 def display(fm, fn, ctx, pstates, states):
3294 def display(fm, fn, ctx, pstates, states):
3344 rev = scmutil.intrev(ctx)
3295 rev = scmutil.intrev(ctx)
3345 if fm.isplain():
3296 if fm.isplain():
3346 formatuser = ui.shortuser
3297 formatuser = ui.shortuser
3347 else:
3298 else:
3348 formatuser = pycompat.bytestr
3299 formatuser = pycompat.bytestr
3349 if ui.quiet:
3300 if ui.quiet:
3350 datefmt = b'%Y-%m-%d'
3301 datefmt = b'%Y-%m-%d'
3351 else:
3302 else:
3352 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3303 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3353 found = False
3304 found = False
3354
3305
3355 @util.cachefunc
3306 @util.cachefunc
3356 def binary():
3307 def binary():
3357 flog = getfile(fn)
3308 flog = getfile(fn)
3358 try:
3309 try:
3359 return stringutil.binary(flog.read(ctx.filenode(fn)))
3310 return stringutil.binary(flog.read(ctx.filenode(fn)))
3360 except error.WdirUnsupported:
3311 except error.WdirUnsupported:
3361 return ctx[fn].isbinary()
3312 return ctx[fn].isbinary()
3362
3313
3363 fieldnamemap = {b'linenumber': b'lineno'}
3314 fieldnamemap = {b'linenumber': b'lineno'}
3364 if diff:
3315 if diff:
3365 iter = grepmod.difflinestates(pstates, states)
3316 iter = grepmod.difflinestates(pstates, states)
3366 else:
3317 else:
3367 iter = [(b'', l) for l in states]
3318 iter = [(b'', l) for l in states]
3368 for change, l in iter:
3319 for change, l in iter:
3369 fm.startitem()
3320 fm.startitem()
3370 fm.context(ctx=ctx)
3321 fm.context(ctx=ctx)
3371 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3322 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3372 fm.plain(uipathfn(fn), label=b'grep.filename')
3323 fm.plain(uipathfn(fn), label=b'grep.filename')
3373
3324
3374 cols = [
3325 cols = [
3375 (b'rev', b'%d', rev, not plaingrep, b''),
3326 (b'rev', b'%d', rev, not plaingrep, b''),
3376 (
3327 (
3377 b'linenumber',
3328 b'linenumber',
3378 b'%d',
3329 b'%d',
3379 l.linenum,
3330 l.linenum,
3380 opts.get('line_number'),
3331 opts.get('line_number'),
3381 b'',
3332 b'',
3382 ),
3333 ),
3383 ]
3334 ]
3384 if diff:
3335 if diff:
3385 cols.append(
3336 cols.append(
3386 (
3337 (
3387 b'change',
3338 b'change',
3388 b'%s',
3339 b'%s',
3389 change,
3340 change,
3390 True,
3341 True,
3391 b'grep.inserted '
3342 b'grep.inserted '
3392 if change == b'+'
3343 if change == b'+'
3393 else b'grep.deleted ',
3344 else b'grep.deleted ',
3394 )
3345 )
3395 )
3346 )
3396 cols.extend(
3347 cols.extend(
3397 [
3348 [
3398 (
3349 (
3399 b'user',
3350 b'user',
3400 b'%s',
3351 b'%s',
3401 formatuser(ctx.user()),
3352 formatuser(ctx.user()),
3402 opts.get('user'),
3353 opts.get('user'),
3403 b'',
3354 b'',
3404 ),
3355 ),
3405 (
3356 (
3406 b'date',
3357 b'date',
3407 b'%s',
3358 b'%s',
3408 fm.formatdate(ctx.date(), datefmt),
3359 fm.formatdate(ctx.date(), datefmt),
3409 opts.get('date'),
3360 opts.get('date'),
3410 b'',
3361 b'',
3411 ),
3362 ),
3412 ]
3363 ]
3413 )
3364 )
3414 for name, fmt, data, cond, extra_label in cols:
3365 for name, fmt, data, cond, extra_label in cols:
3415 if cond:
3366 if cond:
3416 fm.plain(sep, label=b'grep.sep')
3367 fm.plain(sep, label=b'grep.sep')
3417 field = fieldnamemap.get(name, name)
3368 field = fieldnamemap.get(name, name)
3418 label = extra_label + (b'grep.%s' % name)
3369 label = extra_label + (b'grep.%s' % name)
3419 fm.condwrite(cond, field, fmt, data, label=label)
3370 fm.condwrite(cond, field, fmt, data, label=label)
3420 if not opts.get('files_with_matches'):
3371 if not opts.get('files_with_matches'):
3421 fm.plain(sep, label=b'grep.sep')
3372 fm.plain(sep, label=b'grep.sep')
3422 if not opts.get('text') and binary():
3373 if not opts.get('text') and binary():
3423 fm.plain(_(b" Binary file matches"))
3374 fm.plain(_(b" Binary file matches"))
3424 else:
3375 else:
3425 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3376 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3426 fm.plain(eol)
3377 fm.plain(eol)
3427 found = True
3378 found = True
3428 if opts.get('files_with_matches'):
3379 if opts.get('files_with_matches'):
3429 break
3380 break
3430 return found
3381 return found
3431
3382
3432 def displaymatches(fm, l):
3383 def displaymatches(fm, l):
3433 p = 0
3384 p = 0
3434 for s, e in l.findpos(regexp):
3385 for s, e in l.findpos(regexp):
3435 if p < s:
3386 if p < s:
3436 fm.startitem()
3387 fm.startitem()
3437 fm.write(b'text', b'%s', l.line[p:s])
3388 fm.write(b'text', b'%s', l.line[p:s])
3438 fm.data(matched=False)
3389 fm.data(matched=False)
3439 fm.startitem()
3390 fm.startitem()
3440 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3391 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3441 fm.data(matched=True)
3392 fm.data(matched=True)
3442 p = e
3393 p = e
3443 if p < len(l.line):
3394 if p < len(l.line):
3444 fm.startitem()
3395 fm.startitem()
3445 fm.write(b'text', b'%s', l.line[p:])
3396 fm.write(b'text', b'%s', l.line[p:])
3446 fm.data(matched=False)
3397 fm.data(matched=False)
3447 fm.end()
3398 fm.end()
3448
3399
3449 found = False
3400 found = False
3450
3401
3451 wopts = logcmdutil.walkopts(
3402 wopts = logcmdutil.walkopts(
3452 pats=pats,
3403 pats=pats,
3453 opts=pycompat.byteskwargs(opts),
3404 opts=pycompat.byteskwargs(opts),
3454 revspec=opts['rev'],
3405 revspec=opts['rev'],
3455 include_pats=opts['include'],
3406 include_pats=opts['include'],
3456 exclude_pats=opts['exclude'],
3407 exclude_pats=opts['exclude'],
3457 follow=follow,
3408 follow=follow,
3458 force_changelog_traversal=all_files,
3409 force_changelog_traversal=all_files,
3459 filter_revisions_by_pats=not all_files,
3410 filter_revisions_by_pats=not all_files,
3460 )
3411 )
3461 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3412 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3462
3413
3463 ui.pager(b'grep')
3414 ui.pager(b'grep')
3464 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3415 fm = ui.formatter(b'grep', pycompat.byteskwargs(opts))
3465 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3416 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3466 r = display(fm, fn, ctx, pstates, states)
3417 r = display(fm, fn, ctx, pstates, states)
3467 found = found or r
3418 found = found or r
3468 if r and not diff and not all_files:
3419 if r and not diff and not all_files:
3469 searcher.skipfile(fn, ctx.rev())
3420 searcher.skipfile(fn, ctx.rev())
3470 fm.end()
3421 fm.end()
3471
3422
3472 return not found
3423 return not found
3473
3424
3474
3425
3475 @command(
3426 @command(
3476 b'heads',
3427 b'heads',
3477 [
3428 [
3478 (
3429 (
3479 b'r',
3430 b'r',
3480 b'rev',
3431 b'rev',
3481 b'',
3432 b'',
3482 _(b'show only heads which are descendants of STARTREV'),
3433 _(b'show only heads which are descendants of STARTREV'),
3483 _(b'STARTREV'),
3434 _(b'STARTREV'),
3484 ),
3435 ),
3485 (b't', b'topo', False, _(b'show topological heads only')),
3436 (b't', b'topo', False, _(b'show topological heads only')),
3486 (
3437 (
3487 b'a',
3438 b'a',
3488 b'active',
3439 b'active',
3489 False,
3440 False,
3490 _(b'show active branchheads only (DEPRECATED)'),
3441 _(b'show active branchheads only (DEPRECATED)'),
3491 ),
3442 ),
3492 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3443 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3493 ]
3444 ]
3494 + templateopts,
3445 + templateopts,
3495 _(b'[-ct] [-r STARTREV] [REV]...'),
3446 _(b'[-ct] [-r STARTREV] [REV]...'),
3496 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3447 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3497 intents={INTENT_READONLY},
3448 intents={INTENT_READONLY},
3498 )
3449 )
3499 def heads(ui, repo, *branchrevs, **opts):
3450 def heads(ui, repo, *branchrevs, **opts):
3500 """show branch heads
3451 """show branch heads
3501
3452
3502 With no arguments, show all open branch heads in the repository.
3453 With no arguments, show all open branch heads in the repository.
3503 Branch heads are changesets that have no descendants on the
3454 Branch heads are changesets that have no descendants on the
3504 same branch. They are where development generally takes place and
3455 same branch. They are where development generally takes place and
3505 are the usual targets for update and merge operations.
3456 are the usual targets for update and merge operations.
3506
3457
3507 If one or more REVs are given, only open branch heads on the
3458 If one or more REVs are given, only open branch heads on the
3508 branches associated with the specified changesets are shown. This
3459 branches associated with the specified changesets are shown. This
3509 means that you can use :hg:`heads .` to see the heads on the
3460 means that you can use :hg:`heads .` to see the heads on the
3510 currently checked-out branch.
3461 currently checked-out branch.
3511
3462
3512 If -c/--closed is specified, also show branch heads marked closed
3463 If -c/--closed is specified, also show branch heads marked closed
3513 (see :hg:`commit --close-branch`).
3464 (see :hg:`commit --close-branch`).
3514
3465
3515 If STARTREV is specified, only those heads that are descendants of
3466 If STARTREV is specified, only those heads that are descendants of
3516 STARTREV will be displayed.
3467 STARTREV will be displayed.
3517
3468
3518 If -t/--topo is specified, named branch mechanics will be ignored and only
3469 If -t/--topo is specified, named branch mechanics will be ignored and only
3519 topological heads (changesets with no children) will be shown.
3470 topological heads (changesets with no children) will be shown.
3520
3471
3521 Returns 0 if matching heads are found, 1 if not.
3472 Returns 0 if matching heads are found, 1 if not.
3522 """
3473 """
3523
3474
3524 start = None
3475 start = None
3525 rev = opts.get('rev')
3476 rev = opts.get('rev')
3526 if rev:
3477 if rev:
3527 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3478 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3528 start = logcmdutil.revsingle(repo, rev, None).node()
3479 start = logcmdutil.revsingle(repo, rev, None).node()
3529
3480
3530 if opts.get('topo'):
3481 if opts.get('topo'):
3531 heads = [repo[h] for h in repo.heads(start)]
3482 heads = [repo[h] for h in repo.heads(start)]
3532 else:
3483 else:
3533 heads = []
3484 heads = []
3534 for branch in repo.branchmap():
3485 for branch in repo.branchmap():
3535 heads += repo.branchheads(branch, start, opts.get('closed'))
3486 heads += repo.branchheads(branch, start, opts.get('closed'))
3536 heads = [repo[h] for h in heads]
3487 heads = [repo[h] for h in heads]
3537
3488
3538 if branchrevs:
3489 if branchrevs:
3539 branches = {
3490 branches = {
3540 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3491 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3541 }
3492 }
3542 heads = [h for h in heads if h.branch() in branches]
3493 heads = [h for h in heads if h.branch() in branches]
3543
3494
3544 if opts.get('active') and branchrevs:
3495 if opts.get('active') and branchrevs:
3545 dagheads = repo.heads(start)
3496 dagheads = repo.heads(start)
3546 heads = [h for h in heads if h.node() in dagheads]
3497 heads = [h for h in heads if h.node() in dagheads]
3547
3498
3548 if branchrevs:
3499 if branchrevs:
3549 haveheads = {h.branch() for h in heads}
3500 haveheads = {h.branch() for h in heads}
3550 if branches - haveheads:
3501 if branches - haveheads:
3551 headless = b', '.join(b for b in branches - haveheads)
3502 headless = b', '.join(b for b in branches - haveheads)
3552 msg = _(b'no open branch heads found on branches %s')
3503 msg = _(b'no open branch heads found on branches %s')
3553 if opts.get('rev'):
3504 if opts.get('rev'):
3554 msg += _(b' (started at %s)') % opts['rev']
3505 msg += _(b' (started at %s)') % opts['rev']
3555 ui.warn((msg + b'\n') % headless)
3506 ui.warn((msg + b'\n') % headless)
3556
3507
3557 if not heads:
3508 if not heads:
3558 return 1
3509 return 1
3559
3510
3560 ui.pager(b'heads')
3511 ui.pager(b'heads')
3561 heads = sorted(heads, key=lambda x: -(x.rev()))
3512 heads = sorted(heads, key=lambda x: -(x.rev()))
3562 displayer = logcmdutil.changesetdisplayer(
3513 displayer = logcmdutil.changesetdisplayer(
3563 ui, repo, pycompat.byteskwargs(opts)
3514 ui, repo, pycompat.byteskwargs(opts)
3564 )
3515 )
3565 for ctx in heads:
3516 for ctx in heads:
3566 displayer.show(ctx)
3517 displayer.show(ctx)
3567 displayer.close()
3518 displayer.close()
3568
3519
3569
3520
3570 @command(
3521 @command(
3571 b'help',
3522 b'help',
3572 [
3523 [
3573 (b'e', b'extension', None, _(b'show only help for extensions')),
3524 (b'e', b'extension', None, _(b'show only help for extensions')),
3574 (b'c', b'command', None, _(b'show only help for commands')),
3525 (b'c', b'command', None, _(b'show only help for commands')),
3575 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3526 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3576 (
3527 (
3577 b's',
3528 b's',
3578 b'system',
3529 b'system',
3579 [],
3530 [],
3580 _(b'show help for specific platform(s)'),
3531 _(b'show help for specific platform(s)'),
3581 _(b'PLATFORM'),
3532 _(b'PLATFORM'),
3582 ),
3533 ),
3583 ],
3534 ],
3584 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3535 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3585 helpcategory=command.CATEGORY_HELP,
3536 helpcategory=command.CATEGORY_HELP,
3586 norepo=True,
3537 norepo=True,
3587 intents={INTENT_READONLY},
3538 intents={INTENT_READONLY},
3588 )
3539 )
3589 def help_(ui, name=None, **opts):
3540 def help_(ui, name=None, **opts):
3590 """show help for a given topic or a help overview
3541 """show help for a given topic or a help overview
3591
3542
3592 With no arguments, print a list of commands with short help messages.
3543 With no arguments, print a list of commands with short help messages.
3593
3544
3594 Given a topic, extension, or command name, print help for that
3545 Given a topic, extension, or command name, print help for that
3595 topic.
3546 topic.
3596
3547
3597 Returns 0 if successful.
3548 Returns 0 if successful.
3598 """
3549 """
3599
3550
3600 keep = opts.get('system') or []
3551 keep = opts.get('system') or []
3601 if len(keep) == 0:
3552 if len(keep) == 0:
3602 if pycompat.sysplatform.startswith(b'win'):
3553 if pycompat.sysplatform.startswith(b'win'):
3603 keep.append(b'windows')
3554 keep.append(b'windows')
3604 elif pycompat.sysplatform == b'OpenVMS':
3555 elif pycompat.sysplatform == b'OpenVMS':
3605 keep.append(b'vms')
3556 keep.append(b'vms')
3606 elif pycompat.sysplatform == b'plan9':
3557 elif pycompat.sysplatform == b'plan9':
3607 keep.append(b'plan9')
3558 keep.append(b'plan9')
3608 else:
3559 else:
3609 keep.append(b'unix')
3560 keep.append(b'unix')
3610 keep.append(pycompat.sysplatform.lower())
3561 keep.append(pycompat.sysplatform.lower())
3611 if ui.verbose:
3562 if ui.verbose:
3612 keep.append(b'verbose')
3563 keep.append(b'verbose')
3613
3564
3614 commands = sys.modules[__name__]
3565 commands = sys.modules[__name__]
3615 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3566 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3616 ui.pager(b'help')
3567 ui.pager(b'help')
3617 ui.write(formatted)
3568 ui.write(formatted)
3618
3569
3619
3570
3620 @command(
3571 @command(
3621 b'identify|id',
3572 b'identify|id',
3622 [
3573 [
3623 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3574 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3624 (b'n', b'num', None, _(b'show local revision number')),
3575 (b'n', b'num', None, _(b'show local revision number')),
3625 (b'i', b'id', None, _(b'show global revision id')),
3576 (b'i', b'id', None, _(b'show global revision id')),
3626 (b'b', b'branch', None, _(b'show branch')),
3577 (b'b', b'branch', None, _(b'show branch')),
3627 (b't', b'tags', None, _(b'show tags')),
3578 (b't', b'tags', None, _(b'show tags')),
3628 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3579 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3629 ]
3580 ]
3630 + remoteopts
3581 + remoteopts
3631 + formatteropts,
3582 + formatteropts,
3632 _(b'[-nibtB] [-r REV] [SOURCE]'),
3583 _(b'[-nibtB] [-r REV] [SOURCE]'),
3633 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3584 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3634 optionalrepo=True,
3585 optionalrepo=True,
3635 intents={INTENT_READONLY},
3586 intents={INTENT_READONLY},
3636 )
3587 )
3637 def identify(
3588 def identify(
3638 ui,
3589 ui,
3639 repo,
3590 repo,
3640 source=None,
3591 source=None,
3641 rev=None,
3592 rev=None,
3642 num=None,
3593 num=None,
3643 id=None,
3594 id=None,
3644 branch=None,
3595 branch=None,
3645 tags=None,
3596 tags=None,
3646 bookmarks=None,
3597 bookmarks=None,
3647 **opts,
3598 **opts,
3648 ):
3599 ):
3649 """identify the working directory or specified revision
3600 """identify the working directory or specified revision
3650
3601
3651 Print a summary identifying the repository state at REV using one or
3602 Print a summary identifying the repository state at REV using one or
3652 two parent hash identifiers, followed by a "+" if the working
3603 two parent hash identifiers, followed by a "+" if the working
3653 directory has uncommitted changes, the branch name (if not default),
3604 directory has uncommitted changes, the branch name (if not default),
3654 a list of tags, and a list of bookmarks.
3605 a list of tags, and a list of bookmarks.
3655
3606
3656 When REV is not given, print a summary of the current state of the
3607 When REV is not given, print a summary of the current state of the
3657 repository including the working directory. Specify -r. to get information
3608 repository including the working directory. Specify -r. to get information
3658 of the working directory parent without scanning uncommitted changes.
3609 of the working directory parent without scanning uncommitted changes.
3659
3610
3660 Specifying a path to a repository root or Mercurial bundle will
3611 Specifying a path to a repository root or Mercurial bundle will
3661 cause lookup to operate on that repository/bundle.
3612 cause lookup to operate on that repository/bundle.
3662
3613
3663 .. container:: verbose
3614 .. container:: verbose
3664
3615
3665 Template:
3616 Template:
3666
3617
3667 The following keywords are supported in addition to the common template
3618 The following keywords are supported in addition to the common template
3668 keywords and functions. See also :hg:`help templates`.
3619 keywords and functions. See also :hg:`help templates`.
3669
3620
3670 :dirty: String. Character ``+`` denoting if the working directory has
3621 :dirty: String. Character ``+`` denoting if the working directory has
3671 uncommitted changes.
3622 uncommitted changes.
3672 :id: String. One or two nodes, optionally followed by ``+``.
3623 :id: String. One or two nodes, optionally followed by ``+``.
3673 :parents: List of strings. Parent nodes of the changeset.
3624 :parents: List of strings. Parent nodes of the changeset.
3674
3625
3675 Examples:
3626 Examples:
3676
3627
3677 - generate a build identifier for the working directory::
3628 - generate a build identifier for the working directory::
3678
3629
3679 hg id --id > build-id.dat
3630 hg id --id > build-id.dat
3680
3631
3681 - find the revision corresponding to a tag::
3632 - find the revision corresponding to a tag::
3682
3633
3683 hg id -n -r 1.3
3634 hg id -n -r 1.3
3684
3635
3685 - check the most recent revision of a remote repository::
3636 - check the most recent revision of a remote repository::
3686
3637
3687 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3638 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3688
3639
3689 See :hg:`log` for generating more information about specific revisions,
3640 See :hg:`log` for generating more information about specific revisions,
3690 including full hash identifiers.
3641 including full hash identifiers.
3691
3642
3692 Returns 0 if successful.
3643 Returns 0 if successful.
3693 """
3644 """
3694
3645
3695 opts = pycompat.byteskwargs(opts)
3646 opts = pycompat.byteskwargs(opts)
3696 if not repo and not source:
3647 if not repo and not source:
3697 raise error.InputError(
3648 raise error.InputError(
3698 _(b"there is no Mercurial repository here (.hg not found)")
3649 _(b"there is no Mercurial repository here (.hg not found)")
3699 )
3650 )
3700
3651
3701 default = not (num or id or branch or tags or bookmarks)
3652 default = not (num or id or branch or tags or bookmarks)
3702 output = []
3653 output = []
3703 revs = []
3654 revs = []
3704
3655
3705 peer = None
3656 peer = None
3706 try:
3657 try:
3707 if source:
3658 if source:
3708 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3659 path = urlutil.get_unique_pull_path_obj(b'identify', ui, source)
3709 # only pass ui when no repo
3660 # only pass ui when no repo
3710 peer = hg.peer(repo or ui, opts, path)
3661 peer = hg.peer(repo or ui, opts, path)
3711 repo = peer.local()
3662 repo = peer.local()
3712 branches = (path.branch, [])
3663 branches = (path.branch, [])
3713 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3664 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3714
3665
3715 fm = ui.formatter(b'identify', opts)
3666 fm = ui.formatter(b'identify', opts)
3716 fm.startitem()
3667 fm.startitem()
3717
3668
3718 if not repo:
3669 if not repo:
3719 if num or branch or tags:
3670 if num or branch or tags:
3720 raise error.InputError(
3671 raise error.InputError(
3721 _(b"can't query remote revision number, branch, or tags")
3672 _(b"can't query remote revision number, branch, or tags")
3722 )
3673 )
3723 if not rev and revs:
3674 if not rev and revs:
3724 rev = revs[0]
3675 rev = revs[0]
3725 if not rev:
3676 if not rev:
3726 rev = b"tip"
3677 rev = b"tip"
3727
3678
3728 remoterev = peer.lookup(rev)
3679 remoterev = peer.lookup(rev)
3729 hexrev = fm.hexfunc(remoterev)
3680 hexrev = fm.hexfunc(remoterev)
3730 if default or id:
3681 if default or id:
3731 output = [hexrev]
3682 output = [hexrev]
3732 fm.data(id=hexrev)
3683 fm.data(id=hexrev)
3733
3684
3734 @util.cachefunc
3685 @util.cachefunc
3735 def getbms():
3686 def getbms():
3736 bms = []
3687 bms = []
3737
3688
3738 if b'bookmarks' in peer.listkeys(b'namespaces'):
3689 if b'bookmarks' in peer.listkeys(b'namespaces'):
3739 hexremoterev = hex(remoterev)
3690 hexremoterev = hex(remoterev)
3740 bms = [
3691 bms = [
3741 bm
3692 bm
3742 for bm, bmr in peer.listkeys(b'bookmarks').items()
3693 for bm, bmr in peer.listkeys(b'bookmarks').items()
3743 if bmr == hexremoterev
3694 if bmr == hexremoterev
3744 ]
3695 ]
3745
3696
3746 return sorted(bms)
3697 return sorted(bms)
3747
3698
3748 if fm.isplain():
3699 if fm.isplain():
3749 if bookmarks:
3700 if bookmarks:
3750 output.extend(getbms())
3701 output.extend(getbms())
3751 elif default and not ui.quiet:
3702 elif default and not ui.quiet:
3752 # multiple bookmarks for a single parent separated by '/'
3703 # multiple bookmarks for a single parent separated by '/'
3753 bm = b'/'.join(getbms())
3704 bm = b'/'.join(getbms())
3754 if bm:
3705 if bm:
3755 output.append(bm)
3706 output.append(bm)
3756 else:
3707 else:
3757 fm.data(node=hex(remoterev))
3708 fm.data(node=hex(remoterev))
3758 if bookmarks or b'bookmarks' in fm.datahint():
3709 if bookmarks or b'bookmarks' in fm.datahint():
3759 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3710 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3760 else:
3711 else:
3761 if rev:
3712 if rev:
3762 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3713 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3763 ctx = logcmdutil.revsingle(repo, rev, None)
3714 ctx = logcmdutil.revsingle(repo, rev, None)
3764
3715
3765 if ctx.rev() is None:
3716 if ctx.rev() is None:
3766 ctx = repo[None]
3717 ctx = repo[None]
3767 parents = ctx.parents()
3718 parents = ctx.parents()
3768 taglist = []
3719 taglist = []
3769 for p in parents:
3720 for p in parents:
3770 taglist.extend(p.tags())
3721 taglist.extend(p.tags())
3771
3722
3772 dirty = b""
3723 dirty = b""
3773 if ctx.dirty(missing=True, merge=False, branch=False):
3724 if ctx.dirty(missing=True, merge=False, branch=False):
3774 dirty = b'+'
3725 dirty = b'+'
3775 fm.data(dirty=dirty)
3726 fm.data(dirty=dirty)
3776
3727
3777 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3728 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3778 if default or id:
3729 if default or id:
3779 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3730 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3780 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3731 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3781
3732
3782 if num:
3733 if num:
3783 numoutput = [b"%d" % p.rev() for p in parents]
3734 numoutput = [b"%d" % p.rev() for p in parents]
3784 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3735 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3785
3736
3786 fm.data(
3737 fm.data(
3787 parents=fm.formatlist(
3738 parents=fm.formatlist(
3788 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3739 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3789 )
3740 )
3790 )
3741 )
3791 else:
3742 else:
3792 hexoutput = fm.hexfunc(ctx.node())
3743 hexoutput = fm.hexfunc(ctx.node())
3793 if default or id:
3744 if default or id:
3794 output = [hexoutput]
3745 output = [hexoutput]
3795 fm.data(id=hexoutput)
3746 fm.data(id=hexoutput)
3796
3747
3797 if num:
3748 if num:
3798 output.append(pycompat.bytestr(ctx.rev()))
3749 output.append(pycompat.bytestr(ctx.rev()))
3799 taglist = ctx.tags()
3750 taglist = ctx.tags()
3800
3751
3801 if default and not ui.quiet:
3752 if default and not ui.quiet:
3802 b = ctx.branch()
3753 b = ctx.branch()
3803 if b != b'default':
3754 if b != b'default':
3804 output.append(b"(%s)" % b)
3755 output.append(b"(%s)" % b)
3805
3756
3806 # multiple tags for a single parent separated by '/'
3757 # multiple tags for a single parent separated by '/'
3807 t = b'/'.join(taglist)
3758 t = b'/'.join(taglist)
3808 if t:
3759 if t:
3809 output.append(t)
3760 output.append(t)
3810
3761
3811 # multiple bookmarks for a single parent separated by '/'
3762 # multiple bookmarks for a single parent separated by '/'
3812 bm = b'/'.join(ctx.bookmarks())
3763 bm = b'/'.join(ctx.bookmarks())
3813 if bm:
3764 if bm:
3814 output.append(bm)
3765 output.append(bm)
3815 else:
3766 else:
3816 if branch:
3767 if branch:
3817 output.append(ctx.branch())
3768 output.append(ctx.branch())
3818
3769
3819 if tags:
3770 if tags:
3820 output.extend(taglist)
3771 output.extend(taglist)
3821
3772
3822 if bookmarks:
3773 if bookmarks:
3823 output.extend(ctx.bookmarks())
3774 output.extend(ctx.bookmarks())
3824
3775
3825 fm.data(node=ctx.hex())
3776 fm.data(node=ctx.hex())
3826 fm.data(branch=ctx.branch())
3777 fm.data(branch=ctx.branch())
3827 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3778 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3828 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3779 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3829 fm.context(ctx=ctx)
3780 fm.context(ctx=ctx)
3830
3781
3831 fm.plain(b"%s\n" % b' '.join(output))
3782 fm.plain(b"%s\n" % b' '.join(output))
3832 fm.end()
3783 fm.end()
3833 finally:
3784 finally:
3834 if peer:
3785 if peer:
3835 peer.close()
3786 peer.close()
3836
3787
3837
3788
3838 @command(
3789 @command(
3839 b'import|patch',
3790 b'import|patch',
3840 [
3791 [
3841 (
3792 (
3842 b'p',
3793 b'p',
3843 b'strip',
3794 b'strip',
3844 1,
3795 1,
3845 _(
3796 _(
3846 b'directory strip option for patch. This has the same '
3797 b'directory strip option for patch. This has the same '
3847 b'meaning as the corresponding patch option'
3798 b'meaning as the corresponding patch option'
3848 ),
3799 ),
3849 _(b'NUM'),
3800 _(b'NUM'),
3850 ),
3801 ),
3851 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3802 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3852 (b'', b'secret', None, _(b'use the secret phase for committing')),
3803 (b'', b'secret', None, _(b'use the secret phase for committing')),
3853 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3804 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3854 (
3805 (
3855 b'f',
3806 b'f',
3856 b'force',
3807 b'force',
3857 None,
3808 None,
3858 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3809 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3859 ),
3810 ),
3860 (
3811 (
3861 b'',
3812 b'',
3862 b'no-commit',
3813 b'no-commit',
3863 None,
3814 None,
3864 _(b"don't commit, just update the working directory"),
3815 _(b"don't commit, just update the working directory"),
3865 ),
3816 ),
3866 (
3817 (
3867 b'',
3818 b'',
3868 b'bypass',
3819 b'bypass',
3869 None,
3820 None,
3870 _(b"apply patch without touching the working directory"),
3821 _(b"apply patch without touching the working directory"),
3871 ),
3822 ),
3872 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3823 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3873 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3824 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3874 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3825 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3875 (
3826 (
3876 b'',
3827 b'',
3877 b'import-branch',
3828 b'import-branch',
3878 None,
3829 None,
3879 _(b'use any branch information in patch (implied by --exact)'),
3830 _(b'use any branch information in patch (implied by --exact)'),
3880 ),
3831 ),
3881 ]
3832 ]
3882 + commitopts
3833 + commitopts
3883 + commitopts2
3834 + commitopts2
3884 + similarityopts,
3835 + similarityopts,
3885 _(b'[OPTION]... PATCH...'),
3836 _(b'[OPTION]... PATCH...'),
3886 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3837 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3887 )
3838 )
3888 def import_(ui, repo, patch1=None, *patches, **opts):
3839 def import_(ui, repo, patch1=None, *patches, **opts):
3889 """import an ordered set of patches
3840 """import an ordered set of patches
3890
3841
3891 Import a list of patches and commit them individually (unless
3842 Import a list of patches and commit them individually (unless
3892 --no-commit is specified).
3843 --no-commit is specified).
3893
3844
3894 To read a patch from standard input (stdin), use "-" as the patch
3845 To read a patch from standard input (stdin), use "-" as the patch
3895 name. If a URL is specified, the patch will be downloaded from
3846 name. If a URL is specified, the patch will be downloaded from
3896 there.
3847 there.
3897
3848
3898 Import first applies changes to the working directory (unless
3849 Import first applies changes to the working directory (unless
3899 --bypass is specified), import will abort if there are outstanding
3850 --bypass is specified), import will abort if there are outstanding
3900 changes.
3851 changes.
3901
3852
3902 Use --bypass to apply and commit patches directly to the
3853 Use --bypass to apply and commit patches directly to the
3903 repository, without affecting the working directory. Without
3854 repository, without affecting the working directory. Without
3904 --exact, patches will be applied on top of the working directory
3855 --exact, patches will be applied on top of the working directory
3905 parent revision.
3856 parent revision.
3906
3857
3907 You can import a patch straight from a mail message. Even patches
3858 You can import a patch straight from a mail message. Even patches
3908 as attachments work (to use the body part, it must have type
3859 as attachments work (to use the body part, it must have type
3909 text/plain or text/x-patch). From and Subject headers of email
3860 text/plain or text/x-patch). From and Subject headers of email
3910 message are used as default committer and commit message. All
3861 message are used as default committer and commit message. All
3911 text/plain body parts before first diff are added to the commit
3862 text/plain body parts before first diff are added to the commit
3912 message.
3863 message.
3913
3864
3914 If the imported patch was generated by :hg:`export`, user and
3865 If the imported patch was generated by :hg:`export`, user and
3915 description from patch override values from message headers and
3866 description from patch override values from message headers and
3916 body. Values given on command line with -m/--message and -u/--user
3867 body. Values given on command line with -m/--message and -u/--user
3917 override these.
3868 override these.
3918
3869
3919 If --exact is specified, import will set the working directory to
3870 If --exact is specified, import will set the working directory to
3920 the parent of each patch before applying it, and will abort if the
3871 the parent of each patch before applying it, and will abort if the
3921 resulting changeset has a different ID than the one recorded in
3872 resulting changeset has a different ID than the one recorded in
3922 the patch. This will guard against various ways that portable
3873 the patch. This will guard against various ways that portable
3923 patch formats and mail systems might fail to transfer Mercurial
3874 patch formats and mail systems might fail to transfer Mercurial
3924 data or metadata. See :hg:`bundle` for lossless transmission.
3875 data or metadata. See :hg:`bundle` for lossless transmission.
3925
3876
3926 Use --partial to ensure a changeset will be created from the patch
3877 Use --partial to ensure a changeset will be created from the patch
3927 even if some hunks fail to apply. Hunks that fail to apply will be
3878 even if some hunks fail to apply. Hunks that fail to apply will be
3928 written to a <target-file>.rej file. Conflicts can then be resolved
3879 written to a <target-file>.rej file. Conflicts can then be resolved
3929 by hand before :hg:`commit --amend` is run to update the created
3880 by hand before :hg:`commit --amend` is run to update the created
3930 changeset. This flag exists to let people import patches that
3881 changeset. This flag exists to let people import patches that
3931 partially apply without losing the associated metadata (author,
3882 partially apply without losing the associated metadata (author,
3932 date, description, ...).
3883 date, description, ...).
3933
3884
3934 .. note::
3885 .. note::
3935
3886
3936 When no hunks apply cleanly, :hg:`import --partial` will create
3887 When no hunks apply cleanly, :hg:`import --partial` will create
3937 an empty changeset, importing only the patch metadata.
3888 an empty changeset, importing only the patch metadata.
3938
3889
3939 With -s/--similarity, hg will attempt to discover renames and
3890 With -s/--similarity, hg will attempt to discover renames and
3940 copies in the patch in the same way as :hg:`addremove`.
3891 copies in the patch in the same way as :hg:`addremove`.
3941
3892
3942 It is possible to use external patch programs to perform the patch
3893 It is possible to use external patch programs to perform the patch
3943 by setting the ``ui.patch`` configuration option. For the default
3894 by setting the ``ui.patch`` configuration option. For the default
3944 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3895 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3945 See :hg:`help config` for more information about configuration
3896 See :hg:`help config` for more information about configuration
3946 files and how to use these options.
3897 files and how to use these options.
3947
3898
3948 See :hg:`help dates` for a list of formats valid for -d/--date.
3899 See :hg:`help dates` for a list of formats valid for -d/--date.
3949
3900
3950 .. container:: verbose
3901 .. container:: verbose
3951
3902
3952 Examples:
3903 Examples:
3953
3904
3954 - import a traditional patch from a website and detect renames::
3905 - import a traditional patch from a website and detect renames::
3955
3906
3956 hg import -s 80 http://example.com/bugfix.patch
3907 hg import -s 80 http://example.com/bugfix.patch
3957
3908
3958 - import a changeset from an hgweb server::
3909 - import a changeset from an hgweb server::
3959
3910
3960 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3911 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3961
3912
3962 - import all the patches in an Unix-style mbox::
3913 - import all the patches in an Unix-style mbox::
3963
3914
3964 hg import incoming-patches.mbox
3915 hg import incoming-patches.mbox
3965
3916
3966 - import patches from stdin::
3917 - import patches from stdin::
3967
3918
3968 hg import -
3919 hg import -
3969
3920
3970 - attempt to exactly restore an exported changeset (not always
3921 - attempt to exactly restore an exported changeset (not always
3971 possible)::
3922 possible)::
3972
3923
3973 hg import --exact proposed-fix.patch
3924 hg import --exact proposed-fix.patch
3974
3925
3975 - use an external tool to apply a patch which is too fuzzy for
3926 - use an external tool to apply a patch which is too fuzzy for
3976 the default internal tool.
3927 the default internal tool.
3977
3928
3978 hg import --config ui.patch="patch --merge" fuzzy.patch
3929 hg import --config ui.patch="patch --merge" fuzzy.patch
3979
3930
3980 - change the default fuzzing from 2 to a less strict 7
3931 - change the default fuzzing from 2 to a less strict 7
3981
3932
3982 hg import --config ui.fuzz=7 fuzz.patch
3933 hg import --config ui.fuzz=7 fuzz.patch
3983
3934
3984 Returns 0 on success, 1 on partial success (see --partial).
3935 Returns 0 on success, 1 on partial success (see --partial).
3985 """
3936 """
3986
3937
3987 cmdutil.check_incompatible_arguments(
3938 cmdutil.check_incompatible_arguments(
3988 opts, 'no_commit', ['bypass', 'secret']
3939 opts, 'no_commit', ['bypass', 'secret']
3989 )
3940 )
3990 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3941 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
3991
3942
3992 if not patch1:
3943 if not patch1:
3993 raise error.InputError(_(b'need at least one patch to import'))
3944 raise error.InputError(_(b'need at least one patch to import'))
3994
3945
3995 patches = (patch1,) + patches
3946 patches = (patch1,) + patches
3996
3947
3997 date = opts.get('date')
3948 date = opts.get('date')
3998 if date:
3949 if date:
3999 opts['date'] = dateutil.parsedate(date)
3950 opts['date'] = dateutil.parsedate(date)
4000
3951
4001 exact = opts.get('exact')
3952 exact = opts.get('exact')
4002 update = not opts.get('bypass')
3953 update = not opts.get('bypass')
4003 try:
3954 try:
4004 sim = float(opts.get('similarity') or 0)
3955 sim = float(opts.get('similarity') or 0)
4005 except ValueError:
3956 except ValueError:
4006 raise error.InputError(_(b'similarity must be a number'))
3957 raise error.InputError(_(b'similarity must be a number'))
4007 if sim < 0 or sim > 100:
3958 if sim < 0 or sim > 100:
4008 raise error.InputError(_(b'similarity must be between 0 and 100'))
3959 raise error.InputError(_(b'similarity must be between 0 and 100'))
4009 if sim and not update:
3960 if sim and not update:
4010 raise error.InputError(_(b'cannot use --similarity with --bypass'))
3961 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4011
3962
4012 base = opts["base"]
3963 base = opts["base"]
4013 msgs = []
3964 msgs = []
4014 ret = 0
3965 ret = 0
4015
3966
4016 with repo.wlock():
3967 with repo.wlock():
4017 if update:
3968 if update:
4018 cmdutil.checkunfinished(repo)
3969 cmdutil.checkunfinished(repo)
4019 if exact or not opts.get('force'):
3970 if exact or not opts.get('force'):
4020 cmdutil.bailifchanged(repo)
3971 cmdutil.bailifchanged(repo)
4021
3972
4022 if not opts.get('no_commit'):
3973 if not opts.get('no_commit'):
4023 lock = repo.lock
3974 lock = repo.lock
4024 tr = lambda: repo.transaction(b'import')
3975 tr = lambda: repo.transaction(b'import')
4025 else:
3976 else:
4026 lock = util.nullcontextmanager
3977 lock = util.nullcontextmanager
4027 tr = util.nullcontextmanager
3978 tr = util.nullcontextmanager
4028 with lock(), tr():
3979 with lock(), tr():
4029 parents = repo[None].parents()
3980 parents = repo[None].parents()
4030 for patchurl in patches:
3981 for patchurl in patches:
4031 if patchurl == b'-':
3982 if patchurl == b'-':
4032 ui.status(_(b'applying patch from stdin\n'))
3983 ui.status(_(b'applying patch from stdin\n'))
4033 patchfile = ui.fin
3984 patchfile = ui.fin
4034 patchurl = b'stdin' # for error message
3985 patchurl = b'stdin' # for error message
4035 else:
3986 else:
4036 patchurl = os.path.join(base, patchurl)
3987 patchurl = os.path.join(base, patchurl)
4037 ui.status(_(b'applying %s\n') % patchurl)
3988 ui.status(_(b'applying %s\n') % patchurl)
4038 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3989 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4039
3990
4040 haspatch = False
3991 haspatch = False
4041 for hunk in patch.split(patchfile):
3992 for hunk in patch.split(patchfile):
4042 with patch.extract(ui, hunk) as patchdata:
3993 with patch.extract(ui, hunk) as patchdata:
4043 msg, node, rej = cmdutil.tryimportone(
3994 msg, node, rej = cmdutil.tryimportone(
4044 ui,
3995 ui,
4045 repo,
3996 repo,
4046 patchdata,
3997 patchdata,
4047 parents,
3998 parents,
4048 pycompat.byteskwargs(opts),
3999 pycompat.byteskwargs(opts),
4049 msgs,
4000 msgs,
4050 hg.clean,
4001 hg.clean,
4051 )
4002 )
4052 if msg:
4003 if msg:
4053 haspatch = True
4004 haspatch = True
4054 ui.note(msg + b'\n')
4005 ui.note(msg + b'\n')
4055 if update or exact:
4006 if update or exact:
4056 parents = repo[None].parents()
4007 parents = repo[None].parents()
4057 else:
4008 else:
4058 parents = [repo[node]]
4009 parents = [repo[node]]
4059 if rej:
4010 if rej:
4060 ui.write_err(_(b"patch applied partially\n"))
4011 ui.write_err(_(b"patch applied partially\n"))
4061 ui.write_err(
4012 ui.write_err(
4062 _(
4013 _(
4063 b"(fix the .rej files and run "
4014 b"(fix the .rej files and run "
4064 b"`hg commit --amend`)\n"
4015 b"`hg commit --amend`)\n"
4065 )
4016 )
4066 )
4017 )
4067 ret = 1
4018 ret = 1
4068 break
4019 break
4069
4020
4070 if not haspatch:
4021 if not haspatch:
4071 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4022 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4072
4023
4073 if msgs:
4024 if msgs:
4074 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4025 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4075 return ret
4026 return ret
4076
4027
4077
4028
4078 @command(
4029 @command(
4079 b'incoming|in',
4030 b'incoming|in',
4080 [
4031 [
4081 (
4032 (
4082 b'f',
4033 b'f',
4083 b'force',
4034 b'force',
4084 None,
4035 None,
4085 _(b'run even if remote repository is unrelated'),
4036 _(b'run even if remote repository is unrelated'),
4086 ),
4037 ),
4087 (b'n', b'newest-first', None, _(b'show newest record first')),
4038 (b'n', b'newest-first', None, _(b'show newest record first')),
4088 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4039 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4089 (
4040 (
4090 b'r',
4041 b'r',
4091 b'rev',
4042 b'rev',
4092 [],
4043 [],
4093 _(b'a remote changeset intended to be added'),
4044 _(b'a remote changeset intended to be added'),
4094 _(b'REV'),
4045 _(b'REV'),
4095 ),
4046 ),
4096 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4047 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4097 (
4048 (
4098 b'b',
4049 b'b',
4099 b'branch',
4050 b'branch',
4100 [],
4051 [],
4101 _(b'a specific branch you would like to pull'),
4052 _(b'a specific branch you would like to pull'),
4102 _(b'BRANCH'),
4053 _(b'BRANCH'),
4103 ),
4054 ),
4104 ]
4055 ]
4105 + logopts
4056 + logopts
4106 + remoteopts
4057 + remoteopts
4107 + subrepoopts,
4058 + subrepoopts,
4108 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4059 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4109 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4060 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4110 )
4061 )
4111 def incoming(ui, repo, source=b"default", **opts):
4062 def incoming(ui, repo, source=b"default", **opts):
4112 """show new changesets found in source
4063 """show new changesets found in source
4113
4064
4114 Show new changesets found in the specified path/URL or the default
4065 Show new changesets found in the specified path/URL or the default
4115 pull location. These are the changesets that would have been pulled
4066 pull location. These are the changesets that would have been pulled
4116 by :hg:`pull` at the time you issued this command.
4067 by :hg:`pull` at the time you issued this command.
4117
4068
4118 See pull for valid source format details.
4069 See pull for valid source format details.
4119
4070
4120 .. container:: verbose
4071 .. container:: verbose
4121
4072
4122 With -B/--bookmarks, the result of bookmark comparison between
4073 With -B/--bookmarks, the result of bookmark comparison between
4123 local and remote repositories is displayed. With -v/--verbose,
4074 local and remote repositories is displayed. With -v/--verbose,
4124 status is also displayed for each bookmark like below::
4075 status is also displayed for each bookmark like below::
4125
4076
4126 BM1 01234567890a added
4077 BM1 01234567890a added
4127 BM2 1234567890ab advanced
4078 BM2 1234567890ab advanced
4128 BM3 234567890abc diverged
4079 BM3 234567890abc diverged
4129 BM4 34567890abcd changed
4080 BM4 34567890abcd changed
4130
4081
4131 The action taken locally when pulling depends on the
4082 The action taken locally when pulling depends on the
4132 status of each bookmark:
4083 status of each bookmark:
4133
4084
4134 :``added``: pull will create it
4085 :``added``: pull will create it
4135 :``advanced``: pull will update it
4086 :``advanced``: pull will update it
4136 :``diverged``: pull will create a divergent bookmark
4087 :``diverged``: pull will create a divergent bookmark
4137 :``changed``: result depends on remote changesets
4088 :``changed``: result depends on remote changesets
4138
4089
4139 From the point of view of pulling behavior, bookmark
4090 From the point of view of pulling behavior, bookmark
4140 existing only in the remote repository are treated as ``added``,
4091 existing only in the remote repository are treated as ``added``,
4141 even if it is in fact locally deleted.
4092 even if it is in fact locally deleted.
4142
4093
4143 .. container:: verbose
4094 .. container:: verbose
4144
4095
4145 For remote repository, using --bundle avoids downloading the
4096 For remote repository, using --bundle avoids downloading the
4146 changesets twice if the incoming is followed by a pull.
4097 changesets twice if the incoming is followed by a pull.
4147
4098
4148 Examples:
4099 Examples:
4149
4100
4150 - show incoming changes with patches and full description::
4101 - show incoming changes with patches and full description::
4151
4102
4152 hg incoming -vp
4103 hg incoming -vp
4153
4104
4154 - show incoming changes excluding merges, store a bundle::
4105 - show incoming changes excluding merges, store a bundle::
4155
4106
4156 hg in -vpM --bundle incoming.hg
4107 hg in -vpM --bundle incoming.hg
4157 hg pull incoming.hg
4108 hg pull incoming.hg
4158
4109
4159 - briefly list changes inside a bundle::
4110 - briefly list changes inside a bundle::
4160
4111
4161 hg in changes.hg -T "{desc|firstline}\\n"
4112 hg in changes.hg -T "{desc|firstline}\\n"
4162
4113
4163 Returns 0 if there are incoming changes, 1 otherwise.
4114 Returns 0 if there are incoming changes, 1 otherwise.
4164 """
4115 """
4165 opts = pycompat.byteskwargs(opts)
4116 opts = pycompat.byteskwargs(opts)
4166 if opts.get(b'graph'):
4117 if opts.get(b'graph'):
4167 logcmdutil.checkunsupportedgraphflags([], opts)
4118 logcmdutil.checkunsupportedgraphflags([], opts)
4168
4119
4169 def display(other, chlist, displayer):
4120 def display(other, chlist, displayer):
4170 revdag = logcmdutil.graphrevs(other, chlist, opts)
4121 revdag = logcmdutil.graphrevs(other, chlist, opts)
4171 logcmdutil.displaygraph(
4122 logcmdutil.displaygraph(
4172 ui, repo, revdag, displayer, graphmod.asciiedges
4123 ui, repo, revdag, displayer, graphmod.asciiedges
4173 )
4124 )
4174
4125
4175 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4126 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4176 return 0
4127 return 0
4177
4128
4178 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4129 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4179
4130
4180 if opts.get(b'bookmarks'):
4131 if opts.get(b'bookmarks'):
4181 srcs = urlutil.get_pull_paths(repo, ui, [source])
4132 srcs = urlutil.get_pull_paths(repo, ui, [source])
4182 for path in srcs:
4133 for path in srcs:
4183 # XXX the "branches" options are not used. Should it be used?
4134 # XXX the "branches" options are not used. Should it be used?
4184 other = hg.peer(repo, opts, path)
4135 other = hg.peer(repo, opts, path)
4185 try:
4136 try:
4186 if b'bookmarks' not in other.listkeys(b'namespaces'):
4137 if b'bookmarks' not in other.listkeys(b'namespaces'):
4187 ui.warn(_(b"remote doesn't support bookmarks\n"))
4138 ui.warn(_(b"remote doesn't support bookmarks\n"))
4188 return 0
4139 return 0
4189 ui.pager(b'incoming')
4140 ui.pager(b'incoming')
4190 ui.status(
4141 ui.status(
4191 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4142 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4192 )
4143 )
4193 return bookmarks.incoming(
4144 return bookmarks.incoming(
4194 ui, repo, other, mode=path.bookmarks_mode
4145 ui, repo, other, mode=path.bookmarks_mode
4195 )
4146 )
4196 finally:
4147 finally:
4197 other.close()
4148 other.close()
4198
4149
4199 return hg.incoming(ui, repo, source, opts)
4150 return hg.incoming(ui, repo, source, opts)
4200
4151
4201
4152
4202 @command(
4153 @command(
4203 b'init',
4154 b'init',
4204 remoteopts,
4155 remoteopts,
4205 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4156 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4206 helpcategory=command.CATEGORY_REPO_CREATION,
4157 helpcategory=command.CATEGORY_REPO_CREATION,
4207 helpbasic=True,
4158 helpbasic=True,
4208 norepo=True,
4159 norepo=True,
4209 )
4160 )
4210 def init(ui, dest=b".", **opts):
4161 def init(ui, dest=b".", **opts):
4211 """create a new repository in the given directory
4162 """create a new repository in the given directory
4212
4163
4213 Initialize a new repository in the given directory. If the given
4164 Initialize a new repository in the given directory. If the given
4214 directory does not exist, it will be created.
4165 directory does not exist, it will be created.
4215
4166
4216 If no directory is given, the current directory is used.
4167 If no directory is given, the current directory is used.
4217
4168
4218 It is possible to specify an ``ssh://`` URL as the destination.
4169 It is possible to specify an ``ssh://`` URL as the destination.
4219 See :hg:`help urls` for more information.
4170 See :hg:`help urls` for more information.
4220
4171
4221 Returns 0 on success.
4172 Returns 0 on success.
4222 """
4173 """
4223 opts = pycompat.byteskwargs(opts)
4174 opts = pycompat.byteskwargs(opts)
4224 path = urlutil.get_clone_path_obj(ui, dest)
4175 path = urlutil.get_clone_path_obj(ui, dest)
4225 peer = hg.peer(ui, opts, path, create=True)
4176 peer = hg.peer(ui, opts, path, create=True)
4226 peer.close()
4177 peer.close()
4227
4178
4228
4179
4229 @command(
4180 @command(
4230 b'locate',
4181 b'locate',
4231 [
4182 [
4232 (
4183 (
4233 b'r',
4184 b'r',
4234 b'rev',
4185 b'rev',
4235 b'',
4186 b'',
4236 _(b'search the repository as it is in REV'),
4187 _(b'search the repository as it is in REV'),
4237 _(b'REV'),
4188 _(b'REV'),
4238 ),
4189 ),
4239 (
4190 (
4240 b'0',
4191 b'0',
4241 b'print0',
4192 b'print0',
4242 None,
4193 None,
4243 _(b'end filenames with NUL, for use with xargs'),
4194 _(b'end filenames with NUL, for use with xargs'),
4244 ),
4195 ),
4245 (
4196 (
4246 b'f',
4197 b'f',
4247 b'fullpath',
4198 b'fullpath',
4248 None,
4199 None,
4249 _(b'print complete paths from the filesystem root'),
4200 _(b'print complete paths from the filesystem root'),
4250 ),
4201 ),
4251 ]
4202 ]
4252 + walkopts,
4203 + walkopts,
4253 _(b'[OPTION]... [PATTERN]...'),
4204 _(b'[OPTION]... [PATTERN]...'),
4254 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4205 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4255 )
4206 )
4256 def locate(ui, repo, *pats, **opts):
4207 def locate(ui, repo, *pats, **opts):
4257 """locate files matching specific patterns (DEPRECATED)
4208 """locate files matching specific patterns (DEPRECATED)
4258
4209
4259 Print files under Mercurial control in the working directory whose
4210 Print files under Mercurial control in the working directory whose
4260 names match the given patterns.
4211 names match the given patterns.
4261
4212
4262 By default, this command searches all directories in the working
4213 By default, this command searches all directories in the working
4263 directory. To search just the current directory and its
4214 directory. To search just the current directory and its
4264 subdirectories, use "--include .".
4215 subdirectories, use "--include .".
4265
4216
4266 If no patterns are given to match, this command prints the names
4217 If no patterns are given to match, this command prints the names
4267 of all files under Mercurial control in the working directory.
4218 of all files under Mercurial control in the working directory.
4268
4219
4269 If you want to feed the output of this command into the "xargs"
4220 If you want to feed the output of this command into the "xargs"
4270 command, use the -0 option to both this command and "xargs". This
4221 command, use the -0 option to both this command and "xargs". This
4271 will avoid the problem of "xargs" treating single filenames that
4222 will avoid the problem of "xargs" treating single filenames that
4272 contain whitespace as multiple filenames.
4223 contain whitespace as multiple filenames.
4273
4224
4274 See :hg:`help files` for a more versatile command.
4225 See :hg:`help files` for a more versatile command.
4275
4226
4276 Returns 0 if a match is found, 1 otherwise.
4227 Returns 0 if a match is found, 1 otherwise.
4277 """
4228 """
4278 if opts.get('print0'):
4229 if opts.get('print0'):
4279 end = b'\0'
4230 end = b'\0'
4280 else:
4231 else:
4281 end = b'\n'
4232 end = b'\n'
4282 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4233 ctx = logcmdutil.revsingle(repo, opts.get('rev'), None)
4283
4234
4284 ret = 1
4235 ret = 1
4285 m = scmutil.match(
4236 m = scmutil.match(
4286 ctx,
4237 ctx,
4287 pats,
4238 pats,
4288 pycompat.byteskwargs(opts),
4239 pycompat.byteskwargs(opts),
4289 default=b'relglob',
4240 default=b'relglob',
4290 badfn=lambda x, y: False,
4241 badfn=lambda x, y: False,
4291 )
4242 )
4292
4243
4293 ui.pager(b'locate')
4244 ui.pager(b'locate')
4294 if ctx.rev() is None:
4245 if ctx.rev() is None:
4295 # When run on the working copy, "locate" includes removed files, so
4246 # When run on the working copy, "locate" includes removed files, so
4296 # we get the list of files from the dirstate.
4247 # we get the list of files from the dirstate.
4297 filesgen = sorted(repo.dirstate.matches(m))
4248 filesgen = sorted(repo.dirstate.matches(m))
4298 else:
4249 else:
4299 filesgen = ctx.matches(m)
4250 filesgen = ctx.matches(m)
4300 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4251 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4301 for abs in filesgen:
4252 for abs in filesgen:
4302 if opts.get('fullpath'):
4253 if opts.get('fullpath'):
4303 ui.write(repo.wjoin(abs), end)
4254 ui.write(repo.wjoin(abs), end)
4304 else:
4255 else:
4305 ui.write(uipathfn(abs), end)
4256 ui.write(uipathfn(abs), end)
4306 ret = 0
4257 ret = 0
4307
4258
4308 return ret
4259 return ret
4309
4260
4310
4261
4311 @command(
4262 @command(
4312 b'log|history',
4263 b'log|history',
4313 [
4264 [
4314 (
4265 (
4315 b'f',
4266 b'f',
4316 b'follow',
4267 b'follow',
4317 None,
4268 None,
4318 _(
4269 _(
4319 b'follow changeset history, or file history across copies and renames'
4270 b'follow changeset history, or file history across copies and renames'
4320 ),
4271 ),
4321 ),
4272 ),
4322 (
4273 (
4323 b'',
4274 b'',
4324 b'follow-first',
4275 b'follow-first',
4325 None,
4276 None,
4326 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4277 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4327 ),
4278 ),
4328 (
4279 (
4329 b'd',
4280 b'd',
4330 b'date',
4281 b'date',
4331 b'',
4282 b'',
4332 _(b'show revisions matching date spec'),
4283 _(b'show revisions matching date spec'),
4333 _(b'DATE'),
4284 _(b'DATE'),
4334 ),
4285 ),
4335 (b'C', b'copies', None, _(b'show copied files')),
4286 (b'C', b'copies', None, _(b'show copied files')),
4336 (
4287 (
4337 b'k',
4288 b'k',
4338 b'keyword',
4289 b'keyword',
4339 [],
4290 [],
4340 _(b'do case-insensitive search for a given text'),
4291 _(b'do case-insensitive search for a given text'),
4341 _(b'TEXT'),
4292 _(b'TEXT'),
4342 ),
4293 ),
4343 (
4294 (
4344 b'r',
4295 b'r',
4345 b'rev',
4296 b'rev',
4346 [],
4297 [],
4347 _(b'revisions to select or follow from'),
4298 _(b'revisions to select or follow from'),
4348 _(b'REV'),
4299 _(b'REV'),
4349 ),
4300 ),
4350 (
4301 (
4351 b'L',
4302 b'L',
4352 b'line-range',
4303 b'line-range',
4353 [],
4304 [],
4354 _(b'follow line range of specified file (EXPERIMENTAL)'),
4305 _(b'follow line range of specified file (EXPERIMENTAL)'),
4355 _(b'FILE,RANGE'),
4306 _(b'FILE,RANGE'),
4356 ),
4307 ),
4357 (
4308 (
4358 b'',
4309 b'',
4359 b'removed',
4310 b'removed',
4360 None,
4311 None,
4361 _(b'include revisions where files were removed'),
4312 _(b'include revisions where files were removed'),
4362 ),
4313 ),
4363 (
4314 (
4364 b'm',
4315 b'm',
4365 b'only-merges',
4316 b'only-merges',
4366 None,
4317 None,
4367 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4318 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4368 ),
4319 ),
4369 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4320 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4370 (
4321 (
4371 b'',
4322 b'',
4372 b'only-branch',
4323 b'only-branch',
4373 [],
4324 [],
4374 _(
4325 _(
4375 b'show only changesets within the given named branch (DEPRECATED)'
4326 b'show only changesets within the given named branch (DEPRECATED)'
4376 ),
4327 ),
4377 _(b'BRANCH'),
4328 _(b'BRANCH'),
4378 ),
4329 ),
4379 (
4330 (
4380 b'b',
4331 b'b',
4381 b'branch',
4332 b'branch',
4382 [],
4333 [],
4383 _(b'show changesets within the given named branch'),
4334 _(b'show changesets within the given named branch'),
4384 _(b'BRANCH'),
4335 _(b'BRANCH'),
4385 ),
4336 ),
4386 (
4337 (
4387 b'B',
4338 b'B',
4388 b'bookmark',
4339 b'bookmark',
4389 [],
4340 [],
4390 _(b"show changesets within the given bookmark"),
4341 _(b"show changesets within the given bookmark"),
4391 _(b'BOOKMARK'),
4342 _(b'BOOKMARK'),
4392 ),
4343 ),
4393 (
4344 (
4394 b'P',
4345 b'P',
4395 b'prune',
4346 b'prune',
4396 [],
4347 [],
4397 _(b'do not display revision or any of its ancestors'),
4348 _(b'do not display revision or any of its ancestors'),
4398 _(b'REV'),
4349 _(b'REV'),
4399 ),
4350 ),
4400 ]
4351 ]
4401 + logopts
4352 + logopts
4402 + walkopts,
4353 + walkopts,
4403 _(b'[OPTION]... [FILE]'),
4354 _(b'[OPTION]... [FILE]'),
4404 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4355 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4405 helpbasic=True,
4356 helpbasic=True,
4406 inferrepo=True,
4357 inferrepo=True,
4407 intents={INTENT_READONLY},
4358 intents={INTENT_READONLY},
4408 )
4359 )
4409 def log(ui, repo, *pats, **opts):
4360 def log(ui, repo, *pats, **opts):
4410 """show revision history of entire repository or files
4361 """show revision history of entire repository or files
4411
4362
4412 Print the revision history of the specified files or the entire
4363 Print the revision history of the specified files or the entire
4413 project.
4364 project.
4414
4365
4415 If no revision range is specified, the default is ``tip:0`` unless
4366 If no revision range is specified, the default is ``tip:0`` unless
4416 --follow is set.
4367 --follow is set.
4417
4368
4418 File history is shown without following rename or copy history of
4369 File history is shown without following rename or copy history of
4419 files. Use -f/--follow with a filename to follow history across
4370 files. Use -f/--follow with a filename to follow history across
4420 renames and copies. --follow without a filename will only show
4371 renames and copies. --follow without a filename will only show
4421 ancestors of the starting revisions. The starting revisions can be
4372 ancestors of the starting revisions. The starting revisions can be
4422 specified by -r/--rev, which default to the working directory parent.
4373 specified by -r/--rev, which default to the working directory parent.
4423
4374
4424 By default this command prints revision number and changeset id,
4375 By default this command prints revision number and changeset id,
4425 tags, non-trivial parents, user, date and time, and a summary for
4376 tags, non-trivial parents, user, date and time, and a summary for
4426 each commit. When the -v/--verbose switch is used, the list of
4377 each commit. When the -v/--verbose switch is used, the list of
4427 changed files and full commit message are shown.
4378 changed files and full commit message are shown.
4428
4379
4429 With --graph the revisions are shown as an ASCII art DAG with the most
4380 With --graph the revisions are shown as an ASCII art DAG with the most
4430 recent changeset at the top.
4381 recent changeset at the top.
4431 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4382 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4432 involved in an unresolved merge conflict, '_' closes a branch,
4383 involved in an unresolved merge conflict, '_' closes a branch,
4433 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4384 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4434 changeset from the lines below is a parent of the 'o' merge on the same
4385 changeset from the lines below is a parent of the 'o' merge on the same
4435 line.
4386 line.
4436 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4387 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4437 of a '|' indicates one or more revisions in a path are omitted.
4388 of a '|' indicates one or more revisions in a path are omitted.
4438
4389
4439 .. container:: verbose
4390 .. container:: verbose
4440
4391
4441 Use -L/--line-range FILE,M:N options to follow the history of lines
4392 Use -L/--line-range FILE,M:N options to follow the history of lines
4442 from M to N in FILE. With -p/--patch only diff hunks affecting
4393 from M to N in FILE. With -p/--patch only diff hunks affecting
4443 specified line range will be shown. This option requires --follow;
4394 specified line range will be shown. This option requires --follow;
4444 it can be specified multiple times. Currently, this option is not
4395 it can be specified multiple times. Currently, this option is not
4445 compatible with --graph. This option is experimental.
4396 compatible with --graph. This option is experimental.
4446
4397
4447 .. note::
4398 .. note::
4448
4399
4449 :hg:`log --patch` may generate unexpected diff output for merge
4400 :hg:`log --patch` may generate unexpected diff output for merge
4450 changesets, as it will only compare the merge changeset against
4401 changesets, as it will only compare the merge changeset against
4451 its first parent. Also, only files different from BOTH parents
4402 its first parent. Also, only files different from BOTH parents
4452 will appear in files:.
4403 will appear in files:.
4453
4404
4454 .. note::
4405 .. note::
4455
4406
4456 For performance reasons, :hg:`log FILE` may omit duplicate changes
4407 For performance reasons, :hg:`log FILE` may omit duplicate changes
4457 made on branches and will not show removals or mode changes. To
4408 made on branches and will not show removals or mode changes. To
4458 see all such changes, use the --removed switch.
4409 see all such changes, use the --removed switch.
4459
4410
4460 .. container:: verbose
4411 .. container:: verbose
4461
4412
4462 .. note::
4413 .. note::
4463
4414
4464 The history resulting from -L/--line-range options depends on diff
4415 The history resulting from -L/--line-range options depends on diff
4465 options; for instance if white-spaces are ignored, respective changes
4416 options; for instance if white-spaces are ignored, respective changes
4466 with only white-spaces in specified line range will not be listed.
4417 with only white-spaces in specified line range will not be listed.
4467
4418
4468 .. container:: verbose
4419 .. container:: verbose
4469
4420
4470 Some examples:
4421 Some examples:
4471
4422
4472 - changesets with full descriptions and file lists::
4423 - changesets with full descriptions and file lists::
4473
4424
4474 hg log -v
4425 hg log -v
4475
4426
4476 - changesets ancestral to the working directory::
4427 - changesets ancestral to the working directory::
4477
4428
4478 hg log -f
4429 hg log -f
4479
4430
4480 - last 10 commits on the current branch::
4431 - last 10 commits on the current branch::
4481
4432
4482 hg log -l 10 -b .
4433 hg log -l 10 -b .
4483
4434
4484 - changesets showing all modifications of a file, including removals::
4435 - changesets showing all modifications of a file, including removals::
4485
4436
4486 hg log --removed file.c
4437 hg log --removed file.c
4487
4438
4488 - all changesets that touch a directory, with diffs, excluding merges::
4439 - all changesets that touch a directory, with diffs, excluding merges::
4489
4440
4490 hg log -Mp lib/
4441 hg log -Mp lib/
4491
4442
4492 - all revision numbers that match a keyword::
4443 - all revision numbers that match a keyword::
4493
4444
4494 hg log -k bug --template "{rev}\\n"
4445 hg log -k bug --template "{rev}\\n"
4495
4446
4496 - the full hash identifier of the working directory parent::
4447 - the full hash identifier of the working directory parent::
4497
4448
4498 hg log -r . --template "{node}\\n"
4449 hg log -r . --template "{node}\\n"
4499
4450
4500 - list available log templates::
4451 - list available log templates::
4501
4452
4502 hg log -T list
4453 hg log -T list
4503
4454
4504 - check if a given changeset is included in a tagged release::
4455 - check if a given changeset is included in a tagged release::
4505
4456
4506 hg log -r "a21ccf and ancestor(1.9)"
4457 hg log -r "a21ccf and ancestor(1.9)"
4507
4458
4508 - find all changesets by some user in a date range::
4459 - find all changesets by some user in a date range::
4509
4460
4510 hg log -k alice -d "may 2008 to jul 2008"
4461 hg log -k alice -d "may 2008 to jul 2008"
4511
4462
4512 - summary of all changesets after the last tag::
4463 - summary of all changesets after the last tag::
4513
4464
4514 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4465 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4515
4466
4516 - changesets touching lines 13 to 23 for file.c::
4467 - changesets touching lines 13 to 23 for file.c::
4517
4468
4518 hg log -L file.c,13:23
4469 hg log -L file.c,13:23
4519
4470
4520 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4471 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4521 main.c with patch::
4472 main.c with patch::
4522
4473
4523 hg log -L file.c,13:23 -L main.c,2:6 -p
4474 hg log -L file.c,13:23 -L main.c,2:6 -p
4524
4475
4525 See :hg:`help dates` for a list of formats valid for -d/--date.
4476 See :hg:`help dates` for a list of formats valid for -d/--date.
4526
4477
4527 See :hg:`help revisions` for more about specifying and ordering
4478 See :hg:`help revisions` for more about specifying and ordering
4528 revisions.
4479 revisions.
4529
4480
4530 See :hg:`help templates` for more about pre-packaged styles and
4481 See :hg:`help templates` for more about pre-packaged styles and
4531 specifying custom templates. The default template used by the log
4482 specifying custom templates. The default template used by the log
4532 command can be customized via the ``command-templates.log`` configuration
4483 command can be customized via the ``command-templates.log`` configuration
4533 setting.
4484 setting.
4534
4485
4535 Returns 0 on success.
4486 Returns 0 on success.
4536
4487
4537 """
4488 """
4538 opts = pycompat.byteskwargs(opts)
4489 opts = pycompat.byteskwargs(opts)
4539 linerange = opts.get(b'line_range')
4490 linerange = opts.get(b'line_range')
4540
4491
4541 if linerange and not opts.get(b'follow'):
4492 if linerange and not opts.get(b'follow'):
4542 raise error.InputError(_(b'--line-range requires --follow'))
4493 raise error.InputError(_(b'--line-range requires --follow'))
4543
4494
4544 if linerange and pats:
4495 if linerange and pats:
4545 # TODO: take pats as patterns with no line-range filter
4496 # TODO: take pats as patterns with no line-range filter
4546 raise error.InputError(
4497 raise error.InputError(
4547 _(b'FILE arguments are not compatible with --line-range option')
4498 _(b'FILE arguments are not compatible with --line-range option')
4548 )
4499 )
4549
4500
4550 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4501 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4551 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4502 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4552 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4503 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4553 if linerange:
4504 if linerange:
4554 # TODO: should follow file history from logcmdutil._initialrevs(),
4505 # TODO: should follow file history from logcmdutil._initialrevs(),
4555 # then filter the result by logcmdutil._makerevset() and --limit
4506 # then filter the result by logcmdutil._makerevset() and --limit
4556 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4507 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4557
4508
4558 getcopies = None
4509 getcopies = None
4559 if opts.get(b'copies'):
4510 if opts.get(b'copies'):
4560 endrev = None
4511 endrev = None
4561 if revs:
4512 if revs:
4562 endrev = revs.max() + 1
4513 endrev = revs.max() + 1
4563 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4514 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4564
4515
4565 ui.pager(b'log')
4516 ui.pager(b'log')
4566 displayer = logcmdutil.changesetdisplayer(
4517 displayer = logcmdutil.changesetdisplayer(
4567 ui, repo, opts, differ, buffered=True
4518 ui, repo, opts, differ, buffered=True
4568 )
4519 )
4569 if opts.get(b'graph'):
4520 if opts.get(b'graph'):
4570 displayfn = logcmdutil.displaygraphrevs
4521 displayfn = logcmdutil.displaygraphrevs
4571 else:
4522 else:
4572 displayfn = logcmdutil.displayrevs
4523 displayfn = logcmdutil.displayrevs
4573 displayfn(ui, repo, revs, displayer, getcopies)
4524 displayfn(ui, repo, revs, displayer, getcopies)
4574
4525
4575
4526
4576 @command(
4527 @command(
4577 b'manifest',
4528 b'manifest',
4578 [
4529 [
4579 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4530 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4580 (b'', b'all', False, _(b"list files from all revisions")),
4531 (b'', b'all', False, _(b"list files from all revisions")),
4581 ]
4532 ]
4582 + formatteropts,
4533 + formatteropts,
4583 _(b'[-r REV]'),
4534 _(b'[-r REV]'),
4584 helpcategory=command.CATEGORY_MAINTENANCE,
4535 helpcategory=command.CATEGORY_MAINTENANCE,
4585 intents={INTENT_READONLY},
4536 intents={INTENT_READONLY},
4586 )
4537 )
4587 def manifest(ui, repo, node=None, rev=None, **opts):
4538 def manifest(ui, repo, node=None, rev=None, **opts):
4588 """output the current or given revision of the project manifest
4539 """output the current or given revision of the project manifest
4589
4540
4590 Print a list of version controlled files for the given revision.
4541 Print a list of version controlled files for the given revision.
4591 If no revision is given, the first parent of the working directory
4542 If no revision is given, the first parent of the working directory
4592 is used, or the null revision if no revision is checked out.
4543 is used, or the null revision if no revision is checked out.
4593
4544
4594 With -v, print file permissions, symlink and executable bits.
4545 With -v, print file permissions, symlink and executable bits.
4595 With --debug, print file revision hashes.
4546 With --debug, print file revision hashes.
4596
4547
4597 If option --all is specified, the list of all files from all revisions
4548 If option --all is specified, the list of all files from all revisions
4598 is printed. This includes deleted and renamed files.
4549 is printed. This includes deleted and renamed files.
4599
4550
4600 Returns 0 on success.
4551 Returns 0 on success.
4601 """
4552 """
4602 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4553 fm = ui.formatter(b'manifest', pycompat.byteskwargs(opts))
4603
4554
4604 if opts.get('all'):
4555 if opts.get('all'):
4605 if rev or node:
4556 if rev or node:
4606 raise error.InputError(_(b"can't specify a revision with --all"))
4557 raise error.InputError(_(b"can't specify a revision with --all"))
4607
4558
4608 res = set()
4559 res = set()
4609 for rev in repo:
4560 for rev in repo:
4610 ctx = repo[rev]
4561 ctx = repo[rev]
4611 res |= set(ctx.files())
4562 res |= set(ctx.files())
4612
4563
4613 ui.pager(b'manifest')
4564 ui.pager(b'manifest')
4614 for f in sorted(res):
4565 for f in sorted(res):
4615 fm.startitem()
4566 fm.startitem()
4616 fm.write(b"path", b'%s\n', f)
4567 fm.write(b"path", b'%s\n', f)
4617 fm.end()
4568 fm.end()
4618 return
4569 return
4619
4570
4620 if rev and node:
4571 if rev and node:
4621 raise error.InputError(_(b"please specify just one revision"))
4572 raise error.InputError(_(b"please specify just one revision"))
4622
4573
4623 if not node:
4574 if not node:
4624 node = rev
4575 node = rev
4625
4576
4626 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4577 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4627 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4578 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4628 if node:
4579 if node:
4629 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4580 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4630 ctx = logcmdutil.revsingle(repo, node)
4581 ctx = logcmdutil.revsingle(repo, node)
4631 mf = ctx.manifest()
4582 mf = ctx.manifest()
4632 ui.pager(b'manifest')
4583 ui.pager(b'manifest')
4633 for f in ctx:
4584 for f in ctx:
4634 fm.startitem()
4585 fm.startitem()
4635 fm.context(ctx=ctx)
4586 fm.context(ctx=ctx)
4636 fl = ctx[f].flags()
4587 fl = ctx[f].flags()
4637 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4588 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4638 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4589 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4639 fm.write(b'path', b'%s\n', f)
4590 fm.write(b'path', b'%s\n', f)
4640 fm.end()
4591 fm.end()
4641
4592
4642
4593
4643 @command(
4594 @command(
4644 b'merge',
4595 b'merge',
4645 [
4596 [
4646 (
4597 (
4647 b'f',
4598 b'f',
4648 b'force',
4599 b'force',
4649 None,
4600 None,
4650 _(b'force a merge including outstanding changes (DEPRECATED)'),
4601 _(b'force a merge including outstanding changes (DEPRECATED)'),
4651 ),
4602 ),
4652 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4603 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4653 (
4604 (
4654 b'P',
4605 b'P',
4655 b'preview',
4606 b'preview',
4656 None,
4607 None,
4657 _(b'review revisions to merge (no merge is performed)'),
4608 _(b'review revisions to merge (no merge is performed)'),
4658 ),
4609 ),
4659 (b'', b'abort', None, _(b'abort the ongoing merge')),
4610 (b'', b'abort', None, _(b'abort the ongoing merge')),
4660 ]
4611 ]
4661 + mergetoolopts,
4612 + mergetoolopts,
4662 _(b'[-P] [[-r] REV]'),
4613 _(b'[-P] [[-r] REV]'),
4663 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4614 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4664 helpbasic=True,
4615 helpbasic=True,
4665 )
4616 )
4666 def merge(ui, repo, node=None, **opts):
4617 def merge(ui, repo, node=None, **opts):
4667 """merge another revision into working directory
4618 """merge another revision into working directory
4668
4619
4669 The current working directory is updated with all changes made in
4620 The current working directory is updated with all changes made in
4670 the requested revision since the last common predecessor revision.
4621 the requested revision since the last common predecessor revision.
4671
4622
4672 Files that changed between either parent are marked as changed for
4623 Files that changed between either parent are marked as changed for
4673 the next commit and a commit must be performed before any further
4624 the next commit and a commit must be performed before any further
4674 updates to the repository are allowed. The next commit will have
4625 updates to the repository are allowed. The next commit will have
4675 two parents.
4626 two parents.
4676
4627
4677 ``--tool`` can be used to specify the merge tool used for file
4628 ``--tool`` can be used to specify the merge tool used for file
4678 merges. It overrides the HGMERGE environment variable and your
4629 merges. It overrides the HGMERGE environment variable and your
4679 configuration files. See :hg:`help merge-tools` for options.
4630 configuration files. See :hg:`help merge-tools` for options.
4680
4631
4681 If no revision is specified, the working directory's parent is a
4632 If no revision is specified, the working directory's parent is a
4682 head revision, and the current branch contains exactly one other
4633 head revision, and the current branch contains exactly one other
4683 head, the other head is merged with by default. Otherwise, an
4634 head, the other head is merged with by default. Otherwise, an
4684 explicit revision with which to merge must be provided.
4635 explicit revision with which to merge must be provided.
4685
4636
4686 See :hg:`help resolve` for information on handling file conflicts.
4637 See :hg:`help resolve` for information on handling file conflicts.
4687
4638
4688 To undo an uncommitted merge, use :hg:`merge --abort` which
4639 To undo an uncommitted merge, use :hg:`merge --abort` which
4689 will check out a clean copy of the original merge parent, losing
4640 will check out a clean copy of the original merge parent, losing
4690 all changes.
4641 all changes.
4691
4642
4692 Returns 0 on success, 1 if there are unresolved files.
4643 Returns 0 on success, 1 if there are unresolved files.
4693 """
4644 """
4694
4645
4695 abort = opts.get('abort')
4646 abort = opts.get('abort')
4696 if abort and repo.dirstate.p2() == repo.nullid:
4647 if abort and repo.dirstate.p2() == repo.nullid:
4697 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4648 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4698 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4649 cmdutil.check_incompatible_arguments(opts, 'abort', ['rev', 'preview'])
4699 if abort:
4650 if abort:
4700 state = cmdutil.getunfinishedstate(repo)
4651 state = cmdutil.getunfinishedstate(repo)
4701 if state and state._opname != b'merge':
4652 if state and state._opname != b'merge':
4702 raise error.StateError(
4653 raise error.StateError(
4703 _(b'cannot abort merge with %s in progress') % (state._opname),
4654 _(b'cannot abort merge with %s in progress') % (state._opname),
4704 hint=state.hint(),
4655 hint=state.hint(),
4705 )
4656 )
4706 if node:
4657 if node:
4707 raise error.InputError(_(b"cannot specify a node with --abort"))
4658 raise error.InputError(_(b"cannot specify a node with --abort"))
4708 return hg.abortmerge(repo.ui, repo)
4659 return hg.abortmerge(repo.ui, repo)
4709
4660
4710 if opts.get('rev') and node:
4661 if opts.get('rev') and node:
4711 raise error.InputError(_(b"please specify just one revision"))
4662 raise error.InputError(_(b"please specify just one revision"))
4712 if not node:
4663 if not node:
4713 node = opts.get('rev')
4664 node = opts.get('rev')
4714
4665
4715 if node:
4666 if node:
4716 ctx = logcmdutil.revsingle(repo, node)
4667 ctx = logcmdutil.revsingle(repo, node)
4717 else:
4668 else:
4718 if ui.configbool(b'commands', b'merge.require-rev'):
4669 if ui.configbool(b'commands', b'merge.require-rev'):
4719 raise error.InputError(
4670 raise error.InputError(
4720 _(
4671 _(
4721 b'configuration requires specifying revision to merge '
4672 b'configuration requires specifying revision to merge '
4722 b'with'
4673 b'with'
4723 )
4674 )
4724 )
4675 )
4725 ctx = repo[destutil.destmerge(repo)]
4676 ctx = repo[destutil.destmerge(repo)]
4726
4677
4727 if ctx.node() is None:
4678 if ctx.node() is None:
4728 raise error.InputError(
4679 raise error.InputError(
4729 _(b'merging with the working copy has no effect')
4680 _(b'merging with the working copy has no effect')
4730 )
4681 )
4731
4682
4732 if opts.get('preview'):
4683 if opts.get('preview'):
4733 # find nodes that are ancestors of p2 but not of p1
4684 # find nodes that are ancestors of p2 but not of p1
4734 p1 = repo[b'.'].node()
4685 p1 = repo[b'.'].node()
4735 p2 = ctx.node()
4686 p2 = ctx.node()
4736 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4687 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4737
4688
4738 displayer = logcmdutil.changesetdisplayer(
4689 displayer = logcmdutil.changesetdisplayer(
4739 ui, repo, pycompat.byteskwargs(opts)
4690 ui, repo, pycompat.byteskwargs(opts)
4740 )
4691 )
4741 for node in nodes:
4692 for node in nodes:
4742 displayer.show(repo[node])
4693 displayer.show(repo[node])
4743 displayer.close()
4694 displayer.close()
4744 return 0
4695 return 0
4745
4696
4746 # ui.forcemerge is an internal variable, do not document
4697 # ui.forcemerge is an internal variable, do not document
4747 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4698 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
4748 with ui.configoverride(overrides, b'merge'):
4699 with ui.configoverride(overrides, b'merge'):
4749 force = opts.get('force')
4700 force = opts.get('force')
4750 labels = [b'working copy', b'merge rev', b'common ancestor']
4701 labels = [b'working copy', b'merge rev', b'common ancestor']
4751 return hg.merge(ctx, force=force, labels=labels)
4702 return hg.merge(ctx, force=force, labels=labels)
4752
4703
4753
4704
4754 statemod.addunfinished(
4705 statemod.addunfinished(
4755 b'merge',
4706 b'merge',
4756 fname=None,
4707 fname=None,
4757 clearable=True,
4708 clearable=True,
4758 allowcommit=True,
4709 allowcommit=True,
4759 cmdmsg=_(b'outstanding uncommitted merge'),
4710 cmdmsg=_(b'outstanding uncommitted merge'),
4760 abortfunc=hg.abortmerge,
4711 abortfunc=hg.abortmerge,
4761 statushint=_(
4712 statushint=_(
4762 b'To continue: hg commit\nTo abort: hg merge --abort'
4713 b'To continue: hg commit\nTo abort: hg merge --abort'
4763 ),
4714 ),
4764 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4715 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4765 )
4716 )
4766
4717
4767
4718
4768 @command(
4719 @command(
4769 b'outgoing|out',
4720 b'outgoing|out',
4770 [
4721 [
4771 (
4722 (
4772 b'f',
4723 b'f',
4773 b'force',
4724 b'force',
4774 None,
4725 None,
4775 _(b'run even when the destination is unrelated'),
4726 _(b'run even when the destination is unrelated'),
4776 ),
4727 ),
4777 (
4728 (
4778 b'r',
4729 b'r',
4779 b'rev',
4730 b'rev',
4780 [],
4731 [],
4781 _(b'a changeset intended to be included in the destination'),
4732 _(b'a changeset intended to be included in the destination'),
4782 _(b'REV'),
4733 _(b'REV'),
4783 ),
4734 ),
4784 (b'n', b'newest-first', None, _(b'show newest record first')),
4735 (b'n', b'newest-first', None, _(b'show newest record first')),
4785 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4736 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4786 (
4737 (
4787 b'b',
4738 b'b',
4788 b'branch',
4739 b'branch',
4789 [],
4740 [],
4790 _(b'a specific branch you would like to push'),
4741 _(b'a specific branch you would like to push'),
4791 _(b'BRANCH'),
4742 _(b'BRANCH'),
4792 ),
4743 ),
4793 ]
4744 ]
4794 + logopts
4745 + logopts
4795 + remoteopts
4746 + remoteopts
4796 + subrepoopts,
4747 + subrepoopts,
4797 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4748 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4798 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4749 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4799 )
4750 )
4800 def outgoing(ui, repo, *dests, **opts):
4751 def outgoing(ui, repo, *dests, **opts):
4801 """show changesets not found in the destination
4752 """show changesets not found in the destination
4802
4753
4803 Show changesets not found in the specified destination repository
4754 Show changesets not found in the specified destination repository
4804 or the default push location. These are the changesets that would
4755 or the default push location. These are the changesets that would
4805 be pushed if a push was requested.
4756 be pushed if a push was requested.
4806
4757
4807 See pull for details of valid destination formats.
4758 See pull for details of valid destination formats.
4808
4759
4809 .. container:: verbose
4760 .. container:: verbose
4810
4761
4811 With -B/--bookmarks, the result of bookmark comparison between
4762 With -B/--bookmarks, the result of bookmark comparison between
4812 local and remote repositories is displayed. With -v/--verbose,
4763 local and remote repositories is displayed. With -v/--verbose,
4813 status is also displayed for each bookmark like below::
4764 status is also displayed for each bookmark like below::
4814
4765
4815 BM1 01234567890a added
4766 BM1 01234567890a added
4816 BM2 deleted
4767 BM2 deleted
4817 BM3 234567890abc advanced
4768 BM3 234567890abc advanced
4818 BM4 34567890abcd diverged
4769 BM4 34567890abcd diverged
4819 BM5 4567890abcde changed
4770 BM5 4567890abcde changed
4820
4771
4821 The action taken when pushing depends on the
4772 The action taken when pushing depends on the
4822 status of each bookmark:
4773 status of each bookmark:
4823
4774
4824 :``added``: push with ``-B`` will create it
4775 :``added``: push with ``-B`` will create it
4825 :``deleted``: push with ``-B`` will delete it
4776 :``deleted``: push with ``-B`` will delete it
4826 :``advanced``: push will update it
4777 :``advanced``: push will update it
4827 :``diverged``: push with ``-B`` will update it
4778 :``diverged``: push with ``-B`` will update it
4828 :``changed``: push with ``-B`` will update it
4779 :``changed``: push with ``-B`` will update it
4829
4780
4830 From the point of view of pushing behavior, bookmarks
4781 From the point of view of pushing behavior, bookmarks
4831 existing only in the remote repository are treated as
4782 existing only in the remote repository are treated as
4832 ``deleted``, even if it is in fact added remotely.
4783 ``deleted``, even if it is in fact added remotely.
4833
4784
4834 Returns 0 if there are outgoing changes, 1 otherwise.
4785 Returns 0 if there are outgoing changes, 1 otherwise.
4835 """
4786 """
4836 opts = pycompat.byteskwargs(opts)
4787 opts = pycompat.byteskwargs(opts)
4837 if opts.get(b'bookmarks'):
4788 if opts.get(b'bookmarks'):
4838 for path in urlutil.get_push_paths(repo, ui, dests):
4789 for path in urlutil.get_push_paths(repo, ui, dests):
4839 other = hg.peer(repo, opts, path)
4790 other = hg.peer(repo, opts, path)
4840 try:
4791 try:
4841 if b'bookmarks' not in other.listkeys(b'namespaces'):
4792 if b'bookmarks' not in other.listkeys(b'namespaces'):
4842 ui.warn(_(b"remote doesn't support bookmarks\n"))
4793 ui.warn(_(b"remote doesn't support bookmarks\n"))
4843 return 0
4794 return 0
4844 ui.status(
4795 ui.status(
4845 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4796 _(b'comparing with %s\n') % urlutil.hidepassword(path.loc)
4846 )
4797 )
4847 ui.pager(b'outgoing')
4798 ui.pager(b'outgoing')
4848 return bookmarks.outgoing(ui, repo, other)
4799 return bookmarks.outgoing(ui, repo, other)
4849 finally:
4800 finally:
4850 other.close()
4801 other.close()
4851
4802
4852 return hg.outgoing(ui, repo, dests, opts)
4803 return hg.outgoing(ui, repo, dests, opts)
4853
4804
4854
4805
4855 @command(
4806 @command(
4856 b'parents',
4807 b'parents',
4857 [
4808 [
4858 (
4809 (
4859 b'r',
4810 b'r',
4860 b'rev',
4811 b'rev',
4861 b'',
4812 b'',
4862 _(b'show parents of the specified revision'),
4813 _(b'show parents of the specified revision'),
4863 _(b'REV'),
4814 _(b'REV'),
4864 ),
4815 ),
4865 ]
4816 ]
4866 + templateopts,
4817 + templateopts,
4867 _(b'[-r REV] [FILE]'),
4818 _(b'[-r REV] [FILE]'),
4868 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4819 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4869 inferrepo=True,
4820 inferrepo=True,
4870 )
4821 )
4871 def parents(ui, repo, file_=None, **opts):
4822 def parents(ui, repo, file_=None, **opts):
4872 """show the parents of the working directory or revision (DEPRECATED)
4823 """show the parents of the working directory or revision (DEPRECATED)
4873
4824
4874 Print the working directory's parent revisions. If a revision is
4825 Print the working directory's parent revisions. If a revision is
4875 given via -r/--rev, the parent of that revision will be printed.
4826 given via -r/--rev, the parent of that revision will be printed.
4876 If a file argument is given, the revision in which the file was
4827 If a file argument is given, the revision in which the file was
4877 last changed (before the working directory revision or the
4828 last changed (before the working directory revision or the
4878 argument to --rev if given) is printed.
4829 argument to --rev if given) is printed.
4879
4830
4880 This command is equivalent to::
4831 This command is equivalent to::
4881
4832
4882 hg log -r "p1()+p2()" or
4833 hg log -r "p1()+p2()" or
4883 hg log -r "p1(REV)+p2(REV)" or
4834 hg log -r "p1(REV)+p2(REV)" or
4884 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4835 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4885 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4836 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4886
4837
4887 See :hg:`summary` and :hg:`help revsets` for related information.
4838 See :hg:`summary` and :hg:`help revsets` for related information.
4888
4839
4889 Returns 0 on success.
4840 Returns 0 on success.
4890 """
4841 """
4891
4842
4892 opts = pycompat.byteskwargs(opts)
4843 opts = pycompat.byteskwargs(opts)
4893 rev = opts.get(b'rev')
4844 rev = opts.get(b'rev')
4894 if rev:
4845 if rev:
4895 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4846 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4896 ctx = logcmdutil.revsingle(repo, rev, None)
4847 ctx = logcmdutil.revsingle(repo, rev, None)
4897
4848
4898 if file_:
4849 if file_:
4899 m = scmutil.match(ctx, (file_,), opts)
4850 m = scmutil.match(ctx, (file_,), opts)
4900 if m.anypats() or len(m.files()) != 1:
4851 if m.anypats() or len(m.files()) != 1:
4901 raise error.InputError(_(b'can only specify an explicit filename'))
4852 raise error.InputError(_(b'can only specify an explicit filename'))
4902 file_ = m.files()[0]
4853 file_ = m.files()[0]
4903 filenodes = []
4854 filenodes = []
4904 for cp in ctx.parents():
4855 for cp in ctx.parents():
4905 if not cp:
4856 if not cp:
4906 continue
4857 continue
4907 try:
4858 try:
4908 filenodes.append(cp.filenode(file_))
4859 filenodes.append(cp.filenode(file_))
4909 except error.LookupError:
4860 except error.LookupError:
4910 pass
4861 pass
4911 if not filenodes:
4862 if not filenodes:
4912 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4863 raise error.InputError(_(b"'%s' not found in manifest") % file_)
4913 p = []
4864 p = []
4914 for fn in filenodes:
4865 for fn in filenodes:
4915 fctx = repo.filectx(file_, fileid=fn)
4866 fctx = repo.filectx(file_, fileid=fn)
4916 p.append(fctx.node())
4867 p.append(fctx.node())
4917 else:
4868 else:
4918 p = [cp.node() for cp in ctx.parents()]
4869 p = [cp.node() for cp in ctx.parents()]
4919
4870
4920 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4871 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4921 for n in p:
4872 for n in p:
4922 if n != repo.nullid:
4873 if n != repo.nullid:
4923 displayer.show(repo[n])
4874 displayer.show(repo[n])
4924 displayer.close()
4875 displayer.close()
4925
4876
4926
4877
4927 @command(
4878 @command(
4928 b'paths',
4879 b'paths',
4929 formatteropts,
4880 formatteropts,
4930 _(b'[NAME]'),
4881 _(b'[NAME]'),
4931 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4882 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4932 optionalrepo=True,
4883 optionalrepo=True,
4933 intents={INTENT_READONLY},
4884 intents={INTENT_READONLY},
4934 )
4885 )
4935 def paths(ui, repo, search=None, **opts):
4886 def paths(ui, repo, search=None, **opts):
4936 """show aliases for remote repositories
4887 """show aliases for remote repositories
4937
4888
4938 Show definition of symbolic path name NAME. If no name is given,
4889 Show definition of symbolic path name NAME. If no name is given,
4939 show definition of all available names.
4890 show definition of all available names.
4940
4891
4941 Option -q/--quiet suppresses all output when searching for NAME
4892 Option -q/--quiet suppresses all output when searching for NAME
4942 and shows only the path names when listing all definitions.
4893 and shows only the path names when listing all definitions.
4943
4894
4944 Path names are defined in the [paths] section of your
4895 Path names are defined in the [paths] section of your
4945 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4896 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4946 repository, ``.hg/hgrc`` is used, too.
4897 repository, ``.hg/hgrc`` is used, too.
4947
4898
4948 The path names ``default`` and ``default-push`` have a special
4899 The path names ``default`` and ``default-push`` have a special
4949 meaning. When performing a push or pull operation, they are used
4900 meaning. When performing a push or pull operation, they are used
4950 as fallbacks if no location is specified on the command-line.
4901 as fallbacks if no location is specified on the command-line.
4951 When ``default-push`` is set, it will be used for push and
4902 When ``default-push`` is set, it will be used for push and
4952 ``default`` will be used for pull; otherwise ``default`` is used
4903 ``default`` will be used for pull; otherwise ``default`` is used
4953 as the fallback for both. When cloning a repository, the clone
4904 as the fallback for both. When cloning a repository, the clone
4954 source is written as ``default`` in ``.hg/hgrc``.
4905 source is written as ``default`` in ``.hg/hgrc``.
4955
4906
4956 .. note::
4907 .. note::
4957
4908
4958 ``default`` and ``default-push`` apply to all inbound (e.g.
4909 ``default`` and ``default-push`` apply to all inbound (e.g.
4959 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4910 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4960 and :hg:`bundle`) operations.
4911 and :hg:`bundle`) operations.
4961
4912
4962 See :hg:`help urls` for more information.
4913 See :hg:`help urls` for more information.
4963
4914
4964 .. container:: verbose
4915 .. container:: verbose
4965
4916
4966 Template:
4917 Template:
4967
4918
4968 The following keywords are supported. See also :hg:`help templates`.
4919 The following keywords are supported. See also :hg:`help templates`.
4969
4920
4970 :name: String. Symbolic name of the path alias.
4921 :name: String. Symbolic name of the path alias.
4971 :pushurl: String. URL for push operations.
4922 :pushurl: String. URL for push operations.
4972 :url: String. URL or directory path for the other operations.
4923 :url: String. URL or directory path for the other operations.
4973
4924
4974 Returns 0 on success.
4925 Returns 0 on success.
4975 """
4926 """
4976
4927
4977 pathitems = urlutil.list_paths(ui, search)
4928 pathitems = urlutil.list_paths(ui, search)
4978 ui.pager(b'paths')
4929 ui.pager(b'paths')
4979
4930
4980 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4931 fm = ui.formatter(b'paths', pycompat.byteskwargs(opts))
4981 if fm.isplain():
4932 if fm.isplain():
4982 hidepassword = urlutil.hidepassword
4933 hidepassword = urlutil.hidepassword
4983 else:
4934 else:
4984 hidepassword = bytes
4935 hidepassword = bytes
4985 if ui.quiet:
4936 if ui.quiet:
4986 namefmt = b'%s\n'
4937 namefmt = b'%s\n'
4987 else:
4938 else:
4988 namefmt = b'%s = '
4939 namefmt = b'%s = '
4989 showsubopts = not search and not ui.quiet
4940 showsubopts = not search and not ui.quiet
4990
4941
4991 for name, path in pathitems:
4942 for name, path in pathitems:
4992 fm.startitem()
4943 fm.startitem()
4993 fm.condwrite(not search, b'name', namefmt, name)
4944 fm.condwrite(not search, b'name', namefmt, name)
4994 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4945 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
4995 for subopt, value in sorted(path.suboptions.items()):
4946 for subopt, value in sorted(path.suboptions.items()):
4996 assert subopt not in (b'name', b'url')
4947 assert subopt not in (b'name', b'url')
4997 if showsubopts:
4948 if showsubopts:
4998 fm.plain(b'%s:%s = ' % (name, subopt))
4949 fm.plain(b'%s:%s = ' % (name, subopt))
4999 display = urlutil.path_suboptions_display[subopt]
4950 display = urlutil.path_suboptions_display[subopt]
5000 value = display(value)
4951 value = display(value)
5001 fm.condwrite(showsubopts, subopt, b'%s\n', value)
4952 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5002
4953
5003 fm.end()
4954 fm.end()
5004
4955
5005 if search and not pathitems:
4956 if search and not pathitems:
5006 if not ui.quiet:
4957 if not ui.quiet:
5007 ui.warn(_(b"not found!\n"))
4958 ui.warn(_(b"not found!\n"))
5008 return 1
4959 return 1
5009 else:
4960 else:
5010 return 0
4961 return 0
5011
4962
5012
4963
5013 @command(
4964 @command(
5014 b'phase',
4965 b'phase',
5015 [
4966 [
5016 (b'p', b'public', False, _(b'set changeset phase to public')),
4967 (b'p', b'public', False, _(b'set changeset phase to public')),
5017 (b'd', b'draft', False, _(b'set changeset phase to draft')),
4968 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5018 (b's', b'secret', False, _(b'set changeset phase to secret')),
4969 (b's', b'secret', False, _(b'set changeset phase to secret')),
5019 (b'f', b'force', False, _(b'allow to move boundary backward')),
4970 (b'f', b'force', False, _(b'allow to move boundary backward')),
5020 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
4971 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5021 ],
4972 ],
5022 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
4973 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5023 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
4974 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5024 )
4975 )
5025 def phase(ui, repo, *revs, **opts):
4976 def phase(ui, repo, *revs, **opts):
5026 """set or show the current phase name
4977 """set or show the current phase name
5027
4978
5028 With no argument, show the phase name of the current revision(s).
4979 With no argument, show the phase name of the current revision(s).
5029
4980
5030 With one of -p/--public, -d/--draft or -s/--secret, change the
4981 With one of -p/--public, -d/--draft or -s/--secret, change the
5031 phase value of the specified revisions.
4982 phase value of the specified revisions.
5032
4983
5033 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4984 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5034 lower phase to a higher phase. Phases are ordered as follows::
4985 lower phase to a higher phase. Phases are ordered as follows::
5035
4986
5036 public < draft < secret
4987 public < draft < secret
5037
4988
5038 Returns 0 on success, 1 if some phases could not be changed.
4989 Returns 0 on success, 1 if some phases could not be changed.
5039
4990
5040 (For more information about the phases concept, see :hg:`help phases`.)
4991 (For more information about the phases concept, see :hg:`help phases`.)
5041 """
4992 """
5042 opts = pycompat.byteskwargs(opts)
4993 opts = pycompat.byteskwargs(opts)
5043 # search for a unique phase argument
4994 # search for a unique phase argument
5044 targetphase = None
4995 targetphase = None
5045 for idx, name in enumerate(phases.cmdphasenames):
4996 for idx, name in enumerate(phases.cmdphasenames):
5046 if opts[name]:
4997 if opts[name]:
5047 if targetphase is not None:
4998 if targetphase is not None:
5048 raise error.InputError(_(b'only one phase can be specified'))
4999 raise error.InputError(_(b'only one phase can be specified'))
5049 targetphase = idx
5000 targetphase = idx
5050
5001
5051 # look for specified revision
5002 # look for specified revision
5052 revs = list(revs)
5003 revs = list(revs)
5053 revs.extend(opts[b'rev'])
5004 revs.extend(opts[b'rev'])
5054 if revs:
5005 if revs:
5055 revs = logcmdutil.revrange(repo, revs)
5006 revs = logcmdutil.revrange(repo, revs)
5056 else:
5007 else:
5057 # display both parents as the second parent phase can influence
5008 # display both parents as the second parent phase can influence
5058 # the phase of a merge commit
5009 # the phase of a merge commit
5059 revs = [c.rev() for c in repo[None].parents()]
5010 revs = [c.rev() for c in repo[None].parents()]
5060
5011
5061 ret = 0
5012 ret = 0
5062 if targetphase is None:
5013 if targetphase is None:
5063 # display
5014 # display
5064 for r in revs:
5015 for r in revs:
5065 ctx = repo[r]
5016 ctx = repo[r]
5066 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5017 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5067 else:
5018 else:
5068 with repo.lock(), repo.transaction(b"phase") as tr:
5019 with repo.lock(), repo.transaction(b"phase") as tr:
5069 # set phase
5020 # set phase
5070 if not revs:
5021 if not revs:
5071 raise error.InputError(_(b'empty revision set'))
5022 raise error.InputError(_(b'empty revision set'))
5072 nodes = [repo[r].node() for r in revs]
5023 nodes = [repo[r].node() for r in revs]
5073 # moving revision from public to draft may hide them
5024 # moving revision from public to draft may hide them
5074 # We have to check result on an unfiltered repository
5025 # We have to check result on an unfiltered repository
5075 unfi = repo.unfiltered()
5026 unfi = repo.unfiltered()
5076 getphase = unfi._phasecache.phase
5027 getphase = unfi._phasecache.phase
5077 olddata = [getphase(unfi, r) for r in unfi]
5028 olddata = [getphase(unfi, r) for r in unfi]
5078 phases.advanceboundary(repo, tr, targetphase, nodes)
5029 phases.advanceboundary(repo, tr, targetphase, nodes)
5079 if opts[b'force']:
5030 if opts[b'force']:
5080 phases.retractboundary(repo, tr, targetphase, nodes)
5031 phases.retractboundary(repo, tr, targetphase, nodes)
5081 getphase = unfi._phasecache.phase
5032 getphase = unfi._phasecache.phase
5082 newdata = [getphase(unfi, r) for r in unfi]
5033 newdata = [getphase(unfi, r) for r in unfi]
5083 changes = sum(newdata[r] != olddata[r] for r in unfi)
5034 changes = sum(newdata[r] != olddata[r] for r in unfi)
5084 cl = unfi.changelog
5035 cl = unfi.changelog
5085 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5036 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5086 if rejected:
5037 if rejected:
5087 ui.warn(
5038 ui.warn(
5088 _(
5039 _(
5089 b'cannot move %i changesets to a higher '
5040 b'cannot move %i changesets to a higher '
5090 b'phase, use --force\n'
5041 b'phase, use --force\n'
5091 )
5042 )
5092 % len(rejected)
5043 % len(rejected)
5093 )
5044 )
5094 ret = 1
5045 ret = 1
5095 if changes:
5046 if changes:
5096 msg = _(b'phase changed for %i changesets\n') % changes
5047 msg = _(b'phase changed for %i changesets\n') % changes
5097 if ret:
5048 if ret:
5098 ui.status(msg)
5049 ui.status(msg)
5099 else:
5050 else:
5100 ui.note(msg)
5051 ui.note(msg)
5101 else:
5052 else:
5102 ui.warn(_(b'no phases changed\n'))
5053 ui.warn(_(b'no phases changed\n'))
5103 return ret
5054 return ret
5104
5055
5105
5056
5106 @command(
5057 @command(
5107 b'pull',
5058 b'pull',
5108 [
5059 [
5109 (
5060 (
5110 b'u',
5061 b'u',
5111 b'update',
5062 b'update',
5112 None,
5063 None,
5113 _(b'update to new branch head if new descendants were pulled'),
5064 _(b'update to new branch head if new descendants were pulled'),
5114 ),
5065 ),
5115 (
5066 (
5116 b'f',
5067 b'f',
5117 b'force',
5068 b'force',
5118 None,
5069 None,
5119 _(b'run even when remote repository is unrelated'),
5070 _(b'run even when remote repository is unrelated'),
5120 ),
5071 ),
5121 (
5072 (
5122 b'',
5073 b'',
5123 b'confirm',
5074 b'confirm',
5124 None,
5075 None,
5125 _(b'confirm pull before applying changes'),
5076 _(b'confirm pull before applying changes'),
5126 ),
5077 ),
5127 (
5078 (
5128 b'r',
5079 b'r',
5129 b'rev',
5080 b'rev',
5130 [],
5081 [],
5131 _(b'a remote changeset intended to be added'),
5082 _(b'a remote changeset intended to be added'),
5132 _(b'REV'),
5083 _(b'REV'),
5133 ),
5084 ),
5134 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5085 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5135 (
5086 (
5136 b'b',
5087 b'b',
5137 b'branch',
5088 b'branch',
5138 [],
5089 [],
5139 _(b'a specific branch you would like to pull'),
5090 _(b'a specific branch you would like to pull'),
5140 _(b'BRANCH'),
5091 _(b'BRANCH'),
5141 ),
5092 ),
5142 (
5093 (
5143 b'',
5094 b'',
5144 b'remote-hidden',
5095 b'remote-hidden',
5145 False,
5096 False,
5146 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5097 _(b"include changesets hidden on the remote (EXPERIMENTAL)"),
5147 ),
5098 ),
5148 ]
5099 ]
5149 + remoteopts,
5100 + remoteopts,
5150 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5101 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5151 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5102 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5152 helpbasic=True,
5103 helpbasic=True,
5153 )
5104 )
5154 def pull(ui, repo, *sources, **opts):
5105 def pull(ui, repo, *sources, **opts):
5155 """pull changes from the specified source
5106 """pull changes from the specified source
5156
5107
5157 Pull changes from a remote repository to a local one.
5108 Pull changes from a remote repository to a local one.
5158
5109
5159 This finds all changes from the repository at the specified path
5110 This finds all changes from the repository at the specified path
5160 or URL and adds them to a local repository (the current one unless
5111 or URL and adds them to a local repository (the current one unless
5161 -R is specified). By default, this does not update the copy of the
5112 -R is specified). By default, this does not update the copy of the
5162 project in the working directory.
5113 project in the working directory.
5163
5114
5164 When cloning from servers that support it, Mercurial may fetch
5115 When cloning from servers that support it, Mercurial may fetch
5165 pre-generated data. When this is done, hooks operating on incoming
5116 pre-generated data. When this is done, hooks operating on incoming
5166 changesets and changegroups may fire more than once, once for each
5117 changesets and changegroups may fire more than once, once for each
5167 pre-generated bundle and as well as for any additional remaining
5118 pre-generated bundle and as well as for any additional remaining
5168 data. See :hg:`help -e clonebundles` for more.
5119 data. See :hg:`help -e clonebundles` for more.
5169
5120
5170 Use :hg:`incoming` if you want to see what would have been added
5121 Use :hg:`incoming` if you want to see what would have been added
5171 by a pull at the time you issued this command. If you then decide
5122 by a pull at the time you issued this command. If you then decide
5172 to add those changes to the repository, you should use :hg:`pull
5123 to add those changes to the repository, you should use :hg:`pull
5173 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5124 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5174
5125
5175 If SOURCE is omitted, the 'default' path will be used.
5126 If SOURCE is omitted, the 'default' path will be used.
5176 See :hg:`help urls` for more information.
5127 See :hg:`help urls` for more information.
5177
5128
5178 If multiple sources are specified, they will be pulled sequentially as if
5129 If multiple sources are specified, they will be pulled sequentially as if
5179 the command was run multiple time. If --update is specify and the command
5130 the command was run multiple time. If --update is specify and the command
5180 will stop at the first failed --update.
5131 will stop at the first failed --update.
5181
5132
5182 Specifying bookmark as ``.`` is equivalent to specifying the active
5133 Specifying bookmark as ``.`` is equivalent to specifying the active
5183 bookmark's name.
5134 bookmark's name.
5184
5135
5185 .. container:: verbose
5136 .. container:: verbose
5186
5137
5187 One can use the `--remote-hidden` flag to pull changesets
5138 One can use the `--remote-hidden` flag to pull changesets
5188 hidden on the remote. This flag is "best effort", and will only
5139 hidden on the remote. This flag is "best effort", and will only
5189 work if the server supports the feature and is configured to
5140 work if the server supports the feature and is configured to
5190 allow the user to access hidden changesets. This option is
5141 allow the user to access hidden changesets. This option is
5191 experimental and backwards compatibility is not garanteed.
5142 experimental and backwards compatibility is not garanteed.
5192
5143
5193 Returns 0 on success, 1 if an update had unresolved files.
5144 Returns 0 on success, 1 if an update had unresolved files.
5194 """
5145 """
5195
5146
5196 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5147 if ui.configbool(b'commands', b'update.requiredest') and opts.get('update'):
5197 msg = _(b'update destination required by configuration')
5148 msg = _(b'update destination required by configuration')
5198 hint = _(b'use hg pull followed by hg update DEST')
5149 hint = _(b'use hg pull followed by hg update DEST')
5199 raise error.InputError(msg, hint=hint)
5150 raise error.InputError(msg, hint=hint)
5200
5151
5201 update_conflict = None
5152 update_conflict = None
5202
5153
5203 for path in urlutil.get_pull_paths(repo, ui, sources):
5154 for path in urlutil.get_pull_paths(repo, ui, sources):
5204 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5155 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc))
5205 ui.flush()
5156 ui.flush()
5206 other = hg.peer(
5157 other = hg.peer(
5207 repo,
5158 repo,
5208 pycompat.byteskwargs(opts),
5159 pycompat.byteskwargs(opts),
5209 path,
5160 path,
5210 remotehidden=opts['remote_hidden'],
5161 remotehidden=opts['remote_hidden'],
5211 )
5162 )
5212 update_conflict = None
5163 update_conflict = None
5213 try:
5164 try:
5214 branches = (path.branch, opts.get('branch', []))
5165 branches = (path.branch, opts.get('branch', []))
5215 revs, checkout = hg.addbranchrevs(
5166 revs, checkout = hg.addbranchrevs(
5216 repo,
5167 repo,
5217 other,
5168 other,
5218 branches,
5169 branches,
5219 opts.get('rev'),
5170 opts.get('rev'),
5220 remotehidden=opts['remote_hidden'],
5171 remotehidden=opts['remote_hidden'],
5221 )
5172 )
5222
5173
5223 pullopargs = {}
5174 pullopargs = {}
5224
5175
5225 nodes = None
5176 nodes = None
5226 if opts.get('bookmark') or revs:
5177 if opts.get('bookmark') or revs:
5227 # The list of bookmark used here is the same used to actually update
5178 # The list of bookmark used here is the same used to actually update
5228 # the bookmark names, to avoid the race from issue 4689 and we do
5179 # the bookmark names, to avoid the race from issue 4689 and we do
5229 # all lookup and bookmark queries in one go so they see the same
5180 # all lookup and bookmark queries in one go so they see the same
5230 # version of the server state (issue 4700).
5181 # version of the server state (issue 4700).
5231 nodes = []
5182 nodes = []
5232 fnodes = []
5183 fnodes = []
5233 revs = revs or []
5184 revs = revs or []
5234 if revs and not other.capable(b'lookup'):
5185 if revs and not other.capable(b'lookup'):
5235 err = _(
5186 err = _(
5236 b"other repository doesn't support revision lookup, "
5187 b"other repository doesn't support revision lookup, "
5237 b"so a rev cannot be specified."
5188 b"so a rev cannot be specified."
5238 )
5189 )
5239 raise error.Abort(err)
5190 raise error.Abort(err)
5240 with other.commandexecutor() as e:
5191 with other.commandexecutor() as e:
5241 fremotebookmarks = e.callcommand(
5192 fremotebookmarks = e.callcommand(
5242 b'listkeys', {b'namespace': b'bookmarks'}
5193 b'listkeys', {b'namespace': b'bookmarks'}
5243 )
5194 )
5244 for r in revs:
5195 for r in revs:
5245 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5196 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5246 remotebookmarks = fremotebookmarks.result()
5197 remotebookmarks = fremotebookmarks.result()
5247 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5198 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5248 pullopargs[b'remotebookmarks'] = remotebookmarks
5199 pullopargs[b'remotebookmarks'] = remotebookmarks
5249 for b in opts.get('bookmark', []):
5200 for b in opts.get('bookmark', []):
5250 b = repo._bookmarks.expandname(b)
5201 b = repo._bookmarks.expandname(b)
5251 if b not in remotebookmarks:
5202 if b not in remotebookmarks:
5252 raise error.InputError(
5203 raise error.InputError(
5253 _(b'remote bookmark %s not found!') % b
5204 _(b'remote bookmark %s not found!') % b
5254 )
5205 )
5255 nodes.append(remotebookmarks[b])
5206 nodes.append(remotebookmarks[b])
5256 for i, rev in enumerate(revs):
5207 for i, rev in enumerate(revs):
5257 node = fnodes[i].result()
5208 node = fnodes[i].result()
5258 nodes.append(node)
5209 nodes.append(node)
5259 if rev == checkout:
5210 if rev == checkout:
5260 checkout = node
5211 checkout = node
5261
5212
5262 wlock = util.nullcontextmanager()
5213 wlock = util.nullcontextmanager()
5263 if opts.get('update'):
5214 if opts.get('update'):
5264 wlock = repo.wlock()
5215 wlock = repo.wlock()
5265 with wlock:
5216 with wlock:
5266 pullopargs.update(opts.get('opargs', {}))
5217 pullopargs.update(opts.get('opargs', {}))
5267 modheads = exchange.pull(
5218 modheads = exchange.pull(
5268 repo,
5219 repo,
5269 other,
5220 other,
5270 path=path,
5221 path=path,
5271 heads=nodes,
5222 heads=nodes,
5272 force=opts.get('force'),
5223 force=opts.get('force'),
5273 bookmarks=opts.get('bookmark', ()),
5224 bookmarks=opts.get('bookmark', ()),
5274 opargs=pullopargs,
5225 opargs=pullopargs,
5275 confirm=opts.get('confirm'),
5226 confirm=opts.get('confirm'),
5276 ).cgresult
5227 ).cgresult
5277
5228
5278 # brev is a name, which might be a bookmark to be activated at
5229 # brev is a name, which might be a bookmark to be activated at
5279 # the end of the update. In other words, it is an explicit
5230 # the end of the update. In other words, it is an explicit
5280 # destination of the update
5231 # destination of the update
5281 brev = None
5232 brev = None
5282
5233
5283 if checkout:
5234 if checkout:
5284 checkout = repo.unfiltered().changelog.rev(checkout)
5235 checkout = repo.unfiltered().changelog.rev(checkout)
5285
5236
5286 # order below depends on implementation of
5237 # order below depends on implementation of
5287 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5238 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5288 # because 'checkout' is determined without it.
5239 # because 'checkout' is determined without it.
5289 if opts.get('rev'):
5240 if opts.get('rev'):
5290 brev = opts['rev'][0]
5241 brev = opts['rev'][0]
5291 elif opts.get('branch'):
5242 elif opts.get('branch'):
5292 brev = opts['branch'][0]
5243 brev = opts['branch'][0]
5293 else:
5244 else:
5294 brev = path.branch
5245 brev = path.branch
5295
5246
5296 # XXX path: we are losing the `path` object here. Keeping it
5247 # XXX path: we are losing the `path` object here. Keeping it
5297 # would be valuable. For example as a "variant" as we do
5248 # would be valuable. For example as a "variant" as we do
5298 # for pushes.
5249 # for pushes.
5299 repo._subtoppath = path.loc
5250 repo._subtoppath = path.loc
5300 try:
5251 try:
5301 update_conflict = cmdutil.postincoming(
5252 update_conflict = cmdutil.postincoming(
5302 ui, repo, modheads, opts.get('update'), checkout, brev
5253 ui, repo, modheads, opts.get('update'), checkout, brev
5303 )
5254 )
5304 except error.FilteredRepoLookupError as exc:
5255 except error.FilteredRepoLookupError as exc:
5305 msg = _(b'cannot update to target: %s') % exc.args[0]
5256 msg = _(b'cannot update to target: %s') % exc.args[0]
5306 exc.args = (msg,) + exc.args[1:]
5257 exc.args = (msg,) + exc.args[1:]
5307 raise
5258 raise
5308 finally:
5259 finally:
5309 del repo._subtoppath
5260 del repo._subtoppath
5310
5261
5311 finally:
5262 finally:
5312 other.close()
5263 other.close()
5313 # skip the remaining pull source if they are some conflict.
5264 # skip the remaining pull source if they are some conflict.
5314 if update_conflict:
5265 if update_conflict:
5315 break
5266 break
5316 if update_conflict:
5267 if update_conflict:
5317 return 1
5268 return 1
5318 else:
5269 else:
5319 return 0
5270 return 0
5320
5271
5321
5272
5322 @command(
5273 @command(
5323 b'purge|clean',
5274 b'purge|clean',
5324 [
5275 [
5325 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5276 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5326 (b'', b'all', None, _(b'purge ignored files too')),
5277 (b'', b'all', None, _(b'purge ignored files too')),
5327 (b'i', b'ignored', None, _(b'purge only ignored files')),
5278 (b'i', b'ignored', None, _(b'purge only ignored files')),
5328 (b'', b'dirs', None, _(b'purge empty directories')),
5279 (b'', b'dirs', None, _(b'purge empty directories')),
5329 (b'', b'files', None, _(b'purge files')),
5280 (b'', b'files', None, _(b'purge files')),
5330 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5281 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5331 (
5282 (
5332 b'0',
5283 b'0',
5333 b'print0',
5284 b'print0',
5334 None,
5285 None,
5335 _(
5286 _(
5336 b'end filenames with NUL, for use with xargs'
5287 b'end filenames with NUL, for use with xargs'
5337 b' (implies -p/--print)'
5288 b' (implies -p/--print)'
5338 ),
5289 ),
5339 ),
5290 ),
5340 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5291 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5341 ]
5292 ]
5342 + cmdutil.walkopts,
5293 + cmdutil.walkopts,
5343 _(b'hg purge [OPTION]... [DIR]...'),
5294 _(b'hg purge [OPTION]... [DIR]...'),
5344 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5295 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5345 )
5296 )
5346 def purge(ui, repo, *dirs, **opts):
5297 def purge(ui, repo, *dirs, **opts):
5347 """removes files not tracked by Mercurial
5298 """removes files not tracked by Mercurial
5348
5299
5349 Delete files not known to Mercurial. This is useful to test local
5300 Delete files not known to Mercurial. This is useful to test local
5350 and uncommitted changes in an otherwise-clean source tree.
5301 and uncommitted changes in an otherwise-clean source tree.
5351
5302
5352 This means that purge will delete the following by default:
5303 This means that purge will delete the following by default:
5353
5304
5354 - Unknown files: files marked with "?" by :hg:`status`
5305 - Unknown files: files marked with "?" by :hg:`status`
5355 - Empty directories: in fact Mercurial ignores directories unless
5306 - Empty directories: in fact Mercurial ignores directories unless
5356 they contain files under source control management
5307 they contain files under source control management
5357
5308
5358 But it will leave untouched:
5309 But it will leave untouched:
5359
5310
5360 - Modified and unmodified tracked files
5311 - Modified and unmodified tracked files
5361 - Ignored files (unless -i or --all is specified)
5312 - Ignored files (unless -i or --all is specified)
5362 - New files added to the repository (with :hg:`add`)
5313 - New files added to the repository (with :hg:`add`)
5363
5314
5364 The --files and --dirs options can be used to direct purge to delete
5315 The --files and --dirs options can be used to direct purge to delete
5365 only files, only directories, or both. If neither option is given,
5316 only files, only directories, or both. If neither option is given,
5366 both will be deleted.
5317 both will be deleted.
5367
5318
5368 If directories are given on the command line, only files in these
5319 If directories are given on the command line, only files in these
5369 directories are considered.
5320 directories are considered.
5370
5321
5371 Be careful with purge, as you could irreversibly delete some files
5322 Be careful with purge, as you could irreversibly delete some files
5372 you forgot to add to the repository. If you only want to print the
5323 you forgot to add to the repository. If you only want to print the
5373 list of files that this program would delete, use the --print
5324 list of files that this program would delete, use the --print
5374 option.
5325 option.
5375 """
5326 """
5376 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5327 cmdutil.check_at_most_one_arg(opts, 'all', 'ignored')
5377
5328
5378 act = not opts.get('print')
5329 act = not opts.get('print')
5379 eol = b'\n'
5330 eol = b'\n'
5380 if opts.get('print0'):
5331 if opts.get('print0'):
5381 eol = b'\0'
5332 eol = b'\0'
5382 act = False # --print0 implies --print
5333 act = False # --print0 implies --print
5383 if opts.get('all', False):
5334 if opts.get('all', False):
5384 ignored = True
5335 ignored = True
5385 unknown = True
5336 unknown = True
5386 else:
5337 else:
5387 ignored = opts.get('ignored', False)
5338 ignored = opts.get('ignored', False)
5388 unknown = not ignored
5339 unknown = not ignored
5389
5340
5390 removefiles = opts.get('files')
5341 removefiles = opts.get('files')
5391 removedirs = opts.get('dirs')
5342 removedirs = opts.get('dirs')
5392 confirm = opts.get('confirm')
5343 confirm = opts.get('confirm')
5393 if confirm is None:
5344 if confirm is None:
5394 try:
5345 try:
5395 extensions.find(b'purge')
5346 extensions.find(b'purge')
5396 confirm = False
5347 confirm = False
5397 except KeyError:
5348 except KeyError:
5398 confirm = True
5349 confirm = True
5399
5350
5400 if not removefiles and not removedirs:
5351 if not removefiles and not removedirs:
5401 removefiles = True
5352 removefiles = True
5402 removedirs = True
5353 removedirs = True
5403
5354
5404 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5355 match = scmutil.match(repo[None], dirs, pycompat.byteskwargs(opts))
5405
5356
5406 paths = mergemod.purge(
5357 paths = mergemod.purge(
5407 repo,
5358 repo,
5408 match,
5359 match,
5409 unknown=unknown,
5360 unknown=unknown,
5410 ignored=ignored,
5361 ignored=ignored,
5411 removeemptydirs=removedirs,
5362 removeemptydirs=removedirs,
5412 removefiles=removefiles,
5363 removefiles=removefiles,
5413 abortonerror=opts.get('abort_on_err'),
5364 abortonerror=opts.get('abort_on_err'),
5414 noop=not act,
5365 noop=not act,
5415 confirm=confirm,
5366 confirm=confirm,
5416 )
5367 )
5417
5368
5418 for path in paths:
5369 for path in paths:
5419 if not act:
5370 if not act:
5420 ui.write(b'%s%s' % (path, eol))
5371 ui.write(b'%s%s' % (path, eol))
5421
5372
5422
5373
5423 @command(
5374 @command(
5424 b'push',
5375 b'push',
5425 [
5376 [
5426 (b'f', b'force', None, _(b'force push')),
5377 (b'f', b'force', None, _(b'force push')),
5427 (
5378 (
5428 b'r',
5379 b'r',
5429 b'rev',
5380 b'rev',
5430 [],
5381 [],
5431 _(b'a changeset intended to be included in the destination'),
5382 _(b'a changeset intended to be included in the destination'),
5432 _(b'REV'),
5383 _(b'REV'),
5433 ),
5384 ),
5434 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5385 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5435 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5386 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5436 (
5387 (
5437 b'b',
5388 b'b',
5438 b'branch',
5389 b'branch',
5439 [],
5390 [],
5440 _(b'a specific branch you would like to push'),
5391 _(b'a specific branch you would like to push'),
5441 _(b'BRANCH'),
5392 _(b'BRANCH'),
5442 ),
5393 ),
5443 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5394 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5444 (
5395 (
5445 b'',
5396 b'',
5446 b'pushvars',
5397 b'pushvars',
5447 [],
5398 [],
5448 _(b'variables that can be sent to server (ADVANCED)'),
5399 _(b'variables that can be sent to server (ADVANCED)'),
5449 ),
5400 ),
5450 (
5401 (
5451 b'',
5402 b'',
5452 b'publish',
5403 b'publish',
5453 False,
5404 False,
5454 _(b'push the changeset as public (EXPERIMENTAL)'),
5405 _(b'push the changeset as public (EXPERIMENTAL)'),
5455 ),
5406 ),
5456 ]
5407 ]
5457 + remoteopts,
5408 + remoteopts,
5458 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5409 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5459 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5410 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5460 helpbasic=True,
5411 helpbasic=True,
5461 )
5412 )
5462 def push(ui, repo, *dests, **opts):
5413 def push(ui, repo, *dests, **opts):
5463 """push changes to the specified destination
5414 """push changes to the specified destination
5464
5415
5465 Push changesets from the local repository to the specified
5416 Push changesets from the local repository to the specified
5466 destination.
5417 destination.
5467
5418
5468 This operation is symmetrical to pull: it is identical to a pull
5419 This operation is symmetrical to pull: it is identical to a pull
5469 in the destination repository from the current one.
5420 in the destination repository from the current one.
5470
5421
5471 By default, push will not allow creation of new heads at the
5422 By default, push will not allow creation of new heads at the
5472 destination, since multiple heads would make it unclear which head
5423 destination, since multiple heads would make it unclear which head
5473 to use. In this situation, it is recommended to pull and merge
5424 to use. In this situation, it is recommended to pull and merge
5474 before pushing.
5425 before pushing.
5475
5426
5476 Use --new-branch if you want to allow push to create a new named
5427 Use --new-branch if you want to allow push to create a new named
5477 branch that is not present at the destination. This allows you to
5428 branch that is not present at the destination. This allows you to
5478 only create a new branch without forcing other changes.
5429 only create a new branch without forcing other changes.
5479
5430
5480 .. note::
5431 .. note::
5481
5432
5482 Extra care should be taken with the -f/--force option,
5433 Extra care should be taken with the -f/--force option,
5483 which will push all new heads on all branches, an action which will
5434 which will push all new heads on all branches, an action which will
5484 almost always cause confusion for collaborators.
5435 almost always cause confusion for collaborators.
5485
5436
5486 If -r/--rev is used, the specified revision and all its ancestors
5437 If -r/--rev is used, the specified revision and all its ancestors
5487 will be pushed to the remote repository.
5438 will be pushed to the remote repository.
5488
5439
5489 If -B/--bookmark is used, the specified bookmarked revision, its
5440 If -B/--bookmark is used, the specified bookmarked revision, its
5490 ancestors, and the bookmark will be pushed to the remote
5441 ancestors, and the bookmark will be pushed to the remote
5491 repository. Specifying ``.`` is equivalent to specifying the active
5442 repository. Specifying ``.`` is equivalent to specifying the active
5492 bookmark's name. Use the --all-bookmarks option for pushing all
5443 bookmark's name. Use the --all-bookmarks option for pushing all
5493 current bookmarks.
5444 current bookmarks.
5494
5445
5495 Please see :hg:`help urls` for important details about ``ssh://``
5446 Please see :hg:`help urls` for important details about ``ssh://``
5496 URLs. If DESTINATION is omitted, a default path will be used.
5447 URLs. If DESTINATION is omitted, a default path will be used.
5497
5448
5498 When passed multiple destinations, push will process them one after the
5449 When passed multiple destinations, push will process them one after the
5499 other, but stop should an error occur.
5450 other, but stop should an error occur.
5500
5451
5501 .. container:: verbose
5452 .. container:: verbose
5502
5453
5503 The --pushvars option sends strings to the server that become
5454 The --pushvars option sends strings to the server that become
5504 environment variables prepended with ``HG_USERVAR_``. For example,
5455 environment variables prepended with ``HG_USERVAR_``. For example,
5505 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5456 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5506 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5457 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5507
5458
5508 pushvars can provide for user-overridable hooks as well as set debug
5459 pushvars can provide for user-overridable hooks as well as set debug
5509 levels. One example is having a hook that blocks commits containing
5460 levels. One example is having a hook that blocks commits containing
5510 conflict markers, but enables the user to override the hook if the file
5461 conflict markers, but enables the user to override the hook if the file
5511 is using conflict markers for testing purposes or the file format has
5462 is using conflict markers for testing purposes or the file format has
5512 strings that look like conflict markers.
5463 strings that look like conflict markers.
5513
5464
5514 By default, servers will ignore `--pushvars`. To enable it add the
5465 By default, servers will ignore `--pushvars`. To enable it add the
5515 following to your configuration file::
5466 following to your configuration file::
5516
5467
5517 [push]
5468 [push]
5518 pushvars.server = true
5469 pushvars.server = true
5519
5470
5520 Returns 0 if push was successful, 1 if nothing to push.
5471 Returns 0 if push was successful, 1 if nothing to push.
5521 """
5472 """
5522
5473
5523 opts = pycompat.byteskwargs(opts)
5474 opts = pycompat.byteskwargs(opts)
5524
5475
5525 if opts.get(b'all_bookmarks'):
5476 if opts.get(b'all_bookmarks'):
5526 cmdutil.check_incompatible_arguments(
5477 cmdutil.check_incompatible_arguments(
5527 opts,
5478 opts,
5528 b'all_bookmarks',
5479 b'all_bookmarks',
5529 [b'bookmark', b'rev'],
5480 [b'bookmark', b'rev'],
5530 )
5481 )
5531 opts[b'bookmark'] = list(repo._bookmarks)
5482 opts[b'bookmark'] = list(repo._bookmarks)
5532
5483
5533 if opts.get(b'bookmark'):
5484 if opts.get(b'bookmark'):
5534 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5485 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5535 for b in opts[b'bookmark']:
5486 for b in opts[b'bookmark']:
5536 # translate -B options to -r so changesets get pushed
5487 # translate -B options to -r so changesets get pushed
5537 b = repo._bookmarks.expandname(b)
5488 b = repo._bookmarks.expandname(b)
5538 if b in repo._bookmarks:
5489 if b in repo._bookmarks:
5539 opts.setdefault(b'rev', []).append(b)
5490 opts.setdefault(b'rev', []).append(b)
5540 else:
5491 else:
5541 # if we try to push a deleted bookmark, translate it to null
5492 # if we try to push a deleted bookmark, translate it to null
5542 # this lets simultaneous -r, -b options continue working
5493 # this lets simultaneous -r, -b options continue working
5543 opts.setdefault(b'rev', []).append(b"null")
5494 opts.setdefault(b'rev', []).append(b"null")
5544
5495
5545 some_pushed = False
5496 some_pushed = False
5546 result = 0
5497 result = 0
5547 for path in urlutil.get_push_paths(repo, ui, dests):
5498 for path in urlutil.get_push_paths(repo, ui, dests):
5548 dest = path.loc
5499 dest = path.loc
5549 branches = (path.branch, opts.get(b'branch') or [])
5500 branches = (path.branch, opts.get(b'branch') or [])
5550 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5501 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5551 revs, checkout = hg.addbranchrevs(
5502 revs, checkout = hg.addbranchrevs(
5552 repo, repo, branches, opts.get(b'rev')
5503 repo, repo, branches, opts.get(b'rev')
5553 )
5504 )
5554 other = hg.peer(repo, opts, dest)
5505 other = hg.peer(repo, opts, dest)
5555
5506
5556 try:
5507 try:
5557 if revs:
5508 if revs:
5558 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5509 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5559 if not revs:
5510 if not revs:
5560 raise error.InputError(
5511 raise error.InputError(
5561 _(b"specified revisions evaluate to an empty set"),
5512 _(b"specified revisions evaluate to an empty set"),
5562 hint=_(b"use different revision arguments"),
5513 hint=_(b"use different revision arguments"),
5563 )
5514 )
5564 elif path.pushrev:
5515 elif path.pushrev:
5565 # It doesn't make any sense to specify ancestor revisions. So limit
5516 # It doesn't make any sense to specify ancestor revisions. So limit
5566 # to DAG heads to make discovery simpler.
5517 # to DAG heads to make discovery simpler.
5567 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5518 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5568 revs = scmutil.revrange(repo, [expr])
5519 revs = scmutil.revrange(repo, [expr])
5569 revs = [repo[rev].node() for rev in revs]
5520 revs = [repo[rev].node() for rev in revs]
5570 if not revs:
5521 if not revs:
5571 raise error.InputError(
5522 raise error.InputError(
5572 _(
5523 _(
5573 b'default push revset for path evaluates to an empty set'
5524 b'default push revset for path evaluates to an empty set'
5574 )
5525 )
5575 )
5526 )
5576 elif ui.configbool(b'commands', b'push.require-revs'):
5527 elif ui.configbool(b'commands', b'push.require-revs'):
5577 raise error.InputError(
5528 raise error.InputError(
5578 _(b'no revisions specified to push'),
5529 _(b'no revisions specified to push'),
5579 hint=_(b'did you mean "hg push -r ."?'),
5530 hint=_(b'did you mean "hg push -r ."?'),
5580 )
5531 )
5581
5532
5582 repo._subtoppath = dest
5533 repo._subtoppath = dest
5583 try:
5534 try:
5584 # push subrepos depth-first for coherent ordering
5535 # push subrepos depth-first for coherent ordering
5585 c = repo[b'.']
5536 c = repo[b'.']
5586 subs = c.substate # only repos that are committed
5537 subs = c.substate # only repos that are committed
5587 for s in sorted(subs):
5538 for s in sorted(subs):
5588 sub_result = c.sub(s).push(opts)
5539 sub_result = c.sub(s).push(opts)
5589 if sub_result == 0:
5540 if sub_result == 0:
5590 return 1
5541 return 1
5591 finally:
5542 finally:
5592 del repo._subtoppath
5543 del repo._subtoppath
5593
5544
5594 opargs = dict(
5545 opargs = dict(
5595 opts.get(b'opargs', {})
5546 opts.get(b'opargs', {})
5596 ) # copy opargs since we may mutate it
5547 ) # copy opargs since we may mutate it
5597 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5548 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5598
5549
5599 pushop = exchange.push(
5550 pushop = exchange.push(
5600 repo,
5551 repo,
5601 other,
5552 other,
5602 opts.get(b'force'),
5553 opts.get(b'force'),
5603 revs=revs,
5554 revs=revs,
5604 newbranch=opts.get(b'new_branch'),
5555 newbranch=opts.get(b'new_branch'),
5605 bookmarks=opts.get(b'bookmark', ()),
5556 bookmarks=opts.get(b'bookmark', ()),
5606 publish=opts.get(b'publish'),
5557 publish=opts.get(b'publish'),
5607 opargs=opargs,
5558 opargs=opargs,
5608 )
5559 )
5609
5560
5610 if pushop.cgresult == 0:
5561 if pushop.cgresult == 0:
5611 result = 1
5562 result = 1
5612 elif pushop.cgresult is not None:
5563 elif pushop.cgresult is not None:
5613 some_pushed = True
5564 some_pushed = True
5614
5565
5615 if pushop.bkresult is not None:
5566 if pushop.bkresult is not None:
5616 if pushop.bkresult == 2:
5567 if pushop.bkresult == 2:
5617 result = 2
5568 result = 2
5618 elif not result and pushop.bkresult:
5569 elif not result and pushop.bkresult:
5619 result = 2
5570 result = 2
5620
5571
5621 if result:
5572 if result:
5622 break
5573 break
5623
5574
5624 finally:
5575 finally:
5625 other.close()
5576 other.close()
5626 if result == 0 and not some_pushed:
5577 if result == 0 and not some_pushed:
5627 result = 1
5578 result = 1
5628 return result
5579 return result
5629
5580
5630
5581
5631 @command(
5582 @command(
5632 b'recover',
5583 b'recover',
5633 [
5584 [
5634 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5585 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5635 ],
5586 ],
5636 helpcategory=command.CATEGORY_MAINTENANCE,
5587 helpcategory=command.CATEGORY_MAINTENANCE,
5637 )
5588 )
5638 def recover(ui, repo, **opts):
5589 def recover(ui, repo, **opts):
5639 """roll back an interrupted transaction
5590 """roll back an interrupted transaction
5640
5591
5641 Recover from an interrupted commit or pull.
5592 Recover from an interrupted commit or pull.
5642
5593
5643 This command tries to fix the repository status after an
5594 This command tries to fix the repository status after an
5644 interrupted operation. It should only be necessary when Mercurial
5595 interrupted operation. It should only be necessary when Mercurial
5645 suggests it.
5596 suggests it.
5646
5597
5647 Returns 0 if successful, 1 if nothing to recover or verify fails.
5598 Returns 0 if successful, 1 if nothing to recover or verify fails.
5648 """
5599 """
5649 ret = repo.recover()
5600 ret = repo.recover()
5650 if ret:
5601 if ret:
5651 if opts['verify']:
5602 if opts['verify']:
5652 return hg.verify(repo)
5603 return hg.verify(repo)
5653 else:
5604 else:
5654 msg = _(
5605 msg = _(
5655 b"(verify step skipped, run `hg verify` to check your "
5606 b"(verify step skipped, run `hg verify` to check your "
5656 b"repository content)\n"
5607 b"repository content)\n"
5657 )
5608 )
5658 ui.warn(msg)
5609 ui.warn(msg)
5659 return 0
5610 return 0
5660 return 1
5611 return 1
5661
5612
5662
5613
5663 @command(
5614 @command(
5664 b'remove|rm',
5615 b'remove|rm',
5665 [
5616 [
5666 (b'A', b'after', None, _(b'record delete for missing files')),
5617 (b'A', b'after', None, _(b'record delete for missing files')),
5667 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5618 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5668 ]
5619 ]
5669 + subrepoopts
5620 + subrepoopts
5670 + walkopts
5621 + walkopts
5671 + dryrunopts,
5622 + dryrunopts,
5672 _(b'[OPTION]... FILE...'),
5623 _(b'[OPTION]... FILE...'),
5673 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5624 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5674 helpbasic=True,
5625 helpbasic=True,
5675 inferrepo=True,
5626 inferrepo=True,
5676 )
5627 )
5677 def remove(ui, repo, *pats, **opts):
5628 def remove(ui, repo, *pats, **opts):
5678 """remove the specified files on the next commit
5629 """remove the specified files on the next commit
5679
5630
5680 Schedule the indicated files for removal from the current branch.
5631 Schedule the indicated files for removal from the current branch.
5681
5632
5682 This command schedules the files to be removed at the next commit.
5633 This command schedules the files to be removed at the next commit.
5683 To undo a remove before that, see :hg:`revert`. To undo added
5634 To undo a remove before that, see :hg:`revert`. To undo added
5684 files, see :hg:`forget`.
5635 files, see :hg:`forget`.
5685
5636
5686 .. container:: verbose
5637 .. container:: verbose
5687
5638
5688 -A/--after can be used to remove only files that have already
5639 -A/--after can be used to remove only files that have already
5689 been deleted, -f/--force can be used to force deletion, and -Af
5640 been deleted, -f/--force can be used to force deletion, and -Af
5690 can be used to remove files from the next revision without
5641 can be used to remove files from the next revision without
5691 deleting them from the working directory.
5642 deleting them from the working directory.
5692
5643
5693 The following table details the behavior of remove for different
5644 The following table details the behavior of remove for different
5694 file states (columns) and option combinations (rows). The file
5645 file states (columns) and option combinations (rows). The file
5695 states are Added [A], Clean [C], Modified [M] and Missing [!]
5646 states are Added [A], Clean [C], Modified [M] and Missing [!]
5696 (as reported by :hg:`status`). The actions are Warn, Remove
5647 (as reported by :hg:`status`). The actions are Warn, Remove
5697 (from branch) and Delete (from disk):
5648 (from branch) and Delete (from disk):
5698
5649
5699 ========= == == == ==
5650 ========= == == == ==
5700 opt/state A C M !
5651 opt/state A C M !
5701 ========= == == == ==
5652 ========= == == == ==
5702 none W RD W R
5653 none W RD W R
5703 -f R RD RD R
5654 -f R RD RD R
5704 -A W W W R
5655 -A W W W R
5705 -Af R R R R
5656 -Af R R R R
5706 ========= == == == ==
5657 ========= == == == ==
5707
5658
5708 .. note::
5659 .. note::
5709
5660
5710 :hg:`remove` never deletes files in Added [A] state from the
5661 :hg:`remove` never deletes files in Added [A] state from the
5711 working directory, not even if ``--force`` is specified.
5662 working directory, not even if ``--force`` is specified.
5712
5663
5713 Returns 0 on success, 1 if any warnings encountered.
5664 Returns 0 on success, 1 if any warnings encountered.
5714 """
5665 """
5715
5666
5716 after, force = opts.get('after'), opts.get('force')
5667 after, force = opts.get('after'), opts.get('force')
5717 dryrun = opts.get('dry_run')
5668 dryrun = opts.get('dry_run')
5718 if not pats and not after:
5669 if not pats and not after:
5719 raise error.InputError(_(b'no files specified'))
5670 raise error.InputError(_(b'no files specified'))
5720
5671
5721 with repo.wlock(), repo.dirstate.changing_files(repo):
5672 with repo.wlock(), repo.dirstate.changing_files(repo):
5722 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5673 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
5723 subrepos = opts.get('subrepos')
5674 subrepos = opts.get('subrepos')
5724 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5675 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5725 return cmdutil.remove(
5676 return cmdutil.remove(
5726 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5677 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5727 )
5678 )
5728
5679
5729
5680
5730 @command(
5681 @command(
5731 b'rename|move|mv',
5682 b'rename|move|mv',
5732 [
5683 [
5733 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5684 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5734 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5685 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5735 (
5686 (
5736 b'',
5687 b'',
5737 b'at-rev',
5688 b'at-rev',
5738 b'',
5689 b'',
5739 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5690 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5740 _(b'REV'),
5691 _(b'REV'),
5741 ),
5692 ),
5742 (
5693 (
5743 b'f',
5694 b'f',
5744 b'force',
5695 b'force',
5745 None,
5696 None,
5746 _(b'forcibly move over an existing managed file'),
5697 _(b'forcibly move over an existing managed file'),
5747 ),
5698 ),
5748 ]
5699 ]
5749 + walkopts
5700 + walkopts
5750 + dryrunopts,
5701 + dryrunopts,
5751 _(b'[OPTION]... SOURCE... DEST'),
5702 _(b'[OPTION]... SOURCE... DEST'),
5752 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5753 )
5704 )
5754 def rename(ui, repo, *pats, **opts):
5705 def rename(ui, repo, *pats, **opts):
5755 """rename files; equivalent of copy + remove
5706 """rename files; equivalent of copy + remove
5756
5707
5757 Mark dest as copies of sources; mark sources for deletion. If dest
5708 Mark dest as copies of sources; mark sources for deletion. If dest
5758 is a directory, copies are put in that directory. If dest is a
5709 is a directory, copies are put in that directory. If dest is a
5759 file, there can only be one source.
5710 file, there can only be one source.
5760
5711
5761 By default, this command copies the contents of files as they
5712 By default, this command copies the contents of files as they
5762 exist in the working directory. If invoked with -A/--after, the
5713 exist in the working directory. If invoked with -A/--after, the
5763 operation is recorded, but no copying is performed.
5714 operation is recorded, but no copying is performed.
5764
5715
5765 To undo marking a destination file as renamed, use --forget. With that
5716 To undo marking a destination file as renamed, use --forget. With that
5766 option, all given (positional) arguments are unmarked as renames. The
5717 option, all given (positional) arguments are unmarked as renames. The
5767 destination file(s) will be left in place (still tracked). The source
5718 destination file(s) will be left in place (still tracked). The source
5768 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5719 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5769 the same way as :hg:`copy --forget`.
5720 the same way as :hg:`copy --forget`.
5770
5721
5771 This command takes effect with the next commit by default.
5722 This command takes effect with the next commit by default.
5772
5723
5773 Returns 0 on success, 1 if errors are encountered.
5724 Returns 0 on success, 1 if errors are encountered.
5774 """
5725 """
5775 context = lambda repo: repo.dirstate.changing_files(repo)
5726 context = lambda repo: repo.dirstate.changing_files(repo)
5776 rev = opts.get('at_rev')
5727 rev = opts.get('at_rev')
5777
5728
5778 if rev:
5729 if rev:
5779 ctx = logcmdutil.revsingle(repo, rev)
5730 ctx = logcmdutil.revsingle(repo, rev)
5780 if ctx.rev() is not None:
5731 if ctx.rev() is not None:
5781
5732
5782 def context(repo):
5733 def context(repo):
5783 return util.nullcontextmanager()
5734 return util.nullcontextmanager()
5784
5735
5785 opts['at_rev'] = ctx.rev()
5736 opts['at_rev'] = ctx.rev()
5786 with repo.wlock(), context(repo):
5737 with repo.wlock(), context(repo):
5787 return cmdutil.copy(
5738 return cmdutil.copy(
5788 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5739 ui, repo, pats, pycompat.byteskwargs(opts), rename=True
5789 )
5740 )
5790
5741
5791
5742
5792 @command(
5743 @command(
5793 b'resolve',
5744 b'resolve',
5794 [
5745 [
5795 (b'a', b'all', None, _(b'select all unresolved files')),
5746 (b'a', b'all', None, _(b'select all unresolved files')),
5796 (b'l', b'list', None, _(b'list state of files needing merge')),
5747 (b'l', b'list', None, _(b'list state of files needing merge')),
5797 (b'm', b'mark', None, _(b'mark files as resolved')),
5748 (b'm', b'mark', None, _(b'mark files as resolved')),
5798 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5749 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5799 (b'n', b'no-status', None, _(b'hide status prefix')),
5750 (b'n', b'no-status', None, _(b'hide status prefix')),
5800 (b'', b're-merge', None, _(b're-merge files')),
5751 (b'', b're-merge', None, _(b're-merge files')),
5801 ]
5752 ]
5802 + mergetoolopts
5753 + mergetoolopts
5803 + walkopts
5754 + walkopts
5804 + formatteropts,
5755 + formatteropts,
5805 _(b'[OPTION]... [FILE]...'),
5756 _(b'[OPTION]... [FILE]...'),
5806 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5757 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5807 inferrepo=True,
5758 inferrepo=True,
5808 )
5759 )
5809 def resolve(ui, repo, *pats, **opts):
5760 def resolve(ui, repo, *pats, **opts):
5810 """redo merges or set/view the merge status of files
5761 """redo merges or set/view the merge status of files
5811
5762
5812 Merges with unresolved conflicts are often the result of
5763 Merges with unresolved conflicts are often the result of
5813 non-interactive merging using the ``internal:merge`` configuration
5764 non-interactive merging using the ``internal:merge`` configuration
5814 setting, or a command-line merge tool like ``diff3``. The resolve
5765 setting, or a command-line merge tool like ``diff3``. The resolve
5815 command is used to manage the files involved in a merge, after
5766 command is used to manage the files involved in a merge, after
5816 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5767 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5817 working directory must have two parents). See :hg:`help
5768 working directory must have two parents). See :hg:`help
5818 merge-tools` for information on configuring merge tools.
5769 merge-tools` for information on configuring merge tools.
5819
5770
5820 The resolve command can be used in the following ways:
5771 The resolve command can be used in the following ways:
5821
5772
5822 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5773 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5823 the specified files, discarding any previous merge attempts. Re-merging
5774 the specified files, discarding any previous merge attempts. Re-merging
5824 is not performed for files already marked as resolved. Use ``--all/-a``
5775 is not performed for files already marked as resolved. Use ``--all/-a``
5825 to select all unresolved files. ``--tool`` can be used to specify
5776 to select all unresolved files. ``--tool`` can be used to specify
5826 the merge tool used for the given files. It overrides the HGMERGE
5777 the merge tool used for the given files. It overrides the HGMERGE
5827 environment variable and your configuration files. Previous file
5778 environment variable and your configuration files. Previous file
5828 contents are saved with a ``.orig`` suffix.
5779 contents are saved with a ``.orig`` suffix.
5829
5780
5830 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5781 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5831 (e.g. after having manually fixed-up the files). The default is
5782 (e.g. after having manually fixed-up the files). The default is
5832 to mark all unresolved files.
5783 to mark all unresolved files.
5833
5784
5834 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5785 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5835 default is to mark all resolved files.
5786 default is to mark all resolved files.
5836
5787
5837 - :hg:`resolve -l`: list files which had or still have conflicts.
5788 - :hg:`resolve -l`: list files which had or still have conflicts.
5838 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5789 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5839 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5790 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5840 the list. See :hg:`help filesets` for details.
5791 the list. See :hg:`help filesets` for details.
5841
5792
5842 .. note::
5793 .. note::
5843
5794
5844 Mercurial will not let you commit files with unresolved merge
5795 Mercurial will not let you commit files with unresolved merge
5845 conflicts. You must use :hg:`resolve -m ...` before you can
5796 conflicts. You must use :hg:`resolve -m ...` before you can
5846 commit after a conflicting merge.
5797 commit after a conflicting merge.
5847
5798
5848 .. container:: verbose
5799 .. container:: verbose
5849
5800
5850 Template:
5801 Template:
5851
5802
5852 The following keywords are supported in addition to the common template
5803 The following keywords are supported in addition to the common template
5853 keywords and functions. See also :hg:`help templates`.
5804 keywords and functions. See also :hg:`help templates`.
5854
5805
5855 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5806 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5856 :path: String. Repository-absolute path of the file.
5807 :path: String. Repository-absolute path of the file.
5857
5808
5858 Returns 0 on success, 1 if any files fail a resolve attempt.
5809 Returns 0 on success, 1 if any files fail a resolve attempt.
5859 """
5810 """
5860
5811
5861 opts = pycompat.byteskwargs(opts)
5812 opts = pycompat.byteskwargs(opts)
5862 confirm = ui.configbool(b'commands', b'resolve.confirm')
5813 confirm = ui.configbool(b'commands', b'resolve.confirm')
5863 flaglist = b'all mark unmark list no_status re_merge'.split()
5814 flaglist = b'all mark unmark list no_status re_merge'.split()
5864 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5815 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5865
5816
5866 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5817 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5867 if actioncount > 1:
5818 if actioncount > 1:
5868 raise error.InputError(_(b"too many actions specified"))
5819 raise error.InputError(_(b"too many actions specified"))
5869 elif actioncount == 0 and ui.configbool(
5820 elif actioncount == 0 and ui.configbool(
5870 b'commands', b'resolve.explicit-re-merge'
5821 b'commands', b'resolve.explicit-re-merge'
5871 ):
5822 ):
5872 hint = _(b'use --mark, --unmark, --list or --re-merge')
5823 hint = _(b'use --mark, --unmark, --list or --re-merge')
5873 raise error.InputError(_(b'no action specified'), hint=hint)
5824 raise error.InputError(_(b'no action specified'), hint=hint)
5874 if pats and all:
5825 if pats and all:
5875 raise error.InputError(_(b"can't specify --all and patterns"))
5826 raise error.InputError(_(b"can't specify --all and patterns"))
5876 if not (all or pats or show or mark or unmark):
5827 if not (all or pats or show or mark or unmark):
5877 raise error.InputError(
5828 raise error.InputError(
5878 _(b'no files or directories specified'),
5829 _(b'no files or directories specified'),
5879 hint=b'use --all to re-merge all unresolved files',
5830 hint=b'use --all to re-merge all unresolved files',
5880 )
5831 )
5881
5832
5882 if confirm:
5833 if confirm:
5883 if all:
5834 if all:
5884 if ui.promptchoice(
5835 if ui.promptchoice(
5885 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5836 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5886 ):
5837 ):
5887 raise error.CanceledError(_(b'user quit'))
5838 raise error.CanceledError(_(b'user quit'))
5888 if mark and not pats:
5839 if mark and not pats:
5889 if ui.promptchoice(
5840 if ui.promptchoice(
5890 _(
5841 _(
5891 b'mark all unresolved files as resolved (yn)?'
5842 b'mark all unresolved files as resolved (yn)?'
5892 b'$$ &Yes $$ &No'
5843 b'$$ &Yes $$ &No'
5893 )
5844 )
5894 ):
5845 ):
5895 raise error.CanceledError(_(b'user quit'))
5846 raise error.CanceledError(_(b'user quit'))
5896 if unmark and not pats:
5847 if unmark and not pats:
5897 if ui.promptchoice(
5848 if ui.promptchoice(
5898 _(
5849 _(
5899 b'mark all resolved files as unresolved (yn)?'
5850 b'mark all resolved files as unresolved (yn)?'
5900 b'$$ &Yes $$ &No'
5851 b'$$ &Yes $$ &No'
5901 )
5852 )
5902 ):
5853 ):
5903 raise error.CanceledError(_(b'user quit'))
5854 raise error.CanceledError(_(b'user quit'))
5904
5855
5905 uipathfn = scmutil.getuipathfn(repo)
5856 uipathfn = scmutil.getuipathfn(repo)
5906
5857
5907 if show:
5858 if show:
5908 ui.pager(b'resolve')
5859 ui.pager(b'resolve')
5909 fm = ui.formatter(b'resolve', opts)
5860 fm = ui.formatter(b'resolve', opts)
5910 ms = mergestatemod.mergestate.read(repo)
5861 ms = mergestatemod.mergestate.read(repo)
5911 wctx = repo[None]
5862 wctx = repo[None]
5912 m = scmutil.match(wctx, pats, opts)
5863 m = scmutil.match(wctx, pats, opts)
5913
5864
5914 # Labels and keys based on merge state. Unresolved path conflicts show
5865 # Labels and keys based on merge state. Unresolved path conflicts show
5915 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5866 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5916 # resolved conflicts.
5867 # resolved conflicts.
5917 mergestateinfo = {
5868 mergestateinfo = {
5918 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5869 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5919 b'resolve.unresolved',
5870 b'resolve.unresolved',
5920 b'U',
5871 b'U',
5921 ),
5872 ),
5922 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5873 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5923 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5874 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5924 b'resolve.unresolved',
5875 b'resolve.unresolved',
5925 b'P',
5876 b'P',
5926 ),
5877 ),
5927 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5878 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5928 b'resolve.resolved',
5879 b'resolve.resolved',
5929 b'R',
5880 b'R',
5930 ),
5881 ),
5931 }
5882 }
5932
5883
5933 for f in ms:
5884 for f in ms:
5934 if not m(f):
5885 if not m(f):
5935 continue
5886 continue
5936
5887
5937 label, key = mergestateinfo[ms[f]]
5888 label, key = mergestateinfo[ms[f]]
5938 fm.startitem()
5889 fm.startitem()
5939 fm.context(ctx=wctx)
5890 fm.context(ctx=wctx)
5940 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5891 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5941 fm.data(path=f)
5892 fm.data(path=f)
5942 fm.plain(b'%s\n' % uipathfn(f), label=label)
5893 fm.plain(b'%s\n' % uipathfn(f), label=label)
5943 fm.end()
5894 fm.end()
5944 return 0
5895 return 0
5945
5896
5946 with repo.wlock():
5897 with repo.wlock():
5947 ms = mergestatemod.mergestate.read(repo)
5898 ms = mergestatemod.mergestate.read(repo)
5948
5899
5949 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5900 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
5950 raise error.StateError(
5901 raise error.StateError(
5951 _(b'resolve command not applicable when not merging')
5902 _(b'resolve command not applicable when not merging')
5952 )
5903 )
5953
5904
5954 wctx = repo[None]
5905 wctx = repo[None]
5955 m = scmutil.match(wctx, pats, opts)
5906 m = scmutil.match(wctx, pats, opts)
5956 ret = 0
5907 ret = 0
5957 didwork = False
5908 didwork = False
5958
5909
5959 hasconflictmarkers = []
5910 hasconflictmarkers = []
5960 if mark:
5911 if mark:
5961 markcheck = ui.config(b'commands', b'resolve.mark-check')
5912 markcheck = ui.config(b'commands', b'resolve.mark-check')
5962 if markcheck not in [b'warn', b'abort']:
5913 if markcheck not in [b'warn', b'abort']:
5963 # Treat all invalid / unrecognized values as 'none'.
5914 # Treat all invalid / unrecognized values as 'none'.
5964 markcheck = False
5915 markcheck = False
5965 for f in ms:
5916 for f in ms:
5966 if not m(f):
5917 if not m(f):
5967 continue
5918 continue
5968
5919
5969 didwork = True
5920 didwork = True
5970
5921
5971 # path conflicts must be resolved manually
5922 # path conflicts must be resolved manually
5972 if ms[f] in (
5923 if ms[f] in (
5973 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5924 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5974 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5925 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5975 ):
5926 ):
5976 if mark:
5927 if mark:
5977 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5928 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5978 elif unmark:
5929 elif unmark:
5979 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5930 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5980 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5931 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5981 ui.warn(
5932 ui.warn(
5982 _(b'%s: path conflict must be resolved manually\n')
5933 _(b'%s: path conflict must be resolved manually\n')
5983 % uipathfn(f)
5934 % uipathfn(f)
5984 )
5935 )
5985 continue
5936 continue
5986
5937
5987 if mark:
5938 if mark:
5988 if markcheck:
5939 if markcheck:
5989 fdata = repo.wvfs.tryread(f)
5940 fdata = repo.wvfs.tryread(f)
5990 if (
5941 if (
5991 filemerge.hasconflictmarkers(fdata)
5942 filemerge.hasconflictmarkers(fdata)
5992 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5943 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5993 ):
5944 ):
5994 hasconflictmarkers.append(f)
5945 hasconflictmarkers.append(f)
5995 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5946 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5996 elif unmark:
5947 elif unmark:
5997 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5948 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5998 else:
5949 else:
5999 # backup pre-resolve (merge uses .orig for its own purposes)
5950 # backup pre-resolve (merge uses .orig for its own purposes)
6000 a = repo.wjoin(f)
5951 a = repo.wjoin(f)
6001 try:
5952 try:
6002 util.copyfile(a, a + b".resolve")
5953 util.copyfile(a, a + b".resolve")
6003 except FileNotFoundError:
5954 except FileNotFoundError:
6004 pass
5955 pass
6005
5956
6006 try:
5957 try:
6007 # preresolve file
5958 # preresolve file
6008 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5959 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6009 with ui.configoverride(overrides, b'resolve'):
5960 with ui.configoverride(overrides, b'resolve'):
6010 r = ms.resolve(f, wctx)
5961 r = ms.resolve(f, wctx)
6011 if r:
5962 if r:
6012 ret = 1
5963 ret = 1
6013 finally:
5964 finally:
6014 ms.commit()
5965 ms.commit()
6015
5966
6016 # replace filemerge's .orig file with our resolve file
5967 # replace filemerge's .orig file with our resolve file
6017 try:
5968 try:
6018 util.rename(
5969 util.rename(
6019 a + b".resolve", scmutil.backuppath(ui, repo, f)
5970 a + b".resolve", scmutil.backuppath(ui, repo, f)
6020 )
5971 )
6021 except FileNotFoundError:
5972 except FileNotFoundError:
6022 pass
5973 pass
6023
5974
6024 if hasconflictmarkers:
5975 if hasconflictmarkers:
6025 ui.warn(
5976 ui.warn(
6026 _(
5977 _(
6027 b'warning: the following files still have conflict '
5978 b'warning: the following files still have conflict '
6028 b'markers:\n'
5979 b'markers:\n'
6029 )
5980 )
6030 + b''.join(
5981 + b''.join(
6031 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5982 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6032 )
5983 )
6033 )
5984 )
6034 if markcheck == b'abort' and not all and not pats:
5985 if markcheck == b'abort' and not all and not pats:
6035 raise error.StateError(
5986 raise error.StateError(
6036 _(b'conflict markers detected'),
5987 _(b'conflict markers detected'),
6037 hint=_(b'use --all to mark anyway'),
5988 hint=_(b'use --all to mark anyway'),
6038 )
5989 )
6039
5990
6040 ms.commit()
5991 ms.commit()
6041 branchmerge = repo.dirstate.p2() != repo.nullid
5992 branchmerge = repo.dirstate.p2() != repo.nullid
6042 # resolve is not doing a parent change here, however, `record updates`
5993 # resolve is not doing a parent change here, however, `record updates`
6043 # will call some dirstate API that at intended for parent changes call.
5994 # will call some dirstate API that at intended for parent changes call.
6044 # Ideally we would not need this and could implement a lighter version
5995 # Ideally we would not need this and could implement a lighter version
6045 # of the recordupdateslogic that will not have to deal with the part
5996 # of the recordupdateslogic that will not have to deal with the part
6046 # related to parent changes. However this would requires that:
5997 # related to parent changes. However this would requires that:
6047 # - we are sure we passed around enough information at update/merge
5998 # - we are sure we passed around enough information at update/merge
6048 # time to no longer needs it at `hg resolve time`
5999 # time to no longer needs it at `hg resolve time`
6049 # - we are sure we store that information well enough to be able to reuse it
6000 # - we are sure we store that information well enough to be able to reuse it
6050 # - we are the necessary logic to reuse it right.
6001 # - we are the necessary logic to reuse it right.
6051 #
6002 #
6052 # All this should eventually happens, but in the mean time, we use this
6003 # All this should eventually happens, but in the mean time, we use this
6053 # context manager slightly out of the context it should be.
6004 # context manager slightly out of the context it should be.
6054 with repo.dirstate.changing_parents(repo):
6005 with repo.dirstate.changing_parents(repo):
6055 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6006 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6056
6007
6057 if not didwork and pats:
6008 if not didwork and pats:
6058 hint = None
6009 hint = None
6059 if not any([p for p in pats if p.find(b':') >= 0]):
6010 if not any([p for p in pats if p.find(b':') >= 0]):
6060 pats = [b'path:%s' % p for p in pats]
6011 pats = [b'path:%s' % p for p in pats]
6061 m = scmutil.match(wctx, pats, opts)
6012 m = scmutil.match(wctx, pats, opts)
6062 for f in ms:
6013 for f in ms:
6063 if not m(f):
6014 if not m(f):
6064 continue
6015 continue
6065
6016
6066 def flag(o):
6017 def flag(o):
6067 if o == b're_merge':
6018 if o == b're_merge':
6068 return b'--re-merge '
6019 return b'--re-merge '
6069 return b'-%s ' % o[0:1]
6020 return b'-%s ' % o[0:1]
6070
6021
6071 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6022 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6072 hint = _(b"(try: hg resolve %s%s)\n") % (
6023 hint = _(b"(try: hg resolve %s%s)\n") % (
6073 flags,
6024 flags,
6074 b' '.join(pats),
6025 b' '.join(pats),
6075 )
6026 )
6076 break
6027 break
6077 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6028 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6078 if hint:
6029 if hint:
6079 ui.warn(hint)
6030 ui.warn(hint)
6080
6031
6081 unresolvedf = ms.unresolvedcount()
6032 unresolvedf = ms.unresolvedcount()
6082 if not unresolvedf:
6033 if not unresolvedf:
6083 ui.status(_(b'(no more unresolved files)\n'))
6034 ui.status(_(b'(no more unresolved files)\n'))
6084 cmdutil.checkafterresolved(repo)
6035 cmdutil.checkafterresolved(repo)
6085
6036
6086 return ret
6037 return ret
6087
6038
6088
6039
6089 @command(
6040 @command(
6090 b'revert',
6041 b'revert',
6091 [
6042 [
6092 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6043 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6093 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6044 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6094 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6045 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6095 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6046 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6096 (b'i', b'interactive', None, _(b'interactively select the changes')),
6047 (b'i', b'interactive', None, _(b'interactively select the changes')),
6097 ]
6048 ]
6098 + walkopts
6049 + walkopts
6099 + dryrunopts,
6050 + dryrunopts,
6100 _(b'[OPTION]... [-r REV] [NAME]...'),
6051 _(b'[OPTION]... [-r REV] [NAME]...'),
6101 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6052 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6102 )
6053 )
6103 def revert(ui, repo, *pats, **opts):
6054 def revert(ui, repo, *pats, **opts):
6104 """restore files to their checkout state
6055 """restore files to their checkout state
6105
6056
6106 .. note::
6057 .. note::
6107
6058
6108 To check out earlier revisions, you should use :hg:`update REV`.
6059 To check out earlier revisions, you should use :hg:`update REV`.
6109 To cancel an uncommitted merge (and lose your changes),
6060 To cancel an uncommitted merge (and lose your changes),
6110 use :hg:`merge --abort`.
6061 use :hg:`merge --abort`.
6111
6062
6112 With no revision specified, revert the specified files or directories
6063 With no revision specified, revert the specified files or directories
6113 to the contents they had in the parent of the working directory.
6064 to the contents they had in the parent of the working directory.
6114 This restores the contents of files to an unmodified
6065 This restores the contents of files to an unmodified
6115 state and unschedules adds, removes, copies, and renames. If the
6066 state and unschedules adds, removes, copies, and renames. If the
6116 working directory has two parents, you must explicitly specify a
6067 working directory has two parents, you must explicitly specify a
6117 revision.
6068 revision.
6118
6069
6119 Using the -r/--rev or -d/--date options, revert the given files or
6070 Using the -r/--rev or -d/--date options, revert the given files or
6120 directories to their states as of a specific revision. Because
6071 directories to their states as of a specific revision. Because
6121 revert does not change the working directory parents, this will
6072 revert does not change the working directory parents, this will
6122 cause these files to appear modified. This can be helpful to "back
6073 cause these files to appear modified. This can be helpful to "back
6123 out" some or all of an earlier change. See :hg:`backout` for a
6074 out" some or all of an earlier change. See :hg:`backout` for a
6124 related method.
6075 related method.
6125
6076
6126 Modified files are saved with a .orig suffix before reverting.
6077 Modified files are saved with a .orig suffix before reverting.
6127 To disable these backups, use --no-backup. It is possible to store
6078 To disable these backups, use --no-backup. It is possible to store
6128 the backup files in a custom directory relative to the root of the
6079 the backup files in a custom directory relative to the root of the
6129 repository by setting the ``ui.origbackuppath`` configuration
6080 repository by setting the ``ui.origbackuppath`` configuration
6130 option.
6081 option.
6131
6082
6132 See :hg:`help dates` for a list of formats valid for -d/--date.
6083 See :hg:`help dates` for a list of formats valid for -d/--date.
6133
6084
6134 See :hg:`help backout` for a way to reverse the effect of an
6085 See :hg:`help backout` for a way to reverse the effect of an
6135 earlier changeset.
6086 earlier changeset.
6136
6087
6137 Returns 0 on success.
6088 Returns 0 on success.
6138 """
6089 """
6139
6090
6140 if opts.get("date"):
6091 if opts.get("date"):
6141 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6092 cmdutil.check_incompatible_arguments(opts, 'date', ['rev'])
6142 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6093 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6143
6094
6144 parent, p2 = repo.dirstate.parents()
6095 parent, p2 = repo.dirstate.parents()
6145 if not opts.get('rev') and p2 != repo.nullid:
6096 if not opts.get('rev') and p2 != repo.nullid:
6146 # revert after merge is a trap for new users (issue2915)
6097 # revert after merge is a trap for new users (issue2915)
6147 raise error.InputError(
6098 raise error.InputError(
6148 _(b'uncommitted merge with no revision specified'),
6099 _(b'uncommitted merge with no revision specified'),
6149 hint=_(b"use 'hg update' or see 'hg help revert'"),
6100 hint=_(b"use 'hg update' or see 'hg help revert'"),
6150 )
6101 )
6151
6102
6152 rev = opts.get('rev')
6103 rev = opts.get('rev')
6153 if rev:
6104 if rev:
6154 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6105 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6155 ctx = logcmdutil.revsingle(repo, rev)
6106 ctx = logcmdutil.revsingle(repo, rev)
6156
6107
6157 if not (
6108 if not (
6158 pats
6109 pats
6159 or opts.get('include')
6110 or opts.get('include')
6160 or opts.get('exclude')
6111 or opts.get('exclude')
6161 or opts.get('all')
6112 or opts.get('all')
6162 or opts.get('interactive')
6113 or opts.get('interactive')
6163 ):
6114 ):
6164 msg = _(b"no files or directories specified")
6115 msg = _(b"no files or directories specified")
6165 if p2 != repo.nullid:
6116 if p2 != repo.nullid:
6166 hint = _(
6117 hint = _(
6167 b"uncommitted merge, use --all to discard all changes,"
6118 b"uncommitted merge, use --all to discard all changes,"
6168 b" or 'hg update -C .' to abort the merge"
6119 b" or 'hg update -C .' to abort the merge"
6169 )
6120 )
6170 raise error.InputError(msg, hint=hint)
6121 raise error.InputError(msg, hint=hint)
6171 dirty = any(repo.status())
6122 dirty = any(repo.status())
6172 node = ctx.node()
6123 node = ctx.node()
6173 if node != parent:
6124 if node != parent:
6174 if dirty:
6125 if dirty:
6175 hint = (
6126 hint = (
6176 _(
6127 _(
6177 b"uncommitted changes, use --all to discard all"
6128 b"uncommitted changes, use --all to discard all"
6178 b" changes, or 'hg update %d' to update"
6129 b" changes, or 'hg update %d' to update"
6179 )
6130 )
6180 % ctx.rev()
6131 % ctx.rev()
6181 )
6132 )
6182 else:
6133 else:
6183 hint = (
6134 hint = (
6184 _(
6135 _(
6185 b"use --all to revert all files,"
6136 b"use --all to revert all files,"
6186 b" or 'hg update %d' to update"
6137 b" or 'hg update %d' to update"
6187 )
6138 )
6188 % ctx.rev()
6139 % ctx.rev()
6189 )
6140 )
6190 elif dirty:
6141 elif dirty:
6191 hint = _(b"uncommitted changes, use --all to discard all changes")
6142 hint = _(b"uncommitted changes, use --all to discard all changes")
6192 else:
6143 else:
6193 hint = _(b"use --all to revert all files")
6144 hint = _(b"use --all to revert all files")
6194 raise error.InputError(msg, hint=hint)
6145 raise error.InputError(msg, hint=hint)
6195
6146
6196 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6147 return cmdutil.revert(ui, repo, ctx, *pats, **opts)
6197
6148
6198
6149
6199 @command(
6150 @command(
6200 b'rollback',
6151 b'rollback',
6201 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6152 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6202 helpcategory=command.CATEGORY_MAINTENANCE,
6153 helpcategory=command.CATEGORY_MAINTENANCE,
6203 )
6154 )
6204 def rollback(ui, repo, **opts):
6155 def rollback(ui, repo, **opts):
6205 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6156 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6206
6157
6207 Please use :hg:`commit --amend` instead of rollback to correct
6158 Please use :hg:`commit --amend` instead of rollback to correct
6208 mistakes in the last commit.
6159 mistakes in the last commit.
6209
6160
6210 This command should be used with care. There is only one level of
6161 This command should be used with care. There is only one level of
6211 rollback, and there is no way to undo a rollback. It will also
6162 rollback, and there is no way to undo a rollback. It will also
6212 restore the dirstate at the time of the last transaction, losing
6163 restore the dirstate at the time of the last transaction, losing
6213 any dirstate changes since that time. This command does not alter
6164 any dirstate changes since that time. This command does not alter
6214 the working directory.
6165 the working directory.
6215
6166
6216 Transactions are used to encapsulate the effects of all commands
6167 Transactions are used to encapsulate the effects of all commands
6217 that create new changesets or propagate existing changesets into a
6168 that create new changesets or propagate existing changesets into a
6218 repository.
6169 repository.
6219
6170
6220 .. container:: verbose
6171 .. container:: verbose
6221
6172
6222 For example, the following commands are transactional, and their
6173 For example, the following commands are transactional, and their
6223 effects can be rolled back:
6174 effects can be rolled back:
6224
6175
6225 - commit
6176 - commit
6226 - import
6177 - import
6227 - pull
6178 - pull
6228 - push (with this repository as the destination)
6179 - push (with this repository as the destination)
6229 - unbundle
6180 - unbundle
6230
6181
6231 To avoid permanent data loss, rollback will refuse to rollback a
6182 To avoid permanent data loss, rollback will refuse to rollback a
6232 commit transaction if it isn't checked out. Use --force to
6183 commit transaction if it isn't checked out. Use --force to
6233 override this protection.
6184 override this protection.
6234
6185
6235 The rollback command can be entirely disabled by setting the
6186 The rollback command can be entirely disabled by setting the
6236 ``ui.rollback`` configuration setting to false. If you're here
6187 ``ui.rollback`` configuration setting to false. If you're here
6237 because you want to use rollback and it's disabled, you can
6188 because you want to use rollback and it's disabled, you can
6238 re-enable the command by setting ``ui.rollback`` to true.
6189 re-enable the command by setting ``ui.rollback`` to true.
6239
6190
6240 This command is not intended for use on public repositories. Once
6191 This command is not intended for use on public repositories. Once
6241 changes are visible for pull by other users, rolling a transaction
6192 changes are visible for pull by other users, rolling a transaction
6242 back locally is ineffective (someone else may already have pulled
6193 back locally is ineffective (someone else may already have pulled
6243 the changes). Furthermore, a race is possible with readers of the
6194 the changes). Furthermore, a race is possible with readers of the
6244 repository; for example an in-progress pull from the repository
6195 repository; for example an in-progress pull from the repository
6245 may fail if a rollback is performed.
6196 may fail if a rollback is performed.
6246
6197
6247 Returns 0 on success, 1 if no rollback data is available.
6198 Returns 0 on success, 1 if no rollback data is available.
6248 """
6199 """
6249 if not ui.configbool(b'ui', b'rollback'):
6200 if not ui.configbool(b'ui', b'rollback'):
6250 raise error.Abort(
6201 raise error.Abort(
6251 _(b'rollback is disabled because it is unsafe'),
6202 _(b'rollback is disabled because it is unsafe'),
6252 hint=b'see `hg help -v rollback` for information',
6203 hint=b'see `hg help -v rollback` for information',
6253 )
6204 )
6254 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6205 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6255
6206
6256
6207
6257 @command(
6208 @command(
6258 b'root',
6209 b'root',
6259 [] + formatteropts,
6210 [] + formatteropts,
6260 intents={INTENT_READONLY},
6211 intents={INTENT_READONLY},
6261 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6212 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6262 )
6213 )
6263 def root(ui, repo, **opts):
6214 def root(ui, repo, **opts):
6264 """print the root (top) of the current working directory
6215 """print the root (top) of the current working directory
6265
6216
6266 Print the root directory of the current repository.
6217 Print the root directory of the current repository.
6267
6218
6268 .. container:: verbose
6219 .. container:: verbose
6269
6220
6270 Template:
6221 Template:
6271
6222
6272 The following keywords are supported in addition to the common template
6223 The following keywords are supported in addition to the common template
6273 keywords and functions. See also :hg:`help templates`.
6224 keywords and functions. See also :hg:`help templates`.
6274
6225
6275 :hgpath: String. Path to the .hg directory.
6226 :hgpath: String. Path to the .hg directory.
6276 :storepath: String. Path to the directory holding versioned data.
6227 :storepath: String. Path to the directory holding versioned data.
6277
6228
6278 Returns 0 on success.
6229 Returns 0 on success.
6279 """
6230 """
6280 opts = pycompat.byteskwargs(opts)
6231 opts = pycompat.byteskwargs(opts)
6281 with ui.formatter(b'root', opts) as fm:
6232 with ui.formatter(b'root', opts) as fm:
6282 fm.startitem()
6233 fm.startitem()
6283 fm.write(b'reporoot', b'%s\n', repo.root)
6234 fm.write(b'reporoot', b'%s\n', repo.root)
6284 fm.data(hgpath=repo.path, storepath=repo.spath)
6235 fm.data(hgpath=repo.path, storepath=repo.spath)
6285
6236
6286
6237
6287 @command(
6238 @command(
6288 b'serve',
6239 b'serve',
6289 [
6240 [
6290 (
6241 (
6291 b'A',
6242 b'A',
6292 b'accesslog',
6243 b'accesslog',
6293 b'',
6244 b'',
6294 _(b'name of access log file to write to'),
6245 _(b'name of access log file to write to'),
6295 _(b'FILE'),
6246 _(b'FILE'),
6296 ),
6247 ),
6297 (b'd', b'daemon', None, _(b'run server in background')),
6248 (b'd', b'daemon', None, _(b'run server in background')),
6298 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6249 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6299 (
6250 (
6300 b'E',
6251 b'E',
6301 b'errorlog',
6252 b'errorlog',
6302 b'',
6253 b'',
6303 _(b'name of error log file to write to'),
6254 _(b'name of error log file to write to'),
6304 _(b'FILE'),
6255 _(b'FILE'),
6305 ),
6256 ),
6306 # use string type, then we can check if something was passed
6257 # use string type, then we can check if something was passed
6307 (
6258 (
6308 b'p',
6259 b'p',
6309 b'port',
6260 b'port',
6310 b'',
6261 b'',
6311 _(b'port to listen on (default: 8000)'),
6262 _(b'port to listen on (default: 8000)'),
6312 _(b'PORT'),
6263 _(b'PORT'),
6313 ),
6264 ),
6314 (
6265 (
6315 b'a',
6266 b'a',
6316 b'address',
6267 b'address',
6317 b'',
6268 b'',
6318 _(b'address to listen on (default: all interfaces)'),
6269 _(b'address to listen on (default: all interfaces)'),
6319 _(b'ADDR'),
6270 _(b'ADDR'),
6320 ),
6271 ),
6321 (
6272 (
6322 b'',
6273 b'',
6323 b'prefix',
6274 b'prefix',
6324 b'',
6275 b'',
6325 _(b'prefix path to serve from (default: server root)'),
6276 _(b'prefix path to serve from (default: server root)'),
6326 _(b'PREFIX'),
6277 _(b'PREFIX'),
6327 ),
6278 ),
6328 (
6279 (
6329 b'n',
6280 b'n',
6330 b'name',
6281 b'name',
6331 b'',
6282 b'',
6332 _(b'name to show in web pages (default: working directory)'),
6283 _(b'name to show in web pages (default: working directory)'),
6333 _(b'NAME'),
6284 _(b'NAME'),
6334 ),
6285 ),
6335 (
6286 (
6336 b'',
6287 b'',
6337 b'web-conf',
6288 b'web-conf',
6338 b'',
6289 b'',
6339 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6290 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6340 _(b'FILE'),
6291 _(b'FILE'),
6341 ),
6292 ),
6342 (
6293 (
6343 b'',
6294 b'',
6344 b'webdir-conf',
6295 b'webdir-conf',
6345 b'',
6296 b'',
6346 _(b'name of the hgweb config file (DEPRECATED)'),
6297 _(b'name of the hgweb config file (DEPRECATED)'),
6347 _(b'FILE'),
6298 _(b'FILE'),
6348 ),
6299 ),
6349 (
6300 (
6350 b'',
6301 b'',
6351 b'pid-file',
6302 b'pid-file',
6352 b'',
6303 b'',
6353 _(b'name of file to write process ID to'),
6304 _(b'name of file to write process ID to'),
6354 _(b'FILE'),
6305 _(b'FILE'),
6355 ),
6306 ),
6356 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6307 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6357 (
6308 (
6358 b'',
6309 b'',
6359 b'cmdserver',
6310 b'cmdserver',
6360 b'',
6311 b'',
6361 _(b'for remote clients (ADVANCED)'),
6312 _(b'for remote clients (ADVANCED)'),
6362 _(b'MODE'),
6313 _(b'MODE'),
6363 ),
6314 ),
6364 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6315 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6365 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6316 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6366 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6317 (b'6', b'ipv6', None, _(b'use IPv6 instead of IPv4')),
6367 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6318 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6368 (b'', b'print-url', None, _(b'start and print only the URL')),
6319 (b'', b'print-url', None, _(b'start and print only the URL')),
6369 ]
6320 ]
6370 + subrepoopts,
6321 + subrepoopts,
6371 _(b'[OPTION]...'),
6322 _(b'[OPTION]...'),
6372 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6323 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6373 helpbasic=True,
6324 helpbasic=True,
6374 optionalrepo=True,
6325 optionalrepo=True,
6375 )
6326 )
6376 def serve(ui, repo, **opts):
6327 def serve(ui, repo, **opts):
6377 """start stand-alone webserver
6328 """start stand-alone webserver
6378
6329
6379 Start a local HTTP repository browser and pull server. You can use
6330 Start a local HTTP repository browser and pull server. You can use
6380 this for ad-hoc sharing and browsing of repositories. It is
6331 this for ad-hoc sharing and browsing of repositories. It is
6381 recommended to use a real web server to serve a repository for
6332 recommended to use a real web server to serve a repository for
6382 longer periods of time.
6333 longer periods of time.
6383
6334
6384 Please note that the server does not implement access control.
6335 Please note that the server does not implement access control.
6385 This means that, by default, anybody can read from the server and
6336 This means that, by default, anybody can read from the server and
6386 nobody can write to it by default. Set the ``web.allow-push``
6337 nobody can write to it by default. Set the ``web.allow-push``
6387 option to ``*`` to allow everybody to push to the server. You
6338 option to ``*`` to allow everybody to push to the server. You
6388 should use a real web server if you need to authenticate users.
6339 should use a real web server if you need to authenticate users.
6389
6340
6390 By default, the server logs accesses to stdout and errors to
6341 By default, the server logs accesses to stdout and errors to
6391 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6342 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6392 files.
6343 files.
6393
6344
6394 To have the server choose a free port number to listen on, specify
6345 To have the server choose a free port number to listen on, specify
6395 a port number of 0; in this case, the server will print the port
6346 a port number of 0; in this case, the server will print the port
6396 number it uses.
6347 number it uses.
6397
6348
6398 Returns 0 on success.
6349 Returns 0 on success.
6399 """
6350 """
6400
6351
6401 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6352 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6402 opts = pycompat.byteskwargs(opts)
6353 opts = pycompat.byteskwargs(opts)
6403 if opts[b"print_url"] and ui.verbose:
6354 if opts[b"print_url"] and ui.verbose:
6404 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6355 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6405
6356
6406 if opts[b"stdio"]:
6357 if opts[b"stdio"]:
6407 if repo is None:
6358 if repo is None:
6408 raise error.RepoError(
6359 raise error.RepoError(
6409 _(b"there is no Mercurial repository here (.hg not found)")
6360 _(b"there is no Mercurial repository here (.hg not found)")
6410 )
6361 )
6411 accesshidden = False
6362 accesshidden = False
6412 if repo.filtername is None:
6363 if repo.filtername is None:
6413 allow = ui.configlist(
6364 allow = ui.configlist(
6414 b'experimental', b'server.allow-hidden-access'
6365 b'experimental', b'server.allow-hidden-access'
6415 )
6366 )
6416 user = procutil.getuser()
6367 user = procutil.getuser()
6417 if allow and scmutil.ismember(ui, user, allow):
6368 if allow and scmutil.ismember(ui, user, allow):
6418 accesshidden = True
6369 accesshidden = True
6419 else:
6370 else:
6420 msg = (
6371 msg = (
6421 _(
6372 _(
6422 b'ignoring request to access hidden changeset by '
6373 b'ignoring request to access hidden changeset by '
6423 b'unauthorized user: %s\n'
6374 b'unauthorized user: %s\n'
6424 )
6375 )
6425 % user
6376 % user
6426 )
6377 )
6427 ui.warn(msg)
6378 ui.warn(msg)
6428
6379
6429 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6380 s = wireprotoserver.sshserver(ui, repo, accesshidden=accesshidden)
6430 s.serve_forever()
6381 s.serve_forever()
6431 return
6382 return
6432
6383
6433 service = server.createservice(ui, repo, opts)
6384 service = server.createservice(ui, repo, opts)
6434 return server.runservice(opts, initfn=service.init, runfn=service.run)
6385 return server.runservice(opts, initfn=service.init, runfn=service.run)
6435
6386
6436
6387
6437 @command(
6388 @command(
6438 b'shelve',
6389 b'shelve',
6439 [
6390 [
6440 (
6391 (
6441 b'A',
6392 b'A',
6442 b'addremove',
6393 b'addremove',
6443 None,
6394 None,
6444 _(b'mark new/missing files as added/removed before shelving'),
6395 _(b'mark new/missing files as added/removed before shelving'),
6445 ),
6396 ),
6446 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6397 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6447 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6398 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6448 (
6399 (
6449 b'',
6400 b'',
6450 b'date',
6401 b'date',
6451 b'',
6402 b'',
6452 _(b'shelve with the specified commit date'),
6403 _(b'shelve with the specified commit date'),
6453 _(b'DATE'),
6404 _(b'DATE'),
6454 ),
6405 ),
6455 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6406 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6456 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6407 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6457 (
6408 (
6458 b'k',
6409 b'k',
6459 b'keep',
6410 b'keep',
6460 False,
6411 False,
6461 _(b'shelve, but keep changes in the working directory'),
6412 _(b'shelve, but keep changes in the working directory'),
6462 ),
6413 ),
6463 (b'l', b'list', None, _(b'list current shelves')),
6414 (b'l', b'list', None, _(b'list current shelves')),
6464 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6415 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6465 (
6416 (
6466 b'n',
6417 b'n',
6467 b'name',
6418 b'name',
6468 b'',
6419 b'',
6469 _(b'use the given name for the shelved commit'),
6420 _(b'use the given name for the shelved commit'),
6470 _(b'NAME'),
6421 _(b'NAME'),
6471 ),
6422 ),
6472 (
6423 (
6473 b'p',
6424 b'p',
6474 b'patch',
6425 b'patch',
6475 None,
6426 None,
6476 _(
6427 _(
6477 b'output patches for changes (provide the names of the shelved '
6428 b'output patches for changes (provide the names of the shelved '
6478 b'changes as positional arguments)'
6429 b'changes as positional arguments)'
6479 ),
6430 ),
6480 ),
6431 ),
6481 (b'i', b'interactive', None, _(b'interactive mode')),
6432 (b'i', b'interactive', None, _(b'interactive mode')),
6482 (
6433 (
6483 b'',
6434 b'',
6484 b'stat',
6435 b'stat',
6485 None,
6436 None,
6486 _(
6437 _(
6487 b'output diffstat-style summary of changes (provide the names of '
6438 b'output diffstat-style summary of changes (provide the names of '
6488 b'the shelved changes as positional arguments)'
6439 b'the shelved changes as positional arguments)'
6489 ),
6440 ),
6490 ),
6441 ),
6491 ]
6442 ]
6492 + cmdutil.walkopts,
6443 + cmdutil.walkopts,
6493 _(b'hg shelve [OPTION]... [FILE]...'),
6444 _(b'hg shelve [OPTION]... [FILE]...'),
6494 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6445 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6495 )
6446 )
6496 def shelve(ui, repo, *pats, **opts):
6447 def shelve(ui, repo, *pats, **opts):
6497 """save and set aside changes from the working directory
6448 """save and set aside changes from the working directory
6498
6449
6499 Shelving takes files that "hg status" reports as not clean, saves
6450 Shelving takes files that "hg status" reports as not clean, saves
6500 the modifications to a bundle (a shelved change), and reverts the
6451 the modifications to a bundle (a shelved change), and reverts the
6501 files so that their state in the working directory becomes clean.
6452 files so that their state in the working directory becomes clean.
6502
6453
6503 To restore these changes to the working directory, using "hg
6454 To restore these changes to the working directory, using "hg
6504 unshelve"; this will work even if you switch to a different
6455 unshelve"; this will work even if you switch to a different
6505 commit.
6456 commit.
6506
6457
6507 When no files are specified, "hg shelve" saves all not-clean
6458 When no files are specified, "hg shelve" saves all not-clean
6508 files. If specific files or directories are named, only changes to
6459 files. If specific files or directories are named, only changes to
6509 those files are shelved.
6460 those files are shelved.
6510
6461
6511 In bare shelve (when no files are specified, without interactive,
6462 In bare shelve (when no files are specified, without interactive,
6512 include and exclude option), shelving remembers information if the
6463 include and exclude option), shelving remembers information if the
6513 working directory was on newly created branch, in other words working
6464 working directory was on newly created branch, in other words working
6514 directory was on different branch than its first parent. In this
6465 directory was on different branch than its first parent. In this
6515 situation unshelving restores branch information to the working directory.
6466 situation unshelving restores branch information to the working directory.
6516
6467
6517 Each shelved change has a name that makes it easier to find later.
6468 Each shelved change has a name that makes it easier to find later.
6518 The name of a shelved change defaults to being based on the active
6469 The name of a shelved change defaults to being based on the active
6519 bookmark, or if there is no active bookmark, the current named
6470 bookmark, or if there is no active bookmark, the current named
6520 branch. To specify a different name, use ``--name``.
6471 branch. To specify a different name, use ``--name``.
6521
6472
6522 To see a list of existing shelved changes, use the ``--list``
6473 To see a list of existing shelved changes, use the ``--list``
6523 option. For each shelved change, this will print its name, age,
6474 option. For each shelved change, this will print its name, age,
6524 and description; use ``--patch`` or ``--stat`` for more details.
6475 and description; use ``--patch`` or ``--stat`` for more details.
6525
6476
6526 To delete specific shelved changes, use ``--delete``. To delete
6477 To delete specific shelved changes, use ``--delete``. To delete
6527 all shelved changes, use ``--cleanup``.
6478 all shelved changes, use ``--cleanup``.
6528 """
6479 """
6529 opts = pycompat.byteskwargs(opts)
6480 opts = pycompat.byteskwargs(opts)
6530 allowables = [
6481 allowables = [
6531 (b'addremove', {b'create'}), # 'create' is pseudo action
6482 (b'addremove', {b'create'}), # 'create' is pseudo action
6532 (b'unknown', {b'create'}),
6483 (b'unknown', {b'create'}),
6533 (b'cleanup', {b'cleanup'}),
6484 (b'cleanup', {b'cleanup'}),
6534 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6485 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6535 (b'delete', {b'delete'}),
6486 (b'delete', {b'delete'}),
6536 (b'edit', {b'create'}),
6487 (b'edit', {b'create'}),
6537 (b'keep', {b'create'}),
6488 (b'keep', {b'create'}),
6538 (b'list', {b'list'}),
6489 (b'list', {b'list'}),
6539 (b'message', {b'create'}),
6490 (b'message', {b'create'}),
6540 (b'name', {b'create'}),
6491 (b'name', {b'create'}),
6541 (b'patch', {b'patch', b'list'}),
6492 (b'patch', {b'patch', b'list'}),
6542 (b'stat', {b'stat', b'list'}),
6493 (b'stat', {b'stat', b'list'}),
6543 ]
6494 ]
6544
6495
6545 def checkopt(opt):
6496 def checkopt(opt):
6546 if opts.get(opt):
6497 if opts.get(opt):
6547 for i, allowable in allowables:
6498 for i, allowable in allowables:
6548 if opts[i] and opt not in allowable:
6499 if opts[i] and opt not in allowable:
6549 raise error.InputError(
6500 raise error.InputError(
6550 _(
6501 _(
6551 b"options '--%s' and '--%s' may not be "
6502 b"options '--%s' and '--%s' may not be "
6552 b"used together"
6503 b"used together"
6553 )
6504 )
6554 % (opt, i)
6505 % (opt, i)
6555 )
6506 )
6556 return True
6507 return True
6557
6508
6558 if checkopt(b'cleanup'):
6509 if checkopt(b'cleanup'):
6559 if pats:
6510 if pats:
6560 raise error.InputError(
6511 raise error.InputError(
6561 _(b"cannot specify names when using '--cleanup'")
6512 _(b"cannot specify names when using '--cleanup'")
6562 )
6513 )
6563 return shelvemod.cleanupcmd(ui, repo)
6514 return shelvemod.cleanupcmd(ui, repo)
6564 elif checkopt(b'delete'):
6515 elif checkopt(b'delete'):
6565 return shelvemod.deletecmd(ui, repo, pats)
6516 return shelvemod.deletecmd(ui, repo, pats)
6566 elif checkopt(b'list'):
6517 elif checkopt(b'list'):
6567 return shelvemod.listcmd(ui, repo, pats, opts)
6518 return shelvemod.listcmd(ui, repo, pats, opts)
6568 elif checkopt(b'patch') or checkopt(b'stat'):
6519 elif checkopt(b'patch') or checkopt(b'stat'):
6569 return shelvemod.patchcmds(ui, repo, pats, opts)
6520 return shelvemod.patchcmds(ui, repo, pats, opts)
6570 else:
6521 else:
6571 return shelvemod.createcmd(ui, repo, pats, opts)
6522 return shelvemod.createcmd(ui, repo, pats, opts)
6572
6523
6573
6524
6574 _NOTTERSE = b'nothing'
6525 _NOTTERSE = b'nothing'
6575
6526
6576
6527
6577 @command(
6528 @command(
6578 b'status|st',
6529 b'status|st',
6579 [
6530 [
6580 (b'A', b'all', None, _(b'show status of all files')),
6531 (b'A', b'all', None, _(b'show status of all files')),
6581 (b'm', b'modified', None, _(b'show only modified files')),
6532 (b'm', b'modified', None, _(b'show only modified files')),
6582 (b'a', b'added', None, _(b'show only added files')),
6533 (b'a', b'added', None, _(b'show only added files')),
6583 (b'r', b'removed', None, _(b'show only removed files')),
6534 (b'r', b'removed', None, _(b'show only removed files')),
6584 (b'd', b'deleted', None, _(b'show only missing files')),
6535 (b'd', b'deleted', None, _(b'show only missing files')),
6585 (b'c', b'clean', None, _(b'show only files without changes')),
6536 (b'c', b'clean', None, _(b'show only files without changes')),
6586 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6537 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6587 (b'i', b'ignored', None, _(b'show only ignored files')),
6538 (b'i', b'ignored', None, _(b'show only ignored files')),
6588 (b'n', b'no-status', None, _(b'hide status prefix')),
6539 (b'n', b'no-status', None, _(b'hide status prefix')),
6589 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6540 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6590 (
6541 (
6591 b'C',
6542 b'C',
6592 b'copies',
6543 b'copies',
6593 None,
6544 None,
6594 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6545 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6595 ),
6546 ),
6596 (
6547 (
6597 b'0',
6548 b'0',
6598 b'print0',
6549 b'print0',
6599 None,
6550 None,
6600 _(b'end filenames with NUL, for use with xargs'),
6551 _(b'end filenames with NUL, for use with xargs'),
6601 ),
6552 ),
6602 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6553 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6603 (
6554 (
6604 b'',
6555 b'',
6605 b'change',
6556 b'change',
6606 b'',
6557 b'',
6607 _(b'list the changed files of a revision'),
6558 _(b'list the changed files of a revision'),
6608 _(b'REV'),
6559 _(b'REV'),
6609 ),
6560 ),
6610 ]
6561 ]
6611 + walkopts
6562 + walkopts
6612 + subrepoopts
6563 + subrepoopts
6613 + formatteropts,
6564 + formatteropts,
6614 _(b'[OPTION]... [FILE]...'),
6565 _(b'[OPTION]... [FILE]...'),
6615 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6566 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6616 helpbasic=True,
6567 helpbasic=True,
6617 inferrepo=True,
6568 inferrepo=True,
6618 intents={INTENT_READONLY},
6569 intents={INTENT_READONLY},
6619 )
6570 )
6620 def status(ui, repo, *pats, **opts):
6571 def status(ui, repo, *pats, **opts):
6621 """show changed files in the working directory
6572 """show changed files in the working directory
6622
6573
6623 Show status of files in the repository. If names are given, only
6574 Show status of files in the repository. If names are given, only
6624 files that match are shown. Files that are clean or ignored or
6575 files that match are shown. Files that are clean or ignored or
6625 the source of a copy/move operation, are not listed unless
6576 the source of a copy/move operation, are not listed unless
6626 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6577 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6627 Unless options described with "show only ..." are given, the
6578 Unless options described with "show only ..." are given, the
6628 options -mardu are used.
6579 options -mardu are used.
6629
6580
6630 Option -q/--quiet hides untracked (unknown and ignored) files
6581 Option -q/--quiet hides untracked (unknown and ignored) files
6631 unless explicitly requested with -u/--unknown or -i/--ignored.
6582 unless explicitly requested with -u/--unknown or -i/--ignored.
6632
6583
6633 .. note::
6584 .. note::
6634
6585
6635 :hg:`status` may appear to disagree with diff if permissions have
6586 :hg:`status` may appear to disagree with diff if permissions have
6636 changed or a merge has occurred. The standard diff format does
6587 changed or a merge has occurred. The standard diff format does
6637 not report permission changes and diff only reports changes
6588 not report permission changes and diff only reports changes
6638 relative to one merge parent.
6589 relative to one merge parent.
6639
6590
6640 If one revision is given, it is used as the base revision.
6591 If one revision is given, it is used as the base revision.
6641 If two revisions are given, the differences between them are
6592 If two revisions are given, the differences between them are
6642 shown. The --change option can also be used as a shortcut to list
6593 shown. The --change option can also be used as a shortcut to list
6643 the changed files of a revision from its first parent.
6594 the changed files of a revision from its first parent.
6644
6595
6645 The codes used to show the status of files are::
6596 The codes used to show the status of files are::
6646
6597
6647 M = modified
6598 M = modified
6648 A = added
6599 A = added
6649 R = removed
6600 R = removed
6650 C = clean
6601 C = clean
6651 ! = missing (deleted by non-hg command, but still tracked)
6602 ! = missing (deleted by non-hg command, but still tracked)
6652 ? = not tracked
6603 ? = not tracked
6653 I = ignored
6604 I = ignored
6654 = origin of the previous file (with --copies)
6605 = origin of the previous file (with --copies)
6655
6606
6656 .. container:: verbose
6607 .. container:: verbose
6657
6608
6658 The -t/--terse option abbreviates the output by showing only the directory
6609 The -t/--terse option abbreviates the output by showing only the directory
6659 name if all the files in it share the same status. The option takes an
6610 name if all the files in it share the same status. The option takes an
6660 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6611 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6661 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6612 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6662 for 'ignored' and 'c' for clean.
6613 for 'ignored' and 'c' for clean.
6663
6614
6664 It abbreviates only those statuses which are passed. Note that clean and
6615 It abbreviates only those statuses which are passed. Note that clean and
6665 ignored files are not displayed with '--terse ic' unless the -c/--clean
6616 ignored files are not displayed with '--terse ic' unless the -c/--clean
6666 and -i/--ignored options are also used.
6617 and -i/--ignored options are also used.
6667
6618
6668 The -v/--verbose option shows information when the repository is in an
6619 The -v/--verbose option shows information when the repository is in an
6669 unfinished merge, shelve, rebase state etc. You can have this behavior
6620 unfinished merge, shelve, rebase state etc. You can have this behavior
6670 turned on by default by enabling the ``commands.status.verbose`` option.
6621 turned on by default by enabling the ``commands.status.verbose`` option.
6671
6622
6672 You can skip displaying some of these states by setting
6623 You can skip displaying some of these states by setting
6673 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6624 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6674 'histedit', 'merge', 'rebase', or 'unshelve'.
6625 'histedit', 'merge', 'rebase', or 'unshelve'.
6675
6626
6676 Template:
6627 Template:
6677
6628
6678 The following keywords are supported in addition to the common template
6629 The following keywords are supported in addition to the common template
6679 keywords and functions. See also :hg:`help templates`.
6630 keywords and functions. See also :hg:`help templates`.
6680
6631
6681 :path: String. Repository-absolute path of the file.
6632 :path: String. Repository-absolute path of the file.
6682 :source: String. Repository-absolute path of the file originated from.
6633 :source: String. Repository-absolute path of the file originated from.
6683 Available if ``--copies`` is specified.
6634 Available if ``--copies`` is specified.
6684 :status: String. Character denoting file's status.
6635 :status: String. Character denoting file's status.
6685
6636
6686 Examples:
6637 Examples:
6687
6638
6688 - show changes in the working directory relative to a
6639 - show changes in the working directory relative to a
6689 changeset::
6640 changeset::
6690
6641
6691 hg status --rev 9353
6642 hg status --rev 9353
6692
6643
6693 - show changes in the working directory relative to the
6644 - show changes in the working directory relative to the
6694 current directory (see :hg:`help patterns` for more information)::
6645 current directory (see :hg:`help patterns` for more information)::
6695
6646
6696 hg status re:
6647 hg status re:
6697
6648
6698 - show all changes including copies in an existing changeset::
6649 - show all changes including copies in an existing changeset::
6699
6650
6700 hg status --copies --change 9353
6651 hg status --copies --change 9353
6701
6652
6702 - get a NUL separated list of added files, suitable for xargs::
6653 - get a NUL separated list of added files, suitable for xargs::
6703
6654
6704 hg status -an0
6655 hg status -an0
6705
6656
6706 - show more information about the repository status, abbreviating
6657 - show more information about the repository status, abbreviating
6707 added, removed, modified, deleted, and untracked paths::
6658 added, removed, modified, deleted, and untracked paths::
6708
6659
6709 hg status -v -t mardu
6660 hg status -v -t mardu
6710
6661
6711 Returns 0 on success.
6662 Returns 0 on success.
6712
6663
6713 """
6664 """
6714
6665
6715 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6666 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6716 opts = pycompat.byteskwargs(opts)
6667 opts = pycompat.byteskwargs(opts)
6717 revs = opts.get(b'rev', [])
6668 revs = opts.get(b'rev', [])
6718 change = opts.get(b'change', b'')
6669 change = opts.get(b'change', b'')
6719 terse = opts.get(b'terse', _NOTTERSE)
6670 terse = opts.get(b'terse', _NOTTERSE)
6720 if terse is _NOTTERSE:
6671 if terse is _NOTTERSE:
6721 if revs:
6672 if revs:
6722 terse = b''
6673 terse = b''
6723 else:
6674 else:
6724 terse = ui.config(b'commands', b'status.terse')
6675 terse = ui.config(b'commands', b'status.terse')
6725
6676
6726 if revs and terse:
6677 if revs and terse:
6727 msg = _(b'cannot use --terse with --rev')
6678 msg = _(b'cannot use --terse with --rev')
6728 raise error.InputError(msg)
6679 raise error.InputError(msg)
6729 elif change:
6680 elif change:
6730 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6681 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6731 ctx2 = logcmdutil.revsingle(repo, change, None)
6682 ctx2 = logcmdutil.revsingle(repo, change, None)
6732 ctx1 = ctx2.p1()
6683 ctx1 = ctx2.p1()
6733 else:
6684 else:
6734 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6685 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6735 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6686 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6736
6687
6737 forcerelativevalue = None
6688 forcerelativevalue = None
6738 if ui.hasconfig(b'commands', b'status.relative'):
6689 if ui.hasconfig(b'commands', b'status.relative'):
6739 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6690 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6740 uipathfn = scmutil.getuipathfn(
6691 uipathfn = scmutil.getuipathfn(
6741 repo,
6692 repo,
6742 legacyrelativevalue=bool(pats),
6693 legacyrelativevalue=bool(pats),
6743 forcerelativevalue=forcerelativevalue,
6694 forcerelativevalue=forcerelativevalue,
6744 )
6695 )
6745
6696
6746 if opts.get(b'print0'):
6697 if opts.get(b'print0'):
6747 end = b'\0'
6698 end = b'\0'
6748 else:
6699 else:
6749 end = b'\n'
6700 end = b'\n'
6750 states = b'modified added removed deleted unknown ignored clean'.split()
6701 states = b'modified added removed deleted unknown ignored clean'.split()
6751 show = [k for k in states if opts.get(k)]
6702 show = [k for k in states if opts.get(k)]
6752 if opts.get(b'all'):
6703 if opts.get(b'all'):
6753 show += ui.quiet and (states[:4] + [b'clean']) or states
6704 show += ui.quiet and (states[:4] + [b'clean']) or states
6754
6705
6755 if not show:
6706 if not show:
6756 if ui.quiet:
6707 if ui.quiet:
6757 show = states[:4]
6708 show = states[:4]
6758 else:
6709 else:
6759 show = states[:5]
6710 show = states[:5]
6760
6711
6761 m = scmutil.match(ctx2, pats, opts)
6712 m = scmutil.match(ctx2, pats, opts)
6762 if terse:
6713 if terse:
6763 # we need to compute clean and unknown to terse
6714 # we need to compute clean and unknown to terse
6764 stat = repo.status(
6715 stat = repo.status(
6765 ctx1.node(),
6716 ctx1.node(),
6766 ctx2.node(),
6717 ctx2.node(),
6767 m,
6718 m,
6768 b'ignored' in show or b'i' in terse,
6719 b'ignored' in show or b'i' in terse,
6769 clean=True,
6720 clean=True,
6770 unknown=True,
6721 unknown=True,
6771 listsubrepos=opts.get(b'subrepos'),
6722 listsubrepos=opts.get(b'subrepos'),
6772 )
6723 )
6773
6724
6774 stat = cmdutil.tersedir(stat, terse)
6725 stat = cmdutil.tersedir(stat, terse)
6775 else:
6726 else:
6776 stat = repo.status(
6727 stat = repo.status(
6777 ctx1.node(),
6728 ctx1.node(),
6778 ctx2.node(),
6729 ctx2.node(),
6779 m,
6730 m,
6780 b'ignored' in show,
6731 b'ignored' in show,
6781 b'clean' in show,
6732 b'clean' in show,
6782 b'unknown' in show,
6733 b'unknown' in show,
6783 opts.get(b'subrepos'),
6734 opts.get(b'subrepos'),
6784 )
6735 )
6785
6736
6786 changestates = zip(
6737 changestates = zip(
6787 states,
6738 states,
6788 pycompat.iterbytestr(b'MAR!?IC'),
6739 pycompat.iterbytestr(b'MAR!?IC'),
6789 [getattr(stat, s.decode('utf8')) for s in states],
6740 [getattr(stat, s.decode('utf8')) for s in states],
6790 )
6741 )
6791
6742
6792 copy = {}
6743 copy = {}
6793 show_copies = ui.configbool(b'ui', b'statuscopies')
6744 show_copies = ui.configbool(b'ui', b'statuscopies')
6794 if opts.get(b'copies') is not None:
6745 if opts.get(b'copies') is not None:
6795 show_copies = opts.get(b'copies')
6746 show_copies = opts.get(b'copies')
6796 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6747 show_copies = (show_copies or opts.get(b'all')) and not opts.get(
6797 b'no_status'
6748 b'no_status'
6798 )
6749 )
6799 if show_copies:
6750 if show_copies:
6800 copy = copies.pathcopies(ctx1, ctx2, m)
6751 copy = copies.pathcopies(ctx1, ctx2, m)
6801
6752
6802 morestatus = None
6753 morestatus = None
6803 if (
6754 if (
6804 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6755 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6805 and not ui.plain()
6756 and not ui.plain()
6806 and not opts.get(b'print0')
6757 and not opts.get(b'print0')
6807 ):
6758 ):
6808 morestatus = cmdutil.readmorestatus(repo)
6759 morestatus = cmdutil.readmorestatus(repo)
6809
6760
6810 ui.pager(b'status')
6761 ui.pager(b'status')
6811 fm = ui.formatter(b'status', opts)
6762 fm = ui.formatter(b'status', opts)
6812 fmt = b'%s' + end
6763 fmt = b'%s' + end
6813 showchar = not opts.get(b'no_status')
6764 showchar = not opts.get(b'no_status')
6814
6765
6815 for state, char, files in changestates:
6766 for state, char, files in changestates:
6816 if state in show:
6767 if state in show:
6817 label = b'status.' + state
6768 label = b'status.' + state
6818 for f in files:
6769 for f in files:
6819 fm.startitem()
6770 fm.startitem()
6820 fm.context(ctx=ctx2)
6771 fm.context(ctx=ctx2)
6821 fm.data(itemtype=b'file', path=f)
6772 fm.data(itemtype=b'file', path=f)
6822 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6773 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6823 fm.plain(fmt % uipathfn(f), label=label)
6774 fm.plain(fmt % uipathfn(f), label=label)
6824 if f in copy:
6775 if f in copy:
6825 fm.data(source=copy[f])
6776 fm.data(source=copy[f])
6826 fm.plain(
6777 fm.plain(
6827 (b' %s' + end) % uipathfn(copy[f]),
6778 (b' %s' + end) % uipathfn(copy[f]),
6828 label=b'status.copied',
6779 label=b'status.copied',
6829 )
6780 )
6830 if morestatus:
6781 if morestatus:
6831 morestatus.formatfile(f, fm)
6782 morestatus.formatfile(f, fm)
6832
6783
6833 if morestatus:
6784 if morestatus:
6834 morestatus.formatfooter(fm)
6785 morestatus.formatfooter(fm)
6835 fm.end()
6786 fm.end()
6836
6787
6837
6788
6838 @command(
6789 @command(
6839 b'summary|sum',
6790 b'summary|sum',
6840 [(b'', b'remote', None, _(b'check for push and pull'))],
6791 [(b'', b'remote', None, _(b'check for push and pull'))],
6841 b'[--remote]',
6792 b'[--remote]',
6842 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6793 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6843 helpbasic=True,
6794 helpbasic=True,
6844 intents={INTENT_READONLY},
6795 intents={INTENT_READONLY},
6845 )
6796 )
6846 def summary(ui, repo, **opts):
6797 def summary(ui, repo, **opts):
6847 """summarize working directory state
6798 """summarize working directory state
6848
6799
6849 This generates a brief summary of the working directory state,
6800 This generates a brief summary of the working directory state,
6850 including parents, branch, commit status, phase and available updates.
6801 including parents, branch, commit status, phase and available updates.
6851
6802
6852 With the --remote option, this will check the default paths for
6803 With the --remote option, this will check the default paths for
6853 incoming and outgoing changes. This can be time-consuming.
6804 incoming and outgoing changes. This can be time-consuming.
6854
6805
6855 Returns 0 on success.
6806 Returns 0 on success.
6856 """
6807 """
6857
6808
6858 ui.pager(b'summary')
6809 ui.pager(b'summary')
6859 ctx = repo[None]
6810 ctx = repo[None]
6860 parents = ctx.parents()
6811 parents = ctx.parents()
6861 pnode = parents[0].node()
6812 pnode = parents[0].node()
6862 marks = []
6813 marks = []
6863
6814
6864 try:
6815 try:
6865 ms = mergestatemod.mergestate.read(repo)
6816 ms = mergestatemod.mergestate.read(repo)
6866 except error.UnsupportedMergeRecords as e:
6817 except error.UnsupportedMergeRecords as e:
6867 s = b' '.join(e.recordtypes)
6818 s = b' '.join(e.recordtypes)
6868 ui.warn(
6819 ui.warn(
6869 _(b'warning: merge state has unsupported record types: %s\n') % s
6820 _(b'warning: merge state has unsupported record types: %s\n') % s
6870 )
6821 )
6871 unresolved = []
6822 unresolved = []
6872 else:
6823 else:
6873 unresolved = list(ms.unresolved())
6824 unresolved = list(ms.unresolved())
6874
6825
6875 for p in parents:
6826 for p in parents:
6876 # label with log.changeset (instead of log.parent) since this
6827 # label with log.changeset (instead of log.parent) since this
6877 # shows a working directory parent *changeset*:
6828 # shows a working directory parent *changeset*:
6878 # i18n: column positioning for "hg summary"
6829 # i18n: column positioning for "hg summary"
6879 ui.write(
6830 ui.write(
6880 _(b'parent: %d:%s ') % (p.rev(), p),
6831 _(b'parent: %d:%s ') % (p.rev(), p),
6881 label=logcmdutil.changesetlabels(p),
6832 label=logcmdutil.changesetlabels(p),
6882 )
6833 )
6883 ui.write(b' '.join(p.tags()), label=b'log.tag')
6834 ui.write(b' '.join(p.tags()), label=b'log.tag')
6884 if p.bookmarks():
6835 if p.bookmarks():
6885 marks.extend(p.bookmarks())
6836 marks.extend(p.bookmarks())
6886 if p.rev() == -1:
6837 if p.rev() == -1:
6887 if not len(repo):
6838 if not len(repo):
6888 ui.write(_(b' (empty repository)'))
6839 ui.write(_(b' (empty repository)'))
6889 else:
6840 else:
6890 ui.write(_(b' (no revision checked out)'))
6841 ui.write(_(b' (no revision checked out)'))
6891 if p.obsolete():
6842 if p.obsolete():
6892 ui.write(_(b' (obsolete)'))
6843 ui.write(_(b' (obsolete)'))
6893 if p.isunstable():
6844 if p.isunstable():
6894 instabilities = (
6845 instabilities = (
6895 ui.label(instability, b'trouble.%s' % instability)
6846 ui.label(instability, b'trouble.%s' % instability)
6896 for instability in p.instabilities()
6847 for instability in p.instabilities()
6897 )
6848 )
6898 ui.write(b' (' + b', '.join(instabilities) + b')')
6849 ui.write(b' (' + b', '.join(instabilities) + b')')
6899 ui.write(b'\n')
6850 ui.write(b'\n')
6900 if p.description():
6851 if p.description():
6901 ui.status(
6852 ui.status(
6902 b' ' + p.description().splitlines()[0].strip() + b'\n',
6853 b' ' + p.description().splitlines()[0].strip() + b'\n',
6903 label=b'log.summary',
6854 label=b'log.summary',
6904 )
6855 )
6905
6856
6906 branch = ctx.branch()
6857 branch = ctx.branch()
6907 bheads = repo.branchheads(branch)
6858 bheads = repo.branchheads(branch)
6908 # i18n: column positioning for "hg summary"
6859 # i18n: column positioning for "hg summary"
6909 m = _(b'branch: %s\n') % branch
6860 m = _(b'branch: %s\n') % branch
6910 if branch != b'default':
6861 if branch != b'default':
6911 ui.write(m, label=b'log.branch')
6862 ui.write(m, label=b'log.branch')
6912 else:
6863 else:
6913 ui.status(m, label=b'log.branch')
6864 ui.status(m, label=b'log.branch')
6914
6865
6915 if marks:
6866 if marks:
6916 active = repo._activebookmark
6867 active = repo._activebookmark
6917 # i18n: column positioning for "hg summary"
6868 # i18n: column positioning for "hg summary"
6918 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6869 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6919 if active is not None:
6870 if active is not None:
6920 if active in marks:
6871 if active in marks:
6921 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6872 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6922 marks.remove(active)
6873 marks.remove(active)
6923 else:
6874 else:
6924 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6875 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6925 for m in marks:
6876 for m in marks:
6926 ui.write(b' ' + m, label=b'log.bookmark')
6877 ui.write(b' ' + m, label=b'log.bookmark')
6927 ui.write(b'\n', label=b'log.bookmark')
6878 ui.write(b'\n', label=b'log.bookmark')
6928
6879
6929 status = repo.status(unknown=True)
6880 status = repo.status(unknown=True)
6930
6881
6931 c = repo.dirstate.copies()
6882 c = repo.dirstate.copies()
6932 copied, renamed = [], []
6883 copied, renamed = [], []
6933 for d, s in c.items():
6884 for d, s in c.items():
6934 if s in status.removed:
6885 if s in status.removed:
6935 status.removed.remove(s)
6886 status.removed.remove(s)
6936 renamed.append(d)
6887 renamed.append(d)
6937 else:
6888 else:
6938 copied.append(d)
6889 copied.append(d)
6939 if d in status.added:
6890 if d in status.added:
6940 status.added.remove(d)
6891 status.added.remove(d)
6941
6892
6942 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6893 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6943
6894
6944 labels = [
6895 labels = [
6945 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6896 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6946 (ui.label(_(b'%d added'), b'status.added'), status.added),
6897 (ui.label(_(b'%d added'), b'status.added'), status.added),
6947 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6898 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6948 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6899 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6949 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6900 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6950 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6901 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6951 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6902 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6952 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6903 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6953 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6904 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6954 ]
6905 ]
6955 t = []
6906 t = []
6956 for l, s in labels:
6907 for l, s in labels:
6957 if s:
6908 if s:
6958 t.append(l % len(s))
6909 t.append(l % len(s))
6959
6910
6960 t = b', '.join(t)
6911 t = b', '.join(t)
6961 cleanworkdir = False
6912 cleanworkdir = False
6962
6913
6963 if repo.vfs.exists(b'graftstate'):
6914 if repo.vfs.exists(b'graftstate'):
6964 t += _(b' (graft in progress)')
6915 t += _(b' (graft in progress)')
6965 if repo.vfs.exists(b'updatestate'):
6916 if repo.vfs.exists(b'updatestate'):
6966 t += _(b' (interrupted update)')
6917 t += _(b' (interrupted update)')
6967 elif len(parents) > 1:
6918 elif len(parents) > 1:
6968 t += _(b' (merge)')
6919 t += _(b' (merge)')
6969 elif branch != parents[0].branch():
6920 elif branch != parents[0].branch():
6970 t += _(b' (new branch)')
6921 t += _(b' (new branch)')
6971 elif parents[0].closesbranch() and pnode in repo.branchheads(
6922 elif parents[0].closesbranch() and pnode in repo.branchheads(
6972 branch, closed=True
6923 branch, closed=True
6973 ):
6924 ):
6974 t += _(b' (head closed)')
6925 t += _(b' (head closed)')
6975 elif not (
6926 elif not (
6976 status.modified
6927 status.modified
6977 or status.added
6928 or status.added
6978 or status.removed
6929 or status.removed
6979 or renamed
6930 or renamed
6980 or copied
6931 or copied
6981 or subs
6932 or subs
6982 ):
6933 ):
6983 t += _(b' (clean)')
6934 t += _(b' (clean)')
6984 cleanworkdir = True
6935 cleanworkdir = True
6985 elif pnode not in bheads:
6936 elif pnode not in bheads:
6986 t += _(b' (new branch head)')
6937 t += _(b' (new branch head)')
6987
6938
6988 if parents:
6939 if parents:
6989 pendingphase = max(p.phase() for p in parents)
6940 pendingphase = max(p.phase() for p in parents)
6990 else:
6941 else:
6991 pendingphase = phases.public
6942 pendingphase = phases.public
6992
6943
6993 if pendingphase > phases.newcommitphase(ui):
6944 if pendingphase > phases.newcommitphase(ui):
6994 t += b' (%s)' % phases.phasenames[pendingphase]
6945 t += b' (%s)' % phases.phasenames[pendingphase]
6995
6946
6996 if cleanworkdir:
6947 if cleanworkdir:
6997 # i18n: column positioning for "hg summary"
6948 # i18n: column positioning for "hg summary"
6998 ui.status(_(b'commit: %s\n') % t.strip())
6949 ui.status(_(b'commit: %s\n') % t.strip())
6999 else:
6950 else:
7000 # i18n: column positioning for "hg summary"
6951 # i18n: column positioning for "hg summary"
7001 ui.write(_(b'commit: %s\n') % t.strip())
6952 ui.write(_(b'commit: %s\n') % t.strip())
7002
6953
7003 # all ancestors of branch heads - all ancestors of parent = new csets
6954 # all ancestors of branch heads - all ancestors of parent = new csets
7004 new = len(
6955 new = len(
7005 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6956 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7006 )
6957 )
7007
6958
7008 if new == 0:
6959 if new == 0:
7009 # i18n: column positioning for "hg summary"
6960 # i18n: column positioning for "hg summary"
7010 ui.status(_(b'update: (current)\n'))
6961 ui.status(_(b'update: (current)\n'))
7011 elif pnode not in bheads:
6962 elif pnode not in bheads:
7012 # i18n: column positioning for "hg summary"
6963 # i18n: column positioning for "hg summary"
7013 ui.write(_(b'update: %d new changesets (update)\n') % new)
6964 ui.write(_(b'update: %d new changesets (update)\n') % new)
7014 else:
6965 else:
7015 # i18n: column positioning for "hg summary"
6966 # i18n: column positioning for "hg summary"
7016 ui.write(
6967 ui.write(
7017 _(b'update: %d new changesets, %d branch heads (merge)\n')
6968 _(b'update: %d new changesets, %d branch heads (merge)\n')
7018 % (new, len(bheads))
6969 % (new, len(bheads))
7019 )
6970 )
7020
6971
7021 t = []
6972 t = []
7022 draft = len(repo.revs(b'draft()'))
6973 draft = len(repo.revs(b'draft()'))
7023 if draft:
6974 if draft:
7024 t.append(_(b'%d draft') % draft)
6975 t.append(_(b'%d draft') % draft)
7025 secret = len(repo.revs(b'secret()'))
6976 secret = len(repo.revs(b'secret()'))
7026 if secret:
6977 if secret:
7027 t.append(_(b'%d secret') % secret)
6978 t.append(_(b'%d secret') % secret)
7028
6979
7029 if draft or secret:
6980 if draft or secret:
7030 ui.status(_(b'phases: %s\n') % b', '.join(t))
6981 ui.status(_(b'phases: %s\n') % b', '.join(t))
7031
6982
7032 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6983 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7033 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6984 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7034 numtrouble = len(repo.revs(trouble + b"()"))
6985 numtrouble = len(repo.revs(trouble + b"()"))
7035 # We write all the possibilities to ease translation
6986 # We write all the possibilities to ease translation
7036 troublemsg = {
6987 troublemsg = {
7037 b"orphan": _(b"orphan: %d changesets"),
6988 b"orphan": _(b"orphan: %d changesets"),
7038 b"contentdivergent": _(b"content-divergent: %d changesets"),
6989 b"contentdivergent": _(b"content-divergent: %d changesets"),
7039 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6990 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7040 }
6991 }
7041 if numtrouble > 0:
6992 if numtrouble > 0:
7042 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6993 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7043
6994
7044 cmdutil.summaryhooks(ui, repo)
6995 cmdutil.summaryhooks(ui, repo)
7045
6996
7046 if opts.get('remote'):
6997 if opts.get('remote'):
7047 needsincoming, needsoutgoing = True, True
6998 needsincoming, needsoutgoing = True, True
7048 else:
6999 else:
7049 needsincoming, needsoutgoing = False, False
7000 needsincoming, needsoutgoing = False, False
7050 for i, o in cmdutil.summaryremotehooks(
7001 for i, o in cmdutil.summaryremotehooks(
7051 ui, repo, pycompat.byteskwargs(opts), None
7002 ui, repo, pycompat.byteskwargs(opts), None
7052 ):
7003 ):
7053 if i:
7004 if i:
7054 needsincoming = True
7005 needsincoming = True
7055 if o:
7006 if o:
7056 needsoutgoing = True
7007 needsoutgoing = True
7057 if not needsincoming and not needsoutgoing:
7008 if not needsincoming and not needsoutgoing:
7058 return
7009 return
7059
7010
7060 def getincoming():
7011 def getincoming():
7061 # XXX We should actually skip this if no default is specified, instead
7012 # XXX We should actually skip this if no default is specified, instead
7062 # of passing "default" which will resolve as "./default/" if no default
7013 # of passing "default" which will resolve as "./default/" if no default
7063 # path is defined.
7014 # path is defined.
7064 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7015 path = urlutil.get_unique_pull_path_obj(b'summary', ui, b'default')
7065 sbranch = path.branch
7016 sbranch = path.branch
7066 try:
7017 try:
7067 other = hg.peer(repo, {}, path)
7018 other = hg.peer(repo, {}, path)
7068 except error.RepoError:
7019 except error.RepoError:
7069 if opts.get('remote'):
7020 if opts.get('remote'):
7070 raise
7021 raise
7071 return path.loc, sbranch, None, None, None
7022 return path.loc, sbranch, None, None, None
7072 branches = (path.branch, [])
7023 branches = (path.branch, [])
7073 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7024 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7074 if revs:
7025 if revs:
7075 revs = [other.lookup(rev) for rev in revs]
7026 revs = [other.lookup(rev) for rev in revs]
7076 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7027 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(path.loc))
7077 with repo.ui.silent():
7028 with repo.ui.silent():
7078 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7029 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7079 return path.loc, sbranch, other, commoninc, commoninc[1]
7030 return path.loc, sbranch, other, commoninc, commoninc[1]
7080
7031
7081 if needsincoming:
7032 if needsincoming:
7082 source, sbranch, sother, commoninc, incoming = getincoming()
7033 source, sbranch, sother, commoninc, incoming = getincoming()
7083 else:
7034 else:
7084 source = sbranch = sother = commoninc = incoming = None
7035 source = sbranch = sother = commoninc = incoming = None
7085
7036
7086 def getoutgoing():
7037 def getoutgoing():
7087 # XXX We should actually skip this if no default is specified, instead
7038 # XXX We should actually skip this if no default is specified, instead
7088 # of passing "default" which will resolve as "./default/" if no default
7039 # of passing "default" which will resolve as "./default/" if no default
7089 # path is defined.
7040 # path is defined.
7090 d = None
7041 d = None
7091 if b'default-push' in ui.paths:
7042 if b'default-push' in ui.paths:
7092 d = b'default-push'
7043 d = b'default-push'
7093 elif b'default' in ui.paths:
7044 elif b'default' in ui.paths:
7094 d = b'default'
7045 d = b'default'
7095 path = None
7046 path = None
7096 if d is not None:
7047 if d is not None:
7097 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7048 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7098 dest = path.loc
7049 dest = path.loc
7099 dbranch = path.branch
7050 dbranch = path.branch
7100 else:
7051 else:
7101 dest = b'default'
7052 dest = b'default'
7102 dbranch = None
7053 dbranch = None
7103 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7054 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7104 if source != dest:
7055 if source != dest:
7105 try:
7056 try:
7106 dother = hg.peer(repo, {}, path if path is not None else dest)
7057 dother = hg.peer(repo, {}, path if path is not None else dest)
7107 except error.RepoError:
7058 except error.RepoError:
7108 if opts.get('remote'):
7059 if opts.get('remote'):
7109 raise
7060 raise
7110 return dest, dbranch, None, None
7061 return dest, dbranch, None, None
7111 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7062 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7112 elif sother is None:
7063 elif sother is None:
7113 # there is no explicit destination peer, but source one is invalid
7064 # there is no explicit destination peer, but source one is invalid
7114 return dest, dbranch, None, None
7065 return dest, dbranch, None, None
7115 else:
7066 else:
7116 dother = sother
7067 dother = sother
7117 if source != dest or (sbranch is not None and sbranch != dbranch):
7068 if source != dest or (sbranch is not None and sbranch != dbranch):
7118 common = None
7069 common = None
7119 else:
7070 else:
7120 common = commoninc
7071 common = commoninc
7121 if revs:
7072 if revs:
7122 revs = [repo.lookup(rev) for rev in revs]
7073 revs = [repo.lookup(rev) for rev in revs]
7123 with repo.ui.silent():
7074 with repo.ui.silent():
7124 outgoing = discovery.findcommonoutgoing(
7075 outgoing = discovery.findcommonoutgoing(
7125 repo, dother, onlyheads=revs, commoninc=common
7076 repo, dother, onlyheads=revs, commoninc=common
7126 )
7077 )
7127 return dest, dbranch, dother, outgoing
7078 return dest, dbranch, dother, outgoing
7128
7079
7129 if needsoutgoing:
7080 if needsoutgoing:
7130 dest, dbranch, dother, outgoing = getoutgoing()
7081 dest, dbranch, dother, outgoing = getoutgoing()
7131 else:
7082 else:
7132 dest = dbranch = dother = outgoing = None
7083 dest = dbranch = dother = outgoing = None
7133
7084
7134 if opts.get('remote'):
7085 if opts.get('remote'):
7135 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7086 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7136 # The former always sets `sother` (or raises an exception if it can't);
7087 # The former always sets `sother` (or raises an exception if it can't);
7137 # the latter always sets `outgoing`.
7088 # the latter always sets `outgoing`.
7138 assert sother is not None
7089 assert sother is not None
7139 assert outgoing is not None
7090 assert outgoing is not None
7140
7091
7141 t = []
7092 t = []
7142 if incoming:
7093 if incoming:
7143 t.append(_(b'1 or more incoming'))
7094 t.append(_(b'1 or more incoming'))
7144 o = outgoing.missing
7095 o = outgoing.missing
7145 if o:
7096 if o:
7146 t.append(_(b'%d outgoing') % len(o))
7097 t.append(_(b'%d outgoing') % len(o))
7147 other = dother or sother
7098 other = dother or sother
7148 if b'bookmarks' in other.listkeys(b'namespaces'):
7099 if b'bookmarks' in other.listkeys(b'namespaces'):
7149 counts = bookmarks.summary(repo, other)
7100 counts = bookmarks.summary(repo, other)
7150 if counts[0] > 0:
7101 if counts[0] > 0:
7151 t.append(_(b'%d incoming bookmarks') % counts[0])
7102 t.append(_(b'%d incoming bookmarks') % counts[0])
7152 if counts[1] > 0:
7103 if counts[1] > 0:
7153 t.append(_(b'%d outgoing bookmarks') % counts[1])
7104 t.append(_(b'%d outgoing bookmarks') % counts[1])
7154
7105
7155 if t:
7106 if t:
7156 # i18n: column positioning for "hg summary"
7107 # i18n: column positioning for "hg summary"
7157 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7108 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7158 else:
7109 else:
7159 # i18n: column positioning for "hg summary"
7110 # i18n: column positioning for "hg summary"
7160 ui.status(_(b'remote: (synced)\n'))
7111 ui.status(_(b'remote: (synced)\n'))
7161
7112
7162 cmdutil.summaryremotehooks(
7113 cmdutil.summaryremotehooks(
7163 ui,
7114 ui,
7164 repo,
7115 repo,
7165 pycompat.byteskwargs(opts),
7116 pycompat.byteskwargs(opts),
7166 (
7117 (
7167 (source, sbranch, sother, commoninc),
7118 (source, sbranch, sother, commoninc),
7168 (dest, dbranch, dother, outgoing),
7119 (dest, dbranch, dother, outgoing),
7169 ),
7120 ),
7170 )
7121 )
7171
7122
7172
7123
7173 @command(
7124 @command(
7174 b'tag',
7125 b'tag',
7175 [
7126 [
7176 (b'f', b'force', None, _(b'force tag')),
7127 (b'f', b'force', None, _(b'force tag')),
7177 (b'l', b'local', None, _(b'make the tag local')),
7128 (b'l', b'local', None, _(b'make the tag local')),
7178 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7129 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7179 (b'', b'remove', None, _(b'remove a tag')),
7130 (b'', b'remove', None, _(b'remove a tag')),
7180 # -l/--local is already there, commitopts cannot be used
7131 # -l/--local is already there, commitopts cannot be used
7181 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7132 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7182 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7133 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7183 ]
7134 ]
7184 + commitopts2,
7135 + commitopts2,
7185 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7136 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7186 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7137 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7187 )
7138 )
7188 def tag(ui, repo, name1, *names, **opts):
7139 def tag(ui, repo, name1, *names, **opts):
7189 """add one or more tags for the current or given revision
7140 """add one or more tags for the current or given revision
7190
7141
7191 Name a particular revision using <name>.
7142 Name a particular revision using <name>.
7192
7143
7193 Tags are used to name particular revisions of the repository and are
7144 Tags are used to name particular revisions of the repository and are
7194 very useful to compare different revisions, to go back to significant
7145 very useful to compare different revisions, to go back to significant
7195 earlier versions or to mark branch points as releases, etc. Changing
7146 earlier versions or to mark branch points as releases, etc. Changing
7196 an existing tag is normally disallowed; use -f/--force to override.
7147 an existing tag is normally disallowed; use -f/--force to override.
7197
7148
7198 If no revision is given, the parent of the working directory is
7149 If no revision is given, the parent of the working directory is
7199 used.
7150 used.
7200
7151
7201 To facilitate version control, distribution, and merging of tags,
7152 To facilitate version control, distribution, and merging of tags,
7202 they are stored as a file named ".hgtags" which is managed similarly
7153 they are stored as a file named ".hgtags" which is managed similarly
7203 to other project files and can be hand-edited if necessary. This
7154 to other project files and can be hand-edited if necessary. This
7204 also means that tagging creates a new commit. The file
7155 also means that tagging creates a new commit. The file
7205 ".hg/localtags" is used for local tags (not shared among
7156 ".hg/localtags" is used for local tags (not shared among
7206 repositories).
7157 repositories).
7207
7158
7208 Tag commits are usually made at the head of a branch. If the parent
7159 Tag commits are usually made at the head of a branch. If the parent
7209 of the working directory is not a branch head, :hg:`tag` aborts; use
7160 of the working directory is not a branch head, :hg:`tag` aborts; use
7210 -f/--force to force the tag commit to be based on a non-head
7161 -f/--force to force the tag commit to be based on a non-head
7211 changeset.
7162 changeset.
7212
7163
7213 See :hg:`help dates` for a list of formats valid for -d/--date.
7164 See :hg:`help dates` for a list of formats valid for -d/--date.
7214
7165
7215 Since tag names have priority over branch names during revision
7166 Since tag names have priority over branch names during revision
7216 lookup, using an existing branch name as a tag name is discouraged.
7167 lookup, using an existing branch name as a tag name is discouraged.
7217
7168
7218 Returns 0 on success.
7169 Returns 0 on success.
7219 """
7170 """
7220 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7171 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7221
7172
7222 with repo.wlock(), repo.lock():
7173 with repo.wlock(), repo.lock():
7223 rev_ = b"."
7174 rev_ = b"."
7224 names = [t.strip() for t in (name1,) + names]
7175 names = [t.strip() for t in (name1,) + names]
7225 if len(names) != len(set(names)):
7176 if len(names) != len(set(names)):
7226 raise error.InputError(_(b'tag names must be unique'))
7177 raise error.InputError(_(b'tag names must be unique'))
7227 for n in names:
7178 for n in names:
7228 scmutil.checknewlabel(repo, n, b'tag')
7179 scmutil.checknewlabel(repo, n, b'tag')
7229 if not n:
7180 if not n:
7230 raise error.InputError(
7181 raise error.InputError(
7231 _(b'tag names cannot consist entirely of whitespace')
7182 _(b'tag names cannot consist entirely of whitespace')
7232 )
7183 )
7233 if opts.get('rev'):
7184 if opts.get('rev'):
7234 rev_ = opts['rev']
7185 rev_ = opts['rev']
7235 message = opts.get('message')
7186 message = opts.get('message')
7236 if opts.get('remove'):
7187 if opts.get('remove'):
7237 if opts.get('local'):
7188 if opts.get('local'):
7238 expectedtype = b'local'
7189 expectedtype = b'local'
7239 else:
7190 else:
7240 expectedtype = b'global'
7191 expectedtype = b'global'
7241
7192
7242 for n in names:
7193 for n in names:
7243 if repo.tagtype(n) == b'global':
7194 if repo.tagtype(n) == b'global':
7244 alltags = tagsmod.findglobaltags(ui, repo)
7195 alltags = tagsmod.findglobaltags(ui, repo)
7245 if alltags[n][0] == repo.nullid:
7196 if alltags[n][0] == repo.nullid:
7246 raise error.InputError(
7197 raise error.InputError(
7247 _(b"tag '%s' is already removed") % n
7198 _(b"tag '%s' is already removed") % n
7248 )
7199 )
7249 if not repo.tagtype(n):
7200 if not repo.tagtype(n):
7250 raise error.InputError(_(b"tag '%s' does not exist") % n)
7201 raise error.InputError(_(b"tag '%s' does not exist") % n)
7251 if repo.tagtype(n) != expectedtype:
7202 if repo.tagtype(n) != expectedtype:
7252 if expectedtype == b'global':
7203 if expectedtype == b'global':
7253 raise error.InputError(
7204 raise error.InputError(
7254 _(b"tag '%s' is not a global tag") % n
7205 _(b"tag '%s' is not a global tag") % n
7255 )
7206 )
7256 else:
7207 else:
7257 raise error.InputError(
7208 raise error.InputError(
7258 _(b"tag '%s' is not a local tag") % n
7209 _(b"tag '%s' is not a local tag") % n
7259 )
7210 )
7260 rev_ = b'null'
7211 rev_ = b'null'
7261 if not message:
7212 if not message:
7262 # we don't translate commit messages
7213 # we don't translate commit messages
7263 message = b'Removed tag %s' % b', '.join(names)
7214 message = b'Removed tag %s' % b', '.join(names)
7264 elif not opts.get('force'):
7215 elif not opts.get('force'):
7265 for n in names:
7216 for n in names:
7266 if n in repo.tags():
7217 if n in repo.tags():
7267 raise error.InputError(
7218 raise error.InputError(
7268 _(b"tag '%s' already exists (use -f to force)") % n
7219 _(b"tag '%s' already exists (use -f to force)") % n
7269 )
7220 )
7270 if not opts.get('local'):
7221 if not opts.get('local'):
7271 p1, p2 = repo.dirstate.parents()
7222 p1, p2 = repo.dirstate.parents()
7272 if p2 != repo.nullid:
7223 if p2 != repo.nullid:
7273 raise error.StateError(_(b'uncommitted merge'))
7224 raise error.StateError(_(b'uncommitted merge'))
7274 bheads = repo.branchheads()
7225 bheads = repo.branchheads()
7275 if not opts.get('force') and bheads and p1 not in bheads:
7226 if not opts.get('force') and bheads and p1 not in bheads:
7276 raise error.InputError(
7227 raise error.InputError(
7277 _(
7228 _(
7278 b'working directory is not at a branch head '
7229 b'working directory is not at a branch head '
7279 b'(use -f to force)'
7230 b'(use -f to force)'
7280 )
7231 )
7281 )
7232 )
7282 node = logcmdutil.revsingle(repo, rev_).node()
7233 node = logcmdutil.revsingle(repo, rev_).node()
7283
7234
7284 # don't allow tagging the null rev or the working directory
7235 # don't allow tagging the null rev or the working directory
7285 if node is None:
7236 if node is None:
7286 raise error.InputError(_(b"cannot tag working directory"))
7237 raise error.InputError(_(b"cannot tag working directory"))
7287 elif not opts.get('remove') and node == nullid:
7238 elif not opts.get('remove') and node == nullid:
7288 raise error.InputError(_(b"cannot tag null revision"))
7239 raise error.InputError(_(b"cannot tag null revision"))
7289
7240
7290 if not message:
7241 if not message:
7291 # we don't translate commit messages
7242 # we don't translate commit messages
7292 message = b'Added tag %s for changeset %s' % (
7243 message = b'Added tag %s for changeset %s' % (
7293 b', '.join(names),
7244 b', '.join(names),
7294 short(node),
7245 short(node),
7295 )
7246 )
7296
7247
7297 date = opts.get('date')
7248 date = opts.get('date')
7298 if date:
7249 if date:
7299 date = dateutil.parsedate(date)
7250 date = dateutil.parsedate(date)
7300
7251
7301 if opts.get('remove'):
7252 if opts.get('remove'):
7302 editform = b'tag.remove'
7253 editform = b'tag.remove'
7303 else:
7254 else:
7304 editform = b'tag.add'
7255 editform = b'tag.add'
7305 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7256 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7306
7257
7307 tagsmod.tag(
7258 tagsmod.tag(
7308 repo,
7259 repo,
7309 names,
7260 names,
7310 node,
7261 node,
7311 message,
7262 message,
7312 opts.get('local'),
7263 opts.get('local'),
7313 opts.get('user'),
7264 opts.get('user'),
7314 date,
7265 date,
7315 editor=editor,
7266 editor=editor,
7316 )
7267 )
7317
7268
7318
7269
7319 @command(
7270 @command(
7320 b'tags',
7271 b'tags',
7321 formatteropts,
7272 formatteropts,
7322 b'',
7273 b'',
7323 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7274 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7324 intents={INTENT_READONLY},
7275 intents={INTENT_READONLY},
7325 )
7276 )
7326 def tags(ui, repo, **opts):
7277 def tags(ui, repo, **opts):
7327 """list repository tags
7278 """list repository tags
7328
7279
7329 This lists both regular and local tags. When the -v/--verbose
7280 This lists both regular and local tags. When the -v/--verbose
7330 switch is used, a third column "local" is printed for local tags.
7281 switch is used, a third column "local" is printed for local tags.
7331 When the -q/--quiet switch is used, only the tag name is printed.
7282 When the -q/--quiet switch is used, only the tag name is printed.
7332
7283
7333 .. container:: verbose
7284 .. container:: verbose
7334
7285
7335 Template:
7286 Template:
7336
7287
7337 The following keywords are supported in addition to the common template
7288 The following keywords are supported in addition to the common template
7338 keywords and functions such as ``{tag}``. See also
7289 keywords and functions such as ``{tag}``. See also
7339 :hg:`help templates`.
7290 :hg:`help templates`.
7340
7291
7341 :type: String. ``local`` for local tags.
7292 :type: String. ``local`` for local tags.
7342
7293
7343 Returns 0 on success.
7294 Returns 0 on success.
7344 """
7295 """
7345
7296
7346 ui.pager(b'tags')
7297 ui.pager(b'tags')
7347 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7298 fm = ui.formatter(b'tags', pycompat.byteskwargs(opts))
7348 hexfunc = fm.hexfunc
7299 hexfunc = fm.hexfunc
7349
7300
7350 for t, n in reversed(repo.tagslist()):
7301 for t, n in reversed(repo.tagslist()):
7351 hn = hexfunc(n)
7302 hn = hexfunc(n)
7352 label = b'tags.normal'
7303 label = b'tags.normal'
7353 tagtype = repo.tagtype(t)
7304 tagtype = repo.tagtype(t)
7354 if not tagtype or tagtype == b'global':
7305 if not tagtype or tagtype == b'global':
7355 tagtype = b''
7306 tagtype = b''
7356 else:
7307 else:
7357 label = b'tags.' + tagtype
7308 label = b'tags.' + tagtype
7358
7309
7359 fm.startitem()
7310 fm.startitem()
7360 fm.context(repo=repo)
7311 fm.context(repo=repo)
7361 fm.write(b'tag', b'%s', t, label=label)
7312 fm.write(b'tag', b'%s', t, label=label)
7362 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7313 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7363 fm.condwrite(
7314 fm.condwrite(
7364 not ui.quiet,
7315 not ui.quiet,
7365 b'rev node',
7316 b'rev node',
7366 fmt,
7317 fmt,
7367 repo.changelog.rev(n),
7318 repo.changelog.rev(n),
7368 hn,
7319 hn,
7369 label=label,
7320 label=label,
7370 )
7321 )
7371 fm.condwrite(
7322 fm.condwrite(
7372 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7323 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7373 )
7324 )
7374 fm.plain(b'\n')
7325 fm.plain(b'\n')
7375 fm.end()
7326 fm.end()
7376
7327
7377
7328
7378 @command(
7329 @command(
7379 b'tip',
7330 b'tip',
7380 [
7331 [
7381 (b'p', b'patch', None, _(b'show patch')),
7332 (b'p', b'patch', None, _(b'show patch')),
7382 (b'g', b'git', None, _(b'use git extended diff format')),
7333 (b'g', b'git', None, _(b'use git extended diff format')),
7383 ]
7334 ]
7384 + templateopts,
7335 + templateopts,
7385 _(b'[-p] [-g]'),
7336 _(b'[-p] [-g]'),
7386 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7337 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7387 )
7338 )
7388 def tip(ui, repo, **opts):
7339 def tip(ui, repo, **opts):
7389 """show the tip revision (DEPRECATED)
7340 """show the tip revision (DEPRECATED)
7390
7341
7391 The tip revision (usually just called the tip) is the changeset
7342 The tip revision (usually just called the tip) is the changeset
7392 most recently added to the repository (and therefore the most
7343 most recently added to the repository (and therefore the most
7393 recently changed head).
7344 recently changed head).
7394
7345
7395 If you have just made a commit, that commit will be the tip. If
7346 If you have just made a commit, that commit will be the tip. If
7396 you have just pulled changes from another repository, the tip of
7347 you have just pulled changes from another repository, the tip of
7397 that repository becomes the current tip. The "tip" tag is special
7348 that repository becomes the current tip. The "tip" tag is special
7398 and cannot be renamed or assigned to a different changeset.
7349 and cannot be renamed or assigned to a different changeset.
7399
7350
7400 This command is deprecated, please use :hg:`heads` instead.
7351 This command is deprecated, please use :hg:`heads` instead.
7401
7352
7402 Returns 0 on success.
7353 Returns 0 on success.
7403 """
7354 """
7404 opts = pycompat.byteskwargs(opts)
7355 opts = pycompat.byteskwargs(opts)
7405 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7356 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7406 displayer.show(repo[b'tip'])
7357 displayer.show(repo[b'tip'])
7407 displayer.close()
7358 displayer.close()
7408
7359
7409
7360
7410 @command(
7361 @command(
7411 b'unbundle',
7362 b'unbundle',
7412 [
7363 [
7413 (
7364 (
7414 b'u',
7365 b'u',
7415 b'update',
7366 b'update',
7416 None,
7367 None,
7417 _(b'update to new branch head if changesets were unbundled'),
7368 _(b'update to new branch head if changesets were unbundled'),
7418 )
7369 )
7419 ],
7370 ],
7420 _(b'[-u] FILE...'),
7371 _(b'[-u] FILE...'),
7421 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7372 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7422 )
7373 )
7423 def unbundle(ui, repo, fname1, *fnames, **opts):
7374 def unbundle(ui, repo, fname1, *fnames, **opts):
7424 """apply one or more bundle files
7375 """apply one or more bundle files
7425
7376
7426 Apply one or more bundle files generated by :hg:`bundle`.
7377 Apply one or more bundle files generated by :hg:`bundle`.
7427
7378
7428 Returns 0 on success, 1 if an update has unresolved files.
7379 Returns 0 on success, 1 if an update has unresolved files.
7429 """
7380 """
7430 fnames = (fname1,) + fnames
7381 fnames = (fname1,) + fnames
7431 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7382 modheads = cmdutil.unbundle_files(ui, repo, fnames)
7432
7383
7433 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7384 if cmdutil.postincoming(ui, repo, modheads, opts.get('update'), None, None):
7434 return 1
7385 return 1
7435 else:
7386 else:
7436 return 0
7387 return 0
7437
7388
7438
7389
7439 @command(
7390 @command(
7440 b'unshelve',
7391 b'unshelve',
7441 [
7392 [
7442 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7393 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7443 (
7394 (
7444 b'c',
7395 b'c',
7445 b'continue',
7396 b'continue',
7446 None,
7397 None,
7447 _(b'continue an incomplete unshelve operation'),
7398 _(b'continue an incomplete unshelve operation'),
7448 ),
7399 ),
7449 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7400 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7450 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7401 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7451 (
7402 (
7452 b'n',
7403 b'n',
7453 b'name',
7404 b'name',
7454 b'',
7405 b'',
7455 _(b'restore shelved change with given name'),
7406 _(b'restore shelved change with given name'),
7456 _(b'NAME'),
7407 _(b'NAME'),
7457 ),
7408 ),
7458 (b't', b'tool', b'', _(b'specify merge tool')),
7409 (b't', b'tool', b'', _(b'specify merge tool')),
7459 (
7410 (
7460 b'',
7411 b'',
7461 b'date',
7412 b'date',
7462 b'',
7413 b'',
7463 _(b'set date for temporary commits (DEPRECATED)'),
7414 _(b'set date for temporary commits (DEPRECATED)'),
7464 _(b'DATE'),
7415 _(b'DATE'),
7465 ),
7416 ),
7466 ],
7417 ],
7467 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7418 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7468 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7419 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7469 )
7420 )
7470 def unshelve(ui, repo, *shelved, **opts):
7421 def unshelve(ui, repo, *shelved, **opts):
7471 """restore a shelved change to the working directory
7422 """restore a shelved change to the working directory
7472
7423
7473 This command accepts an optional name of a shelved change to
7424 This command accepts an optional name of a shelved change to
7474 restore. If none is given, the most recent shelved change is used.
7425 restore. If none is given, the most recent shelved change is used.
7475
7426
7476 If a shelved change is applied successfully, the bundle that
7427 If a shelved change is applied successfully, the bundle that
7477 contains the shelved changes is moved to a backup location
7428 contains the shelved changes is moved to a backup location
7478 (.hg/shelve-backup).
7429 (.hg/shelve-backup).
7479
7430
7480 Since you can restore a shelved change on top of an arbitrary
7431 Since you can restore a shelved change on top of an arbitrary
7481 commit, it is possible that unshelving will result in a conflict
7432 commit, it is possible that unshelving will result in a conflict
7482 between your changes and the commits you are unshelving onto. If
7433 between your changes and the commits you are unshelving onto. If
7483 this occurs, you must resolve the conflict, then use
7434 this occurs, you must resolve the conflict, then use
7484 ``--continue`` to complete the unshelve operation. (The bundle
7435 ``--continue`` to complete the unshelve operation. (The bundle
7485 will not be moved until you successfully complete the unshelve.)
7436 will not be moved until you successfully complete the unshelve.)
7486
7437
7487 (Alternatively, you can use ``--abort`` to abandon an unshelve
7438 (Alternatively, you can use ``--abort`` to abandon an unshelve
7488 that causes a conflict. This reverts the unshelved changes, and
7439 that causes a conflict. This reverts the unshelved changes, and
7489 leaves the bundle in place.)
7440 leaves the bundle in place.)
7490
7441
7491 If bare shelved change (without interactive, include and exclude
7442 If bare shelved change (without interactive, include and exclude
7492 option) was done on newly created branch it would restore branch
7443 option) was done on newly created branch it would restore branch
7493 information to the working directory.
7444 information to the working directory.
7494
7445
7495 After a successful unshelve, the shelved changes are stored in a
7446 After a successful unshelve, the shelved changes are stored in a
7496 backup directory. Only the N most recent backups are kept. N
7447 backup directory. Only the N most recent backups are kept. N
7497 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7448 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7498 configuration option.
7449 configuration option.
7499
7450
7500 .. container:: verbose
7451 .. container:: verbose
7501
7452
7502 Timestamp in seconds is used to decide order of backups. More
7453 Timestamp in seconds is used to decide order of backups. More
7503 than ``maxbackups`` backups are kept, if same timestamp
7454 than ``maxbackups`` backups are kept, if same timestamp
7504 prevents from deciding exact order of them, for safety.
7455 prevents from deciding exact order of them, for safety.
7505
7456
7506 Selected changes can be unshelved with ``--interactive`` flag.
7457 Selected changes can be unshelved with ``--interactive`` flag.
7507 The working directory is updated with the selected changes, and
7458 The working directory is updated with the selected changes, and
7508 only the unselected changes remain shelved.
7459 only the unselected changes remain shelved.
7509 Note: The whole shelve is applied to working directory first before
7460 Note: The whole shelve is applied to working directory first before
7510 running interactively. So, this will bring up all the conflicts between
7461 running interactively. So, this will bring up all the conflicts between
7511 working directory and the shelve, irrespective of which changes will be
7462 working directory and the shelve, irrespective of which changes will be
7512 unshelved.
7463 unshelved.
7513 """
7464 """
7514 with repo.wlock():
7465 with repo.wlock():
7515 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7466 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7516
7467
7517
7468
7518 statemod.addunfinished(
7469 statemod.addunfinished(
7519 b'unshelve',
7470 b'unshelve',
7520 fname=b'shelvedstate',
7471 fname=b'shelvedstate',
7521 continueflag=True,
7472 continueflag=True,
7522 abortfunc=shelvemod.hgabortunshelve,
7473 abortfunc=shelvemod.hgabortunshelve,
7523 continuefunc=shelvemod.hgcontinueunshelve,
7474 continuefunc=shelvemod.hgcontinueunshelve,
7524 cmdmsg=_(b'unshelve already in progress'),
7475 cmdmsg=_(b'unshelve already in progress'),
7525 )
7476 )
7526
7477
7527
7478
7528 @command(
7479 @command(
7529 b'update|up|checkout|co',
7480 b'update|up|checkout|co',
7530 [
7481 [
7531 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7482 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7532 (b'c', b'check', None, _(b'require clean working directory')),
7483 (b'c', b'check', None, _(b'require clean working directory')),
7533 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7484 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7534 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7485 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7535 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7486 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7536 ]
7487 ]
7537 + mergetoolopts,
7488 + mergetoolopts,
7538 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7489 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7539 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7490 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7540 helpbasic=True,
7491 helpbasic=True,
7541 )
7492 )
7542 def update(ui, repo, node=None, **opts):
7493 def update(ui, repo, node=None, **opts):
7543 """update working directory (or switch revisions)
7494 """update working directory (or switch revisions)
7544
7495
7545 Update the repository's working directory to the specified
7496 Update the repository's working directory to the specified
7546 changeset. If no changeset is specified, update to the tip of the
7497 changeset. If no changeset is specified, update to the tip of the
7547 current named branch and move the active bookmark (see :hg:`help
7498 current named branch and move the active bookmark (see :hg:`help
7548 bookmarks`).
7499 bookmarks`).
7549
7500
7550 Update sets the working directory's parent revision to the specified
7501 Update sets the working directory's parent revision to the specified
7551 changeset (see :hg:`help parents`).
7502 changeset (see :hg:`help parents`).
7552
7503
7553 If the changeset is not a descendant or ancestor of the working
7504 If the changeset is not a descendant or ancestor of the working
7554 directory's parent and there are uncommitted changes, the update is
7505 directory's parent and there are uncommitted changes, the update is
7555 aborted. With the -c/--check option, the working directory is checked
7506 aborted. With the -c/--check option, the working directory is checked
7556 for uncommitted changes; if none are found, the working directory is
7507 for uncommitted changes; if none are found, the working directory is
7557 updated to the specified changeset.
7508 updated to the specified changeset.
7558
7509
7559 .. container:: verbose
7510 .. container:: verbose
7560
7511
7561 The -C/--clean, -c/--check, and -m/--merge options control what
7512 The -C/--clean, -c/--check, and -m/--merge options control what
7562 happens if the working directory contains uncommitted changes.
7513 happens if the working directory contains uncommitted changes.
7563 At most of one of them can be specified.
7514 At most of one of them can be specified.
7564
7515
7565 1. If no option is specified, and if
7516 1. If no option is specified, and if
7566 the requested changeset is an ancestor or descendant of
7517 the requested changeset is an ancestor or descendant of
7567 the working directory's parent, the uncommitted changes
7518 the working directory's parent, the uncommitted changes
7568 are merged into the requested changeset and the merged
7519 are merged into the requested changeset and the merged
7569 result is left uncommitted. If the requested changeset is
7520 result is left uncommitted. If the requested changeset is
7570 not an ancestor or descendant (that is, it is on another
7521 not an ancestor or descendant (that is, it is on another
7571 branch), the update is aborted and the uncommitted changes
7522 branch), the update is aborted and the uncommitted changes
7572 are preserved.
7523 are preserved.
7573
7524
7574 2. With the -m/--merge option, the update is allowed even if the
7525 2. With the -m/--merge option, the update is allowed even if the
7575 requested changeset is not an ancestor or descendant of
7526 requested changeset is not an ancestor or descendant of
7576 the working directory's parent.
7527 the working directory's parent.
7577
7528
7578 3. With the -c/--check option, the update is aborted and the
7529 3. With the -c/--check option, the update is aborted and the
7579 uncommitted changes are preserved.
7530 uncommitted changes are preserved.
7580
7531
7581 4. With the -C/--clean option, uncommitted changes are discarded and
7532 4. With the -C/--clean option, uncommitted changes are discarded and
7582 the working directory is updated to the requested changeset.
7533 the working directory is updated to the requested changeset.
7583
7534
7584 To cancel an uncommitted merge (and lose your changes), use
7535 To cancel an uncommitted merge (and lose your changes), use
7585 :hg:`merge --abort`.
7536 :hg:`merge --abort`.
7586
7537
7587 Use null as the changeset to remove the working directory (like
7538 Use null as the changeset to remove the working directory (like
7588 :hg:`clone -U`).
7539 :hg:`clone -U`).
7589
7540
7590 If you want to revert just one file to an older revision, use
7541 If you want to revert just one file to an older revision, use
7591 :hg:`revert [-r REV] NAME`.
7542 :hg:`revert [-r REV] NAME`.
7592
7543
7593 See :hg:`help dates` for a list of formats valid for -d/--date.
7544 See :hg:`help dates` for a list of formats valid for -d/--date.
7594
7545
7595 Returns 0 on success, 1 if there are unresolved files.
7546 Returns 0 on success, 1 if there are unresolved files.
7596 """
7547 """
7597 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7548 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7598 rev = opts.get('rev')
7549 rev = opts.get('rev')
7599 date = opts.get('date')
7550 date = opts.get('date')
7600 clean = opts.get('clean')
7551 clean = opts.get('clean')
7601 check = opts.get('check')
7552 check = opts.get('check')
7602 merge = opts.get('merge')
7553 merge = opts.get('merge')
7603 if rev and node:
7554 if rev and node:
7604 raise error.InputError(_(b"please specify just one revision"))
7555 raise error.InputError(_(b"please specify just one revision"))
7605
7556
7606 if ui.configbool(b'commands', b'update.requiredest'):
7557 if ui.configbool(b'commands', b'update.requiredest'):
7607 if not node and not rev and not date:
7558 if not node and not rev and not date:
7608 raise error.InputError(
7559 raise error.InputError(
7609 _(b'you must specify a destination'),
7560 _(b'you must specify a destination'),
7610 hint=_(b'for example: hg update ".::"'),
7561 hint=_(b'for example: hg update ".::"'),
7611 )
7562 )
7612
7563
7613 if rev is None or rev == b'':
7564 if rev is None or rev == b'':
7614 rev = node
7565 rev = node
7615
7566
7616 if date and rev is not None:
7567 if date and rev is not None:
7617 raise error.InputError(_(b"you can't specify a revision and a date"))
7568 raise error.InputError(_(b"you can't specify a revision and a date"))
7618
7569
7619 updatecheck = None
7570 updatecheck = None
7620 if check or merge is not None and not merge:
7571 if check or merge is not None and not merge:
7621 updatecheck = b'abort'
7572 updatecheck = b'abort'
7622 elif merge or check is not None and not check:
7573 elif merge or check is not None and not check:
7623 updatecheck = b'none'
7574 updatecheck = b'none'
7624
7575
7625 with repo.wlock():
7576 with repo.wlock():
7626 cmdutil.clearunfinished(repo)
7577 cmdutil.clearunfinished(repo)
7627 if date:
7578 if date:
7628 rev = cmdutil.finddate(ui, repo, date)
7579 rev = cmdutil.finddate(ui, repo, date)
7629
7580
7630 # if we defined a bookmark, we have to remember the original name
7581 # if we defined a bookmark, we have to remember the original name
7631 brev = rev
7582 brev = rev
7632 if rev:
7583 if rev:
7633 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7584 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7634 ctx = logcmdutil.revsingle(repo, rev, default=None)
7585 ctx = logcmdutil.revsingle(repo, rev, default=None)
7635 rev = ctx.rev()
7586 rev = ctx.rev()
7636 hidden = ctx.hidden()
7587 hidden = ctx.hidden()
7637 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7588 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7638 with ui.configoverride(overrides, b'update'):
7589 with ui.configoverride(overrides, b'update'):
7639 ret = hg.updatetotally(
7590 ret = hg.updatetotally(
7640 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7591 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7641 )
7592 )
7642 if hidden:
7593 if hidden:
7643 ctxstr = ctx.hex()[:12]
7594 ctxstr = ctx.hex()[:12]
7644 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7595 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7645
7596
7646 if ctx.obsolete():
7597 if ctx.obsolete():
7647 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7598 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7648 ui.warn(b"(%s)\n" % obsfatemsg)
7599 ui.warn(b"(%s)\n" % obsfatemsg)
7649 return ret
7600 return ret
7650
7601
7651
7602
7652 @command(
7603 @command(
7653 b'verify',
7604 b'verify',
7654 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7605 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7655 helpcategory=command.CATEGORY_MAINTENANCE,
7606 helpcategory=command.CATEGORY_MAINTENANCE,
7656 )
7607 )
7657 def verify(ui, repo, **opts):
7608 def verify(ui, repo, **opts):
7658 """verify the integrity of the repository
7609 """verify the integrity of the repository
7659
7610
7660 Verify the integrity of the current repository.
7611 Verify the integrity of the current repository.
7661
7612
7662 This will perform an extensive check of the repository's
7613 This will perform an extensive check of the repository's
7663 integrity, validating the hashes and checksums of each entry in
7614 integrity, validating the hashes and checksums of each entry in
7664 the changelog, manifest, and tracked files, as well as the
7615 the changelog, manifest, and tracked files, as well as the
7665 integrity of their crosslinks and indices.
7616 integrity of their crosslinks and indices.
7666
7617
7667 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7618 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7668 for more information about recovery from corruption of the
7619 for more information about recovery from corruption of the
7669 repository.
7620 repository.
7670
7621
7671 For an alternative UI with a lot more control over the verification
7622 For an alternative UI with a lot more control over the verification
7672 process and better error reporting, try `hg help admin::verify`.
7623 process and better error reporting, try `hg help admin::verify`.
7673
7624
7674 Returns 0 on success, 1 if errors are encountered.
7625 Returns 0 on success, 1 if errors are encountered.
7675 """
7626 """
7676 level = None
7627 level = None
7677 if opts['full']:
7628 if opts['full']:
7678 level = verifymod.VERIFY_FULL
7629 level = verifymod.VERIFY_FULL
7679 return hg.verify(repo, level)
7630 return hg.verify(repo, level)
7680
7631
7681
7632
7682 @command(
7633 @command(
7683 b'version',
7634 b'version',
7684 [] + formatteropts,
7635 [] + formatteropts,
7685 helpcategory=command.CATEGORY_HELP,
7636 helpcategory=command.CATEGORY_HELP,
7686 norepo=True,
7637 norepo=True,
7687 intents={INTENT_READONLY},
7638 intents={INTENT_READONLY},
7688 )
7639 )
7689 def version_(ui, **opts):
7640 def version_(ui, **opts):
7690 """output version and copyright information
7641 """output version and copyright information
7691
7642
7692 .. container:: verbose
7643 .. container:: verbose
7693
7644
7694 Template:
7645 Template:
7695
7646
7696 The following keywords are supported. See also :hg:`help templates`.
7647 The following keywords are supported. See also :hg:`help templates`.
7697
7648
7698 :extensions: List of extensions.
7649 :extensions: List of extensions.
7699 :ver: String. Version number.
7650 :ver: String. Version number.
7700
7651
7701 And each entry of ``{extensions}`` provides the following sub-keywords
7652 And each entry of ``{extensions}`` provides the following sub-keywords
7702 in addition to ``{ver}``.
7653 in addition to ``{ver}``.
7703
7654
7704 :bundled: Boolean. True if included in the release.
7655 :bundled: Boolean. True if included in the release.
7705 :name: String. Extension name.
7656 :name: String. Extension name.
7706 """
7657 """
7707 if ui.verbose:
7658 if ui.verbose:
7708 ui.pager(b'version')
7659 ui.pager(b'version')
7709 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7660 fm = ui.formatter(b"version", pycompat.byteskwargs(opts))
7710 fm.startitem()
7661 fm.startitem()
7711 fm.write(
7662 fm.write(
7712 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7663 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7713 )
7664 )
7714 license = _(
7665 license = _(
7715 b"(see https://mercurial-scm.org for more information)\n"
7666 b"(see https://mercurial-scm.org for more information)\n"
7716 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7667 b"\nCopyright (C) 2005-2024 Olivia Mackall and others\n"
7717 b"This is free software; see the source for copying conditions. "
7668 b"This is free software; see the source for copying conditions. "
7718 b"There is NO\nwarranty; "
7669 b"There is NO\nwarranty; "
7719 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7670 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7720 )
7671 )
7721 if not ui.quiet:
7672 if not ui.quiet:
7722 fm.plain(license)
7673 fm.plain(license)
7723
7674
7724 if ui.verbose:
7675 if ui.verbose:
7725 fm.plain(_(b"\nEnabled extensions:\n\n"))
7676 fm.plain(_(b"\nEnabled extensions:\n\n"))
7726 # format names and versions into columns
7677 # format names and versions into columns
7727 names = []
7678 names = []
7728 vers = []
7679 vers = []
7729 isinternals = []
7680 isinternals = []
7730 for name, module in sorted(extensions.extensions()):
7681 for name, module in sorted(extensions.extensions()):
7731 names.append(name)
7682 names.append(name)
7732 vers.append(extensions.moduleversion(module) or None)
7683 vers.append(extensions.moduleversion(module) or None)
7733 isinternals.append(extensions.ismoduleinternal(module))
7684 isinternals.append(extensions.ismoduleinternal(module))
7734 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7685 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7735 if names:
7686 if names:
7736 namefmt = b" %%-%ds " % max(len(n) for n in names)
7687 namefmt = b" %%-%ds " % max(len(n) for n in names)
7737 places = [_(b"external"), _(b"internal")]
7688 places = [_(b"external"), _(b"internal")]
7738 for n, v, p in zip(names, vers, isinternals):
7689 for n, v, p in zip(names, vers, isinternals):
7739 fn.startitem()
7690 fn.startitem()
7740 fn.condwrite(ui.verbose, b"name", namefmt, n)
7691 fn.condwrite(ui.verbose, b"name", namefmt, n)
7741 if ui.verbose:
7692 if ui.verbose:
7742 fn.plain(b"%s " % places[p])
7693 fn.plain(b"%s " % places[p])
7743 fn.data(bundled=p)
7694 fn.data(bundled=p)
7744 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7695 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7745 if ui.verbose:
7696 if ui.verbose:
7746 fn.plain(b"\n")
7697 fn.plain(b"\n")
7747 fn.end()
7698 fn.end()
7748 fm.end()
7699 fm.end()
7749
7700
7750
7701
7751 def loadcmdtable(ui, name, cmdtable):
7702 def loadcmdtable(ui, name, cmdtable):
7752 """Load command functions from specified cmdtable"""
7703 """Load command functions from specified cmdtable"""
7753 overrides = [cmd for cmd in cmdtable if cmd in table]
7704 overrides = [cmd for cmd in cmdtable if cmd in table]
7754 if overrides:
7705 if overrides:
7755 ui.warn(
7706 ui.warn(
7756 _(b"extension '%s' overrides commands: %s\n")
7707 _(b"extension '%s' overrides commands: %s\n")
7757 % (name, b" ".join(overrides))
7708 % (name, b" ".join(overrides))
7758 )
7709 )
7759 table.update(cmdtable)
7710 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now