##// END OF EJS Templates
rename: add --forget option and stop suggesting `hg revert` for undoing...
Martin von Zweigbergk -
r47648:37f49d46 default
parent child Browse files
Show More
@@ -1,7937 +1,7944
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 absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 bundlecaches,
29 bundlecaches,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 grep as grepmod,
44 grep as grepmod,
45 hbisect,
45 hbisect,
46 help,
46 help,
47 hg,
47 hg,
48 logcmdutil,
48 logcmdutil,
49 merge as mergemod,
49 merge as mergemod,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 narrowspec,
51 narrowspec,
52 obsolete,
52 obsolete,
53 obsutil,
53 obsutil,
54 patch,
54 patch,
55 phases,
55 phases,
56 pycompat,
56 pycompat,
57 rcutil,
57 rcutil,
58 registrar,
58 registrar,
59 requirements,
59 requirements,
60 revsetlang,
60 revsetlang,
61 rewriteutil,
61 rewriteutil,
62 scmutil,
62 scmutil,
63 server,
63 server,
64 shelve as shelvemod,
64 shelve as shelvemod,
65 state as statemod,
65 state as statemod,
66 streamclone,
66 streamclone,
67 tags as tagsmod,
67 tags as tagsmod,
68 ui as uimod,
68 ui as uimod,
69 util,
69 util,
70 verify as verifymod,
70 verify as verifymod,
71 vfs as vfsmod,
71 vfs as vfsmod,
72 wireprotoserver,
72 wireprotoserver,
73 )
73 )
74 from .utils import (
74 from .utils import (
75 dateutil,
75 dateutil,
76 stringutil,
76 stringutil,
77 )
77 )
78
78
79 if pycompat.TYPE_CHECKING:
79 if pycompat.TYPE_CHECKING:
80 from typing import (
80 from typing import (
81 List,
81 List,
82 )
82 )
83
83
84
84
85 table = {}
85 table = {}
86 table.update(debugcommandsmod.command._table)
86 table.update(debugcommandsmod.command._table)
87
87
88 command = registrar.command(table)
88 command = registrar.command(table)
89 INTENT_READONLY = registrar.INTENT_READONLY
89 INTENT_READONLY = registrar.INTENT_READONLY
90
90
91 # common command options
91 # common command options
92
92
93 globalopts = [
93 globalopts = [
94 (
94 (
95 b'R',
95 b'R',
96 b'repository',
96 b'repository',
97 b'',
97 b'',
98 _(b'repository root directory or name of overlay bundle file'),
98 _(b'repository root directory or name of overlay bundle file'),
99 _(b'REPO'),
99 _(b'REPO'),
100 ),
100 ),
101 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
101 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
102 (
102 (
103 b'y',
103 b'y',
104 b'noninteractive',
104 b'noninteractive',
105 None,
105 None,
106 _(
106 _(
107 b'do not prompt, automatically pick the first choice for all prompts'
107 b'do not prompt, automatically pick the first choice for all prompts'
108 ),
108 ),
109 ),
109 ),
110 (b'q', b'quiet', None, _(b'suppress output')),
110 (b'q', b'quiet', None, _(b'suppress output')),
111 (b'v', b'verbose', None, _(b'enable additional output')),
111 (b'v', b'verbose', None, _(b'enable additional output')),
112 (
112 (
113 b'',
113 b'',
114 b'color',
114 b'color',
115 b'',
115 b'',
116 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
116 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
117 # and should not be translated
117 # and should not be translated
118 _(b"when to colorize (boolean, always, auto, never, or debug)"),
118 _(b"when to colorize (boolean, always, auto, never, or debug)"),
119 _(b'TYPE'),
119 _(b'TYPE'),
120 ),
120 ),
121 (
121 (
122 b'',
122 b'',
123 b'config',
123 b'config',
124 [],
124 [],
125 _(b'set/override config option (use \'section.name=value\')'),
125 _(b'set/override config option (use \'section.name=value\')'),
126 _(b'CONFIG'),
126 _(b'CONFIG'),
127 ),
127 ),
128 (b'', b'debug', None, _(b'enable debugging output')),
128 (b'', b'debug', None, _(b'enable debugging output')),
129 (b'', b'debugger', None, _(b'start debugger')),
129 (b'', b'debugger', None, _(b'start debugger')),
130 (
130 (
131 b'',
131 b'',
132 b'encoding',
132 b'encoding',
133 encoding.encoding,
133 encoding.encoding,
134 _(b'set the charset encoding'),
134 _(b'set the charset encoding'),
135 _(b'ENCODE'),
135 _(b'ENCODE'),
136 ),
136 ),
137 (
137 (
138 b'',
138 b'',
139 b'encodingmode',
139 b'encodingmode',
140 encoding.encodingmode,
140 encoding.encodingmode,
141 _(b'set the charset encoding mode'),
141 _(b'set the charset encoding mode'),
142 _(b'MODE'),
142 _(b'MODE'),
143 ),
143 ),
144 (b'', b'traceback', None, _(b'always print a traceback on exception')),
144 (b'', b'traceback', None, _(b'always print a traceback on exception')),
145 (b'', b'time', None, _(b'time how long the command takes')),
145 (b'', b'time', None, _(b'time how long the command takes')),
146 (b'', b'profile', None, _(b'print command execution profile')),
146 (b'', b'profile', None, _(b'print command execution profile')),
147 (b'', b'version', None, _(b'output version information and exit')),
147 (b'', b'version', None, _(b'output version information and exit')),
148 (b'h', b'help', None, _(b'display help and exit')),
148 (b'h', b'help', None, _(b'display help and exit')),
149 (b'', b'hidden', False, _(b'consider hidden changesets')),
149 (b'', b'hidden', False, _(b'consider hidden changesets')),
150 (
150 (
151 b'',
151 b'',
152 b'pager',
152 b'pager',
153 b'auto',
153 b'auto',
154 _(b"when to paginate (boolean, always, auto, or never)"),
154 _(b"when to paginate (boolean, always, auto, or never)"),
155 _(b'TYPE'),
155 _(b'TYPE'),
156 ),
156 ),
157 ]
157 ]
158
158
159 dryrunopts = cmdutil.dryrunopts
159 dryrunopts = cmdutil.dryrunopts
160 remoteopts = cmdutil.remoteopts
160 remoteopts = cmdutil.remoteopts
161 walkopts = cmdutil.walkopts
161 walkopts = cmdutil.walkopts
162 commitopts = cmdutil.commitopts
162 commitopts = cmdutil.commitopts
163 commitopts2 = cmdutil.commitopts2
163 commitopts2 = cmdutil.commitopts2
164 commitopts3 = cmdutil.commitopts3
164 commitopts3 = cmdutil.commitopts3
165 formatteropts = cmdutil.formatteropts
165 formatteropts = cmdutil.formatteropts
166 templateopts = cmdutil.templateopts
166 templateopts = cmdutil.templateopts
167 logopts = cmdutil.logopts
167 logopts = cmdutil.logopts
168 diffopts = cmdutil.diffopts
168 diffopts = cmdutil.diffopts
169 diffwsopts = cmdutil.diffwsopts
169 diffwsopts = cmdutil.diffwsopts
170 diffopts2 = cmdutil.diffopts2
170 diffopts2 = cmdutil.diffopts2
171 mergetoolopts = cmdutil.mergetoolopts
171 mergetoolopts = cmdutil.mergetoolopts
172 similarityopts = cmdutil.similarityopts
172 similarityopts = cmdutil.similarityopts
173 subrepoopts = cmdutil.subrepoopts
173 subrepoopts = cmdutil.subrepoopts
174 debugrevlogopts = cmdutil.debugrevlogopts
174 debugrevlogopts = cmdutil.debugrevlogopts
175
175
176 # Commands start here, listed alphabetically
176 # Commands start here, listed alphabetically
177
177
178
178
179 @command(
179 @command(
180 b'abort',
180 b'abort',
181 dryrunopts,
181 dryrunopts,
182 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
182 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
183 helpbasic=True,
183 helpbasic=True,
184 )
184 )
185 def abort(ui, repo, **opts):
185 def abort(ui, repo, **opts):
186 """abort an unfinished operation (EXPERIMENTAL)
186 """abort an unfinished operation (EXPERIMENTAL)
187
187
188 Aborts a multistep operation like graft, histedit, rebase, merge,
188 Aborts a multistep operation like graft, histedit, rebase, merge,
189 and unshelve if they are in an unfinished state.
189 and unshelve if they are in an unfinished state.
190
190
191 use --dry-run/-n to dry run the command.
191 use --dry-run/-n to dry run the command.
192 """
192 """
193 dryrun = opts.get('dry_run')
193 dryrun = opts.get('dry_run')
194 abortstate = cmdutil.getunfinishedstate(repo)
194 abortstate = cmdutil.getunfinishedstate(repo)
195 if not abortstate:
195 if not abortstate:
196 raise error.StateError(_(b'no operation in progress'))
196 raise error.StateError(_(b'no operation in progress'))
197 if not abortstate.abortfunc:
197 if not abortstate.abortfunc:
198 raise error.InputError(
198 raise error.InputError(
199 (
199 (
200 _(b"%s in progress but does not support 'hg abort'")
200 _(b"%s in progress but does not support 'hg abort'")
201 % (abortstate._opname)
201 % (abortstate._opname)
202 ),
202 ),
203 hint=abortstate.hint(),
203 hint=abortstate.hint(),
204 )
204 )
205 if dryrun:
205 if dryrun:
206 ui.status(
206 ui.status(
207 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
207 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
208 )
208 )
209 return
209 return
210 return abortstate.abortfunc(ui, repo)
210 return abortstate.abortfunc(ui, repo)
211
211
212
212
213 @command(
213 @command(
214 b'add',
214 b'add',
215 walkopts + subrepoopts + dryrunopts,
215 walkopts + subrepoopts + dryrunopts,
216 _(b'[OPTION]... [FILE]...'),
216 _(b'[OPTION]... [FILE]...'),
217 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
217 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
218 helpbasic=True,
218 helpbasic=True,
219 inferrepo=True,
219 inferrepo=True,
220 )
220 )
221 def add(ui, repo, *pats, **opts):
221 def add(ui, repo, *pats, **opts):
222 """add the specified files on the next commit
222 """add the specified files on the next commit
223
223
224 Schedule files to be version controlled and added to the
224 Schedule files to be version controlled and added to the
225 repository.
225 repository.
226
226
227 The files will be added to the repository at the next commit. To
227 The files will be added to the repository at the next commit. To
228 undo an add before that, see :hg:`forget`.
228 undo an add before that, see :hg:`forget`.
229
229
230 If no names are given, add all files to the repository (except
230 If no names are given, add all files to the repository (except
231 files matching ``.hgignore``).
231 files matching ``.hgignore``).
232
232
233 .. container:: verbose
233 .. container:: verbose
234
234
235 Examples:
235 Examples:
236
236
237 - New (unknown) files are added
237 - New (unknown) files are added
238 automatically by :hg:`add`::
238 automatically by :hg:`add`::
239
239
240 $ ls
240 $ ls
241 foo.c
241 foo.c
242 $ hg status
242 $ hg status
243 ? foo.c
243 ? foo.c
244 $ hg add
244 $ hg add
245 adding foo.c
245 adding foo.c
246 $ hg status
246 $ hg status
247 A foo.c
247 A foo.c
248
248
249 - Specific files to be added can be specified::
249 - Specific files to be added can be specified::
250
250
251 $ ls
251 $ ls
252 bar.c foo.c
252 bar.c foo.c
253 $ hg status
253 $ hg status
254 ? bar.c
254 ? bar.c
255 ? foo.c
255 ? foo.c
256 $ hg add bar.c
256 $ hg add bar.c
257 $ hg status
257 $ hg status
258 A bar.c
258 A bar.c
259 ? foo.c
259 ? foo.c
260
260
261 Returns 0 if all files are successfully added.
261 Returns 0 if all files are successfully added.
262 """
262 """
263
263
264 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
264 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
265 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
265 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
266 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
266 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
267 return rejected and 1 or 0
267 return rejected and 1 or 0
268
268
269
269
270 @command(
270 @command(
271 b'addremove',
271 b'addremove',
272 similarityopts + subrepoopts + walkopts + dryrunopts,
272 similarityopts + subrepoopts + walkopts + dryrunopts,
273 _(b'[OPTION]... [FILE]...'),
273 _(b'[OPTION]... [FILE]...'),
274 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
274 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
275 inferrepo=True,
275 inferrepo=True,
276 )
276 )
277 def addremove(ui, repo, *pats, **opts):
277 def addremove(ui, repo, *pats, **opts):
278 """add all new files, delete all missing files
278 """add all new files, delete all missing files
279
279
280 Add all new files and remove all missing files from the
280 Add all new files and remove all missing files from the
281 repository.
281 repository.
282
282
283 Unless names are given, new files are ignored if they match any of
283 Unless names are given, new files are ignored if they match any of
284 the patterns in ``.hgignore``. As with add, these changes take
284 the patterns in ``.hgignore``. As with add, these changes take
285 effect at the next commit.
285 effect at the next commit.
286
286
287 Use the -s/--similarity option to detect renamed files. This
287 Use the -s/--similarity option to detect renamed files. This
288 option takes a percentage between 0 (disabled) and 100 (files must
288 option takes a percentage between 0 (disabled) and 100 (files must
289 be identical) as its parameter. With a parameter greater than 0,
289 be identical) as its parameter. With a parameter greater than 0,
290 this compares every removed file with every added file and records
290 this compares every removed file with every added file and records
291 those similar enough as renames. Detecting renamed files this way
291 those similar enough as renames. Detecting renamed files this way
292 can be expensive. After using this option, :hg:`status -C` can be
292 can be expensive. After using this option, :hg:`status -C` can be
293 used to check which files were identified as moved or renamed. If
293 used to check which files were identified as moved or renamed. If
294 not specified, -s/--similarity defaults to 100 and only renames of
294 not specified, -s/--similarity defaults to 100 and only renames of
295 identical files are detected.
295 identical files are detected.
296
296
297 .. container:: verbose
297 .. container:: verbose
298
298
299 Examples:
299 Examples:
300
300
301 - A number of files (bar.c and foo.c) are new,
301 - A number of files (bar.c and foo.c) are new,
302 while foobar.c has been removed (without using :hg:`remove`)
302 while foobar.c has been removed (without using :hg:`remove`)
303 from the repository::
303 from the repository::
304
304
305 $ ls
305 $ ls
306 bar.c foo.c
306 bar.c foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? bar.c
309 ? bar.c
310 ? foo.c
310 ? foo.c
311 $ hg addremove
311 $ hg addremove
312 adding bar.c
312 adding bar.c
313 adding foo.c
313 adding foo.c
314 removing foobar.c
314 removing foobar.c
315 $ hg status
315 $ hg status
316 A bar.c
316 A bar.c
317 A foo.c
317 A foo.c
318 R foobar.c
318 R foobar.c
319
319
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
321 Afterwards, it was edited slightly::
321 Afterwards, it was edited slightly::
322
322
323 $ ls
323 $ ls
324 foo.c
324 foo.c
325 $ hg status
325 $ hg status
326 ! foobar.c
326 ! foobar.c
327 ? foo.c
327 ? foo.c
328 $ hg addremove --similarity 90
328 $ hg addremove --similarity 90
329 removing foobar.c
329 removing foobar.c
330 adding foo.c
330 adding foo.c
331 recording removal of foobar.c as rename to foo.c (94% similar)
331 recording removal of foobar.c as rename to foo.c (94% similar)
332 $ hg status -C
332 $ hg status -C
333 A foo.c
333 A foo.c
334 foobar.c
334 foobar.c
335 R foobar.c
335 R foobar.c
336
336
337 Returns 0 if all files are successfully added.
337 Returns 0 if all files are successfully added.
338 """
338 """
339 opts = pycompat.byteskwargs(opts)
339 opts = pycompat.byteskwargs(opts)
340 if not opts.get(b'similarity'):
340 if not opts.get(b'similarity'):
341 opts[b'similarity'] = b'100'
341 opts[b'similarity'] = b'100'
342 matcher = scmutil.match(repo[None], pats, opts)
342 matcher = scmutil.match(repo[None], pats, opts)
343 relative = scmutil.anypats(pats, opts)
343 relative = scmutil.anypats(pats, opts)
344 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
344 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
345 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
345 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
346
346
347
347
348 @command(
348 @command(
349 b'annotate|blame',
349 b'annotate|blame',
350 [
350 [
351 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
351 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
352 (
352 (
353 b'',
353 b'',
354 b'follow',
354 b'follow',
355 None,
355 None,
356 _(b'follow copies/renames and list the filename (DEPRECATED)'),
356 _(b'follow copies/renames and list the filename (DEPRECATED)'),
357 ),
357 ),
358 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
358 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
359 (b'a', b'text', None, _(b'treat all files as text')),
359 (b'a', b'text', None, _(b'treat all files as text')),
360 (b'u', b'user', None, _(b'list the author (long with -v)')),
360 (b'u', b'user', None, _(b'list the author (long with -v)')),
361 (b'f', b'file', None, _(b'list the filename')),
361 (b'f', b'file', None, _(b'list the filename')),
362 (b'd', b'date', None, _(b'list the date (short with -q)')),
362 (b'd', b'date', None, _(b'list the date (short with -q)')),
363 (b'n', b'number', None, _(b'list the revision number (default)')),
363 (b'n', b'number', None, _(b'list the revision number (default)')),
364 (b'c', b'changeset', None, _(b'list the changeset')),
364 (b'c', b'changeset', None, _(b'list the changeset')),
365 (
365 (
366 b'l',
366 b'l',
367 b'line-number',
367 b'line-number',
368 None,
368 None,
369 _(b'show line number at the first appearance'),
369 _(b'show line number at the first appearance'),
370 ),
370 ),
371 (
371 (
372 b'',
372 b'',
373 b'skip',
373 b'skip',
374 [],
374 [],
375 _(b'revset to not display (EXPERIMENTAL)'),
375 _(b'revset to not display (EXPERIMENTAL)'),
376 _(b'REV'),
376 _(b'REV'),
377 ),
377 ),
378 ]
378 ]
379 + diffwsopts
379 + diffwsopts
380 + walkopts
380 + walkopts
381 + formatteropts,
381 + formatteropts,
382 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
382 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
383 helpcategory=command.CATEGORY_FILE_CONTENTS,
383 helpcategory=command.CATEGORY_FILE_CONTENTS,
384 helpbasic=True,
384 helpbasic=True,
385 inferrepo=True,
385 inferrepo=True,
386 )
386 )
387 def annotate(ui, repo, *pats, **opts):
387 def annotate(ui, repo, *pats, **opts):
388 """show changeset information by line for each file
388 """show changeset information by line for each file
389
389
390 List changes in files, showing the revision id responsible for
390 List changes in files, showing the revision id responsible for
391 each line.
391 each line.
392
392
393 This command is useful for discovering when a change was made and
393 This command is useful for discovering when a change was made and
394 by whom.
394 by whom.
395
395
396 If you include --file, --user, or --date, the revision number is
396 If you include --file, --user, or --date, the revision number is
397 suppressed unless you also include --number.
397 suppressed unless you also include --number.
398
398
399 Without the -a/--text option, annotate will avoid processing files
399 Without the -a/--text option, annotate will avoid processing files
400 it detects as binary. With -a, annotate will annotate the file
400 it detects as binary. With -a, annotate will annotate the file
401 anyway, although the results will probably be neither useful
401 anyway, although the results will probably be neither useful
402 nor desirable.
402 nor desirable.
403
403
404 .. container:: verbose
404 .. container:: verbose
405
405
406 Template:
406 Template:
407
407
408 The following keywords are supported in addition to the common template
408 The following keywords are supported in addition to the common template
409 keywords and functions. See also :hg:`help templates`.
409 keywords and functions. See also :hg:`help templates`.
410
410
411 :lines: List of lines with annotation data.
411 :lines: List of lines with annotation data.
412 :path: String. Repository-absolute path of the specified file.
412 :path: String. Repository-absolute path of the specified file.
413
413
414 And each entry of ``{lines}`` provides the following sub-keywords in
414 And each entry of ``{lines}`` provides the following sub-keywords in
415 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
415 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
416
416
417 :line: String. Line content.
417 :line: String. Line content.
418 :lineno: Integer. Line number at that revision.
418 :lineno: Integer. Line number at that revision.
419 :path: String. Repository-absolute path of the file at that revision.
419 :path: String. Repository-absolute path of the file at that revision.
420
420
421 See :hg:`help templates.operators` for the list expansion syntax.
421 See :hg:`help templates.operators` for the list expansion syntax.
422
422
423 Returns 0 on success.
423 Returns 0 on success.
424 """
424 """
425 opts = pycompat.byteskwargs(opts)
425 opts = pycompat.byteskwargs(opts)
426 if not pats:
426 if not pats:
427 raise error.InputError(
427 raise error.InputError(
428 _(b'at least one filename or pattern is required')
428 _(b'at least one filename or pattern is required')
429 )
429 )
430
430
431 if opts.get(b'follow'):
431 if opts.get(b'follow'):
432 # --follow is deprecated and now just an alias for -f/--file
432 # --follow is deprecated and now just an alias for -f/--file
433 # to mimic the behavior of Mercurial before version 1.5
433 # to mimic the behavior of Mercurial before version 1.5
434 opts[b'file'] = True
434 opts[b'file'] = True
435
435
436 if (
436 if (
437 not opts.get(b'user')
437 not opts.get(b'user')
438 and not opts.get(b'changeset')
438 and not opts.get(b'changeset')
439 and not opts.get(b'date')
439 and not opts.get(b'date')
440 and not opts.get(b'file')
440 and not opts.get(b'file')
441 ):
441 ):
442 opts[b'number'] = True
442 opts[b'number'] = True
443
443
444 linenumber = opts.get(b'line_number') is not None
444 linenumber = opts.get(b'line_number') is not None
445 if (
445 if (
446 linenumber
446 linenumber
447 and (not opts.get(b'changeset'))
447 and (not opts.get(b'changeset'))
448 and (not opts.get(b'number'))
448 and (not opts.get(b'number'))
449 ):
449 ):
450 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
450 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
451
451
452 rev = opts.get(b'rev')
452 rev = opts.get(b'rev')
453 if rev:
453 if rev:
454 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
454 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
455 ctx = scmutil.revsingle(repo, rev)
455 ctx = scmutil.revsingle(repo, rev)
456
456
457 ui.pager(b'annotate')
457 ui.pager(b'annotate')
458 rootfm = ui.formatter(b'annotate', opts)
458 rootfm = ui.formatter(b'annotate', opts)
459 if ui.debugflag:
459 if ui.debugflag:
460 shorthex = pycompat.identity
460 shorthex = pycompat.identity
461 else:
461 else:
462
462
463 def shorthex(h):
463 def shorthex(h):
464 return h[:12]
464 return h[:12]
465
465
466 if ui.quiet:
466 if ui.quiet:
467 datefunc = dateutil.shortdate
467 datefunc = dateutil.shortdate
468 else:
468 else:
469 datefunc = dateutil.datestr
469 datefunc = dateutil.datestr
470 if ctx.rev() is None:
470 if ctx.rev() is None:
471 if opts.get(b'changeset'):
471 if opts.get(b'changeset'):
472 # omit "+" suffix which is appended to node hex
472 # omit "+" suffix which is appended to node hex
473 def formatrev(rev):
473 def formatrev(rev):
474 if rev == wdirrev:
474 if rev == wdirrev:
475 return b'%d' % ctx.p1().rev()
475 return b'%d' % ctx.p1().rev()
476 else:
476 else:
477 return b'%d' % rev
477 return b'%d' % rev
478
478
479 else:
479 else:
480
480
481 def formatrev(rev):
481 def formatrev(rev):
482 if rev == wdirrev:
482 if rev == wdirrev:
483 return b'%d+' % ctx.p1().rev()
483 return b'%d+' % ctx.p1().rev()
484 else:
484 else:
485 return b'%d ' % rev
485 return b'%d ' % rev
486
486
487 def formathex(h):
487 def formathex(h):
488 if h == wdirhex:
488 if h == wdirhex:
489 return b'%s+' % shorthex(hex(ctx.p1().node()))
489 return b'%s+' % shorthex(hex(ctx.p1().node()))
490 else:
490 else:
491 return b'%s ' % shorthex(h)
491 return b'%s ' % shorthex(h)
492
492
493 else:
493 else:
494 formatrev = b'%d'.__mod__
494 formatrev = b'%d'.__mod__
495 formathex = shorthex
495 formathex = shorthex
496
496
497 opmap = [
497 opmap = [
498 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
498 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
499 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
499 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
500 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
500 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
501 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
501 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
502 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
502 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
503 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
503 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
504 ]
504 ]
505 opnamemap = {
505 opnamemap = {
506 b'rev': b'number',
506 b'rev': b'number',
507 b'node': b'changeset',
507 b'node': b'changeset',
508 b'path': b'file',
508 b'path': b'file',
509 b'lineno': b'line_number',
509 b'lineno': b'line_number',
510 }
510 }
511
511
512 if rootfm.isplain():
512 if rootfm.isplain():
513
513
514 def makefunc(get, fmt):
514 def makefunc(get, fmt):
515 return lambda x: fmt(get(x))
515 return lambda x: fmt(get(x))
516
516
517 else:
517 else:
518
518
519 def makefunc(get, fmt):
519 def makefunc(get, fmt):
520 return get
520 return get
521
521
522 datahint = rootfm.datahint()
522 datahint = rootfm.datahint()
523 funcmap = [
523 funcmap = [
524 (makefunc(get, fmt), sep)
524 (makefunc(get, fmt), sep)
525 for fn, sep, get, fmt in opmap
525 for fn, sep, get, fmt in opmap
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
527 ]
527 ]
528 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
528 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
529 fields = b' '.join(
529 fields = b' '.join(
530 fn
530 fn
531 for fn, sep, get, fmt in opmap
531 for fn, sep, get, fmt in opmap
532 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
532 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
533 )
533 )
534
534
535 def bad(x, y):
535 def bad(x, y):
536 raise error.Abort(b"%s: %s" % (x, y))
536 raise error.Abort(b"%s: %s" % (x, y))
537
537
538 m = scmutil.match(ctx, pats, opts, badfn=bad)
538 m = scmutil.match(ctx, pats, opts, badfn=bad)
539
539
540 follow = not opts.get(b'no_follow')
540 follow = not opts.get(b'no_follow')
541 diffopts = patch.difffeatureopts(
541 diffopts = patch.difffeatureopts(
542 ui, opts, section=b'annotate', whitespace=True
542 ui, opts, section=b'annotate', whitespace=True
543 )
543 )
544 skiprevs = opts.get(b'skip')
544 skiprevs = opts.get(b'skip')
545 if skiprevs:
545 if skiprevs:
546 skiprevs = scmutil.revrange(repo, skiprevs)
546 skiprevs = scmutil.revrange(repo, skiprevs)
547
547
548 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
548 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
549 for abs in ctx.walk(m):
549 for abs in ctx.walk(m):
550 fctx = ctx[abs]
550 fctx = ctx[abs]
551 rootfm.startitem()
551 rootfm.startitem()
552 rootfm.data(path=abs)
552 rootfm.data(path=abs)
553 if not opts.get(b'text') and fctx.isbinary():
553 if not opts.get(b'text') and fctx.isbinary():
554 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
554 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
555 continue
555 continue
556
556
557 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
557 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
558 lines = fctx.annotate(
558 lines = fctx.annotate(
559 follow=follow, skiprevs=skiprevs, diffopts=diffopts
559 follow=follow, skiprevs=skiprevs, diffopts=diffopts
560 )
560 )
561 if not lines:
561 if not lines:
562 fm.end()
562 fm.end()
563 continue
563 continue
564 formats = []
564 formats = []
565 pieces = []
565 pieces = []
566
566
567 for f, sep in funcmap:
567 for f, sep in funcmap:
568 l = [f(n) for n in lines]
568 l = [f(n) for n in lines]
569 if fm.isplain():
569 if fm.isplain():
570 sizes = [encoding.colwidth(x) for x in l]
570 sizes = [encoding.colwidth(x) for x in l]
571 ml = max(sizes)
571 ml = max(sizes)
572 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
572 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
573 else:
573 else:
574 formats.append([b'%s'] * len(l))
574 formats.append([b'%s'] * len(l))
575 pieces.append(l)
575 pieces.append(l)
576
576
577 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
577 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
578 fm.startitem()
578 fm.startitem()
579 fm.context(fctx=n.fctx)
579 fm.context(fctx=n.fctx)
580 fm.write(fields, b"".join(f), *p)
580 fm.write(fields, b"".join(f), *p)
581 if n.skip:
581 if n.skip:
582 fmt = b"* %s"
582 fmt = b"* %s"
583 else:
583 else:
584 fmt = b": %s"
584 fmt = b": %s"
585 fm.write(b'line', fmt, n.text)
585 fm.write(b'line', fmt, n.text)
586
586
587 if not lines[-1].text.endswith(b'\n'):
587 if not lines[-1].text.endswith(b'\n'):
588 fm.plain(b'\n')
588 fm.plain(b'\n')
589 fm.end()
589 fm.end()
590
590
591 rootfm.end()
591 rootfm.end()
592
592
593
593
594 @command(
594 @command(
595 b'archive',
595 b'archive',
596 [
596 [
597 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
597 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
598 (
598 (
599 b'p',
599 b'p',
600 b'prefix',
600 b'prefix',
601 b'',
601 b'',
602 _(b'directory prefix for files in archive'),
602 _(b'directory prefix for files in archive'),
603 _(b'PREFIX'),
603 _(b'PREFIX'),
604 ),
604 ),
605 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
605 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
606 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
606 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
607 ]
607 ]
608 + subrepoopts
608 + subrepoopts
609 + walkopts,
609 + walkopts,
610 _(b'[OPTION]... DEST'),
610 _(b'[OPTION]... DEST'),
611 helpcategory=command.CATEGORY_IMPORT_EXPORT,
611 helpcategory=command.CATEGORY_IMPORT_EXPORT,
612 )
612 )
613 def archive(ui, repo, dest, **opts):
613 def archive(ui, repo, dest, **opts):
614 """create an unversioned archive of a repository revision
614 """create an unversioned archive of a repository revision
615
615
616 By default, the revision used is the parent of the working
616 By default, the revision used is the parent of the working
617 directory; use -r/--rev to specify a different revision.
617 directory; use -r/--rev to specify a different revision.
618
618
619 The archive type is automatically detected based on file
619 The archive type is automatically detected based on file
620 extension (to override, use -t/--type).
620 extension (to override, use -t/--type).
621
621
622 .. container:: verbose
622 .. container:: verbose
623
623
624 Examples:
624 Examples:
625
625
626 - create a zip file containing the 1.0 release::
626 - create a zip file containing the 1.0 release::
627
627
628 hg archive -r 1.0 project-1.0.zip
628 hg archive -r 1.0 project-1.0.zip
629
629
630 - create a tarball excluding .hg files::
630 - create a tarball excluding .hg files::
631
631
632 hg archive project.tar.gz -X ".hg*"
632 hg archive project.tar.gz -X ".hg*"
633
633
634 Valid types are:
634 Valid types are:
635
635
636 :``files``: a directory full of files (default)
636 :``files``: a directory full of files (default)
637 :``tar``: tar archive, uncompressed
637 :``tar``: tar archive, uncompressed
638 :``tbz2``: tar archive, compressed using bzip2
638 :``tbz2``: tar archive, compressed using bzip2
639 :``tgz``: tar archive, compressed using gzip
639 :``tgz``: tar archive, compressed using gzip
640 :``txz``: tar archive, compressed using lzma (only in Python 3)
640 :``txz``: tar archive, compressed using lzma (only in Python 3)
641 :``uzip``: zip archive, uncompressed
641 :``uzip``: zip archive, uncompressed
642 :``zip``: zip archive, compressed using deflate
642 :``zip``: zip archive, compressed using deflate
643
643
644 The exact name of the destination archive or directory is given
644 The exact name of the destination archive or directory is given
645 using a format string; see :hg:`help export` for details.
645 using a format string; see :hg:`help export` for details.
646
646
647 Each member added to an archive file has a directory prefix
647 Each member added to an archive file has a directory prefix
648 prepended. Use -p/--prefix to specify a format string for the
648 prepended. Use -p/--prefix to specify a format string for the
649 prefix. The default is the basename of the archive, with suffixes
649 prefix. The default is the basename of the archive, with suffixes
650 removed.
650 removed.
651
651
652 Returns 0 on success.
652 Returns 0 on success.
653 """
653 """
654
654
655 opts = pycompat.byteskwargs(opts)
655 opts = pycompat.byteskwargs(opts)
656 rev = opts.get(b'rev')
656 rev = opts.get(b'rev')
657 if rev:
657 if rev:
658 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
658 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
659 ctx = scmutil.revsingle(repo, rev)
659 ctx = scmutil.revsingle(repo, rev)
660 if not ctx:
660 if not ctx:
661 raise error.InputError(
661 raise error.InputError(
662 _(b'no working directory: please specify a revision')
662 _(b'no working directory: please specify a revision')
663 )
663 )
664 node = ctx.node()
664 node = ctx.node()
665 dest = cmdutil.makefilename(ctx, dest)
665 dest = cmdutil.makefilename(ctx, dest)
666 if os.path.realpath(dest) == repo.root:
666 if os.path.realpath(dest) == repo.root:
667 raise error.InputError(_(b'repository root cannot be destination'))
667 raise error.InputError(_(b'repository root cannot be destination'))
668
668
669 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
669 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
670 prefix = opts.get(b'prefix')
670 prefix = opts.get(b'prefix')
671
671
672 if dest == b'-':
672 if dest == b'-':
673 if kind == b'files':
673 if kind == b'files':
674 raise error.InputError(_(b'cannot archive plain files to stdout'))
674 raise error.InputError(_(b'cannot archive plain files to stdout'))
675 dest = cmdutil.makefileobj(ctx, dest)
675 dest = cmdutil.makefileobj(ctx, dest)
676 if not prefix:
676 if not prefix:
677 prefix = os.path.basename(repo.root) + b'-%h'
677 prefix = os.path.basename(repo.root) + b'-%h'
678
678
679 prefix = cmdutil.makefilename(ctx, prefix)
679 prefix = cmdutil.makefilename(ctx, prefix)
680 match = scmutil.match(ctx, [], opts)
680 match = scmutil.match(ctx, [], opts)
681 archival.archive(
681 archival.archive(
682 repo,
682 repo,
683 dest,
683 dest,
684 node,
684 node,
685 kind,
685 kind,
686 not opts.get(b'no_decode'),
686 not opts.get(b'no_decode'),
687 match,
687 match,
688 prefix,
688 prefix,
689 subrepos=opts.get(b'subrepos'),
689 subrepos=opts.get(b'subrepos'),
690 )
690 )
691
691
692
692
693 @command(
693 @command(
694 b'backout',
694 b'backout',
695 [
695 [
696 (
696 (
697 b'',
697 b'',
698 b'merge',
698 b'merge',
699 None,
699 None,
700 _(b'merge with old dirstate parent after backout'),
700 _(b'merge with old dirstate parent after backout'),
701 ),
701 ),
702 (
702 (
703 b'',
703 b'',
704 b'commit',
704 b'commit',
705 None,
705 None,
706 _(b'commit if no conflicts were encountered (DEPRECATED)'),
706 _(b'commit if no conflicts were encountered (DEPRECATED)'),
707 ),
707 ),
708 (b'', b'no-commit', None, _(b'do not commit')),
708 (b'', b'no-commit', None, _(b'do not commit')),
709 (
709 (
710 b'',
710 b'',
711 b'parent',
711 b'parent',
712 b'',
712 b'',
713 _(b'parent to choose when backing out merge (DEPRECATED)'),
713 _(b'parent to choose when backing out merge (DEPRECATED)'),
714 _(b'REV'),
714 _(b'REV'),
715 ),
715 ),
716 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
716 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
717 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
717 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
718 ]
718 ]
719 + mergetoolopts
719 + mergetoolopts
720 + walkopts
720 + walkopts
721 + commitopts
721 + commitopts
722 + commitopts2,
722 + commitopts2,
723 _(b'[OPTION]... [-r] REV'),
723 _(b'[OPTION]... [-r] REV'),
724 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
724 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
725 )
725 )
726 def backout(ui, repo, node=None, rev=None, **opts):
726 def backout(ui, repo, node=None, rev=None, **opts):
727 """reverse effect of earlier changeset
727 """reverse effect of earlier changeset
728
728
729 Prepare a new changeset with the effect of REV undone in the
729 Prepare a new changeset with the effect of REV undone in the
730 current working directory. If no conflicts were encountered,
730 current working directory. If no conflicts were encountered,
731 it will be committed immediately.
731 it will be committed immediately.
732
732
733 If REV is the parent of the working directory, then this new changeset
733 If REV is the parent of the working directory, then this new changeset
734 is committed automatically (unless --no-commit is specified).
734 is committed automatically (unless --no-commit is specified).
735
735
736 .. note::
736 .. note::
737
737
738 :hg:`backout` cannot be used to fix either an unwanted or
738 :hg:`backout` cannot be used to fix either an unwanted or
739 incorrect merge.
739 incorrect merge.
740
740
741 .. container:: verbose
741 .. container:: verbose
742
742
743 Examples:
743 Examples:
744
744
745 - Reverse the effect of the parent of the working directory.
745 - Reverse the effect of the parent of the working directory.
746 This backout will be committed immediately::
746 This backout will be committed immediately::
747
747
748 hg backout -r .
748 hg backout -r .
749
749
750 - Reverse the effect of previous bad revision 23::
750 - Reverse the effect of previous bad revision 23::
751
751
752 hg backout -r 23
752 hg backout -r 23
753
753
754 - Reverse the effect of previous bad revision 23 and
754 - Reverse the effect of previous bad revision 23 and
755 leave changes uncommitted::
755 leave changes uncommitted::
756
756
757 hg backout -r 23 --no-commit
757 hg backout -r 23 --no-commit
758 hg commit -m "Backout revision 23"
758 hg commit -m "Backout revision 23"
759
759
760 By default, the pending changeset will have one parent,
760 By default, the pending changeset will have one parent,
761 maintaining a linear history. With --merge, the pending
761 maintaining a linear history. With --merge, the pending
762 changeset will instead have two parents: the old parent of the
762 changeset will instead have two parents: the old parent of the
763 working directory and a new child of REV that simply undoes REV.
763 working directory and a new child of REV that simply undoes REV.
764
764
765 Before version 1.7, the behavior without --merge was equivalent
765 Before version 1.7, the behavior without --merge was equivalent
766 to specifying --merge followed by :hg:`update --clean .` to
766 to specifying --merge followed by :hg:`update --clean .` to
767 cancel the merge and leave the child of REV as a head to be
767 cancel the merge and leave the child of REV as a head to be
768 merged separately.
768 merged separately.
769
769
770 See :hg:`help dates` for a list of formats valid for -d/--date.
770 See :hg:`help dates` for a list of formats valid for -d/--date.
771
771
772 See :hg:`help revert` for a way to restore files to the state
772 See :hg:`help revert` for a way to restore files to the state
773 of another revision.
773 of another revision.
774
774
775 Returns 0 on success, 1 if nothing to backout or there are unresolved
775 Returns 0 on success, 1 if nothing to backout or there are unresolved
776 files.
776 files.
777 """
777 """
778 with repo.wlock(), repo.lock():
778 with repo.wlock(), repo.lock():
779 return _dobackout(ui, repo, node, rev, **opts)
779 return _dobackout(ui, repo, node, rev, **opts)
780
780
781
781
782 def _dobackout(ui, repo, node=None, rev=None, **opts):
782 def _dobackout(ui, repo, node=None, rev=None, **opts):
783 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
783 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
784 opts = pycompat.byteskwargs(opts)
784 opts = pycompat.byteskwargs(opts)
785
785
786 if rev and node:
786 if rev and node:
787 raise error.InputError(_(b"please specify just one revision"))
787 raise error.InputError(_(b"please specify just one revision"))
788
788
789 if not rev:
789 if not rev:
790 rev = node
790 rev = node
791
791
792 if not rev:
792 if not rev:
793 raise error.InputError(_(b"please specify a revision to backout"))
793 raise error.InputError(_(b"please specify a revision to backout"))
794
794
795 date = opts.get(b'date')
795 date = opts.get(b'date')
796 if date:
796 if date:
797 opts[b'date'] = dateutil.parsedate(date)
797 opts[b'date'] = dateutil.parsedate(date)
798
798
799 cmdutil.checkunfinished(repo)
799 cmdutil.checkunfinished(repo)
800 cmdutil.bailifchanged(repo)
800 cmdutil.bailifchanged(repo)
801 ctx = scmutil.revsingle(repo, rev)
801 ctx = scmutil.revsingle(repo, rev)
802 node = ctx.node()
802 node = ctx.node()
803
803
804 op1, op2 = repo.dirstate.parents()
804 op1, op2 = repo.dirstate.parents()
805 if not repo.changelog.isancestor(node, op1):
805 if not repo.changelog.isancestor(node, op1):
806 raise error.InputError(
806 raise error.InputError(
807 _(b'cannot backout change that is not an ancestor')
807 _(b'cannot backout change that is not an ancestor')
808 )
808 )
809
809
810 p1, p2 = repo.changelog.parents(node)
810 p1, p2 = repo.changelog.parents(node)
811 if p1 == nullid:
811 if p1 == nullid:
812 raise error.InputError(_(b'cannot backout a change with no parents'))
812 raise error.InputError(_(b'cannot backout a change with no parents'))
813 if p2 != nullid:
813 if p2 != nullid:
814 if not opts.get(b'parent'):
814 if not opts.get(b'parent'):
815 raise error.InputError(_(b'cannot backout a merge changeset'))
815 raise error.InputError(_(b'cannot backout a merge changeset'))
816 p = repo.lookup(opts[b'parent'])
816 p = repo.lookup(opts[b'parent'])
817 if p not in (p1, p2):
817 if p not in (p1, p2):
818 raise error.InputError(
818 raise error.InputError(
819 _(b'%s is not a parent of %s') % (short(p), short(node))
819 _(b'%s is not a parent of %s') % (short(p), short(node))
820 )
820 )
821 parent = p
821 parent = p
822 else:
822 else:
823 if opts.get(b'parent'):
823 if opts.get(b'parent'):
824 raise error.InputError(
824 raise error.InputError(
825 _(b'cannot use --parent on non-merge changeset')
825 _(b'cannot use --parent on non-merge changeset')
826 )
826 )
827 parent = p1
827 parent = p1
828
828
829 # the backout should appear on the same branch
829 # the backout should appear on the same branch
830 branch = repo.dirstate.branch()
830 branch = repo.dirstate.branch()
831 bheads = repo.branchheads(branch)
831 bheads = repo.branchheads(branch)
832 rctx = scmutil.revsingle(repo, hex(parent))
832 rctx = scmutil.revsingle(repo, hex(parent))
833 if not opts.get(b'merge') and op1 != node:
833 if not opts.get(b'merge') and op1 != node:
834 with dirstateguard.dirstateguard(repo, b'backout'):
834 with dirstateguard.dirstateguard(repo, b'backout'):
835 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
835 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
836 with ui.configoverride(overrides, b'backout'):
836 with ui.configoverride(overrides, b'backout'):
837 stats = mergemod.back_out(ctx, parent=repo[parent])
837 stats = mergemod.back_out(ctx, parent=repo[parent])
838 repo.setparents(op1, op2)
838 repo.setparents(op1, op2)
839 hg._showstats(repo, stats)
839 hg._showstats(repo, stats)
840 if stats.unresolvedcount:
840 if stats.unresolvedcount:
841 repo.ui.status(
841 repo.ui.status(
842 _(b"use 'hg resolve' to retry unresolved file merges\n")
842 _(b"use 'hg resolve' to retry unresolved file merges\n")
843 )
843 )
844 return 1
844 return 1
845 else:
845 else:
846 hg.clean(repo, node, show_stats=False)
846 hg.clean(repo, node, show_stats=False)
847 repo.dirstate.setbranch(branch)
847 repo.dirstate.setbranch(branch)
848 cmdutil.revert(ui, repo, rctx)
848 cmdutil.revert(ui, repo, rctx)
849
849
850 if opts.get(b'no_commit'):
850 if opts.get(b'no_commit'):
851 msg = _(b"changeset %s backed out, don't forget to commit.\n")
851 msg = _(b"changeset %s backed out, don't forget to commit.\n")
852 ui.status(msg % short(node))
852 ui.status(msg % short(node))
853 return 0
853 return 0
854
854
855 def commitfunc(ui, repo, message, match, opts):
855 def commitfunc(ui, repo, message, match, opts):
856 editform = b'backout'
856 editform = b'backout'
857 e = cmdutil.getcommiteditor(
857 e = cmdutil.getcommiteditor(
858 editform=editform, **pycompat.strkwargs(opts)
858 editform=editform, **pycompat.strkwargs(opts)
859 )
859 )
860 if not message:
860 if not message:
861 # we don't translate commit messages
861 # we don't translate commit messages
862 message = b"Backed out changeset %s" % short(node)
862 message = b"Backed out changeset %s" % short(node)
863 e = cmdutil.getcommiteditor(edit=True, editform=editform)
863 e = cmdutil.getcommiteditor(edit=True, editform=editform)
864 return repo.commit(
864 return repo.commit(
865 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
865 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
866 )
866 )
867
867
868 # save to detect changes
868 # save to detect changes
869 tip = repo.changelog.tip()
869 tip = repo.changelog.tip()
870
870
871 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
871 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
872 if not newnode:
872 if not newnode:
873 ui.status(_(b"nothing changed\n"))
873 ui.status(_(b"nothing changed\n"))
874 return 1
874 return 1
875 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
875 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
876
876
877 def nice(node):
877 def nice(node):
878 return b'%d:%s' % (repo.changelog.rev(node), short(node))
878 return b'%d:%s' % (repo.changelog.rev(node), short(node))
879
879
880 ui.status(
880 ui.status(
881 _(b'changeset %s backs out changeset %s\n')
881 _(b'changeset %s backs out changeset %s\n')
882 % (nice(newnode), nice(node))
882 % (nice(newnode), nice(node))
883 )
883 )
884 if opts.get(b'merge') and op1 != node:
884 if opts.get(b'merge') and op1 != node:
885 hg.clean(repo, op1, show_stats=False)
885 hg.clean(repo, op1, show_stats=False)
886 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
886 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
887 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
887 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
888 with ui.configoverride(overrides, b'backout'):
888 with ui.configoverride(overrides, b'backout'):
889 return hg.merge(repo[b'tip'])
889 return hg.merge(repo[b'tip'])
890 return 0
890 return 0
891
891
892
892
893 @command(
893 @command(
894 b'bisect',
894 b'bisect',
895 [
895 [
896 (b'r', b'reset', False, _(b'reset bisect state')),
896 (b'r', b'reset', False, _(b'reset bisect state')),
897 (b'g', b'good', False, _(b'mark changeset good')),
897 (b'g', b'good', False, _(b'mark changeset good')),
898 (b'b', b'bad', False, _(b'mark changeset bad')),
898 (b'b', b'bad', False, _(b'mark changeset bad')),
899 (b's', b'skip', False, _(b'skip testing changeset')),
899 (b's', b'skip', False, _(b'skip testing changeset')),
900 (b'e', b'extend', False, _(b'extend the bisect range')),
900 (b'e', b'extend', False, _(b'extend the bisect range')),
901 (
901 (
902 b'c',
902 b'c',
903 b'command',
903 b'command',
904 b'',
904 b'',
905 _(b'use command to check changeset state'),
905 _(b'use command to check changeset state'),
906 _(b'CMD'),
906 _(b'CMD'),
907 ),
907 ),
908 (b'U', b'noupdate', False, _(b'do not update to target')),
908 (b'U', b'noupdate', False, _(b'do not update to target')),
909 ],
909 ],
910 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
910 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
911 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
911 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
912 )
912 )
913 def bisect(
913 def bisect(
914 ui,
914 ui,
915 repo,
915 repo,
916 positional_1=None,
916 positional_1=None,
917 positional_2=None,
917 positional_2=None,
918 command=None,
918 command=None,
919 reset=None,
919 reset=None,
920 good=None,
920 good=None,
921 bad=None,
921 bad=None,
922 skip=None,
922 skip=None,
923 extend=None,
923 extend=None,
924 noupdate=None,
924 noupdate=None,
925 ):
925 ):
926 """subdivision search of changesets
926 """subdivision search of changesets
927
927
928 This command helps to find changesets which introduce problems. To
928 This command helps to find changesets which introduce problems. To
929 use, mark the earliest changeset you know exhibits the problem as
929 use, mark the earliest changeset you know exhibits the problem as
930 bad, then mark the latest changeset which is free from the problem
930 bad, then mark the latest changeset which is free from the problem
931 as good. Bisect will update your working directory to a revision
931 as good. Bisect will update your working directory to a revision
932 for testing (unless the -U/--noupdate option is specified). Once
932 for testing (unless the -U/--noupdate option is specified). Once
933 you have performed tests, mark the working directory as good or
933 you have performed tests, mark the working directory as good or
934 bad, and bisect will either update to another candidate changeset
934 bad, and bisect will either update to another candidate changeset
935 or announce that it has found the bad revision.
935 or announce that it has found the bad revision.
936
936
937 As a shortcut, you can also use the revision argument to mark a
937 As a shortcut, you can also use the revision argument to mark a
938 revision as good or bad without checking it out first.
938 revision as good or bad without checking it out first.
939
939
940 If you supply a command, it will be used for automatic bisection.
940 If you supply a command, it will be used for automatic bisection.
941 The environment variable HG_NODE will contain the ID of the
941 The environment variable HG_NODE will contain the ID of the
942 changeset being tested. The exit status of the command will be
942 changeset being tested. The exit status of the command will be
943 used to mark revisions as good or bad: status 0 means good, 125
943 used to mark revisions as good or bad: status 0 means good, 125
944 means to skip the revision, 127 (command not found) will abort the
944 means to skip the revision, 127 (command not found) will abort the
945 bisection, and any other non-zero exit status means the revision
945 bisection, and any other non-zero exit status means the revision
946 is bad.
946 is bad.
947
947
948 .. container:: verbose
948 .. container:: verbose
949
949
950 Some examples:
950 Some examples:
951
951
952 - start a bisection with known bad revision 34, and good revision 12::
952 - start a bisection with known bad revision 34, and good revision 12::
953
953
954 hg bisect --bad 34
954 hg bisect --bad 34
955 hg bisect --good 12
955 hg bisect --good 12
956
956
957 - advance the current bisection by marking current revision as good or
957 - advance the current bisection by marking current revision as good or
958 bad::
958 bad::
959
959
960 hg bisect --good
960 hg bisect --good
961 hg bisect --bad
961 hg bisect --bad
962
962
963 - mark the current revision, or a known revision, to be skipped (e.g. if
963 - mark the current revision, or a known revision, to be skipped (e.g. if
964 that revision is not usable because of another issue)::
964 that revision is not usable because of another issue)::
965
965
966 hg bisect --skip
966 hg bisect --skip
967 hg bisect --skip 23
967 hg bisect --skip 23
968
968
969 - skip all revisions that do not touch directories ``foo`` or ``bar``::
969 - skip all revisions that do not touch directories ``foo`` or ``bar``::
970
970
971 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
971 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
972
972
973 - forget the current bisection::
973 - forget the current bisection::
974
974
975 hg bisect --reset
975 hg bisect --reset
976
976
977 - use 'make && make tests' to automatically find the first broken
977 - use 'make && make tests' to automatically find the first broken
978 revision::
978 revision::
979
979
980 hg bisect --reset
980 hg bisect --reset
981 hg bisect --bad 34
981 hg bisect --bad 34
982 hg bisect --good 12
982 hg bisect --good 12
983 hg bisect --command "make && make tests"
983 hg bisect --command "make && make tests"
984
984
985 - see all changesets whose states are already known in the current
985 - see all changesets whose states are already known in the current
986 bisection::
986 bisection::
987
987
988 hg log -r "bisect(pruned)"
988 hg log -r "bisect(pruned)"
989
989
990 - see the changeset currently being bisected (especially useful
990 - see the changeset currently being bisected (especially useful
991 if running with -U/--noupdate)::
991 if running with -U/--noupdate)::
992
992
993 hg log -r "bisect(current)"
993 hg log -r "bisect(current)"
994
994
995 - see all changesets that took part in the current bisection::
995 - see all changesets that took part in the current bisection::
996
996
997 hg log -r "bisect(range)"
997 hg log -r "bisect(range)"
998
998
999 - you can even get a nice graph::
999 - you can even get a nice graph::
1000
1000
1001 hg log --graph -r "bisect(range)"
1001 hg log --graph -r "bisect(range)"
1002
1002
1003 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1003 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
1004
1004
1005 Returns 0 on success.
1005 Returns 0 on success.
1006 """
1006 """
1007 rev = []
1007 rev = []
1008 # backward compatibility
1008 # backward compatibility
1009 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1009 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1010 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1010 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1011 cmd = positional_1
1011 cmd = positional_1
1012 rev.append(positional_2)
1012 rev.append(positional_2)
1013 if cmd == b"good":
1013 if cmd == b"good":
1014 good = True
1014 good = True
1015 elif cmd == b"bad":
1015 elif cmd == b"bad":
1016 bad = True
1016 bad = True
1017 else:
1017 else:
1018 reset = True
1018 reset = True
1019 elif positional_2:
1019 elif positional_2:
1020 raise error.InputError(_(b'incompatible arguments'))
1020 raise error.InputError(_(b'incompatible arguments'))
1021 elif positional_1 is not None:
1021 elif positional_1 is not None:
1022 rev.append(positional_1)
1022 rev.append(positional_1)
1023
1023
1024 incompatibles = {
1024 incompatibles = {
1025 b'--bad': bad,
1025 b'--bad': bad,
1026 b'--command': bool(command),
1026 b'--command': bool(command),
1027 b'--extend': extend,
1027 b'--extend': extend,
1028 b'--good': good,
1028 b'--good': good,
1029 b'--reset': reset,
1029 b'--reset': reset,
1030 b'--skip': skip,
1030 b'--skip': skip,
1031 }
1031 }
1032
1032
1033 enabled = [x for x in incompatibles if incompatibles[x]]
1033 enabled = [x for x in incompatibles if incompatibles[x]]
1034
1034
1035 if len(enabled) > 1:
1035 if len(enabled) > 1:
1036 raise error.InputError(
1036 raise error.InputError(
1037 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1037 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1038 )
1038 )
1039
1039
1040 if reset:
1040 if reset:
1041 hbisect.resetstate(repo)
1041 hbisect.resetstate(repo)
1042 return
1042 return
1043
1043
1044 state = hbisect.load_state(repo)
1044 state = hbisect.load_state(repo)
1045
1045
1046 if rev:
1046 if rev:
1047 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1047 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1048 else:
1048 else:
1049 nodes = [repo.lookup(b'.')]
1049 nodes = [repo.lookup(b'.')]
1050
1050
1051 # update state
1051 # update state
1052 if good or bad or skip:
1052 if good or bad or skip:
1053 if good:
1053 if good:
1054 state[b'good'] += nodes
1054 state[b'good'] += nodes
1055 elif bad:
1055 elif bad:
1056 state[b'bad'] += nodes
1056 state[b'bad'] += nodes
1057 elif skip:
1057 elif skip:
1058 state[b'skip'] += nodes
1058 state[b'skip'] += nodes
1059 hbisect.save_state(repo, state)
1059 hbisect.save_state(repo, state)
1060 if not (state[b'good'] and state[b'bad']):
1060 if not (state[b'good'] and state[b'bad']):
1061 return
1061 return
1062
1062
1063 def mayupdate(repo, node, show_stats=True):
1063 def mayupdate(repo, node, show_stats=True):
1064 """common used update sequence"""
1064 """common used update sequence"""
1065 if noupdate:
1065 if noupdate:
1066 return
1066 return
1067 cmdutil.checkunfinished(repo)
1067 cmdutil.checkunfinished(repo)
1068 cmdutil.bailifchanged(repo)
1068 cmdutil.bailifchanged(repo)
1069 return hg.clean(repo, node, show_stats=show_stats)
1069 return hg.clean(repo, node, show_stats=show_stats)
1070
1070
1071 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1071 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1072
1072
1073 if command:
1073 if command:
1074 changesets = 1
1074 changesets = 1
1075 if noupdate:
1075 if noupdate:
1076 try:
1076 try:
1077 node = state[b'current'][0]
1077 node = state[b'current'][0]
1078 except LookupError:
1078 except LookupError:
1079 raise error.StateError(
1079 raise error.StateError(
1080 _(
1080 _(
1081 b'current bisect revision is unknown - '
1081 b'current bisect revision is unknown - '
1082 b'start a new bisect to fix'
1082 b'start a new bisect to fix'
1083 )
1083 )
1084 )
1084 )
1085 else:
1085 else:
1086 node, p2 = repo.dirstate.parents()
1086 node, p2 = repo.dirstate.parents()
1087 if p2 != nullid:
1087 if p2 != nullid:
1088 raise error.StateError(_(b'current bisect revision is a merge'))
1088 raise error.StateError(_(b'current bisect revision is a merge'))
1089 if rev:
1089 if rev:
1090 if not nodes:
1090 if not nodes:
1091 raise error.Abort(_(b'empty revision set'))
1091 raise error.Abort(_(b'empty revision set'))
1092 node = repo[nodes[-1]].node()
1092 node = repo[nodes[-1]].node()
1093 with hbisect.restore_state(repo, state, node):
1093 with hbisect.restore_state(repo, state, node):
1094 while changesets:
1094 while changesets:
1095 # update state
1095 # update state
1096 state[b'current'] = [node]
1096 state[b'current'] = [node]
1097 hbisect.save_state(repo, state)
1097 hbisect.save_state(repo, state)
1098 status = ui.system(
1098 status = ui.system(
1099 command,
1099 command,
1100 environ={b'HG_NODE': hex(node)},
1100 environ={b'HG_NODE': hex(node)},
1101 blockedtag=b'bisect_check',
1101 blockedtag=b'bisect_check',
1102 )
1102 )
1103 if status == 125:
1103 if status == 125:
1104 transition = b"skip"
1104 transition = b"skip"
1105 elif status == 0:
1105 elif status == 0:
1106 transition = b"good"
1106 transition = b"good"
1107 # status < 0 means process was killed
1107 # status < 0 means process was killed
1108 elif status == 127:
1108 elif status == 127:
1109 raise error.Abort(_(b"failed to execute %s") % command)
1109 raise error.Abort(_(b"failed to execute %s") % command)
1110 elif status < 0:
1110 elif status < 0:
1111 raise error.Abort(_(b"%s killed") % command)
1111 raise error.Abort(_(b"%s killed") % command)
1112 else:
1112 else:
1113 transition = b"bad"
1113 transition = b"bad"
1114 state[transition].append(node)
1114 state[transition].append(node)
1115 ctx = repo[node]
1115 ctx = repo[node]
1116 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1116 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1117 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1117 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1118 hbisect.checkstate(state)
1118 hbisect.checkstate(state)
1119 # bisect
1119 # bisect
1120 nodes, changesets, bgood = hbisect.bisect(repo, state)
1120 nodes, changesets, bgood = hbisect.bisect(repo, state)
1121 # update to next check
1121 # update to next check
1122 node = nodes[0]
1122 node = nodes[0]
1123 mayupdate(repo, node, show_stats=False)
1123 mayupdate(repo, node, show_stats=False)
1124 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1124 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1125 return
1125 return
1126
1126
1127 hbisect.checkstate(state)
1127 hbisect.checkstate(state)
1128
1128
1129 # actually bisect
1129 # actually bisect
1130 nodes, changesets, good = hbisect.bisect(repo, state)
1130 nodes, changesets, good = hbisect.bisect(repo, state)
1131 if extend:
1131 if extend:
1132 if not changesets:
1132 if not changesets:
1133 extendctx = hbisect.extendrange(repo, state, nodes, good)
1133 extendctx = hbisect.extendrange(repo, state, nodes, good)
1134 if extendctx is not None:
1134 if extendctx is not None:
1135 ui.write(
1135 ui.write(
1136 _(b"Extending search to changeset %s\n")
1136 _(b"Extending search to changeset %s\n")
1137 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1137 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1138 )
1138 )
1139 state[b'current'] = [extendctx.node()]
1139 state[b'current'] = [extendctx.node()]
1140 hbisect.save_state(repo, state)
1140 hbisect.save_state(repo, state)
1141 return mayupdate(repo, extendctx.node())
1141 return mayupdate(repo, extendctx.node())
1142 raise error.StateError(_(b"nothing to extend"))
1142 raise error.StateError(_(b"nothing to extend"))
1143
1143
1144 if changesets == 0:
1144 if changesets == 0:
1145 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1145 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1146 else:
1146 else:
1147 assert len(nodes) == 1 # only a single node can be tested next
1147 assert len(nodes) == 1 # only a single node can be tested next
1148 node = nodes[0]
1148 node = nodes[0]
1149 # compute the approximate number of remaining tests
1149 # compute the approximate number of remaining tests
1150 tests, size = 0, 2
1150 tests, size = 0, 2
1151 while size <= changesets:
1151 while size <= changesets:
1152 tests, size = tests + 1, size * 2
1152 tests, size = tests + 1, size * 2
1153 rev = repo.changelog.rev(node)
1153 rev = repo.changelog.rev(node)
1154 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1154 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1155 ui.write(
1155 ui.write(
1156 _(
1156 _(
1157 b"Testing changeset %s "
1157 b"Testing changeset %s "
1158 b"(%d changesets remaining, ~%d tests)\n"
1158 b"(%d changesets remaining, ~%d tests)\n"
1159 )
1159 )
1160 % (summary, changesets, tests)
1160 % (summary, changesets, tests)
1161 )
1161 )
1162 state[b'current'] = [node]
1162 state[b'current'] = [node]
1163 hbisect.save_state(repo, state)
1163 hbisect.save_state(repo, state)
1164 return mayupdate(repo, node)
1164 return mayupdate(repo, node)
1165
1165
1166
1166
1167 @command(
1167 @command(
1168 b'bookmarks|bookmark',
1168 b'bookmarks|bookmark',
1169 [
1169 [
1170 (b'f', b'force', False, _(b'force')),
1170 (b'f', b'force', False, _(b'force')),
1171 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1171 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1172 (b'd', b'delete', False, _(b'delete a given bookmark')),
1172 (b'd', b'delete', False, _(b'delete a given bookmark')),
1173 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1173 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1174 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1174 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1175 (b'l', b'list', False, _(b'list existing bookmarks')),
1175 (b'l', b'list', False, _(b'list existing bookmarks')),
1176 ]
1176 ]
1177 + formatteropts,
1177 + formatteropts,
1178 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1178 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1179 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1179 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1180 )
1180 )
1181 def bookmark(ui, repo, *names, **opts):
1181 def bookmark(ui, repo, *names, **opts):
1182 """create a new bookmark or list existing bookmarks
1182 """create a new bookmark or list existing bookmarks
1183
1183
1184 Bookmarks are labels on changesets to help track lines of development.
1184 Bookmarks are labels on changesets to help track lines of development.
1185 Bookmarks are unversioned and can be moved, renamed and deleted.
1185 Bookmarks are unversioned and can be moved, renamed and deleted.
1186 Deleting or moving a bookmark has no effect on the associated changesets.
1186 Deleting or moving a bookmark has no effect on the associated changesets.
1187
1187
1188 Creating or updating to a bookmark causes it to be marked as 'active'.
1188 Creating or updating to a bookmark causes it to be marked as 'active'.
1189 The active bookmark is indicated with a '*'.
1189 The active bookmark is indicated with a '*'.
1190 When a commit is made, the active bookmark will advance to the new commit.
1190 When a commit is made, the active bookmark will advance to the new commit.
1191 A plain :hg:`update` will also advance an active bookmark, if possible.
1191 A plain :hg:`update` will also advance an active bookmark, if possible.
1192 Updating away from a bookmark will cause it to be deactivated.
1192 Updating away from a bookmark will cause it to be deactivated.
1193
1193
1194 Bookmarks can be pushed and pulled between repositories (see
1194 Bookmarks can be pushed and pulled between repositories (see
1195 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1195 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1196 diverged, a new 'divergent bookmark' of the form 'name@path' will
1196 diverged, a new 'divergent bookmark' of the form 'name@path' will
1197 be created. Using :hg:`merge` will resolve the divergence.
1197 be created. Using :hg:`merge` will resolve the divergence.
1198
1198
1199 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1199 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1200 the active bookmark's name.
1200 the active bookmark's name.
1201
1201
1202 A bookmark named '@' has the special property that :hg:`clone` will
1202 A bookmark named '@' has the special property that :hg:`clone` will
1203 check it out by default if it exists.
1203 check it out by default if it exists.
1204
1204
1205 .. container:: verbose
1205 .. container:: verbose
1206
1206
1207 Template:
1207 Template:
1208
1208
1209 The following keywords are supported in addition to the common template
1209 The following keywords are supported in addition to the common template
1210 keywords and functions such as ``{bookmark}``. See also
1210 keywords and functions such as ``{bookmark}``. See also
1211 :hg:`help templates`.
1211 :hg:`help templates`.
1212
1212
1213 :active: Boolean. True if the bookmark is active.
1213 :active: Boolean. True if the bookmark is active.
1214
1214
1215 Examples:
1215 Examples:
1216
1216
1217 - create an active bookmark for a new line of development::
1217 - create an active bookmark for a new line of development::
1218
1218
1219 hg book new-feature
1219 hg book new-feature
1220
1220
1221 - create an inactive bookmark as a place marker::
1221 - create an inactive bookmark as a place marker::
1222
1222
1223 hg book -i reviewed
1223 hg book -i reviewed
1224
1224
1225 - create an inactive bookmark on another changeset::
1225 - create an inactive bookmark on another changeset::
1226
1226
1227 hg book -r .^ tested
1227 hg book -r .^ tested
1228
1228
1229 - rename bookmark turkey to dinner::
1229 - rename bookmark turkey to dinner::
1230
1230
1231 hg book -m turkey dinner
1231 hg book -m turkey dinner
1232
1232
1233 - move the '@' bookmark from another branch::
1233 - move the '@' bookmark from another branch::
1234
1234
1235 hg book -f @
1235 hg book -f @
1236
1236
1237 - print only the active bookmark name::
1237 - print only the active bookmark name::
1238
1238
1239 hg book -ql .
1239 hg book -ql .
1240 """
1240 """
1241 opts = pycompat.byteskwargs(opts)
1241 opts = pycompat.byteskwargs(opts)
1242 force = opts.get(b'force')
1242 force = opts.get(b'force')
1243 rev = opts.get(b'rev')
1243 rev = opts.get(b'rev')
1244 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1244 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1245
1245
1246 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1246 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1247 if action:
1247 if action:
1248 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1248 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1249 elif names or rev:
1249 elif names or rev:
1250 action = b'add'
1250 action = b'add'
1251 elif inactive:
1251 elif inactive:
1252 action = b'inactive' # meaning deactivate
1252 action = b'inactive' # meaning deactivate
1253 else:
1253 else:
1254 action = b'list'
1254 action = b'list'
1255
1255
1256 cmdutil.check_incompatible_arguments(
1256 cmdutil.check_incompatible_arguments(
1257 opts, b'inactive', [b'delete', b'list']
1257 opts, b'inactive', [b'delete', b'list']
1258 )
1258 )
1259 if not names and action in {b'add', b'delete'}:
1259 if not names and action in {b'add', b'delete'}:
1260 raise error.InputError(_(b"bookmark name required"))
1260 raise error.InputError(_(b"bookmark name required"))
1261
1261
1262 if action in {b'add', b'delete', b'rename', b'inactive'}:
1262 if action in {b'add', b'delete', b'rename', b'inactive'}:
1263 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1263 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1264 if action == b'delete':
1264 if action == b'delete':
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1266 bookmarks.delete(repo, tr, names)
1266 bookmarks.delete(repo, tr, names)
1267 elif action == b'rename':
1267 elif action == b'rename':
1268 if not names:
1268 if not names:
1269 raise error.InputError(_(b"new bookmark name required"))
1269 raise error.InputError(_(b"new bookmark name required"))
1270 elif len(names) > 1:
1270 elif len(names) > 1:
1271 raise error.InputError(
1271 raise error.InputError(
1272 _(b"only one new bookmark name allowed")
1272 _(b"only one new bookmark name allowed")
1273 )
1273 )
1274 oldname = repo._bookmarks.expandname(opts[b'rename'])
1274 oldname = repo._bookmarks.expandname(opts[b'rename'])
1275 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1275 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1276 elif action == b'add':
1276 elif action == b'add':
1277 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1277 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1278 elif action == b'inactive':
1278 elif action == b'inactive':
1279 if len(repo._bookmarks) == 0:
1279 if len(repo._bookmarks) == 0:
1280 ui.status(_(b"no bookmarks set\n"))
1280 ui.status(_(b"no bookmarks set\n"))
1281 elif not repo._activebookmark:
1281 elif not repo._activebookmark:
1282 ui.status(_(b"no active bookmark\n"))
1282 ui.status(_(b"no active bookmark\n"))
1283 else:
1283 else:
1284 bookmarks.deactivate(repo)
1284 bookmarks.deactivate(repo)
1285 elif action == b'list':
1285 elif action == b'list':
1286 names = pycompat.maplist(repo._bookmarks.expandname, names)
1286 names = pycompat.maplist(repo._bookmarks.expandname, names)
1287 with ui.formatter(b'bookmarks', opts) as fm:
1287 with ui.formatter(b'bookmarks', opts) as fm:
1288 bookmarks.printbookmarks(ui, repo, fm, names)
1288 bookmarks.printbookmarks(ui, repo, fm, names)
1289 else:
1289 else:
1290 raise error.ProgrammingError(b'invalid action: %s' % action)
1290 raise error.ProgrammingError(b'invalid action: %s' % action)
1291
1291
1292
1292
1293 @command(
1293 @command(
1294 b'branch',
1294 b'branch',
1295 [
1295 [
1296 (
1296 (
1297 b'f',
1297 b'f',
1298 b'force',
1298 b'force',
1299 None,
1299 None,
1300 _(b'set branch name even if it shadows an existing branch'),
1300 _(b'set branch name even if it shadows an existing branch'),
1301 ),
1301 ),
1302 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1302 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1303 (
1303 (
1304 b'r',
1304 b'r',
1305 b'rev',
1305 b'rev',
1306 [],
1306 [],
1307 _(b'change branches of the given revs (EXPERIMENTAL)'),
1307 _(b'change branches of the given revs (EXPERIMENTAL)'),
1308 ),
1308 ),
1309 ],
1309 ],
1310 _(b'[-fC] [NAME]'),
1310 _(b'[-fC] [NAME]'),
1311 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1311 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1312 )
1312 )
1313 def branch(ui, repo, label=None, **opts):
1313 def branch(ui, repo, label=None, **opts):
1314 """set or show the current branch name
1314 """set or show the current branch name
1315
1315
1316 .. note::
1316 .. note::
1317
1317
1318 Branch names are permanent and global. Use :hg:`bookmark` to create a
1318 Branch names are permanent and global. Use :hg:`bookmark` to create a
1319 light-weight bookmark instead. See :hg:`help glossary` for more
1319 light-weight bookmark instead. See :hg:`help glossary` for more
1320 information about named branches and bookmarks.
1320 information about named branches and bookmarks.
1321
1321
1322 With no argument, show the current branch name. With one argument,
1322 With no argument, show the current branch name. With one argument,
1323 set the working directory branch name (the branch will not exist
1323 set the working directory branch name (the branch will not exist
1324 in the repository until the next commit). Standard practice
1324 in the repository until the next commit). Standard practice
1325 recommends that primary development take place on the 'default'
1325 recommends that primary development take place on the 'default'
1326 branch.
1326 branch.
1327
1327
1328 Unless -f/--force is specified, branch will not let you set a
1328 Unless -f/--force is specified, branch will not let you set a
1329 branch name that already exists.
1329 branch name that already exists.
1330
1330
1331 Use -C/--clean to reset the working directory branch to that of
1331 Use -C/--clean to reset the working directory branch to that of
1332 the parent of the working directory, negating a previous branch
1332 the parent of the working directory, negating a previous branch
1333 change.
1333 change.
1334
1334
1335 Use the command :hg:`update` to switch to an existing branch. Use
1335 Use the command :hg:`update` to switch to an existing branch. Use
1336 :hg:`commit --close-branch` to mark this branch head as closed.
1336 :hg:`commit --close-branch` to mark this branch head as closed.
1337 When all heads of a branch are closed, the branch will be
1337 When all heads of a branch are closed, the branch will be
1338 considered closed.
1338 considered closed.
1339
1339
1340 Returns 0 on success.
1340 Returns 0 on success.
1341 """
1341 """
1342 opts = pycompat.byteskwargs(opts)
1342 opts = pycompat.byteskwargs(opts)
1343 revs = opts.get(b'rev')
1343 revs = opts.get(b'rev')
1344 if label:
1344 if label:
1345 label = label.strip()
1345 label = label.strip()
1346
1346
1347 if not opts.get(b'clean') and not label:
1347 if not opts.get(b'clean') and not label:
1348 if revs:
1348 if revs:
1349 raise error.InputError(
1349 raise error.InputError(
1350 _(b"no branch name specified for the revisions")
1350 _(b"no branch name specified for the revisions")
1351 )
1351 )
1352 ui.write(b"%s\n" % repo.dirstate.branch())
1352 ui.write(b"%s\n" % repo.dirstate.branch())
1353 return
1353 return
1354
1354
1355 with repo.wlock():
1355 with repo.wlock():
1356 if opts.get(b'clean'):
1356 if opts.get(b'clean'):
1357 label = repo[b'.'].branch()
1357 label = repo[b'.'].branch()
1358 repo.dirstate.setbranch(label)
1358 repo.dirstate.setbranch(label)
1359 ui.status(_(b'reset working directory to branch %s\n') % label)
1359 ui.status(_(b'reset working directory to branch %s\n') % label)
1360 elif label:
1360 elif label:
1361
1361
1362 scmutil.checknewlabel(repo, label, b'branch')
1362 scmutil.checknewlabel(repo, label, b'branch')
1363 if revs:
1363 if revs:
1364 return cmdutil.changebranch(ui, repo, revs, label, opts)
1364 return cmdutil.changebranch(ui, repo, revs, label, opts)
1365
1365
1366 if not opts.get(b'force') and label in repo.branchmap():
1366 if not opts.get(b'force') and label in repo.branchmap():
1367 if label not in [p.branch() for p in repo[None].parents()]:
1367 if label not in [p.branch() for p in repo[None].parents()]:
1368 raise error.InputError(
1368 raise error.InputError(
1369 _(b'a branch of the same name already exists'),
1369 _(b'a branch of the same name already exists'),
1370 # i18n: "it" refers to an existing branch
1370 # i18n: "it" refers to an existing branch
1371 hint=_(b"use 'hg update' to switch to it"),
1371 hint=_(b"use 'hg update' to switch to it"),
1372 )
1372 )
1373
1373
1374 repo.dirstate.setbranch(label)
1374 repo.dirstate.setbranch(label)
1375 ui.status(_(b'marked working directory as branch %s\n') % label)
1375 ui.status(_(b'marked working directory as branch %s\n') % label)
1376
1376
1377 # find any open named branches aside from default
1377 # find any open named branches aside from default
1378 for n, h, t, c in repo.branchmap().iterbranches():
1378 for n, h, t, c in repo.branchmap().iterbranches():
1379 if n != b"default" and not c:
1379 if n != b"default" and not c:
1380 return 0
1380 return 0
1381 ui.status(
1381 ui.status(
1382 _(
1382 _(
1383 b'(branches are permanent and global, '
1383 b'(branches are permanent and global, '
1384 b'did you want a bookmark?)\n'
1384 b'did you want a bookmark?)\n'
1385 )
1385 )
1386 )
1386 )
1387
1387
1388
1388
1389 @command(
1389 @command(
1390 b'branches',
1390 b'branches',
1391 [
1391 [
1392 (
1392 (
1393 b'a',
1393 b'a',
1394 b'active',
1394 b'active',
1395 False,
1395 False,
1396 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1396 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1397 ),
1397 ),
1398 (b'c', b'closed', False, _(b'show normal and closed branches')),
1398 (b'c', b'closed', False, _(b'show normal and closed branches')),
1399 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1399 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1400 ]
1400 ]
1401 + formatteropts,
1401 + formatteropts,
1402 _(b'[-c]'),
1402 _(b'[-c]'),
1403 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1403 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1404 intents={INTENT_READONLY},
1404 intents={INTENT_READONLY},
1405 )
1405 )
1406 def branches(ui, repo, active=False, closed=False, **opts):
1406 def branches(ui, repo, active=False, closed=False, **opts):
1407 """list repository named branches
1407 """list repository named branches
1408
1408
1409 List the repository's named branches, indicating which ones are
1409 List the repository's named branches, indicating which ones are
1410 inactive. If -c/--closed is specified, also list branches which have
1410 inactive. If -c/--closed is specified, also list branches which have
1411 been marked closed (see :hg:`commit --close-branch`).
1411 been marked closed (see :hg:`commit --close-branch`).
1412
1412
1413 Use the command :hg:`update` to switch to an existing branch.
1413 Use the command :hg:`update` to switch to an existing branch.
1414
1414
1415 .. container:: verbose
1415 .. container:: verbose
1416
1416
1417 Template:
1417 Template:
1418
1418
1419 The following keywords are supported in addition to the common template
1419 The following keywords are supported in addition to the common template
1420 keywords and functions such as ``{branch}``. See also
1420 keywords and functions such as ``{branch}``. See also
1421 :hg:`help templates`.
1421 :hg:`help templates`.
1422
1422
1423 :active: Boolean. True if the branch is active.
1423 :active: Boolean. True if the branch is active.
1424 :closed: Boolean. True if the branch is closed.
1424 :closed: Boolean. True if the branch is closed.
1425 :current: Boolean. True if it is the current branch.
1425 :current: Boolean. True if it is the current branch.
1426
1426
1427 Returns 0.
1427 Returns 0.
1428 """
1428 """
1429
1429
1430 opts = pycompat.byteskwargs(opts)
1430 opts = pycompat.byteskwargs(opts)
1431 revs = opts.get(b'rev')
1431 revs = opts.get(b'rev')
1432 selectedbranches = None
1432 selectedbranches = None
1433 if revs:
1433 if revs:
1434 revs = scmutil.revrange(repo, revs)
1434 revs = scmutil.revrange(repo, revs)
1435 getbi = repo.revbranchcache().branchinfo
1435 getbi = repo.revbranchcache().branchinfo
1436 selectedbranches = {getbi(r)[0] for r in revs}
1436 selectedbranches = {getbi(r)[0] for r in revs}
1437
1437
1438 ui.pager(b'branches')
1438 ui.pager(b'branches')
1439 fm = ui.formatter(b'branches', opts)
1439 fm = ui.formatter(b'branches', opts)
1440 hexfunc = fm.hexfunc
1440 hexfunc = fm.hexfunc
1441
1441
1442 allheads = set(repo.heads())
1442 allheads = set(repo.heads())
1443 branches = []
1443 branches = []
1444 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1444 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1445 if selectedbranches is not None and tag not in selectedbranches:
1445 if selectedbranches is not None and tag not in selectedbranches:
1446 continue
1446 continue
1447 isactive = False
1447 isactive = False
1448 if not isclosed:
1448 if not isclosed:
1449 openheads = set(repo.branchmap().iteropen(heads))
1449 openheads = set(repo.branchmap().iteropen(heads))
1450 isactive = bool(openheads & allheads)
1450 isactive = bool(openheads & allheads)
1451 branches.append((tag, repo[tip], isactive, not isclosed))
1451 branches.append((tag, repo[tip], isactive, not isclosed))
1452 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1452 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1453
1453
1454 for tag, ctx, isactive, isopen in branches:
1454 for tag, ctx, isactive, isopen in branches:
1455 if active and not isactive:
1455 if active and not isactive:
1456 continue
1456 continue
1457 if isactive:
1457 if isactive:
1458 label = b'branches.active'
1458 label = b'branches.active'
1459 notice = b''
1459 notice = b''
1460 elif not isopen:
1460 elif not isopen:
1461 if not closed:
1461 if not closed:
1462 continue
1462 continue
1463 label = b'branches.closed'
1463 label = b'branches.closed'
1464 notice = _(b' (closed)')
1464 notice = _(b' (closed)')
1465 else:
1465 else:
1466 label = b'branches.inactive'
1466 label = b'branches.inactive'
1467 notice = _(b' (inactive)')
1467 notice = _(b' (inactive)')
1468 current = tag == repo.dirstate.branch()
1468 current = tag == repo.dirstate.branch()
1469 if current:
1469 if current:
1470 label = b'branches.current'
1470 label = b'branches.current'
1471
1471
1472 fm.startitem()
1472 fm.startitem()
1473 fm.write(b'branch', b'%s', tag, label=label)
1473 fm.write(b'branch', b'%s', tag, label=label)
1474 rev = ctx.rev()
1474 rev = ctx.rev()
1475 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1475 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1476 fmt = b' ' * padsize + b' %d:%s'
1476 fmt = b' ' * padsize + b' %d:%s'
1477 fm.condwrite(
1477 fm.condwrite(
1478 not ui.quiet,
1478 not ui.quiet,
1479 b'rev node',
1479 b'rev node',
1480 fmt,
1480 fmt,
1481 rev,
1481 rev,
1482 hexfunc(ctx.node()),
1482 hexfunc(ctx.node()),
1483 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1483 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1484 )
1484 )
1485 fm.context(ctx=ctx)
1485 fm.context(ctx=ctx)
1486 fm.data(active=isactive, closed=not isopen, current=current)
1486 fm.data(active=isactive, closed=not isopen, current=current)
1487 if not ui.quiet:
1487 if not ui.quiet:
1488 fm.plain(notice)
1488 fm.plain(notice)
1489 fm.plain(b'\n')
1489 fm.plain(b'\n')
1490 fm.end()
1490 fm.end()
1491
1491
1492
1492
1493 @command(
1493 @command(
1494 b'bundle',
1494 b'bundle',
1495 [
1495 [
1496 (
1496 (
1497 b'f',
1497 b'f',
1498 b'force',
1498 b'force',
1499 None,
1499 None,
1500 _(b'run even when the destination is unrelated'),
1500 _(b'run even when the destination is unrelated'),
1501 ),
1501 ),
1502 (
1502 (
1503 b'r',
1503 b'r',
1504 b'rev',
1504 b'rev',
1505 [],
1505 [],
1506 _(b'a changeset intended to be added to the destination'),
1506 _(b'a changeset intended to be added to the destination'),
1507 _(b'REV'),
1507 _(b'REV'),
1508 ),
1508 ),
1509 (
1509 (
1510 b'b',
1510 b'b',
1511 b'branch',
1511 b'branch',
1512 [],
1512 [],
1513 _(b'a specific branch you would like to bundle'),
1513 _(b'a specific branch you would like to bundle'),
1514 _(b'BRANCH'),
1514 _(b'BRANCH'),
1515 ),
1515 ),
1516 (
1516 (
1517 b'',
1517 b'',
1518 b'base',
1518 b'base',
1519 [],
1519 [],
1520 _(b'a base changeset assumed to be available at the destination'),
1520 _(b'a base changeset assumed to be available at the destination'),
1521 _(b'REV'),
1521 _(b'REV'),
1522 ),
1522 ),
1523 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1523 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1524 (
1524 (
1525 b't',
1525 b't',
1526 b'type',
1526 b'type',
1527 b'bzip2',
1527 b'bzip2',
1528 _(b'bundle compression type to use'),
1528 _(b'bundle compression type to use'),
1529 _(b'TYPE'),
1529 _(b'TYPE'),
1530 ),
1530 ),
1531 ]
1531 ]
1532 + remoteopts,
1532 + remoteopts,
1533 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1533 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1534 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1534 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1535 )
1535 )
1536 def bundle(ui, repo, fname, dest=None, **opts):
1536 def bundle(ui, repo, fname, dest=None, **opts):
1537 """create a bundle file
1537 """create a bundle file
1538
1538
1539 Generate a bundle file containing data to be transferred to another
1539 Generate a bundle file containing data to be transferred to another
1540 repository.
1540 repository.
1541
1541
1542 To create a bundle containing all changesets, use -a/--all
1542 To create a bundle containing all changesets, use -a/--all
1543 (or --base null). Otherwise, hg assumes the destination will have
1543 (or --base null). Otherwise, hg assumes the destination will have
1544 all the nodes you specify with --base parameters. Otherwise, hg
1544 all the nodes you specify with --base parameters. Otherwise, hg
1545 will assume the repository has all the nodes in destination, or
1545 will assume the repository has all the nodes in destination, or
1546 default-push/default if no destination is specified, where destination
1546 default-push/default if no destination is specified, where destination
1547 is the repository you provide through DEST option.
1547 is the repository you provide through DEST option.
1548
1548
1549 You can change bundle format with the -t/--type option. See
1549 You can change bundle format with the -t/--type option. See
1550 :hg:`help bundlespec` for documentation on this format. By default,
1550 :hg:`help bundlespec` for documentation on this format. By default,
1551 the most appropriate format is used and compression defaults to
1551 the most appropriate format is used and compression defaults to
1552 bzip2.
1552 bzip2.
1553
1553
1554 The bundle file can then be transferred using conventional means
1554 The bundle file can then be transferred using conventional means
1555 and applied to another repository with the unbundle or pull
1555 and applied to another repository with the unbundle or pull
1556 command. This is useful when direct push and pull are not
1556 command. This is useful when direct push and pull are not
1557 available or when exporting an entire repository is undesirable.
1557 available or when exporting an entire repository is undesirable.
1558
1558
1559 Applying bundles preserves all changeset contents including
1559 Applying bundles preserves all changeset contents including
1560 permissions, copy/rename information, and revision history.
1560 permissions, copy/rename information, and revision history.
1561
1561
1562 Returns 0 on success, 1 if no changes found.
1562 Returns 0 on success, 1 if no changes found.
1563 """
1563 """
1564 opts = pycompat.byteskwargs(opts)
1564 opts = pycompat.byteskwargs(opts)
1565 revs = None
1565 revs = None
1566 if b'rev' in opts:
1566 if b'rev' in opts:
1567 revstrings = opts[b'rev']
1567 revstrings = opts[b'rev']
1568 revs = scmutil.revrange(repo, revstrings)
1568 revs = scmutil.revrange(repo, revstrings)
1569 if revstrings and not revs:
1569 if revstrings and not revs:
1570 raise error.InputError(_(b'no commits to bundle'))
1570 raise error.InputError(_(b'no commits to bundle'))
1571
1571
1572 bundletype = opts.get(b'type', b'bzip2').lower()
1572 bundletype = opts.get(b'type', b'bzip2').lower()
1573 try:
1573 try:
1574 bundlespec = bundlecaches.parsebundlespec(
1574 bundlespec = bundlecaches.parsebundlespec(
1575 repo, bundletype, strict=False
1575 repo, bundletype, strict=False
1576 )
1576 )
1577 except error.UnsupportedBundleSpecification as e:
1577 except error.UnsupportedBundleSpecification as e:
1578 raise error.InputError(
1578 raise error.InputError(
1579 pycompat.bytestr(e),
1579 pycompat.bytestr(e),
1580 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1580 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1581 )
1581 )
1582 cgversion = bundlespec.contentopts[b"cg.version"]
1582 cgversion = bundlespec.contentopts[b"cg.version"]
1583
1583
1584 # Packed bundles are a pseudo bundle format for now.
1584 # Packed bundles are a pseudo bundle format for now.
1585 if cgversion == b's1':
1585 if cgversion == b's1':
1586 raise error.InputError(
1586 raise error.InputError(
1587 _(b'packed bundles cannot be produced by "hg bundle"'),
1587 _(b'packed bundles cannot be produced by "hg bundle"'),
1588 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1588 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1589 )
1589 )
1590
1590
1591 if opts.get(b'all'):
1591 if opts.get(b'all'):
1592 if dest:
1592 if dest:
1593 raise error.InputError(
1593 raise error.InputError(
1594 _(b"--all is incompatible with specifying a destination")
1594 _(b"--all is incompatible with specifying a destination")
1595 )
1595 )
1596 if opts.get(b'base'):
1596 if opts.get(b'base'):
1597 ui.warn(_(b"ignoring --base because --all was specified\n"))
1597 ui.warn(_(b"ignoring --base because --all was specified\n"))
1598 base = [nullrev]
1598 base = [nullrev]
1599 else:
1599 else:
1600 base = scmutil.revrange(repo, opts.get(b'base'))
1600 base = scmutil.revrange(repo, opts.get(b'base'))
1601 if cgversion not in changegroup.supportedoutgoingversions(repo):
1601 if cgversion not in changegroup.supportedoutgoingversions(repo):
1602 raise error.Abort(
1602 raise error.Abort(
1603 _(b"repository does not support bundle version %s") % cgversion
1603 _(b"repository does not support bundle version %s") % cgversion
1604 )
1604 )
1605
1605
1606 if base:
1606 if base:
1607 if dest:
1607 if dest:
1608 raise error.InputError(
1608 raise error.InputError(
1609 _(b"--base is incompatible with specifying a destination")
1609 _(b"--base is incompatible with specifying a destination")
1610 )
1610 )
1611 common = [repo[rev].node() for rev in base]
1611 common = [repo[rev].node() for rev in base]
1612 heads = [repo[r].node() for r in revs] if revs else None
1612 heads = [repo[r].node() for r in revs] if revs else None
1613 outgoing = discovery.outgoing(repo, common, heads)
1613 outgoing = discovery.outgoing(repo, common, heads)
1614 else:
1614 else:
1615 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1615 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1616 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1616 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1617 other = hg.peer(repo, opts, dest)
1617 other = hg.peer(repo, opts, dest)
1618 revs = [repo[r].hex() for r in revs]
1618 revs = [repo[r].hex() for r in revs]
1619 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1619 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1620 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1620 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1621 outgoing = discovery.findcommonoutgoing(
1621 outgoing = discovery.findcommonoutgoing(
1622 repo,
1622 repo,
1623 other,
1623 other,
1624 onlyheads=heads,
1624 onlyheads=heads,
1625 force=opts.get(b'force'),
1625 force=opts.get(b'force'),
1626 portable=True,
1626 portable=True,
1627 )
1627 )
1628
1628
1629 if not outgoing.missing:
1629 if not outgoing.missing:
1630 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1630 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1631 return 1
1631 return 1
1632
1632
1633 if cgversion == b'01': # bundle1
1633 if cgversion == b'01': # bundle1
1634 bversion = b'HG10' + bundlespec.wirecompression
1634 bversion = b'HG10' + bundlespec.wirecompression
1635 bcompression = None
1635 bcompression = None
1636 elif cgversion in (b'02', b'03'):
1636 elif cgversion in (b'02', b'03'):
1637 bversion = b'HG20'
1637 bversion = b'HG20'
1638 bcompression = bundlespec.wirecompression
1638 bcompression = bundlespec.wirecompression
1639 else:
1639 else:
1640 raise error.ProgrammingError(
1640 raise error.ProgrammingError(
1641 b'bundle: unexpected changegroup version %s' % cgversion
1641 b'bundle: unexpected changegroup version %s' % cgversion
1642 )
1642 )
1643
1643
1644 # TODO compression options should be derived from bundlespec parsing.
1644 # TODO compression options should be derived from bundlespec parsing.
1645 # This is a temporary hack to allow adjusting bundle compression
1645 # This is a temporary hack to allow adjusting bundle compression
1646 # level without a) formalizing the bundlespec changes to declare it
1646 # level without a) formalizing the bundlespec changes to declare it
1647 # b) introducing a command flag.
1647 # b) introducing a command flag.
1648 compopts = {}
1648 compopts = {}
1649 complevel = ui.configint(
1649 complevel = ui.configint(
1650 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1650 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1651 )
1651 )
1652 if complevel is None:
1652 if complevel is None:
1653 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1653 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1654 if complevel is not None:
1654 if complevel is not None:
1655 compopts[b'level'] = complevel
1655 compopts[b'level'] = complevel
1656
1656
1657 compthreads = ui.configint(
1657 compthreads = ui.configint(
1658 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1658 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1659 )
1659 )
1660 if compthreads is None:
1660 if compthreads is None:
1661 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1661 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1662 if compthreads is not None:
1662 if compthreads is not None:
1663 compopts[b'threads'] = compthreads
1663 compopts[b'threads'] = compthreads
1664
1664
1665 # Bundling of obsmarker and phases is optional as not all clients
1665 # Bundling of obsmarker and phases is optional as not all clients
1666 # support the necessary features.
1666 # support the necessary features.
1667 cfg = ui.configbool
1667 cfg = ui.configbool
1668 contentopts = {
1668 contentopts = {
1669 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1669 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1670 b'obsolescence-mandatory': cfg(
1670 b'obsolescence-mandatory': cfg(
1671 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1671 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1672 ),
1672 ),
1673 b'phases': cfg(b'experimental', b'bundle-phases'),
1673 b'phases': cfg(b'experimental', b'bundle-phases'),
1674 }
1674 }
1675 bundlespec.contentopts.update(contentopts)
1675 bundlespec.contentopts.update(contentopts)
1676
1676
1677 bundle2.writenewbundle(
1677 bundle2.writenewbundle(
1678 ui,
1678 ui,
1679 repo,
1679 repo,
1680 b'bundle',
1680 b'bundle',
1681 fname,
1681 fname,
1682 bversion,
1682 bversion,
1683 outgoing,
1683 outgoing,
1684 bundlespec.contentopts,
1684 bundlespec.contentopts,
1685 compression=bcompression,
1685 compression=bcompression,
1686 compopts=compopts,
1686 compopts=compopts,
1687 )
1687 )
1688
1688
1689
1689
1690 @command(
1690 @command(
1691 b'cat',
1691 b'cat',
1692 [
1692 [
1693 (
1693 (
1694 b'o',
1694 b'o',
1695 b'output',
1695 b'output',
1696 b'',
1696 b'',
1697 _(b'print output to file with formatted name'),
1697 _(b'print output to file with formatted name'),
1698 _(b'FORMAT'),
1698 _(b'FORMAT'),
1699 ),
1699 ),
1700 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1700 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1701 (b'', b'decode', None, _(b'apply any matching decode filter')),
1701 (b'', b'decode', None, _(b'apply any matching decode filter')),
1702 ]
1702 ]
1703 + walkopts
1703 + walkopts
1704 + formatteropts,
1704 + formatteropts,
1705 _(b'[OPTION]... FILE...'),
1705 _(b'[OPTION]... FILE...'),
1706 helpcategory=command.CATEGORY_FILE_CONTENTS,
1706 helpcategory=command.CATEGORY_FILE_CONTENTS,
1707 inferrepo=True,
1707 inferrepo=True,
1708 intents={INTENT_READONLY},
1708 intents={INTENT_READONLY},
1709 )
1709 )
1710 def cat(ui, repo, file1, *pats, **opts):
1710 def cat(ui, repo, file1, *pats, **opts):
1711 """output the current or given revision of files
1711 """output the current or given revision of files
1712
1712
1713 Print the specified files as they were at the given revision. If
1713 Print the specified files as they were at the given revision. If
1714 no revision is given, the parent of the working directory is used.
1714 no revision is given, the parent of the working directory is used.
1715
1715
1716 Output may be to a file, in which case the name of the file is
1716 Output may be to a file, in which case the name of the file is
1717 given using a template string. See :hg:`help templates`. In addition
1717 given using a template string. See :hg:`help templates`. In addition
1718 to the common template keywords, the following formatting rules are
1718 to the common template keywords, the following formatting rules are
1719 supported:
1719 supported:
1720
1720
1721 :``%%``: literal "%" character
1721 :``%%``: literal "%" character
1722 :``%s``: basename of file being printed
1722 :``%s``: basename of file being printed
1723 :``%d``: dirname of file being printed, or '.' if in repository root
1723 :``%d``: dirname of file being printed, or '.' if in repository root
1724 :``%p``: root-relative path name of file being printed
1724 :``%p``: root-relative path name of file being printed
1725 :``%H``: changeset hash (40 hexadecimal digits)
1725 :``%H``: changeset hash (40 hexadecimal digits)
1726 :``%R``: changeset revision number
1726 :``%R``: changeset revision number
1727 :``%h``: short-form changeset hash (12 hexadecimal digits)
1727 :``%h``: short-form changeset hash (12 hexadecimal digits)
1728 :``%r``: zero-padded changeset revision number
1728 :``%r``: zero-padded changeset revision number
1729 :``%b``: basename of the exporting repository
1729 :``%b``: basename of the exporting repository
1730 :``\\``: literal "\\" character
1730 :``\\``: literal "\\" character
1731
1731
1732 .. container:: verbose
1732 .. container:: verbose
1733
1733
1734 Template:
1734 Template:
1735
1735
1736 The following keywords are supported in addition to the common template
1736 The following keywords are supported in addition to the common template
1737 keywords and functions. See also :hg:`help templates`.
1737 keywords and functions. See also :hg:`help templates`.
1738
1738
1739 :data: String. File content.
1739 :data: String. File content.
1740 :path: String. Repository-absolute path of the file.
1740 :path: String. Repository-absolute path of the file.
1741
1741
1742 Returns 0 on success.
1742 Returns 0 on success.
1743 """
1743 """
1744 opts = pycompat.byteskwargs(opts)
1744 opts = pycompat.byteskwargs(opts)
1745 rev = opts.get(b'rev')
1745 rev = opts.get(b'rev')
1746 if rev:
1746 if rev:
1747 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1747 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1748 ctx = scmutil.revsingle(repo, rev)
1748 ctx = scmutil.revsingle(repo, rev)
1749 m = scmutil.match(ctx, (file1,) + pats, opts)
1749 m = scmutil.match(ctx, (file1,) + pats, opts)
1750 fntemplate = opts.pop(b'output', b'')
1750 fntemplate = opts.pop(b'output', b'')
1751 if cmdutil.isstdiofilename(fntemplate):
1751 if cmdutil.isstdiofilename(fntemplate):
1752 fntemplate = b''
1752 fntemplate = b''
1753
1753
1754 if fntemplate:
1754 if fntemplate:
1755 fm = formatter.nullformatter(ui, b'cat', opts)
1755 fm = formatter.nullformatter(ui, b'cat', opts)
1756 else:
1756 else:
1757 ui.pager(b'cat')
1757 ui.pager(b'cat')
1758 fm = ui.formatter(b'cat', opts)
1758 fm = ui.formatter(b'cat', opts)
1759 with fm:
1759 with fm:
1760 return cmdutil.cat(
1760 return cmdutil.cat(
1761 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1761 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1762 )
1762 )
1763
1763
1764
1764
1765 @command(
1765 @command(
1766 b'clone',
1766 b'clone',
1767 [
1767 [
1768 (
1768 (
1769 b'U',
1769 b'U',
1770 b'noupdate',
1770 b'noupdate',
1771 None,
1771 None,
1772 _(
1772 _(
1773 b'the clone will include an empty working '
1773 b'the clone will include an empty working '
1774 b'directory (only a repository)'
1774 b'directory (only a repository)'
1775 ),
1775 ),
1776 ),
1776 ),
1777 (
1777 (
1778 b'u',
1778 b'u',
1779 b'updaterev',
1779 b'updaterev',
1780 b'',
1780 b'',
1781 _(b'revision, tag, or branch to check out'),
1781 _(b'revision, tag, or branch to check out'),
1782 _(b'REV'),
1782 _(b'REV'),
1783 ),
1783 ),
1784 (
1784 (
1785 b'r',
1785 b'r',
1786 b'rev',
1786 b'rev',
1787 [],
1787 [],
1788 _(
1788 _(
1789 b'do not clone everything, but include this changeset'
1789 b'do not clone everything, but include this changeset'
1790 b' and its ancestors'
1790 b' and its ancestors'
1791 ),
1791 ),
1792 _(b'REV'),
1792 _(b'REV'),
1793 ),
1793 ),
1794 (
1794 (
1795 b'b',
1795 b'b',
1796 b'branch',
1796 b'branch',
1797 [],
1797 [],
1798 _(
1798 _(
1799 b'do not clone everything, but include this branch\'s'
1799 b'do not clone everything, but include this branch\'s'
1800 b' changesets and their ancestors'
1800 b' changesets and their ancestors'
1801 ),
1801 ),
1802 _(b'BRANCH'),
1802 _(b'BRANCH'),
1803 ),
1803 ),
1804 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1804 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1805 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1805 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1806 (b'', b'stream', None, _(b'clone with minimal data processing')),
1806 (b'', b'stream', None, _(b'clone with minimal data processing')),
1807 ]
1807 ]
1808 + remoteopts,
1808 + remoteopts,
1809 _(b'[OPTION]... SOURCE [DEST]'),
1809 _(b'[OPTION]... SOURCE [DEST]'),
1810 helpcategory=command.CATEGORY_REPO_CREATION,
1810 helpcategory=command.CATEGORY_REPO_CREATION,
1811 helpbasic=True,
1811 helpbasic=True,
1812 norepo=True,
1812 norepo=True,
1813 )
1813 )
1814 def clone(ui, source, dest=None, **opts):
1814 def clone(ui, source, dest=None, **opts):
1815 """make a copy of an existing repository
1815 """make a copy of an existing repository
1816
1816
1817 Create a copy of an existing repository in a new directory.
1817 Create a copy of an existing repository in a new directory.
1818
1818
1819 If no destination directory name is specified, it defaults to the
1819 If no destination directory name is specified, it defaults to the
1820 basename of the source.
1820 basename of the source.
1821
1821
1822 The location of the source is added to the new repository's
1822 The location of the source is added to the new repository's
1823 ``.hg/hgrc`` file, as the default to be used for future pulls.
1823 ``.hg/hgrc`` file, as the default to be used for future pulls.
1824
1824
1825 Only local paths and ``ssh://`` URLs are supported as
1825 Only local paths and ``ssh://`` URLs are supported as
1826 destinations. For ``ssh://`` destinations, no working directory or
1826 destinations. For ``ssh://`` destinations, no working directory or
1827 ``.hg/hgrc`` will be created on the remote side.
1827 ``.hg/hgrc`` will be created on the remote side.
1828
1828
1829 If the source repository has a bookmark called '@' set, that
1829 If the source repository has a bookmark called '@' set, that
1830 revision will be checked out in the new repository by default.
1830 revision will be checked out in the new repository by default.
1831
1831
1832 To check out a particular version, use -u/--update, or
1832 To check out a particular version, use -u/--update, or
1833 -U/--noupdate to create a clone with no working directory.
1833 -U/--noupdate to create a clone with no working directory.
1834
1834
1835 To pull only a subset of changesets, specify one or more revisions
1835 To pull only a subset of changesets, specify one or more revisions
1836 identifiers with -r/--rev or branches with -b/--branch. The
1836 identifiers with -r/--rev or branches with -b/--branch. The
1837 resulting clone will contain only the specified changesets and
1837 resulting clone will contain only the specified changesets and
1838 their ancestors. These options (or 'clone src#rev dest') imply
1838 their ancestors. These options (or 'clone src#rev dest') imply
1839 --pull, even for local source repositories.
1839 --pull, even for local source repositories.
1840
1840
1841 In normal clone mode, the remote normalizes repository data into a common
1841 In normal clone mode, the remote normalizes repository data into a common
1842 exchange format and the receiving end translates this data into its local
1842 exchange format and the receiving end translates this data into its local
1843 storage format. --stream activates a different clone mode that essentially
1843 storage format. --stream activates a different clone mode that essentially
1844 copies repository files from the remote with minimal data processing. This
1844 copies repository files from the remote with minimal data processing. This
1845 significantly reduces the CPU cost of a clone both remotely and locally.
1845 significantly reduces the CPU cost of a clone both remotely and locally.
1846 However, it often increases the transferred data size by 30-40%. This can
1846 However, it often increases the transferred data size by 30-40%. This can
1847 result in substantially faster clones where I/O throughput is plentiful,
1847 result in substantially faster clones where I/O throughput is plentiful,
1848 especially for larger repositories. A side-effect of --stream clones is
1848 especially for larger repositories. A side-effect of --stream clones is
1849 that storage settings and requirements on the remote are applied locally:
1849 that storage settings and requirements on the remote are applied locally:
1850 a modern client may inherit legacy or inefficient storage used by the
1850 a modern client may inherit legacy or inefficient storage used by the
1851 remote or a legacy Mercurial client may not be able to clone from a
1851 remote or a legacy Mercurial client may not be able to clone from a
1852 modern Mercurial remote.
1852 modern Mercurial remote.
1853
1853
1854 .. note::
1854 .. note::
1855
1855
1856 Specifying a tag will include the tagged changeset but not the
1856 Specifying a tag will include the tagged changeset but not the
1857 changeset containing the tag.
1857 changeset containing the tag.
1858
1858
1859 .. container:: verbose
1859 .. container:: verbose
1860
1860
1861 For efficiency, hardlinks are used for cloning whenever the
1861 For efficiency, hardlinks are used for cloning whenever the
1862 source and destination are on the same filesystem (note this
1862 source and destination are on the same filesystem (note this
1863 applies only to the repository data, not to the working
1863 applies only to the repository data, not to the working
1864 directory). Some filesystems, such as AFS, implement hardlinking
1864 directory). Some filesystems, such as AFS, implement hardlinking
1865 incorrectly, but do not report errors. In these cases, use the
1865 incorrectly, but do not report errors. In these cases, use the
1866 --pull option to avoid hardlinking.
1866 --pull option to avoid hardlinking.
1867
1867
1868 Mercurial will update the working directory to the first applicable
1868 Mercurial will update the working directory to the first applicable
1869 revision from this list:
1869 revision from this list:
1870
1870
1871 a) null if -U or the source repository has no changesets
1871 a) null if -U or the source repository has no changesets
1872 b) if -u . and the source repository is local, the first parent of
1872 b) if -u . and the source repository is local, the first parent of
1873 the source repository's working directory
1873 the source repository's working directory
1874 c) the changeset specified with -u (if a branch name, this means the
1874 c) the changeset specified with -u (if a branch name, this means the
1875 latest head of that branch)
1875 latest head of that branch)
1876 d) the changeset specified with -r
1876 d) the changeset specified with -r
1877 e) the tipmost head specified with -b
1877 e) the tipmost head specified with -b
1878 f) the tipmost head specified with the url#branch source syntax
1878 f) the tipmost head specified with the url#branch source syntax
1879 g) the revision marked with the '@' bookmark, if present
1879 g) the revision marked with the '@' bookmark, if present
1880 h) the tipmost head of the default branch
1880 h) the tipmost head of the default branch
1881 i) tip
1881 i) tip
1882
1882
1883 When cloning from servers that support it, Mercurial may fetch
1883 When cloning from servers that support it, Mercurial may fetch
1884 pre-generated data from a server-advertised URL or inline from the
1884 pre-generated data from a server-advertised URL or inline from the
1885 same stream. When this is done, hooks operating on incoming changesets
1885 same stream. When this is done, hooks operating on incoming changesets
1886 and changegroups may fire more than once, once for each pre-generated
1886 and changegroups may fire more than once, once for each pre-generated
1887 bundle and as well as for any additional remaining data. In addition,
1887 bundle and as well as for any additional remaining data. In addition,
1888 if an error occurs, the repository may be rolled back to a partial
1888 if an error occurs, the repository may be rolled back to a partial
1889 clone. This behavior may change in future releases.
1889 clone. This behavior may change in future releases.
1890 See :hg:`help -e clonebundles` for more.
1890 See :hg:`help -e clonebundles` for more.
1891
1891
1892 Examples:
1892 Examples:
1893
1893
1894 - clone a remote repository to a new directory named hg/::
1894 - clone a remote repository to a new directory named hg/::
1895
1895
1896 hg clone https://www.mercurial-scm.org/repo/hg/
1896 hg clone https://www.mercurial-scm.org/repo/hg/
1897
1897
1898 - create a lightweight local clone::
1898 - create a lightweight local clone::
1899
1899
1900 hg clone project/ project-feature/
1900 hg clone project/ project-feature/
1901
1901
1902 - clone from an absolute path on an ssh server (note double-slash)::
1902 - clone from an absolute path on an ssh server (note double-slash)::
1903
1903
1904 hg clone ssh://user@server//home/projects/alpha/
1904 hg clone ssh://user@server//home/projects/alpha/
1905
1905
1906 - do a streaming clone while checking out a specified version::
1906 - do a streaming clone while checking out a specified version::
1907
1907
1908 hg clone --stream http://server/repo -u 1.5
1908 hg clone --stream http://server/repo -u 1.5
1909
1909
1910 - create a repository without changesets after a particular revision::
1910 - create a repository without changesets after a particular revision::
1911
1911
1912 hg clone -r 04e544 experimental/ good/
1912 hg clone -r 04e544 experimental/ good/
1913
1913
1914 - clone (and track) a particular named branch::
1914 - clone (and track) a particular named branch::
1915
1915
1916 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1916 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1917
1917
1918 See :hg:`help urls` for details on specifying URLs.
1918 See :hg:`help urls` for details on specifying URLs.
1919
1919
1920 Returns 0 on success.
1920 Returns 0 on success.
1921 """
1921 """
1922 opts = pycompat.byteskwargs(opts)
1922 opts = pycompat.byteskwargs(opts)
1923 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1923 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1924
1924
1925 # --include/--exclude can come from narrow or sparse.
1925 # --include/--exclude can come from narrow or sparse.
1926 includepats, excludepats = None, None
1926 includepats, excludepats = None, None
1927
1927
1928 # hg.clone() differentiates between None and an empty set. So make sure
1928 # hg.clone() differentiates between None and an empty set. So make sure
1929 # patterns are sets if narrow is requested without patterns.
1929 # patterns are sets if narrow is requested without patterns.
1930 if opts.get(b'narrow'):
1930 if opts.get(b'narrow'):
1931 includepats = set()
1931 includepats = set()
1932 excludepats = set()
1932 excludepats = set()
1933
1933
1934 if opts.get(b'include'):
1934 if opts.get(b'include'):
1935 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1935 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1936 if opts.get(b'exclude'):
1936 if opts.get(b'exclude'):
1937 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1937 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1938
1938
1939 r = hg.clone(
1939 r = hg.clone(
1940 ui,
1940 ui,
1941 opts,
1941 opts,
1942 source,
1942 source,
1943 dest,
1943 dest,
1944 pull=opts.get(b'pull'),
1944 pull=opts.get(b'pull'),
1945 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1945 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1946 revs=opts.get(b'rev'),
1946 revs=opts.get(b'rev'),
1947 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1947 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1948 branch=opts.get(b'branch'),
1948 branch=opts.get(b'branch'),
1949 shareopts=opts.get(b'shareopts'),
1949 shareopts=opts.get(b'shareopts'),
1950 storeincludepats=includepats,
1950 storeincludepats=includepats,
1951 storeexcludepats=excludepats,
1951 storeexcludepats=excludepats,
1952 depth=opts.get(b'depth') or None,
1952 depth=opts.get(b'depth') or None,
1953 )
1953 )
1954
1954
1955 return r is None
1955 return r is None
1956
1956
1957
1957
1958 @command(
1958 @command(
1959 b'commit|ci',
1959 b'commit|ci',
1960 [
1960 [
1961 (
1961 (
1962 b'A',
1962 b'A',
1963 b'addremove',
1963 b'addremove',
1964 None,
1964 None,
1965 _(b'mark new/missing files as added/removed before committing'),
1965 _(b'mark new/missing files as added/removed before committing'),
1966 ),
1966 ),
1967 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1967 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1968 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1968 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1969 (b's', b'secret', None, _(b'use the secret phase for committing')),
1969 (b's', b'secret', None, _(b'use the secret phase for committing')),
1970 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1970 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1971 (
1971 (
1972 b'',
1972 b'',
1973 b'force-close-branch',
1973 b'force-close-branch',
1974 None,
1974 None,
1975 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1975 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1976 ),
1976 ),
1977 (b'i', b'interactive', None, _(b'use interactive mode')),
1977 (b'i', b'interactive', None, _(b'use interactive mode')),
1978 ]
1978 ]
1979 + walkopts
1979 + walkopts
1980 + commitopts
1980 + commitopts
1981 + commitopts2
1981 + commitopts2
1982 + subrepoopts,
1982 + subrepoopts,
1983 _(b'[OPTION]... [FILE]...'),
1983 _(b'[OPTION]... [FILE]...'),
1984 helpcategory=command.CATEGORY_COMMITTING,
1984 helpcategory=command.CATEGORY_COMMITTING,
1985 helpbasic=True,
1985 helpbasic=True,
1986 inferrepo=True,
1986 inferrepo=True,
1987 )
1987 )
1988 def commit(ui, repo, *pats, **opts):
1988 def commit(ui, repo, *pats, **opts):
1989 """commit the specified files or all outstanding changes
1989 """commit the specified files or all outstanding changes
1990
1990
1991 Commit changes to the given files into the repository. Unlike a
1991 Commit changes to the given files into the repository. Unlike a
1992 centralized SCM, this operation is a local operation. See
1992 centralized SCM, this operation is a local operation. See
1993 :hg:`push` for a way to actively distribute your changes.
1993 :hg:`push` for a way to actively distribute your changes.
1994
1994
1995 If a list of files is omitted, all changes reported by :hg:`status`
1995 If a list of files is omitted, all changes reported by :hg:`status`
1996 will be committed.
1996 will be committed.
1997
1997
1998 If you are committing the result of a merge, do not provide any
1998 If you are committing the result of a merge, do not provide any
1999 filenames or -I/-X filters.
1999 filenames or -I/-X filters.
2000
2000
2001 If no commit message is specified, Mercurial starts your
2001 If no commit message is specified, Mercurial starts your
2002 configured editor where you can enter a message. In case your
2002 configured editor where you can enter a message. In case your
2003 commit fails, you will find a backup of your message in
2003 commit fails, you will find a backup of your message in
2004 ``.hg/last-message.txt``.
2004 ``.hg/last-message.txt``.
2005
2005
2006 The --close-branch flag can be used to mark the current branch
2006 The --close-branch flag can be used to mark the current branch
2007 head closed. When all heads of a branch are closed, the branch
2007 head closed. When all heads of a branch are closed, the branch
2008 will be considered closed and no longer listed.
2008 will be considered closed and no longer listed.
2009
2009
2010 The --amend flag can be used to amend the parent of the
2010 The --amend flag can be used to amend the parent of the
2011 working directory with a new commit that contains the changes
2011 working directory with a new commit that contains the changes
2012 in the parent in addition to those currently reported by :hg:`status`,
2012 in the parent in addition to those currently reported by :hg:`status`,
2013 if there are any. The old commit is stored in a backup bundle in
2013 if there are any. The old commit is stored in a backup bundle in
2014 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2014 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2015 on how to restore it).
2015 on how to restore it).
2016
2016
2017 Message, user and date are taken from the amended commit unless
2017 Message, user and date are taken from the amended commit unless
2018 specified. When a message isn't specified on the command line,
2018 specified. When a message isn't specified on the command line,
2019 the editor will open with the message of the amended commit.
2019 the editor will open with the message of the amended commit.
2020
2020
2021 It is not possible to amend public changesets (see :hg:`help phases`)
2021 It is not possible to amend public changesets (see :hg:`help phases`)
2022 or changesets that have children.
2022 or changesets that have children.
2023
2023
2024 See :hg:`help dates` for a list of formats valid for -d/--date.
2024 See :hg:`help dates` for a list of formats valid for -d/--date.
2025
2025
2026 Returns 0 on success, 1 if nothing changed.
2026 Returns 0 on success, 1 if nothing changed.
2027
2027
2028 .. container:: verbose
2028 .. container:: verbose
2029
2029
2030 Examples:
2030 Examples:
2031
2031
2032 - commit all files ending in .py::
2032 - commit all files ending in .py::
2033
2033
2034 hg commit --include "set:**.py"
2034 hg commit --include "set:**.py"
2035
2035
2036 - commit all non-binary files::
2036 - commit all non-binary files::
2037
2037
2038 hg commit --exclude "set:binary()"
2038 hg commit --exclude "set:binary()"
2039
2039
2040 - amend the current commit and set the date to now::
2040 - amend the current commit and set the date to now::
2041
2041
2042 hg commit --amend --date now
2042 hg commit --amend --date now
2043 """
2043 """
2044 with repo.wlock(), repo.lock():
2044 with repo.wlock(), repo.lock():
2045 return _docommit(ui, repo, *pats, **opts)
2045 return _docommit(ui, repo, *pats, **opts)
2046
2046
2047
2047
2048 def _docommit(ui, repo, *pats, **opts):
2048 def _docommit(ui, repo, *pats, **opts):
2049 if opts.get('interactive'):
2049 if opts.get('interactive'):
2050 opts.pop('interactive')
2050 opts.pop('interactive')
2051 ret = cmdutil.dorecord(
2051 ret = cmdutil.dorecord(
2052 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2052 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2053 )
2053 )
2054 # ret can be 0 (no changes to record) or the value returned by
2054 # ret can be 0 (no changes to record) or the value returned by
2055 # commit(), 1 if nothing changed or None on success.
2055 # commit(), 1 if nothing changed or None on success.
2056 return 1 if ret == 0 else ret
2056 return 1 if ret == 0 else ret
2057
2057
2058 opts = pycompat.byteskwargs(opts)
2058 opts = pycompat.byteskwargs(opts)
2059 if opts.get(b'subrepos'):
2059 if opts.get(b'subrepos'):
2060 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2060 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2061 # Let --subrepos on the command line override config setting.
2061 # Let --subrepos on the command line override config setting.
2062 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2062 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2063
2063
2064 cmdutil.checkunfinished(repo, commit=True)
2064 cmdutil.checkunfinished(repo, commit=True)
2065
2065
2066 branch = repo[None].branch()
2066 branch = repo[None].branch()
2067 bheads = repo.branchheads(branch)
2067 bheads = repo.branchheads(branch)
2068 tip = repo.changelog.tip()
2068 tip = repo.changelog.tip()
2069
2069
2070 extra = {}
2070 extra = {}
2071 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2071 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2072 extra[b'close'] = b'1'
2072 extra[b'close'] = b'1'
2073
2073
2074 if repo[b'.'].closesbranch():
2074 if repo[b'.'].closesbranch():
2075 raise error.InputError(
2075 raise error.InputError(
2076 _(b'current revision is already a branch closing head')
2076 _(b'current revision is already a branch closing head')
2077 )
2077 )
2078 elif not bheads:
2078 elif not bheads:
2079 raise error.InputError(
2079 raise error.InputError(
2080 _(b'branch "%s" has no heads to close') % branch
2080 _(b'branch "%s" has no heads to close') % branch
2081 )
2081 )
2082 elif (
2082 elif (
2083 branch == repo[b'.'].branch()
2083 branch == repo[b'.'].branch()
2084 and repo[b'.'].node() not in bheads
2084 and repo[b'.'].node() not in bheads
2085 and not opts.get(b'force_close_branch')
2085 and not opts.get(b'force_close_branch')
2086 ):
2086 ):
2087 hint = _(
2087 hint = _(
2088 b'use --force-close-branch to close branch from a non-head'
2088 b'use --force-close-branch to close branch from a non-head'
2089 b' changeset'
2089 b' changeset'
2090 )
2090 )
2091 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2091 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2092 elif opts.get(b'amend'):
2092 elif opts.get(b'amend'):
2093 if (
2093 if (
2094 repo[b'.'].p1().branch() != branch
2094 repo[b'.'].p1().branch() != branch
2095 and repo[b'.'].p2().branch() != branch
2095 and repo[b'.'].p2().branch() != branch
2096 ):
2096 ):
2097 raise error.InputError(_(b'can only close branch heads'))
2097 raise error.InputError(_(b'can only close branch heads'))
2098
2098
2099 if opts.get(b'amend'):
2099 if opts.get(b'amend'):
2100 if ui.configbool(b'ui', b'commitsubrepos'):
2100 if ui.configbool(b'ui', b'commitsubrepos'):
2101 raise error.InputError(
2101 raise error.InputError(
2102 _(b'cannot amend with ui.commitsubrepos enabled')
2102 _(b'cannot amend with ui.commitsubrepos enabled')
2103 )
2103 )
2104
2104
2105 old = repo[b'.']
2105 old = repo[b'.']
2106 rewriteutil.precheck(repo, [old.rev()], b'amend')
2106 rewriteutil.precheck(repo, [old.rev()], b'amend')
2107
2107
2108 # Currently histedit gets confused if an amend happens while histedit
2108 # Currently histedit gets confused if an amend happens while histedit
2109 # is in progress. Since we have a checkunfinished command, we are
2109 # is in progress. Since we have a checkunfinished command, we are
2110 # temporarily honoring it.
2110 # temporarily honoring it.
2111 #
2111 #
2112 # Note: eventually this guard will be removed. Please do not expect
2112 # Note: eventually this guard will be removed. Please do not expect
2113 # this behavior to remain.
2113 # this behavior to remain.
2114 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2114 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2115 cmdutil.checkunfinished(repo)
2115 cmdutil.checkunfinished(repo)
2116
2116
2117 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2117 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2118 if node == old.node():
2118 if node == old.node():
2119 ui.status(_(b"nothing changed\n"))
2119 ui.status(_(b"nothing changed\n"))
2120 return 1
2120 return 1
2121 else:
2121 else:
2122
2122
2123 def commitfunc(ui, repo, message, match, opts):
2123 def commitfunc(ui, repo, message, match, opts):
2124 overrides = {}
2124 overrides = {}
2125 if opts.get(b'secret'):
2125 if opts.get(b'secret'):
2126 overrides[(b'phases', b'new-commit')] = b'secret'
2126 overrides[(b'phases', b'new-commit')] = b'secret'
2127
2127
2128 baseui = repo.baseui
2128 baseui = repo.baseui
2129 with baseui.configoverride(overrides, b'commit'):
2129 with baseui.configoverride(overrides, b'commit'):
2130 with ui.configoverride(overrides, b'commit'):
2130 with ui.configoverride(overrides, b'commit'):
2131 editform = cmdutil.mergeeditform(
2131 editform = cmdutil.mergeeditform(
2132 repo[None], b'commit.normal'
2132 repo[None], b'commit.normal'
2133 )
2133 )
2134 editor = cmdutil.getcommiteditor(
2134 editor = cmdutil.getcommiteditor(
2135 editform=editform, **pycompat.strkwargs(opts)
2135 editform=editform, **pycompat.strkwargs(opts)
2136 )
2136 )
2137 return repo.commit(
2137 return repo.commit(
2138 message,
2138 message,
2139 opts.get(b'user'),
2139 opts.get(b'user'),
2140 opts.get(b'date'),
2140 opts.get(b'date'),
2141 match,
2141 match,
2142 editor=editor,
2142 editor=editor,
2143 extra=extra,
2143 extra=extra,
2144 )
2144 )
2145
2145
2146 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2146 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2147
2147
2148 if not node:
2148 if not node:
2149 stat = cmdutil.postcommitstatus(repo, pats, opts)
2149 stat = cmdutil.postcommitstatus(repo, pats, opts)
2150 if stat.deleted:
2150 if stat.deleted:
2151 ui.status(
2151 ui.status(
2152 _(
2152 _(
2153 b"nothing changed (%d missing files, see "
2153 b"nothing changed (%d missing files, see "
2154 b"'hg status')\n"
2154 b"'hg status')\n"
2155 )
2155 )
2156 % len(stat.deleted)
2156 % len(stat.deleted)
2157 )
2157 )
2158 else:
2158 else:
2159 ui.status(_(b"nothing changed\n"))
2159 ui.status(_(b"nothing changed\n"))
2160 return 1
2160 return 1
2161
2161
2162 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2162 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2163
2163
2164 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2164 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2165 status(
2165 status(
2166 ui,
2166 ui,
2167 repo,
2167 repo,
2168 modified=True,
2168 modified=True,
2169 added=True,
2169 added=True,
2170 removed=True,
2170 removed=True,
2171 deleted=True,
2171 deleted=True,
2172 unknown=True,
2172 unknown=True,
2173 subrepos=opts.get(b'subrepos'),
2173 subrepos=opts.get(b'subrepos'),
2174 )
2174 )
2175
2175
2176
2176
2177 @command(
2177 @command(
2178 b'config|showconfig|debugconfig',
2178 b'config|showconfig|debugconfig',
2179 [
2179 [
2180 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2180 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2181 (b'e', b'edit', None, _(b'edit user config')),
2181 (b'e', b'edit', None, _(b'edit user config')),
2182 (b'l', b'local', None, _(b'edit repository config')),
2182 (b'l', b'local', None, _(b'edit repository config')),
2183 (
2183 (
2184 b'',
2184 b'',
2185 b'shared',
2185 b'shared',
2186 None,
2186 None,
2187 _(b'edit shared source repository config (EXPERIMENTAL)'),
2187 _(b'edit shared source repository config (EXPERIMENTAL)'),
2188 ),
2188 ),
2189 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2189 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2190 (b'g', b'global', None, _(b'edit global config')),
2190 (b'g', b'global', None, _(b'edit global config')),
2191 ]
2191 ]
2192 + formatteropts,
2192 + formatteropts,
2193 _(b'[-u] [NAME]...'),
2193 _(b'[-u] [NAME]...'),
2194 helpcategory=command.CATEGORY_HELP,
2194 helpcategory=command.CATEGORY_HELP,
2195 optionalrepo=True,
2195 optionalrepo=True,
2196 intents={INTENT_READONLY},
2196 intents={INTENT_READONLY},
2197 )
2197 )
2198 def config(ui, repo, *values, **opts):
2198 def config(ui, repo, *values, **opts):
2199 """show combined config settings from all hgrc files
2199 """show combined config settings from all hgrc files
2200
2200
2201 With no arguments, print names and values of all config items.
2201 With no arguments, print names and values of all config items.
2202
2202
2203 With one argument of the form section.name, print just the value
2203 With one argument of the form section.name, print just the value
2204 of that config item.
2204 of that config item.
2205
2205
2206 With multiple arguments, print names and values of all config
2206 With multiple arguments, print names and values of all config
2207 items with matching section names or section.names.
2207 items with matching section names or section.names.
2208
2208
2209 With --edit, start an editor on the user-level config file. With
2209 With --edit, start an editor on the user-level config file. With
2210 --global, edit the system-wide config file. With --local, edit the
2210 --global, edit the system-wide config file. With --local, edit the
2211 repository-level config file.
2211 repository-level config file.
2212
2212
2213 With --debug, the source (filename and line number) is printed
2213 With --debug, the source (filename and line number) is printed
2214 for each config item.
2214 for each config item.
2215
2215
2216 See :hg:`help config` for more information about config files.
2216 See :hg:`help config` for more information about config files.
2217
2217
2218 .. container:: verbose
2218 .. container:: verbose
2219
2219
2220 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2220 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2221 This file is not shared across shares when in share-safe mode.
2221 This file is not shared across shares when in share-safe mode.
2222
2222
2223 Template:
2223 Template:
2224
2224
2225 The following keywords are supported. See also :hg:`help templates`.
2225 The following keywords are supported. See also :hg:`help templates`.
2226
2226
2227 :name: String. Config name.
2227 :name: String. Config name.
2228 :source: String. Filename and line number where the item is defined.
2228 :source: String. Filename and line number where the item is defined.
2229 :value: String. Config value.
2229 :value: String. Config value.
2230
2230
2231 The --shared flag can be used to edit the config file of shared source
2231 The --shared flag can be used to edit the config file of shared source
2232 repository. It only works when you have shared using the experimental
2232 repository. It only works when you have shared using the experimental
2233 share safe feature.
2233 share safe feature.
2234
2234
2235 Returns 0 on success, 1 if NAME does not exist.
2235 Returns 0 on success, 1 if NAME does not exist.
2236
2236
2237 """
2237 """
2238
2238
2239 opts = pycompat.byteskwargs(opts)
2239 opts = pycompat.byteskwargs(opts)
2240 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2240 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2241 if any(opts.get(o) for o in editopts):
2241 if any(opts.get(o) for o in editopts):
2242 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2242 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2243 if opts.get(b'local'):
2243 if opts.get(b'local'):
2244 if not repo:
2244 if not repo:
2245 raise error.InputError(
2245 raise error.InputError(
2246 _(b"can't use --local outside a repository")
2246 _(b"can't use --local outside a repository")
2247 )
2247 )
2248 paths = [repo.vfs.join(b'hgrc')]
2248 paths = [repo.vfs.join(b'hgrc')]
2249 elif opts.get(b'global'):
2249 elif opts.get(b'global'):
2250 paths = rcutil.systemrcpath()
2250 paths = rcutil.systemrcpath()
2251 elif opts.get(b'shared'):
2251 elif opts.get(b'shared'):
2252 if not repo.shared():
2252 if not repo.shared():
2253 raise error.InputError(
2253 raise error.InputError(
2254 _(b"repository is not shared; can't use --shared")
2254 _(b"repository is not shared; can't use --shared")
2255 )
2255 )
2256 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2256 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2257 raise error.InputError(
2257 raise error.InputError(
2258 _(
2258 _(
2259 b"share safe feature not enabled; "
2259 b"share safe feature not enabled; "
2260 b"unable to edit shared source repository config"
2260 b"unable to edit shared source repository config"
2261 )
2261 )
2262 )
2262 )
2263 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2263 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2264 elif opts.get(b'non_shared'):
2264 elif opts.get(b'non_shared'):
2265 paths = [repo.vfs.join(b'hgrc-not-shared')]
2265 paths = [repo.vfs.join(b'hgrc-not-shared')]
2266 else:
2266 else:
2267 paths = rcutil.userrcpath()
2267 paths = rcutil.userrcpath()
2268
2268
2269 for f in paths:
2269 for f in paths:
2270 if os.path.exists(f):
2270 if os.path.exists(f):
2271 break
2271 break
2272 else:
2272 else:
2273 if opts.get(b'global'):
2273 if opts.get(b'global'):
2274 samplehgrc = uimod.samplehgrcs[b'global']
2274 samplehgrc = uimod.samplehgrcs[b'global']
2275 elif opts.get(b'local'):
2275 elif opts.get(b'local'):
2276 samplehgrc = uimod.samplehgrcs[b'local']
2276 samplehgrc = uimod.samplehgrcs[b'local']
2277 else:
2277 else:
2278 samplehgrc = uimod.samplehgrcs[b'user']
2278 samplehgrc = uimod.samplehgrcs[b'user']
2279
2279
2280 f = paths[0]
2280 f = paths[0]
2281 fp = open(f, b"wb")
2281 fp = open(f, b"wb")
2282 fp.write(util.tonativeeol(samplehgrc))
2282 fp.write(util.tonativeeol(samplehgrc))
2283 fp.close()
2283 fp.close()
2284
2284
2285 editor = ui.geteditor()
2285 editor = ui.geteditor()
2286 ui.system(
2286 ui.system(
2287 b"%s \"%s\"" % (editor, f),
2287 b"%s \"%s\"" % (editor, f),
2288 onerr=error.InputError,
2288 onerr=error.InputError,
2289 errprefix=_(b"edit failed"),
2289 errprefix=_(b"edit failed"),
2290 blockedtag=b'config_edit',
2290 blockedtag=b'config_edit',
2291 )
2291 )
2292 return
2292 return
2293 ui.pager(b'config')
2293 ui.pager(b'config')
2294 fm = ui.formatter(b'config', opts)
2294 fm = ui.formatter(b'config', opts)
2295 for t, f in rcutil.rccomponents():
2295 for t, f in rcutil.rccomponents():
2296 if t == b'path':
2296 if t == b'path':
2297 ui.debug(b'read config from: %s\n' % f)
2297 ui.debug(b'read config from: %s\n' % f)
2298 elif t == b'resource':
2298 elif t == b'resource':
2299 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2299 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2300 elif t == b'items':
2300 elif t == b'items':
2301 # Don't print anything for 'items'.
2301 # Don't print anything for 'items'.
2302 pass
2302 pass
2303 else:
2303 else:
2304 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2304 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2305 untrusted = bool(opts.get(b'untrusted'))
2305 untrusted = bool(opts.get(b'untrusted'))
2306
2306
2307 selsections = selentries = []
2307 selsections = selentries = []
2308 if values:
2308 if values:
2309 selsections = [v for v in values if b'.' not in v]
2309 selsections = [v for v in values if b'.' not in v]
2310 selentries = [v for v in values if b'.' in v]
2310 selentries = [v for v in values if b'.' in v]
2311 uniquesel = len(selentries) == 1 and not selsections
2311 uniquesel = len(selentries) == 1 and not selsections
2312 selsections = set(selsections)
2312 selsections = set(selsections)
2313 selentries = set(selentries)
2313 selentries = set(selentries)
2314
2314
2315 matched = False
2315 matched = False
2316 for section, name, value in ui.walkconfig(untrusted=untrusted):
2316 for section, name, value in ui.walkconfig(untrusted=untrusted):
2317 source = ui.configsource(section, name, untrusted)
2317 source = ui.configsource(section, name, untrusted)
2318 value = pycompat.bytestr(value)
2318 value = pycompat.bytestr(value)
2319 defaultvalue = ui.configdefault(section, name)
2319 defaultvalue = ui.configdefault(section, name)
2320 if fm.isplain():
2320 if fm.isplain():
2321 source = source or b'none'
2321 source = source or b'none'
2322 value = value.replace(b'\n', b'\\n')
2322 value = value.replace(b'\n', b'\\n')
2323 entryname = section + b'.' + name
2323 entryname = section + b'.' + name
2324 if values and not (section in selsections or entryname in selentries):
2324 if values and not (section in selsections or entryname in selentries):
2325 continue
2325 continue
2326 fm.startitem()
2326 fm.startitem()
2327 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2327 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2328 if uniquesel:
2328 if uniquesel:
2329 fm.data(name=entryname)
2329 fm.data(name=entryname)
2330 fm.write(b'value', b'%s\n', value)
2330 fm.write(b'value', b'%s\n', value)
2331 else:
2331 else:
2332 fm.write(b'name value', b'%s=%s\n', entryname, value)
2332 fm.write(b'name value', b'%s=%s\n', entryname, value)
2333 if formatter.isprintable(defaultvalue):
2333 if formatter.isprintable(defaultvalue):
2334 fm.data(defaultvalue=defaultvalue)
2334 fm.data(defaultvalue=defaultvalue)
2335 elif isinstance(defaultvalue, list) and all(
2335 elif isinstance(defaultvalue, list) and all(
2336 formatter.isprintable(e) for e in defaultvalue
2336 formatter.isprintable(e) for e in defaultvalue
2337 ):
2337 ):
2338 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2338 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2339 # TODO: no idea how to process unsupported defaultvalue types
2339 # TODO: no idea how to process unsupported defaultvalue types
2340 matched = True
2340 matched = True
2341 fm.end()
2341 fm.end()
2342 if matched:
2342 if matched:
2343 return 0
2343 return 0
2344 return 1
2344 return 1
2345
2345
2346
2346
2347 @command(
2347 @command(
2348 b'continue',
2348 b'continue',
2349 dryrunopts,
2349 dryrunopts,
2350 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2350 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2351 helpbasic=True,
2351 helpbasic=True,
2352 )
2352 )
2353 def continuecmd(ui, repo, **opts):
2353 def continuecmd(ui, repo, **opts):
2354 """resumes an interrupted operation (EXPERIMENTAL)
2354 """resumes an interrupted operation (EXPERIMENTAL)
2355
2355
2356 Finishes a multistep operation like graft, histedit, rebase, merge,
2356 Finishes a multistep operation like graft, histedit, rebase, merge,
2357 and unshelve if they are in an interrupted state.
2357 and unshelve if they are in an interrupted state.
2358
2358
2359 use --dry-run/-n to dry run the command.
2359 use --dry-run/-n to dry run the command.
2360 """
2360 """
2361 dryrun = opts.get('dry_run')
2361 dryrun = opts.get('dry_run')
2362 contstate = cmdutil.getunfinishedstate(repo)
2362 contstate = cmdutil.getunfinishedstate(repo)
2363 if not contstate:
2363 if not contstate:
2364 raise error.StateError(_(b'no operation in progress'))
2364 raise error.StateError(_(b'no operation in progress'))
2365 if not contstate.continuefunc:
2365 if not contstate.continuefunc:
2366 raise error.StateError(
2366 raise error.StateError(
2367 (
2367 (
2368 _(b"%s in progress but does not support 'hg continue'")
2368 _(b"%s in progress but does not support 'hg continue'")
2369 % (contstate._opname)
2369 % (contstate._opname)
2370 ),
2370 ),
2371 hint=contstate.continuemsg(),
2371 hint=contstate.continuemsg(),
2372 )
2372 )
2373 if dryrun:
2373 if dryrun:
2374 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2374 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2375 return
2375 return
2376 return contstate.continuefunc(ui, repo)
2376 return contstate.continuefunc(ui, repo)
2377
2377
2378
2378
2379 @command(
2379 @command(
2380 b'copy|cp',
2380 b'copy|cp',
2381 [
2381 [
2382 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2382 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2383 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2383 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2384 (
2384 (
2385 b'',
2385 b'',
2386 b'at-rev',
2386 b'at-rev',
2387 b'',
2387 b'',
2388 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2388 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2389 _(b'REV'),
2389 _(b'REV'),
2390 ),
2390 ),
2391 (
2391 (
2392 b'f',
2392 b'f',
2393 b'force',
2393 b'force',
2394 None,
2394 None,
2395 _(b'forcibly copy over an existing managed file'),
2395 _(b'forcibly copy over an existing managed file'),
2396 ),
2396 ),
2397 ]
2397 ]
2398 + walkopts
2398 + walkopts
2399 + dryrunopts,
2399 + dryrunopts,
2400 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2400 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2401 helpcategory=command.CATEGORY_FILE_CONTENTS,
2401 helpcategory=command.CATEGORY_FILE_CONTENTS,
2402 )
2402 )
2403 def copy(ui, repo, *pats, **opts):
2403 def copy(ui, repo, *pats, **opts):
2404 """mark files as copied for the next commit
2404 """mark files as copied for the next commit
2405
2405
2406 Mark dest as having copies of source files. If dest is a
2406 Mark dest as having copies of source files. If dest is a
2407 directory, copies are put in that directory. If dest is a file,
2407 directory, copies are put in that directory. If dest is a file,
2408 the source must be a single file.
2408 the source must be a single file.
2409
2409
2410 By default, this command copies the contents of files as they
2410 By default, this command copies the contents of files as they
2411 exist in the working directory. If invoked with -A/--after, the
2411 exist in the working directory. If invoked with -A/--after, the
2412 operation is recorded, but no copying is performed.
2412 operation is recorded, but no copying is performed.
2413
2413
2414 To undo marking a destination file as copied, use --forget. With that
2414 To undo marking a destination file as copied, use --forget. With that
2415 option, all given (positional) arguments are unmarked as copies. The
2415 option, all given (positional) arguments are unmarked as copies. The
2416 destination file(s) will be left in place (still tracked).
2416 destination file(s) will be left in place (still tracked). Note that
2417 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2417
2418
2418 This command takes effect with the next commit by default.
2419 This command takes effect with the next commit by default.
2419
2420
2420 Returns 0 on success, 1 if errors are encountered.
2421 Returns 0 on success, 1 if errors are encountered.
2421 """
2422 """
2422 opts = pycompat.byteskwargs(opts)
2423 opts = pycompat.byteskwargs(opts)
2423 with repo.wlock():
2424 with repo.wlock():
2424 return cmdutil.copy(ui, repo, pats, opts)
2425 return cmdutil.copy(ui, repo, pats, opts)
2425
2426
2426
2427
2427 @command(
2428 @command(
2428 b'debugcommands',
2429 b'debugcommands',
2429 [],
2430 [],
2430 _(b'[COMMAND]'),
2431 _(b'[COMMAND]'),
2431 helpcategory=command.CATEGORY_HELP,
2432 helpcategory=command.CATEGORY_HELP,
2432 norepo=True,
2433 norepo=True,
2433 )
2434 )
2434 def debugcommands(ui, cmd=b'', *args):
2435 def debugcommands(ui, cmd=b'', *args):
2435 """list all available commands and options"""
2436 """list all available commands and options"""
2436 for cmd, vals in sorted(pycompat.iteritems(table)):
2437 for cmd, vals in sorted(pycompat.iteritems(table)):
2437 cmd = cmd.split(b'|')[0]
2438 cmd = cmd.split(b'|')[0]
2438 opts = b', '.join([i[1] for i in vals[1]])
2439 opts = b', '.join([i[1] for i in vals[1]])
2439 ui.write(b'%s: %s\n' % (cmd, opts))
2440 ui.write(b'%s: %s\n' % (cmd, opts))
2440
2441
2441
2442
2442 @command(
2443 @command(
2443 b'debugcomplete',
2444 b'debugcomplete',
2444 [(b'o', b'options', None, _(b'show the command options'))],
2445 [(b'o', b'options', None, _(b'show the command options'))],
2445 _(b'[-o] CMD'),
2446 _(b'[-o] CMD'),
2446 helpcategory=command.CATEGORY_HELP,
2447 helpcategory=command.CATEGORY_HELP,
2447 norepo=True,
2448 norepo=True,
2448 )
2449 )
2449 def debugcomplete(ui, cmd=b'', **opts):
2450 def debugcomplete(ui, cmd=b'', **opts):
2450 """returns the completion list associated with the given command"""
2451 """returns the completion list associated with the given command"""
2451
2452
2452 if opts.get('options'):
2453 if opts.get('options'):
2453 options = []
2454 options = []
2454 otables = [globalopts]
2455 otables = [globalopts]
2455 if cmd:
2456 if cmd:
2456 aliases, entry = cmdutil.findcmd(cmd, table, False)
2457 aliases, entry = cmdutil.findcmd(cmd, table, False)
2457 otables.append(entry[1])
2458 otables.append(entry[1])
2458 for t in otables:
2459 for t in otables:
2459 for o in t:
2460 for o in t:
2460 if b"(DEPRECATED)" in o[3]:
2461 if b"(DEPRECATED)" in o[3]:
2461 continue
2462 continue
2462 if o[0]:
2463 if o[0]:
2463 options.append(b'-%s' % o[0])
2464 options.append(b'-%s' % o[0])
2464 options.append(b'--%s' % o[1])
2465 options.append(b'--%s' % o[1])
2465 ui.write(b"%s\n" % b"\n".join(options))
2466 ui.write(b"%s\n" % b"\n".join(options))
2466 return
2467 return
2467
2468
2468 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2469 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2469 if ui.verbose:
2470 if ui.verbose:
2470 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2471 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2471 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2472 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2472
2473
2473
2474
2474 @command(
2475 @command(
2475 b'diff',
2476 b'diff',
2476 [
2477 [
2477 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2478 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2478 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2479 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2479 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2480 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2480 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2481 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2481 ]
2482 ]
2482 + diffopts
2483 + diffopts
2483 + diffopts2
2484 + diffopts2
2484 + walkopts
2485 + walkopts
2485 + subrepoopts,
2486 + subrepoopts,
2486 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2487 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2487 helpcategory=command.CATEGORY_FILE_CONTENTS,
2488 helpcategory=command.CATEGORY_FILE_CONTENTS,
2488 helpbasic=True,
2489 helpbasic=True,
2489 inferrepo=True,
2490 inferrepo=True,
2490 intents={INTENT_READONLY},
2491 intents={INTENT_READONLY},
2491 )
2492 )
2492 def diff(ui, repo, *pats, **opts):
2493 def diff(ui, repo, *pats, **opts):
2493 """diff repository (or selected files)
2494 """diff repository (or selected files)
2494
2495
2495 Show differences between revisions for the specified files.
2496 Show differences between revisions for the specified files.
2496
2497
2497 Differences between files are shown using the unified diff format.
2498 Differences between files are shown using the unified diff format.
2498
2499
2499 .. note::
2500 .. note::
2500
2501
2501 :hg:`diff` may generate unexpected results for merges, as it will
2502 :hg:`diff` may generate unexpected results for merges, as it will
2502 default to comparing against the working directory's first
2503 default to comparing against the working directory's first
2503 parent changeset if no revisions are specified.
2504 parent changeset if no revisions are specified.
2504
2505
2505 By default, the working directory files are compared to its first parent. To
2506 By default, the working directory files are compared to its first parent. To
2506 see the differences from another revision, use --from. To see the difference
2507 see the differences from another revision, use --from. To see the difference
2507 to another revision, use --to. For example, :hg:`diff --from .^` will show
2508 to another revision, use --to. For example, :hg:`diff --from .^` will show
2508 the differences from the working copy's grandparent to the working copy,
2509 the differences from the working copy's grandparent to the working copy,
2509 :hg:`diff --to .` will show the diff from the working copy to its parent
2510 :hg:`diff --to .` will show the diff from the working copy to its parent
2510 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2511 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2511 show the diff between those two revisions.
2512 show the diff between those two revisions.
2512
2513
2513 Alternatively you can specify -c/--change with a revision to see the changes
2514 Alternatively you can specify -c/--change with a revision to see the changes
2514 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2515 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2515 equivalent to :hg:`diff --from 42^ --to 42`)
2516 equivalent to :hg:`diff --from 42^ --to 42`)
2516
2517
2517 Without the -a/--text option, diff will avoid generating diffs of
2518 Without the -a/--text option, diff will avoid generating diffs of
2518 files it detects as binary. With -a, diff will generate a diff
2519 files it detects as binary. With -a, diff will generate a diff
2519 anyway, probably with undesirable results.
2520 anyway, probably with undesirable results.
2520
2521
2521 Use the -g/--git option to generate diffs in the git extended diff
2522 Use the -g/--git option to generate diffs in the git extended diff
2522 format. For more information, read :hg:`help diffs`.
2523 format. For more information, read :hg:`help diffs`.
2523
2524
2524 .. container:: verbose
2525 .. container:: verbose
2525
2526
2526 Examples:
2527 Examples:
2527
2528
2528 - compare a file in the current working directory to its parent::
2529 - compare a file in the current working directory to its parent::
2529
2530
2530 hg diff foo.c
2531 hg diff foo.c
2531
2532
2532 - compare two historical versions of a directory, with rename info::
2533 - compare two historical versions of a directory, with rename info::
2533
2534
2534 hg diff --git --from 1.0 --to 1.2 lib/
2535 hg diff --git --from 1.0 --to 1.2 lib/
2535
2536
2536 - get change stats relative to the last change on some date::
2537 - get change stats relative to the last change on some date::
2537
2538
2538 hg diff --stat --from "date('may 2')"
2539 hg diff --stat --from "date('may 2')"
2539
2540
2540 - diff all newly-added files that contain a keyword::
2541 - diff all newly-added files that contain a keyword::
2541
2542
2542 hg diff "set:added() and grep(GNU)"
2543 hg diff "set:added() and grep(GNU)"
2543
2544
2544 - compare a revision and its parents::
2545 - compare a revision and its parents::
2545
2546
2546 hg diff -c 9353 # compare against first parent
2547 hg diff -c 9353 # compare against first parent
2547 hg diff --from 9353^ --to 9353 # same using revset syntax
2548 hg diff --from 9353^ --to 9353 # same using revset syntax
2548 hg diff --from 9353^2 --to 9353 # compare against the second parent
2549 hg diff --from 9353^2 --to 9353 # compare against the second parent
2549
2550
2550 Returns 0 on success.
2551 Returns 0 on success.
2551 """
2552 """
2552
2553
2553 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2554 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2554 opts = pycompat.byteskwargs(opts)
2555 opts = pycompat.byteskwargs(opts)
2555 revs = opts.get(b'rev')
2556 revs = opts.get(b'rev')
2556 change = opts.get(b'change')
2557 change = opts.get(b'change')
2557 from_rev = opts.get(b'from')
2558 from_rev = opts.get(b'from')
2558 to_rev = opts.get(b'to')
2559 to_rev = opts.get(b'to')
2559 stat = opts.get(b'stat')
2560 stat = opts.get(b'stat')
2560 reverse = opts.get(b'reverse')
2561 reverse = opts.get(b'reverse')
2561
2562
2562 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2563 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2563 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2564 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2564 if change:
2565 if change:
2565 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2566 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2566 ctx2 = scmutil.revsingle(repo, change, None)
2567 ctx2 = scmutil.revsingle(repo, change, None)
2567 ctx1 = logcmdutil.diff_parent(ctx2)
2568 ctx1 = logcmdutil.diff_parent(ctx2)
2568 elif from_rev or to_rev:
2569 elif from_rev or to_rev:
2569 repo = scmutil.unhidehashlikerevs(
2570 repo = scmutil.unhidehashlikerevs(
2570 repo, [from_rev] + [to_rev], b'nowarn'
2571 repo, [from_rev] + [to_rev], b'nowarn'
2571 )
2572 )
2572 ctx1 = scmutil.revsingle(repo, from_rev, None)
2573 ctx1 = scmutil.revsingle(repo, from_rev, None)
2573 ctx2 = scmutil.revsingle(repo, to_rev, None)
2574 ctx2 = scmutil.revsingle(repo, to_rev, None)
2574 else:
2575 else:
2575 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2576 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2576 ctx1, ctx2 = scmutil.revpair(repo, revs)
2577 ctx1, ctx2 = scmutil.revpair(repo, revs)
2577
2578
2578 if reverse:
2579 if reverse:
2579 ctxleft = ctx2
2580 ctxleft = ctx2
2580 ctxright = ctx1
2581 ctxright = ctx1
2581 else:
2582 else:
2582 ctxleft = ctx1
2583 ctxleft = ctx1
2583 ctxright = ctx2
2584 ctxright = ctx2
2584
2585
2585 diffopts = patch.diffallopts(ui, opts)
2586 diffopts = patch.diffallopts(ui, opts)
2586 m = scmutil.match(ctx2, pats, opts)
2587 m = scmutil.match(ctx2, pats, opts)
2587 m = repo.narrowmatch(m)
2588 m = repo.narrowmatch(m)
2588 ui.pager(b'diff')
2589 ui.pager(b'diff')
2589 logcmdutil.diffordiffstat(
2590 logcmdutil.diffordiffstat(
2590 ui,
2591 ui,
2591 repo,
2592 repo,
2592 diffopts,
2593 diffopts,
2593 ctxleft,
2594 ctxleft,
2594 ctxright,
2595 ctxright,
2595 m,
2596 m,
2596 stat=stat,
2597 stat=stat,
2597 listsubrepos=opts.get(b'subrepos'),
2598 listsubrepos=opts.get(b'subrepos'),
2598 root=opts.get(b'root'),
2599 root=opts.get(b'root'),
2599 )
2600 )
2600
2601
2601
2602
2602 @command(
2603 @command(
2603 b'export',
2604 b'export',
2604 [
2605 [
2605 (
2606 (
2606 b'B',
2607 b'B',
2607 b'bookmark',
2608 b'bookmark',
2608 b'',
2609 b'',
2609 _(b'export changes only reachable by given bookmark'),
2610 _(b'export changes only reachable by given bookmark'),
2610 _(b'BOOKMARK'),
2611 _(b'BOOKMARK'),
2611 ),
2612 ),
2612 (
2613 (
2613 b'o',
2614 b'o',
2614 b'output',
2615 b'output',
2615 b'',
2616 b'',
2616 _(b'print output to file with formatted name'),
2617 _(b'print output to file with formatted name'),
2617 _(b'FORMAT'),
2618 _(b'FORMAT'),
2618 ),
2619 ),
2619 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2620 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2620 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2621 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2621 ]
2622 ]
2622 + diffopts
2623 + diffopts
2623 + formatteropts,
2624 + formatteropts,
2624 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2625 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2625 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2626 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2626 helpbasic=True,
2627 helpbasic=True,
2627 intents={INTENT_READONLY},
2628 intents={INTENT_READONLY},
2628 )
2629 )
2629 def export(ui, repo, *changesets, **opts):
2630 def export(ui, repo, *changesets, **opts):
2630 """dump the header and diffs for one or more changesets
2631 """dump the header and diffs for one or more changesets
2631
2632
2632 Print the changeset header and diffs for one or more revisions.
2633 Print the changeset header and diffs for one or more revisions.
2633 If no revision is given, the parent of the working directory is used.
2634 If no revision is given, the parent of the working directory is used.
2634
2635
2635 The information shown in the changeset header is: author, date,
2636 The information shown in the changeset header is: author, date,
2636 branch name (if non-default), changeset hash, parent(s) and commit
2637 branch name (if non-default), changeset hash, parent(s) and commit
2637 comment.
2638 comment.
2638
2639
2639 .. note::
2640 .. note::
2640
2641
2641 :hg:`export` may generate unexpected diff output for merge
2642 :hg:`export` may generate unexpected diff output for merge
2642 changesets, as it will compare the merge changeset against its
2643 changesets, as it will compare the merge changeset against its
2643 first parent only.
2644 first parent only.
2644
2645
2645 Output may be to a file, in which case the name of the file is
2646 Output may be to a file, in which case the name of the file is
2646 given using a template string. See :hg:`help templates`. In addition
2647 given using a template string. See :hg:`help templates`. In addition
2647 to the common template keywords, the following formatting rules are
2648 to the common template keywords, the following formatting rules are
2648 supported:
2649 supported:
2649
2650
2650 :``%%``: literal "%" character
2651 :``%%``: literal "%" character
2651 :``%H``: changeset hash (40 hexadecimal digits)
2652 :``%H``: changeset hash (40 hexadecimal digits)
2652 :``%N``: number of patches being generated
2653 :``%N``: number of patches being generated
2653 :``%R``: changeset revision number
2654 :``%R``: changeset revision number
2654 :``%b``: basename of the exporting repository
2655 :``%b``: basename of the exporting repository
2655 :``%h``: short-form changeset hash (12 hexadecimal digits)
2656 :``%h``: short-form changeset hash (12 hexadecimal digits)
2656 :``%m``: first line of the commit message (only alphanumeric characters)
2657 :``%m``: first line of the commit message (only alphanumeric characters)
2657 :``%n``: zero-padded sequence number, starting at 1
2658 :``%n``: zero-padded sequence number, starting at 1
2658 :``%r``: zero-padded changeset revision number
2659 :``%r``: zero-padded changeset revision number
2659 :``\\``: literal "\\" character
2660 :``\\``: literal "\\" character
2660
2661
2661 Without the -a/--text option, export will avoid generating diffs
2662 Without the -a/--text option, export will avoid generating diffs
2662 of files it detects as binary. With -a, export will generate a
2663 of files it detects as binary. With -a, export will generate a
2663 diff anyway, probably with undesirable results.
2664 diff anyway, probably with undesirable results.
2664
2665
2665 With -B/--bookmark changesets reachable by the given bookmark are
2666 With -B/--bookmark changesets reachable by the given bookmark are
2666 selected.
2667 selected.
2667
2668
2668 Use the -g/--git option to generate diffs in the git extended diff
2669 Use the -g/--git option to generate diffs in the git extended diff
2669 format. See :hg:`help diffs` for more information.
2670 format. See :hg:`help diffs` for more information.
2670
2671
2671 With the --switch-parent option, the diff will be against the
2672 With the --switch-parent option, the diff will be against the
2672 second parent. It can be useful to review a merge.
2673 second parent. It can be useful to review a merge.
2673
2674
2674 .. container:: verbose
2675 .. container:: verbose
2675
2676
2676 Template:
2677 Template:
2677
2678
2678 The following keywords are supported in addition to the common template
2679 The following keywords are supported in addition to the common template
2679 keywords and functions. See also :hg:`help templates`.
2680 keywords and functions. See also :hg:`help templates`.
2680
2681
2681 :diff: String. Diff content.
2682 :diff: String. Diff content.
2682 :parents: List of strings. Parent nodes of the changeset.
2683 :parents: List of strings. Parent nodes of the changeset.
2683
2684
2684 Examples:
2685 Examples:
2685
2686
2686 - use export and import to transplant a bugfix to the current
2687 - use export and import to transplant a bugfix to the current
2687 branch::
2688 branch::
2688
2689
2689 hg export -r 9353 | hg import -
2690 hg export -r 9353 | hg import -
2690
2691
2691 - export all the changesets between two revisions to a file with
2692 - export all the changesets between two revisions to a file with
2692 rename information::
2693 rename information::
2693
2694
2694 hg export --git -r 123:150 > changes.txt
2695 hg export --git -r 123:150 > changes.txt
2695
2696
2696 - split outgoing changes into a series of patches with
2697 - split outgoing changes into a series of patches with
2697 descriptive names::
2698 descriptive names::
2698
2699
2699 hg export -r "outgoing()" -o "%n-%m.patch"
2700 hg export -r "outgoing()" -o "%n-%m.patch"
2700
2701
2701 Returns 0 on success.
2702 Returns 0 on success.
2702 """
2703 """
2703 opts = pycompat.byteskwargs(opts)
2704 opts = pycompat.byteskwargs(opts)
2704 bookmark = opts.get(b'bookmark')
2705 bookmark = opts.get(b'bookmark')
2705 changesets += tuple(opts.get(b'rev', []))
2706 changesets += tuple(opts.get(b'rev', []))
2706
2707
2707 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2708 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2708
2709
2709 if bookmark:
2710 if bookmark:
2710 if bookmark not in repo._bookmarks:
2711 if bookmark not in repo._bookmarks:
2711 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2712 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2712
2713
2713 revs = scmutil.bookmarkrevs(repo, bookmark)
2714 revs = scmutil.bookmarkrevs(repo, bookmark)
2714 else:
2715 else:
2715 if not changesets:
2716 if not changesets:
2716 changesets = [b'.']
2717 changesets = [b'.']
2717
2718
2718 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2719 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2719 revs = scmutil.revrange(repo, changesets)
2720 revs = scmutil.revrange(repo, changesets)
2720
2721
2721 if not revs:
2722 if not revs:
2722 raise error.InputError(_(b"export requires at least one changeset"))
2723 raise error.InputError(_(b"export requires at least one changeset"))
2723 if len(revs) > 1:
2724 if len(revs) > 1:
2724 ui.note(_(b'exporting patches:\n'))
2725 ui.note(_(b'exporting patches:\n'))
2725 else:
2726 else:
2726 ui.note(_(b'exporting patch:\n'))
2727 ui.note(_(b'exporting patch:\n'))
2727
2728
2728 fntemplate = opts.get(b'output')
2729 fntemplate = opts.get(b'output')
2729 if cmdutil.isstdiofilename(fntemplate):
2730 if cmdutil.isstdiofilename(fntemplate):
2730 fntemplate = b''
2731 fntemplate = b''
2731
2732
2732 if fntemplate:
2733 if fntemplate:
2733 fm = formatter.nullformatter(ui, b'export', opts)
2734 fm = formatter.nullformatter(ui, b'export', opts)
2734 else:
2735 else:
2735 ui.pager(b'export')
2736 ui.pager(b'export')
2736 fm = ui.formatter(b'export', opts)
2737 fm = ui.formatter(b'export', opts)
2737 with fm:
2738 with fm:
2738 cmdutil.export(
2739 cmdutil.export(
2739 repo,
2740 repo,
2740 revs,
2741 revs,
2741 fm,
2742 fm,
2742 fntemplate=fntemplate,
2743 fntemplate=fntemplate,
2743 switch_parent=opts.get(b'switch_parent'),
2744 switch_parent=opts.get(b'switch_parent'),
2744 opts=patch.diffallopts(ui, opts),
2745 opts=patch.diffallopts(ui, opts),
2745 )
2746 )
2746
2747
2747
2748
2748 @command(
2749 @command(
2749 b'files',
2750 b'files',
2750 [
2751 [
2751 (
2752 (
2752 b'r',
2753 b'r',
2753 b'rev',
2754 b'rev',
2754 b'',
2755 b'',
2755 _(b'search the repository as it is in REV'),
2756 _(b'search the repository as it is in REV'),
2756 _(b'REV'),
2757 _(b'REV'),
2757 ),
2758 ),
2758 (
2759 (
2759 b'0',
2760 b'0',
2760 b'print0',
2761 b'print0',
2761 None,
2762 None,
2762 _(b'end filenames with NUL, for use with xargs'),
2763 _(b'end filenames with NUL, for use with xargs'),
2763 ),
2764 ),
2764 ]
2765 ]
2765 + walkopts
2766 + walkopts
2766 + formatteropts
2767 + formatteropts
2767 + subrepoopts,
2768 + subrepoopts,
2768 _(b'[OPTION]... [FILE]...'),
2769 _(b'[OPTION]... [FILE]...'),
2769 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2770 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2770 intents={INTENT_READONLY},
2771 intents={INTENT_READONLY},
2771 )
2772 )
2772 def files(ui, repo, *pats, **opts):
2773 def files(ui, repo, *pats, **opts):
2773 """list tracked files
2774 """list tracked files
2774
2775
2775 Print files under Mercurial control in the working directory or
2776 Print files under Mercurial control in the working directory or
2776 specified revision for given files (excluding removed files).
2777 specified revision for given files (excluding removed files).
2777 Files can be specified as filenames or filesets.
2778 Files can be specified as filenames or filesets.
2778
2779
2779 If no files are given to match, this command prints the names
2780 If no files are given to match, this command prints the names
2780 of all files under Mercurial control.
2781 of all files under Mercurial control.
2781
2782
2782 .. container:: verbose
2783 .. container:: verbose
2783
2784
2784 Template:
2785 Template:
2785
2786
2786 The following keywords are supported in addition to the common template
2787 The following keywords are supported in addition to the common template
2787 keywords and functions. See also :hg:`help templates`.
2788 keywords and functions. See also :hg:`help templates`.
2788
2789
2789 :flags: String. Character denoting file's symlink and executable bits.
2790 :flags: String. Character denoting file's symlink and executable bits.
2790 :path: String. Repository-absolute path of the file.
2791 :path: String. Repository-absolute path of the file.
2791 :size: Integer. Size of the file in bytes.
2792 :size: Integer. Size of the file in bytes.
2792
2793
2793 Examples:
2794 Examples:
2794
2795
2795 - list all files under the current directory::
2796 - list all files under the current directory::
2796
2797
2797 hg files .
2798 hg files .
2798
2799
2799 - shows sizes and flags for current revision::
2800 - shows sizes and flags for current revision::
2800
2801
2801 hg files -vr .
2802 hg files -vr .
2802
2803
2803 - list all files named README::
2804 - list all files named README::
2804
2805
2805 hg files -I "**/README"
2806 hg files -I "**/README"
2806
2807
2807 - list all binary files::
2808 - list all binary files::
2808
2809
2809 hg files "set:binary()"
2810 hg files "set:binary()"
2810
2811
2811 - find files containing a regular expression::
2812 - find files containing a regular expression::
2812
2813
2813 hg files "set:grep('bob')"
2814 hg files "set:grep('bob')"
2814
2815
2815 - search tracked file contents with xargs and grep::
2816 - search tracked file contents with xargs and grep::
2816
2817
2817 hg files -0 | xargs -0 grep foo
2818 hg files -0 | xargs -0 grep foo
2818
2819
2819 See :hg:`help patterns` and :hg:`help filesets` for more information
2820 See :hg:`help patterns` and :hg:`help filesets` for more information
2820 on specifying file patterns.
2821 on specifying file patterns.
2821
2822
2822 Returns 0 if a match is found, 1 otherwise.
2823 Returns 0 if a match is found, 1 otherwise.
2823
2824
2824 """
2825 """
2825
2826
2826 opts = pycompat.byteskwargs(opts)
2827 opts = pycompat.byteskwargs(opts)
2827 rev = opts.get(b'rev')
2828 rev = opts.get(b'rev')
2828 if rev:
2829 if rev:
2829 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2830 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2830 ctx = scmutil.revsingle(repo, rev, None)
2831 ctx = scmutil.revsingle(repo, rev, None)
2831
2832
2832 end = b'\n'
2833 end = b'\n'
2833 if opts.get(b'print0'):
2834 if opts.get(b'print0'):
2834 end = b'\0'
2835 end = b'\0'
2835 fmt = b'%s' + end
2836 fmt = b'%s' + end
2836
2837
2837 m = scmutil.match(ctx, pats, opts)
2838 m = scmutil.match(ctx, pats, opts)
2838 ui.pager(b'files')
2839 ui.pager(b'files')
2839 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2840 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2840 with ui.formatter(b'files', opts) as fm:
2841 with ui.formatter(b'files', opts) as fm:
2841 return cmdutil.files(
2842 return cmdutil.files(
2842 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2843 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2843 )
2844 )
2844
2845
2845
2846
2846 @command(
2847 @command(
2847 b'forget',
2848 b'forget',
2848 [
2849 [
2849 (b'i', b'interactive', None, _(b'use interactive mode')),
2850 (b'i', b'interactive', None, _(b'use interactive mode')),
2850 ]
2851 ]
2851 + walkopts
2852 + walkopts
2852 + dryrunopts,
2853 + dryrunopts,
2853 _(b'[OPTION]... FILE...'),
2854 _(b'[OPTION]... FILE...'),
2854 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2855 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2855 helpbasic=True,
2856 helpbasic=True,
2856 inferrepo=True,
2857 inferrepo=True,
2857 )
2858 )
2858 def forget(ui, repo, *pats, **opts):
2859 def forget(ui, repo, *pats, **opts):
2859 """forget the specified files on the next commit
2860 """forget the specified files on the next commit
2860
2861
2861 Mark the specified files so they will no longer be tracked
2862 Mark the specified files so they will no longer be tracked
2862 after the next commit.
2863 after the next commit.
2863
2864
2864 This only removes files from the current branch, not from the
2865 This only removes files from the current branch, not from the
2865 entire project history, and it does not delete them from the
2866 entire project history, and it does not delete them from the
2866 working directory.
2867 working directory.
2867
2868
2868 To delete the file from the working directory, see :hg:`remove`.
2869 To delete the file from the working directory, see :hg:`remove`.
2869
2870
2870 To undo a forget before the next commit, see :hg:`add`.
2871 To undo a forget before the next commit, see :hg:`add`.
2871
2872
2872 .. container:: verbose
2873 .. container:: verbose
2873
2874
2874 Examples:
2875 Examples:
2875
2876
2876 - forget newly-added binary files::
2877 - forget newly-added binary files::
2877
2878
2878 hg forget "set:added() and binary()"
2879 hg forget "set:added() and binary()"
2879
2880
2880 - forget files that would be excluded by .hgignore::
2881 - forget files that would be excluded by .hgignore::
2881
2882
2882 hg forget "set:hgignore()"
2883 hg forget "set:hgignore()"
2883
2884
2884 Returns 0 on success.
2885 Returns 0 on success.
2885 """
2886 """
2886
2887
2887 opts = pycompat.byteskwargs(opts)
2888 opts = pycompat.byteskwargs(opts)
2888 if not pats:
2889 if not pats:
2889 raise error.InputError(_(b'no files specified'))
2890 raise error.InputError(_(b'no files specified'))
2890
2891
2891 m = scmutil.match(repo[None], pats, opts)
2892 m = scmutil.match(repo[None], pats, opts)
2892 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2893 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2893 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2894 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2894 rejected = cmdutil.forget(
2895 rejected = cmdutil.forget(
2895 ui,
2896 ui,
2896 repo,
2897 repo,
2897 m,
2898 m,
2898 prefix=b"",
2899 prefix=b"",
2899 uipathfn=uipathfn,
2900 uipathfn=uipathfn,
2900 explicitonly=False,
2901 explicitonly=False,
2901 dryrun=dryrun,
2902 dryrun=dryrun,
2902 interactive=interactive,
2903 interactive=interactive,
2903 )[0]
2904 )[0]
2904 return rejected and 1 or 0
2905 return rejected and 1 or 0
2905
2906
2906
2907
2907 @command(
2908 @command(
2908 b'graft',
2909 b'graft',
2909 [
2910 [
2910 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2911 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2911 (
2912 (
2912 b'',
2913 b'',
2913 b'base',
2914 b'base',
2914 b'',
2915 b'',
2915 _(b'base revision when doing the graft merge (ADVANCED)'),
2916 _(b'base revision when doing the graft merge (ADVANCED)'),
2916 _(b'REV'),
2917 _(b'REV'),
2917 ),
2918 ),
2918 (b'c', b'continue', False, _(b'resume interrupted graft')),
2919 (b'c', b'continue', False, _(b'resume interrupted graft')),
2919 (b'', b'stop', False, _(b'stop interrupted graft')),
2920 (b'', b'stop', False, _(b'stop interrupted graft')),
2920 (b'', b'abort', False, _(b'abort interrupted graft')),
2921 (b'', b'abort', False, _(b'abort interrupted graft')),
2921 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2922 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2922 (b'', b'log', None, _(b'append graft info to log message')),
2923 (b'', b'log', None, _(b'append graft info to log message')),
2923 (
2924 (
2924 b'',
2925 b'',
2925 b'no-commit',
2926 b'no-commit',
2926 None,
2927 None,
2927 _(b"don't commit, just apply the changes in working directory"),
2928 _(b"don't commit, just apply the changes in working directory"),
2928 ),
2929 ),
2929 (b'f', b'force', False, _(b'force graft')),
2930 (b'f', b'force', False, _(b'force graft')),
2930 (
2931 (
2931 b'D',
2932 b'D',
2932 b'currentdate',
2933 b'currentdate',
2933 False,
2934 False,
2934 _(b'record the current date as commit date'),
2935 _(b'record the current date as commit date'),
2935 ),
2936 ),
2936 (
2937 (
2937 b'U',
2938 b'U',
2938 b'currentuser',
2939 b'currentuser',
2939 False,
2940 False,
2940 _(b'record the current user as committer'),
2941 _(b'record the current user as committer'),
2941 ),
2942 ),
2942 ]
2943 ]
2943 + commitopts2
2944 + commitopts2
2944 + mergetoolopts
2945 + mergetoolopts
2945 + dryrunopts,
2946 + dryrunopts,
2946 _(b'[OPTION]... [-r REV]... REV...'),
2947 _(b'[OPTION]... [-r REV]... REV...'),
2947 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2948 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2948 )
2949 )
2949 def graft(ui, repo, *revs, **opts):
2950 def graft(ui, repo, *revs, **opts):
2950 """copy changes from other branches onto the current branch
2951 """copy changes from other branches onto the current branch
2951
2952
2952 This command uses Mercurial's merge logic to copy individual
2953 This command uses Mercurial's merge logic to copy individual
2953 changes from other branches without merging branches in the
2954 changes from other branches without merging branches in the
2954 history graph. This is sometimes known as 'backporting' or
2955 history graph. This is sometimes known as 'backporting' or
2955 'cherry-picking'. By default, graft will copy user, date, and
2956 'cherry-picking'. By default, graft will copy user, date, and
2956 description from the source changesets.
2957 description from the source changesets.
2957
2958
2958 Changesets that are ancestors of the current revision, that have
2959 Changesets that are ancestors of the current revision, that have
2959 already been grafted, or that are merges will be skipped.
2960 already been grafted, or that are merges will be skipped.
2960
2961
2961 If --log is specified, log messages will have a comment appended
2962 If --log is specified, log messages will have a comment appended
2962 of the form::
2963 of the form::
2963
2964
2964 (grafted from CHANGESETHASH)
2965 (grafted from CHANGESETHASH)
2965
2966
2966 If --force is specified, revisions will be grafted even if they
2967 If --force is specified, revisions will be grafted even if they
2967 are already ancestors of, or have been grafted to, the destination.
2968 are already ancestors of, or have been grafted to, the destination.
2968 This is useful when the revisions have since been backed out.
2969 This is useful when the revisions have since been backed out.
2969
2970
2970 If a graft merge results in conflicts, the graft process is
2971 If a graft merge results in conflicts, the graft process is
2971 interrupted so that the current merge can be manually resolved.
2972 interrupted so that the current merge can be manually resolved.
2972 Once all conflicts are addressed, the graft process can be
2973 Once all conflicts are addressed, the graft process can be
2973 continued with the -c/--continue option.
2974 continued with the -c/--continue option.
2974
2975
2975 The -c/--continue option reapplies all the earlier options.
2976 The -c/--continue option reapplies all the earlier options.
2976
2977
2977 .. container:: verbose
2978 .. container:: verbose
2978
2979
2979 The --base option exposes more of how graft internally uses merge with a
2980 The --base option exposes more of how graft internally uses merge with a
2980 custom base revision. --base can be used to specify another ancestor than
2981 custom base revision. --base can be used to specify another ancestor than
2981 the first and only parent.
2982 the first and only parent.
2982
2983
2983 The command::
2984 The command::
2984
2985
2985 hg graft -r 345 --base 234
2986 hg graft -r 345 --base 234
2986
2987
2987 is thus pretty much the same as::
2988 is thus pretty much the same as::
2988
2989
2989 hg diff --from 234 --to 345 | hg import
2990 hg diff --from 234 --to 345 | hg import
2990
2991
2991 but using merge to resolve conflicts and track moved files.
2992 but using merge to resolve conflicts and track moved files.
2992
2993
2993 The result of a merge can thus be backported as a single commit by
2994 The result of a merge can thus be backported as a single commit by
2994 specifying one of the merge parents as base, and thus effectively
2995 specifying one of the merge parents as base, and thus effectively
2995 grafting the changes from the other side.
2996 grafting the changes from the other side.
2996
2997
2997 It is also possible to collapse multiple changesets and clean up history
2998 It is also possible to collapse multiple changesets and clean up history
2998 by specifying another ancestor as base, much like rebase --collapse
2999 by specifying another ancestor as base, much like rebase --collapse
2999 --keep.
3000 --keep.
3000
3001
3001 The commit message can be tweaked after the fact using commit --amend .
3002 The commit message can be tweaked after the fact using commit --amend .
3002
3003
3003 For using non-ancestors as the base to backout changes, see the backout
3004 For using non-ancestors as the base to backout changes, see the backout
3004 command and the hidden --parent option.
3005 command and the hidden --parent option.
3005
3006
3006 .. container:: verbose
3007 .. container:: verbose
3007
3008
3008 Examples:
3009 Examples:
3009
3010
3010 - copy a single change to the stable branch and edit its description::
3011 - copy a single change to the stable branch and edit its description::
3011
3012
3012 hg update stable
3013 hg update stable
3013 hg graft --edit 9393
3014 hg graft --edit 9393
3014
3015
3015 - graft a range of changesets with one exception, updating dates::
3016 - graft a range of changesets with one exception, updating dates::
3016
3017
3017 hg graft -D "2085::2093 and not 2091"
3018 hg graft -D "2085::2093 and not 2091"
3018
3019
3019 - continue a graft after resolving conflicts::
3020 - continue a graft after resolving conflicts::
3020
3021
3021 hg graft -c
3022 hg graft -c
3022
3023
3023 - show the source of a grafted changeset::
3024 - show the source of a grafted changeset::
3024
3025
3025 hg log --debug -r .
3026 hg log --debug -r .
3026
3027
3027 - show revisions sorted by date::
3028 - show revisions sorted by date::
3028
3029
3029 hg log -r "sort(all(), date)"
3030 hg log -r "sort(all(), date)"
3030
3031
3031 - backport the result of a merge as a single commit::
3032 - backport the result of a merge as a single commit::
3032
3033
3033 hg graft -r 123 --base 123^
3034 hg graft -r 123 --base 123^
3034
3035
3035 - land a feature branch as one changeset::
3036 - land a feature branch as one changeset::
3036
3037
3037 hg up -cr default
3038 hg up -cr default
3038 hg graft -r featureX --base "ancestor('featureX', 'default')"
3039 hg graft -r featureX --base "ancestor('featureX', 'default')"
3039
3040
3040 See :hg:`help revisions` for more about specifying revisions.
3041 See :hg:`help revisions` for more about specifying revisions.
3041
3042
3042 Returns 0 on successful completion, 1 if there are unresolved files.
3043 Returns 0 on successful completion, 1 if there are unresolved files.
3043 """
3044 """
3044 with repo.wlock():
3045 with repo.wlock():
3045 return _dograft(ui, repo, *revs, **opts)
3046 return _dograft(ui, repo, *revs, **opts)
3046
3047
3047
3048
3048 def _dograft(ui, repo, *revs, **opts):
3049 def _dograft(ui, repo, *revs, **opts):
3049 opts = pycompat.byteskwargs(opts)
3050 opts = pycompat.byteskwargs(opts)
3050 if revs and opts.get(b'rev'):
3051 if revs and opts.get(b'rev'):
3051 ui.warn(
3052 ui.warn(
3052 _(
3053 _(
3053 b'warning: inconsistent use of --rev might give unexpected '
3054 b'warning: inconsistent use of --rev might give unexpected '
3054 b'revision ordering!\n'
3055 b'revision ordering!\n'
3055 )
3056 )
3056 )
3057 )
3057
3058
3058 revs = list(revs)
3059 revs = list(revs)
3059 revs.extend(opts.get(b'rev'))
3060 revs.extend(opts.get(b'rev'))
3060 # a dict of data to be stored in state file
3061 # a dict of data to be stored in state file
3061 statedata = {}
3062 statedata = {}
3062 # list of new nodes created by ongoing graft
3063 # list of new nodes created by ongoing graft
3063 statedata[b'newnodes'] = []
3064 statedata[b'newnodes'] = []
3064
3065
3065 cmdutil.resolvecommitoptions(ui, opts)
3066 cmdutil.resolvecommitoptions(ui, opts)
3066
3067
3067 editor = cmdutil.getcommiteditor(
3068 editor = cmdutil.getcommiteditor(
3068 editform=b'graft', **pycompat.strkwargs(opts)
3069 editform=b'graft', **pycompat.strkwargs(opts)
3069 )
3070 )
3070
3071
3071 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3072 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3072
3073
3073 cont = False
3074 cont = False
3074 if opts.get(b'no_commit'):
3075 if opts.get(b'no_commit'):
3075 cmdutil.check_incompatible_arguments(
3076 cmdutil.check_incompatible_arguments(
3076 opts,
3077 opts,
3077 b'no_commit',
3078 b'no_commit',
3078 [b'edit', b'currentuser', b'currentdate', b'log'],
3079 [b'edit', b'currentuser', b'currentdate', b'log'],
3079 )
3080 )
3080
3081
3081 graftstate = statemod.cmdstate(repo, b'graftstate')
3082 graftstate = statemod.cmdstate(repo, b'graftstate')
3082
3083
3083 if opts.get(b'stop'):
3084 if opts.get(b'stop'):
3084 cmdutil.check_incompatible_arguments(
3085 cmdutil.check_incompatible_arguments(
3085 opts,
3086 opts,
3086 b'stop',
3087 b'stop',
3087 [
3088 [
3088 b'edit',
3089 b'edit',
3089 b'log',
3090 b'log',
3090 b'user',
3091 b'user',
3091 b'date',
3092 b'date',
3092 b'currentdate',
3093 b'currentdate',
3093 b'currentuser',
3094 b'currentuser',
3094 b'rev',
3095 b'rev',
3095 ],
3096 ],
3096 )
3097 )
3097 return _stopgraft(ui, repo, graftstate)
3098 return _stopgraft(ui, repo, graftstate)
3098 elif opts.get(b'abort'):
3099 elif opts.get(b'abort'):
3099 cmdutil.check_incompatible_arguments(
3100 cmdutil.check_incompatible_arguments(
3100 opts,
3101 opts,
3101 b'abort',
3102 b'abort',
3102 [
3103 [
3103 b'edit',
3104 b'edit',
3104 b'log',
3105 b'log',
3105 b'user',
3106 b'user',
3106 b'date',
3107 b'date',
3107 b'currentdate',
3108 b'currentdate',
3108 b'currentuser',
3109 b'currentuser',
3109 b'rev',
3110 b'rev',
3110 ],
3111 ],
3111 )
3112 )
3112 return cmdutil.abortgraft(ui, repo, graftstate)
3113 return cmdutil.abortgraft(ui, repo, graftstate)
3113 elif opts.get(b'continue'):
3114 elif opts.get(b'continue'):
3114 cont = True
3115 cont = True
3115 if revs:
3116 if revs:
3116 raise error.InputError(_(b"can't specify --continue and revisions"))
3117 raise error.InputError(_(b"can't specify --continue and revisions"))
3117 # read in unfinished revisions
3118 # read in unfinished revisions
3118 if graftstate.exists():
3119 if graftstate.exists():
3119 statedata = cmdutil.readgraftstate(repo, graftstate)
3120 statedata = cmdutil.readgraftstate(repo, graftstate)
3120 if statedata.get(b'date'):
3121 if statedata.get(b'date'):
3121 opts[b'date'] = statedata[b'date']
3122 opts[b'date'] = statedata[b'date']
3122 if statedata.get(b'user'):
3123 if statedata.get(b'user'):
3123 opts[b'user'] = statedata[b'user']
3124 opts[b'user'] = statedata[b'user']
3124 if statedata.get(b'log'):
3125 if statedata.get(b'log'):
3125 opts[b'log'] = True
3126 opts[b'log'] = True
3126 if statedata.get(b'no_commit'):
3127 if statedata.get(b'no_commit'):
3127 opts[b'no_commit'] = statedata.get(b'no_commit')
3128 opts[b'no_commit'] = statedata.get(b'no_commit')
3128 if statedata.get(b'base'):
3129 if statedata.get(b'base'):
3129 opts[b'base'] = statedata.get(b'base')
3130 opts[b'base'] = statedata.get(b'base')
3130 nodes = statedata[b'nodes']
3131 nodes = statedata[b'nodes']
3131 revs = [repo[node].rev() for node in nodes]
3132 revs = [repo[node].rev() for node in nodes]
3132 else:
3133 else:
3133 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3134 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3134 else:
3135 else:
3135 if not revs:
3136 if not revs:
3136 raise error.InputError(_(b'no revisions specified'))
3137 raise error.InputError(_(b'no revisions specified'))
3137 cmdutil.checkunfinished(repo)
3138 cmdutil.checkunfinished(repo)
3138 cmdutil.bailifchanged(repo)
3139 cmdutil.bailifchanged(repo)
3139 revs = scmutil.revrange(repo, revs)
3140 revs = scmutil.revrange(repo, revs)
3140
3141
3141 skipped = set()
3142 skipped = set()
3142 basectx = None
3143 basectx = None
3143 if opts.get(b'base'):
3144 if opts.get(b'base'):
3144 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3145 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3145 if basectx is None:
3146 if basectx is None:
3146 # check for merges
3147 # check for merges
3147 for rev in repo.revs(b'%ld and merge()', revs):
3148 for rev in repo.revs(b'%ld and merge()', revs):
3148 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3149 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3149 skipped.add(rev)
3150 skipped.add(rev)
3150 revs = [r for r in revs if r not in skipped]
3151 revs = [r for r in revs if r not in skipped]
3151 if not revs:
3152 if not revs:
3152 return -1
3153 return -1
3153 if basectx is not None and len(revs) != 1:
3154 if basectx is not None and len(revs) != 1:
3154 raise error.InputError(_(b'only one revision allowed with --base '))
3155 raise error.InputError(_(b'only one revision allowed with --base '))
3155
3156
3156 # Don't check in the --continue case, in effect retaining --force across
3157 # Don't check in the --continue case, in effect retaining --force across
3157 # --continues. That's because without --force, any revisions we decided to
3158 # --continues. That's because without --force, any revisions we decided to
3158 # skip would have been filtered out here, so they wouldn't have made their
3159 # skip would have been filtered out here, so they wouldn't have made their
3159 # way to the graftstate. With --force, any revisions we would have otherwise
3160 # way to the graftstate. With --force, any revisions we would have otherwise
3160 # skipped would not have been filtered out, and if they hadn't been applied
3161 # skipped would not have been filtered out, and if they hadn't been applied
3161 # already, they'd have been in the graftstate.
3162 # already, they'd have been in the graftstate.
3162 if not (cont or opts.get(b'force')) and basectx is None:
3163 if not (cont or opts.get(b'force')) and basectx is None:
3163 # check for ancestors of dest branch
3164 # check for ancestors of dest branch
3164 ancestors = repo.revs(b'%ld & (::.)', revs)
3165 ancestors = repo.revs(b'%ld & (::.)', revs)
3165 for rev in ancestors:
3166 for rev in ancestors:
3166 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3167 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3167
3168
3168 revs = [r for r in revs if r not in ancestors]
3169 revs = [r for r in revs if r not in ancestors]
3169
3170
3170 if not revs:
3171 if not revs:
3171 return -1
3172 return -1
3172
3173
3173 # analyze revs for earlier grafts
3174 # analyze revs for earlier grafts
3174 ids = {}
3175 ids = {}
3175 for ctx in repo.set(b"%ld", revs):
3176 for ctx in repo.set(b"%ld", revs):
3176 ids[ctx.hex()] = ctx.rev()
3177 ids[ctx.hex()] = ctx.rev()
3177 n = ctx.extra().get(b'source')
3178 n = ctx.extra().get(b'source')
3178 if n:
3179 if n:
3179 ids[n] = ctx.rev()
3180 ids[n] = ctx.rev()
3180
3181
3181 # check ancestors for earlier grafts
3182 # check ancestors for earlier grafts
3182 ui.debug(b'scanning for duplicate grafts\n')
3183 ui.debug(b'scanning for duplicate grafts\n')
3183
3184
3184 # The only changesets we can be sure doesn't contain grafts of any
3185 # The only changesets we can be sure doesn't contain grafts of any
3185 # revs, are the ones that are common ancestors of *all* revs:
3186 # revs, are the ones that are common ancestors of *all* revs:
3186 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3187 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3187 ctx = repo[rev]
3188 ctx = repo[rev]
3188 n = ctx.extra().get(b'source')
3189 n = ctx.extra().get(b'source')
3189 if n in ids:
3190 if n in ids:
3190 try:
3191 try:
3191 r = repo[n].rev()
3192 r = repo[n].rev()
3192 except error.RepoLookupError:
3193 except error.RepoLookupError:
3193 r = None
3194 r = None
3194 if r in revs:
3195 if r in revs:
3195 ui.warn(
3196 ui.warn(
3196 _(
3197 _(
3197 b'skipping revision %d:%s '
3198 b'skipping revision %d:%s '
3198 b'(already grafted to %d:%s)\n'
3199 b'(already grafted to %d:%s)\n'
3199 )
3200 )
3200 % (r, repo[r], rev, ctx)
3201 % (r, repo[r], rev, ctx)
3201 )
3202 )
3202 revs.remove(r)
3203 revs.remove(r)
3203 elif ids[n] in revs:
3204 elif ids[n] in revs:
3204 if r is None:
3205 if r is None:
3205 ui.warn(
3206 ui.warn(
3206 _(
3207 _(
3207 b'skipping already grafted revision %d:%s '
3208 b'skipping already grafted revision %d:%s '
3208 b'(%d:%s also has unknown origin %s)\n'
3209 b'(%d:%s also has unknown origin %s)\n'
3209 )
3210 )
3210 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3211 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3211 )
3212 )
3212 else:
3213 else:
3213 ui.warn(
3214 ui.warn(
3214 _(
3215 _(
3215 b'skipping already grafted revision %d:%s '
3216 b'skipping already grafted revision %d:%s '
3216 b'(%d:%s also has origin %d:%s)\n'
3217 b'(%d:%s also has origin %d:%s)\n'
3217 )
3218 )
3218 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3219 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3219 )
3220 )
3220 revs.remove(ids[n])
3221 revs.remove(ids[n])
3221 elif ctx.hex() in ids:
3222 elif ctx.hex() in ids:
3222 r = ids[ctx.hex()]
3223 r = ids[ctx.hex()]
3223 if r in revs:
3224 if r in revs:
3224 ui.warn(
3225 ui.warn(
3225 _(
3226 _(
3226 b'skipping already grafted revision %d:%s '
3227 b'skipping already grafted revision %d:%s '
3227 b'(was grafted from %d:%s)\n'
3228 b'(was grafted from %d:%s)\n'
3228 )
3229 )
3229 % (r, repo[r], rev, ctx)
3230 % (r, repo[r], rev, ctx)
3230 )
3231 )
3231 revs.remove(r)
3232 revs.remove(r)
3232 if not revs:
3233 if not revs:
3233 return -1
3234 return -1
3234
3235
3235 if opts.get(b'no_commit'):
3236 if opts.get(b'no_commit'):
3236 statedata[b'no_commit'] = True
3237 statedata[b'no_commit'] = True
3237 if opts.get(b'base'):
3238 if opts.get(b'base'):
3238 statedata[b'base'] = opts[b'base']
3239 statedata[b'base'] = opts[b'base']
3239 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3240 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3240 desc = b'%d:%s "%s"' % (
3241 desc = b'%d:%s "%s"' % (
3241 ctx.rev(),
3242 ctx.rev(),
3242 ctx,
3243 ctx,
3243 ctx.description().split(b'\n', 1)[0],
3244 ctx.description().split(b'\n', 1)[0],
3244 )
3245 )
3245 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3246 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3246 if names:
3247 if names:
3247 desc += b' (%s)' % b' '.join(names)
3248 desc += b' (%s)' % b' '.join(names)
3248 ui.status(_(b'grafting %s\n') % desc)
3249 ui.status(_(b'grafting %s\n') % desc)
3249 if opts.get(b'dry_run'):
3250 if opts.get(b'dry_run'):
3250 continue
3251 continue
3251
3252
3252 source = ctx.extra().get(b'source')
3253 source = ctx.extra().get(b'source')
3253 extra = {}
3254 extra = {}
3254 if source:
3255 if source:
3255 extra[b'source'] = source
3256 extra[b'source'] = source
3256 extra[b'intermediate-source'] = ctx.hex()
3257 extra[b'intermediate-source'] = ctx.hex()
3257 else:
3258 else:
3258 extra[b'source'] = ctx.hex()
3259 extra[b'source'] = ctx.hex()
3259 user = ctx.user()
3260 user = ctx.user()
3260 if opts.get(b'user'):
3261 if opts.get(b'user'):
3261 user = opts[b'user']
3262 user = opts[b'user']
3262 statedata[b'user'] = user
3263 statedata[b'user'] = user
3263 date = ctx.date()
3264 date = ctx.date()
3264 if opts.get(b'date'):
3265 if opts.get(b'date'):
3265 date = opts[b'date']
3266 date = opts[b'date']
3266 statedata[b'date'] = date
3267 statedata[b'date'] = date
3267 message = ctx.description()
3268 message = ctx.description()
3268 if opts.get(b'log'):
3269 if opts.get(b'log'):
3269 message += b'\n(grafted from %s)' % ctx.hex()
3270 message += b'\n(grafted from %s)' % ctx.hex()
3270 statedata[b'log'] = True
3271 statedata[b'log'] = True
3271
3272
3272 # we don't merge the first commit when continuing
3273 # we don't merge the first commit when continuing
3273 if not cont:
3274 if not cont:
3274 # perform the graft merge with p1(rev) as 'ancestor'
3275 # perform the graft merge with p1(rev) as 'ancestor'
3275 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3276 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3276 base = ctx.p1() if basectx is None else basectx
3277 base = ctx.p1() if basectx is None else basectx
3277 with ui.configoverride(overrides, b'graft'):
3278 with ui.configoverride(overrides, b'graft'):
3278 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3279 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3279 # report any conflicts
3280 # report any conflicts
3280 if stats.unresolvedcount > 0:
3281 if stats.unresolvedcount > 0:
3281 # write out state for --continue
3282 # write out state for --continue
3282 nodes = [repo[rev].hex() for rev in revs[pos:]]
3283 nodes = [repo[rev].hex() for rev in revs[pos:]]
3283 statedata[b'nodes'] = nodes
3284 statedata[b'nodes'] = nodes
3284 stateversion = 1
3285 stateversion = 1
3285 graftstate.save(stateversion, statedata)
3286 graftstate.save(stateversion, statedata)
3286 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3287 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3287 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3288 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3288 return 1
3289 return 1
3289 else:
3290 else:
3290 cont = False
3291 cont = False
3291
3292
3292 # commit if --no-commit is false
3293 # commit if --no-commit is false
3293 if not opts.get(b'no_commit'):
3294 if not opts.get(b'no_commit'):
3294 node = repo.commit(
3295 node = repo.commit(
3295 text=message, user=user, date=date, extra=extra, editor=editor
3296 text=message, user=user, date=date, extra=extra, editor=editor
3296 )
3297 )
3297 if node is None:
3298 if node is None:
3298 ui.warn(
3299 ui.warn(
3299 _(b'note: graft of %d:%s created no changes to commit\n')
3300 _(b'note: graft of %d:%s created no changes to commit\n')
3300 % (ctx.rev(), ctx)
3301 % (ctx.rev(), ctx)
3301 )
3302 )
3302 # checking that newnodes exist because old state files won't have it
3303 # checking that newnodes exist because old state files won't have it
3303 elif statedata.get(b'newnodes') is not None:
3304 elif statedata.get(b'newnodes') is not None:
3304 nn = statedata[b'newnodes'] # type: List[bytes]
3305 nn = statedata[b'newnodes'] # type: List[bytes]
3305 nn.append(node)
3306 nn.append(node)
3306
3307
3307 # remove state when we complete successfully
3308 # remove state when we complete successfully
3308 if not opts.get(b'dry_run'):
3309 if not opts.get(b'dry_run'):
3309 graftstate.delete()
3310 graftstate.delete()
3310
3311
3311 return 0
3312 return 0
3312
3313
3313
3314
3314 def _stopgraft(ui, repo, graftstate):
3315 def _stopgraft(ui, repo, graftstate):
3315 """stop the interrupted graft"""
3316 """stop the interrupted graft"""
3316 if not graftstate.exists():
3317 if not graftstate.exists():
3317 raise error.StateError(_(b"no interrupted graft found"))
3318 raise error.StateError(_(b"no interrupted graft found"))
3318 pctx = repo[b'.']
3319 pctx = repo[b'.']
3319 mergemod.clean_update(pctx)
3320 mergemod.clean_update(pctx)
3320 graftstate.delete()
3321 graftstate.delete()
3321 ui.status(_(b"stopped the interrupted graft\n"))
3322 ui.status(_(b"stopped the interrupted graft\n"))
3322 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3323 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3323 return 0
3324 return 0
3324
3325
3325
3326
3326 statemod.addunfinished(
3327 statemod.addunfinished(
3327 b'graft',
3328 b'graft',
3328 fname=b'graftstate',
3329 fname=b'graftstate',
3329 clearable=True,
3330 clearable=True,
3330 stopflag=True,
3331 stopflag=True,
3331 continueflag=True,
3332 continueflag=True,
3332 abortfunc=cmdutil.hgabortgraft,
3333 abortfunc=cmdutil.hgabortgraft,
3333 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3334 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3334 )
3335 )
3335
3336
3336
3337
3337 @command(
3338 @command(
3338 b'grep',
3339 b'grep',
3339 [
3340 [
3340 (b'0', b'print0', None, _(b'end fields with NUL')),
3341 (b'0', b'print0', None, _(b'end fields with NUL')),
3341 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3342 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3342 (
3343 (
3343 b'',
3344 b'',
3344 b'diff',
3345 b'diff',
3345 None,
3346 None,
3346 _(
3347 _(
3347 b'search revision differences for when the pattern was added '
3348 b'search revision differences for when the pattern was added '
3348 b'or removed'
3349 b'or removed'
3349 ),
3350 ),
3350 ),
3351 ),
3351 (b'a', b'text', None, _(b'treat all files as text')),
3352 (b'a', b'text', None, _(b'treat all files as text')),
3352 (
3353 (
3353 b'f',
3354 b'f',
3354 b'follow',
3355 b'follow',
3355 None,
3356 None,
3356 _(
3357 _(
3357 b'follow changeset history,'
3358 b'follow changeset history,'
3358 b' or file history across copies and renames'
3359 b' or file history across copies and renames'
3359 ),
3360 ),
3360 ),
3361 ),
3361 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3362 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3362 (
3363 (
3363 b'l',
3364 b'l',
3364 b'files-with-matches',
3365 b'files-with-matches',
3365 None,
3366 None,
3366 _(b'print only filenames and revisions that match'),
3367 _(b'print only filenames and revisions that match'),
3367 ),
3368 ),
3368 (b'n', b'line-number', None, _(b'print matching line numbers')),
3369 (b'n', b'line-number', None, _(b'print matching line numbers')),
3369 (
3370 (
3370 b'r',
3371 b'r',
3371 b'rev',
3372 b'rev',
3372 [],
3373 [],
3373 _(b'search files changed within revision range'),
3374 _(b'search files changed within revision range'),
3374 _(b'REV'),
3375 _(b'REV'),
3375 ),
3376 ),
3376 (
3377 (
3377 b'',
3378 b'',
3378 b'all-files',
3379 b'all-files',
3379 None,
3380 None,
3380 _(
3381 _(
3381 b'include all files in the changeset while grepping (DEPRECATED)'
3382 b'include all files in the changeset while grepping (DEPRECATED)'
3382 ),
3383 ),
3383 ),
3384 ),
3384 (b'u', b'user', None, _(b'list the author (long with -v)')),
3385 (b'u', b'user', None, _(b'list the author (long with -v)')),
3385 (b'd', b'date', None, _(b'list the date (short with -q)')),
3386 (b'd', b'date', None, _(b'list the date (short with -q)')),
3386 ]
3387 ]
3387 + formatteropts
3388 + formatteropts
3388 + walkopts,
3389 + walkopts,
3389 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3390 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3390 helpcategory=command.CATEGORY_FILE_CONTENTS,
3391 helpcategory=command.CATEGORY_FILE_CONTENTS,
3391 inferrepo=True,
3392 inferrepo=True,
3392 intents={INTENT_READONLY},
3393 intents={INTENT_READONLY},
3393 )
3394 )
3394 def grep(ui, repo, pattern, *pats, **opts):
3395 def grep(ui, repo, pattern, *pats, **opts):
3395 """search for a pattern in specified files
3396 """search for a pattern in specified files
3396
3397
3397 Search the working directory or revision history for a regular
3398 Search the working directory or revision history for a regular
3398 expression in the specified files for the entire repository.
3399 expression in the specified files for the entire repository.
3399
3400
3400 By default, grep searches the repository files in the working
3401 By default, grep searches the repository files in the working
3401 directory and prints the files where it finds a match. To specify
3402 directory and prints the files where it finds a match. To specify
3402 historical revisions instead of the working directory, use the
3403 historical revisions instead of the working directory, use the
3403 --rev flag.
3404 --rev flag.
3404
3405
3405 To search instead historical revision differences that contains a
3406 To search instead historical revision differences that contains a
3406 change in match status ("-" for a match that becomes a non-match,
3407 change in match status ("-" for a match that becomes a non-match,
3407 or "+" for a non-match that becomes a match), use the --diff flag.
3408 or "+" for a non-match that becomes a match), use the --diff flag.
3408
3409
3409 PATTERN can be any Python (roughly Perl-compatible) regular
3410 PATTERN can be any Python (roughly Perl-compatible) regular
3410 expression.
3411 expression.
3411
3412
3412 If no FILEs are specified and the --rev flag isn't supplied, all
3413 If no FILEs are specified and the --rev flag isn't supplied, all
3413 files in the working directory are searched. When using the --rev
3414 files in the working directory are searched. When using the --rev
3414 flag and specifying FILEs, use the --follow argument to also
3415 flag and specifying FILEs, use the --follow argument to also
3415 follow the specified FILEs across renames and copies.
3416 follow the specified FILEs across renames and copies.
3416
3417
3417 .. container:: verbose
3418 .. container:: verbose
3418
3419
3419 Template:
3420 Template:
3420
3421
3421 The following keywords are supported in addition to the common template
3422 The following keywords are supported in addition to the common template
3422 keywords and functions. See also :hg:`help templates`.
3423 keywords and functions. See also :hg:`help templates`.
3423
3424
3424 :change: String. Character denoting insertion ``+`` or removal ``-``.
3425 :change: String. Character denoting insertion ``+`` or removal ``-``.
3425 Available if ``--diff`` is specified.
3426 Available if ``--diff`` is specified.
3426 :lineno: Integer. Line number of the match.
3427 :lineno: Integer. Line number of the match.
3427 :path: String. Repository-absolute path of the file.
3428 :path: String. Repository-absolute path of the file.
3428 :texts: List of text chunks.
3429 :texts: List of text chunks.
3429
3430
3430 And each entry of ``{texts}`` provides the following sub-keywords.
3431 And each entry of ``{texts}`` provides the following sub-keywords.
3431
3432
3432 :matched: Boolean. True if the chunk matches the specified pattern.
3433 :matched: Boolean. True if the chunk matches the specified pattern.
3433 :text: String. Chunk content.
3434 :text: String. Chunk content.
3434
3435
3435 See :hg:`help templates.operators` for the list expansion syntax.
3436 See :hg:`help templates.operators` for the list expansion syntax.
3436
3437
3437 Returns 0 if a match is found, 1 otherwise.
3438 Returns 0 if a match is found, 1 otherwise.
3438
3439
3439 """
3440 """
3440 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3441 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3441 opts = pycompat.byteskwargs(opts)
3442 opts = pycompat.byteskwargs(opts)
3442 diff = opts.get(b'all') or opts.get(b'diff')
3443 diff = opts.get(b'all') or opts.get(b'diff')
3443 follow = opts.get(b'follow')
3444 follow = opts.get(b'follow')
3444 if opts.get(b'all_files') is None and not diff:
3445 if opts.get(b'all_files') is None and not diff:
3445 opts[b'all_files'] = True
3446 opts[b'all_files'] = True
3446 plaingrep = (
3447 plaingrep = (
3447 opts.get(b'all_files')
3448 opts.get(b'all_files')
3448 and not opts.get(b'rev')
3449 and not opts.get(b'rev')
3449 and not opts.get(b'follow')
3450 and not opts.get(b'follow')
3450 )
3451 )
3451 all_files = opts.get(b'all_files')
3452 all_files = opts.get(b'all_files')
3452 if plaingrep:
3453 if plaingrep:
3453 opts[b'rev'] = [b'wdir()']
3454 opts[b'rev'] = [b'wdir()']
3454
3455
3455 reflags = re.M
3456 reflags = re.M
3456 if opts.get(b'ignore_case'):
3457 if opts.get(b'ignore_case'):
3457 reflags |= re.I
3458 reflags |= re.I
3458 try:
3459 try:
3459 regexp = util.re.compile(pattern, reflags)
3460 regexp = util.re.compile(pattern, reflags)
3460 except re.error as inst:
3461 except re.error as inst:
3461 ui.warn(
3462 ui.warn(
3462 _(b"grep: invalid match pattern: %s\n")
3463 _(b"grep: invalid match pattern: %s\n")
3463 % stringutil.forcebytestr(inst)
3464 % stringutil.forcebytestr(inst)
3464 )
3465 )
3465 return 1
3466 return 1
3466 sep, eol = b':', b'\n'
3467 sep, eol = b':', b'\n'
3467 if opts.get(b'print0'):
3468 if opts.get(b'print0'):
3468 sep = eol = b'\0'
3469 sep = eol = b'\0'
3469
3470
3470 searcher = grepmod.grepsearcher(
3471 searcher = grepmod.grepsearcher(
3471 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3472 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3472 )
3473 )
3473
3474
3474 getfile = searcher._getfile
3475 getfile = searcher._getfile
3475
3476
3476 uipathfn = scmutil.getuipathfn(repo)
3477 uipathfn = scmutil.getuipathfn(repo)
3477
3478
3478 def display(fm, fn, ctx, pstates, states):
3479 def display(fm, fn, ctx, pstates, states):
3479 rev = scmutil.intrev(ctx)
3480 rev = scmutil.intrev(ctx)
3480 if fm.isplain():
3481 if fm.isplain():
3481 formatuser = ui.shortuser
3482 formatuser = ui.shortuser
3482 else:
3483 else:
3483 formatuser = pycompat.bytestr
3484 formatuser = pycompat.bytestr
3484 if ui.quiet:
3485 if ui.quiet:
3485 datefmt = b'%Y-%m-%d'
3486 datefmt = b'%Y-%m-%d'
3486 else:
3487 else:
3487 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3488 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3488 found = False
3489 found = False
3489
3490
3490 @util.cachefunc
3491 @util.cachefunc
3491 def binary():
3492 def binary():
3492 flog = getfile(fn)
3493 flog = getfile(fn)
3493 try:
3494 try:
3494 return stringutil.binary(flog.read(ctx.filenode(fn)))
3495 return stringutil.binary(flog.read(ctx.filenode(fn)))
3495 except error.WdirUnsupported:
3496 except error.WdirUnsupported:
3496 return ctx[fn].isbinary()
3497 return ctx[fn].isbinary()
3497
3498
3498 fieldnamemap = {b'linenumber': b'lineno'}
3499 fieldnamemap = {b'linenumber': b'lineno'}
3499 if diff:
3500 if diff:
3500 iter = grepmod.difflinestates(pstates, states)
3501 iter = grepmod.difflinestates(pstates, states)
3501 else:
3502 else:
3502 iter = [(b'', l) for l in states]
3503 iter = [(b'', l) for l in states]
3503 for change, l in iter:
3504 for change, l in iter:
3504 fm.startitem()
3505 fm.startitem()
3505 fm.context(ctx=ctx)
3506 fm.context(ctx=ctx)
3506 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3507 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3507 fm.plain(uipathfn(fn), label=b'grep.filename')
3508 fm.plain(uipathfn(fn), label=b'grep.filename')
3508
3509
3509 cols = [
3510 cols = [
3510 (b'rev', b'%d', rev, not plaingrep, b''),
3511 (b'rev', b'%d', rev, not plaingrep, b''),
3511 (
3512 (
3512 b'linenumber',
3513 b'linenumber',
3513 b'%d',
3514 b'%d',
3514 l.linenum,
3515 l.linenum,
3515 opts.get(b'line_number'),
3516 opts.get(b'line_number'),
3516 b'',
3517 b'',
3517 ),
3518 ),
3518 ]
3519 ]
3519 if diff:
3520 if diff:
3520 cols.append(
3521 cols.append(
3521 (
3522 (
3522 b'change',
3523 b'change',
3523 b'%s',
3524 b'%s',
3524 change,
3525 change,
3525 True,
3526 True,
3526 b'grep.inserted '
3527 b'grep.inserted '
3527 if change == b'+'
3528 if change == b'+'
3528 else b'grep.deleted ',
3529 else b'grep.deleted ',
3529 )
3530 )
3530 )
3531 )
3531 cols.extend(
3532 cols.extend(
3532 [
3533 [
3533 (
3534 (
3534 b'user',
3535 b'user',
3535 b'%s',
3536 b'%s',
3536 formatuser(ctx.user()),
3537 formatuser(ctx.user()),
3537 opts.get(b'user'),
3538 opts.get(b'user'),
3538 b'',
3539 b'',
3539 ),
3540 ),
3540 (
3541 (
3541 b'date',
3542 b'date',
3542 b'%s',
3543 b'%s',
3543 fm.formatdate(ctx.date(), datefmt),
3544 fm.formatdate(ctx.date(), datefmt),
3544 opts.get(b'date'),
3545 opts.get(b'date'),
3545 b'',
3546 b'',
3546 ),
3547 ),
3547 ]
3548 ]
3548 )
3549 )
3549 for name, fmt, data, cond, extra_label in cols:
3550 for name, fmt, data, cond, extra_label in cols:
3550 if cond:
3551 if cond:
3551 fm.plain(sep, label=b'grep.sep')
3552 fm.plain(sep, label=b'grep.sep')
3552 field = fieldnamemap.get(name, name)
3553 field = fieldnamemap.get(name, name)
3553 label = extra_label + (b'grep.%s' % name)
3554 label = extra_label + (b'grep.%s' % name)
3554 fm.condwrite(cond, field, fmt, data, label=label)
3555 fm.condwrite(cond, field, fmt, data, label=label)
3555 if not opts.get(b'files_with_matches'):
3556 if not opts.get(b'files_with_matches'):
3556 fm.plain(sep, label=b'grep.sep')
3557 fm.plain(sep, label=b'grep.sep')
3557 if not opts.get(b'text') and binary():
3558 if not opts.get(b'text') and binary():
3558 fm.plain(_(b" Binary file matches"))
3559 fm.plain(_(b" Binary file matches"))
3559 else:
3560 else:
3560 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3561 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3561 fm.plain(eol)
3562 fm.plain(eol)
3562 found = True
3563 found = True
3563 if opts.get(b'files_with_matches'):
3564 if opts.get(b'files_with_matches'):
3564 break
3565 break
3565 return found
3566 return found
3566
3567
3567 def displaymatches(fm, l):
3568 def displaymatches(fm, l):
3568 p = 0
3569 p = 0
3569 for s, e in l.findpos(regexp):
3570 for s, e in l.findpos(regexp):
3570 if p < s:
3571 if p < s:
3571 fm.startitem()
3572 fm.startitem()
3572 fm.write(b'text', b'%s', l.line[p:s])
3573 fm.write(b'text', b'%s', l.line[p:s])
3573 fm.data(matched=False)
3574 fm.data(matched=False)
3574 fm.startitem()
3575 fm.startitem()
3575 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3576 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3576 fm.data(matched=True)
3577 fm.data(matched=True)
3577 p = e
3578 p = e
3578 if p < len(l.line):
3579 if p < len(l.line):
3579 fm.startitem()
3580 fm.startitem()
3580 fm.write(b'text', b'%s', l.line[p:])
3581 fm.write(b'text', b'%s', l.line[p:])
3581 fm.data(matched=False)
3582 fm.data(matched=False)
3582 fm.end()
3583 fm.end()
3583
3584
3584 found = False
3585 found = False
3585
3586
3586 wopts = logcmdutil.walkopts(
3587 wopts = logcmdutil.walkopts(
3587 pats=pats,
3588 pats=pats,
3588 opts=opts,
3589 opts=opts,
3589 revspec=opts[b'rev'],
3590 revspec=opts[b'rev'],
3590 include_pats=opts[b'include'],
3591 include_pats=opts[b'include'],
3591 exclude_pats=opts[b'exclude'],
3592 exclude_pats=opts[b'exclude'],
3592 follow=follow,
3593 follow=follow,
3593 force_changelog_traversal=all_files,
3594 force_changelog_traversal=all_files,
3594 filter_revisions_by_pats=not all_files,
3595 filter_revisions_by_pats=not all_files,
3595 )
3596 )
3596 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3597 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3597
3598
3598 ui.pager(b'grep')
3599 ui.pager(b'grep')
3599 fm = ui.formatter(b'grep', opts)
3600 fm = ui.formatter(b'grep', opts)
3600 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3601 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3601 r = display(fm, fn, ctx, pstates, states)
3602 r = display(fm, fn, ctx, pstates, states)
3602 found = found or r
3603 found = found or r
3603 if r and not diff and not all_files:
3604 if r and not diff and not all_files:
3604 searcher.skipfile(fn, ctx.rev())
3605 searcher.skipfile(fn, ctx.rev())
3605 fm.end()
3606 fm.end()
3606
3607
3607 return not found
3608 return not found
3608
3609
3609
3610
3610 @command(
3611 @command(
3611 b'heads',
3612 b'heads',
3612 [
3613 [
3613 (
3614 (
3614 b'r',
3615 b'r',
3615 b'rev',
3616 b'rev',
3616 b'',
3617 b'',
3617 _(b'show only heads which are descendants of STARTREV'),
3618 _(b'show only heads which are descendants of STARTREV'),
3618 _(b'STARTREV'),
3619 _(b'STARTREV'),
3619 ),
3620 ),
3620 (b't', b'topo', False, _(b'show topological heads only')),
3621 (b't', b'topo', False, _(b'show topological heads only')),
3621 (
3622 (
3622 b'a',
3623 b'a',
3623 b'active',
3624 b'active',
3624 False,
3625 False,
3625 _(b'show active branchheads only (DEPRECATED)'),
3626 _(b'show active branchheads only (DEPRECATED)'),
3626 ),
3627 ),
3627 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3628 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3628 ]
3629 ]
3629 + templateopts,
3630 + templateopts,
3630 _(b'[-ct] [-r STARTREV] [REV]...'),
3631 _(b'[-ct] [-r STARTREV] [REV]...'),
3631 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3632 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3632 intents={INTENT_READONLY},
3633 intents={INTENT_READONLY},
3633 )
3634 )
3634 def heads(ui, repo, *branchrevs, **opts):
3635 def heads(ui, repo, *branchrevs, **opts):
3635 """show branch heads
3636 """show branch heads
3636
3637
3637 With no arguments, show all open branch heads in the repository.
3638 With no arguments, show all open branch heads in the repository.
3638 Branch heads are changesets that have no descendants on the
3639 Branch heads are changesets that have no descendants on the
3639 same branch. They are where development generally takes place and
3640 same branch. They are where development generally takes place and
3640 are the usual targets for update and merge operations.
3641 are the usual targets for update and merge operations.
3641
3642
3642 If one or more REVs are given, only open branch heads on the
3643 If one or more REVs are given, only open branch heads on the
3643 branches associated with the specified changesets are shown. This
3644 branches associated with the specified changesets are shown. This
3644 means that you can use :hg:`heads .` to see the heads on the
3645 means that you can use :hg:`heads .` to see the heads on the
3645 currently checked-out branch.
3646 currently checked-out branch.
3646
3647
3647 If -c/--closed is specified, also show branch heads marked closed
3648 If -c/--closed is specified, also show branch heads marked closed
3648 (see :hg:`commit --close-branch`).
3649 (see :hg:`commit --close-branch`).
3649
3650
3650 If STARTREV is specified, only those heads that are descendants of
3651 If STARTREV is specified, only those heads that are descendants of
3651 STARTREV will be displayed.
3652 STARTREV will be displayed.
3652
3653
3653 If -t/--topo is specified, named branch mechanics will be ignored and only
3654 If -t/--topo is specified, named branch mechanics will be ignored and only
3654 topological heads (changesets with no children) will be shown.
3655 topological heads (changesets with no children) will be shown.
3655
3656
3656 Returns 0 if matching heads are found, 1 if not.
3657 Returns 0 if matching heads are found, 1 if not.
3657 """
3658 """
3658
3659
3659 opts = pycompat.byteskwargs(opts)
3660 opts = pycompat.byteskwargs(opts)
3660 start = None
3661 start = None
3661 rev = opts.get(b'rev')
3662 rev = opts.get(b'rev')
3662 if rev:
3663 if rev:
3663 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3664 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3664 start = scmutil.revsingle(repo, rev, None).node()
3665 start = scmutil.revsingle(repo, rev, None).node()
3665
3666
3666 if opts.get(b'topo'):
3667 if opts.get(b'topo'):
3667 heads = [repo[h] for h in repo.heads(start)]
3668 heads = [repo[h] for h in repo.heads(start)]
3668 else:
3669 else:
3669 heads = []
3670 heads = []
3670 for branch in repo.branchmap():
3671 for branch in repo.branchmap():
3671 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3672 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3672 heads = [repo[h] for h in heads]
3673 heads = [repo[h] for h in heads]
3673
3674
3674 if branchrevs:
3675 if branchrevs:
3675 branches = {
3676 branches = {
3676 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3677 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3677 }
3678 }
3678 heads = [h for h in heads if h.branch() in branches]
3679 heads = [h for h in heads if h.branch() in branches]
3679
3680
3680 if opts.get(b'active') and branchrevs:
3681 if opts.get(b'active') and branchrevs:
3681 dagheads = repo.heads(start)
3682 dagheads = repo.heads(start)
3682 heads = [h for h in heads if h.node() in dagheads]
3683 heads = [h for h in heads if h.node() in dagheads]
3683
3684
3684 if branchrevs:
3685 if branchrevs:
3685 haveheads = {h.branch() for h in heads}
3686 haveheads = {h.branch() for h in heads}
3686 if branches - haveheads:
3687 if branches - haveheads:
3687 headless = b', '.join(b for b in branches - haveheads)
3688 headless = b', '.join(b for b in branches - haveheads)
3688 msg = _(b'no open branch heads found on branches %s')
3689 msg = _(b'no open branch heads found on branches %s')
3689 if opts.get(b'rev'):
3690 if opts.get(b'rev'):
3690 msg += _(b' (started at %s)') % opts[b'rev']
3691 msg += _(b' (started at %s)') % opts[b'rev']
3691 ui.warn((msg + b'\n') % headless)
3692 ui.warn((msg + b'\n') % headless)
3692
3693
3693 if not heads:
3694 if not heads:
3694 return 1
3695 return 1
3695
3696
3696 ui.pager(b'heads')
3697 ui.pager(b'heads')
3697 heads = sorted(heads, key=lambda x: -(x.rev()))
3698 heads = sorted(heads, key=lambda x: -(x.rev()))
3698 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3699 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3699 for ctx in heads:
3700 for ctx in heads:
3700 displayer.show(ctx)
3701 displayer.show(ctx)
3701 displayer.close()
3702 displayer.close()
3702
3703
3703
3704
3704 @command(
3705 @command(
3705 b'help',
3706 b'help',
3706 [
3707 [
3707 (b'e', b'extension', None, _(b'show only help for extensions')),
3708 (b'e', b'extension', None, _(b'show only help for extensions')),
3708 (b'c', b'command', None, _(b'show only help for commands')),
3709 (b'c', b'command', None, _(b'show only help for commands')),
3709 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3710 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3710 (
3711 (
3711 b's',
3712 b's',
3712 b'system',
3713 b'system',
3713 [],
3714 [],
3714 _(b'show help for specific platform(s)'),
3715 _(b'show help for specific platform(s)'),
3715 _(b'PLATFORM'),
3716 _(b'PLATFORM'),
3716 ),
3717 ),
3717 ],
3718 ],
3718 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3719 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3719 helpcategory=command.CATEGORY_HELP,
3720 helpcategory=command.CATEGORY_HELP,
3720 norepo=True,
3721 norepo=True,
3721 intents={INTENT_READONLY},
3722 intents={INTENT_READONLY},
3722 )
3723 )
3723 def help_(ui, name=None, **opts):
3724 def help_(ui, name=None, **opts):
3724 """show help for a given topic or a help overview
3725 """show help for a given topic or a help overview
3725
3726
3726 With no arguments, print a list of commands with short help messages.
3727 With no arguments, print a list of commands with short help messages.
3727
3728
3728 Given a topic, extension, or command name, print help for that
3729 Given a topic, extension, or command name, print help for that
3729 topic.
3730 topic.
3730
3731
3731 Returns 0 if successful.
3732 Returns 0 if successful.
3732 """
3733 """
3733
3734
3734 keep = opts.get('system') or []
3735 keep = opts.get('system') or []
3735 if len(keep) == 0:
3736 if len(keep) == 0:
3736 if pycompat.sysplatform.startswith(b'win'):
3737 if pycompat.sysplatform.startswith(b'win'):
3737 keep.append(b'windows')
3738 keep.append(b'windows')
3738 elif pycompat.sysplatform == b'OpenVMS':
3739 elif pycompat.sysplatform == b'OpenVMS':
3739 keep.append(b'vms')
3740 keep.append(b'vms')
3740 elif pycompat.sysplatform == b'plan9':
3741 elif pycompat.sysplatform == b'plan9':
3741 keep.append(b'plan9')
3742 keep.append(b'plan9')
3742 else:
3743 else:
3743 keep.append(b'unix')
3744 keep.append(b'unix')
3744 keep.append(pycompat.sysplatform.lower())
3745 keep.append(pycompat.sysplatform.lower())
3745 if ui.verbose:
3746 if ui.verbose:
3746 keep.append(b'verbose')
3747 keep.append(b'verbose')
3747
3748
3748 commands = sys.modules[__name__]
3749 commands = sys.modules[__name__]
3749 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3750 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3750 ui.pager(b'help')
3751 ui.pager(b'help')
3751 ui.write(formatted)
3752 ui.write(formatted)
3752
3753
3753
3754
3754 @command(
3755 @command(
3755 b'identify|id',
3756 b'identify|id',
3756 [
3757 [
3757 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3758 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3758 (b'n', b'num', None, _(b'show local revision number')),
3759 (b'n', b'num', None, _(b'show local revision number')),
3759 (b'i', b'id', None, _(b'show global revision id')),
3760 (b'i', b'id', None, _(b'show global revision id')),
3760 (b'b', b'branch', None, _(b'show branch')),
3761 (b'b', b'branch', None, _(b'show branch')),
3761 (b't', b'tags', None, _(b'show tags')),
3762 (b't', b'tags', None, _(b'show tags')),
3762 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3763 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3763 ]
3764 ]
3764 + remoteopts
3765 + remoteopts
3765 + formatteropts,
3766 + formatteropts,
3766 _(b'[-nibtB] [-r REV] [SOURCE]'),
3767 _(b'[-nibtB] [-r REV] [SOURCE]'),
3767 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3768 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3768 optionalrepo=True,
3769 optionalrepo=True,
3769 intents={INTENT_READONLY},
3770 intents={INTENT_READONLY},
3770 )
3771 )
3771 def identify(
3772 def identify(
3772 ui,
3773 ui,
3773 repo,
3774 repo,
3774 source=None,
3775 source=None,
3775 rev=None,
3776 rev=None,
3776 num=None,
3777 num=None,
3777 id=None,
3778 id=None,
3778 branch=None,
3779 branch=None,
3779 tags=None,
3780 tags=None,
3780 bookmarks=None,
3781 bookmarks=None,
3781 **opts
3782 **opts
3782 ):
3783 ):
3783 """identify the working directory or specified revision
3784 """identify the working directory or specified revision
3784
3785
3785 Print a summary identifying the repository state at REV using one or
3786 Print a summary identifying the repository state at REV using one or
3786 two parent hash identifiers, followed by a "+" if the working
3787 two parent hash identifiers, followed by a "+" if the working
3787 directory has uncommitted changes, the branch name (if not default),
3788 directory has uncommitted changes, the branch name (if not default),
3788 a list of tags, and a list of bookmarks.
3789 a list of tags, and a list of bookmarks.
3789
3790
3790 When REV is not given, print a summary of the current state of the
3791 When REV is not given, print a summary of the current state of the
3791 repository including the working directory. Specify -r. to get information
3792 repository including the working directory. Specify -r. to get information
3792 of the working directory parent without scanning uncommitted changes.
3793 of the working directory parent without scanning uncommitted changes.
3793
3794
3794 Specifying a path to a repository root or Mercurial bundle will
3795 Specifying a path to a repository root or Mercurial bundle will
3795 cause lookup to operate on that repository/bundle.
3796 cause lookup to operate on that repository/bundle.
3796
3797
3797 .. container:: verbose
3798 .. container:: verbose
3798
3799
3799 Template:
3800 Template:
3800
3801
3801 The following keywords are supported in addition to the common template
3802 The following keywords are supported in addition to the common template
3802 keywords and functions. See also :hg:`help templates`.
3803 keywords and functions. See also :hg:`help templates`.
3803
3804
3804 :dirty: String. Character ``+`` denoting if the working directory has
3805 :dirty: String. Character ``+`` denoting if the working directory has
3805 uncommitted changes.
3806 uncommitted changes.
3806 :id: String. One or two nodes, optionally followed by ``+``.
3807 :id: String. One or two nodes, optionally followed by ``+``.
3807 :parents: List of strings. Parent nodes of the changeset.
3808 :parents: List of strings. Parent nodes of the changeset.
3808
3809
3809 Examples:
3810 Examples:
3810
3811
3811 - generate a build identifier for the working directory::
3812 - generate a build identifier for the working directory::
3812
3813
3813 hg id --id > build-id.dat
3814 hg id --id > build-id.dat
3814
3815
3815 - find the revision corresponding to a tag::
3816 - find the revision corresponding to a tag::
3816
3817
3817 hg id -n -r 1.3
3818 hg id -n -r 1.3
3818
3819
3819 - check the most recent revision of a remote repository::
3820 - check the most recent revision of a remote repository::
3820
3821
3821 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3822 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3822
3823
3823 See :hg:`log` for generating more information about specific revisions,
3824 See :hg:`log` for generating more information about specific revisions,
3824 including full hash identifiers.
3825 including full hash identifiers.
3825
3826
3826 Returns 0 if successful.
3827 Returns 0 if successful.
3827 """
3828 """
3828
3829
3829 opts = pycompat.byteskwargs(opts)
3830 opts = pycompat.byteskwargs(opts)
3830 if not repo and not source:
3831 if not repo and not source:
3831 raise error.InputError(
3832 raise error.InputError(
3832 _(b"there is no Mercurial repository here (.hg not found)")
3833 _(b"there is no Mercurial repository here (.hg not found)")
3833 )
3834 )
3834
3835
3835 default = not (num or id or branch or tags or bookmarks)
3836 default = not (num or id or branch or tags or bookmarks)
3836 output = []
3837 output = []
3837 revs = []
3838 revs = []
3838
3839
3839 peer = None
3840 peer = None
3840 try:
3841 try:
3841 if source:
3842 if source:
3842 source, branches = hg.parseurl(ui.expandpath(source))
3843 source, branches = hg.parseurl(ui.expandpath(source))
3843 # only pass ui when no repo
3844 # only pass ui when no repo
3844 peer = hg.peer(repo or ui, opts, source)
3845 peer = hg.peer(repo or ui, opts, source)
3845 repo = peer.local()
3846 repo = peer.local()
3846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3847 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3847
3848
3848 fm = ui.formatter(b'identify', opts)
3849 fm = ui.formatter(b'identify', opts)
3849 fm.startitem()
3850 fm.startitem()
3850
3851
3851 if not repo:
3852 if not repo:
3852 if num or branch or tags:
3853 if num or branch or tags:
3853 raise error.InputError(
3854 raise error.InputError(
3854 _(b"can't query remote revision number, branch, or tags")
3855 _(b"can't query remote revision number, branch, or tags")
3855 )
3856 )
3856 if not rev and revs:
3857 if not rev and revs:
3857 rev = revs[0]
3858 rev = revs[0]
3858 if not rev:
3859 if not rev:
3859 rev = b"tip"
3860 rev = b"tip"
3860
3861
3861 remoterev = peer.lookup(rev)
3862 remoterev = peer.lookup(rev)
3862 hexrev = fm.hexfunc(remoterev)
3863 hexrev = fm.hexfunc(remoterev)
3863 if default or id:
3864 if default or id:
3864 output = [hexrev]
3865 output = [hexrev]
3865 fm.data(id=hexrev)
3866 fm.data(id=hexrev)
3866
3867
3867 @util.cachefunc
3868 @util.cachefunc
3868 def getbms():
3869 def getbms():
3869 bms = []
3870 bms = []
3870
3871
3871 if b'bookmarks' in peer.listkeys(b'namespaces'):
3872 if b'bookmarks' in peer.listkeys(b'namespaces'):
3872 hexremoterev = hex(remoterev)
3873 hexremoterev = hex(remoterev)
3873 bms = [
3874 bms = [
3874 bm
3875 bm
3875 for bm, bmr in pycompat.iteritems(
3876 for bm, bmr in pycompat.iteritems(
3876 peer.listkeys(b'bookmarks')
3877 peer.listkeys(b'bookmarks')
3877 )
3878 )
3878 if bmr == hexremoterev
3879 if bmr == hexremoterev
3879 ]
3880 ]
3880
3881
3881 return sorted(bms)
3882 return sorted(bms)
3882
3883
3883 if fm.isplain():
3884 if fm.isplain():
3884 if bookmarks:
3885 if bookmarks:
3885 output.extend(getbms())
3886 output.extend(getbms())
3886 elif default and not ui.quiet:
3887 elif default and not ui.quiet:
3887 # multiple bookmarks for a single parent separated by '/'
3888 # multiple bookmarks for a single parent separated by '/'
3888 bm = b'/'.join(getbms())
3889 bm = b'/'.join(getbms())
3889 if bm:
3890 if bm:
3890 output.append(bm)
3891 output.append(bm)
3891 else:
3892 else:
3892 fm.data(node=hex(remoterev))
3893 fm.data(node=hex(remoterev))
3893 if bookmarks or b'bookmarks' in fm.datahint():
3894 if bookmarks or b'bookmarks' in fm.datahint():
3894 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3895 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3895 else:
3896 else:
3896 if rev:
3897 if rev:
3897 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3898 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3898 ctx = scmutil.revsingle(repo, rev, None)
3899 ctx = scmutil.revsingle(repo, rev, None)
3899
3900
3900 if ctx.rev() is None:
3901 if ctx.rev() is None:
3901 ctx = repo[None]
3902 ctx = repo[None]
3902 parents = ctx.parents()
3903 parents = ctx.parents()
3903 taglist = []
3904 taglist = []
3904 for p in parents:
3905 for p in parents:
3905 taglist.extend(p.tags())
3906 taglist.extend(p.tags())
3906
3907
3907 dirty = b""
3908 dirty = b""
3908 if ctx.dirty(missing=True, merge=False, branch=False):
3909 if ctx.dirty(missing=True, merge=False, branch=False):
3909 dirty = b'+'
3910 dirty = b'+'
3910 fm.data(dirty=dirty)
3911 fm.data(dirty=dirty)
3911
3912
3912 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3913 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3913 if default or id:
3914 if default or id:
3914 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3915 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3915 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3916 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3916
3917
3917 if num:
3918 if num:
3918 numoutput = [b"%d" % p.rev() for p in parents]
3919 numoutput = [b"%d" % p.rev() for p in parents]
3919 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3920 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3920
3921
3921 fm.data(
3922 fm.data(
3922 parents=fm.formatlist(
3923 parents=fm.formatlist(
3923 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3924 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3924 )
3925 )
3925 )
3926 )
3926 else:
3927 else:
3927 hexoutput = fm.hexfunc(ctx.node())
3928 hexoutput = fm.hexfunc(ctx.node())
3928 if default or id:
3929 if default or id:
3929 output = [hexoutput]
3930 output = [hexoutput]
3930 fm.data(id=hexoutput)
3931 fm.data(id=hexoutput)
3931
3932
3932 if num:
3933 if num:
3933 output.append(pycompat.bytestr(ctx.rev()))
3934 output.append(pycompat.bytestr(ctx.rev()))
3934 taglist = ctx.tags()
3935 taglist = ctx.tags()
3935
3936
3936 if default and not ui.quiet:
3937 if default and not ui.quiet:
3937 b = ctx.branch()
3938 b = ctx.branch()
3938 if b != b'default':
3939 if b != b'default':
3939 output.append(b"(%s)" % b)
3940 output.append(b"(%s)" % b)
3940
3941
3941 # multiple tags for a single parent separated by '/'
3942 # multiple tags for a single parent separated by '/'
3942 t = b'/'.join(taglist)
3943 t = b'/'.join(taglist)
3943 if t:
3944 if t:
3944 output.append(t)
3945 output.append(t)
3945
3946
3946 # multiple bookmarks for a single parent separated by '/'
3947 # multiple bookmarks for a single parent separated by '/'
3947 bm = b'/'.join(ctx.bookmarks())
3948 bm = b'/'.join(ctx.bookmarks())
3948 if bm:
3949 if bm:
3949 output.append(bm)
3950 output.append(bm)
3950 else:
3951 else:
3951 if branch:
3952 if branch:
3952 output.append(ctx.branch())
3953 output.append(ctx.branch())
3953
3954
3954 if tags:
3955 if tags:
3955 output.extend(taglist)
3956 output.extend(taglist)
3956
3957
3957 if bookmarks:
3958 if bookmarks:
3958 output.extend(ctx.bookmarks())
3959 output.extend(ctx.bookmarks())
3959
3960
3960 fm.data(node=ctx.hex())
3961 fm.data(node=ctx.hex())
3961 fm.data(branch=ctx.branch())
3962 fm.data(branch=ctx.branch())
3962 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3963 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3963 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3964 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3964 fm.context(ctx=ctx)
3965 fm.context(ctx=ctx)
3965
3966
3966 fm.plain(b"%s\n" % b' '.join(output))
3967 fm.plain(b"%s\n" % b' '.join(output))
3967 fm.end()
3968 fm.end()
3968 finally:
3969 finally:
3969 if peer:
3970 if peer:
3970 peer.close()
3971 peer.close()
3971
3972
3972
3973
3973 @command(
3974 @command(
3974 b'import|patch',
3975 b'import|patch',
3975 [
3976 [
3976 (
3977 (
3977 b'p',
3978 b'p',
3978 b'strip',
3979 b'strip',
3979 1,
3980 1,
3980 _(
3981 _(
3981 b'directory strip option for patch. This has the same '
3982 b'directory strip option for patch. This has the same '
3982 b'meaning as the corresponding patch option'
3983 b'meaning as the corresponding patch option'
3983 ),
3984 ),
3984 _(b'NUM'),
3985 _(b'NUM'),
3985 ),
3986 ),
3986 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3987 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3987 (b'', b'secret', None, _(b'use the secret phase for committing')),
3988 (b'', b'secret', None, _(b'use the secret phase for committing')),
3988 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3989 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3989 (
3990 (
3990 b'f',
3991 b'f',
3991 b'force',
3992 b'force',
3992 None,
3993 None,
3993 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3994 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3994 ),
3995 ),
3995 (
3996 (
3996 b'',
3997 b'',
3997 b'no-commit',
3998 b'no-commit',
3998 None,
3999 None,
3999 _(b"don't commit, just update the working directory"),
4000 _(b"don't commit, just update the working directory"),
4000 ),
4001 ),
4001 (
4002 (
4002 b'',
4003 b'',
4003 b'bypass',
4004 b'bypass',
4004 None,
4005 None,
4005 _(b"apply patch without touching the working directory"),
4006 _(b"apply patch without touching the working directory"),
4006 ),
4007 ),
4007 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4008 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4008 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4009 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4009 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4010 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4010 (
4011 (
4011 b'',
4012 b'',
4012 b'import-branch',
4013 b'import-branch',
4013 None,
4014 None,
4014 _(b'use any branch information in patch (implied by --exact)'),
4015 _(b'use any branch information in patch (implied by --exact)'),
4015 ),
4016 ),
4016 ]
4017 ]
4017 + commitopts
4018 + commitopts
4018 + commitopts2
4019 + commitopts2
4019 + similarityopts,
4020 + similarityopts,
4020 _(b'[OPTION]... PATCH...'),
4021 _(b'[OPTION]... PATCH...'),
4021 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4022 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4022 )
4023 )
4023 def import_(ui, repo, patch1=None, *patches, **opts):
4024 def import_(ui, repo, patch1=None, *patches, **opts):
4024 """import an ordered set of patches
4025 """import an ordered set of patches
4025
4026
4026 Import a list of patches and commit them individually (unless
4027 Import a list of patches and commit them individually (unless
4027 --no-commit is specified).
4028 --no-commit is specified).
4028
4029
4029 To read a patch from standard input (stdin), use "-" as the patch
4030 To read a patch from standard input (stdin), use "-" as the patch
4030 name. If a URL is specified, the patch will be downloaded from
4031 name. If a URL is specified, the patch will be downloaded from
4031 there.
4032 there.
4032
4033
4033 Import first applies changes to the working directory (unless
4034 Import first applies changes to the working directory (unless
4034 --bypass is specified), import will abort if there are outstanding
4035 --bypass is specified), import will abort if there are outstanding
4035 changes.
4036 changes.
4036
4037
4037 Use --bypass to apply and commit patches directly to the
4038 Use --bypass to apply and commit patches directly to the
4038 repository, without affecting the working directory. Without
4039 repository, without affecting the working directory. Without
4039 --exact, patches will be applied on top of the working directory
4040 --exact, patches will be applied on top of the working directory
4040 parent revision.
4041 parent revision.
4041
4042
4042 You can import a patch straight from a mail message. Even patches
4043 You can import a patch straight from a mail message. Even patches
4043 as attachments work (to use the body part, it must have type
4044 as attachments work (to use the body part, it must have type
4044 text/plain or text/x-patch). From and Subject headers of email
4045 text/plain or text/x-patch). From and Subject headers of email
4045 message are used as default committer and commit message. All
4046 message are used as default committer and commit message. All
4046 text/plain body parts before first diff are added to the commit
4047 text/plain body parts before first diff are added to the commit
4047 message.
4048 message.
4048
4049
4049 If the imported patch was generated by :hg:`export`, user and
4050 If the imported patch was generated by :hg:`export`, user and
4050 description from patch override values from message headers and
4051 description from patch override values from message headers and
4051 body. Values given on command line with -m/--message and -u/--user
4052 body. Values given on command line with -m/--message and -u/--user
4052 override these.
4053 override these.
4053
4054
4054 If --exact is specified, import will set the working directory to
4055 If --exact is specified, import will set the working directory to
4055 the parent of each patch before applying it, and will abort if the
4056 the parent of each patch before applying it, and will abort if the
4056 resulting changeset has a different ID than the one recorded in
4057 resulting changeset has a different ID than the one recorded in
4057 the patch. This will guard against various ways that portable
4058 the patch. This will guard against various ways that portable
4058 patch formats and mail systems might fail to transfer Mercurial
4059 patch formats and mail systems might fail to transfer Mercurial
4059 data or metadata. See :hg:`bundle` for lossless transmission.
4060 data or metadata. See :hg:`bundle` for lossless transmission.
4060
4061
4061 Use --partial to ensure a changeset will be created from the patch
4062 Use --partial to ensure a changeset will be created from the patch
4062 even if some hunks fail to apply. Hunks that fail to apply will be
4063 even if some hunks fail to apply. Hunks that fail to apply will be
4063 written to a <target-file>.rej file. Conflicts can then be resolved
4064 written to a <target-file>.rej file. Conflicts can then be resolved
4064 by hand before :hg:`commit --amend` is run to update the created
4065 by hand before :hg:`commit --amend` is run to update the created
4065 changeset. This flag exists to let people import patches that
4066 changeset. This flag exists to let people import patches that
4066 partially apply without losing the associated metadata (author,
4067 partially apply without losing the associated metadata (author,
4067 date, description, ...).
4068 date, description, ...).
4068
4069
4069 .. note::
4070 .. note::
4070
4071
4071 When no hunks apply cleanly, :hg:`import --partial` will create
4072 When no hunks apply cleanly, :hg:`import --partial` will create
4072 an empty changeset, importing only the patch metadata.
4073 an empty changeset, importing only the patch metadata.
4073
4074
4074 With -s/--similarity, hg will attempt to discover renames and
4075 With -s/--similarity, hg will attempt to discover renames and
4075 copies in the patch in the same way as :hg:`addremove`.
4076 copies in the patch in the same way as :hg:`addremove`.
4076
4077
4077 It is possible to use external patch programs to perform the patch
4078 It is possible to use external patch programs to perform the patch
4078 by setting the ``ui.patch`` configuration option. For the default
4079 by setting the ``ui.patch`` configuration option. For the default
4079 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4080 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4080 See :hg:`help config` for more information about configuration
4081 See :hg:`help config` for more information about configuration
4081 files and how to use these options.
4082 files and how to use these options.
4082
4083
4083 See :hg:`help dates` for a list of formats valid for -d/--date.
4084 See :hg:`help dates` for a list of formats valid for -d/--date.
4084
4085
4085 .. container:: verbose
4086 .. container:: verbose
4086
4087
4087 Examples:
4088 Examples:
4088
4089
4089 - import a traditional patch from a website and detect renames::
4090 - import a traditional patch from a website and detect renames::
4090
4091
4091 hg import -s 80 http://example.com/bugfix.patch
4092 hg import -s 80 http://example.com/bugfix.patch
4092
4093
4093 - import a changeset from an hgweb server::
4094 - import a changeset from an hgweb server::
4094
4095
4095 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4096 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4096
4097
4097 - import all the patches in an Unix-style mbox::
4098 - import all the patches in an Unix-style mbox::
4098
4099
4099 hg import incoming-patches.mbox
4100 hg import incoming-patches.mbox
4100
4101
4101 - import patches from stdin::
4102 - import patches from stdin::
4102
4103
4103 hg import -
4104 hg import -
4104
4105
4105 - attempt to exactly restore an exported changeset (not always
4106 - attempt to exactly restore an exported changeset (not always
4106 possible)::
4107 possible)::
4107
4108
4108 hg import --exact proposed-fix.patch
4109 hg import --exact proposed-fix.patch
4109
4110
4110 - use an external tool to apply a patch which is too fuzzy for
4111 - use an external tool to apply a patch which is too fuzzy for
4111 the default internal tool.
4112 the default internal tool.
4112
4113
4113 hg import --config ui.patch="patch --merge" fuzzy.patch
4114 hg import --config ui.patch="patch --merge" fuzzy.patch
4114
4115
4115 - change the default fuzzing from 2 to a less strict 7
4116 - change the default fuzzing from 2 to a less strict 7
4116
4117
4117 hg import --config ui.fuzz=7 fuzz.patch
4118 hg import --config ui.fuzz=7 fuzz.patch
4118
4119
4119 Returns 0 on success, 1 on partial success (see --partial).
4120 Returns 0 on success, 1 on partial success (see --partial).
4120 """
4121 """
4121
4122
4122 cmdutil.check_incompatible_arguments(
4123 cmdutil.check_incompatible_arguments(
4123 opts, 'no_commit', ['bypass', 'secret']
4124 opts, 'no_commit', ['bypass', 'secret']
4124 )
4125 )
4125 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4126 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4126 opts = pycompat.byteskwargs(opts)
4127 opts = pycompat.byteskwargs(opts)
4127 if not patch1:
4128 if not patch1:
4128 raise error.InputError(_(b'need at least one patch to import'))
4129 raise error.InputError(_(b'need at least one patch to import'))
4129
4130
4130 patches = (patch1,) + patches
4131 patches = (patch1,) + patches
4131
4132
4132 date = opts.get(b'date')
4133 date = opts.get(b'date')
4133 if date:
4134 if date:
4134 opts[b'date'] = dateutil.parsedate(date)
4135 opts[b'date'] = dateutil.parsedate(date)
4135
4136
4136 exact = opts.get(b'exact')
4137 exact = opts.get(b'exact')
4137 update = not opts.get(b'bypass')
4138 update = not opts.get(b'bypass')
4138 try:
4139 try:
4139 sim = float(opts.get(b'similarity') or 0)
4140 sim = float(opts.get(b'similarity') or 0)
4140 except ValueError:
4141 except ValueError:
4141 raise error.InputError(_(b'similarity must be a number'))
4142 raise error.InputError(_(b'similarity must be a number'))
4142 if sim < 0 or sim > 100:
4143 if sim < 0 or sim > 100:
4143 raise error.InputError(_(b'similarity must be between 0 and 100'))
4144 raise error.InputError(_(b'similarity must be between 0 and 100'))
4144 if sim and not update:
4145 if sim and not update:
4145 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4146 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4146
4147
4147 base = opts[b"base"]
4148 base = opts[b"base"]
4148 msgs = []
4149 msgs = []
4149 ret = 0
4150 ret = 0
4150
4151
4151 with repo.wlock():
4152 with repo.wlock():
4152 if update:
4153 if update:
4153 cmdutil.checkunfinished(repo)
4154 cmdutil.checkunfinished(repo)
4154 if exact or not opts.get(b'force'):
4155 if exact or not opts.get(b'force'):
4155 cmdutil.bailifchanged(repo)
4156 cmdutil.bailifchanged(repo)
4156
4157
4157 if not opts.get(b'no_commit'):
4158 if not opts.get(b'no_commit'):
4158 lock = repo.lock
4159 lock = repo.lock
4159 tr = lambda: repo.transaction(b'import')
4160 tr = lambda: repo.transaction(b'import')
4160 dsguard = util.nullcontextmanager
4161 dsguard = util.nullcontextmanager
4161 else:
4162 else:
4162 lock = util.nullcontextmanager
4163 lock = util.nullcontextmanager
4163 tr = util.nullcontextmanager
4164 tr = util.nullcontextmanager
4164 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4165 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4165 with lock(), tr(), dsguard():
4166 with lock(), tr(), dsguard():
4166 parents = repo[None].parents()
4167 parents = repo[None].parents()
4167 for patchurl in patches:
4168 for patchurl in patches:
4168 if patchurl == b'-':
4169 if patchurl == b'-':
4169 ui.status(_(b'applying patch from stdin\n'))
4170 ui.status(_(b'applying patch from stdin\n'))
4170 patchfile = ui.fin
4171 patchfile = ui.fin
4171 patchurl = b'stdin' # for error message
4172 patchurl = b'stdin' # for error message
4172 else:
4173 else:
4173 patchurl = os.path.join(base, patchurl)
4174 patchurl = os.path.join(base, patchurl)
4174 ui.status(_(b'applying %s\n') % patchurl)
4175 ui.status(_(b'applying %s\n') % patchurl)
4175 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4176 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4176
4177
4177 haspatch = False
4178 haspatch = False
4178 for hunk in patch.split(patchfile):
4179 for hunk in patch.split(patchfile):
4179 with patch.extract(ui, hunk) as patchdata:
4180 with patch.extract(ui, hunk) as patchdata:
4180 msg, node, rej = cmdutil.tryimportone(
4181 msg, node, rej = cmdutil.tryimportone(
4181 ui, repo, patchdata, parents, opts, msgs, hg.clean
4182 ui, repo, patchdata, parents, opts, msgs, hg.clean
4182 )
4183 )
4183 if msg:
4184 if msg:
4184 haspatch = True
4185 haspatch = True
4185 ui.note(msg + b'\n')
4186 ui.note(msg + b'\n')
4186 if update or exact:
4187 if update or exact:
4187 parents = repo[None].parents()
4188 parents = repo[None].parents()
4188 else:
4189 else:
4189 parents = [repo[node]]
4190 parents = [repo[node]]
4190 if rej:
4191 if rej:
4191 ui.write_err(_(b"patch applied partially\n"))
4192 ui.write_err(_(b"patch applied partially\n"))
4192 ui.write_err(
4193 ui.write_err(
4193 _(
4194 _(
4194 b"(fix the .rej files and run "
4195 b"(fix the .rej files and run "
4195 b"`hg commit --amend`)\n"
4196 b"`hg commit --amend`)\n"
4196 )
4197 )
4197 )
4198 )
4198 ret = 1
4199 ret = 1
4199 break
4200 break
4200
4201
4201 if not haspatch:
4202 if not haspatch:
4202 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4203 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4203
4204
4204 if msgs:
4205 if msgs:
4205 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4206 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4206 return ret
4207 return ret
4207
4208
4208
4209
4209 @command(
4210 @command(
4210 b'incoming|in',
4211 b'incoming|in',
4211 [
4212 [
4212 (
4213 (
4213 b'f',
4214 b'f',
4214 b'force',
4215 b'force',
4215 None,
4216 None,
4216 _(b'run even if remote repository is unrelated'),
4217 _(b'run even if remote repository is unrelated'),
4217 ),
4218 ),
4218 (b'n', b'newest-first', None, _(b'show newest record first')),
4219 (b'n', b'newest-first', None, _(b'show newest record first')),
4219 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4220 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4220 (
4221 (
4221 b'r',
4222 b'r',
4222 b'rev',
4223 b'rev',
4223 [],
4224 [],
4224 _(b'a remote changeset intended to be added'),
4225 _(b'a remote changeset intended to be added'),
4225 _(b'REV'),
4226 _(b'REV'),
4226 ),
4227 ),
4227 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4228 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4228 (
4229 (
4229 b'b',
4230 b'b',
4230 b'branch',
4231 b'branch',
4231 [],
4232 [],
4232 _(b'a specific branch you would like to pull'),
4233 _(b'a specific branch you would like to pull'),
4233 _(b'BRANCH'),
4234 _(b'BRANCH'),
4234 ),
4235 ),
4235 ]
4236 ]
4236 + logopts
4237 + logopts
4237 + remoteopts
4238 + remoteopts
4238 + subrepoopts,
4239 + subrepoopts,
4239 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4240 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4240 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4241 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4241 )
4242 )
4242 def incoming(ui, repo, source=b"default", **opts):
4243 def incoming(ui, repo, source=b"default", **opts):
4243 """show new changesets found in source
4244 """show new changesets found in source
4244
4245
4245 Show new changesets found in the specified path/URL or the default
4246 Show new changesets found in the specified path/URL or the default
4246 pull location. These are the changesets that would have been pulled
4247 pull location. These are the changesets that would have been pulled
4247 by :hg:`pull` at the time you issued this command.
4248 by :hg:`pull` at the time you issued this command.
4248
4249
4249 See pull for valid source format details.
4250 See pull for valid source format details.
4250
4251
4251 .. container:: verbose
4252 .. container:: verbose
4252
4253
4253 With -B/--bookmarks, the result of bookmark comparison between
4254 With -B/--bookmarks, the result of bookmark comparison between
4254 local and remote repositories is displayed. With -v/--verbose,
4255 local and remote repositories is displayed. With -v/--verbose,
4255 status is also displayed for each bookmark like below::
4256 status is also displayed for each bookmark like below::
4256
4257
4257 BM1 01234567890a added
4258 BM1 01234567890a added
4258 BM2 1234567890ab advanced
4259 BM2 1234567890ab advanced
4259 BM3 234567890abc diverged
4260 BM3 234567890abc diverged
4260 BM4 34567890abcd changed
4261 BM4 34567890abcd changed
4261
4262
4262 The action taken locally when pulling depends on the
4263 The action taken locally when pulling depends on the
4263 status of each bookmark:
4264 status of each bookmark:
4264
4265
4265 :``added``: pull will create it
4266 :``added``: pull will create it
4266 :``advanced``: pull will update it
4267 :``advanced``: pull will update it
4267 :``diverged``: pull will create a divergent bookmark
4268 :``diverged``: pull will create a divergent bookmark
4268 :``changed``: result depends on remote changesets
4269 :``changed``: result depends on remote changesets
4269
4270
4270 From the point of view of pulling behavior, bookmark
4271 From the point of view of pulling behavior, bookmark
4271 existing only in the remote repository are treated as ``added``,
4272 existing only in the remote repository are treated as ``added``,
4272 even if it is in fact locally deleted.
4273 even if it is in fact locally deleted.
4273
4274
4274 .. container:: verbose
4275 .. container:: verbose
4275
4276
4276 For remote repository, using --bundle avoids downloading the
4277 For remote repository, using --bundle avoids downloading the
4277 changesets twice if the incoming is followed by a pull.
4278 changesets twice if the incoming is followed by a pull.
4278
4279
4279 Examples:
4280 Examples:
4280
4281
4281 - show incoming changes with patches and full description::
4282 - show incoming changes with patches and full description::
4282
4283
4283 hg incoming -vp
4284 hg incoming -vp
4284
4285
4285 - show incoming changes excluding merges, store a bundle::
4286 - show incoming changes excluding merges, store a bundle::
4286
4287
4287 hg in -vpM --bundle incoming.hg
4288 hg in -vpM --bundle incoming.hg
4288 hg pull incoming.hg
4289 hg pull incoming.hg
4289
4290
4290 - briefly list changes inside a bundle::
4291 - briefly list changes inside a bundle::
4291
4292
4292 hg in changes.hg -T "{desc|firstline}\\n"
4293 hg in changes.hg -T "{desc|firstline}\\n"
4293
4294
4294 Returns 0 if there are incoming changes, 1 otherwise.
4295 Returns 0 if there are incoming changes, 1 otherwise.
4295 """
4296 """
4296 opts = pycompat.byteskwargs(opts)
4297 opts = pycompat.byteskwargs(opts)
4297 if opts.get(b'graph'):
4298 if opts.get(b'graph'):
4298 logcmdutil.checkunsupportedgraphflags([], opts)
4299 logcmdutil.checkunsupportedgraphflags([], opts)
4299
4300
4300 def display(other, chlist, displayer):
4301 def display(other, chlist, displayer):
4301 revdag = logcmdutil.graphrevs(other, chlist, opts)
4302 revdag = logcmdutil.graphrevs(other, chlist, opts)
4302 logcmdutil.displaygraph(
4303 logcmdutil.displaygraph(
4303 ui, repo, revdag, displayer, graphmod.asciiedges
4304 ui, repo, revdag, displayer, graphmod.asciiedges
4304 )
4305 )
4305
4306
4306 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4307 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4307 return 0
4308 return 0
4308
4309
4309 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4310 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4310
4311
4311 if opts.get(b'bookmarks'):
4312 if opts.get(b'bookmarks'):
4312 source, branches = hg.parseurl(
4313 source, branches = hg.parseurl(
4313 ui.expandpath(source), opts.get(b'branch')
4314 ui.expandpath(source), opts.get(b'branch')
4314 )
4315 )
4315 other = hg.peer(repo, opts, source)
4316 other = hg.peer(repo, opts, source)
4316 try:
4317 try:
4317 if b'bookmarks' not in other.listkeys(b'namespaces'):
4318 if b'bookmarks' not in other.listkeys(b'namespaces'):
4318 ui.warn(_(b"remote doesn't support bookmarks\n"))
4319 ui.warn(_(b"remote doesn't support bookmarks\n"))
4319 return 0
4320 return 0
4320 ui.pager(b'incoming')
4321 ui.pager(b'incoming')
4321 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4322 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4322 return bookmarks.incoming(ui, repo, other)
4323 return bookmarks.incoming(ui, repo, other)
4323 finally:
4324 finally:
4324 other.close()
4325 other.close()
4325
4326
4326 repo._subtoppath = ui.expandpath(source)
4327 repo._subtoppath = ui.expandpath(source)
4327 try:
4328 try:
4328 return hg.incoming(ui, repo, source, opts)
4329 return hg.incoming(ui, repo, source, opts)
4329 finally:
4330 finally:
4330 del repo._subtoppath
4331 del repo._subtoppath
4331
4332
4332
4333
4333 @command(
4334 @command(
4334 b'init',
4335 b'init',
4335 remoteopts,
4336 remoteopts,
4336 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4337 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4337 helpcategory=command.CATEGORY_REPO_CREATION,
4338 helpcategory=command.CATEGORY_REPO_CREATION,
4338 helpbasic=True,
4339 helpbasic=True,
4339 norepo=True,
4340 norepo=True,
4340 )
4341 )
4341 def init(ui, dest=b".", **opts):
4342 def init(ui, dest=b".", **opts):
4342 """create a new repository in the given directory
4343 """create a new repository in the given directory
4343
4344
4344 Initialize a new repository in the given directory. If the given
4345 Initialize a new repository in the given directory. If the given
4345 directory does not exist, it will be created.
4346 directory does not exist, it will be created.
4346
4347
4347 If no directory is given, the current directory is used.
4348 If no directory is given, the current directory is used.
4348
4349
4349 It is possible to specify an ``ssh://`` URL as the destination.
4350 It is possible to specify an ``ssh://`` URL as the destination.
4350 See :hg:`help urls` for more information.
4351 See :hg:`help urls` for more information.
4351
4352
4352 Returns 0 on success.
4353 Returns 0 on success.
4353 """
4354 """
4354 opts = pycompat.byteskwargs(opts)
4355 opts = pycompat.byteskwargs(opts)
4355 peer = hg.peer(ui, opts, ui.expandpath(dest), create=True)
4356 peer = hg.peer(ui, opts, ui.expandpath(dest), create=True)
4356 peer.close()
4357 peer.close()
4357
4358
4358
4359
4359 @command(
4360 @command(
4360 b'locate',
4361 b'locate',
4361 [
4362 [
4362 (
4363 (
4363 b'r',
4364 b'r',
4364 b'rev',
4365 b'rev',
4365 b'',
4366 b'',
4366 _(b'search the repository as it is in REV'),
4367 _(b'search the repository as it is in REV'),
4367 _(b'REV'),
4368 _(b'REV'),
4368 ),
4369 ),
4369 (
4370 (
4370 b'0',
4371 b'0',
4371 b'print0',
4372 b'print0',
4372 None,
4373 None,
4373 _(b'end filenames with NUL, for use with xargs'),
4374 _(b'end filenames with NUL, for use with xargs'),
4374 ),
4375 ),
4375 (
4376 (
4376 b'f',
4377 b'f',
4377 b'fullpath',
4378 b'fullpath',
4378 None,
4379 None,
4379 _(b'print complete paths from the filesystem root'),
4380 _(b'print complete paths from the filesystem root'),
4380 ),
4381 ),
4381 ]
4382 ]
4382 + walkopts,
4383 + walkopts,
4383 _(b'[OPTION]... [PATTERN]...'),
4384 _(b'[OPTION]... [PATTERN]...'),
4384 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4385 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4385 )
4386 )
4386 def locate(ui, repo, *pats, **opts):
4387 def locate(ui, repo, *pats, **opts):
4387 """locate files matching specific patterns (DEPRECATED)
4388 """locate files matching specific patterns (DEPRECATED)
4388
4389
4389 Print files under Mercurial control in the working directory whose
4390 Print files under Mercurial control in the working directory whose
4390 names match the given patterns.
4391 names match the given patterns.
4391
4392
4392 By default, this command searches all directories in the working
4393 By default, this command searches all directories in the working
4393 directory. To search just the current directory and its
4394 directory. To search just the current directory and its
4394 subdirectories, use "--include .".
4395 subdirectories, use "--include .".
4395
4396
4396 If no patterns are given to match, this command prints the names
4397 If no patterns are given to match, this command prints the names
4397 of all files under Mercurial control in the working directory.
4398 of all files under Mercurial control in the working directory.
4398
4399
4399 If you want to feed the output of this command into the "xargs"
4400 If you want to feed the output of this command into the "xargs"
4400 command, use the -0 option to both this command and "xargs". This
4401 command, use the -0 option to both this command and "xargs". This
4401 will avoid the problem of "xargs" treating single filenames that
4402 will avoid the problem of "xargs" treating single filenames that
4402 contain whitespace as multiple filenames.
4403 contain whitespace as multiple filenames.
4403
4404
4404 See :hg:`help files` for a more versatile command.
4405 See :hg:`help files` for a more versatile command.
4405
4406
4406 Returns 0 if a match is found, 1 otherwise.
4407 Returns 0 if a match is found, 1 otherwise.
4407 """
4408 """
4408 opts = pycompat.byteskwargs(opts)
4409 opts = pycompat.byteskwargs(opts)
4409 if opts.get(b'print0'):
4410 if opts.get(b'print0'):
4410 end = b'\0'
4411 end = b'\0'
4411 else:
4412 else:
4412 end = b'\n'
4413 end = b'\n'
4413 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4414 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4414
4415
4415 ret = 1
4416 ret = 1
4416 m = scmutil.match(
4417 m = scmutil.match(
4417 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4418 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4418 )
4419 )
4419
4420
4420 ui.pager(b'locate')
4421 ui.pager(b'locate')
4421 if ctx.rev() is None:
4422 if ctx.rev() is None:
4422 # When run on the working copy, "locate" includes removed files, so
4423 # When run on the working copy, "locate" includes removed files, so
4423 # we get the list of files from the dirstate.
4424 # we get the list of files from the dirstate.
4424 filesgen = sorted(repo.dirstate.matches(m))
4425 filesgen = sorted(repo.dirstate.matches(m))
4425 else:
4426 else:
4426 filesgen = ctx.matches(m)
4427 filesgen = ctx.matches(m)
4427 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4428 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4428 for abs in filesgen:
4429 for abs in filesgen:
4429 if opts.get(b'fullpath'):
4430 if opts.get(b'fullpath'):
4430 ui.write(repo.wjoin(abs), end)
4431 ui.write(repo.wjoin(abs), end)
4431 else:
4432 else:
4432 ui.write(uipathfn(abs), end)
4433 ui.write(uipathfn(abs), end)
4433 ret = 0
4434 ret = 0
4434
4435
4435 return ret
4436 return ret
4436
4437
4437
4438
4438 @command(
4439 @command(
4439 b'log|history',
4440 b'log|history',
4440 [
4441 [
4441 (
4442 (
4442 b'f',
4443 b'f',
4443 b'follow',
4444 b'follow',
4444 None,
4445 None,
4445 _(
4446 _(
4446 b'follow changeset history, or file history across copies and renames'
4447 b'follow changeset history, or file history across copies and renames'
4447 ),
4448 ),
4448 ),
4449 ),
4449 (
4450 (
4450 b'',
4451 b'',
4451 b'follow-first',
4452 b'follow-first',
4452 None,
4453 None,
4453 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4454 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4454 ),
4455 ),
4455 (
4456 (
4456 b'd',
4457 b'd',
4457 b'date',
4458 b'date',
4458 b'',
4459 b'',
4459 _(b'show revisions matching date spec'),
4460 _(b'show revisions matching date spec'),
4460 _(b'DATE'),
4461 _(b'DATE'),
4461 ),
4462 ),
4462 (b'C', b'copies', None, _(b'show copied files')),
4463 (b'C', b'copies', None, _(b'show copied files')),
4463 (
4464 (
4464 b'k',
4465 b'k',
4465 b'keyword',
4466 b'keyword',
4466 [],
4467 [],
4467 _(b'do case-insensitive search for a given text'),
4468 _(b'do case-insensitive search for a given text'),
4468 _(b'TEXT'),
4469 _(b'TEXT'),
4469 ),
4470 ),
4470 (
4471 (
4471 b'r',
4472 b'r',
4472 b'rev',
4473 b'rev',
4473 [],
4474 [],
4474 _(b'revisions to select or follow from'),
4475 _(b'revisions to select or follow from'),
4475 _(b'REV'),
4476 _(b'REV'),
4476 ),
4477 ),
4477 (
4478 (
4478 b'L',
4479 b'L',
4479 b'line-range',
4480 b'line-range',
4480 [],
4481 [],
4481 _(b'follow line range of specified file (EXPERIMENTAL)'),
4482 _(b'follow line range of specified file (EXPERIMENTAL)'),
4482 _(b'FILE,RANGE'),
4483 _(b'FILE,RANGE'),
4483 ),
4484 ),
4484 (
4485 (
4485 b'',
4486 b'',
4486 b'removed',
4487 b'removed',
4487 None,
4488 None,
4488 _(b'include revisions where files were removed'),
4489 _(b'include revisions where files were removed'),
4489 ),
4490 ),
4490 (
4491 (
4491 b'm',
4492 b'm',
4492 b'only-merges',
4493 b'only-merges',
4493 None,
4494 None,
4494 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4495 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4495 ),
4496 ),
4496 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4497 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4497 (
4498 (
4498 b'',
4499 b'',
4499 b'only-branch',
4500 b'only-branch',
4500 [],
4501 [],
4501 _(
4502 _(
4502 b'show only changesets within the given named branch (DEPRECATED)'
4503 b'show only changesets within the given named branch (DEPRECATED)'
4503 ),
4504 ),
4504 _(b'BRANCH'),
4505 _(b'BRANCH'),
4505 ),
4506 ),
4506 (
4507 (
4507 b'b',
4508 b'b',
4508 b'branch',
4509 b'branch',
4509 [],
4510 [],
4510 _(b'show changesets within the given named branch'),
4511 _(b'show changesets within the given named branch'),
4511 _(b'BRANCH'),
4512 _(b'BRANCH'),
4512 ),
4513 ),
4513 (
4514 (
4514 b'B',
4515 b'B',
4515 b'bookmark',
4516 b'bookmark',
4516 [],
4517 [],
4517 _(b"show changesets within the given bookmark"),
4518 _(b"show changesets within the given bookmark"),
4518 _(b'BOOKMARK'),
4519 _(b'BOOKMARK'),
4519 ),
4520 ),
4520 (
4521 (
4521 b'P',
4522 b'P',
4522 b'prune',
4523 b'prune',
4523 [],
4524 [],
4524 _(b'do not display revision or any of its ancestors'),
4525 _(b'do not display revision or any of its ancestors'),
4525 _(b'REV'),
4526 _(b'REV'),
4526 ),
4527 ),
4527 ]
4528 ]
4528 + logopts
4529 + logopts
4529 + walkopts,
4530 + walkopts,
4530 _(b'[OPTION]... [FILE]'),
4531 _(b'[OPTION]... [FILE]'),
4531 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4532 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4532 helpbasic=True,
4533 helpbasic=True,
4533 inferrepo=True,
4534 inferrepo=True,
4534 intents={INTENT_READONLY},
4535 intents={INTENT_READONLY},
4535 )
4536 )
4536 def log(ui, repo, *pats, **opts):
4537 def log(ui, repo, *pats, **opts):
4537 """show revision history of entire repository or files
4538 """show revision history of entire repository or files
4538
4539
4539 Print the revision history of the specified files or the entire
4540 Print the revision history of the specified files or the entire
4540 project.
4541 project.
4541
4542
4542 If no revision range is specified, the default is ``tip:0`` unless
4543 If no revision range is specified, the default is ``tip:0`` unless
4543 --follow is set.
4544 --follow is set.
4544
4545
4545 File history is shown without following rename or copy history of
4546 File history is shown without following rename or copy history of
4546 files. Use -f/--follow with a filename to follow history across
4547 files. Use -f/--follow with a filename to follow history across
4547 renames and copies. --follow without a filename will only show
4548 renames and copies. --follow without a filename will only show
4548 ancestors of the starting revisions. The starting revisions can be
4549 ancestors of the starting revisions. The starting revisions can be
4549 specified by -r/--rev, which default to the working directory parent.
4550 specified by -r/--rev, which default to the working directory parent.
4550
4551
4551 By default this command prints revision number and changeset id,
4552 By default this command prints revision number and changeset id,
4552 tags, non-trivial parents, user, date and time, and a summary for
4553 tags, non-trivial parents, user, date and time, and a summary for
4553 each commit. When the -v/--verbose switch is used, the list of
4554 each commit. When the -v/--verbose switch is used, the list of
4554 changed files and full commit message are shown.
4555 changed files and full commit message are shown.
4555
4556
4556 With --graph the revisions are shown as an ASCII art DAG with the most
4557 With --graph the revisions are shown as an ASCII art DAG with the most
4557 recent changeset at the top.
4558 recent changeset at the top.
4558 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4559 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4559 involved in an unresolved merge conflict, '_' closes a branch,
4560 involved in an unresolved merge conflict, '_' closes a branch,
4560 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4561 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4561 changeset from the lines below is a parent of the 'o' merge on the same
4562 changeset from the lines below is a parent of the 'o' merge on the same
4562 line.
4563 line.
4563 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4564 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4564 of a '|' indicates one or more revisions in a path are omitted.
4565 of a '|' indicates one or more revisions in a path are omitted.
4565
4566
4566 .. container:: verbose
4567 .. container:: verbose
4567
4568
4568 Use -L/--line-range FILE,M:N options to follow the history of lines
4569 Use -L/--line-range FILE,M:N options to follow the history of lines
4569 from M to N in FILE. With -p/--patch only diff hunks affecting
4570 from M to N in FILE. With -p/--patch only diff hunks affecting
4570 specified line range will be shown. This option requires --follow;
4571 specified line range will be shown. This option requires --follow;
4571 it can be specified multiple times. Currently, this option is not
4572 it can be specified multiple times. Currently, this option is not
4572 compatible with --graph. This option is experimental.
4573 compatible with --graph. This option is experimental.
4573
4574
4574 .. note::
4575 .. note::
4575
4576
4576 :hg:`log --patch` may generate unexpected diff output for merge
4577 :hg:`log --patch` may generate unexpected diff output for merge
4577 changesets, as it will only compare the merge changeset against
4578 changesets, as it will only compare the merge changeset against
4578 its first parent. Also, only files different from BOTH parents
4579 its first parent. Also, only files different from BOTH parents
4579 will appear in files:.
4580 will appear in files:.
4580
4581
4581 .. note::
4582 .. note::
4582
4583
4583 For performance reasons, :hg:`log FILE` may omit duplicate changes
4584 For performance reasons, :hg:`log FILE` may omit duplicate changes
4584 made on branches and will not show removals or mode changes. To
4585 made on branches and will not show removals or mode changes. To
4585 see all such changes, use the --removed switch.
4586 see all such changes, use the --removed switch.
4586
4587
4587 .. container:: verbose
4588 .. container:: verbose
4588
4589
4589 .. note::
4590 .. note::
4590
4591
4591 The history resulting from -L/--line-range options depends on diff
4592 The history resulting from -L/--line-range options depends on diff
4592 options; for instance if white-spaces are ignored, respective changes
4593 options; for instance if white-spaces are ignored, respective changes
4593 with only white-spaces in specified line range will not be listed.
4594 with only white-spaces in specified line range will not be listed.
4594
4595
4595 .. container:: verbose
4596 .. container:: verbose
4596
4597
4597 Some examples:
4598 Some examples:
4598
4599
4599 - changesets with full descriptions and file lists::
4600 - changesets with full descriptions and file lists::
4600
4601
4601 hg log -v
4602 hg log -v
4602
4603
4603 - changesets ancestral to the working directory::
4604 - changesets ancestral to the working directory::
4604
4605
4605 hg log -f
4606 hg log -f
4606
4607
4607 - last 10 commits on the current branch::
4608 - last 10 commits on the current branch::
4608
4609
4609 hg log -l 10 -b .
4610 hg log -l 10 -b .
4610
4611
4611 - changesets showing all modifications of a file, including removals::
4612 - changesets showing all modifications of a file, including removals::
4612
4613
4613 hg log --removed file.c
4614 hg log --removed file.c
4614
4615
4615 - all changesets that touch a directory, with diffs, excluding merges::
4616 - all changesets that touch a directory, with diffs, excluding merges::
4616
4617
4617 hg log -Mp lib/
4618 hg log -Mp lib/
4618
4619
4619 - all revision numbers that match a keyword::
4620 - all revision numbers that match a keyword::
4620
4621
4621 hg log -k bug --template "{rev}\\n"
4622 hg log -k bug --template "{rev}\\n"
4622
4623
4623 - the full hash identifier of the working directory parent::
4624 - the full hash identifier of the working directory parent::
4624
4625
4625 hg log -r . --template "{node}\\n"
4626 hg log -r . --template "{node}\\n"
4626
4627
4627 - list available log templates::
4628 - list available log templates::
4628
4629
4629 hg log -T list
4630 hg log -T list
4630
4631
4631 - check if a given changeset is included in a tagged release::
4632 - check if a given changeset is included in a tagged release::
4632
4633
4633 hg log -r "a21ccf and ancestor(1.9)"
4634 hg log -r "a21ccf and ancestor(1.9)"
4634
4635
4635 - find all changesets by some user in a date range::
4636 - find all changesets by some user in a date range::
4636
4637
4637 hg log -k alice -d "may 2008 to jul 2008"
4638 hg log -k alice -d "may 2008 to jul 2008"
4638
4639
4639 - summary of all changesets after the last tag::
4640 - summary of all changesets after the last tag::
4640
4641
4641 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4642 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4642
4643
4643 - changesets touching lines 13 to 23 for file.c::
4644 - changesets touching lines 13 to 23 for file.c::
4644
4645
4645 hg log -L file.c,13:23
4646 hg log -L file.c,13:23
4646
4647
4647 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4648 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4648 main.c with patch::
4649 main.c with patch::
4649
4650
4650 hg log -L file.c,13:23 -L main.c,2:6 -p
4651 hg log -L file.c,13:23 -L main.c,2:6 -p
4651
4652
4652 See :hg:`help dates` for a list of formats valid for -d/--date.
4653 See :hg:`help dates` for a list of formats valid for -d/--date.
4653
4654
4654 See :hg:`help revisions` for more about specifying and ordering
4655 See :hg:`help revisions` for more about specifying and ordering
4655 revisions.
4656 revisions.
4656
4657
4657 See :hg:`help templates` for more about pre-packaged styles and
4658 See :hg:`help templates` for more about pre-packaged styles and
4658 specifying custom templates. The default template used by the log
4659 specifying custom templates. The default template used by the log
4659 command can be customized via the ``command-templates.log`` configuration
4660 command can be customized via the ``command-templates.log`` configuration
4660 setting.
4661 setting.
4661
4662
4662 Returns 0 on success.
4663 Returns 0 on success.
4663
4664
4664 """
4665 """
4665 opts = pycompat.byteskwargs(opts)
4666 opts = pycompat.byteskwargs(opts)
4666 linerange = opts.get(b'line_range')
4667 linerange = opts.get(b'line_range')
4667
4668
4668 if linerange and not opts.get(b'follow'):
4669 if linerange and not opts.get(b'follow'):
4669 raise error.InputError(_(b'--line-range requires --follow'))
4670 raise error.InputError(_(b'--line-range requires --follow'))
4670
4671
4671 if linerange and pats:
4672 if linerange and pats:
4672 # TODO: take pats as patterns with no line-range filter
4673 # TODO: take pats as patterns with no line-range filter
4673 raise error.InputError(
4674 raise error.InputError(
4674 _(b'FILE arguments are not compatible with --line-range option')
4675 _(b'FILE arguments are not compatible with --line-range option')
4675 )
4676 )
4676
4677
4677 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4678 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4678 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4679 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4679 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4680 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4680 if linerange:
4681 if linerange:
4681 # TODO: should follow file history from logcmdutil._initialrevs(),
4682 # TODO: should follow file history from logcmdutil._initialrevs(),
4682 # then filter the result by logcmdutil._makerevset() and --limit
4683 # then filter the result by logcmdutil._makerevset() and --limit
4683 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4684 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4684
4685
4685 getcopies = None
4686 getcopies = None
4686 if opts.get(b'copies'):
4687 if opts.get(b'copies'):
4687 endrev = None
4688 endrev = None
4688 if revs:
4689 if revs:
4689 endrev = revs.max() + 1
4690 endrev = revs.max() + 1
4690 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4691 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4691
4692
4692 ui.pager(b'log')
4693 ui.pager(b'log')
4693 displayer = logcmdutil.changesetdisplayer(
4694 displayer = logcmdutil.changesetdisplayer(
4694 ui, repo, opts, differ, buffered=True
4695 ui, repo, opts, differ, buffered=True
4695 )
4696 )
4696 if opts.get(b'graph'):
4697 if opts.get(b'graph'):
4697 displayfn = logcmdutil.displaygraphrevs
4698 displayfn = logcmdutil.displaygraphrevs
4698 else:
4699 else:
4699 displayfn = logcmdutil.displayrevs
4700 displayfn = logcmdutil.displayrevs
4700 displayfn(ui, repo, revs, displayer, getcopies)
4701 displayfn(ui, repo, revs, displayer, getcopies)
4701
4702
4702
4703
4703 @command(
4704 @command(
4704 b'manifest',
4705 b'manifest',
4705 [
4706 [
4706 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4707 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4707 (b'', b'all', False, _(b"list files from all revisions")),
4708 (b'', b'all', False, _(b"list files from all revisions")),
4708 ]
4709 ]
4709 + formatteropts,
4710 + formatteropts,
4710 _(b'[-r REV]'),
4711 _(b'[-r REV]'),
4711 helpcategory=command.CATEGORY_MAINTENANCE,
4712 helpcategory=command.CATEGORY_MAINTENANCE,
4712 intents={INTENT_READONLY},
4713 intents={INTENT_READONLY},
4713 )
4714 )
4714 def manifest(ui, repo, node=None, rev=None, **opts):
4715 def manifest(ui, repo, node=None, rev=None, **opts):
4715 """output the current or given revision of the project manifest
4716 """output the current or given revision of the project manifest
4716
4717
4717 Print a list of version controlled files for the given revision.
4718 Print a list of version controlled files for the given revision.
4718 If no revision is given, the first parent of the working directory
4719 If no revision is given, the first parent of the working directory
4719 is used, or the null revision if no revision is checked out.
4720 is used, or the null revision if no revision is checked out.
4720
4721
4721 With -v, print file permissions, symlink and executable bits.
4722 With -v, print file permissions, symlink and executable bits.
4722 With --debug, print file revision hashes.
4723 With --debug, print file revision hashes.
4723
4724
4724 If option --all is specified, the list of all files from all revisions
4725 If option --all is specified, the list of all files from all revisions
4725 is printed. This includes deleted and renamed files.
4726 is printed. This includes deleted and renamed files.
4726
4727
4727 Returns 0 on success.
4728 Returns 0 on success.
4728 """
4729 """
4729 opts = pycompat.byteskwargs(opts)
4730 opts = pycompat.byteskwargs(opts)
4730 fm = ui.formatter(b'manifest', opts)
4731 fm = ui.formatter(b'manifest', opts)
4731
4732
4732 if opts.get(b'all'):
4733 if opts.get(b'all'):
4733 if rev or node:
4734 if rev or node:
4734 raise error.InputError(_(b"can't specify a revision with --all"))
4735 raise error.InputError(_(b"can't specify a revision with --all"))
4735
4736
4736 res = set()
4737 res = set()
4737 for rev in repo:
4738 for rev in repo:
4738 ctx = repo[rev]
4739 ctx = repo[rev]
4739 res |= set(ctx.files())
4740 res |= set(ctx.files())
4740
4741
4741 ui.pager(b'manifest')
4742 ui.pager(b'manifest')
4742 for f in sorted(res):
4743 for f in sorted(res):
4743 fm.startitem()
4744 fm.startitem()
4744 fm.write(b"path", b'%s\n', f)
4745 fm.write(b"path", b'%s\n', f)
4745 fm.end()
4746 fm.end()
4746 return
4747 return
4747
4748
4748 if rev and node:
4749 if rev and node:
4749 raise error.InputError(_(b"please specify just one revision"))
4750 raise error.InputError(_(b"please specify just one revision"))
4750
4751
4751 if not node:
4752 if not node:
4752 node = rev
4753 node = rev
4753
4754
4754 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4755 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4755 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4756 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4756 if node:
4757 if node:
4757 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4758 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4758 ctx = scmutil.revsingle(repo, node)
4759 ctx = scmutil.revsingle(repo, node)
4759 mf = ctx.manifest()
4760 mf = ctx.manifest()
4760 ui.pager(b'manifest')
4761 ui.pager(b'manifest')
4761 for f in ctx:
4762 for f in ctx:
4762 fm.startitem()
4763 fm.startitem()
4763 fm.context(ctx=ctx)
4764 fm.context(ctx=ctx)
4764 fl = ctx[f].flags()
4765 fl = ctx[f].flags()
4765 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4766 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4766 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4767 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4767 fm.write(b'path', b'%s\n', f)
4768 fm.write(b'path', b'%s\n', f)
4768 fm.end()
4769 fm.end()
4769
4770
4770
4771
4771 @command(
4772 @command(
4772 b'merge',
4773 b'merge',
4773 [
4774 [
4774 (
4775 (
4775 b'f',
4776 b'f',
4776 b'force',
4777 b'force',
4777 None,
4778 None,
4778 _(b'force a merge including outstanding changes (DEPRECATED)'),
4779 _(b'force a merge including outstanding changes (DEPRECATED)'),
4779 ),
4780 ),
4780 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4781 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4781 (
4782 (
4782 b'P',
4783 b'P',
4783 b'preview',
4784 b'preview',
4784 None,
4785 None,
4785 _(b'review revisions to merge (no merge is performed)'),
4786 _(b'review revisions to merge (no merge is performed)'),
4786 ),
4787 ),
4787 (b'', b'abort', None, _(b'abort the ongoing merge')),
4788 (b'', b'abort', None, _(b'abort the ongoing merge')),
4788 ]
4789 ]
4789 + mergetoolopts,
4790 + mergetoolopts,
4790 _(b'[-P] [[-r] REV]'),
4791 _(b'[-P] [[-r] REV]'),
4791 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4792 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4792 helpbasic=True,
4793 helpbasic=True,
4793 )
4794 )
4794 def merge(ui, repo, node=None, **opts):
4795 def merge(ui, repo, node=None, **opts):
4795 """merge another revision into working directory
4796 """merge another revision into working directory
4796
4797
4797 The current working directory is updated with all changes made in
4798 The current working directory is updated with all changes made in
4798 the requested revision since the last common predecessor revision.
4799 the requested revision since the last common predecessor revision.
4799
4800
4800 Files that changed between either parent are marked as changed for
4801 Files that changed between either parent are marked as changed for
4801 the next commit and a commit must be performed before any further
4802 the next commit and a commit must be performed before any further
4802 updates to the repository are allowed. The next commit will have
4803 updates to the repository are allowed. The next commit will have
4803 two parents.
4804 two parents.
4804
4805
4805 ``--tool`` can be used to specify the merge tool used for file
4806 ``--tool`` can be used to specify the merge tool used for file
4806 merges. It overrides the HGMERGE environment variable and your
4807 merges. It overrides the HGMERGE environment variable and your
4807 configuration files. See :hg:`help merge-tools` for options.
4808 configuration files. See :hg:`help merge-tools` for options.
4808
4809
4809 If no revision is specified, the working directory's parent is a
4810 If no revision is specified, the working directory's parent is a
4810 head revision, and the current branch contains exactly one other
4811 head revision, and the current branch contains exactly one other
4811 head, the other head is merged with by default. Otherwise, an
4812 head, the other head is merged with by default. Otherwise, an
4812 explicit revision with which to merge must be provided.
4813 explicit revision with which to merge must be provided.
4813
4814
4814 See :hg:`help resolve` for information on handling file conflicts.
4815 See :hg:`help resolve` for information on handling file conflicts.
4815
4816
4816 To undo an uncommitted merge, use :hg:`merge --abort` which
4817 To undo an uncommitted merge, use :hg:`merge --abort` which
4817 will check out a clean copy of the original merge parent, losing
4818 will check out a clean copy of the original merge parent, losing
4818 all changes.
4819 all changes.
4819
4820
4820 Returns 0 on success, 1 if there are unresolved files.
4821 Returns 0 on success, 1 if there are unresolved files.
4821 """
4822 """
4822
4823
4823 opts = pycompat.byteskwargs(opts)
4824 opts = pycompat.byteskwargs(opts)
4824 abort = opts.get(b'abort')
4825 abort = opts.get(b'abort')
4825 if abort and repo.dirstate.p2() == nullid:
4826 if abort and repo.dirstate.p2() == nullid:
4826 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4827 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4827 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4828 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4828 if abort:
4829 if abort:
4829 state = cmdutil.getunfinishedstate(repo)
4830 state = cmdutil.getunfinishedstate(repo)
4830 if state and state._opname != b'merge':
4831 if state and state._opname != b'merge':
4831 raise error.StateError(
4832 raise error.StateError(
4832 _(b'cannot abort merge with %s in progress') % (state._opname),
4833 _(b'cannot abort merge with %s in progress') % (state._opname),
4833 hint=state.hint(),
4834 hint=state.hint(),
4834 )
4835 )
4835 if node:
4836 if node:
4836 raise error.InputError(_(b"cannot specify a node with --abort"))
4837 raise error.InputError(_(b"cannot specify a node with --abort"))
4837 return hg.abortmerge(repo.ui, repo)
4838 return hg.abortmerge(repo.ui, repo)
4838
4839
4839 if opts.get(b'rev') and node:
4840 if opts.get(b'rev') and node:
4840 raise error.InputError(_(b"please specify just one revision"))
4841 raise error.InputError(_(b"please specify just one revision"))
4841 if not node:
4842 if not node:
4842 node = opts.get(b'rev')
4843 node = opts.get(b'rev')
4843
4844
4844 if node:
4845 if node:
4845 ctx = scmutil.revsingle(repo, node)
4846 ctx = scmutil.revsingle(repo, node)
4846 else:
4847 else:
4847 if ui.configbool(b'commands', b'merge.require-rev'):
4848 if ui.configbool(b'commands', b'merge.require-rev'):
4848 raise error.InputError(
4849 raise error.InputError(
4849 _(
4850 _(
4850 b'configuration requires specifying revision to merge '
4851 b'configuration requires specifying revision to merge '
4851 b'with'
4852 b'with'
4852 )
4853 )
4853 )
4854 )
4854 ctx = repo[destutil.destmerge(repo)]
4855 ctx = repo[destutil.destmerge(repo)]
4855
4856
4856 if ctx.node() is None:
4857 if ctx.node() is None:
4857 raise error.InputError(
4858 raise error.InputError(
4858 _(b'merging with the working copy has no effect')
4859 _(b'merging with the working copy has no effect')
4859 )
4860 )
4860
4861
4861 if opts.get(b'preview'):
4862 if opts.get(b'preview'):
4862 # find nodes that are ancestors of p2 but not of p1
4863 # find nodes that are ancestors of p2 but not of p1
4863 p1 = repo[b'.'].node()
4864 p1 = repo[b'.'].node()
4864 p2 = ctx.node()
4865 p2 = ctx.node()
4865 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4866 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4866
4867
4867 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4868 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4868 for node in nodes:
4869 for node in nodes:
4869 displayer.show(repo[node])
4870 displayer.show(repo[node])
4870 displayer.close()
4871 displayer.close()
4871 return 0
4872 return 0
4872
4873
4873 # ui.forcemerge is an internal variable, do not document
4874 # ui.forcemerge is an internal variable, do not document
4874 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4875 with ui.configoverride(overrides, b'merge'):
4876 with ui.configoverride(overrides, b'merge'):
4876 force = opts.get(b'force')
4877 force = opts.get(b'force')
4877 labels = [b'working copy', b'merge rev']
4878 labels = [b'working copy', b'merge rev']
4878 return hg.merge(ctx, force=force, labels=labels)
4879 return hg.merge(ctx, force=force, labels=labels)
4879
4880
4880
4881
4881 statemod.addunfinished(
4882 statemod.addunfinished(
4882 b'merge',
4883 b'merge',
4883 fname=None,
4884 fname=None,
4884 clearable=True,
4885 clearable=True,
4885 allowcommit=True,
4886 allowcommit=True,
4886 cmdmsg=_(b'outstanding uncommitted merge'),
4887 cmdmsg=_(b'outstanding uncommitted merge'),
4887 abortfunc=hg.abortmerge,
4888 abortfunc=hg.abortmerge,
4888 statushint=_(
4889 statushint=_(
4889 b'To continue: hg commit\nTo abort: hg merge --abort'
4890 b'To continue: hg commit\nTo abort: hg merge --abort'
4890 ),
4891 ),
4891 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4892 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4892 )
4893 )
4893
4894
4894
4895
4895 @command(
4896 @command(
4896 b'outgoing|out',
4897 b'outgoing|out',
4897 [
4898 [
4898 (
4899 (
4899 b'f',
4900 b'f',
4900 b'force',
4901 b'force',
4901 None,
4902 None,
4902 _(b'run even when the destination is unrelated'),
4903 _(b'run even when the destination is unrelated'),
4903 ),
4904 ),
4904 (
4905 (
4905 b'r',
4906 b'r',
4906 b'rev',
4907 b'rev',
4907 [],
4908 [],
4908 _(b'a changeset intended to be included in the destination'),
4909 _(b'a changeset intended to be included in the destination'),
4909 _(b'REV'),
4910 _(b'REV'),
4910 ),
4911 ),
4911 (b'n', b'newest-first', None, _(b'show newest record first')),
4912 (b'n', b'newest-first', None, _(b'show newest record first')),
4912 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4913 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4913 (
4914 (
4914 b'b',
4915 b'b',
4915 b'branch',
4916 b'branch',
4916 [],
4917 [],
4917 _(b'a specific branch you would like to push'),
4918 _(b'a specific branch you would like to push'),
4918 _(b'BRANCH'),
4919 _(b'BRANCH'),
4919 ),
4920 ),
4920 ]
4921 ]
4921 + logopts
4922 + logopts
4922 + remoteopts
4923 + remoteopts
4923 + subrepoopts,
4924 + subrepoopts,
4924 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4925 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4925 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4926 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4926 )
4927 )
4927 def outgoing(ui, repo, dest=None, **opts):
4928 def outgoing(ui, repo, dest=None, **opts):
4928 """show changesets not found in the destination
4929 """show changesets not found in the destination
4929
4930
4930 Show changesets not found in the specified destination repository
4931 Show changesets not found in the specified destination repository
4931 or the default push location. These are the changesets that would
4932 or the default push location. These are the changesets that would
4932 be pushed if a push was requested.
4933 be pushed if a push was requested.
4933
4934
4934 See pull for details of valid destination formats.
4935 See pull for details of valid destination formats.
4935
4936
4936 .. container:: verbose
4937 .. container:: verbose
4937
4938
4938 With -B/--bookmarks, the result of bookmark comparison between
4939 With -B/--bookmarks, the result of bookmark comparison between
4939 local and remote repositories is displayed. With -v/--verbose,
4940 local and remote repositories is displayed. With -v/--verbose,
4940 status is also displayed for each bookmark like below::
4941 status is also displayed for each bookmark like below::
4941
4942
4942 BM1 01234567890a added
4943 BM1 01234567890a added
4943 BM2 deleted
4944 BM2 deleted
4944 BM3 234567890abc advanced
4945 BM3 234567890abc advanced
4945 BM4 34567890abcd diverged
4946 BM4 34567890abcd diverged
4946 BM5 4567890abcde changed
4947 BM5 4567890abcde changed
4947
4948
4948 The action taken when pushing depends on the
4949 The action taken when pushing depends on the
4949 status of each bookmark:
4950 status of each bookmark:
4950
4951
4951 :``added``: push with ``-B`` will create it
4952 :``added``: push with ``-B`` will create it
4952 :``deleted``: push with ``-B`` will delete it
4953 :``deleted``: push with ``-B`` will delete it
4953 :``advanced``: push will update it
4954 :``advanced``: push will update it
4954 :``diverged``: push with ``-B`` will update it
4955 :``diverged``: push with ``-B`` will update it
4955 :``changed``: push with ``-B`` will update it
4956 :``changed``: push with ``-B`` will update it
4956
4957
4957 From the point of view of pushing behavior, bookmarks
4958 From the point of view of pushing behavior, bookmarks
4958 existing only in the remote repository are treated as
4959 existing only in the remote repository are treated as
4959 ``deleted``, even if it is in fact added remotely.
4960 ``deleted``, even if it is in fact added remotely.
4960
4961
4961 Returns 0 if there are outgoing changes, 1 otherwise.
4962 Returns 0 if there are outgoing changes, 1 otherwise.
4962 """
4963 """
4963 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4964 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4964 # style URLs, so don't overwrite dest.
4965 # style URLs, so don't overwrite dest.
4965 path = ui.getpath(dest, default=(b'default-push', b'default'))
4966 path = ui.getpath(dest, default=(b'default-push', b'default'))
4966 if not path:
4967 if not path:
4967 raise error.ConfigError(
4968 raise error.ConfigError(
4968 _(b'default repository not configured!'),
4969 _(b'default repository not configured!'),
4969 hint=_(b"see 'hg help config.paths'"),
4970 hint=_(b"see 'hg help config.paths'"),
4970 )
4971 )
4971
4972
4972 opts = pycompat.byteskwargs(opts)
4973 opts = pycompat.byteskwargs(opts)
4973 if opts.get(b'graph'):
4974 if opts.get(b'graph'):
4974 logcmdutil.checkunsupportedgraphflags([], opts)
4975 logcmdutil.checkunsupportedgraphflags([], opts)
4975 o, other = hg._outgoing(ui, repo, dest, opts)
4976 o, other = hg._outgoing(ui, repo, dest, opts)
4976 if not o:
4977 if not o:
4977 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4978 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4978 return
4979 return
4979
4980
4980 revdag = logcmdutil.graphrevs(repo, o, opts)
4981 revdag = logcmdutil.graphrevs(repo, o, opts)
4981 ui.pager(b'outgoing')
4982 ui.pager(b'outgoing')
4982 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4983 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4983 logcmdutil.displaygraph(
4984 logcmdutil.displaygraph(
4984 ui, repo, revdag, displayer, graphmod.asciiedges
4985 ui, repo, revdag, displayer, graphmod.asciiedges
4985 )
4986 )
4986 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4987 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4987 return 0
4988 return 0
4988
4989
4989 if opts.get(b'bookmarks'):
4990 if opts.get(b'bookmarks'):
4990 dest = path.pushloc or path.loc
4991 dest = path.pushloc or path.loc
4991 other = hg.peer(repo, opts, dest)
4992 other = hg.peer(repo, opts, dest)
4992 try:
4993 try:
4993 if b'bookmarks' not in other.listkeys(b'namespaces'):
4994 if b'bookmarks' not in other.listkeys(b'namespaces'):
4994 ui.warn(_(b"remote doesn't support bookmarks\n"))
4995 ui.warn(_(b"remote doesn't support bookmarks\n"))
4995 return 0
4996 return 0
4996 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4997 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4997 ui.pager(b'outgoing')
4998 ui.pager(b'outgoing')
4998 return bookmarks.outgoing(ui, repo, other)
4999 return bookmarks.outgoing(ui, repo, other)
4999 finally:
5000 finally:
5000 other.close()
5001 other.close()
5001
5002
5002 repo._subtoppath = path.pushloc or path.loc
5003 repo._subtoppath = path.pushloc or path.loc
5003 try:
5004 try:
5004 return hg.outgoing(ui, repo, dest, opts)
5005 return hg.outgoing(ui, repo, dest, opts)
5005 finally:
5006 finally:
5006 del repo._subtoppath
5007 del repo._subtoppath
5007
5008
5008
5009
5009 @command(
5010 @command(
5010 b'parents',
5011 b'parents',
5011 [
5012 [
5012 (
5013 (
5013 b'r',
5014 b'r',
5014 b'rev',
5015 b'rev',
5015 b'',
5016 b'',
5016 _(b'show parents of the specified revision'),
5017 _(b'show parents of the specified revision'),
5017 _(b'REV'),
5018 _(b'REV'),
5018 ),
5019 ),
5019 ]
5020 ]
5020 + templateopts,
5021 + templateopts,
5021 _(b'[-r REV] [FILE]'),
5022 _(b'[-r REV] [FILE]'),
5022 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5023 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5023 inferrepo=True,
5024 inferrepo=True,
5024 )
5025 )
5025 def parents(ui, repo, file_=None, **opts):
5026 def parents(ui, repo, file_=None, **opts):
5026 """show the parents of the working directory or revision (DEPRECATED)
5027 """show the parents of the working directory or revision (DEPRECATED)
5027
5028
5028 Print the working directory's parent revisions. If a revision is
5029 Print the working directory's parent revisions. If a revision is
5029 given via -r/--rev, the parent of that revision will be printed.
5030 given via -r/--rev, the parent of that revision will be printed.
5030 If a file argument is given, the revision in which the file was
5031 If a file argument is given, the revision in which the file was
5031 last changed (before the working directory revision or the
5032 last changed (before the working directory revision or the
5032 argument to --rev if given) is printed.
5033 argument to --rev if given) is printed.
5033
5034
5034 This command is equivalent to::
5035 This command is equivalent to::
5035
5036
5036 hg log -r "p1()+p2()" or
5037 hg log -r "p1()+p2()" or
5037 hg log -r "p1(REV)+p2(REV)" or
5038 hg log -r "p1(REV)+p2(REV)" or
5038 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5039 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5039 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5040 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5040
5041
5041 See :hg:`summary` and :hg:`help revsets` for related information.
5042 See :hg:`summary` and :hg:`help revsets` for related information.
5042
5043
5043 Returns 0 on success.
5044 Returns 0 on success.
5044 """
5045 """
5045
5046
5046 opts = pycompat.byteskwargs(opts)
5047 opts = pycompat.byteskwargs(opts)
5047 rev = opts.get(b'rev')
5048 rev = opts.get(b'rev')
5048 if rev:
5049 if rev:
5049 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5050 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5050 ctx = scmutil.revsingle(repo, rev, None)
5051 ctx = scmutil.revsingle(repo, rev, None)
5051
5052
5052 if file_:
5053 if file_:
5053 m = scmutil.match(ctx, (file_,), opts)
5054 m = scmutil.match(ctx, (file_,), opts)
5054 if m.anypats() or len(m.files()) != 1:
5055 if m.anypats() or len(m.files()) != 1:
5055 raise error.InputError(_(b'can only specify an explicit filename'))
5056 raise error.InputError(_(b'can only specify an explicit filename'))
5056 file_ = m.files()[0]
5057 file_ = m.files()[0]
5057 filenodes = []
5058 filenodes = []
5058 for cp in ctx.parents():
5059 for cp in ctx.parents():
5059 if not cp:
5060 if not cp:
5060 continue
5061 continue
5061 try:
5062 try:
5062 filenodes.append(cp.filenode(file_))
5063 filenodes.append(cp.filenode(file_))
5063 except error.LookupError:
5064 except error.LookupError:
5064 pass
5065 pass
5065 if not filenodes:
5066 if not filenodes:
5066 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5067 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5067 p = []
5068 p = []
5068 for fn in filenodes:
5069 for fn in filenodes:
5069 fctx = repo.filectx(file_, fileid=fn)
5070 fctx = repo.filectx(file_, fileid=fn)
5070 p.append(fctx.node())
5071 p.append(fctx.node())
5071 else:
5072 else:
5072 p = [cp.node() for cp in ctx.parents()]
5073 p = [cp.node() for cp in ctx.parents()]
5073
5074
5074 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5075 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5075 for n in p:
5076 for n in p:
5076 if n != nullid:
5077 if n != nullid:
5077 displayer.show(repo[n])
5078 displayer.show(repo[n])
5078 displayer.close()
5079 displayer.close()
5079
5080
5080
5081
5081 @command(
5082 @command(
5082 b'paths',
5083 b'paths',
5083 formatteropts,
5084 formatteropts,
5084 _(b'[NAME]'),
5085 _(b'[NAME]'),
5085 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5086 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5086 optionalrepo=True,
5087 optionalrepo=True,
5087 intents={INTENT_READONLY},
5088 intents={INTENT_READONLY},
5088 )
5089 )
5089 def paths(ui, repo, search=None, **opts):
5090 def paths(ui, repo, search=None, **opts):
5090 """show aliases for remote repositories
5091 """show aliases for remote repositories
5091
5092
5092 Show definition of symbolic path name NAME. If no name is given,
5093 Show definition of symbolic path name NAME. If no name is given,
5093 show definition of all available names.
5094 show definition of all available names.
5094
5095
5095 Option -q/--quiet suppresses all output when searching for NAME
5096 Option -q/--quiet suppresses all output when searching for NAME
5096 and shows only the path names when listing all definitions.
5097 and shows only the path names when listing all definitions.
5097
5098
5098 Path names are defined in the [paths] section of your
5099 Path names are defined in the [paths] section of your
5099 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5100 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5100 repository, ``.hg/hgrc`` is used, too.
5101 repository, ``.hg/hgrc`` is used, too.
5101
5102
5102 The path names ``default`` and ``default-push`` have a special
5103 The path names ``default`` and ``default-push`` have a special
5103 meaning. When performing a push or pull operation, they are used
5104 meaning. When performing a push or pull operation, they are used
5104 as fallbacks if no location is specified on the command-line.
5105 as fallbacks if no location is specified on the command-line.
5105 When ``default-push`` is set, it will be used for push and
5106 When ``default-push`` is set, it will be used for push and
5106 ``default`` will be used for pull; otherwise ``default`` is used
5107 ``default`` will be used for pull; otherwise ``default`` is used
5107 as the fallback for both. When cloning a repository, the clone
5108 as the fallback for both. When cloning a repository, the clone
5108 source is written as ``default`` in ``.hg/hgrc``.
5109 source is written as ``default`` in ``.hg/hgrc``.
5109
5110
5110 .. note::
5111 .. note::
5111
5112
5112 ``default`` and ``default-push`` apply to all inbound (e.g.
5113 ``default`` and ``default-push`` apply to all inbound (e.g.
5113 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5114 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5114 and :hg:`bundle`) operations.
5115 and :hg:`bundle`) operations.
5115
5116
5116 See :hg:`help urls` for more information.
5117 See :hg:`help urls` for more information.
5117
5118
5118 .. container:: verbose
5119 .. container:: verbose
5119
5120
5120 Template:
5121 Template:
5121
5122
5122 The following keywords are supported. See also :hg:`help templates`.
5123 The following keywords are supported. See also :hg:`help templates`.
5123
5124
5124 :name: String. Symbolic name of the path alias.
5125 :name: String. Symbolic name of the path alias.
5125 :pushurl: String. URL for push operations.
5126 :pushurl: String. URL for push operations.
5126 :url: String. URL or directory path for the other operations.
5127 :url: String. URL or directory path for the other operations.
5127
5128
5128 Returns 0 on success.
5129 Returns 0 on success.
5129 """
5130 """
5130
5131
5131 opts = pycompat.byteskwargs(opts)
5132 opts = pycompat.byteskwargs(opts)
5132 ui.pager(b'paths')
5133 ui.pager(b'paths')
5133 if search:
5134 if search:
5134 pathitems = [
5135 pathitems = [
5135 (name, path)
5136 (name, path)
5136 for name, path in pycompat.iteritems(ui.paths)
5137 for name, path in pycompat.iteritems(ui.paths)
5137 if name == search
5138 if name == search
5138 ]
5139 ]
5139 else:
5140 else:
5140 pathitems = sorted(pycompat.iteritems(ui.paths))
5141 pathitems = sorted(pycompat.iteritems(ui.paths))
5141
5142
5142 fm = ui.formatter(b'paths', opts)
5143 fm = ui.formatter(b'paths', opts)
5143 if fm.isplain():
5144 if fm.isplain():
5144 hidepassword = util.hidepassword
5145 hidepassword = util.hidepassword
5145 else:
5146 else:
5146 hidepassword = bytes
5147 hidepassword = bytes
5147 if ui.quiet:
5148 if ui.quiet:
5148 namefmt = b'%s\n'
5149 namefmt = b'%s\n'
5149 else:
5150 else:
5150 namefmt = b'%s = '
5151 namefmt = b'%s = '
5151 showsubopts = not search and not ui.quiet
5152 showsubopts = not search and not ui.quiet
5152
5153
5153 for name, path in pathitems:
5154 for name, path in pathitems:
5154 fm.startitem()
5155 fm.startitem()
5155 fm.condwrite(not search, b'name', namefmt, name)
5156 fm.condwrite(not search, b'name', namefmt, name)
5156 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5157 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5157 for subopt, value in sorted(path.suboptions.items()):
5158 for subopt, value in sorted(path.suboptions.items()):
5158 assert subopt not in (b'name', b'url')
5159 assert subopt not in (b'name', b'url')
5159 if showsubopts:
5160 if showsubopts:
5160 fm.plain(b'%s:%s = ' % (name, subopt))
5161 fm.plain(b'%s:%s = ' % (name, subopt))
5161 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5162 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5162
5163
5163 fm.end()
5164 fm.end()
5164
5165
5165 if search and not pathitems:
5166 if search and not pathitems:
5166 if not ui.quiet:
5167 if not ui.quiet:
5167 ui.warn(_(b"not found!\n"))
5168 ui.warn(_(b"not found!\n"))
5168 return 1
5169 return 1
5169 else:
5170 else:
5170 return 0
5171 return 0
5171
5172
5172
5173
5173 @command(
5174 @command(
5174 b'phase',
5175 b'phase',
5175 [
5176 [
5176 (b'p', b'public', False, _(b'set changeset phase to public')),
5177 (b'p', b'public', False, _(b'set changeset phase to public')),
5177 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5178 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5178 (b's', b'secret', False, _(b'set changeset phase to secret')),
5179 (b's', b'secret', False, _(b'set changeset phase to secret')),
5179 (b'f', b'force', False, _(b'allow to move boundary backward')),
5180 (b'f', b'force', False, _(b'allow to move boundary backward')),
5180 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5181 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5181 ],
5182 ],
5182 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5183 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5183 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5184 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5184 )
5185 )
5185 def phase(ui, repo, *revs, **opts):
5186 def phase(ui, repo, *revs, **opts):
5186 """set or show the current phase name
5187 """set or show the current phase name
5187
5188
5188 With no argument, show the phase name of the current revision(s).
5189 With no argument, show the phase name of the current revision(s).
5189
5190
5190 With one of -p/--public, -d/--draft or -s/--secret, change the
5191 With one of -p/--public, -d/--draft or -s/--secret, change the
5191 phase value of the specified revisions.
5192 phase value of the specified revisions.
5192
5193
5193 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5194 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5194 lower phase to a higher phase. Phases are ordered as follows::
5195 lower phase to a higher phase. Phases are ordered as follows::
5195
5196
5196 public < draft < secret
5197 public < draft < secret
5197
5198
5198 Returns 0 on success, 1 if some phases could not be changed.
5199 Returns 0 on success, 1 if some phases could not be changed.
5199
5200
5200 (For more information about the phases concept, see :hg:`help phases`.)
5201 (For more information about the phases concept, see :hg:`help phases`.)
5201 """
5202 """
5202 opts = pycompat.byteskwargs(opts)
5203 opts = pycompat.byteskwargs(opts)
5203 # search for a unique phase argument
5204 # search for a unique phase argument
5204 targetphase = None
5205 targetphase = None
5205 for idx, name in enumerate(phases.cmdphasenames):
5206 for idx, name in enumerate(phases.cmdphasenames):
5206 if opts[name]:
5207 if opts[name]:
5207 if targetphase is not None:
5208 if targetphase is not None:
5208 raise error.InputError(_(b'only one phase can be specified'))
5209 raise error.InputError(_(b'only one phase can be specified'))
5209 targetphase = idx
5210 targetphase = idx
5210
5211
5211 # look for specified revision
5212 # look for specified revision
5212 revs = list(revs)
5213 revs = list(revs)
5213 revs.extend(opts[b'rev'])
5214 revs.extend(opts[b'rev'])
5214 if not revs:
5215 if not revs:
5215 # display both parents as the second parent phase can influence
5216 # display both parents as the second parent phase can influence
5216 # the phase of a merge commit
5217 # the phase of a merge commit
5217 revs = [c.rev() for c in repo[None].parents()]
5218 revs = [c.rev() for c in repo[None].parents()]
5218
5219
5219 revs = scmutil.revrange(repo, revs)
5220 revs = scmutil.revrange(repo, revs)
5220
5221
5221 ret = 0
5222 ret = 0
5222 if targetphase is None:
5223 if targetphase is None:
5223 # display
5224 # display
5224 for r in revs:
5225 for r in revs:
5225 ctx = repo[r]
5226 ctx = repo[r]
5226 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5227 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5227 else:
5228 else:
5228 with repo.lock(), repo.transaction(b"phase") as tr:
5229 with repo.lock(), repo.transaction(b"phase") as tr:
5229 # set phase
5230 # set phase
5230 if not revs:
5231 if not revs:
5231 raise error.InputError(_(b'empty revision set'))
5232 raise error.InputError(_(b'empty revision set'))
5232 nodes = [repo[r].node() for r in revs]
5233 nodes = [repo[r].node() for r in revs]
5233 # moving revision from public to draft may hide them
5234 # moving revision from public to draft may hide them
5234 # We have to check result on an unfiltered repository
5235 # We have to check result on an unfiltered repository
5235 unfi = repo.unfiltered()
5236 unfi = repo.unfiltered()
5236 getphase = unfi._phasecache.phase
5237 getphase = unfi._phasecache.phase
5237 olddata = [getphase(unfi, r) for r in unfi]
5238 olddata = [getphase(unfi, r) for r in unfi]
5238 phases.advanceboundary(repo, tr, targetphase, nodes)
5239 phases.advanceboundary(repo, tr, targetphase, nodes)
5239 if opts[b'force']:
5240 if opts[b'force']:
5240 phases.retractboundary(repo, tr, targetphase, nodes)
5241 phases.retractboundary(repo, tr, targetphase, nodes)
5241 getphase = unfi._phasecache.phase
5242 getphase = unfi._phasecache.phase
5242 newdata = [getphase(unfi, r) for r in unfi]
5243 newdata = [getphase(unfi, r) for r in unfi]
5243 changes = sum(newdata[r] != olddata[r] for r in unfi)
5244 changes = sum(newdata[r] != olddata[r] for r in unfi)
5244 cl = unfi.changelog
5245 cl = unfi.changelog
5245 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5246 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5246 if rejected:
5247 if rejected:
5247 ui.warn(
5248 ui.warn(
5248 _(
5249 _(
5249 b'cannot move %i changesets to a higher '
5250 b'cannot move %i changesets to a higher '
5250 b'phase, use --force\n'
5251 b'phase, use --force\n'
5251 )
5252 )
5252 % len(rejected)
5253 % len(rejected)
5253 )
5254 )
5254 ret = 1
5255 ret = 1
5255 if changes:
5256 if changes:
5256 msg = _(b'phase changed for %i changesets\n') % changes
5257 msg = _(b'phase changed for %i changesets\n') % changes
5257 if ret:
5258 if ret:
5258 ui.status(msg)
5259 ui.status(msg)
5259 else:
5260 else:
5260 ui.note(msg)
5261 ui.note(msg)
5261 else:
5262 else:
5262 ui.warn(_(b'no phases changed\n'))
5263 ui.warn(_(b'no phases changed\n'))
5263 return ret
5264 return ret
5264
5265
5265
5266
5266 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5267 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5267 """Run after a changegroup has been added via pull/unbundle
5268 """Run after a changegroup has been added via pull/unbundle
5268
5269
5269 This takes arguments below:
5270 This takes arguments below:
5270
5271
5271 :modheads: change of heads by pull/unbundle
5272 :modheads: change of heads by pull/unbundle
5272 :optupdate: updating working directory is needed or not
5273 :optupdate: updating working directory is needed or not
5273 :checkout: update destination revision (or None to default destination)
5274 :checkout: update destination revision (or None to default destination)
5274 :brev: a name, which might be a bookmark to be activated after updating
5275 :brev: a name, which might be a bookmark to be activated after updating
5275
5276
5276 return True if update raise any conflict, False otherwise.
5277 return True if update raise any conflict, False otherwise.
5277 """
5278 """
5278 if modheads == 0:
5279 if modheads == 0:
5279 return False
5280 return False
5280 if optupdate:
5281 if optupdate:
5281 try:
5282 try:
5282 return hg.updatetotally(ui, repo, checkout, brev)
5283 return hg.updatetotally(ui, repo, checkout, brev)
5283 except error.UpdateAbort as inst:
5284 except error.UpdateAbort as inst:
5284 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5285 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5285 hint = inst.hint
5286 hint = inst.hint
5286 raise error.UpdateAbort(msg, hint=hint)
5287 raise error.UpdateAbort(msg, hint=hint)
5287 if modheads is not None and modheads > 1:
5288 if modheads is not None and modheads > 1:
5288 currentbranchheads = len(repo.branchheads())
5289 currentbranchheads = len(repo.branchheads())
5289 if currentbranchheads == modheads:
5290 if currentbranchheads == modheads:
5290 ui.status(
5291 ui.status(
5291 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5292 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5292 )
5293 )
5293 elif currentbranchheads > 1:
5294 elif currentbranchheads > 1:
5294 ui.status(
5295 ui.status(
5295 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5296 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5296 )
5297 )
5297 else:
5298 else:
5298 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5299 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5299 elif not ui.configbool(b'commands', b'update.requiredest'):
5300 elif not ui.configbool(b'commands', b'update.requiredest'):
5300 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5301 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5301 return False
5302 return False
5302
5303
5303
5304
5304 @command(
5305 @command(
5305 b'pull',
5306 b'pull',
5306 [
5307 [
5307 (
5308 (
5308 b'u',
5309 b'u',
5309 b'update',
5310 b'update',
5310 None,
5311 None,
5311 _(b'update to new branch head if new descendants were pulled'),
5312 _(b'update to new branch head if new descendants were pulled'),
5312 ),
5313 ),
5313 (
5314 (
5314 b'f',
5315 b'f',
5315 b'force',
5316 b'force',
5316 None,
5317 None,
5317 _(b'run even when remote repository is unrelated'),
5318 _(b'run even when remote repository is unrelated'),
5318 ),
5319 ),
5319 (
5320 (
5320 b'',
5321 b'',
5321 b'confirm',
5322 b'confirm',
5322 None,
5323 None,
5323 _(b'confirm pull before applying changes'),
5324 _(b'confirm pull before applying changes'),
5324 ),
5325 ),
5325 (
5326 (
5326 b'r',
5327 b'r',
5327 b'rev',
5328 b'rev',
5328 [],
5329 [],
5329 _(b'a remote changeset intended to be added'),
5330 _(b'a remote changeset intended to be added'),
5330 _(b'REV'),
5331 _(b'REV'),
5331 ),
5332 ),
5332 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5333 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5333 (
5334 (
5334 b'b',
5335 b'b',
5335 b'branch',
5336 b'branch',
5336 [],
5337 [],
5337 _(b'a specific branch you would like to pull'),
5338 _(b'a specific branch you would like to pull'),
5338 _(b'BRANCH'),
5339 _(b'BRANCH'),
5339 ),
5340 ),
5340 ]
5341 ]
5341 + remoteopts,
5342 + remoteopts,
5342 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5343 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5343 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5344 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5344 helpbasic=True,
5345 helpbasic=True,
5345 )
5346 )
5346 def pull(ui, repo, *sources, **opts):
5347 def pull(ui, repo, *sources, **opts):
5347 """pull changes from the specified source
5348 """pull changes from the specified source
5348
5349
5349 Pull changes from a remote repository to a local one.
5350 Pull changes from a remote repository to a local one.
5350
5351
5351 This finds all changes from the repository at the specified path
5352 This finds all changes from the repository at the specified path
5352 or URL and adds them to a local repository (the current one unless
5353 or URL and adds them to a local repository (the current one unless
5353 -R is specified). By default, this does not update the copy of the
5354 -R is specified). By default, this does not update the copy of the
5354 project in the working directory.
5355 project in the working directory.
5355
5356
5356 When cloning from servers that support it, Mercurial may fetch
5357 When cloning from servers that support it, Mercurial may fetch
5357 pre-generated data. When this is done, hooks operating on incoming
5358 pre-generated data. When this is done, hooks operating on incoming
5358 changesets and changegroups may fire more than once, once for each
5359 changesets and changegroups may fire more than once, once for each
5359 pre-generated bundle and as well as for any additional remaining
5360 pre-generated bundle and as well as for any additional remaining
5360 data. See :hg:`help -e clonebundles` for more.
5361 data. See :hg:`help -e clonebundles` for more.
5361
5362
5362 Use :hg:`incoming` if you want to see what would have been added
5363 Use :hg:`incoming` if you want to see what would have been added
5363 by a pull at the time you issued this command. If you then decide
5364 by a pull at the time you issued this command. If you then decide
5364 to add those changes to the repository, you should use :hg:`pull
5365 to add those changes to the repository, you should use :hg:`pull
5365 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5366 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5366
5367
5367 If SOURCE is omitted, the 'default' path will be used.
5368 If SOURCE is omitted, the 'default' path will be used.
5368 See :hg:`help urls` for more information.
5369 See :hg:`help urls` for more information.
5369
5370
5370 If multiple sources are specified, they will be pulled sequentially as if
5371 If multiple sources are specified, they will be pulled sequentially as if
5371 the command was run multiple time. If --update is specify and the command
5372 the command was run multiple time. If --update is specify and the command
5372 will stop at the first failed --update.
5373 will stop at the first failed --update.
5373
5374
5374 Specifying bookmark as ``.`` is equivalent to specifying the active
5375 Specifying bookmark as ``.`` is equivalent to specifying the active
5375 bookmark's name.
5376 bookmark's name.
5376
5377
5377 Returns 0 on success, 1 if an update had unresolved files.
5378 Returns 0 on success, 1 if an update had unresolved files.
5378 """
5379 """
5379
5380
5380 opts = pycompat.byteskwargs(opts)
5381 opts = pycompat.byteskwargs(opts)
5381 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5382 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5382 b'update'
5383 b'update'
5383 ):
5384 ):
5384 msg = _(b'update destination required by configuration')
5385 msg = _(b'update destination required by configuration')
5385 hint = _(b'use hg pull followed by hg update DEST')
5386 hint = _(b'use hg pull followed by hg update DEST')
5386 raise error.InputError(msg, hint=hint)
5387 raise error.InputError(msg, hint=hint)
5387
5388
5388 if not sources:
5389 if not sources:
5389 sources = [b'default']
5390 sources = [b'default']
5390 for source in sources:
5391 for source in sources:
5391 source, branches = hg.parseurl(
5392 source, branches = hg.parseurl(
5392 ui.expandpath(source), opts.get(b'branch')
5393 ui.expandpath(source), opts.get(b'branch')
5393 )
5394 )
5394 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5395 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5395 ui.flush()
5396 ui.flush()
5396 other = hg.peer(repo, opts, source)
5397 other = hg.peer(repo, opts, source)
5397 update_conflict = None
5398 update_conflict = None
5398 try:
5399 try:
5399 revs, checkout = hg.addbranchrevs(
5400 revs, checkout = hg.addbranchrevs(
5400 repo, other, branches, opts.get(b'rev')
5401 repo, other, branches, opts.get(b'rev')
5401 )
5402 )
5402
5403
5403 pullopargs = {}
5404 pullopargs = {}
5404
5405
5405 nodes = None
5406 nodes = None
5406 if opts.get(b'bookmark') or revs:
5407 if opts.get(b'bookmark') or revs:
5407 # The list of bookmark used here is the same used to actually update
5408 # The list of bookmark used here is the same used to actually update
5408 # the bookmark names, to avoid the race from issue 4689 and we do
5409 # the bookmark names, to avoid the race from issue 4689 and we do
5409 # all lookup and bookmark queries in one go so they see the same
5410 # all lookup and bookmark queries in one go so they see the same
5410 # version of the server state (issue 4700).
5411 # version of the server state (issue 4700).
5411 nodes = []
5412 nodes = []
5412 fnodes = []
5413 fnodes = []
5413 revs = revs or []
5414 revs = revs or []
5414 if revs and not other.capable(b'lookup'):
5415 if revs and not other.capable(b'lookup'):
5415 err = _(
5416 err = _(
5416 b"other repository doesn't support revision lookup, "
5417 b"other repository doesn't support revision lookup, "
5417 b"so a rev cannot be specified."
5418 b"so a rev cannot be specified."
5418 )
5419 )
5419 raise error.Abort(err)
5420 raise error.Abort(err)
5420 with other.commandexecutor() as e:
5421 with other.commandexecutor() as e:
5421 fremotebookmarks = e.callcommand(
5422 fremotebookmarks = e.callcommand(
5422 b'listkeys', {b'namespace': b'bookmarks'}
5423 b'listkeys', {b'namespace': b'bookmarks'}
5423 )
5424 )
5424 for r in revs:
5425 for r in revs:
5425 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5426 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5426 remotebookmarks = fremotebookmarks.result()
5427 remotebookmarks = fremotebookmarks.result()
5427 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5428 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5428 pullopargs[b'remotebookmarks'] = remotebookmarks
5429 pullopargs[b'remotebookmarks'] = remotebookmarks
5429 for b in opts.get(b'bookmark', []):
5430 for b in opts.get(b'bookmark', []):
5430 b = repo._bookmarks.expandname(b)
5431 b = repo._bookmarks.expandname(b)
5431 if b not in remotebookmarks:
5432 if b not in remotebookmarks:
5432 raise error.InputError(
5433 raise error.InputError(
5433 _(b'remote bookmark %s not found!') % b
5434 _(b'remote bookmark %s not found!') % b
5434 )
5435 )
5435 nodes.append(remotebookmarks[b])
5436 nodes.append(remotebookmarks[b])
5436 for i, rev in enumerate(revs):
5437 for i, rev in enumerate(revs):
5437 node = fnodes[i].result()
5438 node = fnodes[i].result()
5438 nodes.append(node)
5439 nodes.append(node)
5439 if rev == checkout:
5440 if rev == checkout:
5440 checkout = node
5441 checkout = node
5441
5442
5442 wlock = util.nullcontextmanager()
5443 wlock = util.nullcontextmanager()
5443 if opts.get(b'update'):
5444 if opts.get(b'update'):
5444 wlock = repo.wlock()
5445 wlock = repo.wlock()
5445 with wlock:
5446 with wlock:
5446 pullopargs.update(opts.get(b'opargs', {}))
5447 pullopargs.update(opts.get(b'opargs', {}))
5447 modheads = exchange.pull(
5448 modheads = exchange.pull(
5448 repo,
5449 repo,
5449 other,
5450 other,
5450 heads=nodes,
5451 heads=nodes,
5451 force=opts.get(b'force'),
5452 force=opts.get(b'force'),
5452 bookmarks=opts.get(b'bookmark', ()),
5453 bookmarks=opts.get(b'bookmark', ()),
5453 opargs=pullopargs,
5454 opargs=pullopargs,
5454 confirm=opts.get(b'confirm'),
5455 confirm=opts.get(b'confirm'),
5455 ).cgresult
5456 ).cgresult
5456
5457
5457 # brev is a name, which might be a bookmark to be activated at
5458 # brev is a name, which might be a bookmark to be activated at
5458 # the end of the update. In other words, it is an explicit
5459 # the end of the update. In other words, it is an explicit
5459 # destination of the update
5460 # destination of the update
5460 brev = None
5461 brev = None
5461
5462
5462 if checkout:
5463 if checkout:
5463 checkout = repo.unfiltered().changelog.rev(checkout)
5464 checkout = repo.unfiltered().changelog.rev(checkout)
5464
5465
5465 # order below depends on implementation of
5466 # order below depends on implementation of
5466 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5467 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5467 # because 'checkout' is determined without it.
5468 # because 'checkout' is determined without it.
5468 if opts.get(b'rev'):
5469 if opts.get(b'rev'):
5469 brev = opts[b'rev'][0]
5470 brev = opts[b'rev'][0]
5470 elif opts.get(b'branch'):
5471 elif opts.get(b'branch'):
5471 brev = opts[b'branch'][0]
5472 brev = opts[b'branch'][0]
5472 else:
5473 else:
5473 brev = branches[0]
5474 brev = branches[0]
5474 repo._subtoppath = source
5475 repo._subtoppath = source
5475 try:
5476 try:
5476 update_conflict = postincoming(
5477 update_conflict = postincoming(
5477 ui, repo, modheads, opts.get(b'update'), checkout, brev
5478 ui, repo, modheads, opts.get(b'update'), checkout, brev
5478 )
5479 )
5479 except error.FilteredRepoLookupError as exc:
5480 except error.FilteredRepoLookupError as exc:
5480 msg = _(b'cannot update to target: %s') % exc.args[0]
5481 msg = _(b'cannot update to target: %s') % exc.args[0]
5481 exc.args = (msg,) + exc.args[1:]
5482 exc.args = (msg,) + exc.args[1:]
5482 raise
5483 raise
5483 finally:
5484 finally:
5484 del repo._subtoppath
5485 del repo._subtoppath
5485
5486
5486 finally:
5487 finally:
5487 other.close()
5488 other.close()
5488 # skip the remaining pull source if they are some conflict.
5489 # skip the remaining pull source if they are some conflict.
5489 if update_conflict:
5490 if update_conflict:
5490 break
5491 break
5491 if update_conflict:
5492 if update_conflict:
5492 return 1
5493 return 1
5493 else:
5494 else:
5494 return 0
5495 return 0
5495
5496
5496
5497
5497 @command(
5498 @command(
5498 b'purge|clean',
5499 b'purge|clean',
5499 [
5500 [
5500 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5501 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5501 (b'', b'all', None, _(b'purge ignored files too')),
5502 (b'', b'all', None, _(b'purge ignored files too')),
5502 (b'i', b'ignored', None, _(b'purge only ignored files')),
5503 (b'i', b'ignored', None, _(b'purge only ignored files')),
5503 (b'', b'dirs', None, _(b'purge empty directories')),
5504 (b'', b'dirs', None, _(b'purge empty directories')),
5504 (b'', b'files', None, _(b'purge files')),
5505 (b'', b'files', None, _(b'purge files')),
5505 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5506 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5506 (
5507 (
5507 b'0',
5508 b'0',
5508 b'print0',
5509 b'print0',
5509 None,
5510 None,
5510 _(
5511 _(
5511 b'end filenames with NUL, for use with xargs'
5512 b'end filenames with NUL, for use with xargs'
5512 b' (implies -p/--print)'
5513 b' (implies -p/--print)'
5513 ),
5514 ),
5514 ),
5515 ),
5515 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5516 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5516 ]
5517 ]
5517 + cmdutil.walkopts,
5518 + cmdutil.walkopts,
5518 _(b'hg purge [OPTION]... [DIR]...'),
5519 _(b'hg purge [OPTION]... [DIR]...'),
5519 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5520 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5520 )
5521 )
5521 def purge(ui, repo, *dirs, **opts):
5522 def purge(ui, repo, *dirs, **opts):
5522 """removes files not tracked by Mercurial
5523 """removes files not tracked by Mercurial
5523
5524
5524 Delete files not known to Mercurial. This is useful to test local
5525 Delete files not known to Mercurial. This is useful to test local
5525 and uncommitted changes in an otherwise-clean source tree.
5526 and uncommitted changes in an otherwise-clean source tree.
5526
5527
5527 This means that purge will delete the following by default:
5528 This means that purge will delete the following by default:
5528
5529
5529 - Unknown files: files marked with "?" by :hg:`status`
5530 - Unknown files: files marked with "?" by :hg:`status`
5530 - Empty directories: in fact Mercurial ignores directories unless
5531 - Empty directories: in fact Mercurial ignores directories unless
5531 they contain files under source control management
5532 they contain files under source control management
5532
5533
5533 But it will leave untouched:
5534 But it will leave untouched:
5534
5535
5535 - Modified and unmodified tracked files
5536 - Modified and unmodified tracked files
5536 - Ignored files (unless -i or --all is specified)
5537 - Ignored files (unless -i or --all is specified)
5537 - New files added to the repository (with :hg:`add`)
5538 - New files added to the repository (with :hg:`add`)
5538
5539
5539 The --files and --dirs options can be used to direct purge to delete
5540 The --files and --dirs options can be used to direct purge to delete
5540 only files, only directories, or both. If neither option is given,
5541 only files, only directories, or both. If neither option is given,
5541 both will be deleted.
5542 both will be deleted.
5542
5543
5543 If directories are given on the command line, only files in these
5544 If directories are given on the command line, only files in these
5544 directories are considered.
5545 directories are considered.
5545
5546
5546 Be careful with purge, as you could irreversibly delete some files
5547 Be careful with purge, as you could irreversibly delete some files
5547 you forgot to add to the repository. If you only want to print the
5548 you forgot to add to the repository. If you only want to print the
5548 list of files that this program would delete, use the --print
5549 list of files that this program would delete, use the --print
5549 option.
5550 option.
5550 """
5551 """
5551 opts = pycompat.byteskwargs(opts)
5552 opts = pycompat.byteskwargs(opts)
5552 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5553 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5553
5554
5554 act = not opts.get(b'print')
5555 act = not opts.get(b'print')
5555 eol = b'\n'
5556 eol = b'\n'
5556 if opts.get(b'print0'):
5557 if opts.get(b'print0'):
5557 eol = b'\0'
5558 eol = b'\0'
5558 act = False # --print0 implies --print
5559 act = False # --print0 implies --print
5559 if opts.get(b'all', False):
5560 if opts.get(b'all', False):
5560 ignored = True
5561 ignored = True
5561 unknown = True
5562 unknown = True
5562 else:
5563 else:
5563 ignored = opts.get(b'ignored', False)
5564 ignored = opts.get(b'ignored', False)
5564 unknown = not ignored
5565 unknown = not ignored
5565
5566
5566 removefiles = opts.get(b'files')
5567 removefiles = opts.get(b'files')
5567 removedirs = opts.get(b'dirs')
5568 removedirs = opts.get(b'dirs')
5568 confirm = opts.get(b'confirm')
5569 confirm = opts.get(b'confirm')
5569 if confirm is None:
5570 if confirm is None:
5570 try:
5571 try:
5571 extensions.find(b'purge')
5572 extensions.find(b'purge')
5572 confirm = False
5573 confirm = False
5573 except KeyError:
5574 except KeyError:
5574 confirm = True
5575 confirm = True
5575
5576
5576 if not removefiles and not removedirs:
5577 if not removefiles and not removedirs:
5577 removefiles = True
5578 removefiles = True
5578 removedirs = True
5579 removedirs = True
5579
5580
5580 match = scmutil.match(repo[None], dirs, opts)
5581 match = scmutil.match(repo[None], dirs, opts)
5581
5582
5582 paths = mergemod.purge(
5583 paths = mergemod.purge(
5583 repo,
5584 repo,
5584 match,
5585 match,
5585 unknown=unknown,
5586 unknown=unknown,
5586 ignored=ignored,
5587 ignored=ignored,
5587 removeemptydirs=removedirs,
5588 removeemptydirs=removedirs,
5588 removefiles=removefiles,
5589 removefiles=removefiles,
5589 abortonerror=opts.get(b'abort_on_err'),
5590 abortonerror=opts.get(b'abort_on_err'),
5590 noop=not act,
5591 noop=not act,
5591 confirm=confirm,
5592 confirm=confirm,
5592 )
5593 )
5593
5594
5594 for path in paths:
5595 for path in paths:
5595 if not act:
5596 if not act:
5596 ui.write(b'%s%s' % (path, eol))
5597 ui.write(b'%s%s' % (path, eol))
5597
5598
5598
5599
5599 @command(
5600 @command(
5600 b'push',
5601 b'push',
5601 [
5602 [
5602 (b'f', b'force', None, _(b'force push')),
5603 (b'f', b'force', None, _(b'force push')),
5603 (
5604 (
5604 b'r',
5605 b'r',
5605 b'rev',
5606 b'rev',
5606 [],
5607 [],
5607 _(b'a changeset intended to be included in the destination'),
5608 _(b'a changeset intended to be included in the destination'),
5608 _(b'REV'),
5609 _(b'REV'),
5609 ),
5610 ),
5610 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5611 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5611 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5612 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5612 (
5613 (
5613 b'b',
5614 b'b',
5614 b'branch',
5615 b'branch',
5615 [],
5616 [],
5616 _(b'a specific branch you would like to push'),
5617 _(b'a specific branch you would like to push'),
5617 _(b'BRANCH'),
5618 _(b'BRANCH'),
5618 ),
5619 ),
5619 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5620 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5620 (
5621 (
5621 b'',
5622 b'',
5622 b'pushvars',
5623 b'pushvars',
5623 [],
5624 [],
5624 _(b'variables that can be sent to server (ADVANCED)'),
5625 _(b'variables that can be sent to server (ADVANCED)'),
5625 ),
5626 ),
5626 (
5627 (
5627 b'',
5628 b'',
5628 b'publish',
5629 b'publish',
5629 False,
5630 False,
5630 _(b'push the changeset as public (EXPERIMENTAL)'),
5631 _(b'push the changeset as public (EXPERIMENTAL)'),
5631 ),
5632 ),
5632 ]
5633 ]
5633 + remoteopts,
5634 + remoteopts,
5634 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5635 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5635 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5636 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5636 helpbasic=True,
5637 helpbasic=True,
5637 )
5638 )
5638 def push(ui, repo, *dests, **opts):
5639 def push(ui, repo, *dests, **opts):
5639 """push changes to the specified destination
5640 """push changes to the specified destination
5640
5641
5641 Push changesets from the local repository to the specified
5642 Push changesets from the local repository to the specified
5642 destination.
5643 destination.
5643
5644
5644 This operation is symmetrical to pull: it is identical to a pull
5645 This operation is symmetrical to pull: it is identical to a pull
5645 in the destination repository from the current one.
5646 in the destination repository from the current one.
5646
5647
5647 By default, push will not allow creation of new heads at the
5648 By default, push will not allow creation of new heads at the
5648 destination, since multiple heads would make it unclear which head
5649 destination, since multiple heads would make it unclear which head
5649 to use. In this situation, it is recommended to pull and merge
5650 to use. In this situation, it is recommended to pull and merge
5650 before pushing.
5651 before pushing.
5651
5652
5652 Use --new-branch if you want to allow push to create a new named
5653 Use --new-branch if you want to allow push to create a new named
5653 branch that is not present at the destination. This allows you to
5654 branch that is not present at the destination. This allows you to
5654 only create a new branch without forcing other changes.
5655 only create a new branch without forcing other changes.
5655
5656
5656 .. note::
5657 .. note::
5657
5658
5658 Extra care should be taken with the -f/--force option,
5659 Extra care should be taken with the -f/--force option,
5659 which will push all new heads on all branches, an action which will
5660 which will push all new heads on all branches, an action which will
5660 almost always cause confusion for collaborators.
5661 almost always cause confusion for collaborators.
5661
5662
5662 If -r/--rev is used, the specified revision and all its ancestors
5663 If -r/--rev is used, the specified revision and all its ancestors
5663 will be pushed to the remote repository.
5664 will be pushed to the remote repository.
5664
5665
5665 If -B/--bookmark is used, the specified bookmarked revision, its
5666 If -B/--bookmark is used, the specified bookmarked revision, its
5666 ancestors, and the bookmark will be pushed to the remote
5667 ancestors, and the bookmark will be pushed to the remote
5667 repository. Specifying ``.`` is equivalent to specifying the active
5668 repository. Specifying ``.`` is equivalent to specifying the active
5668 bookmark's name. Use the --all-bookmarks option for pushing all
5669 bookmark's name. Use the --all-bookmarks option for pushing all
5669 current bookmarks.
5670 current bookmarks.
5670
5671
5671 Please see :hg:`help urls` for important details about ``ssh://``
5672 Please see :hg:`help urls` for important details about ``ssh://``
5672 URLs. If DESTINATION is omitted, a default path will be used.
5673 URLs. If DESTINATION is omitted, a default path will be used.
5673
5674
5674 When passed multiple destinations, push will process them one after the
5675 When passed multiple destinations, push will process them one after the
5675 other, but stop should an error occur.
5676 other, but stop should an error occur.
5676
5677
5677 .. container:: verbose
5678 .. container:: verbose
5678
5679
5679 The --pushvars option sends strings to the server that become
5680 The --pushvars option sends strings to the server that become
5680 environment variables prepended with ``HG_USERVAR_``. For example,
5681 environment variables prepended with ``HG_USERVAR_``. For example,
5681 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5682 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5682 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5683 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5683
5684
5684 pushvars can provide for user-overridable hooks as well as set debug
5685 pushvars can provide for user-overridable hooks as well as set debug
5685 levels. One example is having a hook that blocks commits containing
5686 levels. One example is having a hook that blocks commits containing
5686 conflict markers, but enables the user to override the hook if the file
5687 conflict markers, but enables the user to override the hook if the file
5687 is using conflict markers for testing purposes or the file format has
5688 is using conflict markers for testing purposes or the file format has
5688 strings that look like conflict markers.
5689 strings that look like conflict markers.
5689
5690
5690 By default, servers will ignore `--pushvars`. To enable it add the
5691 By default, servers will ignore `--pushvars`. To enable it add the
5691 following to your configuration file::
5692 following to your configuration file::
5692
5693
5693 [push]
5694 [push]
5694 pushvars.server = true
5695 pushvars.server = true
5695
5696
5696 Returns 0 if push was successful, 1 if nothing to push.
5697 Returns 0 if push was successful, 1 if nothing to push.
5697 """
5698 """
5698
5699
5699 opts = pycompat.byteskwargs(opts)
5700 opts = pycompat.byteskwargs(opts)
5700
5701
5701 if opts.get(b'all_bookmarks'):
5702 if opts.get(b'all_bookmarks'):
5702 cmdutil.check_incompatible_arguments(
5703 cmdutil.check_incompatible_arguments(
5703 opts,
5704 opts,
5704 b'all_bookmarks',
5705 b'all_bookmarks',
5705 [b'bookmark', b'rev'],
5706 [b'bookmark', b'rev'],
5706 )
5707 )
5707 opts[b'bookmark'] = list(repo._bookmarks)
5708 opts[b'bookmark'] = list(repo._bookmarks)
5708
5709
5709 if opts.get(b'bookmark'):
5710 if opts.get(b'bookmark'):
5710 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5711 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5711 for b in opts[b'bookmark']:
5712 for b in opts[b'bookmark']:
5712 # translate -B options to -r so changesets get pushed
5713 # translate -B options to -r so changesets get pushed
5713 b = repo._bookmarks.expandname(b)
5714 b = repo._bookmarks.expandname(b)
5714 if b in repo._bookmarks:
5715 if b in repo._bookmarks:
5715 opts.setdefault(b'rev', []).append(b)
5716 opts.setdefault(b'rev', []).append(b)
5716 else:
5717 else:
5717 # if we try to push a deleted bookmark, translate it to null
5718 # if we try to push a deleted bookmark, translate it to null
5718 # this lets simultaneous -r, -b options continue working
5719 # this lets simultaneous -r, -b options continue working
5719 opts.setdefault(b'rev', []).append(b"null")
5720 opts.setdefault(b'rev', []).append(b"null")
5720
5721
5721 if not dests:
5722 if not dests:
5722 dests = [None]
5723 dests = [None]
5723 some_pushed = False
5724 some_pushed = False
5724 result = 0
5725 result = 0
5725 for dest in dests:
5726 for dest in dests:
5726 path = ui.getpath(dest, default=(b'default-push', b'default'))
5727 path = ui.getpath(dest, default=(b'default-push', b'default'))
5727 if not path:
5728 if not path:
5728 raise error.ConfigError(
5729 raise error.ConfigError(
5729 _(b'default repository not configured!'),
5730 _(b'default repository not configured!'),
5730 hint=_(b"see 'hg help config.paths'"),
5731 hint=_(b"see 'hg help config.paths'"),
5731 )
5732 )
5732 dest = path.pushloc or path.loc
5733 dest = path.pushloc or path.loc
5733 branches = (path.branch, opts.get(b'branch') or [])
5734 branches = (path.branch, opts.get(b'branch') or [])
5734 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5735 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5735 revs, checkout = hg.addbranchrevs(
5736 revs, checkout = hg.addbranchrevs(
5736 repo, repo, branches, opts.get(b'rev')
5737 repo, repo, branches, opts.get(b'rev')
5737 )
5738 )
5738 other = hg.peer(repo, opts, dest)
5739 other = hg.peer(repo, opts, dest)
5739
5740
5740 try:
5741 try:
5741 if revs:
5742 if revs:
5742 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5743 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5743 if not revs:
5744 if not revs:
5744 raise error.InputError(
5745 raise error.InputError(
5745 _(b"specified revisions evaluate to an empty set"),
5746 _(b"specified revisions evaluate to an empty set"),
5746 hint=_(b"use different revision arguments"),
5747 hint=_(b"use different revision arguments"),
5747 )
5748 )
5748 elif path.pushrev:
5749 elif path.pushrev:
5749 # It doesn't make any sense to specify ancestor revisions. So limit
5750 # It doesn't make any sense to specify ancestor revisions. So limit
5750 # to DAG heads to make discovery simpler.
5751 # to DAG heads to make discovery simpler.
5751 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5752 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5752 revs = scmutil.revrange(repo, [expr])
5753 revs = scmutil.revrange(repo, [expr])
5753 revs = [repo[rev].node() for rev in revs]
5754 revs = [repo[rev].node() for rev in revs]
5754 if not revs:
5755 if not revs:
5755 raise error.InputError(
5756 raise error.InputError(
5756 _(
5757 _(
5757 b'default push revset for path evaluates to an empty set'
5758 b'default push revset for path evaluates to an empty set'
5758 )
5759 )
5759 )
5760 )
5760 elif ui.configbool(b'commands', b'push.require-revs'):
5761 elif ui.configbool(b'commands', b'push.require-revs'):
5761 raise error.InputError(
5762 raise error.InputError(
5762 _(b'no revisions specified to push'),
5763 _(b'no revisions specified to push'),
5763 hint=_(b'did you mean "hg push -r ."?'),
5764 hint=_(b'did you mean "hg push -r ."?'),
5764 )
5765 )
5765
5766
5766 repo._subtoppath = dest
5767 repo._subtoppath = dest
5767 try:
5768 try:
5768 # push subrepos depth-first for coherent ordering
5769 # push subrepos depth-first for coherent ordering
5769 c = repo[b'.']
5770 c = repo[b'.']
5770 subs = c.substate # only repos that are committed
5771 subs = c.substate # only repos that are committed
5771 for s in sorted(subs):
5772 for s in sorted(subs):
5772 sub_result = c.sub(s).push(opts)
5773 sub_result = c.sub(s).push(opts)
5773 if sub_result == 0:
5774 if sub_result == 0:
5774 return 1
5775 return 1
5775 finally:
5776 finally:
5776 del repo._subtoppath
5777 del repo._subtoppath
5777
5778
5778 opargs = dict(
5779 opargs = dict(
5779 opts.get(b'opargs', {})
5780 opts.get(b'opargs', {})
5780 ) # copy opargs since we may mutate it
5781 ) # copy opargs since we may mutate it
5781 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5782 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5782
5783
5783 pushop = exchange.push(
5784 pushop = exchange.push(
5784 repo,
5785 repo,
5785 other,
5786 other,
5786 opts.get(b'force'),
5787 opts.get(b'force'),
5787 revs=revs,
5788 revs=revs,
5788 newbranch=opts.get(b'new_branch'),
5789 newbranch=opts.get(b'new_branch'),
5789 bookmarks=opts.get(b'bookmark', ()),
5790 bookmarks=opts.get(b'bookmark', ()),
5790 publish=opts.get(b'publish'),
5791 publish=opts.get(b'publish'),
5791 opargs=opargs,
5792 opargs=opargs,
5792 )
5793 )
5793
5794
5794 if pushop.cgresult == 0:
5795 if pushop.cgresult == 0:
5795 result = 1
5796 result = 1
5796 elif pushop.cgresult is not None:
5797 elif pushop.cgresult is not None:
5797 some_pushed = True
5798 some_pushed = True
5798
5799
5799 if pushop.bkresult is not None:
5800 if pushop.bkresult is not None:
5800 if pushop.bkresult == 2:
5801 if pushop.bkresult == 2:
5801 result = 2
5802 result = 2
5802 elif not result and pushop.bkresult:
5803 elif not result and pushop.bkresult:
5803 result = 2
5804 result = 2
5804
5805
5805 if result:
5806 if result:
5806 break
5807 break
5807
5808
5808 finally:
5809 finally:
5809 other.close()
5810 other.close()
5810 if result == 0 and not some_pushed:
5811 if result == 0 and not some_pushed:
5811 result = 1
5812 result = 1
5812 return result
5813 return result
5813
5814
5814
5815
5815 @command(
5816 @command(
5816 b'recover',
5817 b'recover',
5817 [
5818 [
5818 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5819 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5819 ],
5820 ],
5820 helpcategory=command.CATEGORY_MAINTENANCE,
5821 helpcategory=command.CATEGORY_MAINTENANCE,
5821 )
5822 )
5822 def recover(ui, repo, **opts):
5823 def recover(ui, repo, **opts):
5823 """roll back an interrupted transaction
5824 """roll back an interrupted transaction
5824
5825
5825 Recover from an interrupted commit or pull.
5826 Recover from an interrupted commit or pull.
5826
5827
5827 This command tries to fix the repository status after an
5828 This command tries to fix the repository status after an
5828 interrupted operation. It should only be necessary when Mercurial
5829 interrupted operation. It should only be necessary when Mercurial
5829 suggests it.
5830 suggests it.
5830
5831
5831 Returns 0 if successful, 1 if nothing to recover or verify fails.
5832 Returns 0 if successful, 1 if nothing to recover or verify fails.
5832 """
5833 """
5833 ret = repo.recover()
5834 ret = repo.recover()
5834 if ret:
5835 if ret:
5835 if opts['verify']:
5836 if opts['verify']:
5836 return hg.verify(repo)
5837 return hg.verify(repo)
5837 else:
5838 else:
5838 msg = _(
5839 msg = _(
5839 b"(verify step skipped, run `hg verify` to check your "
5840 b"(verify step skipped, run `hg verify` to check your "
5840 b"repository content)\n"
5841 b"repository content)\n"
5841 )
5842 )
5842 ui.warn(msg)
5843 ui.warn(msg)
5843 return 0
5844 return 0
5844 return 1
5845 return 1
5845
5846
5846
5847
5847 @command(
5848 @command(
5848 b'remove|rm',
5849 b'remove|rm',
5849 [
5850 [
5850 (b'A', b'after', None, _(b'record delete for missing files')),
5851 (b'A', b'after', None, _(b'record delete for missing files')),
5851 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5852 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5852 ]
5853 ]
5853 + subrepoopts
5854 + subrepoopts
5854 + walkopts
5855 + walkopts
5855 + dryrunopts,
5856 + dryrunopts,
5856 _(b'[OPTION]... FILE...'),
5857 _(b'[OPTION]... FILE...'),
5857 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5858 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5858 helpbasic=True,
5859 helpbasic=True,
5859 inferrepo=True,
5860 inferrepo=True,
5860 )
5861 )
5861 def remove(ui, repo, *pats, **opts):
5862 def remove(ui, repo, *pats, **opts):
5862 """remove the specified files on the next commit
5863 """remove the specified files on the next commit
5863
5864
5864 Schedule the indicated files for removal from the current branch.
5865 Schedule the indicated files for removal from the current branch.
5865
5866
5866 This command schedules the files to be removed at the next commit.
5867 This command schedules the files to be removed at the next commit.
5867 To undo a remove before that, see :hg:`revert`. To undo added
5868 To undo a remove before that, see :hg:`revert`. To undo added
5868 files, see :hg:`forget`.
5869 files, see :hg:`forget`.
5869
5870
5870 .. container:: verbose
5871 .. container:: verbose
5871
5872
5872 -A/--after can be used to remove only files that have already
5873 -A/--after can be used to remove only files that have already
5873 been deleted, -f/--force can be used to force deletion, and -Af
5874 been deleted, -f/--force can be used to force deletion, and -Af
5874 can be used to remove files from the next revision without
5875 can be used to remove files from the next revision without
5875 deleting them from the working directory.
5876 deleting them from the working directory.
5876
5877
5877 The following table details the behavior of remove for different
5878 The following table details the behavior of remove for different
5878 file states (columns) and option combinations (rows). The file
5879 file states (columns) and option combinations (rows). The file
5879 states are Added [A], Clean [C], Modified [M] and Missing [!]
5880 states are Added [A], Clean [C], Modified [M] and Missing [!]
5880 (as reported by :hg:`status`). The actions are Warn, Remove
5881 (as reported by :hg:`status`). The actions are Warn, Remove
5881 (from branch) and Delete (from disk):
5882 (from branch) and Delete (from disk):
5882
5883
5883 ========= == == == ==
5884 ========= == == == ==
5884 opt/state A C M !
5885 opt/state A C M !
5885 ========= == == == ==
5886 ========= == == == ==
5886 none W RD W R
5887 none W RD W R
5887 -f R RD RD R
5888 -f R RD RD R
5888 -A W W W R
5889 -A W W W R
5889 -Af R R R R
5890 -Af R R R R
5890 ========= == == == ==
5891 ========= == == == ==
5891
5892
5892 .. note::
5893 .. note::
5893
5894
5894 :hg:`remove` never deletes files in Added [A] state from the
5895 :hg:`remove` never deletes files in Added [A] state from the
5895 working directory, not even if ``--force`` is specified.
5896 working directory, not even if ``--force`` is specified.
5896
5897
5897 Returns 0 on success, 1 if any warnings encountered.
5898 Returns 0 on success, 1 if any warnings encountered.
5898 """
5899 """
5899
5900
5900 opts = pycompat.byteskwargs(opts)
5901 opts = pycompat.byteskwargs(opts)
5901 after, force = opts.get(b'after'), opts.get(b'force')
5902 after, force = opts.get(b'after'), opts.get(b'force')
5902 dryrun = opts.get(b'dry_run')
5903 dryrun = opts.get(b'dry_run')
5903 if not pats and not after:
5904 if not pats and not after:
5904 raise error.InputError(_(b'no files specified'))
5905 raise error.InputError(_(b'no files specified'))
5905
5906
5906 m = scmutil.match(repo[None], pats, opts)
5907 m = scmutil.match(repo[None], pats, opts)
5907 subrepos = opts.get(b'subrepos')
5908 subrepos = opts.get(b'subrepos')
5908 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5909 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5909 return cmdutil.remove(
5910 return cmdutil.remove(
5910 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5911 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5911 )
5912 )
5912
5913
5913
5914
5914 @command(
5915 @command(
5915 b'rename|move|mv',
5916 b'rename|move|mv',
5916 [
5917 [
5918 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5917 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5919 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5918 (
5920 (
5919 b'',
5921 b'',
5920 b'at-rev',
5922 b'at-rev',
5921 b'',
5923 b'',
5922 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5924 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5923 _(b'REV'),
5925 _(b'REV'),
5924 ),
5926 ),
5925 (
5927 (
5926 b'f',
5928 b'f',
5927 b'force',
5929 b'force',
5928 None,
5930 None,
5929 _(b'forcibly move over an existing managed file'),
5931 _(b'forcibly move over an existing managed file'),
5930 ),
5932 ),
5931 ]
5933 ]
5932 + walkopts
5934 + walkopts
5933 + dryrunopts,
5935 + dryrunopts,
5934 _(b'[OPTION]... SOURCE... DEST'),
5936 _(b'[OPTION]... SOURCE... DEST'),
5935 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5937 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5936 )
5938 )
5937 def rename(ui, repo, *pats, **opts):
5939 def rename(ui, repo, *pats, **opts):
5938 """rename files; equivalent of copy + remove
5940 """rename files; equivalent of copy + remove
5939
5941
5940 Mark dest as copies of sources; mark sources for deletion. If dest
5942 Mark dest as copies of sources; mark sources for deletion. If dest
5941 is a directory, copies are put in that directory. If dest is a
5943 is a directory, copies are put in that directory. If dest is a
5942 file, there can only be one source.
5944 file, there can only be one source.
5943
5945
5944 By default, this command copies the contents of files as they
5946 By default, this command copies the contents of files as they
5945 exist in the working directory. If invoked with -A/--after, the
5947 exist in the working directory. If invoked with -A/--after, the
5946 operation is recorded, but no copying is performed.
5948 operation is recorded, but no copying is performed.
5947
5949
5948 This command takes effect at the next commit. To undo a rename
5950 To undo marking a destination file as renamed, use --forget. With that
5949 before that, see :hg:`revert`.
5951 option, all given (positional) arguments are unmarked as renames. The
5952 destination file(s) will be left in place (still tracked). The source
5953 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5954 the same way as :hg:`copy --forget`.
5955
5956 This command takes effect with the next commit by default.
5950
5957
5951 Returns 0 on success, 1 if errors are encountered.
5958 Returns 0 on success, 1 if errors are encountered.
5952 """
5959 """
5953 opts = pycompat.byteskwargs(opts)
5960 opts = pycompat.byteskwargs(opts)
5954 with repo.wlock():
5961 with repo.wlock():
5955 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5962 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5956
5963
5957
5964
5958 @command(
5965 @command(
5959 b'resolve',
5966 b'resolve',
5960 [
5967 [
5961 (b'a', b'all', None, _(b'select all unresolved files')),
5968 (b'a', b'all', None, _(b'select all unresolved files')),
5962 (b'l', b'list', None, _(b'list state of files needing merge')),
5969 (b'l', b'list', None, _(b'list state of files needing merge')),
5963 (b'm', b'mark', None, _(b'mark files as resolved')),
5970 (b'm', b'mark', None, _(b'mark files as resolved')),
5964 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5971 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5965 (b'n', b'no-status', None, _(b'hide status prefix')),
5972 (b'n', b'no-status', None, _(b'hide status prefix')),
5966 (b'', b're-merge', None, _(b're-merge files')),
5973 (b'', b're-merge', None, _(b're-merge files')),
5967 ]
5974 ]
5968 + mergetoolopts
5975 + mergetoolopts
5969 + walkopts
5976 + walkopts
5970 + formatteropts,
5977 + formatteropts,
5971 _(b'[OPTION]... [FILE]...'),
5978 _(b'[OPTION]... [FILE]...'),
5972 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5979 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5973 inferrepo=True,
5980 inferrepo=True,
5974 )
5981 )
5975 def resolve(ui, repo, *pats, **opts):
5982 def resolve(ui, repo, *pats, **opts):
5976 """redo merges or set/view the merge status of files
5983 """redo merges or set/view the merge status of files
5977
5984
5978 Merges with unresolved conflicts are often the result of
5985 Merges with unresolved conflicts are often the result of
5979 non-interactive merging using the ``internal:merge`` configuration
5986 non-interactive merging using the ``internal:merge`` configuration
5980 setting, or a command-line merge tool like ``diff3``. The resolve
5987 setting, or a command-line merge tool like ``diff3``. The resolve
5981 command is used to manage the files involved in a merge, after
5988 command is used to manage the files involved in a merge, after
5982 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5989 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5983 working directory must have two parents). See :hg:`help
5990 working directory must have two parents). See :hg:`help
5984 merge-tools` for information on configuring merge tools.
5991 merge-tools` for information on configuring merge tools.
5985
5992
5986 The resolve command can be used in the following ways:
5993 The resolve command can be used in the following ways:
5987
5994
5988 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5995 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5989 the specified files, discarding any previous merge attempts. Re-merging
5996 the specified files, discarding any previous merge attempts. Re-merging
5990 is not performed for files already marked as resolved. Use ``--all/-a``
5997 is not performed for files already marked as resolved. Use ``--all/-a``
5991 to select all unresolved files. ``--tool`` can be used to specify
5998 to select all unresolved files. ``--tool`` can be used to specify
5992 the merge tool used for the given files. It overrides the HGMERGE
5999 the merge tool used for the given files. It overrides the HGMERGE
5993 environment variable and your configuration files. Previous file
6000 environment variable and your configuration files. Previous file
5994 contents are saved with a ``.orig`` suffix.
6001 contents are saved with a ``.orig`` suffix.
5995
6002
5996 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6003 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5997 (e.g. after having manually fixed-up the files). The default is
6004 (e.g. after having manually fixed-up the files). The default is
5998 to mark all unresolved files.
6005 to mark all unresolved files.
5999
6006
6000 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6007 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6001 default is to mark all resolved files.
6008 default is to mark all resolved files.
6002
6009
6003 - :hg:`resolve -l`: list files which had or still have conflicts.
6010 - :hg:`resolve -l`: list files which had or still have conflicts.
6004 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6011 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6005 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6012 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6006 the list. See :hg:`help filesets` for details.
6013 the list. See :hg:`help filesets` for details.
6007
6014
6008 .. note::
6015 .. note::
6009
6016
6010 Mercurial will not let you commit files with unresolved merge
6017 Mercurial will not let you commit files with unresolved merge
6011 conflicts. You must use :hg:`resolve -m ...` before you can
6018 conflicts. You must use :hg:`resolve -m ...` before you can
6012 commit after a conflicting merge.
6019 commit after a conflicting merge.
6013
6020
6014 .. container:: verbose
6021 .. container:: verbose
6015
6022
6016 Template:
6023 Template:
6017
6024
6018 The following keywords are supported in addition to the common template
6025 The following keywords are supported in addition to the common template
6019 keywords and functions. See also :hg:`help templates`.
6026 keywords and functions. See also :hg:`help templates`.
6020
6027
6021 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6028 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6022 :path: String. Repository-absolute path of the file.
6029 :path: String. Repository-absolute path of the file.
6023
6030
6024 Returns 0 on success, 1 if any files fail a resolve attempt.
6031 Returns 0 on success, 1 if any files fail a resolve attempt.
6025 """
6032 """
6026
6033
6027 opts = pycompat.byteskwargs(opts)
6034 opts = pycompat.byteskwargs(opts)
6028 confirm = ui.configbool(b'commands', b'resolve.confirm')
6035 confirm = ui.configbool(b'commands', b'resolve.confirm')
6029 flaglist = b'all mark unmark list no_status re_merge'.split()
6036 flaglist = b'all mark unmark list no_status re_merge'.split()
6030 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6037 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6031
6038
6032 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6039 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6033 if actioncount > 1:
6040 if actioncount > 1:
6034 raise error.InputError(_(b"too many actions specified"))
6041 raise error.InputError(_(b"too many actions specified"))
6035 elif actioncount == 0 and ui.configbool(
6042 elif actioncount == 0 and ui.configbool(
6036 b'commands', b'resolve.explicit-re-merge'
6043 b'commands', b'resolve.explicit-re-merge'
6037 ):
6044 ):
6038 hint = _(b'use --mark, --unmark, --list or --re-merge')
6045 hint = _(b'use --mark, --unmark, --list or --re-merge')
6039 raise error.InputError(_(b'no action specified'), hint=hint)
6046 raise error.InputError(_(b'no action specified'), hint=hint)
6040 if pats and all:
6047 if pats and all:
6041 raise error.InputError(_(b"can't specify --all and patterns"))
6048 raise error.InputError(_(b"can't specify --all and patterns"))
6042 if not (all or pats or show or mark or unmark):
6049 if not (all or pats or show or mark or unmark):
6043 raise error.InputError(
6050 raise error.InputError(
6044 _(b'no files or directories specified'),
6051 _(b'no files or directories specified'),
6045 hint=b'use --all to re-merge all unresolved files',
6052 hint=b'use --all to re-merge all unresolved files',
6046 )
6053 )
6047
6054
6048 if confirm:
6055 if confirm:
6049 if all:
6056 if all:
6050 if ui.promptchoice(
6057 if ui.promptchoice(
6051 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6058 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6052 ):
6059 ):
6053 raise error.CanceledError(_(b'user quit'))
6060 raise error.CanceledError(_(b'user quit'))
6054 if mark and not pats:
6061 if mark and not pats:
6055 if ui.promptchoice(
6062 if ui.promptchoice(
6056 _(
6063 _(
6057 b'mark all unresolved files as resolved (yn)?'
6064 b'mark all unresolved files as resolved (yn)?'
6058 b'$$ &Yes $$ &No'
6065 b'$$ &Yes $$ &No'
6059 )
6066 )
6060 ):
6067 ):
6061 raise error.CanceledError(_(b'user quit'))
6068 raise error.CanceledError(_(b'user quit'))
6062 if unmark and not pats:
6069 if unmark and not pats:
6063 if ui.promptchoice(
6070 if ui.promptchoice(
6064 _(
6071 _(
6065 b'mark all resolved files as unresolved (yn)?'
6072 b'mark all resolved files as unresolved (yn)?'
6066 b'$$ &Yes $$ &No'
6073 b'$$ &Yes $$ &No'
6067 )
6074 )
6068 ):
6075 ):
6069 raise error.CanceledError(_(b'user quit'))
6076 raise error.CanceledError(_(b'user quit'))
6070
6077
6071 uipathfn = scmutil.getuipathfn(repo)
6078 uipathfn = scmutil.getuipathfn(repo)
6072
6079
6073 if show:
6080 if show:
6074 ui.pager(b'resolve')
6081 ui.pager(b'resolve')
6075 fm = ui.formatter(b'resolve', opts)
6082 fm = ui.formatter(b'resolve', opts)
6076 ms = mergestatemod.mergestate.read(repo)
6083 ms = mergestatemod.mergestate.read(repo)
6077 wctx = repo[None]
6084 wctx = repo[None]
6078 m = scmutil.match(wctx, pats, opts)
6085 m = scmutil.match(wctx, pats, opts)
6079
6086
6080 # Labels and keys based on merge state. Unresolved path conflicts show
6087 # Labels and keys based on merge state. Unresolved path conflicts show
6081 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6088 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6082 # resolved conflicts.
6089 # resolved conflicts.
6083 mergestateinfo = {
6090 mergestateinfo = {
6084 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6091 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6085 b'resolve.unresolved',
6092 b'resolve.unresolved',
6086 b'U',
6093 b'U',
6087 ),
6094 ),
6088 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6095 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6089 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6096 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6090 b'resolve.unresolved',
6097 b'resolve.unresolved',
6091 b'P',
6098 b'P',
6092 ),
6099 ),
6093 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6100 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6094 b'resolve.resolved',
6101 b'resolve.resolved',
6095 b'R',
6102 b'R',
6096 ),
6103 ),
6097 }
6104 }
6098
6105
6099 for f in ms:
6106 for f in ms:
6100 if not m(f):
6107 if not m(f):
6101 continue
6108 continue
6102
6109
6103 label, key = mergestateinfo[ms[f]]
6110 label, key = mergestateinfo[ms[f]]
6104 fm.startitem()
6111 fm.startitem()
6105 fm.context(ctx=wctx)
6112 fm.context(ctx=wctx)
6106 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6113 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6107 fm.data(path=f)
6114 fm.data(path=f)
6108 fm.plain(b'%s\n' % uipathfn(f), label=label)
6115 fm.plain(b'%s\n' % uipathfn(f), label=label)
6109 fm.end()
6116 fm.end()
6110 return 0
6117 return 0
6111
6118
6112 with repo.wlock():
6119 with repo.wlock():
6113 ms = mergestatemod.mergestate.read(repo)
6120 ms = mergestatemod.mergestate.read(repo)
6114
6121
6115 if not (ms.active() or repo.dirstate.p2() != nullid):
6122 if not (ms.active() or repo.dirstate.p2() != nullid):
6116 raise error.StateError(
6123 raise error.StateError(
6117 _(b'resolve command not applicable when not merging')
6124 _(b'resolve command not applicable when not merging')
6118 )
6125 )
6119
6126
6120 wctx = repo[None]
6127 wctx = repo[None]
6121 m = scmutil.match(wctx, pats, opts)
6128 m = scmutil.match(wctx, pats, opts)
6122 ret = 0
6129 ret = 0
6123 didwork = False
6130 didwork = False
6124
6131
6125 tocomplete = []
6132 tocomplete = []
6126 hasconflictmarkers = []
6133 hasconflictmarkers = []
6127 if mark:
6134 if mark:
6128 markcheck = ui.config(b'commands', b'resolve.mark-check')
6135 markcheck = ui.config(b'commands', b'resolve.mark-check')
6129 if markcheck not in [b'warn', b'abort']:
6136 if markcheck not in [b'warn', b'abort']:
6130 # Treat all invalid / unrecognized values as 'none'.
6137 # Treat all invalid / unrecognized values as 'none'.
6131 markcheck = False
6138 markcheck = False
6132 for f in ms:
6139 for f in ms:
6133 if not m(f):
6140 if not m(f):
6134 continue
6141 continue
6135
6142
6136 didwork = True
6143 didwork = True
6137
6144
6138 # path conflicts must be resolved manually
6145 # path conflicts must be resolved manually
6139 if ms[f] in (
6146 if ms[f] in (
6140 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6147 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6141 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6148 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6142 ):
6149 ):
6143 if mark:
6150 if mark:
6144 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6151 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6145 elif unmark:
6152 elif unmark:
6146 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6153 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6147 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6154 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6148 ui.warn(
6155 ui.warn(
6149 _(b'%s: path conflict must be resolved manually\n')
6156 _(b'%s: path conflict must be resolved manually\n')
6150 % uipathfn(f)
6157 % uipathfn(f)
6151 )
6158 )
6152 continue
6159 continue
6153
6160
6154 if mark:
6161 if mark:
6155 if markcheck:
6162 if markcheck:
6156 fdata = repo.wvfs.tryread(f)
6163 fdata = repo.wvfs.tryread(f)
6157 if (
6164 if (
6158 filemerge.hasconflictmarkers(fdata)
6165 filemerge.hasconflictmarkers(fdata)
6159 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6166 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6160 ):
6167 ):
6161 hasconflictmarkers.append(f)
6168 hasconflictmarkers.append(f)
6162 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6169 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6163 elif unmark:
6170 elif unmark:
6164 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6171 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6165 else:
6172 else:
6166 # backup pre-resolve (merge uses .orig for its own purposes)
6173 # backup pre-resolve (merge uses .orig for its own purposes)
6167 a = repo.wjoin(f)
6174 a = repo.wjoin(f)
6168 try:
6175 try:
6169 util.copyfile(a, a + b".resolve")
6176 util.copyfile(a, a + b".resolve")
6170 except (IOError, OSError) as inst:
6177 except (IOError, OSError) as inst:
6171 if inst.errno != errno.ENOENT:
6178 if inst.errno != errno.ENOENT:
6172 raise
6179 raise
6173
6180
6174 try:
6181 try:
6175 # preresolve file
6182 # preresolve file
6176 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6183 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6177 with ui.configoverride(overrides, b'resolve'):
6184 with ui.configoverride(overrides, b'resolve'):
6178 complete, r = ms.preresolve(f, wctx)
6185 complete, r = ms.preresolve(f, wctx)
6179 if not complete:
6186 if not complete:
6180 tocomplete.append(f)
6187 tocomplete.append(f)
6181 elif r:
6188 elif r:
6182 ret = 1
6189 ret = 1
6183 finally:
6190 finally:
6184 ms.commit()
6191 ms.commit()
6185
6192
6186 # replace filemerge's .orig file with our resolve file, but only
6193 # replace filemerge's .orig file with our resolve file, but only
6187 # for merges that are complete
6194 # for merges that are complete
6188 if complete:
6195 if complete:
6189 try:
6196 try:
6190 util.rename(
6197 util.rename(
6191 a + b".resolve", scmutil.backuppath(ui, repo, f)
6198 a + b".resolve", scmutil.backuppath(ui, repo, f)
6192 )
6199 )
6193 except OSError as inst:
6200 except OSError as inst:
6194 if inst.errno != errno.ENOENT:
6201 if inst.errno != errno.ENOENT:
6195 raise
6202 raise
6196
6203
6197 if hasconflictmarkers:
6204 if hasconflictmarkers:
6198 ui.warn(
6205 ui.warn(
6199 _(
6206 _(
6200 b'warning: the following files still have conflict '
6207 b'warning: the following files still have conflict '
6201 b'markers:\n'
6208 b'markers:\n'
6202 )
6209 )
6203 + b''.join(
6210 + b''.join(
6204 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6211 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6205 )
6212 )
6206 )
6213 )
6207 if markcheck == b'abort' and not all and not pats:
6214 if markcheck == b'abort' and not all and not pats:
6208 raise error.StateError(
6215 raise error.StateError(
6209 _(b'conflict markers detected'),
6216 _(b'conflict markers detected'),
6210 hint=_(b'use --all to mark anyway'),
6217 hint=_(b'use --all to mark anyway'),
6211 )
6218 )
6212
6219
6213 for f in tocomplete:
6220 for f in tocomplete:
6214 try:
6221 try:
6215 # resolve file
6222 # resolve file
6216 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6223 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6217 with ui.configoverride(overrides, b'resolve'):
6224 with ui.configoverride(overrides, b'resolve'):
6218 r = ms.resolve(f, wctx)
6225 r = ms.resolve(f, wctx)
6219 if r:
6226 if r:
6220 ret = 1
6227 ret = 1
6221 finally:
6228 finally:
6222 ms.commit()
6229 ms.commit()
6223
6230
6224 # replace filemerge's .orig file with our resolve file
6231 # replace filemerge's .orig file with our resolve file
6225 a = repo.wjoin(f)
6232 a = repo.wjoin(f)
6226 try:
6233 try:
6227 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6234 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6228 except OSError as inst:
6235 except OSError as inst:
6229 if inst.errno != errno.ENOENT:
6236 if inst.errno != errno.ENOENT:
6230 raise
6237 raise
6231
6238
6232 ms.commit()
6239 ms.commit()
6233 branchmerge = repo.dirstate.p2() != nullid
6240 branchmerge = repo.dirstate.p2() != nullid
6234 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6241 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6235
6242
6236 if not didwork and pats:
6243 if not didwork and pats:
6237 hint = None
6244 hint = None
6238 if not any([p for p in pats if p.find(b':') >= 0]):
6245 if not any([p for p in pats if p.find(b':') >= 0]):
6239 pats = [b'path:%s' % p for p in pats]
6246 pats = [b'path:%s' % p for p in pats]
6240 m = scmutil.match(wctx, pats, opts)
6247 m = scmutil.match(wctx, pats, opts)
6241 for f in ms:
6248 for f in ms:
6242 if not m(f):
6249 if not m(f):
6243 continue
6250 continue
6244
6251
6245 def flag(o):
6252 def flag(o):
6246 if o == b're_merge':
6253 if o == b're_merge':
6247 return b'--re-merge '
6254 return b'--re-merge '
6248 return b'-%s ' % o[0:1]
6255 return b'-%s ' % o[0:1]
6249
6256
6250 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6257 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6251 hint = _(b"(try: hg resolve %s%s)\n") % (
6258 hint = _(b"(try: hg resolve %s%s)\n") % (
6252 flags,
6259 flags,
6253 b' '.join(pats),
6260 b' '.join(pats),
6254 )
6261 )
6255 break
6262 break
6256 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6263 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6257 if hint:
6264 if hint:
6258 ui.warn(hint)
6265 ui.warn(hint)
6259
6266
6260 unresolvedf = ms.unresolvedcount()
6267 unresolvedf = ms.unresolvedcount()
6261 if not unresolvedf:
6268 if not unresolvedf:
6262 ui.status(_(b'(no more unresolved files)\n'))
6269 ui.status(_(b'(no more unresolved files)\n'))
6263 cmdutil.checkafterresolved(repo)
6270 cmdutil.checkafterresolved(repo)
6264
6271
6265 return ret
6272 return ret
6266
6273
6267
6274
6268 @command(
6275 @command(
6269 b'revert',
6276 b'revert',
6270 [
6277 [
6271 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6278 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6272 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6279 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6273 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6280 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6274 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6281 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6275 (b'i', b'interactive', None, _(b'interactively select the changes')),
6282 (b'i', b'interactive', None, _(b'interactively select the changes')),
6276 ]
6283 ]
6277 + walkopts
6284 + walkopts
6278 + dryrunopts,
6285 + dryrunopts,
6279 _(b'[OPTION]... [-r REV] [NAME]...'),
6286 _(b'[OPTION]... [-r REV] [NAME]...'),
6280 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6287 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6281 )
6288 )
6282 def revert(ui, repo, *pats, **opts):
6289 def revert(ui, repo, *pats, **opts):
6283 """restore files to their checkout state
6290 """restore files to their checkout state
6284
6291
6285 .. note::
6292 .. note::
6286
6293
6287 To check out earlier revisions, you should use :hg:`update REV`.
6294 To check out earlier revisions, you should use :hg:`update REV`.
6288 To cancel an uncommitted merge (and lose your changes),
6295 To cancel an uncommitted merge (and lose your changes),
6289 use :hg:`merge --abort`.
6296 use :hg:`merge --abort`.
6290
6297
6291 With no revision specified, revert the specified files or directories
6298 With no revision specified, revert the specified files or directories
6292 to the contents they had in the parent of the working directory.
6299 to the contents they had in the parent of the working directory.
6293 This restores the contents of files to an unmodified
6300 This restores the contents of files to an unmodified
6294 state and unschedules adds, removes, copies, and renames. If the
6301 state and unschedules adds, removes, copies, and renames. If the
6295 working directory has two parents, you must explicitly specify a
6302 working directory has two parents, you must explicitly specify a
6296 revision.
6303 revision.
6297
6304
6298 Using the -r/--rev or -d/--date options, revert the given files or
6305 Using the -r/--rev or -d/--date options, revert the given files or
6299 directories to their states as of a specific revision. Because
6306 directories to their states as of a specific revision. Because
6300 revert does not change the working directory parents, this will
6307 revert does not change the working directory parents, this will
6301 cause these files to appear modified. This can be helpful to "back
6308 cause these files to appear modified. This can be helpful to "back
6302 out" some or all of an earlier change. See :hg:`backout` for a
6309 out" some or all of an earlier change. See :hg:`backout` for a
6303 related method.
6310 related method.
6304
6311
6305 Modified files are saved with a .orig suffix before reverting.
6312 Modified files are saved with a .orig suffix before reverting.
6306 To disable these backups, use --no-backup. It is possible to store
6313 To disable these backups, use --no-backup. It is possible to store
6307 the backup files in a custom directory relative to the root of the
6314 the backup files in a custom directory relative to the root of the
6308 repository by setting the ``ui.origbackuppath`` configuration
6315 repository by setting the ``ui.origbackuppath`` configuration
6309 option.
6316 option.
6310
6317
6311 See :hg:`help dates` for a list of formats valid for -d/--date.
6318 See :hg:`help dates` for a list of formats valid for -d/--date.
6312
6319
6313 See :hg:`help backout` for a way to reverse the effect of an
6320 See :hg:`help backout` for a way to reverse the effect of an
6314 earlier changeset.
6321 earlier changeset.
6315
6322
6316 Returns 0 on success.
6323 Returns 0 on success.
6317 """
6324 """
6318
6325
6319 opts = pycompat.byteskwargs(opts)
6326 opts = pycompat.byteskwargs(opts)
6320 if opts.get(b"date"):
6327 if opts.get(b"date"):
6321 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6328 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6322 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6329 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6323
6330
6324 parent, p2 = repo.dirstate.parents()
6331 parent, p2 = repo.dirstate.parents()
6325 if not opts.get(b'rev') and p2 != nullid:
6332 if not opts.get(b'rev') and p2 != nullid:
6326 # revert after merge is a trap for new users (issue2915)
6333 # revert after merge is a trap for new users (issue2915)
6327 raise error.InputError(
6334 raise error.InputError(
6328 _(b'uncommitted merge with no revision specified'),
6335 _(b'uncommitted merge with no revision specified'),
6329 hint=_(b"use 'hg update' or see 'hg help revert'"),
6336 hint=_(b"use 'hg update' or see 'hg help revert'"),
6330 )
6337 )
6331
6338
6332 rev = opts.get(b'rev')
6339 rev = opts.get(b'rev')
6333 if rev:
6340 if rev:
6334 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6341 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6335 ctx = scmutil.revsingle(repo, rev)
6342 ctx = scmutil.revsingle(repo, rev)
6336
6343
6337 if not (
6344 if not (
6338 pats
6345 pats
6339 or opts.get(b'include')
6346 or opts.get(b'include')
6340 or opts.get(b'exclude')
6347 or opts.get(b'exclude')
6341 or opts.get(b'all')
6348 or opts.get(b'all')
6342 or opts.get(b'interactive')
6349 or opts.get(b'interactive')
6343 ):
6350 ):
6344 msg = _(b"no files or directories specified")
6351 msg = _(b"no files or directories specified")
6345 if p2 != nullid:
6352 if p2 != nullid:
6346 hint = _(
6353 hint = _(
6347 b"uncommitted merge, use --all to discard all changes,"
6354 b"uncommitted merge, use --all to discard all changes,"
6348 b" or 'hg update -C .' to abort the merge"
6355 b" or 'hg update -C .' to abort the merge"
6349 )
6356 )
6350 raise error.InputError(msg, hint=hint)
6357 raise error.InputError(msg, hint=hint)
6351 dirty = any(repo.status())
6358 dirty = any(repo.status())
6352 node = ctx.node()
6359 node = ctx.node()
6353 if node != parent:
6360 if node != parent:
6354 if dirty:
6361 if dirty:
6355 hint = (
6362 hint = (
6356 _(
6363 _(
6357 b"uncommitted changes, use --all to discard all"
6364 b"uncommitted changes, use --all to discard all"
6358 b" changes, or 'hg update %d' to update"
6365 b" changes, or 'hg update %d' to update"
6359 )
6366 )
6360 % ctx.rev()
6367 % ctx.rev()
6361 )
6368 )
6362 else:
6369 else:
6363 hint = (
6370 hint = (
6364 _(
6371 _(
6365 b"use --all to revert all files,"
6372 b"use --all to revert all files,"
6366 b" or 'hg update %d' to update"
6373 b" or 'hg update %d' to update"
6367 )
6374 )
6368 % ctx.rev()
6375 % ctx.rev()
6369 )
6376 )
6370 elif dirty:
6377 elif dirty:
6371 hint = _(b"uncommitted changes, use --all to discard all changes")
6378 hint = _(b"uncommitted changes, use --all to discard all changes")
6372 else:
6379 else:
6373 hint = _(b"use --all to revert all files")
6380 hint = _(b"use --all to revert all files")
6374 raise error.InputError(msg, hint=hint)
6381 raise error.InputError(msg, hint=hint)
6375
6382
6376 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6383 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6377
6384
6378
6385
6379 @command(
6386 @command(
6380 b'rollback',
6387 b'rollback',
6381 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6388 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6382 helpcategory=command.CATEGORY_MAINTENANCE,
6389 helpcategory=command.CATEGORY_MAINTENANCE,
6383 )
6390 )
6384 def rollback(ui, repo, **opts):
6391 def rollback(ui, repo, **opts):
6385 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6392 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6386
6393
6387 Please use :hg:`commit --amend` instead of rollback to correct
6394 Please use :hg:`commit --amend` instead of rollback to correct
6388 mistakes in the last commit.
6395 mistakes in the last commit.
6389
6396
6390 This command should be used with care. There is only one level of
6397 This command should be used with care. There is only one level of
6391 rollback, and there is no way to undo a rollback. It will also
6398 rollback, and there is no way to undo a rollback. It will also
6392 restore the dirstate at the time of the last transaction, losing
6399 restore the dirstate at the time of the last transaction, losing
6393 any dirstate changes since that time. This command does not alter
6400 any dirstate changes since that time. This command does not alter
6394 the working directory.
6401 the working directory.
6395
6402
6396 Transactions are used to encapsulate the effects of all commands
6403 Transactions are used to encapsulate the effects of all commands
6397 that create new changesets or propagate existing changesets into a
6404 that create new changesets or propagate existing changesets into a
6398 repository.
6405 repository.
6399
6406
6400 .. container:: verbose
6407 .. container:: verbose
6401
6408
6402 For example, the following commands are transactional, and their
6409 For example, the following commands are transactional, and their
6403 effects can be rolled back:
6410 effects can be rolled back:
6404
6411
6405 - commit
6412 - commit
6406 - import
6413 - import
6407 - pull
6414 - pull
6408 - push (with this repository as the destination)
6415 - push (with this repository as the destination)
6409 - unbundle
6416 - unbundle
6410
6417
6411 To avoid permanent data loss, rollback will refuse to rollback a
6418 To avoid permanent data loss, rollback will refuse to rollback a
6412 commit transaction if it isn't checked out. Use --force to
6419 commit transaction if it isn't checked out. Use --force to
6413 override this protection.
6420 override this protection.
6414
6421
6415 The rollback command can be entirely disabled by setting the
6422 The rollback command can be entirely disabled by setting the
6416 ``ui.rollback`` configuration setting to false. If you're here
6423 ``ui.rollback`` configuration setting to false. If you're here
6417 because you want to use rollback and it's disabled, you can
6424 because you want to use rollback and it's disabled, you can
6418 re-enable the command by setting ``ui.rollback`` to true.
6425 re-enable the command by setting ``ui.rollback`` to true.
6419
6426
6420 This command is not intended for use on public repositories. Once
6427 This command is not intended for use on public repositories. Once
6421 changes are visible for pull by other users, rolling a transaction
6428 changes are visible for pull by other users, rolling a transaction
6422 back locally is ineffective (someone else may already have pulled
6429 back locally is ineffective (someone else may already have pulled
6423 the changes). Furthermore, a race is possible with readers of the
6430 the changes). Furthermore, a race is possible with readers of the
6424 repository; for example an in-progress pull from the repository
6431 repository; for example an in-progress pull from the repository
6425 may fail if a rollback is performed.
6432 may fail if a rollback is performed.
6426
6433
6427 Returns 0 on success, 1 if no rollback data is available.
6434 Returns 0 on success, 1 if no rollback data is available.
6428 """
6435 """
6429 if not ui.configbool(b'ui', b'rollback'):
6436 if not ui.configbool(b'ui', b'rollback'):
6430 raise error.Abort(
6437 raise error.Abort(
6431 _(b'rollback is disabled because it is unsafe'),
6438 _(b'rollback is disabled because it is unsafe'),
6432 hint=b'see `hg help -v rollback` for information',
6439 hint=b'see `hg help -v rollback` for information',
6433 )
6440 )
6434 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6441 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6435
6442
6436
6443
6437 @command(
6444 @command(
6438 b'root',
6445 b'root',
6439 [] + formatteropts,
6446 [] + formatteropts,
6440 intents={INTENT_READONLY},
6447 intents={INTENT_READONLY},
6441 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6448 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6442 )
6449 )
6443 def root(ui, repo, **opts):
6450 def root(ui, repo, **opts):
6444 """print the root (top) of the current working directory
6451 """print the root (top) of the current working directory
6445
6452
6446 Print the root directory of the current repository.
6453 Print the root directory of the current repository.
6447
6454
6448 .. container:: verbose
6455 .. container:: verbose
6449
6456
6450 Template:
6457 Template:
6451
6458
6452 The following keywords are supported in addition to the common template
6459 The following keywords are supported in addition to the common template
6453 keywords and functions. See also :hg:`help templates`.
6460 keywords and functions. See also :hg:`help templates`.
6454
6461
6455 :hgpath: String. Path to the .hg directory.
6462 :hgpath: String. Path to the .hg directory.
6456 :storepath: String. Path to the directory holding versioned data.
6463 :storepath: String. Path to the directory holding versioned data.
6457
6464
6458 Returns 0 on success.
6465 Returns 0 on success.
6459 """
6466 """
6460 opts = pycompat.byteskwargs(opts)
6467 opts = pycompat.byteskwargs(opts)
6461 with ui.formatter(b'root', opts) as fm:
6468 with ui.formatter(b'root', opts) as fm:
6462 fm.startitem()
6469 fm.startitem()
6463 fm.write(b'reporoot', b'%s\n', repo.root)
6470 fm.write(b'reporoot', b'%s\n', repo.root)
6464 fm.data(hgpath=repo.path, storepath=repo.spath)
6471 fm.data(hgpath=repo.path, storepath=repo.spath)
6465
6472
6466
6473
6467 @command(
6474 @command(
6468 b'serve',
6475 b'serve',
6469 [
6476 [
6470 (
6477 (
6471 b'A',
6478 b'A',
6472 b'accesslog',
6479 b'accesslog',
6473 b'',
6480 b'',
6474 _(b'name of access log file to write to'),
6481 _(b'name of access log file to write to'),
6475 _(b'FILE'),
6482 _(b'FILE'),
6476 ),
6483 ),
6477 (b'd', b'daemon', None, _(b'run server in background')),
6484 (b'd', b'daemon', None, _(b'run server in background')),
6478 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6485 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6479 (
6486 (
6480 b'E',
6487 b'E',
6481 b'errorlog',
6488 b'errorlog',
6482 b'',
6489 b'',
6483 _(b'name of error log file to write to'),
6490 _(b'name of error log file to write to'),
6484 _(b'FILE'),
6491 _(b'FILE'),
6485 ),
6492 ),
6486 # use string type, then we can check if something was passed
6493 # use string type, then we can check if something was passed
6487 (
6494 (
6488 b'p',
6495 b'p',
6489 b'port',
6496 b'port',
6490 b'',
6497 b'',
6491 _(b'port to listen on (default: 8000)'),
6498 _(b'port to listen on (default: 8000)'),
6492 _(b'PORT'),
6499 _(b'PORT'),
6493 ),
6500 ),
6494 (
6501 (
6495 b'a',
6502 b'a',
6496 b'address',
6503 b'address',
6497 b'',
6504 b'',
6498 _(b'address to listen on (default: all interfaces)'),
6505 _(b'address to listen on (default: all interfaces)'),
6499 _(b'ADDR'),
6506 _(b'ADDR'),
6500 ),
6507 ),
6501 (
6508 (
6502 b'',
6509 b'',
6503 b'prefix',
6510 b'prefix',
6504 b'',
6511 b'',
6505 _(b'prefix path to serve from (default: server root)'),
6512 _(b'prefix path to serve from (default: server root)'),
6506 _(b'PREFIX'),
6513 _(b'PREFIX'),
6507 ),
6514 ),
6508 (
6515 (
6509 b'n',
6516 b'n',
6510 b'name',
6517 b'name',
6511 b'',
6518 b'',
6512 _(b'name to show in web pages (default: working directory)'),
6519 _(b'name to show in web pages (default: working directory)'),
6513 _(b'NAME'),
6520 _(b'NAME'),
6514 ),
6521 ),
6515 (
6522 (
6516 b'',
6523 b'',
6517 b'web-conf',
6524 b'web-conf',
6518 b'',
6525 b'',
6519 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6526 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6520 _(b'FILE'),
6527 _(b'FILE'),
6521 ),
6528 ),
6522 (
6529 (
6523 b'',
6530 b'',
6524 b'webdir-conf',
6531 b'webdir-conf',
6525 b'',
6532 b'',
6526 _(b'name of the hgweb config file (DEPRECATED)'),
6533 _(b'name of the hgweb config file (DEPRECATED)'),
6527 _(b'FILE'),
6534 _(b'FILE'),
6528 ),
6535 ),
6529 (
6536 (
6530 b'',
6537 b'',
6531 b'pid-file',
6538 b'pid-file',
6532 b'',
6539 b'',
6533 _(b'name of file to write process ID to'),
6540 _(b'name of file to write process ID to'),
6534 _(b'FILE'),
6541 _(b'FILE'),
6535 ),
6542 ),
6536 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6543 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6537 (
6544 (
6538 b'',
6545 b'',
6539 b'cmdserver',
6546 b'cmdserver',
6540 b'',
6547 b'',
6541 _(b'for remote clients (ADVANCED)'),
6548 _(b'for remote clients (ADVANCED)'),
6542 _(b'MODE'),
6549 _(b'MODE'),
6543 ),
6550 ),
6544 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6551 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6545 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6552 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6546 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6553 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6547 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6554 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6548 (b'', b'print-url', None, _(b'start and print only the URL')),
6555 (b'', b'print-url', None, _(b'start and print only the URL')),
6549 ]
6556 ]
6550 + subrepoopts,
6557 + subrepoopts,
6551 _(b'[OPTION]...'),
6558 _(b'[OPTION]...'),
6552 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6559 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6553 helpbasic=True,
6560 helpbasic=True,
6554 optionalrepo=True,
6561 optionalrepo=True,
6555 )
6562 )
6556 def serve(ui, repo, **opts):
6563 def serve(ui, repo, **opts):
6557 """start stand-alone webserver
6564 """start stand-alone webserver
6558
6565
6559 Start a local HTTP repository browser and pull server. You can use
6566 Start a local HTTP repository browser and pull server. You can use
6560 this for ad-hoc sharing and browsing of repositories. It is
6567 this for ad-hoc sharing and browsing of repositories. It is
6561 recommended to use a real web server to serve a repository for
6568 recommended to use a real web server to serve a repository for
6562 longer periods of time.
6569 longer periods of time.
6563
6570
6564 Please note that the server does not implement access control.
6571 Please note that the server does not implement access control.
6565 This means that, by default, anybody can read from the server and
6572 This means that, by default, anybody can read from the server and
6566 nobody can write to it by default. Set the ``web.allow-push``
6573 nobody can write to it by default. Set the ``web.allow-push``
6567 option to ``*`` to allow everybody to push to the server. You
6574 option to ``*`` to allow everybody to push to the server. You
6568 should use a real web server if you need to authenticate users.
6575 should use a real web server if you need to authenticate users.
6569
6576
6570 By default, the server logs accesses to stdout and errors to
6577 By default, the server logs accesses to stdout and errors to
6571 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6578 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6572 files.
6579 files.
6573
6580
6574 To have the server choose a free port number to listen on, specify
6581 To have the server choose a free port number to listen on, specify
6575 a port number of 0; in this case, the server will print the port
6582 a port number of 0; in this case, the server will print the port
6576 number it uses.
6583 number it uses.
6577
6584
6578 Returns 0 on success.
6585 Returns 0 on success.
6579 """
6586 """
6580
6587
6581 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6588 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6582 opts = pycompat.byteskwargs(opts)
6589 opts = pycompat.byteskwargs(opts)
6583 if opts[b"print_url"] and ui.verbose:
6590 if opts[b"print_url"] and ui.verbose:
6584 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6591 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6585
6592
6586 if opts[b"stdio"]:
6593 if opts[b"stdio"]:
6587 if repo is None:
6594 if repo is None:
6588 raise error.RepoError(
6595 raise error.RepoError(
6589 _(b"there is no Mercurial repository here (.hg not found)")
6596 _(b"there is no Mercurial repository here (.hg not found)")
6590 )
6597 )
6591 s = wireprotoserver.sshserver(ui, repo)
6598 s = wireprotoserver.sshserver(ui, repo)
6592 s.serve_forever()
6599 s.serve_forever()
6593 return
6600 return
6594
6601
6595 service = server.createservice(ui, repo, opts)
6602 service = server.createservice(ui, repo, opts)
6596 return server.runservice(opts, initfn=service.init, runfn=service.run)
6603 return server.runservice(opts, initfn=service.init, runfn=service.run)
6597
6604
6598
6605
6599 @command(
6606 @command(
6600 b'shelve',
6607 b'shelve',
6601 [
6608 [
6602 (
6609 (
6603 b'A',
6610 b'A',
6604 b'addremove',
6611 b'addremove',
6605 None,
6612 None,
6606 _(b'mark new/missing files as added/removed before shelving'),
6613 _(b'mark new/missing files as added/removed before shelving'),
6607 ),
6614 ),
6608 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6615 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6609 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6616 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6610 (
6617 (
6611 b'',
6618 b'',
6612 b'date',
6619 b'date',
6613 b'',
6620 b'',
6614 _(b'shelve with the specified commit date'),
6621 _(b'shelve with the specified commit date'),
6615 _(b'DATE'),
6622 _(b'DATE'),
6616 ),
6623 ),
6617 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6624 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6618 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6625 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6619 (
6626 (
6620 b'k',
6627 b'k',
6621 b'keep',
6628 b'keep',
6622 False,
6629 False,
6623 _(b'shelve, but keep changes in the working directory'),
6630 _(b'shelve, but keep changes in the working directory'),
6624 ),
6631 ),
6625 (b'l', b'list', None, _(b'list current shelves')),
6632 (b'l', b'list', None, _(b'list current shelves')),
6626 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6633 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6627 (
6634 (
6628 b'n',
6635 b'n',
6629 b'name',
6636 b'name',
6630 b'',
6637 b'',
6631 _(b'use the given name for the shelved commit'),
6638 _(b'use the given name for the shelved commit'),
6632 _(b'NAME'),
6639 _(b'NAME'),
6633 ),
6640 ),
6634 (
6641 (
6635 b'p',
6642 b'p',
6636 b'patch',
6643 b'patch',
6637 None,
6644 None,
6638 _(
6645 _(
6639 b'output patches for changes (provide the names of the shelved '
6646 b'output patches for changes (provide the names of the shelved '
6640 b'changes as positional arguments)'
6647 b'changes as positional arguments)'
6641 ),
6648 ),
6642 ),
6649 ),
6643 (b'i', b'interactive', None, _(b'interactive mode')),
6650 (b'i', b'interactive', None, _(b'interactive mode')),
6644 (
6651 (
6645 b'',
6652 b'',
6646 b'stat',
6653 b'stat',
6647 None,
6654 None,
6648 _(
6655 _(
6649 b'output diffstat-style summary of changes (provide the names of '
6656 b'output diffstat-style summary of changes (provide the names of '
6650 b'the shelved changes as positional arguments)'
6657 b'the shelved changes as positional arguments)'
6651 ),
6658 ),
6652 ),
6659 ),
6653 ]
6660 ]
6654 + cmdutil.walkopts,
6661 + cmdutil.walkopts,
6655 _(b'hg shelve [OPTION]... [FILE]...'),
6662 _(b'hg shelve [OPTION]... [FILE]...'),
6656 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6663 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6657 )
6664 )
6658 def shelve(ui, repo, *pats, **opts):
6665 def shelve(ui, repo, *pats, **opts):
6659 """save and set aside changes from the working directory
6666 """save and set aside changes from the working directory
6660
6667
6661 Shelving takes files that "hg status" reports as not clean, saves
6668 Shelving takes files that "hg status" reports as not clean, saves
6662 the modifications to a bundle (a shelved change), and reverts the
6669 the modifications to a bundle (a shelved change), and reverts the
6663 files so that their state in the working directory becomes clean.
6670 files so that their state in the working directory becomes clean.
6664
6671
6665 To restore these changes to the working directory, using "hg
6672 To restore these changes to the working directory, using "hg
6666 unshelve"; this will work even if you switch to a different
6673 unshelve"; this will work even if you switch to a different
6667 commit.
6674 commit.
6668
6675
6669 When no files are specified, "hg shelve" saves all not-clean
6676 When no files are specified, "hg shelve" saves all not-clean
6670 files. If specific files or directories are named, only changes to
6677 files. If specific files or directories are named, only changes to
6671 those files are shelved.
6678 those files are shelved.
6672
6679
6673 In bare shelve (when no files are specified, without interactive,
6680 In bare shelve (when no files are specified, without interactive,
6674 include and exclude option), shelving remembers information if the
6681 include and exclude option), shelving remembers information if the
6675 working directory was on newly created branch, in other words working
6682 working directory was on newly created branch, in other words working
6676 directory was on different branch than its first parent. In this
6683 directory was on different branch than its first parent. In this
6677 situation unshelving restores branch information to the working directory.
6684 situation unshelving restores branch information to the working directory.
6678
6685
6679 Each shelved change has a name that makes it easier to find later.
6686 Each shelved change has a name that makes it easier to find later.
6680 The name of a shelved change defaults to being based on the active
6687 The name of a shelved change defaults to being based on the active
6681 bookmark, or if there is no active bookmark, the current named
6688 bookmark, or if there is no active bookmark, the current named
6682 branch. To specify a different name, use ``--name``.
6689 branch. To specify a different name, use ``--name``.
6683
6690
6684 To see a list of existing shelved changes, use the ``--list``
6691 To see a list of existing shelved changes, use the ``--list``
6685 option. For each shelved change, this will print its name, age,
6692 option. For each shelved change, this will print its name, age,
6686 and description; use ``--patch`` or ``--stat`` for more details.
6693 and description; use ``--patch`` or ``--stat`` for more details.
6687
6694
6688 To delete specific shelved changes, use ``--delete``. To delete
6695 To delete specific shelved changes, use ``--delete``. To delete
6689 all shelved changes, use ``--cleanup``.
6696 all shelved changes, use ``--cleanup``.
6690 """
6697 """
6691 opts = pycompat.byteskwargs(opts)
6698 opts = pycompat.byteskwargs(opts)
6692 allowables = [
6699 allowables = [
6693 (b'addremove', {b'create'}), # 'create' is pseudo action
6700 (b'addremove', {b'create'}), # 'create' is pseudo action
6694 (b'unknown', {b'create'}),
6701 (b'unknown', {b'create'}),
6695 (b'cleanup', {b'cleanup'}),
6702 (b'cleanup', {b'cleanup'}),
6696 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6703 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6697 (b'delete', {b'delete'}),
6704 (b'delete', {b'delete'}),
6698 (b'edit', {b'create'}),
6705 (b'edit', {b'create'}),
6699 (b'keep', {b'create'}),
6706 (b'keep', {b'create'}),
6700 (b'list', {b'list'}),
6707 (b'list', {b'list'}),
6701 (b'message', {b'create'}),
6708 (b'message', {b'create'}),
6702 (b'name', {b'create'}),
6709 (b'name', {b'create'}),
6703 (b'patch', {b'patch', b'list'}),
6710 (b'patch', {b'patch', b'list'}),
6704 (b'stat', {b'stat', b'list'}),
6711 (b'stat', {b'stat', b'list'}),
6705 ]
6712 ]
6706
6713
6707 def checkopt(opt):
6714 def checkopt(opt):
6708 if opts.get(opt):
6715 if opts.get(opt):
6709 for i, allowable in allowables:
6716 for i, allowable in allowables:
6710 if opts[i] and opt not in allowable:
6717 if opts[i] and opt not in allowable:
6711 raise error.InputError(
6718 raise error.InputError(
6712 _(
6719 _(
6713 b"options '--%s' and '--%s' may not be "
6720 b"options '--%s' and '--%s' may not be "
6714 b"used together"
6721 b"used together"
6715 )
6722 )
6716 % (opt, i)
6723 % (opt, i)
6717 )
6724 )
6718 return True
6725 return True
6719
6726
6720 if checkopt(b'cleanup'):
6727 if checkopt(b'cleanup'):
6721 if pats:
6728 if pats:
6722 raise error.InputError(
6729 raise error.InputError(
6723 _(b"cannot specify names when using '--cleanup'")
6730 _(b"cannot specify names when using '--cleanup'")
6724 )
6731 )
6725 return shelvemod.cleanupcmd(ui, repo)
6732 return shelvemod.cleanupcmd(ui, repo)
6726 elif checkopt(b'delete'):
6733 elif checkopt(b'delete'):
6727 return shelvemod.deletecmd(ui, repo, pats)
6734 return shelvemod.deletecmd(ui, repo, pats)
6728 elif checkopt(b'list'):
6735 elif checkopt(b'list'):
6729 return shelvemod.listcmd(ui, repo, pats, opts)
6736 return shelvemod.listcmd(ui, repo, pats, opts)
6730 elif checkopt(b'patch') or checkopt(b'stat'):
6737 elif checkopt(b'patch') or checkopt(b'stat'):
6731 return shelvemod.patchcmds(ui, repo, pats, opts)
6738 return shelvemod.patchcmds(ui, repo, pats, opts)
6732 else:
6739 else:
6733 return shelvemod.createcmd(ui, repo, pats, opts)
6740 return shelvemod.createcmd(ui, repo, pats, opts)
6734
6741
6735
6742
6736 _NOTTERSE = b'nothing'
6743 _NOTTERSE = b'nothing'
6737
6744
6738
6745
6739 @command(
6746 @command(
6740 b'status|st',
6747 b'status|st',
6741 [
6748 [
6742 (b'A', b'all', None, _(b'show status of all files')),
6749 (b'A', b'all', None, _(b'show status of all files')),
6743 (b'm', b'modified', None, _(b'show only modified files')),
6750 (b'm', b'modified', None, _(b'show only modified files')),
6744 (b'a', b'added', None, _(b'show only added files')),
6751 (b'a', b'added', None, _(b'show only added files')),
6745 (b'r', b'removed', None, _(b'show only removed files')),
6752 (b'r', b'removed', None, _(b'show only removed files')),
6746 (b'd', b'deleted', None, _(b'show only missing files')),
6753 (b'd', b'deleted', None, _(b'show only missing files')),
6747 (b'c', b'clean', None, _(b'show only files without changes')),
6754 (b'c', b'clean', None, _(b'show only files without changes')),
6748 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6755 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6749 (b'i', b'ignored', None, _(b'show only ignored files')),
6756 (b'i', b'ignored', None, _(b'show only ignored files')),
6750 (b'n', b'no-status', None, _(b'hide status prefix')),
6757 (b'n', b'no-status', None, _(b'hide status prefix')),
6751 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6758 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6752 (
6759 (
6753 b'C',
6760 b'C',
6754 b'copies',
6761 b'copies',
6755 None,
6762 None,
6756 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6763 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6757 ),
6764 ),
6758 (
6765 (
6759 b'0',
6766 b'0',
6760 b'print0',
6767 b'print0',
6761 None,
6768 None,
6762 _(b'end filenames with NUL, for use with xargs'),
6769 _(b'end filenames with NUL, for use with xargs'),
6763 ),
6770 ),
6764 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6771 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6765 (
6772 (
6766 b'',
6773 b'',
6767 b'change',
6774 b'change',
6768 b'',
6775 b'',
6769 _(b'list the changed files of a revision'),
6776 _(b'list the changed files of a revision'),
6770 _(b'REV'),
6777 _(b'REV'),
6771 ),
6778 ),
6772 ]
6779 ]
6773 + walkopts
6780 + walkopts
6774 + subrepoopts
6781 + subrepoopts
6775 + formatteropts,
6782 + formatteropts,
6776 _(b'[OPTION]... [FILE]...'),
6783 _(b'[OPTION]... [FILE]...'),
6777 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6784 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6778 helpbasic=True,
6785 helpbasic=True,
6779 inferrepo=True,
6786 inferrepo=True,
6780 intents={INTENT_READONLY},
6787 intents={INTENT_READONLY},
6781 )
6788 )
6782 def status(ui, repo, *pats, **opts):
6789 def status(ui, repo, *pats, **opts):
6783 """show changed files in the working directory
6790 """show changed files in the working directory
6784
6791
6785 Show status of files in the repository. If names are given, only
6792 Show status of files in the repository. If names are given, only
6786 files that match are shown. Files that are clean or ignored or
6793 files that match are shown. Files that are clean or ignored or
6787 the source of a copy/move operation, are not listed unless
6794 the source of a copy/move operation, are not listed unless
6788 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6795 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6789 Unless options described with "show only ..." are given, the
6796 Unless options described with "show only ..." are given, the
6790 options -mardu are used.
6797 options -mardu are used.
6791
6798
6792 Option -q/--quiet hides untracked (unknown and ignored) files
6799 Option -q/--quiet hides untracked (unknown and ignored) files
6793 unless explicitly requested with -u/--unknown or -i/--ignored.
6800 unless explicitly requested with -u/--unknown or -i/--ignored.
6794
6801
6795 .. note::
6802 .. note::
6796
6803
6797 :hg:`status` may appear to disagree with diff if permissions have
6804 :hg:`status` may appear to disagree with diff if permissions have
6798 changed or a merge has occurred. The standard diff format does
6805 changed or a merge has occurred. The standard diff format does
6799 not report permission changes and diff only reports changes
6806 not report permission changes and diff only reports changes
6800 relative to one merge parent.
6807 relative to one merge parent.
6801
6808
6802 If one revision is given, it is used as the base revision.
6809 If one revision is given, it is used as the base revision.
6803 If two revisions are given, the differences between them are
6810 If two revisions are given, the differences between them are
6804 shown. The --change option can also be used as a shortcut to list
6811 shown. The --change option can also be used as a shortcut to list
6805 the changed files of a revision from its first parent.
6812 the changed files of a revision from its first parent.
6806
6813
6807 The codes used to show the status of files are::
6814 The codes used to show the status of files are::
6808
6815
6809 M = modified
6816 M = modified
6810 A = added
6817 A = added
6811 R = removed
6818 R = removed
6812 C = clean
6819 C = clean
6813 ! = missing (deleted by non-hg command, but still tracked)
6820 ! = missing (deleted by non-hg command, but still tracked)
6814 ? = not tracked
6821 ? = not tracked
6815 I = ignored
6822 I = ignored
6816 = origin of the previous file (with --copies)
6823 = origin of the previous file (with --copies)
6817
6824
6818 .. container:: verbose
6825 .. container:: verbose
6819
6826
6820 The -t/--terse option abbreviates the output by showing only the directory
6827 The -t/--terse option abbreviates the output by showing only the directory
6821 name if all the files in it share the same status. The option takes an
6828 name if all the files in it share the same status. The option takes an
6822 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6829 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6823 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6830 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6824 for 'ignored' and 'c' for clean.
6831 for 'ignored' and 'c' for clean.
6825
6832
6826 It abbreviates only those statuses which are passed. Note that clean and
6833 It abbreviates only those statuses which are passed. Note that clean and
6827 ignored files are not displayed with '--terse ic' unless the -c/--clean
6834 ignored files are not displayed with '--terse ic' unless the -c/--clean
6828 and -i/--ignored options are also used.
6835 and -i/--ignored options are also used.
6829
6836
6830 The -v/--verbose option shows information when the repository is in an
6837 The -v/--verbose option shows information when the repository is in an
6831 unfinished merge, shelve, rebase state etc. You can have this behavior
6838 unfinished merge, shelve, rebase state etc. You can have this behavior
6832 turned on by default by enabling the ``commands.status.verbose`` option.
6839 turned on by default by enabling the ``commands.status.verbose`` option.
6833
6840
6834 You can skip displaying some of these states by setting
6841 You can skip displaying some of these states by setting
6835 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6842 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6836 'histedit', 'merge', 'rebase', or 'unshelve'.
6843 'histedit', 'merge', 'rebase', or 'unshelve'.
6837
6844
6838 Template:
6845 Template:
6839
6846
6840 The following keywords are supported in addition to the common template
6847 The following keywords are supported in addition to the common template
6841 keywords and functions. See also :hg:`help templates`.
6848 keywords and functions. See also :hg:`help templates`.
6842
6849
6843 :path: String. Repository-absolute path of the file.
6850 :path: String. Repository-absolute path of the file.
6844 :source: String. Repository-absolute path of the file originated from.
6851 :source: String. Repository-absolute path of the file originated from.
6845 Available if ``--copies`` is specified.
6852 Available if ``--copies`` is specified.
6846 :status: String. Character denoting file's status.
6853 :status: String. Character denoting file's status.
6847
6854
6848 Examples:
6855 Examples:
6849
6856
6850 - show changes in the working directory relative to a
6857 - show changes in the working directory relative to a
6851 changeset::
6858 changeset::
6852
6859
6853 hg status --rev 9353
6860 hg status --rev 9353
6854
6861
6855 - show changes in the working directory relative to the
6862 - show changes in the working directory relative to the
6856 current directory (see :hg:`help patterns` for more information)::
6863 current directory (see :hg:`help patterns` for more information)::
6857
6864
6858 hg status re:
6865 hg status re:
6859
6866
6860 - show all changes including copies in an existing changeset::
6867 - show all changes including copies in an existing changeset::
6861
6868
6862 hg status --copies --change 9353
6869 hg status --copies --change 9353
6863
6870
6864 - get a NUL separated list of added files, suitable for xargs::
6871 - get a NUL separated list of added files, suitable for xargs::
6865
6872
6866 hg status -an0
6873 hg status -an0
6867
6874
6868 - show more information about the repository status, abbreviating
6875 - show more information about the repository status, abbreviating
6869 added, removed, modified, deleted, and untracked paths::
6876 added, removed, modified, deleted, and untracked paths::
6870
6877
6871 hg status -v -t mardu
6878 hg status -v -t mardu
6872
6879
6873 Returns 0 on success.
6880 Returns 0 on success.
6874
6881
6875 """
6882 """
6876
6883
6877 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6884 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6878 opts = pycompat.byteskwargs(opts)
6885 opts = pycompat.byteskwargs(opts)
6879 revs = opts.get(b'rev')
6886 revs = opts.get(b'rev')
6880 change = opts.get(b'change')
6887 change = opts.get(b'change')
6881 terse = opts.get(b'terse')
6888 terse = opts.get(b'terse')
6882 if terse is _NOTTERSE:
6889 if terse is _NOTTERSE:
6883 if revs:
6890 if revs:
6884 terse = b''
6891 terse = b''
6885 else:
6892 else:
6886 terse = ui.config(b'commands', b'status.terse')
6893 terse = ui.config(b'commands', b'status.terse')
6887
6894
6888 if revs and terse:
6895 if revs and terse:
6889 msg = _(b'cannot use --terse with --rev')
6896 msg = _(b'cannot use --terse with --rev')
6890 raise error.InputError(msg)
6897 raise error.InputError(msg)
6891 elif change:
6898 elif change:
6892 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6899 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6893 ctx2 = scmutil.revsingle(repo, change, None)
6900 ctx2 = scmutil.revsingle(repo, change, None)
6894 ctx1 = ctx2.p1()
6901 ctx1 = ctx2.p1()
6895 else:
6902 else:
6896 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6903 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6897 ctx1, ctx2 = scmutil.revpair(repo, revs)
6904 ctx1, ctx2 = scmutil.revpair(repo, revs)
6898
6905
6899 forcerelativevalue = None
6906 forcerelativevalue = None
6900 if ui.hasconfig(b'commands', b'status.relative'):
6907 if ui.hasconfig(b'commands', b'status.relative'):
6901 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6908 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6902 uipathfn = scmutil.getuipathfn(
6909 uipathfn = scmutil.getuipathfn(
6903 repo,
6910 repo,
6904 legacyrelativevalue=bool(pats),
6911 legacyrelativevalue=bool(pats),
6905 forcerelativevalue=forcerelativevalue,
6912 forcerelativevalue=forcerelativevalue,
6906 )
6913 )
6907
6914
6908 if opts.get(b'print0'):
6915 if opts.get(b'print0'):
6909 end = b'\0'
6916 end = b'\0'
6910 else:
6917 else:
6911 end = b'\n'
6918 end = b'\n'
6912 states = b'modified added removed deleted unknown ignored clean'.split()
6919 states = b'modified added removed deleted unknown ignored clean'.split()
6913 show = [k for k in states if opts.get(k)]
6920 show = [k for k in states if opts.get(k)]
6914 if opts.get(b'all'):
6921 if opts.get(b'all'):
6915 show += ui.quiet and (states[:4] + [b'clean']) or states
6922 show += ui.quiet and (states[:4] + [b'clean']) or states
6916
6923
6917 if not show:
6924 if not show:
6918 if ui.quiet:
6925 if ui.quiet:
6919 show = states[:4]
6926 show = states[:4]
6920 else:
6927 else:
6921 show = states[:5]
6928 show = states[:5]
6922
6929
6923 m = scmutil.match(ctx2, pats, opts)
6930 m = scmutil.match(ctx2, pats, opts)
6924 if terse:
6931 if terse:
6925 # we need to compute clean and unknown to terse
6932 # we need to compute clean and unknown to terse
6926 stat = repo.status(
6933 stat = repo.status(
6927 ctx1.node(),
6934 ctx1.node(),
6928 ctx2.node(),
6935 ctx2.node(),
6929 m,
6936 m,
6930 b'ignored' in show or b'i' in terse,
6937 b'ignored' in show or b'i' in terse,
6931 clean=True,
6938 clean=True,
6932 unknown=True,
6939 unknown=True,
6933 listsubrepos=opts.get(b'subrepos'),
6940 listsubrepos=opts.get(b'subrepos'),
6934 )
6941 )
6935
6942
6936 stat = cmdutil.tersedir(stat, terse)
6943 stat = cmdutil.tersedir(stat, terse)
6937 else:
6944 else:
6938 stat = repo.status(
6945 stat = repo.status(
6939 ctx1.node(),
6946 ctx1.node(),
6940 ctx2.node(),
6947 ctx2.node(),
6941 m,
6948 m,
6942 b'ignored' in show,
6949 b'ignored' in show,
6943 b'clean' in show,
6950 b'clean' in show,
6944 b'unknown' in show,
6951 b'unknown' in show,
6945 opts.get(b'subrepos'),
6952 opts.get(b'subrepos'),
6946 )
6953 )
6947
6954
6948 changestates = zip(
6955 changestates = zip(
6949 states,
6956 states,
6950 pycompat.iterbytestr(b'MAR!?IC'),
6957 pycompat.iterbytestr(b'MAR!?IC'),
6951 [getattr(stat, s.decode('utf8')) for s in states],
6958 [getattr(stat, s.decode('utf8')) for s in states],
6952 )
6959 )
6953
6960
6954 copy = {}
6961 copy = {}
6955 if (
6962 if (
6956 opts.get(b'all')
6963 opts.get(b'all')
6957 or opts.get(b'copies')
6964 or opts.get(b'copies')
6958 or ui.configbool(b'ui', b'statuscopies')
6965 or ui.configbool(b'ui', b'statuscopies')
6959 ) and not opts.get(b'no_status'):
6966 ) and not opts.get(b'no_status'):
6960 copy = copies.pathcopies(ctx1, ctx2, m)
6967 copy = copies.pathcopies(ctx1, ctx2, m)
6961
6968
6962 morestatus = None
6969 morestatus = None
6963 if (
6970 if (
6964 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6971 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6965 and not ui.plain()
6972 and not ui.plain()
6966 and not opts.get(b'print0')
6973 and not opts.get(b'print0')
6967 ):
6974 ):
6968 morestatus = cmdutil.readmorestatus(repo)
6975 morestatus = cmdutil.readmorestatus(repo)
6969
6976
6970 ui.pager(b'status')
6977 ui.pager(b'status')
6971 fm = ui.formatter(b'status', opts)
6978 fm = ui.formatter(b'status', opts)
6972 fmt = b'%s' + end
6979 fmt = b'%s' + end
6973 showchar = not opts.get(b'no_status')
6980 showchar = not opts.get(b'no_status')
6974
6981
6975 for state, char, files in changestates:
6982 for state, char, files in changestates:
6976 if state in show:
6983 if state in show:
6977 label = b'status.' + state
6984 label = b'status.' + state
6978 for f in files:
6985 for f in files:
6979 fm.startitem()
6986 fm.startitem()
6980 fm.context(ctx=ctx2)
6987 fm.context(ctx=ctx2)
6981 fm.data(itemtype=b'file', path=f)
6988 fm.data(itemtype=b'file', path=f)
6982 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6989 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6983 fm.plain(fmt % uipathfn(f), label=label)
6990 fm.plain(fmt % uipathfn(f), label=label)
6984 if f in copy:
6991 if f in copy:
6985 fm.data(source=copy[f])
6992 fm.data(source=copy[f])
6986 fm.plain(
6993 fm.plain(
6987 (b' %s' + end) % uipathfn(copy[f]),
6994 (b' %s' + end) % uipathfn(copy[f]),
6988 label=b'status.copied',
6995 label=b'status.copied',
6989 )
6996 )
6990 if morestatus:
6997 if morestatus:
6991 morestatus.formatfile(f, fm)
6998 morestatus.formatfile(f, fm)
6992
6999
6993 if morestatus:
7000 if morestatus:
6994 morestatus.formatfooter(fm)
7001 morestatus.formatfooter(fm)
6995 fm.end()
7002 fm.end()
6996
7003
6997
7004
6998 @command(
7005 @command(
6999 b'summary|sum',
7006 b'summary|sum',
7000 [(b'', b'remote', None, _(b'check for push and pull'))],
7007 [(b'', b'remote', None, _(b'check for push and pull'))],
7001 b'[--remote]',
7008 b'[--remote]',
7002 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7009 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7003 helpbasic=True,
7010 helpbasic=True,
7004 intents={INTENT_READONLY},
7011 intents={INTENT_READONLY},
7005 )
7012 )
7006 def summary(ui, repo, **opts):
7013 def summary(ui, repo, **opts):
7007 """summarize working directory state
7014 """summarize working directory state
7008
7015
7009 This generates a brief summary of the working directory state,
7016 This generates a brief summary of the working directory state,
7010 including parents, branch, commit status, phase and available updates.
7017 including parents, branch, commit status, phase and available updates.
7011
7018
7012 With the --remote option, this will check the default paths for
7019 With the --remote option, this will check the default paths for
7013 incoming and outgoing changes. This can be time-consuming.
7020 incoming and outgoing changes. This can be time-consuming.
7014
7021
7015 Returns 0 on success.
7022 Returns 0 on success.
7016 """
7023 """
7017
7024
7018 opts = pycompat.byteskwargs(opts)
7025 opts = pycompat.byteskwargs(opts)
7019 ui.pager(b'summary')
7026 ui.pager(b'summary')
7020 ctx = repo[None]
7027 ctx = repo[None]
7021 parents = ctx.parents()
7028 parents = ctx.parents()
7022 pnode = parents[0].node()
7029 pnode = parents[0].node()
7023 marks = []
7030 marks = []
7024
7031
7025 try:
7032 try:
7026 ms = mergestatemod.mergestate.read(repo)
7033 ms = mergestatemod.mergestate.read(repo)
7027 except error.UnsupportedMergeRecords as e:
7034 except error.UnsupportedMergeRecords as e:
7028 s = b' '.join(e.recordtypes)
7035 s = b' '.join(e.recordtypes)
7029 ui.warn(
7036 ui.warn(
7030 _(b'warning: merge state has unsupported record types: %s\n') % s
7037 _(b'warning: merge state has unsupported record types: %s\n') % s
7031 )
7038 )
7032 unresolved = []
7039 unresolved = []
7033 else:
7040 else:
7034 unresolved = list(ms.unresolved())
7041 unresolved = list(ms.unresolved())
7035
7042
7036 for p in parents:
7043 for p in parents:
7037 # label with log.changeset (instead of log.parent) since this
7044 # label with log.changeset (instead of log.parent) since this
7038 # shows a working directory parent *changeset*:
7045 # shows a working directory parent *changeset*:
7039 # i18n: column positioning for "hg summary"
7046 # i18n: column positioning for "hg summary"
7040 ui.write(
7047 ui.write(
7041 _(b'parent: %d:%s ') % (p.rev(), p),
7048 _(b'parent: %d:%s ') % (p.rev(), p),
7042 label=logcmdutil.changesetlabels(p),
7049 label=logcmdutil.changesetlabels(p),
7043 )
7050 )
7044 ui.write(b' '.join(p.tags()), label=b'log.tag')
7051 ui.write(b' '.join(p.tags()), label=b'log.tag')
7045 if p.bookmarks():
7052 if p.bookmarks():
7046 marks.extend(p.bookmarks())
7053 marks.extend(p.bookmarks())
7047 if p.rev() == -1:
7054 if p.rev() == -1:
7048 if not len(repo):
7055 if not len(repo):
7049 ui.write(_(b' (empty repository)'))
7056 ui.write(_(b' (empty repository)'))
7050 else:
7057 else:
7051 ui.write(_(b' (no revision checked out)'))
7058 ui.write(_(b' (no revision checked out)'))
7052 if p.obsolete():
7059 if p.obsolete():
7053 ui.write(_(b' (obsolete)'))
7060 ui.write(_(b' (obsolete)'))
7054 if p.isunstable():
7061 if p.isunstable():
7055 instabilities = (
7062 instabilities = (
7056 ui.label(instability, b'trouble.%s' % instability)
7063 ui.label(instability, b'trouble.%s' % instability)
7057 for instability in p.instabilities()
7064 for instability in p.instabilities()
7058 )
7065 )
7059 ui.write(b' (' + b', '.join(instabilities) + b')')
7066 ui.write(b' (' + b', '.join(instabilities) + b')')
7060 ui.write(b'\n')
7067 ui.write(b'\n')
7061 if p.description():
7068 if p.description():
7062 ui.status(
7069 ui.status(
7063 b' ' + p.description().splitlines()[0].strip() + b'\n',
7070 b' ' + p.description().splitlines()[0].strip() + b'\n',
7064 label=b'log.summary',
7071 label=b'log.summary',
7065 )
7072 )
7066
7073
7067 branch = ctx.branch()
7074 branch = ctx.branch()
7068 bheads = repo.branchheads(branch)
7075 bheads = repo.branchheads(branch)
7069 # i18n: column positioning for "hg summary"
7076 # i18n: column positioning for "hg summary"
7070 m = _(b'branch: %s\n') % branch
7077 m = _(b'branch: %s\n') % branch
7071 if branch != b'default':
7078 if branch != b'default':
7072 ui.write(m, label=b'log.branch')
7079 ui.write(m, label=b'log.branch')
7073 else:
7080 else:
7074 ui.status(m, label=b'log.branch')
7081 ui.status(m, label=b'log.branch')
7075
7082
7076 if marks:
7083 if marks:
7077 active = repo._activebookmark
7084 active = repo._activebookmark
7078 # i18n: column positioning for "hg summary"
7085 # i18n: column positioning for "hg summary"
7079 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7086 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7080 if active is not None:
7087 if active is not None:
7081 if active in marks:
7088 if active in marks:
7082 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7089 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7083 marks.remove(active)
7090 marks.remove(active)
7084 else:
7091 else:
7085 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7092 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7086 for m in marks:
7093 for m in marks:
7087 ui.write(b' ' + m, label=b'log.bookmark')
7094 ui.write(b' ' + m, label=b'log.bookmark')
7088 ui.write(b'\n', label=b'log.bookmark')
7095 ui.write(b'\n', label=b'log.bookmark')
7089
7096
7090 status = repo.status(unknown=True)
7097 status = repo.status(unknown=True)
7091
7098
7092 c = repo.dirstate.copies()
7099 c = repo.dirstate.copies()
7093 copied, renamed = [], []
7100 copied, renamed = [], []
7094 for d, s in pycompat.iteritems(c):
7101 for d, s in pycompat.iteritems(c):
7095 if s in status.removed:
7102 if s in status.removed:
7096 status.removed.remove(s)
7103 status.removed.remove(s)
7097 renamed.append(d)
7104 renamed.append(d)
7098 else:
7105 else:
7099 copied.append(d)
7106 copied.append(d)
7100 if d in status.added:
7107 if d in status.added:
7101 status.added.remove(d)
7108 status.added.remove(d)
7102
7109
7103 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7110 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7104
7111
7105 labels = [
7112 labels = [
7106 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7113 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7107 (ui.label(_(b'%d added'), b'status.added'), status.added),
7114 (ui.label(_(b'%d added'), b'status.added'), status.added),
7108 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7115 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7109 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7116 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7110 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7117 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7111 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7118 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7112 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7119 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7113 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7120 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7114 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7121 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7115 ]
7122 ]
7116 t = []
7123 t = []
7117 for l, s in labels:
7124 for l, s in labels:
7118 if s:
7125 if s:
7119 t.append(l % len(s))
7126 t.append(l % len(s))
7120
7127
7121 t = b', '.join(t)
7128 t = b', '.join(t)
7122 cleanworkdir = False
7129 cleanworkdir = False
7123
7130
7124 if repo.vfs.exists(b'graftstate'):
7131 if repo.vfs.exists(b'graftstate'):
7125 t += _(b' (graft in progress)')
7132 t += _(b' (graft in progress)')
7126 if repo.vfs.exists(b'updatestate'):
7133 if repo.vfs.exists(b'updatestate'):
7127 t += _(b' (interrupted update)')
7134 t += _(b' (interrupted update)')
7128 elif len(parents) > 1:
7135 elif len(parents) > 1:
7129 t += _(b' (merge)')
7136 t += _(b' (merge)')
7130 elif branch != parents[0].branch():
7137 elif branch != parents[0].branch():
7131 t += _(b' (new branch)')
7138 t += _(b' (new branch)')
7132 elif parents[0].closesbranch() and pnode in repo.branchheads(
7139 elif parents[0].closesbranch() and pnode in repo.branchheads(
7133 branch, closed=True
7140 branch, closed=True
7134 ):
7141 ):
7135 t += _(b' (head closed)')
7142 t += _(b' (head closed)')
7136 elif not (
7143 elif not (
7137 status.modified
7144 status.modified
7138 or status.added
7145 or status.added
7139 or status.removed
7146 or status.removed
7140 or renamed
7147 or renamed
7141 or copied
7148 or copied
7142 or subs
7149 or subs
7143 ):
7150 ):
7144 t += _(b' (clean)')
7151 t += _(b' (clean)')
7145 cleanworkdir = True
7152 cleanworkdir = True
7146 elif pnode not in bheads:
7153 elif pnode not in bheads:
7147 t += _(b' (new branch head)')
7154 t += _(b' (new branch head)')
7148
7155
7149 if parents:
7156 if parents:
7150 pendingphase = max(p.phase() for p in parents)
7157 pendingphase = max(p.phase() for p in parents)
7151 else:
7158 else:
7152 pendingphase = phases.public
7159 pendingphase = phases.public
7153
7160
7154 if pendingphase > phases.newcommitphase(ui):
7161 if pendingphase > phases.newcommitphase(ui):
7155 t += b' (%s)' % phases.phasenames[pendingphase]
7162 t += b' (%s)' % phases.phasenames[pendingphase]
7156
7163
7157 if cleanworkdir:
7164 if cleanworkdir:
7158 # i18n: column positioning for "hg summary"
7165 # i18n: column positioning for "hg summary"
7159 ui.status(_(b'commit: %s\n') % t.strip())
7166 ui.status(_(b'commit: %s\n') % t.strip())
7160 else:
7167 else:
7161 # i18n: column positioning for "hg summary"
7168 # i18n: column positioning for "hg summary"
7162 ui.write(_(b'commit: %s\n') % t.strip())
7169 ui.write(_(b'commit: %s\n') % t.strip())
7163
7170
7164 # all ancestors of branch heads - all ancestors of parent = new csets
7171 # all ancestors of branch heads - all ancestors of parent = new csets
7165 new = len(
7172 new = len(
7166 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7173 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7167 )
7174 )
7168
7175
7169 if new == 0:
7176 if new == 0:
7170 # i18n: column positioning for "hg summary"
7177 # i18n: column positioning for "hg summary"
7171 ui.status(_(b'update: (current)\n'))
7178 ui.status(_(b'update: (current)\n'))
7172 elif pnode not in bheads:
7179 elif pnode not in bheads:
7173 # i18n: column positioning for "hg summary"
7180 # i18n: column positioning for "hg summary"
7174 ui.write(_(b'update: %d new changesets (update)\n') % new)
7181 ui.write(_(b'update: %d new changesets (update)\n') % new)
7175 else:
7182 else:
7176 # i18n: column positioning for "hg summary"
7183 # i18n: column positioning for "hg summary"
7177 ui.write(
7184 ui.write(
7178 _(b'update: %d new changesets, %d branch heads (merge)\n')
7185 _(b'update: %d new changesets, %d branch heads (merge)\n')
7179 % (new, len(bheads))
7186 % (new, len(bheads))
7180 )
7187 )
7181
7188
7182 t = []
7189 t = []
7183 draft = len(repo.revs(b'draft()'))
7190 draft = len(repo.revs(b'draft()'))
7184 if draft:
7191 if draft:
7185 t.append(_(b'%d draft') % draft)
7192 t.append(_(b'%d draft') % draft)
7186 secret = len(repo.revs(b'secret()'))
7193 secret = len(repo.revs(b'secret()'))
7187 if secret:
7194 if secret:
7188 t.append(_(b'%d secret') % secret)
7195 t.append(_(b'%d secret') % secret)
7189
7196
7190 if draft or secret:
7197 if draft or secret:
7191 ui.status(_(b'phases: %s\n') % b', '.join(t))
7198 ui.status(_(b'phases: %s\n') % b', '.join(t))
7192
7199
7193 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7200 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7194 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7201 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7195 numtrouble = len(repo.revs(trouble + b"()"))
7202 numtrouble = len(repo.revs(trouble + b"()"))
7196 # We write all the possibilities to ease translation
7203 # We write all the possibilities to ease translation
7197 troublemsg = {
7204 troublemsg = {
7198 b"orphan": _(b"orphan: %d changesets"),
7205 b"orphan": _(b"orphan: %d changesets"),
7199 b"contentdivergent": _(b"content-divergent: %d changesets"),
7206 b"contentdivergent": _(b"content-divergent: %d changesets"),
7200 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7207 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7201 }
7208 }
7202 if numtrouble > 0:
7209 if numtrouble > 0:
7203 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7210 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7204
7211
7205 cmdutil.summaryhooks(ui, repo)
7212 cmdutil.summaryhooks(ui, repo)
7206
7213
7207 if opts.get(b'remote'):
7214 if opts.get(b'remote'):
7208 needsincoming, needsoutgoing = True, True
7215 needsincoming, needsoutgoing = True, True
7209 else:
7216 else:
7210 needsincoming, needsoutgoing = False, False
7217 needsincoming, needsoutgoing = False, False
7211 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7218 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7212 if i:
7219 if i:
7213 needsincoming = True
7220 needsincoming = True
7214 if o:
7221 if o:
7215 needsoutgoing = True
7222 needsoutgoing = True
7216 if not needsincoming and not needsoutgoing:
7223 if not needsincoming and not needsoutgoing:
7217 return
7224 return
7218
7225
7219 def getincoming():
7226 def getincoming():
7220 source, branches = hg.parseurl(ui.expandpath(b'default'))
7227 source, branches = hg.parseurl(ui.expandpath(b'default'))
7221 sbranch = branches[0]
7228 sbranch = branches[0]
7222 try:
7229 try:
7223 other = hg.peer(repo, {}, source)
7230 other = hg.peer(repo, {}, source)
7224 except error.RepoError:
7231 except error.RepoError:
7225 if opts.get(b'remote'):
7232 if opts.get(b'remote'):
7226 raise
7233 raise
7227 return source, sbranch, None, None, None
7234 return source, sbranch, None, None, None
7228 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7235 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7229 if revs:
7236 if revs:
7230 revs = [other.lookup(rev) for rev in revs]
7237 revs = [other.lookup(rev) for rev in revs]
7231 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7238 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7232 repo.ui.pushbuffer()
7239 repo.ui.pushbuffer()
7233 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7240 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7234 repo.ui.popbuffer()
7241 repo.ui.popbuffer()
7235 return source, sbranch, other, commoninc, commoninc[1]
7242 return source, sbranch, other, commoninc, commoninc[1]
7236
7243
7237 if needsincoming:
7244 if needsincoming:
7238 source, sbranch, sother, commoninc, incoming = getincoming()
7245 source, sbranch, sother, commoninc, incoming = getincoming()
7239 else:
7246 else:
7240 source = sbranch = sother = commoninc = incoming = None
7247 source = sbranch = sother = commoninc = incoming = None
7241
7248
7242 def getoutgoing():
7249 def getoutgoing():
7243 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7250 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7244 dbranch = branches[0]
7251 dbranch = branches[0]
7245 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7252 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7246 if source != dest:
7253 if source != dest:
7247 try:
7254 try:
7248 dother = hg.peer(repo, {}, dest)
7255 dother = hg.peer(repo, {}, dest)
7249 except error.RepoError:
7256 except error.RepoError:
7250 if opts.get(b'remote'):
7257 if opts.get(b'remote'):
7251 raise
7258 raise
7252 return dest, dbranch, None, None
7259 return dest, dbranch, None, None
7253 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7260 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7254 elif sother is None:
7261 elif sother is None:
7255 # there is no explicit destination peer, but source one is invalid
7262 # there is no explicit destination peer, but source one is invalid
7256 return dest, dbranch, None, None
7263 return dest, dbranch, None, None
7257 else:
7264 else:
7258 dother = sother
7265 dother = sother
7259 if source != dest or (sbranch is not None and sbranch != dbranch):
7266 if source != dest or (sbranch is not None and sbranch != dbranch):
7260 common = None
7267 common = None
7261 else:
7268 else:
7262 common = commoninc
7269 common = commoninc
7263 if revs:
7270 if revs:
7264 revs = [repo.lookup(rev) for rev in revs]
7271 revs = [repo.lookup(rev) for rev in revs]
7265 repo.ui.pushbuffer()
7272 repo.ui.pushbuffer()
7266 outgoing = discovery.findcommonoutgoing(
7273 outgoing = discovery.findcommonoutgoing(
7267 repo, dother, onlyheads=revs, commoninc=common
7274 repo, dother, onlyheads=revs, commoninc=common
7268 )
7275 )
7269 repo.ui.popbuffer()
7276 repo.ui.popbuffer()
7270 return dest, dbranch, dother, outgoing
7277 return dest, dbranch, dother, outgoing
7271
7278
7272 if needsoutgoing:
7279 if needsoutgoing:
7273 dest, dbranch, dother, outgoing = getoutgoing()
7280 dest, dbranch, dother, outgoing = getoutgoing()
7274 else:
7281 else:
7275 dest = dbranch = dother = outgoing = None
7282 dest = dbranch = dother = outgoing = None
7276
7283
7277 if opts.get(b'remote'):
7284 if opts.get(b'remote'):
7278 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7285 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7279 # The former always sets `sother` (or raises an exception if it can't);
7286 # The former always sets `sother` (or raises an exception if it can't);
7280 # the latter always sets `outgoing`.
7287 # the latter always sets `outgoing`.
7281 assert sother is not None
7288 assert sother is not None
7282 assert outgoing is not None
7289 assert outgoing is not None
7283
7290
7284 t = []
7291 t = []
7285 if incoming:
7292 if incoming:
7286 t.append(_(b'1 or more incoming'))
7293 t.append(_(b'1 or more incoming'))
7287 o = outgoing.missing
7294 o = outgoing.missing
7288 if o:
7295 if o:
7289 t.append(_(b'%d outgoing') % len(o))
7296 t.append(_(b'%d outgoing') % len(o))
7290 other = dother or sother
7297 other = dother or sother
7291 if b'bookmarks' in other.listkeys(b'namespaces'):
7298 if b'bookmarks' in other.listkeys(b'namespaces'):
7292 counts = bookmarks.summary(repo, other)
7299 counts = bookmarks.summary(repo, other)
7293 if counts[0] > 0:
7300 if counts[0] > 0:
7294 t.append(_(b'%d incoming bookmarks') % counts[0])
7301 t.append(_(b'%d incoming bookmarks') % counts[0])
7295 if counts[1] > 0:
7302 if counts[1] > 0:
7296 t.append(_(b'%d outgoing bookmarks') % counts[1])
7303 t.append(_(b'%d outgoing bookmarks') % counts[1])
7297
7304
7298 if t:
7305 if t:
7299 # i18n: column positioning for "hg summary"
7306 # i18n: column positioning for "hg summary"
7300 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7307 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7301 else:
7308 else:
7302 # i18n: column positioning for "hg summary"
7309 # i18n: column positioning for "hg summary"
7303 ui.status(_(b'remote: (synced)\n'))
7310 ui.status(_(b'remote: (synced)\n'))
7304
7311
7305 cmdutil.summaryremotehooks(
7312 cmdutil.summaryremotehooks(
7306 ui,
7313 ui,
7307 repo,
7314 repo,
7308 opts,
7315 opts,
7309 (
7316 (
7310 (source, sbranch, sother, commoninc),
7317 (source, sbranch, sother, commoninc),
7311 (dest, dbranch, dother, outgoing),
7318 (dest, dbranch, dother, outgoing),
7312 ),
7319 ),
7313 )
7320 )
7314
7321
7315
7322
7316 @command(
7323 @command(
7317 b'tag',
7324 b'tag',
7318 [
7325 [
7319 (b'f', b'force', None, _(b'force tag')),
7326 (b'f', b'force', None, _(b'force tag')),
7320 (b'l', b'local', None, _(b'make the tag local')),
7327 (b'l', b'local', None, _(b'make the tag local')),
7321 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7328 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7322 (b'', b'remove', None, _(b'remove a tag')),
7329 (b'', b'remove', None, _(b'remove a tag')),
7323 # -l/--local is already there, commitopts cannot be used
7330 # -l/--local is already there, commitopts cannot be used
7324 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7331 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7325 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7332 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7326 ]
7333 ]
7327 + commitopts2,
7334 + commitopts2,
7328 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7335 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7329 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7336 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7330 )
7337 )
7331 def tag(ui, repo, name1, *names, **opts):
7338 def tag(ui, repo, name1, *names, **opts):
7332 """add one or more tags for the current or given revision
7339 """add one or more tags for the current or given revision
7333
7340
7334 Name a particular revision using <name>.
7341 Name a particular revision using <name>.
7335
7342
7336 Tags are used to name particular revisions of the repository and are
7343 Tags are used to name particular revisions of the repository and are
7337 very useful to compare different revisions, to go back to significant
7344 very useful to compare different revisions, to go back to significant
7338 earlier versions or to mark branch points as releases, etc. Changing
7345 earlier versions or to mark branch points as releases, etc. Changing
7339 an existing tag is normally disallowed; use -f/--force to override.
7346 an existing tag is normally disallowed; use -f/--force to override.
7340
7347
7341 If no revision is given, the parent of the working directory is
7348 If no revision is given, the parent of the working directory is
7342 used.
7349 used.
7343
7350
7344 To facilitate version control, distribution, and merging of tags,
7351 To facilitate version control, distribution, and merging of tags,
7345 they are stored as a file named ".hgtags" which is managed similarly
7352 they are stored as a file named ".hgtags" which is managed similarly
7346 to other project files and can be hand-edited if necessary. This
7353 to other project files and can be hand-edited if necessary. This
7347 also means that tagging creates a new commit. The file
7354 also means that tagging creates a new commit. The file
7348 ".hg/localtags" is used for local tags (not shared among
7355 ".hg/localtags" is used for local tags (not shared among
7349 repositories).
7356 repositories).
7350
7357
7351 Tag commits are usually made at the head of a branch. If the parent
7358 Tag commits are usually made at the head of a branch. If the parent
7352 of the working directory is not a branch head, :hg:`tag` aborts; use
7359 of the working directory is not a branch head, :hg:`tag` aborts; use
7353 -f/--force to force the tag commit to be based on a non-head
7360 -f/--force to force the tag commit to be based on a non-head
7354 changeset.
7361 changeset.
7355
7362
7356 See :hg:`help dates` for a list of formats valid for -d/--date.
7363 See :hg:`help dates` for a list of formats valid for -d/--date.
7357
7364
7358 Since tag names have priority over branch names during revision
7365 Since tag names have priority over branch names during revision
7359 lookup, using an existing branch name as a tag name is discouraged.
7366 lookup, using an existing branch name as a tag name is discouraged.
7360
7367
7361 Returns 0 on success.
7368 Returns 0 on success.
7362 """
7369 """
7363 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7370 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7364 opts = pycompat.byteskwargs(opts)
7371 opts = pycompat.byteskwargs(opts)
7365 with repo.wlock(), repo.lock():
7372 with repo.wlock(), repo.lock():
7366 rev_ = b"."
7373 rev_ = b"."
7367 names = [t.strip() for t in (name1,) + names]
7374 names = [t.strip() for t in (name1,) + names]
7368 if len(names) != len(set(names)):
7375 if len(names) != len(set(names)):
7369 raise error.InputError(_(b'tag names must be unique'))
7376 raise error.InputError(_(b'tag names must be unique'))
7370 for n in names:
7377 for n in names:
7371 scmutil.checknewlabel(repo, n, b'tag')
7378 scmutil.checknewlabel(repo, n, b'tag')
7372 if not n:
7379 if not n:
7373 raise error.InputError(
7380 raise error.InputError(
7374 _(b'tag names cannot consist entirely of whitespace')
7381 _(b'tag names cannot consist entirely of whitespace')
7375 )
7382 )
7376 if opts.get(b'rev'):
7383 if opts.get(b'rev'):
7377 rev_ = opts[b'rev']
7384 rev_ = opts[b'rev']
7378 message = opts.get(b'message')
7385 message = opts.get(b'message')
7379 if opts.get(b'remove'):
7386 if opts.get(b'remove'):
7380 if opts.get(b'local'):
7387 if opts.get(b'local'):
7381 expectedtype = b'local'
7388 expectedtype = b'local'
7382 else:
7389 else:
7383 expectedtype = b'global'
7390 expectedtype = b'global'
7384
7391
7385 for n in names:
7392 for n in names:
7386 if repo.tagtype(n) == b'global':
7393 if repo.tagtype(n) == b'global':
7387 alltags = tagsmod.findglobaltags(ui, repo)
7394 alltags = tagsmod.findglobaltags(ui, repo)
7388 if alltags[n][0] == nullid:
7395 if alltags[n][0] == nullid:
7389 raise error.InputError(
7396 raise error.InputError(
7390 _(b"tag '%s' is already removed") % n
7397 _(b"tag '%s' is already removed") % n
7391 )
7398 )
7392 if not repo.tagtype(n):
7399 if not repo.tagtype(n):
7393 raise error.InputError(_(b"tag '%s' does not exist") % n)
7400 raise error.InputError(_(b"tag '%s' does not exist") % n)
7394 if repo.tagtype(n) != expectedtype:
7401 if repo.tagtype(n) != expectedtype:
7395 if expectedtype == b'global':
7402 if expectedtype == b'global':
7396 raise error.InputError(
7403 raise error.InputError(
7397 _(b"tag '%s' is not a global tag") % n
7404 _(b"tag '%s' is not a global tag") % n
7398 )
7405 )
7399 else:
7406 else:
7400 raise error.InputError(
7407 raise error.InputError(
7401 _(b"tag '%s' is not a local tag") % n
7408 _(b"tag '%s' is not a local tag") % n
7402 )
7409 )
7403 rev_ = b'null'
7410 rev_ = b'null'
7404 if not message:
7411 if not message:
7405 # we don't translate commit messages
7412 # we don't translate commit messages
7406 message = b'Removed tag %s' % b', '.join(names)
7413 message = b'Removed tag %s' % b', '.join(names)
7407 elif not opts.get(b'force'):
7414 elif not opts.get(b'force'):
7408 for n in names:
7415 for n in names:
7409 if n in repo.tags():
7416 if n in repo.tags():
7410 raise error.InputError(
7417 raise error.InputError(
7411 _(b"tag '%s' already exists (use -f to force)") % n
7418 _(b"tag '%s' already exists (use -f to force)") % n
7412 )
7419 )
7413 if not opts.get(b'local'):
7420 if not opts.get(b'local'):
7414 p1, p2 = repo.dirstate.parents()
7421 p1, p2 = repo.dirstate.parents()
7415 if p2 != nullid:
7422 if p2 != nullid:
7416 raise error.StateError(_(b'uncommitted merge'))
7423 raise error.StateError(_(b'uncommitted merge'))
7417 bheads = repo.branchheads()
7424 bheads = repo.branchheads()
7418 if not opts.get(b'force') and bheads and p1 not in bheads:
7425 if not opts.get(b'force') and bheads and p1 not in bheads:
7419 raise error.InputError(
7426 raise error.InputError(
7420 _(
7427 _(
7421 b'working directory is not at a branch head '
7428 b'working directory is not at a branch head '
7422 b'(use -f to force)'
7429 b'(use -f to force)'
7423 )
7430 )
7424 )
7431 )
7425 node = scmutil.revsingle(repo, rev_).node()
7432 node = scmutil.revsingle(repo, rev_).node()
7426
7433
7427 if not message:
7434 if not message:
7428 # we don't translate commit messages
7435 # we don't translate commit messages
7429 message = b'Added tag %s for changeset %s' % (
7436 message = b'Added tag %s for changeset %s' % (
7430 b', '.join(names),
7437 b', '.join(names),
7431 short(node),
7438 short(node),
7432 )
7439 )
7433
7440
7434 date = opts.get(b'date')
7441 date = opts.get(b'date')
7435 if date:
7442 if date:
7436 date = dateutil.parsedate(date)
7443 date = dateutil.parsedate(date)
7437
7444
7438 if opts.get(b'remove'):
7445 if opts.get(b'remove'):
7439 editform = b'tag.remove'
7446 editform = b'tag.remove'
7440 else:
7447 else:
7441 editform = b'tag.add'
7448 editform = b'tag.add'
7442 editor = cmdutil.getcommiteditor(
7449 editor = cmdutil.getcommiteditor(
7443 editform=editform, **pycompat.strkwargs(opts)
7450 editform=editform, **pycompat.strkwargs(opts)
7444 )
7451 )
7445
7452
7446 # don't allow tagging the null rev
7453 # don't allow tagging the null rev
7447 if (
7454 if (
7448 not opts.get(b'remove')
7455 not opts.get(b'remove')
7449 and scmutil.revsingle(repo, rev_).rev() == nullrev
7456 and scmutil.revsingle(repo, rev_).rev() == nullrev
7450 ):
7457 ):
7451 raise error.InputError(_(b"cannot tag null revision"))
7458 raise error.InputError(_(b"cannot tag null revision"))
7452
7459
7453 tagsmod.tag(
7460 tagsmod.tag(
7454 repo,
7461 repo,
7455 names,
7462 names,
7456 node,
7463 node,
7457 message,
7464 message,
7458 opts.get(b'local'),
7465 opts.get(b'local'),
7459 opts.get(b'user'),
7466 opts.get(b'user'),
7460 date,
7467 date,
7461 editor=editor,
7468 editor=editor,
7462 )
7469 )
7463
7470
7464
7471
7465 @command(
7472 @command(
7466 b'tags',
7473 b'tags',
7467 formatteropts,
7474 formatteropts,
7468 b'',
7475 b'',
7469 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7476 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7470 intents={INTENT_READONLY},
7477 intents={INTENT_READONLY},
7471 )
7478 )
7472 def tags(ui, repo, **opts):
7479 def tags(ui, repo, **opts):
7473 """list repository tags
7480 """list repository tags
7474
7481
7475 This lists both regular and local tags. When the -v/--verbose
7482 This lists both regular and local tags. When the -v/--verbose
7476 switch is used, a third column "local" is printed for local tags.
7483 switch is used, a third column "local" is printed for local tags.
7477 When the -q/--quiet switch is used, only the tag name is printed.
7484 When the -q/--quiet switch is used, only the tag name is printed.
7478
7485
7479 .. container:: verbose
7486 .. container:: verbose
7480
7487
7481 Template:
7488 Template:
7482
7489
7483 The following keywords are supported in addition to the common template
7490 The following keywords are supported in addition to the common template
7484 keywords and functions such as ``{tag}``. See also
7491 keywords and functions such as ``{tag}``. See also
7485 :hg:`help templates`.
7492 :hg:`help templates`.
7486
7493
7487 :type: String. ``local`` for local tags.
7494 :type: String. ``local`` for local tags.
7488
7495
7489 Returns 0 on success.
7496 Returns 0 on success.
7490 """
7497 """
7491
7498
7492 opts = pycompat.byteskwargs(opts)
7499 opts = pycompat.byteskwargs(opts)
7493 ui.pager(b'tags')
7500 ui.pager(b'tags')
7494 fm = ui.formatter(b'tags', opts)
7501 fm = ui.formatter(b'tags', opts)
7495 hexfunc = fm.hexfunc
7502 hexfunc = fm.hexfunc
7496
7503
7497 for t, n in reversed(repo.tagslist()):
7504 for t, n in reversed(repo.tagslist()):
7498 hn = hexfunc(n)
7505 hn = hexfunc(n)
7499 label = b'tags.normal'
7506 label = b'tags.normal'
7500 tagtype = repo.tagtype(t)
7507 tagtype = repo.tagtype(t)
7501 if not tagtype or tagtype == b'global':
7508 if not tagtype or tagtype == b'global':
7502 tagtype = b''
7509 tagtype = b''
7503 else:
7510 else:
7504 label = b'tags.' + tagtype
7511 label = b'tags.' + tagtype
7505
7512
7506 fm.startitem()
7513 fm.startitem()
7507 fm.context(repo=repo)
7514 fm.context(repo=repo)
7508 fm.write(b'tag', b'%s', t, label=label)
7515 fm.write(b'tag', b'%s', t, label=label)
7509 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7516 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7510 fm.condwrite(
7517 fm.condwrite(
7511 not ui.quiet,
7518 not ui.quiet,
7512 b'rev node',
7519 b'rev node',
7513 fmt,
7520 fmt,
7514 repo.changelog.rev(n),
7521 repo.changelog.rev(n),
7515 hn,
7522 hn,
7516 label=label,
7523 label=label,
7517 )
7524 )
7518 fm.condwrite(
7525 fm.condwrite(
7519 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7526 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7520 )
7527 )
7521 fm.plain(b'\n')
7528 fm.plain(b'\n')
7522 fm.end()
7529 fm.end()
7523
7530
7524
7531
7525 @command(
7532 @command(
7526 b'tip',
7533 b'tip',
7527 [
7534 [
7528 (b'p', b'patch', None, _(b'show patch')),
7535 (b'p', b'patch', None, _(b'show patch')),
7529 (b'g', b'git', None, _(b'use git extended diff format')),
7536 (b'g', b'git', None, _(b'use git extended diff format')),
7530 ]
7537 ]
7531 + templateopts,
7538 + templateopts,
7532 _(b'[-p] [-g]'),
7539 _(b'[-p] [-g]'),
7533 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7540 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7534 )
7541 )
7535 def tip(ui, repo, **opts):
7542 def tip(ui, repo, **opts):
7536 """show the tip revision (DEPRECATED)
7543 """show the tip revision (DEPRECATED)
7537
7544
7538 The tip revision (usually just called the tip) is the changeset
7545 The tip revision (usually just called the tip) is the changeset
7539 most recently added to the repository (and therefore the most
7546 most recently added to the repository (and therefore the most
7540 recently changed head).
7547 recently changed head).
7541
7548
7542 If you have just made a commit, that commit will be the tip. If
7549 If you have just made a commit, that commit will be the tip. If
7543 you have just pulled changes from another repository, the tip of
7550 you have just pulled changes from another repository, the tip of
7544 that repository becomes the current tip. The "tip" tag is special
7551 that repository becomes the current tip. The "tip" tag is special
7545 and cannot be renamed or assigned to a different changeset.
7552 and cannot be renamed or assigned to a different changeset.
7546
7553
7547 This command is deprecated, please use :hg:`heads` instead.
7554 This command is deprecated, please use :hg:`heads` instead.
7548
7555
7549 Returns 0 on success.
7556 Returns 0 on success.
7550 """
7557 """
7551 opts = pycompat.byteskwargs(opts)
7558 opts = pycompat.byteskwargs(opts)
7552 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7559 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7553 displayer.show(repo[b'tip'])
7560 displayer.show(repo[b'tip'])
7554 displayer.close()
7561 displayer.close()
7555
7562
7556
7563
7557 @command(
7564 @command(
7558 b'unbundle',
7565 b'unbundle',
7559 [
7566 [
7560 (
7567 (
7561 b'u',
7568 b'u',
7562 b'update',
7569 b'update',
7563 None,
7570 None,
7564 _(b'update to new branch head if changesets were unbundled'),
7571 _(b'update to new branch head if changesets were unbundled'),
7565 )
7572 )
7566 ],
7573 ],
7567 _(b'[-u] FILE...'),
7574 _(b'[-u] FILE...'),
7568 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7575 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7569 )
7576 )
7570 def unbundle(ui, repo, fname1, *fnames, **opts):
7577 def unbundle(ui, repo, fname1, *fnames, **opts):
7571 """apply one or more bundle files
7578 """apply one or more bundle files
7572
7579
7573 Apply one or more bundle files generated by :hg:`bundle`.
7580 Apply one or more bundle files generated by :hg:`bundle`.
7574
7581
7575 Returns 0 on success, 1 if an update has unresolved files.
7582 Returns 0 on success, 1 if an update has unresolved files.
7576 """
7583 """
7577 fnames = (fname1,) + fnames
7584 fnames = (fname1,) + fnames
7578
7585
7579 with repo.lock():
7586 with repo.lock():
7580 for fname in fnames:
7587 for fname in fnames:
7581 f = hg.openpath(ui, fname)
7588 f = hg.openpath(ui, fname)
7582 gen = exchange.readbundle(ui, f, fname)
7589 gen = exchange.readbundle(ui, f, fname)
7583 if isinstance(gen, streamclone.streamcloneapplier):
7590 if isinstance(gen, streamclone.streamcloneapplier):
7584 raise error.InputError(
7591 raise error.InputError(
7585 _(
7592 _(
7586 b'packed bundles cannot be applied with '
7593 b'packed bundles cannot be applied with '
7587 b'"hg unbundle"'
7594 b'"hg unbundle"'
7588 ),
7595 ),
7589 hint=_(b'use "hg debugapplystreamclonebundle"'),
7596 hint=_(b'use "hg debugapplystreamclonebundle"'),
7590 )
7597 )
7591 url = b'bundle:' + fname
7598 url = b'bundle:' + fname
7592 try:
7599 try:
7593 txnname = b'unbundle'
7600 txnname = b'unbundle'
7594 if not isinstance(gen, bundle2.unbundle20):
7601 if not isinstance(gen, bundle2.unbundle20):
7595 txnname = b'unbundle\n%s' % util.hidepassword(url)
7602 txnname = b'unbundle\n%s' % util.hidepassword(url)
7596 with repo.transaction(txnname) as tr:
7603 with repo.transaction(txnname) as tr:
7597 op = bundle2.applybundle(
7604 op = bundle2.applybundle(
7598 repo, gen, tr, source=b'unbundle', url=url
7605 repo, gen, tr, source=b'unbundle', url=url
7599 )
7606 )
7600 except error.BundleUnknownFeatureError as exc:
7607 except error.BundleUnknownFeatureError as exc:
7601 raise error.Abort(
7608 raise error.Abort(
7602 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7609 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7603 hint=_(
7610 hint=_(
7604 b"see https://mercurial-scm.org/"
7611 b"see https://mercurial-scm.org/"
7605 b"wiki/BundleFeature for more "
7612 b"wiki/BundleFeature for more "
7606 b"information"
7613 b"information"
7607 ),
7614 ),
7608 )
7615 )
7609 modheads = bundle2.combinechangegroupresults(op)
7616 modheads = bundle2.combinechangegroupresults(op)
7610
7617
7611 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7618 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7612 return 1
7619 return 1
7613 else:
7620 else:
7614 return 0
7621 return 0
7615
7622
7616
7623
7617 @command(
7624 @command(
7618 b'unshelve',
7625 b'unshelve',
7619 [
7626 [
7620 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7627 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7621 (
7628 (
7622 b'c',
7629 b'c',
7623 b'continue',
7630 b'continue',
7624 None,
7631 None,
7625 _(b'continue an incomplete unshelve operation'),
7632 _(b'continue an incomplete unshelve operation'),
7626 ),
7633 ),
7627 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7634 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7628 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7635 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7629 (
7636 (
7630 b'n',
7637 b'n',
7631 b'name',
7638 b'name',
7632 b'',
7639 b'',
7633 _(b'restore shelved change with given name'),
7640 _(b'restore shelved change with given name'),
7634 _(b'NAME'),
7641 _(b'NAME'),
7635 ),
7642 ),
7636 (b't', b'tool', b'', _(b'specify merge tool')),
7643 (b't', b'tool', b'', _(b'specify merge tool')),
7637 (
7644 (
7638 b'',
7645 b'',
7639 b'date',
7646 b'date',
7640 b'',
7647 b'',
7641 _(b'set date for temporary commits (DEPRECATED)'),
7648 _(b'set date for temporary commits (DEPRECATED)'),
7642 _(b'DATE'),
7649 _(b'DATE'),
7643 ),
7650 ),
7644 ],
7651 ],
7645 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7652 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7646 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7653 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7647 )
7654 )
7648 def unshelve(ui, repo, *shelved, **opts):
7655 def unshelve(ui, repo, *shelved, **opts):
7649 """restore a shelved change to the working directory
7656 """restore a shelved change to the working directory
7650
7657
7651 This command accepts an optional name of a shelved change to
7658 This command accepts an optional name of a shelved change to
7652 restore. If none is given, the most recent shelved change is used.
7659 restore. If none is given, the most recent shelved change is used.
7653
7660
7654 If a shelved change is applied successfully, the bundle that
7661 If a shelved change is applied successfully, the bundle that
7655 contains the shelved changes is moved to a backup location
7662 contains the shelved changes is moved to a backup location
7656 (.hg/shelve-backup).
7663 (.hg/shelve-backup).
7657
7664
7658 Since you can restore a shelved change on top of an arbitrary
7665 Since you can restore a shelved change on top of an arbitrary
7659 commit, it is possible that unshelving will result in a conflict
7666 commit, it is possible that unshelving will result in a conflict
7660 between your changes and the commits you are unshelving onto. If
7667 between your changes and the commits you are unshelving onto. If
7661 this occurs, you must resolve the conflict, then use
7668 this occurs, you must resolve the conflict, then use
7662 ``--continue`` to complete the unshelve operation. (The bundle
7669 ``--continue`` to complete the unshelve operation. (The bundle
7663 will not be moved until you successfully complete the unshelve.)
7670 will not be moved until you successfully complete the unshelve.)
7664
7671
7665 (Alternatively, you can use ``--abort`` to abandon an unshelve
7672 (Alternatively, you can use ``--abort`` to abandon an unshelve
7666 that causes a conflict. This reverts the unshelved changes, and
7673 that causes a conflict. This reverts the unshelved changes, and
7667 leaves the bundle in place.)
7674 leaves the bundle in place.)
7668
7675
7669 If bare shelved change (without interactive, include and exclude
7676 If bare shelved change (without interactive, include and exclude
7670 option) was done on newly created branch it would restore branch
7677 option) was done on newly created branch it would restore branch
7671 information to the working directory.
7678 information to the working directory.
7672
7679
7673 After a successful unshelve, the shelved changes are stored in a
7680 After a successful unshelve, the shelved changes are stored in a
7674 backup directory. Only the N most recent backups are kept. N
7681 backup directory. Only the N most recent backups are kept. N
7675 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7682 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7676 configuration option.
7683 configuration option.
7677
7684
7678 .. container:: verbose
7685 .. container:: verbose
7679
7686
7680 Timestamp in seconds is used to decide order of backups. More
7687 Timestamp in seconds is used to decide order of backups. More
7681 than ``maxbackups`` backups are kept, if same timestamp
7688 than ``maxbackups`` backups are kept, if same timestamp
7682 prevents from deciding exact order of them, for safety.
7689 prevents from deciding exact order of them, for safety.
7683
7690
7684 Selected changes can be unshelved with ``--interactive`` flag.
7691 Selected changes can be unshelved with ``--interactive`` flag.
7685 The working directory is updated with the selected changes, and
7692 The working directory is updated with the selected changes, and
7686 only the unselected changes remain shelved.
7693 only the unselected changes remain shelved.
7687 Note: The whole shelve is applied to working directory first before
7694 Note: The whole shelve is applied to working directory first before
7688 running interactively. So, this will bring up all the conflicts between
7695 running interactively. So, this will bring up all the conflicts between
7689 working directory and the shelve, irrespective of which changes will be
7696 working directory and the shelve, irrespective of which changes will be
7690 unshelved.
7697 unshelved.
7691 """
7698 """
7692 with repo.wlock():
7699 with repo.wlock():
7693 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7700 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7694
7701
7695
7702
7696 statemod.addunfinished(
7703 statemod.addunfinished(
7697 b'unshelve',
7704 b'unshelve',
7698 fname=b'shelvedstate',
7705 fname=b'shelvedstate',
7699 continueflag=True,
7706 continueflag=True,
7700 abortfunc=shelvemod.hgabortunshelve,
7707 abortfunc=shelvemod.hgabortunshelve,
7701 continuefunc=shelvemod.hgcontinueunshelve,
7708 continuefunc=shelvemod.hgcontinueunshelve,
7702 cmdmsg=_(b'unshelve already in progress'),
7709 cmdmsg=_(b'unshelve already in progress'),
7703 )
7710 )
7704
7711
7705
7712
7706 @command(
7713 @command(
7707 b'update|up|checkout|co',
7714 b'update|up|checkout|co',
7708 [
7715 [
7709 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7716 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7710 (b'c', b'check', None, _(b'require clean working directory')),
7717 (b'c', b'check', None, _(b'require clean working directory')),
7711 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7718 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7712 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7719 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7713 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7720 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7714 ]
7721 ]
7715 + mergetoolopts,
7722 + mergetoolopts,
7716 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7723 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7717 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7724 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7718 helpbasic=True,
7725 helpbasic=True,
7719 )
7726 )
7720 def update(ui, repo, node=None, **opts):
7727 def update(ui, repo, node=None, **opts):
7721 """update working directory (or switch revisions)
7728 """update working directory (or switch revisions)
7722
7729
7723 Update the repository's working directory to the specified
7730 Update the repository's working directory to the specified
7724 changeset. If no changeset is specified, update to the tip of the
7731 changeset. If no changeset is specified, update to the tip of the
7725 current named branch and move the active bookmark (see :hg:`help
7732 current named branch and move the active bookmark (see :hg:`help
7726 bookmarks`).
7733 bookmarks`).
7727
7734
7728 Update sets the working directory's parent revision to the specified
7735 Update sets the working directory's parent revision to the specified
7729 changeset (see :hg:`help parents`).
7736 changeset (see :hg:`help parents`).
7730
7737
7731 If the changeset is not a descendant or ancestor of the working
7738 If the changeset is not a descendant or ancestor of the working
7732 directory's parent and there are uncommitted changes, the update is
7739 directory's parent and there are uncommitted changes, the update is
7733 aborted. With the -c/--check option, the working directory is checked
7740 aborted. With the -c/--check option, the working directory is checked
7734 for uncommitted changes; if none are found, the working directory is
7741 for uncommitted changes; if none are found, the working directory is
7735 updated to the specified changeset.
7742 updated to the specified changeset.
7736
7743
7737 .. container:: verbose
7744 .. container:: verbose
7738
7745
7739 The -C/--clean, -c/--check, and -m/--merge options control what
7746 The -C/--clean, -c/--check, and -m/--merge options control what
7740 happens if the working directory contains uncommitted changes.
7747 happens if the working directory contains uncommitted changes.
7741 At most of one of them can be specified.
7748 At most of one of them can be specified.
7742
7749
7743 1. If no option is specified, and if
7750 1. If no option is specified, and if
7744 the requested changeset is an ancestor or descendant of
7751 the requested changeset is an ancestor or descendant of
7745 the working directory's parent, the uncommitted changes
7752 the working directory's parent, the uncommitted changes
7746 are merged into the requested changeset and the merged
7753 are merged into the requested changeset and the merged
7747 result is left uncommitted. If the requested changeset is
7754 result is left uncommitted. If the requested changeset is
7748 not an ancestor or descendant (that is, it is on another
7755 not an ancestor or descendant (that is, it is on another
7749 branch), the update is aborted and the uncommitted changes
7756 branch), the update is aborted and the uncommitted changes
7750 are preserved.
7757 are preserved.
7751
7758
7752 2. With the -m/--merge option, the update is allowed even if the
7759 2. With the -m/--merge option, the update is allowed even if the
7753 requested changeset is not an ancestor or descendant of
7760 requested changeset is not an ancestor or descendant of
7754 the working directory's parent.
7761 the working directory's parent.
7755
7762
7756 3. With the -c/--check option, the update is aborted and the
7763 3. With the -c/--check option, the update is aborted and the
7757 uncommitted changes are preserved.
7764 uncommitted changes are preserved.
7758
7765
7759 4. With the -C/--clean option, uncommitted changes are discarded and
7766 4. With the -C/--clean option, uncommitted changes are discarded and
7760 the working directory is updated to the requested changeset.
7767 the working directory is updated to the requested changeset.
7761
7768
7762 To cancel an uncommitted merge (and lose your changes), use
7769 To cancel an uncommitted merge (and lose your changes), use
7763 :hg:`merge --abort`.
7770 :hg:`merge --abort`.
7764
7771
7765 Use null as the changeset to remove the working directory (like
7772 Use null as the changeset to remove the working directory (like
7766 :hg:`clone -U`).
7773 :hg:`clone -U`).
7767
7774
7768 If you want to revert just one file to an older revision, use
7775 If you want to revert just one file to an older revision, use
7769 :hg:`revert [-r REV] NAME`.
7776 :hg:`revert [-r REV] NAME`.
7770
7777
7771 See :hg:`help dates` for a list of formats valid for -d/--date.
7778 See :hg:`help dates` for a list of formats valid for -d/--date.
7772
7779
7773 Returns 0 on success, 1 if there are unresolved files.
7780 Returns 0 on success, 1 if there are unresolved files.
7774 """
7781 """
7775 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7782 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7776 rev = opts.get('rev')
7783 rev = opts.get('rev')
7777 date = opts.get('date')
7784 date = opts.get('date')
7778 clean = opts.get('clean')
7785 clean = opts.get('clean')
7779 check = opts.get('check')
7786 check = opts.get('check')
7780 merge = opts.get('merge')
7787 merge = opts.get('merge')
7781 if rev and node:
7788 if rev and node:
7782 raise error.InputError(_(b"please specify just one revision"))
7789 raise error.InputError(_(b"please specify just one revision"))
7783
7790
7784 if ui.configbool(b'commands', b'update.requiredest'):
7791 if ui.configbool(b'commands', b'update.requiredest'):
7785 if not node and not rev and not date:
7792 if not node and not rev and not date:
7786 raise error.InputError(
7793 raise error.InputError(
7787 _(b'you must specify a destination'),
7794 _(b'you must specify a destination'),
7788 hint=_(b'for example: hg update ".::"'),
7795 hint=_(b'for example: hg update ".::"'),
7789 )
7796 )
7790
7797
7791 if rev is None or rev == b'':
7798 if rev is None or rev == b'':
7792 rev = node
7799 rev = node
7793
7800
7794 if date and rev is not None:
7801 if date and rev is not None:
7795 raise error.InputError(_(b"you can't specify a revision and a date"))
7802 raise error.InputError(_(b"you can't specify a revision and a date"))
7796
7803
7797 updatecheck = None
7804 updatecheck = None
7798 if check:
7805 if check:
7799 updatecheck = b'abort'
7806 updatecheck = b'abort'
7800 elif merge:
7807 elif merge:
7801 updatecheck = b'none'
7808 updatecheck = b'none'
7802
7809
7803 with repo.wlock():
7810 with repo.wlock():
7804 cmdutil.clearunfinished(repo)
7811 cmdutil.clearunfinished(repo)
7805 if date:
7812 if date:
7806 rev = cmdutil.finddate(ui, repo, date)
7813 rev = cmdutil.finddate(ui, repo, date)
7807
7814
7808 # if we defined a bookmark, we have to remember the original name
7815 # if we defined a bookmark, we have to remember the original name
7809 brev = rev
7816 brev = rev
7810 if rev:
7817 if rev:
7811 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7818 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7812 ctx = scmutil.revsingle(repo, rev, default=None)
7819 ctx = scmutil.revsingle(repo, rev, default=None)
7813 rev = ctx.rev()
7820 rev = ctx.rev()
7814 hidden = ctx.hidden()
7821 hidden = ctx.hidden()
7815 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7822 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7816 with ui.configoverride(overrides, b'update'):
7823 with ui.configoverride(overrides, b'update'):
7817 ret = hg.updatetotally(
7824 ret = hg.updatetotally(
7818 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7825 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7819 )
7826 )
7820 if hidden:
7827 if hidden:
7821 ctxstr = ctx.hex()[:12]
7828 ctxstr = ctx.hex()[:12]
7822 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7829 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7823
7830
7824 if ctx.obsolete():
7831 if ctx.obsolete():
7825 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7832 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7826 ui.warn(b"(%s)\n" % obsfatemsg)
7833 ui.warn(b"(%s)\n" % obsfatemsg)
7827 return ret
7834 return ret
7828
7835
7829
7836
7830 @command(
7837 @command(
7831 b'verify',
7838 b'verify',
7832 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7839 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7833 helpcategory=command.CATEGORY_MAINTENANCE,
7840 helpcategory=command.CATEGORY_MAINTENANCE,
7834 )
7841 )
7835 def verify(ui, repo, **opts):
7842 def verify(ui, repo, **opts):
7836 """verify the integrity of the repository
7843 """verify the integrity of the repository
7837
7844
7838 Verify the integrity of the current repository.
7845 Verify the integrity of the current repository.
7839
7846
7840 This will perform an extensive check of the repository's
7847 This will perform an extensive check of the repository's
7841 integrity, validating the hashes and checksums of each entry in
7848 integrity, validating the hashes and checksums of each entry in
7842 the changelog, manifest, and tracked files, as well as the
7849 the changelog, manifest, and tracked files, as well as the
7843 integrity of their crosslinks and indices.
7850 integrity of their crosslinks and indices.
7844
7851
7845 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7852 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7846 for more information about recovery from corruption of the
7853 for more information about recovery from corruption of the
7847 repository.
7854 repository.
7848
7855
7849 Returns 0 on success, 1 if errors are encountered.
7856 Returns 0 on success, 1 if errors are encountered.
7850 """
7857 """
7851 opts = pycompat.byteskwargs(opts)
7858 opts = pycompat.byteskwargs(opts)
7852
7859
7853 level = None
7860 level = None
7854 if opts[b'full']:
7861 if opts[b'full']:
7855 level = verifymod.VERIFY_FULL
7862 level = verifymod.VERIFY_FULL
7856 return hg.verify(repo, level)
7863 return hg.verify(repo, level)
7857
7864
7858
7865
7859 @command(
7866 @command(
7860 b'version',
7867 b'version',
7861 [] + formatteropts,
7868 [] + formatteropts,
7862 helpcategory=command.CATEGORY_HELP,
7869 helpcategory=command.CATEGORY_HELP,
7863 norepo=True,
7870 norepo=True,
7864 intents={INTENT_READONLY},
7871 intents={INTENT_READONLY},
7865 )
7872 )
7866 def version_(ui, **opts):
7873 def version_(ui, **opts):
7867 """output version and copyright information
7874 """output version and copyright information
7868
7875
7869 .. container:: verbose
7876 .. container:: verbose
7870
7877
7871 Template:
7878 Template:
7872
7879
7873 The following keywords are supported. See also :hg:`help templates`.
7880 The following keywords are supported. See also :hg:`help templates`.
7874
7881
7875 :extensions: List of extensions.
7882 :extensions: List of extensions.
7876 :ver: String. Version number.
7883 :ver: String. Version number.
7877
7884
7878 And each entry of ``{extensions}`` provides the following sub-keywords
7885 And each entry of ``{extensions}`` provides the following sub-keywords
7879 in addition to ``{ver}``.
7886 in addition to ``{ver}``.
7880
7887
7881 :bundled: Boolean. True if included in the release.
7888 :bundled: Boolean. True if included in the release.
7882 :name: String. Extension name.
7889 :name: String. Extension name.
7883 """
7890 """
7884 opts = pycompat.byteskwargs(opts)
7891 opts = pycompat.byteskwargs(opts)
7885 if ui.verbose:
7892 if ui.verbose:
7886 ui.pager(b'version')
7893 ui.pager(b'version')
7887 fm = ui.formatter(b"version", opts)
7894 fm = ui.formatter(b"version", opts)
7888 fm.startitem()
7895 fm.startitem()
7889 fm.write(
7896 fm.write(
7890 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7897 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7891 )
7898 )
7892 license = _(
7899 license = _(
7893 b"(see https://mercurial-scm.org for more information)\n"
7900 b"(see https://mercurial-scm.org for more information)\n"
7894 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7901 b"\nCopyright (C) 2005-2021 Olivia Mackall and others\n"
7895 b"This is free software; see the source for copying conditions. "
7902 b"This is free software; see the source for copying conditions. "
7896 b"There is NO\nwarranty; "
7903 b"There is NO\nwarranty; "
7897 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7904 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7898 )
7905 )
7899 if not ui.quiet:
7906 if not ui.quiet:
7900 fm.plain(license)
7907 fm.plain(license)
7901
7908
7902 if ui.verbose:
7909 if ui.verbose:
7903 fm.plain(_(b"\nEnabled extensions:\n\n"))
7910 fm.plain(_(b"\nEnabled extensions:\n\n"))
7904 # format names and versions into columns
7911 # format names and versions into columns
7905 names = []
7912 names = []
7906 vers = []
7913 vers = []
7907 isinternals = []
7914 isinternals = []
7908 for name, module in sorted(extensions.extensions()):
7915 for name, module in sorted(extensions.extensions()):
7909 names.append(name)
7916 names.append(name)
7910 vers.append(extensions.moduleversion(module) or None)
7917 vers.append(extensions.moduleversion(module) or None)
7911 isinternals.append(extensions.ismoduleinternal(module))
7918 isinternals.append(extensions.ismoduleinternal(module))
7912 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7919 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7913 if names:
7920 if names:
7914 namefmt = b" %%-%ds " % max(len(n) for n in names)
7921 namefmt = b" %%-%ds " % max(len(n) for n in names)
7915 places = [_(b"external"), _(b"internal")]
7922 places = [_(b"external"), _(b"internal")]
7916 for n, v, p in zip(names, vers, isinternals):
7923 for n, v, p in zip(names, vers, isinternals):
7917 fn.startitem()
7924 fn.startitem()
7918 fn.condwrite(ui.verbose, b"name", namefmt, n)
7925 fn.condwrite(ui.verbose, b"name", namefmt, n)
7919 if ui.verbose:
7926 if ui.verbose:
7920 fn.plain(b"%s " % places[p])
7927 fn.plain(b"%s " % places[p])
7921 fn.data(bundled=p)
7928 fn.data(bundled=p)
7922 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7929 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7923 if ui.verbose:
7930 if ui.verbose:
7924 fn.plain(b"\n")
7931 fn.plain(b"\n")
7925 fn.end()
7932 fn.end()
7926 fm.end()
7933 fm.end()
7927
7934
7928
7935
7929 def loadcmdtable(ui, name, cmdtable):
7936 def loadcmdtable(ui, name, cmdtable):
7930 """Load command functions from specified cmdtable"""
7937 """Load command functions from specified cmdtable"""
7931 overrides = [cmd for cmd in cmdtable if cmd in table]
7938 overrides = [cmd for cmd in cmdtable if cmd in table]
7932 if overrides:
7939 if overrides:
7933 ui.warn(
7940 ui.warn(
7934 _(b"extension '%s' overrides commands: %s\n")
7941 _(b"extension '%s' overrides commands: %s\n")
7935 % (name, b" ".join(overrides))
7942 % (name, b" ".join(overrides))
7936 )
7943 )
7937 table.update(cmdtable)
7944 table.update(cmdtable)
@@ -1,443 +1,443
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 abort
3 abort
4 add
4 add
5 addremove
5 addremove
6 annotate
6 annotate
7 archive
7 archive
8 backout
8 backout
9 bisect
9 bisect
10 bookmarks
10 bookmarks
11 branch
11 branch
12 branches
12 branches
13 bundle
13 bundle
14 cat
14 cat
15 clone
15 clone
16 commit
16 commit
17 config
17 config
18 continue
18 continue
19 copy
19 copy
20 diff
20 diff
21 export
21 export
22 files
22 files
23 forget
23 forget
24 graft
24 graft
25 grep
25 grep
26 heads
26 heads
27 help
27 help
28 identify
28 identify
29 import
29 import
30 incoming
30 incoming
31 init
31 init
32 locate
32 locate
33 log
33 log
34 manifest
34 manifest
35 merge
35 merge
36 outgoing
36 outgoing
37 parents
37 parents
38 paths
38 paths
39 phase
39 phase
40 pull
40 pull
41 purge
41 purge
42 push
42 push
43 recover
43 recover
44 remove
44 remove
45 rename
45 rename
46 resolve
46 resolve
47 revert
47 revert
48 rollback
48 rollback
49 root
49 root
50 serve
50 serve
51 shelve
51 shelve
52 status
52 status
53 summary
53 summary
54 tag
54 tag
55 tags
55 tags
56 tip
56 tip
57 unbundle
57 unbundle
58 unshelve
58 unshelve
59 update
59 update
60 verify
60 verify
61 version
61 version
62
62
63 Show all commands that start with "a"
63 Show all commands that start with "a"
64 $ hg debugcomplete a
64 $ hg debugcomplete a
65 abort
65 abort
66 add
66 add
67 addremove
67 addremove
68 annotate
68 annotate
69 archive
69 archive
70
70
71 Do not show debug commands if there are other candidates
71 Do not show debug commands if there are other candidates
72 $ hg debugcomplete d
72 $ hg debugcomplete d
73 diff
73 diff
74
74
75 Show debug commands if there are no other candidates
75 Show debug commands if there are no other candidates
76 $ hg debugcomplete debug
76 $ hg debugcomplete debug
77 debugancestor
77 debugancestor
78 debugantivirusrunning
78 debugantivirusrunning
79 debugapplystreamclonebundle
79 debugapplystreamclonebundle
80 debugbackupbundle
80 debugbackupbundle
81 debugbuilddag
81 debugbuilddag
82 debugbundle
82 debugbundle
83 debugcapabilities
83 debugcapabilities
84 debugchangedfiles
84 debugchangedfiles
85 debugcheckstate
85 debugcheckstate
86 debugcolor
86 debugcolor
87 debugcommands
87 debugcommands
88 debugcomplete
88 debugcomplete
89 debugconfig
89 debugconfig
90 debugcreatestreamclonebundle
90 debugcreatestreamclonebundle
91 debugdag
91 debugdag
92 debugdata
92 debugdata
93 debugdate
93 debugdate
94 debugdeltachain
94 debugdeltachain
95 debugdirstate
95 debugdirstate
96 debugdiscovery
96 debugdiscovery
97 debugdownload
97 debugdownload
98 debugextensions
98 debugextensions
99 debugfileset
99 debugfileset
100 debugformat
100 debugformat
101 debugfsinfo
101 debugfsinfo
102 debuggetbundle
102 debuggetbundle
103 debugignore
103 debugignore
104 debugindex
104 debugindex
105 debugindexdot
105 debugindexdot
106 debugindexstats
106 debugindexstats
107 debuginstall
107 debuginstall
108 debugknown
108 debugknown
109 debuglabelcomplete
109 debuglabelcomplete
110 debuglocks
110 debuglocks
111 debugmanifestfulltextcache
111 debugmanifestfulltextcache
112 debugmergestate
112 debugmergestate
113 debugnamecomplete
113 debugnamecomplete
114 debugnodemap
114 debugnodemap
115 debugobsolete
115 debugobsolete
116 debugp1copies
116 debugp1copies
117 debugp2copies
117 debugp2copies
118 debugpathcomplete
118 debugpathcomplete
119 debugpathcopies
119 debugpathcopies
120 debugpeer
120 debugpeer
121 debugpickmergetool
121 debugpickmergetool
122 debugpushkey
122 debugpushkey
123 debugpvec
123 debugpvec
124 debugrebuilddirstate
124 debugrebuilddirstate
125 debugrebuildfncache
125 debugrebuildfncache
126 debugrename
126 debugrename
127 debugrequires
127 debugrequires
128 debugrevlog
128 debugrevlog
129 debugrevlogindex
129 debugrevlogindex
130 debugrevspec
130 debugrevspec
131 debugserve
131 debugserve
132 debugsetparents
132 debugsetparents
133 debugshell
133 debugshell
134 debugsidedata
134 debugsidedata
135 debugssl
135 debugssl
136 debugstrip
136 debugstrip
137 debugsub
137 debugsub
138 debugsuccessorssets
138 debugsuccessorssets
139 debugtagscache
139 debugtagscache
140 debugtemplate
140 debugtemplate
141 debuguigetpass
141 debuguigetpass
142 debuguiprompt
142 debuguiprompt
143 debugupdatecaches
143 debugupdatecaches
144 debugupgraderepo
144 debugupgraderepo
145 debugwalk
145 debugwalk
146 debugwhyunstable
146 debugwhyunstable
147 debugwireargs
147 debugwireargs
148 debugwireproto
148 debugwireproto
149
149
150 Do not show the alias of a debug command if there are other candidates
150 Do not show the alias of a debug command if there are other candidates
151 (this should hide rawcommit)
151 (this should hide rawcommit)
152 $ hg debugcomplete r
152 $ hg debugcomplete r
153 recover
153 recover
154 remove
154 remove
155 rename
155 rename
156 resolve
156 resolve
157 revert
157 revert
158 rollback
158 rollback
159 root
159 root
160 Show the alias of a debug command if there are no other candidates
160 Show the alias of a debug command if there are no other candidates
161 $ hg debugcomplete rawc
161 $ hg debugcomplete rawc
162
162
163
163
164 Show the global options
164 Show the global options
165 $ hg debugcomplete --options | sort
165 $ hg debugcomplete --options | sort
166 --color
166 --color
167 --config
167 --config
168 --cwd
168 --cwd
169 --debug
169 --debug
170 --debugger
170 --debugger
171 --encoding
171 --encoding
172 --encodingmode
172 --encodingmode
173 --help
173 --help
174 --hidden
174 --hidden
175 --noninteractive
175 --noninteractive
176 --pager
176 --pager
177 --profile
177 --profile
178 --quiet
178 --quiet
179 --repository
179 --repository
180 --time
180 --time
181 --traceback
181 --traceback
182 --verbose
182 --verbose
183 --version
183 --version
184 -R
184 -R
185 -h
185 -h
186 -q
186 -q
187 -v
187 -v
188 -y
188 -y
189
189
190 Show the options for the "serve" command
190 Show the options for the "serve" command
191 $ hg debugcomplete --options serve | sort
191 $ hg debugcomplete --options serve | sort
192 --accesslog
192 --accesslog
193 --address
193 --address
194 --certificate
194 --certificate
195 --cmdserver
195 --cmdserver
196 --color
196 --color
197 --config
197 --config
198 --cwd
198 --cwd
199 --daemon
199 --daemon
200 --daemon-postexec
200 --daemon-postexec
201 --debug
201 --debug
202 --debugger
202 --debugger
203 --encoding
203 --encoding
204 --encodingmode
204 --encodingmode
205 --errorlog
205 --errorlog
206 --help
206 --help
207 --hidden
207 --hidden
208 --ipv6
208 --ipv6
209 --name
209 --name
210 --noninteractive
210 --noninteractive
211 --pager
211 --pager
212 --pid-file
212 --pid-file
213 --port
213 --port
214 --prefix
214 --prefix
215 --print-url
215 --print-url
216 --profile
216 --profile
217 --quiet
217 --quiet
218 --repository
218 --repository
219 --stdio
219 --stdio
220 --style
220 --style
221 --subrepos
221 --subrepos
222 --templates
222 --templates
223 --time
223 --time
224 --traceback
224 --traceback
225 --verbose
225 --verbose
226 --version
226 --version
227 --web-conf
227 --web-conf
228 -6
228 -6
229 -A
229 -A
230 -E
230 -E
231 -R
231 -R
232 -S
232 -S
233 -a
233 -a
234 -d
234 -d
235 -h
235 -h
236 -n
236 -n
237 -p
237 -p
238 -q
238 -q
239 -t
239 -t
240 -v
240 -v
241 -y
241 -y
242
242
243 Show an error if we use --options with an ambiguous abbreviation
243 Show an error if we use --options with an ambiguous abbreviation
244 $ hg debugcomplete --options s
244 $ hg debugcomplete --options s
245 hg: command 's' is ambiguous:
245 hg: command 's' is ambiguous:
246 serve shelve showconfig status summary
246 serve shelve showconfig status summary
247 [10]
247 [10]
248
248
249 Show all commands + options
249 Show all commands + options
250 $ hg debugcommands
250 $ hg debugcommands
251 abort: dry-run
251 abort: dry-run
252 add: include, exclude, subrepos, dry-run
252 add: include, exclude, subrepos, dry-run
253 addremove: similarity, subrepos, include, exclude, dry-run
253 addremove: similarity, subrepos, include, exclude, dry-run
254 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
254 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
255 archive: no-decode, prefix, rev, type, subrepos, include, exclude
255 archive: no-decode, prefix, rev, type, subrepos, include, exclude
256 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
256 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
257 bisect: reset, good, bad, skip, extend, command, noupdate
257 bisect: reset, good, bad, skip, extend, command, noupdate
258 bookmarks: force, rev, delete, rename, inactive, list, template
258 bookmarks: force, rev, delete, rename, inactive, list, template
259 branch: force, clean, rev
259 branch: force, clean, rev
260 branches: active, closed, rev, template
260 branches: active, closed, rev, template
261 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
261 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
262 cat: output, rev, decode, include, exclude, template
262 cat: output, rev, decode, include, exclude, template
263 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
263 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
264 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
264 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
265 config: untrusted, edit, local, shared, non-shared, global, template
265 config: untrusted, edit, local, shared, non-shared, global, template
266 continue: dry-run
266 continue: dry-run
267 copy: forget, after, at-rev, force, include, exclude, dry-run
267 copy: forget, after, at-rev, force, include, exclude, dry-run
268 debugancestor:
268 debugancestor:
269 debugantivirusrunning:
269 debugantivirusrunning:
270 debugapplystreamclonebundle:
270 debugapplystreamclonebundle:
271 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
271 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
272 debugbuilddag: mergeable-file, overwritten-file, new-file
272 debugbuilddag: mergeable-file, overwritten-file, new-file
273 debugbundle: all, part-type, spec
273 debugbundle: all, part-type, spec
274 debugcapabilities:
274 debugcapabilities:
275 debugchangedfiles: compute
275 debugchangedfiles: compute
276 debugcheckstate:
276 debugcheckstate:
277 debugcolor: style
277 debugcolor: style
278 debugcommands:
278 debugcommands:
279 debugcomplete: options
279 debugcomplete: options
280 debugcreatestreamclonebundle:
280 debugcreatestreamclonebundle:
281 debugdag: tags, branches, dots, spaces
281 debugdag: tags, branches, dots, spaces
282 debugdata: changelog, manifest, dir
282 debugdata: changelog, manifest, dir
283 debugdate: extended
283 debugdate: extended
284 debugdeltachain: changelog, manifest, dir, template
284 debugdeltachain: changelog, manifest, dir, template
285 debugdirstate: nodates, dates, datesort
285 debugdirstate: nodates, dates, datesort
286 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
286 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
287 debugdownload: output
287 debugdownload: output
288 debugextensions: template
288 debugextensions: template
289 debugfileset: rev, all-files, show-matcher, show-stage
289 debugfileset: rev, all-files, show-matcher, show-stage
290 debugformat: template
290 debugformat: template
291 debugfsinfo:
291 debugfsinfo:
292 debuggetbundle: head, common, type
292 debuggetbundle: head, common, type
293 debugignore:
293 debugignore:
294 debugindex: changelog, manifest, dir, template
294 debugindex: changelog, manifest, dir, template
295 debugindexdot: changelog, manifest, dir
295 debugindexdot: changelog, manifest, dir
296 debugindexstats:
296 debugindexstats:
297 debuginstall: template
297 debuginstall: template
298 debugknown:
298 debugknown:
299 debuglabelcomplete:
299 debuglabelcomplete:
300 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
300 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
301 debugmanifestfulltextcache: clear, add
301 debugmanifestfulltextcache: clear, add
302 debugmergestate: style, template
302 debugmergestate: style, template
303 debugnamecomplete:
303 debugnamecomplete:
304 debugnodemap: dump-new, dump-disk, check, metadata
304 debugnodemap: dump-new, dump-disk, check, metadata
305 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
305 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
306 debugp1copies: rev
306 debugp1copies: rev
307 debugp2copies: rev
307 debugp2copies: rev
308 debugpathcomplete: full, normal, added, removed
308 debugpathcomplete: full, normal, added, removed
309 debugpathcopies: include, exclude
309 debugpathcopies: include, exclude
310 debugpeer:
310 debugpeer:
311 debugpickmergetool: rev, changedelete, include, exclude, tool
311 debugpickmergetool: rev, changedelete, include, exclude, tool
312 debugpushkey:
312 debugpushkey:
313 debugpvec:
313 debugpvec:
314 debugrebuilddirstate: rev, minimal
314 debugrebuilddirstate: rev, minimal
315 debugrebuildfncache:
315 debugrebuildfncache:
316 debugrename: rev
316 debugrename: rev
317 debugrequires:
317 debugrequires:
318 debugrevlog: changelog, manifest, dir, dump
318 debugrevlog: changelog, manifest, dir, dump
319 debugrevlogindex: changelog, manifest, dir, format
319 debugrevlogindex: changelog, manifest, dir, format
320 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
320 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
321 debugserve: sshstdio, logiofd, logiofile
321 debugserve: sshstdio, logiofd, logiofile
322 debugsetparents:
322 debugsetparents:
323 debugshell:
323 debugshell:
324 debugsidedata: changelog, manifest, dir
324 debugsidedata: changelog, manifest, dir
325 debugssl:
325 debugssl:
326 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
326 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
327 debugsub: rev
327 debugsub: rev
328 debugsuccessorssets: closest
328 debugsuccessorssets: closest
329 debugtagscache:
329 debugtagscache:
330 debugtemplate: rev, define
330 debugtemplate: rev, define
331 debuguigetpass: prompt
331 debuguigetpass: prompt
332 debuguiprompt: prompt
332 debuguiprompt: prompt
333 debugupdatecaches:
333 debugupdatecaches:
334 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
334 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
335 debugwalk: include, exclude
335 debugwalk: include, exclude
336 debugwhyunstable:
336 debugwhyunstable:
337 debugwireargs: three, four, five, ssh, remotecmd, insecure
337 debugwireargs: three, four, five, ssh, remotecmd, insecure
338 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
338 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
339 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
339 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
340 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
340 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
341 files: rev, print0, include, exclude, template, subrepos
341 files: rev, print0, include, exclude, template, subrepos
342 forget: interactive, include, exclude, dry-run
342 forget: interactive, include, exclude, dry-run
343 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
343 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
344 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
344 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
345 heads: rev, topo, active, closed, style, template
345 heads: rev, topo, active, closed, style, template
346 help: extension, command, keyword, system
346 help: extension, command, keyword, system
347 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
347 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
348 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
348 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
349 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
349 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
350 init: ssh, remotecmd, insecure
350 init: ssh, remotecmd, insecure
351 locate: rev, print0, fullpath, include, exclude
351 locate: rev, print0, fullpath, include, exclude
352 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
352 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
353 manifest: rev, all, template
353 manifest: rev, all, template
354 merge: force, rev, preview, abort, tool
354 merge: force, rev, preview, abort, tool
355 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
355 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
356 parents: rev, style, template
356 parents: rev, style, template
357 paths: template
357 paths: template
358 phase: public, draft, secret, force, rev
358 phase: public, draft, secret, force, rev
359 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
359 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
360 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
360 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
361 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
361 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
362 recover: verify
362 recover: verify
363 remove: after, force, subrepos, include, exclude, dry-run
363 remove: after, force, subrepos, include, exclude, dry-run
364 rename: after, at-rev, force, include, exclude, dry-run
364 rename: forget, after, at-rev, force, include, exclude, dry-run
365 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
365 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
366 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
366 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
367 rollback: dry-run, force
367 rollback: dry-run, force
368 root: template
368 root: template
369 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
369 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
370 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
370 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
371 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
371 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
372 summary: remote
372 summary: remote
373 tag: force, local, rev, remove, edit, message, date, user
373 tag: force, local, rev, remove, edit, message, date, user
374 tags: template
374 tags: template
375 tip: patch, git, style, template
375 tip: patch, git, style, template
376 unbundle: update
376 unbundle: update
377 unshelve: abort, continue, interactive, keep, name, tool, date
377 unshelve: abort, continue, interactive, keep, name, tool, date
378 update: clean, check, merge, date, rev, tool
378 update: clean, check, merge, date, rev, tool
379 verify: full
379 verify: full
380 version: template
380 version: template
381
381
382 $ hg init a
382 $ hg init a
383 $ cd a
383 $ cd a
384 $ echo fee > fee
384 $ echo fee > fee
385 $ hg ci -q -Amfee
385 $ hg ci -q -Amfee
386 $ hg tag fee
386 $ hg tag fee
387 $ mkdir fie
387 $ mkdir fie
388 $ echo dead > fie/dead
388 $ echo dead > fie/dead
389 $ echo live > fie/live
389 $ echo live > fie/live
390 $ hg bookmark fo
390 $ hg bookmark fo
391 $ hg branch -q fie
391 $ hg branch -q fie
392 $ hg ci -q -Amfie
392 $ hg ci -q -Amfie
393 $ echo fo > fo
393 $ echo fo > fo
394 $ hg branch -qf default
394 $ hg branch -qf default
395 $ hg ci -q -Amfo
395 $ hg ci -q -Amfo
396 $ echo Fum > Fum
396 $ echo Fum > Fum
397 $ hg ci -q -AmFum
397 $ hg ci -q -AmFum
398 $ hg bookmark Fum
398 $ hg bookmark Fum
399
399
400 Test debugpathcomplete
400 Test debugpathcomplete
401
401
402 $ hg debugpathcomplete f
402 $ hg debugpathcomplete f
403 fee
403 fee
404 fie
404 fie
405 fo
405 fo
406 $ hg debugpathcomplete -f f
406 $ hg debugpathcomplete -f f
407 fee
407 fee
408 fie/dead
408 fie/dead
409 fie/live
409 fie/live
410 fo
410 fo
411
411
412 $ hg rm Fum
412 $ hg rm Fum
413 $ hg debugpathcomplete -r F
413 $ hg debugpathcomplete -r F
414 Fum
414 Fum
415
415
416 Test debugnamecomplete
416 Test debugnamecomplete
417
417
418 $ hg debugnamecomplete
418 $ hg debugnamecomplete
419 Fum
419 Fum
420 default
420 default
421 fee
421 fee
422 fie
422 fie
423 fo
423 fo
424 tip
424 tip
425 $ hg debugnamecomplete f
425 $ hg debugnamecomplete f
426 fee
426 fee
427 fie
427 fie
428 fo
428 fo
429
429
430 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
430 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
431 used for completions in some shells.
431 used for completions in some shells.
432
432
433 $ hg debuglabelcomplete
433 $ hg debuglabelcomplete
434 Fum
434 Fum
435 default
435 default
436 fee
436 fee
437 fie
437 fie
438 fo
438 fo
439 tip
439 tip
440 $ hg debuglabelcomplete f
440 $ hg debuglabelcomplete f
441 fee
441 fee
442 fie
442 fie
443 fo
443 fo
@@ -1,385 +1,412
1 $ mkdir part1
1 $ mkdir part1
2 $ cd part1
2 $ cd part1
3
3
4 $ hg init
4 $ hg init
5 $ echo a > a
5 $ echo a > a
6 $ hg add a
6 $ hg add a
7 $ hg commit -m "1"
7 $ hg commit -m "1"
8 $ hg status
8 $ hg status
9 $ hg copy a b
9 $ hg copy a b
10 $ hg --config ui.portablefilenames=abort copy a con.xml
10 $ hg --config ui.portablefilenames=abort copy a con.xml
11 abort: filename contains 'con', which is reserved on Windows: con.xml
11 abort: filename contains 'con', which is reserved on Windows: con.xml
12 [10]
12 [10]
13 $ hg status
13 $ hg status
14 A b
14 A b
15 $ hg sum
15 $ hg sum
16 parent: 0:c19d34741b0a tip
16 parent: 0:c19d34741b0a tip
17 1
17 1
18 branch: default
18 branch: default
19 commit: 1 copied
19 commit: 1 copied
20 update: (current)
20 update: (current)
21 phases: 1 draft
21 phases: 1 draft
22 $ hg --debug commit -m "2"
22 $ hg --debug commit -m "2"
23 committing files:
23 committing files:
24 b
24 b
25 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
25 b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
26 committing manifest
26 committing manifest
27 committing changelog
27 committing changelog
28 updating the branch cache
28 updating the branch cache
29 committed changeset 1:93580a2c28a50a56f63526fb305067e6fbf739c4
29 committed changeset 1:93580a2c28a50a56f63526fb305067e6fbf739c4
30
30
31 we should see two history entries
31 we should see two history entries
32
32
33 $ hg history -v
33 $ hg history -v
34 changeset: 1:93580a2c28a5
34 changeset: 1:93580a2c28a5
35 tag: tip
35 tag: tip
36 user: test
36 user: test
37 date: Thu Jan 01 00:00:00 1970 +0000
37 date: Thu Jan 01 00:00:00 1970 +0000
38 files: b
38 files: b
39 description:
39 description:
40 2
40 2
41
41
42
42
43 changeset: 0:c19d34741b0a
43 changeset: 0:c19d34741b0a
44 user: test
44 user: test
45 date: Thu Jan 01 00:00:00 1970 +0000
45 date: Thu Jan 01 00:00:00 1970 +0000
46 files: a
46 files: a
47 description:
47 description:
48 1
48 1
49
49
50
50
51
51
52 we should see one log entry for a
52 we should see one log entry for a
53
53
54 $ hg log a
54 $ hg log a
55 changeset: 0:c19d34741b0a
55 changeset: 0:c19d34741b0a
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
57 date: Thu Jan 01 00:00:00 1970 +0000
58 summary: 1
58 summary: 1
59
59
60
60
61 this should show a revision linked to changeset 0
61 this should show a revision linked to changeset 0
62
62
63 $ hg debugindex a
63 $ hg debugindex a
64 rev linkrev nodeid p1 p2
64 rev linkrev nodeid p1 p2
65 0 0 b789fdd96dc2 000000000000 000000000000
65 0 0 b789fdd96dc2 000000000000 000000000000
66
66
67 we should see one log entry for b
67 we should see one log entry for b
68
68
69 $ hg log b
69 $ hg log b
70 changeset: 1:93580a2c28a5
70 changeset: 1:93580a2c28a5
71 tag: tip
71 tag: tip
72 user: test
72 user: test
73 date: Thu Jan 01 00:00:00 1970 +0000
73 date: Thu Jan 01 00:00:00 1970 +0000
74 summary: 2
74 summary: 2
75
75
76
76
77 this should show a revision linked to changeset 1
77 this should show a revision linked to changeset 1
78
78
79 $ hg debugindex b
79 $ hg debugindex b
80 rev linkrev nodeid p1 p2
80 rev linkrev nodeid p1 p2
81 0 1 37d9b5d994ea 000000000000 000000000000
81 0 1 37d9b5d994ea 000000000000 000000000000
82
82
83 this should show the rename information in the metadata
83 this should show the rename information in the metadata
84
84
85 $ hg debugdata b 0 | head -3 | tail -2
85 $ hg debugdata b 0 | head -3 | tail -2
86 copy: a
86 copy: a
87 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
87 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
88
88
89 #if reporevlogstore
89 #if reporevlogstore
90 $ md5sum.py .hg/store/data/b.i
90 $ md5sum.py .hg/store/data/b.i
91 44913824c8f5890ae218f9829535922e .hg/store/data/b.i
91 44913824c8f5890ae218f9829535922e .hg/store/data/b.i
92 #endif
92 #endif
93 $ hg cat b > bsum
93 $ hg cat b > bsum
94 $ md5sum.py bsum
94 $ md5sum.py bsum
95 60b725f10c9c85c70d97880dfe8191b3 bsum
95 60b725f10c9c85c70d97880dfe8191b3 bsum
96 $ hg cat a > asum
96 $ hg cat a > asum
97 $ md5sum.py asum
97 $ md5sum.py asum
98 60b725f10c9c85c70d97880dfe8191b3 asum
98 60b725f10c9c85c70d97880dfe8191b3 asum
99 $ hg verify
99 $ hg verify
100 checking changesets
100 checking changesets
101 checking manifests
101 checking manifests
102 crosschecking files in changesets and manifests
102 crosschecking files in changesets and manifests
103 checking files
103 checking files
104 checked 2 changesets with 2 changes to 2 files
104 checked 2 changesets with 2 changes to 2 files
105
105
106 $ cd ..
106 $ cd ..
107
107
108
108
109 $ mkdir part2
109 $ mkdir part2
110 $ cd part2
110 $ cd part2
111
111
112 $ hg init
112 $ hg init
113 $ echo foo > foo
113 $ echo foo > foo
114 should fail - foo is not managed
114 should fail - foo is not managed
115 $ hg mv foo bar
115 $ hg mv foo bar
116 foo: not copying - file is not managed
116 foo: not copying - file is not managed
117 abort: no files to copy
117 abort: no files to copy
118 [10]
118 [10]
119 $ hg st -A
119 $ hg st -A
120 ? foo
120 ? foo
121 respects ui.relative-paths
121 respects ui.relative-paths
122 $ mkdir dir
122 $ mkdir dir
123 $ cd dir
123 $ cd dir
124 $ hg mv ../foo ../bar
124 $ hg mv ../foo ../bar
125 ../foo: not copying - file is not managed
125 ../foo: not copying - file is not managed
126 abort: no files to copy
126 abort: no files to copy
127 [10]
127 [10]
128 $ hg mv ../foo ../bar --config ui.relative-paths=yes
128 $ hg mv ../foo ../bar --config ui.relative-paths=yes
129 ../foo: not copying - file is not managed
129 ../foo: not copying - file is not managed
130 abort: no files to copy
130 abort: no files to copy
131 [10]
131 [10]
132 $ hg mv ../foo ../bar --config ui.relative-paths=no
132 $ hg mv ../foo ../bar --config ui.relative-paths=no
133 foo: not copying - file is not managed
133 foo: not copying - file is not managed
134 abort: no files to copy
134 abort: no files to copy
135 [10]
135 [10]
136 $ cd ..
136 $ cd ..
137 $ rmdir dir
137 $ rmdir dir
138 $ hg add foo
138 $ hg add foo
139 dry-run; print a warning that this is not a real copy; foo is added
139 dry-run; print a warning that this is not a real copy; foo is added
140 $ hg mv --dry-run foo bar
140 $ hg mv --dry-run foo bar
141 foo has not been committed yet, so no copy data will be stored for bar.
141 foo has not been committed yet, so no copy data will be stored for bar.
142 $ hg st -A
142 $ hg st -A
143 A foo
143 A foo
144 should print a warning that this is not a real copy; bar is added
144 should print a warning that this is not a real copy; bar is added
145 $ hg mv foo bar
145 $ hg mv foo bar
146 foo has not been committed yet, so no copy data will be stored for bar.
146 foo has not been committed yet, so no copy data will be stored for bar.
147 $ hg st -A
147 $ hg st -A
148 A bar
148 A bar
149 should print a warning that this is not a real copy; foo is added
149 should print a warning that this is not a real copy; foo is added
150 $ hg cp bar foo
150 $ hg cp bar foo
151 bar has not been committed yet, so no copy data will be stored for foo.
151 bar has not been committed yet, so no copy data will be stored for foo.
152 $ hg rm -f bar
152 $ hg rm -f bar
153 $ rm bar
153 $ rm bar
154 $ hg st -A
154 $ hg st -A
155 A foo
155 A foo
156 $ hg commit -m1
156 $ hg commit -m1
157
157
158 moving a missing file
158 moving a missing file
159 $ rm foo
159 $ rm foo
160 $ hg mv foo foo3
160 $ hg mv foo foo3
161 foo: deleted in working directory
161 foo: deleted in working directory
162 foo3 does not exist!
162 foo3 does not exist!
163 $ hg up -qC .
163 $ hg up -qC .
164
164
165 copy --after to a nonexistent target filename
165 copy --after to a nonexistent target filename
166 $ hg cp -A foo dummy
166 $ hg cp -A foo dummy
167 foo: not recording copy - dummy does not exist
167 foo: not recording copy - dummy does not exist
168 [1]
168 [1]
169
169
170 dry-run; should show that foo is clean
170 dry-run; should show that foo is clean
171 $ hg copy --dry-run foo bar
171 $ hg copy --dry-run foo bar
172 $ hg st -A
172 $ hg st -A
173 C foo
173 C foo
174 should show copy
174 should show copy
175 $ hg copy foo bar
175 $ hg copy foo bar
176 $ hg st -C
176 $ hg st -C
177 A bar
177 A bar
178 foo
178 foo
179
179
180 shouldn't show copy
180 shouldn't show copy
181 $ hg commit -m2
181 $ hg commit -m2
182 $ hg st -C
182 $ hg st -C
183
183
184 should match
184 should match
185 $ hg debugindex foo
185 $ hg debugindex foo
186 rev linkrev nodeid p1 p2
186 rev linkrev nodeid p1 p2
187 0 0 2ed2a3912a0b 000000000000 000000000000
187 0 0 2ed2a3912a0b 000000000000 000000000000
188 $ hg debugrename bar
188 $ hg debugrename bar
189 bar renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
189 bar renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
190
190
191 $ echo bleah > foo
191 $ echo bleah > foo
192 $ echo quux > bar
192 $ echo quux > bar
193 $ hg commit -m3
193 $ hg commit -m3
194
194
195 should not be renamed
195 should not be renamed
196 $ hg debugrename bar
196 $ hg debugrename bar
197 bar not renamed
197 bar not renamed
198
198
199 $ hg copy -f foo bar
199 $ hg copy -f foo bar
200 should show copy
200 should show copy
201 $ hg st -C
201 $ hg st -C
202 M bar
202 M bar
203 foo
203 foo
204
204
205 XXX: filtering lfilesrepo.status() in 3.3-rc causes the copy source to not be
205 XXX: filtering lfilesrepo.status() in 3.3-rc causes the copy source to not be
206 displayed.
206 displayed.
207 $ hg st -C --config extensions.largefiles=
207 $ hg st -C --config extensions.largefiles=
208 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
208 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
209 M bar
209 M bar
210 foo
210 foo
211
211
212 $ hg commit -m3
212 $ hg commit -m3
213
213
214 should show no parents for tip
214 should show no parents for tip
215 $ hg debugindex bar
215 $ hg debugindex bar
216 rev linkrev nodeid p1 p2
216 rev linkrev nodeid p1 p2
217 0 1 7711d36246cc 000000000000 000000000000
217 0 1 7711d36246cc 000000000000 000000000000
218 1 2 bdf70a2b8d03 7711d36246cc 000000000000
218 1 2 bdf70a2b8d03 7711d36246cc 000000000000
219 2 3 b2558327ea8d 000000000000 000000000000
219 2 3 b2558327ea8d 000000000000 000000000000
220 should match
220 should match
221 $ hg debugindex foo
221 $ hg debugindex foo
222 rev linkrev nodeid p1 p2
222 rev linkrev nodeid p1 p2
223 0 0 2ed2a3912a0b 000000000000 000000000000
223 0 0 2ed2a3912a0b 000000000000 000000000000
224 1 2 dd12c926cf16 2ed2a3912a0b 000000000000
224 1 2 dd12c926cf16 2ed2a3912a0b 000000000000
225 $ hg debugrename bar
225 $ hg debugrename bar
226 bar renamed from foo:dd12c926cf165e3eb4cf87b084955cb617221c17
226 bar renamed from foo:dd12c926cf165e3eb4cf87b084955cb617221c17
227
227
228 should show no copies
228 should show no copies
229 $ hg st -C
229 $ hg st -C
230
230
231 note: since filelog based copy tracing only trace copy for new file, the copy information here is not displayed.
231 note: since filelog based copy tracing only trace copy for new file, the copy information here is not displayed.
232
232
233 $ hg status --copies --change .
233 $ hg status --copies --change .
234 M bar
234 M bar
235
235
236 They are a devel option to walk all file and fine this information anyway.
236 They are a devel option to walk all file and fine this information anyway.
237
237
238 $ hg status --copies --change . --config devel.copy-tracing.trace-all-files=yes
238 $ hg status --copies --change . --config devel.copy-tracing.trace-all-files=yes
239 M bar
239 M bar
240 foo
240 foo
241
241
242 copy --after on an added file
242 copy --after on an added file
243 $ cp bar baz
243 $ cp bar baz
244 $ hg add baz
244 $ hg add baz
245 $ hg cp -A bar baz
245 $ hg cp -A bar baz
246 $ hg st -C
246 $ hg st -C
247 A baz
247 A baz
248 bar
248 bar
249
249
250 foo was clean:
250 foo was clean:
251 $ hg st -AC foo
251 $ hg st -AC foo
252 C foo
252 C foo
253 Trying to copy on top of an existing file fails,
253 Trying to copy on top of an existing file fails,
254 $ hg copy -A bar foo
254 $ hg copy -A bar foo
255 foo: not overwriting - file already committed
255 foo: not overwriting - file already committed
256 ('hg copy --after --force' to replace the file by recording a copy)
256 ('hg copy --after --force' to replace the file by recording a copy)
257 [1]
257 [1]
258 same error without the --after, so the user doesn't have to go through
258 same error without the --after, so the user doesn't have to go through
259 two hints:
259 two hints:
260 $ hg copy bar foo
260 $ hg copy bar foo
261 foo: not overwriting - file already committed
261 foo: not overwriting - file already committed
262 ('hg copy --force' to replace the file by recording a copy)
262 ('hg copy --force' to replace the file by recording a copy)
263 [1]
263 [1]
264 but it's considered modified after a copy --after --force
264 but it's considered modified after a copy --after --force
265 $ hg copy -Af bar foo
265 $ hg copy -Af bar foo
266 $ hg st -AC foo
266 $ hg st -AC foo
267 M foo
267 M foo
268 bar
268 bar
269 The hint for a file that exists but is not in file history doesn't
269 The hint for a file that exists but is not in file history doesn't
270 mention --force:
270 mention --force:
271 $ touch xyzzy
271 $ touch xyzzy
272 $ hg cp bar xyzzy
272 $ hg cp bar xyzzy
273 xyzzy: not overwriting - file exists
273 xyzzy: not overwriting - file exists
274 ('hg copy --after' to record the copy)
274 ('hg copy --after' to record the copy)
275 [1]
275 [1]
276 $ hg co -qC .
276 $ hg co -qC .
277 $ rm baz xyzzy
277 $ rm baz xyzzy
278
278
279
279
280 Test unmarking copy of a single file
280 Test unmarking copy/rename of a single file
281
281
282 # Set up by creating a copy
282 # Set up by creating a copy
283 $ hg cp bar baz
283 $ hg cp bar baz
284 # Test uncopying a non-existent file
284 # Test unmarking as copy a non-existent file
285 $ hg copy --forget non-existent
285 $ hg copy --forget non-existent
286 non-existent: $ENOENT$
286 non-existent: $ENOENT$
287 # Test uncopying an tracked but unrelated file
287 $ hg rename --forget non-existent
288 non-existent: $ENOENT$
289 # Test unmarking as copy an tracked but unrelated file
288 $ hg copy --forget foo
290 $ hg copy --forget foo
289 foo: not unmarking as copy - file is not marked as copied
291 foo: not unmarking as copy - file is not marked as copied
290 # Test uncopying a copy source
292 $ hg rename --forget foo
293 foo: not unmarking as copy - file is not marked as copied
294 # Test unmarking as copy a copy source
291 $ hg copy --forget bar
295 $ hg copy --forget bar
292 bar: not unmarking as copy - file is not marked as copied
296 bar: not unmarking as copy - file is not marked as copied
297 $ hg rename --forget bar
298 bar: not unmarking as copy - file is not marked as copied
293 # baz should still be marked as a copy
299 # baz should still be marked as a copy
294 $ hg st -C
300 $ hg st -C
295 A baz
301 A baz
296 bar
302 bar
297 # Test the normal case
303 # Test the normal case
298 $ hg copy --forget baz
304 $ hg copy --forget baz
299 $ hg st -C
305 $ hg st -C
300 A baz
306 A baz
301 # Test uncopy with matching an non-matching patterns
307 $ rm bar
308 $ hg rename --after bar baz
309 $ hg st -C
310 A baz
311 bar
312 R bar
313 $ hg rename --forget baz
314 $ hg st -C
315 A baz
316 R bar
317 $ hg revert bar
318 # Test unmarking as copy with matching an non-matching patterns
302 $ hg cp bar baz --after
319 $ hg cp bar baz --after
303 $ hg copy --forget bar baz
320 $ hg copy --forget bar baz
304 bar: not unmarking as copy - file is not marked as copied
321 bar: not unmarking as copy - file is not marked as copied
322 $ hg cp bar baz --after
323 $ hg rename --forget bar baz
324 bar: not unmarking as copy - file is not marked as copied
305 $ hg st -C
325 $ hg st -C
306 A baz
326 A baz
307 # Test uncopy with no exact matches
327 # Test unmarking as copy with no exact matches
308 $ hg cp bar baz --after
328 $ hg cp bar baz --after
309 $ hg copy --forget .
329 $ hg copy --forget .
310 $ hg st -C
330 $ hg st -C
311 A baz
331 A baz
332 $ hg cp bar baz --after
333 $ hg st -C
334 A baz
335 bar
336 $ hg rename --forget .
337 $ hg st -C
338 A baz
312 $ hg forget baz
339 $ hg forget baz
313 $ rm baz
340 $ rm baz
314
341
315 Test unmarking copy of a directory
342 Test unmarking copy of a directory
316
343
317 $ mkdir dir
344 $ mkdir dir
318 $ echo foo > dir/foo
345 $ echo foo > dir/foo
319 $ echo bar > dir/bar
346 $ echo bar > dir/bar
320 $ hg add dir
347 $ hg add dir
321 adding dir/bar
348 adding dir/bar
322 adding dir/foo
349 adding dir/foo
323 $ hg ci -m 'add dir/'
350 $ hg ci -m 'add dir/'
324 $ hg cp dir dir2
351 $ hg cp dir dir2
325 copying dir/bar to dir2/bar
352 copying dir/bar to dir2/bar
326 copying dir/foo to dir2/foo
353 copying dir/foo to dir2/foo
327 $ touch dir2/untracked
354 $ touch dir2/untracked
328 $ hg copy --forget dir2
355 $ hg copy --forget dir2
329 $ hg st -C
356 $ hg st -C
330 A dir2/bar
357 A dir2/bar
331 A dir2/foo
358 A dir2/foo
332 ? dir2/untracked
359 ? dir2/untracked
333 # Clean up for next test
360 # Clean up for next test
334 $ hg forget dir2
361 $ hg forget dir2
335 removing dir2/bar
362 removing dir2/bar
336 removing dir2/foo
363 removing dir2/foo
337 $ rm -r dir2
364 $ rm -r dir2
338
365
339 Test uncopy on committed copies
366 Test uncopy on committed copies
340
367
341 # Commit some copies
368 # Commit some copies
342 $ hg cp bar baz
369 $ hg cp bar baz
343 $ hg cp bar qux
370 $ hg cp bar qux
344 $ hg ci -m copies
371 $ hg ci -m copies
345 $ hg st -C --change .
372 $ hg st -C --change .
346 A baz
373 A baz
347 bar
374 bar
348 A qux
375 A qux
349 bar
376 bar
350 $ base=$(hg log -r '.^' -T '{rev}')
377 $ base=$(hg log -r '.^' -T '{rev}')
351 $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
378 $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
352 @ 5:a612dc2edfda copies
379 @ 5:a612dc2edfda copies
353 |
380 |
354 o 4:4800b1f1f38e add dir/
381 o 4:4800b1f1f38e add dir/
355 |
382 |
356 ~
383 ~
357 # Add a dirty change on top to show that it's unaffected
384 # Add a dirty change on top to show that it's unaffected
358 $ echo dirty >> baz
385 $ echo dirty >> baz
359 $ hg st
386 $ hg st
360 M baz
387 M baz
361 $ cat baz
388 $ cat baz
362 bleah
389 bleah
363 dirty
390 dirty
364 $ hg copy --forget --at-rev . baz
391 $ hg copy --forget --at-rev . baz
365 saved backup bundle to $TESTTMP/part2/.hg/strip-backup/a612dc2edfda-e36b4448-uncopy.hg
392 saved backup bundle to $TESTTMP/part2/.hg/strip-backup/a612dc2edfda-e36b4448-uncopy.hg
366 # The unwanted copy is no longer recorded, but the unrelated one is
393 # The unwanted copy is no longer recorded, but the unrelated one is
367 $ hg st -C --change .
394 $ hg st -C --change .
368 A baz
395 A baz
369 A qux
396 A qux
370 bar
397 bar
371 # The old commit is gone and we have updated to the new commit
398 # The old commit is gone and we have updated to the new commit
372 $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
399 $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
373 @ 5:c45090e5effe copies
400 @ 5:c45090e5effe copies
374 |
401 |
375 o 4:4800b1f1f38e add dir/
402 o 4:4800b1f1f38e add dir/
376 |
403 |
377 ~
404 ~
378 # Working copy still has the uncommitted change
405 # Working copy still has the uncommitted change
379 $ hg st
406 $ hg st
380 M baz
407 M baz
381 $ cat baz
408 $ cat baz
382 bleah
409 bleah
383 dirty
410 dirty
384
411
385 $ cd ..
412 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now