##// END OF EJS Templates
commit: allow to close branch when committing change over a closed head...
marmoute -
r50215:3d3d7fc6 stable
parent child Browse files
Show More
@@ -1,7952 +1,7959 b''
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 nullrev,
18 nullrev,
19 short,
19 short,
20 wdirrev,
20 wdirrev,
21 )
21 )
22 from .pycompat import open
22 from .pycompat import open
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 bundlecaches,
27 bundlecaches,
28 changegroup,
28 changegroup,
29 cmdutil,
29 cmdutil,
30 copies,
30 copies,
31 debugcommands as debugcommandsmod,
31 debugcommands as debugcommandsmod,
32 destutil,
32 destutil,
33 dirstateguard,
33 dirstateguard,
34 discovery,
34 discovery,
35 encoding,
35 encoding,
36 error,
36 error,
37 exchange,
37 exchange,
38 extensions,
38 extensions,
39 filemerge,
39 filemerge,
40 formatter,
40 formatter,
41 graphmod,
41 graphmod,
42 grep as grepmod,
42 grep as grepmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 mergestate as mergestatemod,
48 mergestate as mergestatemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 requirements,
57 requirements,
58 revsetlang,
58 revsetlang,
59 rewriteutil,
59 rewriteutil,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 shelve as shelvemod,
62 shelve as shelvemod,
63 state as statemod,
63 state as statemod,
64 streamclone,
64 streamclone,
65 tags as tagsmod,
65 tags as tagsmod,
66 ui as uimod,
66 ui as uimod,
67 util,
67 util,
68 verify as verifymod,
68 verify as verifymod,
69 vfs as vfsmod,
69 vfs as vfsmod,
70 wireprotoserver,
70 wireprotoserver,
71 )
71 )
72 from .utils import (
72 from .utils import (
73 dateutil,
73 dateutil,
74 stringutil,
74 stringutil,
75 urlutil,
75 urlutil,
76 )
76 )
77
77
78 table = {}
78 table = {}
79 table.update(debugcommandsmod.command._table)
79 table.update(debugcommandsmod.command._table)
80
80
81 command = registrar.command(table)
81 command = registrar.command(table)
82 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
83
83
84 # common command options
84 # common command options
85
85
86 globalopts = [
86 globalopts = [
87 (
87 (
88 b'R',
88 b'R',
89 b'repository',
89 b'repository',
90 b'',
90 b'',
91 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
92 _(b'REPO'),
92 _(b'REPO'),
93 ),
93 ),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (
95 (
96 b'y',
96 b'y',
97 b'noninteractive',
97 b'noninteractive',
98 None,
98 None,
99 _(
99 _(
100 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
101 ),
101 ),
102 ),
102 ),
103 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
105 (
105 (
106 b'',
106 b'',
107 b'color',
107 b'color',
108 b'',
108 b'',
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # and should not be translated
110 # and should not be translated
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b'TYPE'),
112 _(b'TYPE'),
113 ),
113 ),
114 (
114 (
115 b'',
115 b'',
116 b'config',
116 b'config',
117 [],
117 [],
118 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'CONFIG'),
119 _(b'CONFIG'),
120 ),
120 ),
121 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
123 (
123 (
124 b'',
124 b'',
125 b'encoding',
125 b'encoding',
126 encoding.encoding,
126 encoding.encoding,
127 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
128 _(b'ENCODE'),
128 _(b'ENCODE'),
129 ),
129 ),
130 (
130 (
131 b'',
131 b'',
132 b'encodingmode',
132 b'encodingmode',
133 encoding.encodingmode,
133 encoding.encodingmode,
134 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
135 _(b'MODE'),
135 _(b'MODE'),
136 ),
136 ),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (
143 (
144 b'',
144 b'',
145 b'pager',
145 b'pager',
146 b'auto',
146 b'auto',
147 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b'TYPE'),
148 _(b'TYPE'),
149 ),
149 ),
150 ]
150 ]
151
151
152 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
153 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
154 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
155 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
156 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
157 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
158 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
159 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
160 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
161 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
162 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
163 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
164 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
165 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
166 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
167 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
168
168
169 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
170
170
171
171
172 @command(
172 @command(
173 b'abort',
173 b'abort',
174 dryrunopts,
174 dryrunopts,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpbasic=True,
176 helpbasic=True,
177 )
177 )
178 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
179 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
180
180
181 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
182 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
183
183
184 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
185 """
185 """
186 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
187 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
188 if not abortstate:
188 if not abortstate:
189 raise error.StateError(_(b'no operation in progress'))
189 raise error.StateError(_(b'no operation in progress'))
190 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
191 raise error.InputError(
191 raise error.InputError(
192 (
192 (
193 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
194 % (abortstate._opname)
194 % (abortstate._opname)
195 ),
195 ),
196 hint=abortstate.hint(),
196 hint=abortstate.hint(),
197 )
197 )
198 if dryrun:
198 if dryrun:
199 ui.status(
199 ui.status(
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 )
201 )
202 return
202 return
203 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
204
204
205
205
206 @command(
206 @command(
207 b'add',
207 b'add',
208 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
209 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpbasic=True,
211 helpbasic=True,
212 inferrepo=True,
212 inferrepo=True,
213 )
213 )
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 return rejected and 1 or 0
260 return rejected and 1 or 0
261
261
262
262
263 @command(
263 @command(
264 b'addremove',
264 b'addremove',
265 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
266 _(b'[OPTION]... [FILE]...'),
266 _(b'[OPTION]... [FILE]...'),
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 inferrepo=True,
268 inferrepo=True,
269 )
269 )
270 def addremove(ui, repo, *pats, **opts):
270 def addremove(ui, repo, *pats, **opts):
271 """add all new files, delete all missing files
271 """add all new files, delete all missing files
272
272
273 Add all new files and remove all missing files from the
273 Add all new files and remove all missing files from the
274 repository.
274 repository.
275
275
276 Unless names are given, new files are ignored if they match any of
276 Unless names are given, new files are ignored if they match any of
277 the patterns in ``.hgignore``. As with add, these changes take
277 the patterns in ``.hgignore``. As with add, these changes take
278 effect at the next commit.
278 effect at the next commit.
279
279
280 Use the -s/--similarity option to detect renamed files. This
280 Use the -s/--similarity option to detect renamed files. This
281 option takes a percentage between 0 (disabled) and 100 (files must
281 option takes a percentage between 0 (disabled) and 100 (files must
282 be identical) as its parameter. With a parameter greater than 0,
282 be identical) as its parameter. With a parameter greater than 0,
283 this compares every removed file with every added file and records
283 this compares every removed file with every added file and records
284 those similar enough as renames. Detecting renamed files this way
284 those similar enough as renames. Detecting renamed files this way
285 can be expensive. After using this option, :hg:`status -C` can be
285 can be expensive. After using this option, :hg:`status -C` can be
286 used to check which files were identified as moved or renamed. If
286 used to check which files were identified as moved or renamed. If
287 not specified, -s/--similarity defaults to 100 and only renames of
287 not specified, -s/--similarity defaults to 100 and only renames of
288 identical files are detected.
288 identical files are detected.
289
289
290 .. container:: verbose
290 .. container:: verbose
291
291
292 Examples:
292 Examples:
293
293
294 - A number of files (bar.c and foo.c) are new,
294 - A number of files (bar.c and foo.c) are new,
295 while foobar.c has been removed (without using :hg:`remove`)
295 while foobar.c has been removed (without using :hg:`remove`)
296 from the repository::
296 from the repository::
297
297
298 $ ls
298 $ ls
299 bar.c foo.c
299 bar.c foo.c
300 $ hg status
300 $ hg status
301 ! foobar.c
301 ! foobar.c
302 ? bar.c
302 ? bar.c
303 ? foo.c
303 ? foo.c
304 $ hg addremove
304 $ hg addremove
305 adding bar.c
305 adding bar.c
306 adding foo.c
306 adding foo.c
307 removing foobar.c
307 removing foobar.c
308 $ hg status
308 $ hg status
309 A bar.c
309 A bar.c
310 A foo.c
310 A foo.c
311 R foobar.c
311 R foobar.c
312
312
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 Afterwards, it was edited slightly::
314 Afterwards, it was edited slightly::
315
315
316 $ ls
316 $ ls
317 foo.c
317 foo.c
318 $ hg status
318 $ hg status
319 ! foobar.c
319 ! foobar.c
320 ? foo.c
320 ? foo.c
321 $ hg addremove --similarity 90
321 $ hg addremove --similarity 90
322 removing foobar.c
322 removing foobar.c
323 adding foo.c
323 adding foo.c
324 recording removal of foobar.c as rename to foo.c (94% similar)
324 recording removal of foobar.c as rename to foo.c (94% similar)
325 $ hg status -C
325 $ hg status -C
326 A foo.c
326 A foo.c
327 foobar.c
327 foobar.c
328 R foobar.c
328 R foobar.c
329
329
330 Returns 0 if all files are successfully added.
330 Returns 0 if all files are successfully added.
331 """
331 """
332 opts = pycompat.byteskwargs(opts)
332 opts = pycompat.byteskwargs(opts)
333 if not opts.get(b'similarity'):
333 if not opts.get(b'similarity'):
334 opts[b'similarity'] = b'100'
334 opts[b'similarity'] = b'100'
335 matcher = scmutil.match(repo[None], pats, opts)
335 matcher = scmutil.match(repo[None], pats, opts)
336 relative = scmutil.anypats(pats, opts)
336 relative = scmutil.anypats(pats, opts)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339
339
340
340
341 @command(
341 @command(
342 b'annotate|blame',
342 b'annotate|blame',
343 [
343 [
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (
345 (
346 b'',
346 b'',
347 b'follow',
347 b'follow',
348 None,
348 None,
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 ),
350 ),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'a', b'text', None, _(b'treat all files as text')),
352 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'f', b'file', None, _(b'list the filename')),
354 (b'f', b'file', None, _(b'list the filename')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
358 (
358 (
359 b'l',
359 b'l',
360 b'line-number',
360 b'line-number',
361 None,
361 None,
362 _(b'show line number at the first appearance'),
362 _(b'show line number at the first appearance'),
363 ),
363 ),
364 (
364 (
365 b'',
365 b'',
366 b'skip',
366 b'skip',
367 [],
367 [],
368 _(b'revset to not display (EXPERIMENTAL)'),
368 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'REV'),
369 _(b'REV'),
370 ),
370 ),
371 ]
371 ]
372 + diffwsopts
372 + diffwsopts
373 + walkopts
373 + walkopts
374 + formatteropts,
374 + formatteropts,
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpbasic=True,
377 helpbasic=True,
378 inferrepo=True,
378 inferrepo=True,
379 )
379 )
380 def annotate(ui, repo, *pats, **opts):
380 def annotate(ui, repo, *pats, **opts):
381 """show changeset information by line for each file
381 """show changeset information by line for each file
382
382
383 List changes in files, showing the revision id responsible for
383 List changes in files, showing the revision id responsible for
384 each line.
384 each line.
385
385
386 This command is useful for discovering when a change was made and
386 This command is useful for discovering when a change was made and
387 by whom.
387 by whom.
388
388
389 If you include --file, --user, or --date, the revision number is
389 If you include --file, --user, or --date, the revision number is
390 suppressed unless you also include --number.
390 suppressed unless you also include --number.
391
391
392 Without the -a/--text option, annotate will avoid processing files
392 Without the -a/--text option, annotate will avoid processing files
393 it detects as binary. With -a, annotate will annotate the file
393 it detects as binary. With -a, annotate will annotate the file
394 anyway, although the results will probably be neither useful
394 anyway, although the results will probably be neither useful
395 nor desirable.
395 nor desirable.
396
396
397 .. container:: verbose
397 .. container:: verbose
398
398
399 Template:
399 Template:
400
400
401 The following keywords are supported in addition to the common template
401 The following keywords are supported in addition to the common template
402 keywords and functions. See also :hg:`help templates`.
402 keywords and functions. See also :hg:`help templates`.
403
403
404 :lines: List of lines with annotation data.
404 :lines: List of lines with annotation data.
405 :path: String. Repository-absolute path of the specified file.
405 :path: String. Repository-absolute path of the specified file.
406
406
407 And each entry of ``{lines}`` provides the following sub-keywords in
407 And each entry of ``{lines}`` provides the following sub-keywords in
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409
409
410 :line: String. Line content.
410 :line: String. Line content.
411 :lineno: Integer. Line number at that revision.
411 :lineno: Integer. Line number at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
413
413
414 See :hg:`help templates.operators` for the list expansion syntax.
414 See :hg:`help templates.operators` for the list expansion syntax.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 """
417 """
418 opts = pycompat.byteskwargs(opts)
418 opts = pycompat.byteskwargs(opts)
419 if not pats:
419 if not pats:
420 raise error.InputError(
420 raise error.InputError(
421 _(b'at least one filename or pattern is required')
421 _(b'at least one filename or pattern is required')
422 )
422 )
423
423
424 if opts.get(b'follow'):
424 if opts.get(b'follow'):
425 # --follow is deprecated and now just an alias for -f/--file
425 # --follow is deprecated and now just an alias for -f/--file
426 # to mimic the behavior of Mercurial before version 1.5
426 # to mimic the behavior of Mercurial before version 1.5
427 opts[b'file'] = True
427 opts[b'file'] = True
428
428
429 if (
429 if (
430 not opts.get(b'user')
430 not opts.get(b'user')
431 and not opts.get(b'changeset')
431 and not opts.get(b'changeset')
432 and not opts.get(b'date')
432 and not opts.get(b'date')
433 and not opts.get(b'file')
433 and not opts.get(b'file')
434 ):
434 ):
435 opts[b'number'] = True
435 opts[b'number'] = True
436
436
437 linenumber = opts.get(b'line_number') is not None
437 linenumber = opts.get(b'line_number') is not None
438 if (
438 if (
439 linenumber
439 linenumber
440 and (not opts.get(b'changeset'))
440 and (not opts.get(b'changeset'))
441 and (not opts.get(b'number'))
441 and (not opts.get(b'number'))
442 ):
442 ):
443 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
443 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
444
444
445 rev = opts.get(b'rev')
445 rev = opts.get(b'rev')
446 if rev:
446 if rev:
447 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
448 ctx = logcmdutil.revsingle(repo, rev)
448 ctx = logcmdutil.revsingle(repo, rev)
449
449
450 ui.pager(b'annotate')
450 ui.pager(b'annotate')
451 rootfm = ui.formatter(b'annotate', opts)
451 rootfm = ui.formatter(b'annotate', opts)
452 if ui.debugflag:
452 if ui.debugflag:
453 shorthex = pycompat.identity
453 shorthex = pycompat.identity
454 else:
454 else:
455
455
456 def shorthex(h):
456 def shorthex(h):
457 return h[:12]
457 return h[:12]
458
458
459 if ui.quiet:
459 if ui.quiet:
460 datefunc = dateutil.shortdate
460 datefunc = dateutil.shortdate
461 else:
461 else:
462 datefunc = dateutil.datestr
462 datefunc = dateutil.datestr
463 if ctx.rev() is None:
463 if ctx.rev() is None:
464 if opts.get(b'changeset'):
464 if opts.get(b'changeset'):
465 # omit "+" suffix which is appended to node hex
465 # omit "+" suffix which is appended to node hex
466 def formatrev(rev):
466 def formatrev(rev):
467 if rev == wdirrev:
467 if rev == wdirrev:
468 return b'%d' % ctx.p1().rev()
468 return b'%d' % ctx.p1().rev()
469 else:
469 else:
470 return b'%d' % rev
470 return b'%d' % rev
471
471
472 else:
472 else:
473
473
474 def formatrev(rev):
474 def formatrev(rev):
475 if rev == wdirrev:
475 if rev == wdirrev:
476 return b'%d+' % ctx.p1().rev()
476 return b'%d+' % ctx.p1().rev()
477 else:
477 else:
478 return b'%d ' % rev
478 return b'%d ' % rev
479
479
480 def formathex(h):
480 def formathex(h):
481 if h == repo.nodeconstants.wdirhex:
481 if h == repo.nodeconstants.wdirhex:
482 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 return b'%s+' % shorthex(hex(ctx.p1().node()))
483 else:
483 else:
484 return b'%s ' % shorthex(h)
484 return b'%s ' % shorthex(h)
485
485
486 else:
486 else:
487 formatrev = b'%d'.__mod__
487 formatrev = b'%d'.__mod__
488 formathex = shorthex
488 formathex = shorthex
489
489
490 opmap = [
490 opmap = [
491 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
492 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
493 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
494 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
495 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
496 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
497 ]
497 ]
498 opnamemap = {
498 opnamemap = {
499 b'rev': b'number',
499 b'rev': b'number',
500 b'node': b'changeset',
500 b'node': b'changeset',
501 b'path': b'file',
501 b'path': b'file',
502 b'lineno': b'line_number',
502 b'lineno': b'line_number',
503 }
503 }
504
504
505 if rootfm.isplain():
505 if rootfm.isplain():
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return lambda x: fmt(get(x))
508 return lambda x: fmt(get(x))
509
509
510 else:
510 else:
511
511
512 def makefunc(get, fmt):
512 def makefunc(get, fmt):
513 return get
513 return get
514
514
515 datahint = rootfm.datahint()
515 datahint = rootfm.datahint()
516 funcmap = [
516 funcmap = [
517 (makefunc(get, fmt), sep)
517 (makefunc(get, fmt), sep)
518 for fn, sep, get, fmt in opmap
518 for fn, sep, get, fmt in opmap
519 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 ]
520 ]
521 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
522 fields = b' '.join(
522 fields = b' '.join(
523 fn
523 fn
524 for fn, sep, get, fmt in opmap
524 for fn, sep, get, fmt in opmap
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 )
526 )
527
527
528 def bad(x, y):
528 def bad(x, y):
529 raise error.InputError(b"%s: %s" % (x, y))
529 raise error.InputError(b"%s: %s" % (x, y))
530
530
531 m = scmutil.match(ctx, pats, opts, badfn=bad)
531 m = scmutil.match(ctx, pats, opts, badfn=bad)
532
532
533 follow = not opts.get(b'no_follow')
533 follow = not opts.get(b'no_follow')
534 diffopts = patch.difffeatureopts(
534 diffopts = patch.difffeatureopts(
535 ui, opts, section=b'annotate', whitespace=True
535 ui, opts, section=b'annotate', whitespace=True
536 )
536 )
537 skiprevs = opts.get(b'skip')
537 skiprevs = opts.get(b'skip')
538 if skiprevs:
538 if skiprevs:
539 skiprevs = logcmdutil.revrange(repo, skiprevs)
539 skiprevs = logcmdutil.revrange(repo, skiprevs)
540
540
541 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
542 for abs in ctx.walk(m):
542 for abs in ctx.walk(m):
543 fctx = ctx[abs]
543 fctx = ctx[abs]
544 rootfm.startitem()
544 rootfm.startitem()
545 rootfm.data(path=abs)
545 rootfm.data(path=abs)
546 if not opts.get(b'text') and fctx.isbinary():
546 if not opts.get(b'text') and fctx.isbinary():
547 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
548 continue
548 continue
549
549
550 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
551 lines = fctx.annotate(
551 lines = fctx.annotate(
552 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 follow=follow, skiprevs=skiprevs, diffopts=diffopts
553 )
553 )
554 if not lines:
554 if not lines:
555 fm.end()
555 fm.end()
556 continue
556 continue
557 formats = []
557 formats = []
558 pieces = []
558 pieces = []
559
559
560 for f, sep in funcmap:
560 for f, sep in funcmap:
561 l = [f(n) for n in lines]
561 l = [f(n) for n in lines]
562 if fm.isplain():
562 if fm.isplain():
563 sizes = [encoding.colwidth(x) for x in l]
563 sizes = [encoding.colwidth(x) for x in l]
564 ml = max(sizes)
564 ml = max(sizes)
565 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
566 else:
566 else:
567 formats.append([b'%s'] * len(l))
567 formats.append([b'%s'] * len(l))
568 pieces.append(l)
568 pieces.append(l)
569
569
570 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
571 fm.startitem()
571 fm.startitem()
572 fm.context(fctx=n.fctx)
572 fm.context(fctx=n.fctx)
573 fm.write(fields, b"".join(f), *p)
573 fm.write(fields, b"".join(f), *p)
574 if n.skip:
574 if n.skip:
575 fmt = b"* %s"
575 fmt = b"* %s"
576 else:
576 else:
577 fmt = b": %s"
577 fmt = b": %s"
578 fm.write(b'line', fmt, n.text)
578 fm.write(b'line', fmt, n.text)
579
579
580 if not lines[-1].text.endswith(b'\n'):
580 if not lines[-1].text.endswith(b'\n'):
581 fm.plain(b'\n')
581 fm.plain(b'\n')
582 fm.end()
582 fm.end()
583
583
584 rootfm.end()
584 rootfm.end()
585
585
586
586
587 @command(
587 @command(
588 b'archive',
588 b'archive',
589 [
589 [
590 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
591 (
591 (
592 b'p',
592 b'p',
593 b'prefix',
593 b'prefix',
594 b'',
594 b'',
595 _(b'directory prefix for files in archive'),
595 _(b'directory prefix for files in archive'),
596 _(b'PREFIX'),
596 _(b'PREFIX'),
597 ),
597 ),
598 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
598 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
599 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
599 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
600 ]
600 ]
601 + subrepoopts
601 + subrepoopts
602 + walkopts,
602 + walkopts,
603 _(b'[OPTION]... DEST'),
603 _(b'[OPTION]... DEST'),
604 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 helpcategory=command.CATEGORY_IMPORT_EXPORT,
605 )
605 )
606 def archive(ui, repo, dest, **opts):
606 def archive(ui, repo, dest, **opts):
607 """create an unversioned archive of a repository revision
607 """create an unversioned archive of a repository revision
608
608
609 By default, the revision used is the parent of the working
609 By default, the revision used is the parent of the working
610 directory; use -r/--rev to specify a different revision.
610 directory; use -r/--rev to specify a different revision.
611
611
612 The archive type is automatically detected based on file
612 The archive type is automatically detected based on file
613 extension (to override, use -t/--type).
613 extension (to override, use -t/--type).
614
614
615 .. container:: verbose
615 .. container:: verbose
616
616
617 Examples:
617 Examples:
618
618
619 - create a zip file containing the 1.0 release::
619 - create a zip file containing the 1.0 release::
620
620
621 hg archive -r 1.0 project-1.0.zip
621 hg archive -r 1.0 project-1.0.zip
622
622
623 - create a tarball excluding .hg files::
623 - create a tarball excluding .hg files::
624
624
625 hg archive project.tar.gz -X ".hg*"
625 hg archive project.tar.gz -X ".hg*"
626
626
627 Valid types are:
627 Valid types are:
628
628
629 :``files``: a directory full of files (default)
629 :``files``: a directory full of files (default)
630 :``tar``: tar archive, uncompressed
630 :``tar``: tar archive, uncompressed
631 :``tbz2``: tar archive, compressed using bzip2
631 :``tbz2``: tar archive, compressed using bzip2
632 :``tgz``: tar archive, compressed using gzip
632 :``tgz``: tar archive, compressed using gzip
633 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``txz``: tar archive, compressed using lzma (only in Python 3)
634 :``uzip``: zip archive, uncompressed
634 :``uzip``: zip archive, uncompressed
635 :``zip``: zip archive, compressed using deflate
635 :``zip``: zip archive, compressed using deflate
636
636
637 The exact name of the destination archive or directory is given
637 The exact name of the destination archive or directory is given
638 using a format string; see :hg:`help export` for details.
638 using a format string; see :hg:`help export` for details.
639
639
640 Each member added to an archive file has a directory prefix
640 Each member added to an archive file has a directory prefix
641 prepended. Use -p/--prefix to specify a format string for the
641 prepended. Use -p/--prefix to specify a format string for the
642 prefix. The default is the basename of the archive, with suffixes
642 prefix. The default is the basename of the archive, with suffixes
643 removed.
643 removed.
644
644
645 Returns 0 on success.
645 Returns 0 on success.
646 """
646 """
647
647
648 opts = pycompat.byteskwargs(opts)
648 opts = pycompat.byteskwargs(opts)
649 rev = opts.get(b'rev')
649 rev = opts.get(b'rev')
650 if rev:
650 if rev:
651 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
652 ctx = logcmdutil.revsingle(repo, rev)
652 ctx = logcmdutil.revsingle(repo, rev)
653 if not ctx:
653 if not ctx:
654 raise error.InputError(
654 raise error.InputError(
655 _(b'no working directory: please specify a revision')
655 _(b'no working directory: please specify a revision')
656 )
656 )
657 node = ctx.node()
657 node = ctx.node()
658 dest = cmdutil.makefilename(ctx, dest)
658 dest = cmdutil.makefilename(ctx, dest)
659 if os.path.realpath(dest) == repo.root:
659 if os.path.realpath(dest) == repo.root:
660 raise error.InputError(_(b'repository root cannot be destination'))
660 raise error.InputError(_(b'repository root cannot be destination'))
661
661
662 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
662 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
663 prefix = opts.get(b'prefix')
663 prefix = opts.get(b'prefix')
664
664
665 if dest == b'-':
665 if dest == b'-':
666 if kind == b'files':
666 if kind == b'files':
667 raise error.InputError(_(b'cannot archive plain files to stdout'))
667 raise error.InputError(_(b'cannot archive plain files to stdout'))
668 dest = cmdutil.makefileobj(ctx, dest)
668 dest = cmdutil.makefileobj(ctx, dest)
669 if not prefix:
669 if not prefix:
670 prefix = os.path.basename(repo.root) + b'-%h'
670 prefix = os.path.basename(repo.root) + b'-%h'
671
671
672 prefix = cmdutil.makefilename(ctx, prefix)
672 prefix = cmdutil.makefilename(ctx, prefix)
673 match = scmutil.match(ctx, [], opts)
673 match = scmutil.match(ctx, [], opts)
674 archival.archive(
674 archival.archive(
675 repo,
675 repo,
676 dest,
676 dest,
677 node,
677 node,
678 kind,
678 kind,
679 not opts.get(b'no_decode'),
679 not opts.get(b'no_decode'),
680 match,
680 match,
681 prefix,
681 prefix,
682 subrepos=opts.get(b'subrepos'),
682 subrepos=opts.get(b'subrepos'),
683 )
683 )
684
684
685
685
686 @command(
686 @command(
687 b'backout',
687 b'backout',
688 [
688 [
689 (
689 (
690 b'',
690 b'',
691 b'merge',
691 b'merge',
692 None,
692 None,
693 _(b'merge with old dirstate parent after backout'),
693 _(b'merge with old dirstate parent after backout'),
694 ),
694 ),
695 (
695 (
696 b'',
696 b'',
697 b'commit',
697 b'commit',
698 None,
698 None,
699 _(b'commit if no conflicts were encountered (DEPRECATED)'),
699 _(b'commit if no conflicts were encountered (DEPRECATED)'),
700 ),
700 ),
701 (b'', b'no-commit', None, _(b'do not commit')),
701 (b'', b'no-commit', None, _(b'do not commit')),
702 (
702 (
703 b'',
703 b'',
704 b'parent',
704 b'parent',
705 b'',
705 b'',
706 _(b'parent to choose when backing out merge (DEPRECATED)'),
706 _(b'parent to choose when backing out merge (DEPRECATED)'),
707 _(b'REV'),
707 _(b'REV'),
708 ),
708 ),
709 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
709 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
710 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
710 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
711 ]
711 ]
712 + mergetoolopts
712 + mergetoolopts
713 + walkopts
713 + walkopts
714 + commitopts
714 + commitopts
715 + commitopts2,
715 + commitopts2,
716 _(b'[OPTION]... [-r] REV'),
716 _(b'[OPTION]... [-r] REV'),
717 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
717 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
718 )
718 )
719 def backout(ui, repo, node=None, rev=None, **opts):
719 def backout(ui, repo, node=None, rev=None, **opts):
720 """reverse effect of earlier changeset
720 """reverse effect of earlier changeset
721
721
722 Prepare a new changeset with the effect of REV undone in the
722 Prepare a new changeset with the effect of REV undone in the
723 current working directory. If no conflicts were encountered,
723 current working directory. If no conflicts were encountered,
724 it will be committed immediately.
724 it will be committed immediately.
725
725
726 If REV is the parent of the working directory, then this new changeset
726 If REV is the parent of the working directory, then this new changeset
727 is committed automatically (unless --no-commit is specified).
727 is committed automatically (unless --no-commit is specified).
728
728
729 .. note::
729 .. note::
730
730
731 :hg:`backout` cannot be used to fix either an unwanted or
731 :hg:`backout` cannot be used to fix either an unwanted or
732 incorrect merge.
732 incorrect merge.
733
733
734 .. container:: verbose
734 .. container:: verbose
735
735
736 Examples:
736 Examples:
737
737
738 - Reverse the effect of the parent of the working directory.
738 - Reverse the effect of the parent of the working directory.
739 This backout will be committed immediately::
739 This backout will be committed immediately::
740
740
741 hg backout -r .
741 hg backout -r .
742
742
743 - Reverse the effect of previous bad revision 23::
743 - Reverse the effect of previous bad revision 23::
744
744
745 hg backout -r 23
745 hg backout -r 23
746
746
747 - Reverse the effect of previous bad revision 23 and
747 - Reverse the effect of previous bad revision 23 and
748 leave changes uncommitted::
748 leave changes uncommitted::
749
749
750 hg backout -r 23 --no-commit
750 hg backout -r 23 --no-commit
751 hg commit -m "Backout revision 23"
751 hg commit -m "Backout revision 23"
752
752
753 By default, the pending changeset will have one parent,
753 By default, the pending changeset will have one parent,
754 maintaining a linear history. With --merge, the pending
754 maintaining a linear history. With --merge, the pending
755 changeset will instead have two parents: the old parent of the
755 changeset will instead have two parents: the old parent of the
756 working directory and a new child of REV that simply undoes REV.
756 working directory and a new child of REV that simply undoes REV.
757
757
758 Before version 1.7, the behavior without --merge was equivalent
758 Before version 1.7, the behavior without --merge was equivalent
759 to specifying --merge followed by :hg:`update --clean .` to
759 to specifying --merge followed by :hg:`update --clean .` to
760 cancel the merge and leave the child of REV as a head to be
760 cancel the merge and leave the child of REV as a head to be
761 merged separately.
761 merged separately.
762
762
763 See :hg:`help dates` for a list of formats valid for -d/--date.
763 See :hg:`help dates` for a list of formats valid for -d/--date.
764
764
765 See :hg:`help revert` for a way to restore files to the state
765 See :hg:`help revert` for a way to restore files to the state
766 of another revision.
766 of another revision.
767
767
768 Returns 0 on success, 1 if nothing to backout or there are unresolved
768 Returns 0 on success, 1 if nothing to backout or there are unresolved
769 files.
769 files.
770 """
770 """
771 with repo.wlock(), repo.lock():
771 with repo.wlock(), repo.lock():
772 return _dobackout(ui, repo, node, rev, **opts)
772 return _dobackout(ui, repo, node, rev, **opts)
773
773
774
774
775 def _dobackout(ui, repo, node=None, rev=None, **opts):
775 def _dobackout(ui, repo, node=None, rev=None, **opts):
776 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
776 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
777 opts = pycompat.byteskwargs(opts)
777 opts = pycompat.byteskwargs(opts)
778
778
779 if rev and node:
779 if rev and node:
780 raise error.InputError(_(b"please specify just one revision"))
780 raise error.InputError(_(b"please specify just one revision"))
781
781
782 if not rev:
782 if not rev:
783 rev = node
783 rev = node
784
784
785 if not rev:
785 if not rev:
786 raise error.InputError(_(b"please specify a revision to backout"))
786 raise error.InputError(_(b"please specify a revision to backout"))
787
787
788 date = opts.get(b'date')
788 date = opts.get(b'date')
789 if date:
789 if date:
790 opts[b'date'] = dateutil.parsedate(date)
790 opts[b'date'] = dateutil.parsedate(date)
791
791
792 cmdutil.checkunfinished(repo)
792 cmdutil.checkunfinished(repo)
793 cmdutil.bailifchanged(repo)
793 cmdutil.bailifchanged(repo)
794 ctx = logcmdutil.revsingle(repo, rev)
794 ctx = logcmdutil.revsingle(repo, rev)
795 node = ctx.node()
795 node = ctx.node()
796
796
797 op1, op2 = repo.dirstate.parents()
797 op1, op2 = repo.dirstate.parents()
798 if not repo.changelog.isancestor(node, op1):
798 if not repo.changelog.isancestor(node, op1):
799 raise error.InputError(
799 raise error.InputError(
800 _(b'cannot backout change that is not an ancestor')
800 _(b'cannot backout change that is not an ancestor')
801 )
801 )
802
802
803 p1, p2 = repo.changelog.parents(node)
803 p1, p2 = repo.changelog.parents(node)
804 if p1 == repo.nullid:
804 if p1 == repo.nullid:
805 raise error.InputError(_(b'cannot backout a change with no parents'))
805 raise error.InputError(_(b'cannot backout a change with no parents'))
806 if p2 != repo.nullid:
806 if p2 != repo.nullid:
807 if not opts.get(b'parent'):
807 if not opts.get(b'parent'):
808 raise error.InputError(_(b'cannot backout a merge changeset'))
808 raise error.InputError(_(b'cannot backout a merge changeset'))
809 p = repo.lookup(opts[b'parent'])
809 p = repo.lookup(opts[b'parent'])
810 if p not in (p1, p2):
810 if p not in (p1, p2):
811 raise error.InputError(
811 raise error.InputError(
812 _(b'%s is not a parent of %s') % (short(p), short(node))
812 _(b'%s is not a parent of %s') % (short(p), short(node))
813 )
813 )
814 parent = p
814 parent = p
815 else:
815 else:
816 if opts.get(b'parent'):
816 if opts.get(b'parent'):
817 raise error.InputError(
817 raise error.InputError(
818 _(b'cannot use --parent on non-merge changeset')
818 _(b'cannot use --parent on non-merge changeset')
819 )
819 )
820 parent = p1
820 parent = p1
821
821
822 # the backout should appear on the same branch
822 # the backout should appear on the same branch
823 branch = repo.dirstate.branch()
823 branch = repo.dirstate.branch()
824 bheads = repo.branchheads(branch)
824 bheads = repo.branchheads(branch)
825 rctx = scmutil.revsingle(repo, hex(parent))
825 rctx = scmutil.revsingle(repo, hex(parent))
826 if not opts.get(b'merge') and op1 != node:
826 if not opts.get(b'merge') and op1 != node:
827 with dirstateguard.dirstateguard(repo, b'backout'):
827 with dirstateguard.dirstateguard(repo, b'backout'):
828 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
828 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
829 with ui.configoverride(overrides, b'backout'):
829 with ui.configoverride(overrides, b'backout'):
830 stats = mergemod.back_out(ctx, parent=repo[parent])
830 stats = mergemod.back_out(ctx, parent=repo[parent])
831 repo.setparents(op1, op2)
831 repo.setparents(op1, op2)
832 hg._showstats(repo, stats)
832 hg._showstats(repo, stats)
833 if stats.unresolvedcount:
833 if stats.unresolvedcount:
834 repo.ui.status(
834 repo.ui.status(
835 _(b"use 'hg resolve' to retry unresolved file merges\n")
835 _(b"use 'hg resolve' to retry unresolved file merges\n")
836 )
836 )
837 return 1
837 return 1
838 else:
838 else:
839 hg.clean(repo, node, show_stats=False)
839 hg.clean(repo, node, show_stats=False)
840 repo.dirstate.setbranch(branch)
840 repo.dirstate.setbranch(branch)
841 cmdutil.revert(ui, repo, rctx)
841 cmdutil.revert(ui, repo, rctx)
842
842
843 if opts.get(b'no_commit'):
843 if opts.get(b'no_commit'):
844 msg = _(b"changeset %s backed out, don't forget to commit.\n")
844 msg = _(b"changeset %s backed out, don't forget to commit.\n")
845 ui.status(msg % short(node))
845 ui.status(msg % short(node))
846 return 0
846 return 0
847
847
848 def commitfunc(ui, repo, message, match, opts):
848 def commitfunc(ui, repo, message, match, opts):
849 editform = b'backout'
849 editform = b'backout'
850 e = cmdutil.getcommiteditor(
850 e = cmdutil.getcommiteditor(
851 editform=editform, **pycompat.strkwargs(opts)
851 editform=editform, **pycompat.strkwargs(opts)
852 )
852 )
853 if not message:
853 if not message:
854 # we don't translate commit messages
854 # we don't translate commit messages
855 message = b"Backed out changeset %s" % short(node)
855 message = b"Backed out changeset %s" % short(node)
856 e = cmdutil.getcommiteditor(edit=True, editform=editform)
856 e = cmdutil.getcommiteditor(edit=True, editform=editform)
857 return repo.commit(
857 return repo.commit(
858 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
858 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
859 )
859 )
860
860
861 # save to detect changes
861 # save to detect changes
862 tip = repo.changelog.tip()
862 tip = repo.changelog.tip()
863
863
864 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
864 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
865 if not newnode:
865 if not newnode:
866 ui.status(_(b"nothing changed\n"))
866 ui.status(_(b"nothing changed\n"))
867 return 1
867 return 1
868 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
868 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
869
869
870 def nice(node):
870 def nice(node):
871 return b'%d:%s' % (repo.changelog.rev(node), short(node))
871 return b'%d:%s' % (repo.changelog.rev(node), short(node))
872
872
873 ui.status(
873 ui.status(
874 _(b'changeset %s backs out changeset %s\n')
874 _(b'changeset %s backs out changeset %s\n')
875 % (nice(newnode), nice(node))
875 % (nice(newnode), nice(node))
876 )
876 )
877 if opts.get(b'merge') and op1 != node:
877 if opts.get(b'merge') and op1 != node:
878 hg.clean(repo, op1, show_stats=False)
878 hg.clean(repo, op1, show_stats=False)
879 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
879 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
880 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
880 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
881 with ui.configoverride(overrides, b'backout'):
881 with ui.configoverride(overrides, b'backout'):
882 return hg.merge(repo[b'tip'])
882 return hg.merge(repo[b'tip'])
883 return 0
883 return 0
884
884
885
885
886 @command(
886 @command(
887 b'bisect',
887 b'bisect',
888 [
888 [
889 (b'r', b'reset', False, _(b'reset bisect state')),
889 (b'r', b'reset', False, _(b'reset bisect state')),
890 (b'g', b'good', False, _(b'mark changeset good')),
890 (b'g', b'good', False, _(b'mark changeset good')),
891 (b'b', b'bad', False, _(b'mark changeset bad')),
891 (b'b', b'bad', False, _(b'mark changeset bad')),
892 (b's', b'skip', False, _(b'skip testing changeset')),
892 (b's', b'skip', False, _(b'skip testing changeset')),
893 (b'e', b'extend', False, _(b'extend the bisect range')),
893 (b'e', b'extend', False, _(b'extend the bisect range')),
894 (
894 (
895 b'c',
895 b'c',
896 b'command',
896 b'command',
897 b'',
897 b'',
898 _(b'use command to check changeset state'),
898 _(b'use command to check changeset state'),
899 _(b'CMD'),
899 _(b'CMD'),
900 ),
900 ),
901 (b'U', b'noupdate', False, _(b'do not update to target')),
901 (b'U', b'noupdate', False, _(b'do not update to target')),
902 ],
902 ],
903 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
903 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
904 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
904 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
905 )
905 )
906 def bisect(
906 def bisect(
907 ui,
907 ui,
908 repo,
908 repo,
909 positional_1=None,
909 positional_1=None,
910 positional_2=None,
910 positional_2=None,
911 command=None,
911 command=None,
912 reset=None,
912 reset=None,
913 good=None,
913 good=None,
914 bad=None,
914 bad=None,
915 skip=None,
915 skip=None,
916 extend=None,
916 extend=None,
917 noupdate=None,
917 noupdate=None,
918 ):
918 ):
919 """subdivision search of changesets
919 """subdivision search of changesets
920
920
921 This command helps to find changesets which introduce problems. To
921 This command helps to find changesets which introduce problems. To
922 use, mark the earliest changeset you know exhibits the problem as
922 use, mark the earliest changeset you know exhibits the problem as
923 bad, then mark the latest changeset which is free from the problem
923 bad, then mark the latest changeset which is free from the problem
924 as good. Bisect will update your working directory to a revision
924 as good. Bisect will update your working directory to a revision
925 for testing (unless the -U/--noupdate option is specified). Once
925 for testing (unless the -U/--noupdate option is specified). Once
926 you have performed tests, mark the working directory as good or
926 you have performed tests, mark the working directory as good or
927 bad, and bisect will either update to another candidate changeset
927 bad, and bisect will either update to another candidate changeset
928 or announce that it has found the bad revision.
928 or announce that it has found the bad revision.
929
929
930 As a shortcut, you can also use the revision argument to mark a
930 As a shortcut, you can also use the revision argument to mark a
931 revision as good or bad without checking it out first.
931 revision as good or bad without checking it out first.
932
932
933 If you supply a command, it will be used for automatic bisection.
933 If you supply a command, it will be used for automatic bisection.
934 The environment variable HG_NODE will contain the ID of the
934 The environment variable HG_NODE will contain the ID of the
935 changeset being tested. The exit status of the command will be
935 changeset being tested. The exit status of the command will be
936 used to mark revisions as good or bad: status 0 means good, 125
936 used to mark revisions as good or bad: status 0 means good, 125
937 means to skip the revision, 127 (command not found) will abort the
937 means to skip the revision, 127 (command not found) will abort the
938 bisection, and any other non-zero exit status means the revision
938 bisection, and any other non-zero exit status means the revision
939 is bad.
939 is bad.
940
940
941 .. container:: verbose
941 .. container:: verbose
942
942
943 Some examples:
943 Some examples:
944
944
945 - start a bisection with known bad revision 34, and good revision 12::
945 - start a bisection with known bad revision 34, and good revision 12::
946
946
947 hg bisect --bad 34
947 hg bisect --bad 34
948 hg bisect --good 12
948 hg bisect --good 12
949
949
950 - advance the current bisection by marking current revision as good or
950 - advance the current bisection by marking current revision as good or
951 bad::
951 bad::
952
952
953 hg bisect --good
953 hg bisect --good
954 hg bisect --bad
954 hg bisect --bad
955
955
956 - mark the current revision, or a known revision, to be skipped (e.g. if
956 - mark the current revision, or a known revision, to be skipped (e.g. if
957 that revision is not usable because of another issue)::
957 that revision is not usable because of another issue)::
958
958
959 hg bisect --skip
959 hg bisect --skip
960 hg bisect --skip 23
960 hg bisect --skip 23
961
961
962 - skip all revisions that do not touch directories ``foo`` or ``bar``::
962 - skip all revisions that do not touch directories ``foo`` or ``bar``::
963
963
964 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
964 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
965
965
966 - forget the current bisection::
966 - forget the current bisection::
967
967
968 hg bisect --reset
968 hg bisect --reset
969
969
970 - use 'make && make tests' to automatically find the first broken
970 - use 'make && make tests' to automatically find the first broken
971 revision::
971 revision::
972
972
973 hg bisect --reset
973 hg bisect --reset
974 hg bisect --bad 34
974 hg bisect --bad 34
975 hg bisect --good 12
975 hg bisect --good 12
976 hg bisect --command "make && make tests"
976 hg bisect --command "make && make tests"
977
977
978 - see all changesets whose states are already known in the current
978 - see all changesets whose states are already known in the current
979 bisection::
979 bisection::
980
980
981 hg log -r "bisect(pruned)"
981 hg log -r "bisect(pruned)"
982
982
983 - see the changeset currently being bisected (especially useful
983 - see the changeset currently being bisected (especially useful
984 if running with -U/--noupdate)::
984 if running with -U/--noupdate)::
985
985
986 hg log -r "bisect(current)"
986 hg log -r "bisect(current)"
987
987
988 - see all changesets that took part in the current bisection::
988 - see all changesets that took part in the current bisection::
989
989
990 hg log -r "bisect(range)"
990 hg log -r "bisect(range)"
991
991
992 - you can even get a nice graph::
992 - you can even get a nice graph::
993
993
994 hg log --graph -r "bisect(range)"
994 hg log --graph -r "bisect(range)"
995
995
996 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
996 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
997
997
998 Returns 0 on success.
998 Returns 0 on success.
999 """
999 """
1000 rev = []
1000 rev = []
1001 # backward compatibility
1001 # backward compatibility
1002 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1002 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1003 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1003 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1004 cmd = positional_1
1004 cmd = positional_1
1005 rev.append(positional_2)
1005 rev.append(positional_2)
1006 if cmd == b"good":
1006 if cmd == b"good":
1007 good = True
1007 good = True
1008 elif cmd == b"bad":
1008 elif cmd == b"bad":
1009 bad = True
1009 bad = True
1010 else:
1010 else:
1011 reset = True
1011 reset = True
1012 elif positional_2:
1012 elif positional_2:
1013 raise error.InputError(_(b'incompatible arguments'))
1013 raise error.InputError(_(b'incompatible arguments'))
1014 elif positional_1 is not None:
1014 elif positional_1 is not None:
1015 rev.append(positional_1)
1015 rev.append(positional_1)
1016
1016
1017 incompatibles = {
1017 incompatibles = {
1018 b'--bad': bad,
1018 b'--bad': bad,
1019 b'--command': bool(command),
1019 b'--command': bool(command),
1020 b'--extend': extend,
1020 b'--extend': extend,
1021 b'--good': good,
1021 b'--good': good,
1022 b'--reset': reset,
1022 b'--reset': reset,
1023 b'--skip': skip,
1023 b'--skip': skip,
1024 }
1024 }
1025
1025
1026 enabled = [x for x in incompatibles if incompatibles[x]]
1026 enabled = [x for x in incompatibles if incompatibles[x]]
1027
1027
1028 if len(enabled) > 1:
1028 if len(enabled) > 1:
1029 raise error.InputError(
1029 raise error.InputError(
1030 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1030 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1031 )
1031 )
1032
1032
1033 if reset:
1033 if reset:
1034 hbisect.resetstate(repo)
1034 hbisect.resetstate(repo)
1035 return
1035 return
1036
1036
1037 state = hbisect.load_state(repo)
1037 state = hbisect.load_state(repo)
1038
1038
1039 if rev:
1039 if rev:
1040 nodes = [repo[i].node() for i in logcmdutil.revrange(repo, rev)]
1040 nodes = [repo[i].node() for i in logcmdutil.revrange(repo, rev)]
1041 else:
1041 else:
1042 nodes = [repo.lookup(b'.')]
1042 nodes = [repo.lookup(b'.')]
1043
1043
1044 # update state
1044 # update state
1045 if good or bad or skip:
1045 if good or bad or skip:
1046 if good:
1046 if good:
1047 state[b'good'] += nodes
1047 state[b'good'] += nodes
1048 elif bad:
1048 elif bad:
1049 state[b'bad'] += nodes
1049 state[b'bad'] += nodes
1050 elif skip:
1050 elif skip:
1051 state[b'skip'] += nodes
1051 state[b'skip'] += nodes
1052 hbisect.save_state(repo, state)
1052 hbisect.save_state(repo, state)
1053 if not (state[b'good'] and state[b'bad']):
1053 if not (state[b'good'] and state[b'bad']):
1054 return
1054 return
1055
1055
1056 def mayupdate(repo, node, show_stats=True):
1056 def mayupdate(repo, node, show_stats=True):
1057 """common used update sequence"""
1057 """common used update sequence"""
1058 if noupdate:
1058 if noupdate:
1059 return
1059 return
1060 cmdutil.checkunfinished(repo)
1060 cmdutil.checkunfinished(repo)
1061 cmdutil.bailifchanged(repo)
1061 cmdutil.bailifchanged(repo)
1062 return hg.clean(repo, node, show_stats=show_stats)
1062 return hg.clean(repo, node, show_stats=show_stats)
1063
1063
1064 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1064 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1065
1065
1066 if command:
1066 if command:
1067 changesets = 1
1067 changesets = 1
1068 if noupdate:
1068 if noupdate:
1069 try:
1069 try:
1070 node = state[b'current'][0]
1070 node = state[b'current'][0]
1071 except LookupError:
1071 except LookupError:
1072 raise error.StateError(
1072 raise error.StateError(
1073 _(
1073 _(
1074 b'current bisect revision is unknown - '
1074 b'current bisect revision is unknown - '
1075 b'start a new bisect to fix'
1075 b'start a new bisect to fix'
1076 )
1076 )
1077 )
1077 )
1078 else:
1078 else:
1079 node, p2 = repo.dirstate.parents()
1079 node, p2 = repo.dirstate.parents()
1080 if p2 != repo.nullid:
1080 if p2 != repo.nullid:
1081 raise error.StateError(_(b'current bisect revision is a merge'))
1081 raise error.StateError(_(b'current bisect revision is a merge'))
1082 if rev:
1082 if rev:
1083 if not nodes:
1083 if not nodes:
1084 raise error.InputError(_(b'empty revision set'))
1084 raise error.InputError(_(b'empty revision set'))
1085 node = repo[nodes[-1]].node()
1085 node = repo[nodes[-1]].node()
1086 with hbisect.restore_state(repo, state, node):
1086 with hbisect.restore_state(repo, state, node):
1087 while changesets:
1087 while changesets:
1088 # update state
1088 # update state
1089 state[b'current'] = [node]
1089 state[b'current'] = [node]
1090 hbisect.save_state(repo, state)
1090 hbisect.save_state(repo, state)
1091 status = ui.system(
1091 status = ui.system(
1092 command,
1092 command,
1093 environ={b'HG_NODE': hex(node)},
1093 environ={b'HG_NODE': hex(node)},
1094 blockedtag=b'bisect_check',
1094 blockedtag=b'bisect_check',
1095 )
1095 )
1096 if status == 125:
1096 if status == 125:
1097 transition = b"skip"
1097 transition = b"skip"
1098 elif status == 0:
1098 elif status == 0:
1099 transition = b"good"
1099 transition = b"good"
1100 # status < 0 means process was killed
1100 # status < 0 means process was killed
1101 elif status == 127:
1101 elif status == 127:
1102 raise error.Abort(_(b"failed to execute %s") % command)
1102 raise error.Abort(_(b"failed to execute %s") % command)
1103 elif status < 0:
1103 elif status < 0:
1104 raise error.Abort(_(b"%s killed") % command)
1104 raise error.Abort(_(b"%s killed") % command)
1105 else:
1105 else:
1106 transition = b"bad"
1106 transition = b"bad"
1107 state[transition].append(node)
1107 state[transition].append(node)
1108 ctx = repo[node]
1108 ctx = repo[node]
1109 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1109 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1110 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1110 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1111 hbisect.checkstate(state)
1111 hbisect.checkstate(state)
1112 # bisect
1112 # bisect
1113 nodes, changesets, bgood = hbisect.bisect(repo, state)
1113 nodes, changesets, bgood = hbisect.bisect(repo, state)
1114 # update to next check
1114 # update to next check
1115 node = nodes[0]
1115 node = nodes[0]
1116 mayupdate(repo, node, show_stats=False)
1116 mayupdate(repo, node, show_stats=False)
1117 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1117 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1118 return
1118 return
1119
1119
1120 hbisect.checkstate(state)
1120 hbisect.checkstate(state)
1121
1121
1122 # actually bisect
1122 # actually bisect
1123 nodes, changesets, good = hbisect.bisect(repo, state)
1123 nodes, changesets, good = hbisect.bisect(repo, state)
1124 if extend:
1124 if extend:
1125 if not changesets:
1125 if not changesets:
1126 extendctx = hbisect.extendrange(repo, state, nodes, good)
1126 extendctx = hbisect.extendrange(repo, state, nodes, good)
1127 if extendctx is not None:
1127 if extendctx is not None:
1128 ui.write(
1128 ui.write(
1129 _(b"Extending search to changeset %s\n")
1129 _(b"Extending search to changeset %s\n")
1130 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1130 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1131 )
1131 )
1132 state[b'current'] = [extendctx.node()]
1132 state[b'current'] = [extendctx.node()]
1133 hbisect.save_state(repo, state)
1133 hbisect.save_state(repo, state)
1134 return mayupdate(repo, extendctx.node())
1134 return mayupdate(repo, extendctx.node())
1135 raise error.StateError(_(b"nothing to extend"))
1135 raise error.StateError(_(b"nothing to extend"))
1136
1136
1137 if changesets == 0:
1137 if changesets == 0:
1138 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1138 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1139 else:
1139 else:
1140 assert len(nodes) == 1 # only a single node can be tested next
1140 assert len(nodes) == 1 # only a single node can be tested next
1141 node = nodes[0]
1141 node = nodes[0]
1142 # compute the approximate number of remaining tests
1142 # compute the approximate number of remaining tests
1143 tests, size = 0, 2
1143 tests, size = 0, 2
1144 while size <= changesets:
1144 while size <= changesets:
1145 tests, size = tests + 1, size * 2
1145 tests, size = tests + 1, size * 2
1146 rev = repo.changelog.rev(node)
1146 rev = repo.changelog.rev(node)
1147 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1147 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1148 ui.write(
1148 ui.write(
1149 _(
1149 _(
1150 b"Testing changeset %s "
1150 b"Testing changeset %s "
1151 b"(%d changesets remaining, ~%d tests)\n"
1151 b"(%d changesets remaining, ~%d tests)\n"
1152 )
1152 )
1153 % (summary, changesets, tests)
1153 % (summary, changesets, tests)
1154 )
1154 )
1155 state[b'current'] = [node]
1155 state[b'current'] = [node]
1156 hbisect.save_state(repo, state)
1156 hbisect.save_state(repo, state)
1157 return mayupdate(repo, node)
1157 return mayupdate(repo, node)
1158
1158
1159
1159
1160 @command(
1160 @command(
1161 b'bookmarks|bookmark',
1161 b'bookmarks|bookmark',
1162 [
1162 [
1163 (b'f', b'force', False, _(b'force')),
1163 (b'f', b'force', False, _(b'force')),
1164 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1164 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1165 (b'd', b'delete', False, _(b'delete a given bookmark')),
1165 (b'd', b'delete', False, _(b'delete a given bookmark')),
1166 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1166 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1167 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1167 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1168 (b'l', b'list', False, _(b'list existing bookmarks')),
1168 (b'l', b'list', False, _(b'list existing bookmarks')),
1169 ]
1169 ]
1170 + formatteropts,
1170 + formatteropts,
1171 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1171 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1172 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1172 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1173 )
1173 )
1174 def bookmark(ui, repo, *names, **opts):
1174 def bookmark(ui, repo, *names, **opts):
1175 """create a new bookmark or list existing bookmarks
1175 """create a new bookmark or list existing bookmarks
1176
1176
1177 Bookmarks are labels on changesets to help track lines of development.
1177 Bookmarks are labels on changesets to help track lines of development.
1178 Bookmarks are unversioned and can be moved, renamed and deleted.
1178 Bookmarks are unversioned and can be moved, renamed and deleted.
1179 Deleting or moving a bookmark has no effect on the associated changesets.
1179 Deleting or moving a bookmark has no effect on the associated changesets.
1180
1180
1181 Creating or updating to a bookmark causes it to be marked as 'active'.
1181 Creating or updating to a bookmark causes it to be marked as 'active'.
1182 The active bookmark is indicated with a '*'.
1182 The active bookmark is indicated with a '*'.
1183 When a commit is made, the active bookmark will advance to the new commit.
1183 When a commit is made, the active bookmark will advance to the new commit.
1184 A plain :hg:`update` will also advance an active bookmark, if possible.
1184 A plain :hg:`update` will also advance an active bookmark, if possible.
1185 Updating away from a bookmark will cause it to be deactivated.
1185 Updating away from a bookmark will cause it to be deactivated.
1186
1186
1187 Bookmarks can be pushed and pulled between repositories (see
1187 Bookmarks can be pushed and pulled between repositories (see
1188 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1188 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1189 diverged, a new 'divergent bookmark' of the form 'name@path' will
1189 diverged, a new 'divergent bookmark' of the form 'name@path' will
1190 be created. Using :hg:`merge` will resolve the divergence.
1190 be created. Using :hg:`merge` will resolve the divergence.
1191
1191
1192 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1192 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1193 the active bookmark's name.
1193 the active bookmark's name.
1194
1194
1195 A bookmark named '@' has the special property that :hg:`clone` will
1195 A bookmark named '@' has the special property that :hg:`clone` will
1196 check it out by default if it exists.
1196 check it out by default if it exists.
1197
1197
1198 .. container:: verbose
1198 .. container:: verbose
1199
1199
1200 Template:
1200 Template:
1201
1201
1202 The following keywords are supported in addition to the common template
1202 The following keywords are supported in addition to the common template
1203 keywords and functions such as ``{bookmark}``. See also
1203 keywords and functions such as ``{bookmark}``. See also
1204 :hg:`help templates`.
1204 :hg:`help templates`.
1205
1205
1206 :active: Boolean. True if the bookmark is active.
1206 :active: Boolean. True if the bookmark is active.
1207
1207
1208 Examples:
1208 Examples:
1209
1209
1210 - create an active bookmark for a new line of development::
1210 - create an active bookmark for a new line of development::
1211
1211
1212 hg book new-feature
1212 hg book new-feature
1213
1213
1214 - create an inactive bookmark as a place marker::
1214 - create an inactive bookmark as a place marker::
1215
1215
1216 hg book -i reviewed
1216 hg book -i reviewed
1217
1217
1218 - create an inactive bookmark on another changeset::
1218 - create an inactive bookmark on another changeset::
1219
1219
1220 hg book -r .^ tested
1220 hg book -r .^ tested
1221
1221
1222 - rename bookmark turkey to dinner::
1222 - rename bookmark turkey to dinner::
1223
1223
1224 hg book -m turkey dinner
1224 hg book -m turkey dinner
1225
1225
1226 - move the '@' bookmark from another branch::
1226 - move the '@' bookmark from another branch::
1227
1227
1228 hg book -f @
1228 hg book -f @
1229
1229
1230 - print only the active bookmark name::
1230 - print only the active bookmark name::
1231
1231
1232 hg book -ql .
1232 hg book -ql .
1233 """
1233 """
1234 opts = pycompat.byteskwargs(opts)
1234 opts = pycompat.byteskwargs(opts)
1235 force = opts.get(b'force')
1235 force = opts.get(b'force')
1236 rev = opts.get(b'rev')
1236 rev = opts.get(b'rev')
1237 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1237 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1238
1238
1239 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1239 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1240 if action:
1240 if action:
1241 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1241 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1242 elif names or rev:
1242 elif names or rev:
1243 action = b'add'
1243 action = b'add'
1244 elif inactive:
1244 elif inactive:
1245 action = b'inactive' # meaning deactivate
1245 action = b'inactive' # meaning deactivate
1246 else:
1246 else:
1247 action = b'list'
1247 action = b'list'
1248
1248
1249 cmdutil.check_incompatible_arguments(
1249 cmdutil.check_incompatible_arguments(
1250 opts, b'inactive', [b'delete', b'list']
1250 opts, b'inactive', [b'delete', b'list']
1251 )
1251 )
1252 if not names and action in {b'add', b'delete'}:
1252 if not names and action in {b'add', b'delete'}:
1253 raise error.InputError(_(b"bookmark name required"))
1253 raise error.InputError(_(b"bookmark name required"))
1254
1254
1255 if action in {b'add', b'delete', b'rename', b'inactive'}:
1255 if action in {b'add', b'delete', b'rename', b'inactive'}:
1256 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1256 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1257 if action == b'delete':
1257 if action == b'delete':
1258 names = pycompat.maplist(repo._bookmarks.expandname, names)
1258 names = pycompat.maplist(repo._bookmarks.expandname, names)
1259 bookmarks.delete(repo, tr, names)
1259 bookmarks.delete(repo, tr, names)
1260 elif action == b'rename':
1260 elif action == b'rename':
1261 if not names:
1261 if not names:
1262 raise error.InputError(_(b"new bookmark name required"))
1262 raise error.InputError(_(b"new bookmark name required"))
1263 elif len(names) > 1:
1263 elif len(names) > 1:
1264 raise error.InputError(
1264 raise error.InputError(
1265 _(b"only one new bookmark name allowed")
1265 _(b"only one new bookmark name allowed")
1266 )
1266 )
1267 oldname = repo._bookmarks.expandname(opts[b'rename'])
1267 oldname = repo._bookmarks.expandname(opts[b'rename'])
1268 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1268 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1269 elif action == b'add':
1269 elif action == b'add':
1270 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1270 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1271 elif action == b'inactive':
1271 elif action == b'inactive':
1272 if len(repo._bookmarks) == 0:
1272 if len(repo._bookmarks) == 0:
1273 ui.status(_(b"no bookmarks set\n"))
1273 ui.status(_(b"no bookmarks set\n"))
1274 elif not repo._activebookmark:
1274 elif not repo._activebookmark:
1275 ui.status(_(b"no active bookmark\n"))
1275 ui.status(_(b"no active bookmark\n"))
1276 else:
1276 else:
1277 bookmarks.deactivate(repo)
1277 bookmarks.deactivate(repo)
1278 elif action == b'list':
1278 elif action == b'list':
1279 names = pycompat.maplist(repo._bookmarks.expandname, names)
1279 names = pycompat.maplist(repo._bookmarks.expandname, names)
1280 with ui.formatter(b'bookmarks', opts) as fm:
1280 with ui.formatter(b'bookmarks', opts) as fm:
1281 bookmarks.printbookmarks(ui, repo, fm, names)
1281 bookmarks.printbookmarks(ui, repo, fm, names)
1282 else:
1282 else:
1283 raise error.ProgrammingError(b'invalid action: %s' % action)
1283 raise error.ProgrammingError(b'invalid action: %s' % action)
1284
1284
1285
1285
1286 @command(
1286 @command(
1287 b'branch',
1287 b'branch',
1288 [
1288 [
1289 (
1289 (
1290 b'f',
1290 b'f',
1291 b'force',
1291 b'force',
1292 None,
1292 None,
1293 _(b'set branch name even if it shadows an existing branch'),
1293 _(b'set branch name even if it shadows an existing branch'),
1294 ),
1294 ),
1295 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1295 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1296 (
1296 (
1297 b'r',
1297 b'r',
1298 b'rev',
1298 b'rev',
1299 [],
1299 [],
1300 _(b'change branches of the given revs (EXPERIMENTAL)'),
1300 _(b'change branches of the given revs (EXPERIMENTAL)'),
1301 ),
1301 ),
1302 ],
1302 ],
1303 _(b'[-fC] [NAME]'),
1303 _(b'[-fC] [NAME]'),
1304 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1304 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1305 )
1305 )
1306 def branch(ui, repo, label=None, **opts):
1306 def branch(ui, repo, label=None, **opts):
1307 """set or show the current branch name
1307 """set or show the current branch name
1308
1308
1309 .. note::
1309 .. note::
1310
1310
1311 Branch names are permanent and global. Use :hg:`bookmark` to create a
1311 Branch names are permanent and global. Use :hg:`bookmark` to create a
1312 light-weight bookmark instead. See :hg:`help glossary` for more
1312 light-weight bookmark instead. See :hg:`help glossary` for more
1313 information about named branches and bookmarks.
1313 information about named branches and bookmarks.
1314
1314
1315 With no argument, show the current branch name. With one argument,
1315 With no argument, show the current branch name. With one argument,
1316 set the working directory branch name (the branch will not exist
1316 set the working directory branch name (the branch will not exist
1317 in the repository until the next commit). Standard practice
1317 in the repository until the next commit). Standard practice
1318 recommends that primary development take place on the 'default'
1318 recommends that primary development take place on the 'default'
1319 branch.
1319 branch.
1320
1320
1321 Unless -f/--force is specified, branch will not let you set a
1321 Unless -f/--force is specified, branch will not let you set a
1322 branch name that already exists.
1322 branch name that already exists.
1323
1323
1324 Use -C/--clean to reset the working directory branch to that of
1324 Use -C/--clean to reset the working directory branch to that of
1325 the parent of the working directory, negating a previous branch
1325 the parent of the working directory, negating a previous branch
1326 change.
1326 change.
1327
1327
1328 Use the command :hg:`update` to switch to an existing branch. Use
1328 Use the command :hg:`update` to switch to an existing branch. Use
1329 :hg:`commit --close-branch` to mark this branch head as closed.
1329 :hg:`commit --close-branch` to mark this branch head as closed.
1330 When all heads of a branch are closed, the branch will be
1330 When all heads of a branch are closed, the branch will be
1331 considered closed.
1331 considered closed.
1332
1332
1333 Returns 0 on success.
1333 Returns 0 on success.
1334 """
1334 """
1335 opts = pycompat.byteskwargs(opts)
1335 opts = pycompat.byteskwargs(opts)
1336 revs = opts.get(b'rev')
1336 revs = opts.get(b'rev')
1337 if label:
1337 if label:
1338 label = label.strip()
1338 label = label.strip()
1339
1339
1340 if not opts.get(b'clean') and not label:
1340 if not opts.get(b'clean') and not label:
1341 if revs:
1341 if revs:
1342 raise error.InputError(
1342 raise error.InputError(
1343 _(b"no branch name specified for the revisions")
1343 _(b"no branch name specified for the revisions")
1344 )
1344 )
1345 ui.write(b"%s\n" % repo.dirstate.branch())
1345 ui.write(b"%s\n" % repo.dirstate.branch())
1346 return
1346 return
1347
1347
1348 with repo.wlock():
1348 with repo.wlock():
1349 if opts.get(b'clean'):
1349 if opts.get(b'clean'):
1350 label = repo[b'.'].branch()
1350 label = repo[b'.'].branch()
1351 repo.dirstate.setbranch(label)
1351 repo.dirstate.setbranch(label)
1352 ui.status(_(b'reset working directory to branch %s\n') % label)
1352 ui.status(_(b'reset working directory to branch %s\n') % label)
1353 elif label:
1353 elif label:
1354
1354
1355 scmutil.checknewlabel(repo, label, b'branch')
1355 scmutil.checknewlabel(repo, label, b'branch')
1356 if revs:
1356 if revs:
1357 return cmdutil.changebranch(ui, repo, revs, label, opts)
1357 return cmdutil.changebranch(ui, repo, revs, label, opts)
1358
1358
1359 if not opts.get(b'force') and label in repo.branchmap():
1359 if not opts.get(b'force') and label in repo.branchmap():
1360 if label not in [p.branch() for p in repo[None].parents()]:
1360 if label not in [p.branch() for p in repo[None].parents()]:
1361 raise error.InputError(
1361 raise error.InputError(
1362 _(b'a branch of the same name already exists'),
1362 _(b'a branch of the same name already exists'),
1363 # i18n: "it" refers to an existing branch
1363 # i18n: "it" refers to an existing branch
1364 hint=_(b"use 'hg update' to switch to it"),
1364 hint=_(b"use 'hg update' to switch to it"),
1365 )
1365 )
1366
1366
1367 repo.dirstate.setbranch(label)
1367 repo.dirstate.setbranch(label)
1368 ui.status(_(b'marked working directory as branch %s\n') % label)
1368 ui.status(_(b'marked working directory as branch %s\n') % label)
1369
1369
1370 # find any open named branches aside from default
1370 # find any open named branches aside from default
1371 for n, h, t, c in repo.branchmap().iterbranches():
1371 for n, h, t, c in repo.branchmap().iterbranches():
1372 if n != b"default" and not c:
1372 if n != b"default" and not c:
1373 return 0
1373 return 0
1374 ui.status(
1374 ui.status(
1375 _(
1375 _(
1376 b'(branches are permanent and global, '
1376 b'(branches are permanent and global, '
1377 b'did you want a bookmark?)\n'
1377 b'did you want a bookmark?)\n'
1378 )
1378 )
1379 )
1379 )
1380
1380
1381
1381
1382 @command(
1382 @command(
1383 b'branches',
1383 b'branches',
1384 [
1384 [
1385 (
1385 (
1386 b'a',
1386 b'a',
1387 b'active',
1387 b'active',
1388 False,
1388 False,
1389 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1389 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1390 ),
1390 ),
1391 (b'c', b'closed', False, _(b'show normal and closed branches')),
1391 (b'c', b'closed', False, _(b'show normal and closed branches')),
1392 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1392 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1393 ]
1393 ]
1394 + formatteropts,
1394 + formatteropts,
1395 _(b'[-c]'),
1395 _(b'[-c]'),
1396 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1396 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1397 intents={INTENT_READONLY},
1397 intents={INTENT_READONLY},
1398 )
1398 )
1399 def branches(ui, repo, active=False, closed=False, **opts):
1399 def branches(ui, repo, active=False, closed=False, **opts):
1400 """list repository named branches
1400 """list repository named branches
1401
1401
1402 List the repository's named branches, indicating which ones are
1402 List the repository's named branches, indicating which ones are
1403 inactive. If -c/--closed is specified, also list branches which have
1403 inactive. If -c/--closed is specified, also list branches which have
1404 been marked closed (see :hg:`commit --close-branch`).
1404 been marked closed (see :hg:`commit --close-branch`).
1405
1405
1406 Use the command :hg:`update` to switch to an existing branch.
1406 Use the command :hg:`update` to switch to an existing branch.
1407
1407
1408 .. container:: verbose
1408 .. container:: verbose
1409
1409
1410 Template:
1410 Template:
1411
1411
1412 The following keywords are supported in addition to the common template
1412 The following keywords are supported in addition to the common template
1413 keywords and functions such as ``{branch}``. See also
1413 keywords and functions such as ``{branch}``. See also
1414 :hg:`help templates`.
1414 :hg:`help templates`.
1415
1415
1416 :active: Boolean. True if the branch is active.
1416 :active: Boolean. True if the branch is active.
1417 :closed: Boolean. True if the branch is closed.
1417 :closed: Boolean. True if the branch is closed.
1418 :current: Boolean. True if it is the current branch.
1418 :current: Boolean. True if it is the current branch.
1419
1419
1420 Returns 0.
1420 Returns 0.
1421 """
1421 """
1422
1422
1423 opts = pycompat.byteskwargs(opts)
1423 opts = pycompat.byteskwargs(opts)
1424 revs = opts.get(b'rev')
1424 revs = opts.get(b'rev')
1425 selectedbranches = None
1425 selectedbranches = None
1426 if revs:
1426 if revs:
1427 revs = logcmdutil.revrange(repo, revs)
1427 revs = logcmdutil.revrange(repo, revs)
1428 getbi = repo.revbranchcache().branchinfo
1428 getbi = repo.revbranchcache().branchinfo
1429 selectedbranches = {getbi(r)[0] for r in revs}
1429 selectedbranches = {getbi(r)[0] for r in revs}
1430
1430
1431 ui.pager(b'branches')
1431 ui.pager(b'branches')
1432 fm = ui.formatter(b'branches', opts)
1432 fm = ui.formatter(b'branches', opts)
1433 hexfunc = fm.hexfunc
1433 hexfunc = fm.hexfunc
1434
1434
1435 allheads = set(repo.heads())
1435 allheads = set(repo.heads())
1436 branches = []
1436 branches = []
1437 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1437 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1438 if selectedbranches is not None and tag not in selectedbranches:
1438 if selectedbranches is not None and tag not in selectedbranches:
1439 continue
1439 continue
1440 isactive = False
1440 isactive = False
1441 if not isclosed:
1441 if not isclosed:
1442 openheads = set(repo.branchmap().iteropen(heads))
1442 openheads = set(repo.branchmap().iteropen(heads))
1443 isactive = bool(openheads & allheads)
1443 isactive = bool(openheads & allheads)
1444 branches.append((tag, repo[tip], isactive, not isclosed))
1444 branches.append((tag, repo[tip], isactive, not isclosed))
1445 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1445 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1446
1446
1447 for tag, ctx, isactive, isopen in branches:
1447 for tag, ctx, isactive, isopen in branches:
1448 if active and not isactive:
1448 if active and not isactive:
1449 continue
1449 continue
1450 if isactive:
1450 if isactive:
1451 label = b'branches.active'
1451 label = b'branches.active'
1452 notice = b''
1452 notice = b''
1453 elif not isopen:
1453 elif not isopen:
1454 if not closed:
1454 if not closed:
1455 continue
1455 continue
1456 label = b'branches.closed'
1456 label = b'branches.closed'
1457 notice = _(b' (closed)')
1457 notice = _(b' (closed)')
1458 else:
1458 else:
1459 label = b'branches.inactive'
1459 label = b'branches.inactive'
1460 notice = _(b' (inactive)')
1460 notice = _(b' (inactive)')
1461 current = tag == repo.dirstate.branch()
1461 current = tag == repo.dirstate.branch()
1462 if current:
1462 if current:
1463 label = b'branches.current'
1463 label = b'branches.current'
1464
1464
1465 fm.startitem()
1465 fm.startitem()
1466 fm.write(b'branch', b'%s', tag, label=label)
1466 fm.write(b'branch', b'%s', tag, label=label)
1467 rev = ctx.rev()
1467 rev = ctx.rev()
1468 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1468 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1469 fmt = b' ' * padsize + b' %d:%s'
1469 fmt = b' ' * padsize + b' %d:%s'
1470 fm.condwrite(
1470 fm.condwrite(
1471 not ui.quiet,
1471 not ui.quiet,
1472 b'rev node',
1472 b'rev node',
1473 fmt,
1473 fmt,
1474 rev,
1474 rev,
1475 hexfunc(ctx.node()),
1475 hexfunc(ctx.node()),
1476 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1476 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1477 )
1477 )
1478 fm.context(ctx=ctx)
1478 fm.context(ctx=ctx)
1479 fm.data(active=isactive, closed=not isopen, current=current)
1479 fm.data(active=isactive, closed=not isopen, current=current)
1480 if not ui.quiet:
1480 if not ui.quiet:
1481 fm.plain(notice)
1481 fm.plain(notice)
1482 fm.plain(b'\n')
1482 fm.plain(b'\n')
1483 fm.end()
1483 fm.end()
1484
1484
1485
1485
1486 @command(
1486 @command(
1487 b'bundle',
1487 b'bundle',
1488 [
1488 [
1489 (
1489 (
1490 b'f',
1490 b'f',
1491 b'force',
1491 b'force',
1492 None,
1492 None,
1493 _(b'run even when the destination is unrelated'),
1493 _(b'run even when the destination is unrelated'),
1494 ),
1494 ),
1495 (
1495 (
1496 b'r',
1496 b'r',
1497 b'rev',
1497 b'rev',
1498 [],
1498 [],
1499 _(b'a changeset intended to be added to the destination'),
1499 _(b'a changeset intended to be added to the destination'),
1500 _(b'REV'),
1500 _(b'REV'),
1501 ),
1501 ),
1502 (
1502 (
1503 b'b',
1503 b'b',
1504 b'branch',
1504 b'branch',
1505 [],
1505 [],
1506 _(b'a specific branch you would like to bundle'),
1506 _(b'a specific branch you would like to bundle'),
1507 _(b'BRANCH'),
1507 _(b'BRANCH'),
1508 ),
1508 ),
1509 (
1509 (
1510 b'',
1510 b'',
1511 b'base',
1511 b'base',
1512 [],
1512 [],
1513 _(b'a base changeset assumed to be available at the destination'),
1513 _(b'a base changeset assumed to be available at the destination'),
1514 _(b'REV'),
1514 _(b'REV'),
1515 ),
1515 ),
1516 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1516 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1517 (
1517 (
1518 b't',
1518 b't',
1519 b'type',
1519 b'type',
1520 b'bzip2',
1520 b'bzip2',
1521 _(b'bundle compression type to use'),
1521 _(b'bundle compression type to use'),
1522 _(b'TYPE'),
1522 _(b'TYPE'),
1523 ),
1523 ),
1524 ]
1524 ]
1525 + remoteopts,
1525 + remoteopts,
1526 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1526 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1527 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1527 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1528 )
1528 )
1529 def bundle(ui, repo, fname, *dests, **opts):
1529 def bundle(ui, repo, fname, *dests, **opts):
1530 """create a bundle file
1530 """create a bundle file
1531
1531
1532 Generate a bundle file containing data to be transferred to another
1532 Generate a bundle file containing data to be transferred to another
1533 repository.
1533 repository.
1534
1534
1535 To create a bundle containing all changesets, use -a/--all
1535 To create a bundle containing all changesets, use -a/--all
1536 (or --base null). Otherwise, hg assumes the destination will have
1536 (or --base null). Otherwise, hg assumes the destination will have
1537 all the nodes you specify with --base parameters. Otherwise, hg
1537 all the nodes you specify with --base parameters. Otherwise, hg
1538 will assume the repository has all the nodes in destination, or
1538 will assume the repository has all the nodes in destination, or
1539 default-push/default if no destination is specified, where destination
1539 default-push/default if no destination is specified, where destination
1540 is the repositories you provide through DEST option.
1540 is the repositories you provide through DEST option.
1541
1541
1542 You can change bundle format with the -t/--type option. See
1542 You can change bundle format with the -t/--type option. See
1543 :hg:`help bundlespec` for documentation on this format. By default,
1543 :hg:`help bundlespec` for documentation on this format. By default,
1544 the most appropriate format is used and compression defaults to
1544 the most appropriate format is used and compression defaults to
1545 bzip2.
1545 bzip2.
1546
1546
1547 The bundle file can then be transferred using conventional means
1547 The bundle file can then be transferred using conventional means
1548 and applied to another repository with the unbundle or pull
1548 and applied to another repository with the unbundle or pull
1549 command. This is useful when direct push and pull are not
1549 command. This is useful when direct push and pull are not
1550 available or when exporting an entire repository is undesirable.
1550 available or when exporting an entire repository is undesirable.
1551
1551
1552 Applying bundles preserves all changeset contents including
1552 Applying bundles preserves all changeset contents including
1553 permissions, copy/rename information, and revision history.
1553 permissions, copy/rename information, and revision history.
1554
1554
1555 Returns 0 on success, 1 if no changes found.
1555 Returns 0 on success, 1 if no changes found.
1556 """
1556 """
1557 opts = pycompat.byteskwargs(opts)
1557 opts = pycompat.byteskwargs(opts)
1558 revs = None
1558 revs = None
1559 if b'rev' in opts:
1559 if b'rev' in opts:
1560 revstrings = opts[b'rev']
1560 revstrings = opts[b'rev']
1561 revs = logcmdutil.revrange(repo, revstrings)
1561 revs = logcmdutil.revrange(repo, revstrings)
1562 if revstrings and not revs:
1562 if revstrings and not revs:
1563 raise error.InputError(_(b'no commits to bundle'))
1563 raise error.InputError(_(b'no commits to bundle'))
1564
1564
1565 bundletype = opts.get(b'type', b'bzip2').lower()
1565 bundletype = opts.get(b'type', b'bzip2').lower()
1566 try:
1566 try:
1567 bundlespec = bundlecaches.parsebundlespec(
1567 bundlespec = bundlecaches.parsebundlespec(
1568 repo, bundletype, strict=False
1568 repo, bundletype, strict=False
1569 )
1569 )
1570 except error.UnsupportedBundleSpecification as e:
1570 except error.UnsupportedBundleSpecification as e:
1571 raise error.InputError(
1571 raise error.InputError(
1572 pycompat.bytestr(e),
1572 pycompat.bytestr(e),
1573 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1573 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1574 )
1574 )
1575 cgversion = bundlespec.contentopts[b"cg.version"]
1575 cgversion = bundlespec.contentopts[b"cg.version"]
1576
1576
1577 # Packed bundles are a pseudo bundle format for now.
1577 # Packed bundles are a pseudo bundle format for now.
1578 if cgversion == b's1':
1578 if cgversion == b's1':
1579 raise error.InputError(
1579 raise error.InputError(
1580 _(b'packed bundles cannot be produced by "hg bundle"'),
1580 _(b'packed bundles cannot be produced by "hg bundle"'),
1581 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1581 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1582 )
1582 )
1583
1583
1584 if opts.get(b'all'):
1584 if opts.get(b'all'):
1585 if dests:
1585 if dests:
1586 raise error.InputError(
1586 raise error.InputError(
1587 _(b"--all is incompatible with specifying destinations")
1587 _(b"--all is incompatible with specifying destinations")
1588 )
1588 )
1589 if opts.get(b'base'):
1589 if opts.get(b'base'):
1590 ui.warn(_(b"ignoring --base because --all was specified\n"))
1590 ui.warn(_(b"ignoring --base because --all was specified\n"))
1591 base = [nullrev]
1591 base = [nullrev]
1592 else:
1592 else:
1593 base = logcmdutil.revrange(repo, opts.get(b'base'))
1593 base = logcmdutil.revrange(repo, opts.get(b'base'))
1594 if cgversion not in changegroup.supportedoutgoingversions(repo):
1594 if cgversion not in changegroup.supportedoutgoingversions(repo):
1595 raise error.Abort(
1595 raise error.Abort(
1596 _(b"repository does not support bundle version %s") % cgversion
1596 _(b"repository does not support bundle version %s") % cgversion
1597 )
1597 )
1598
1598
1599 if base:
1599 if base:
1600 if dests:
1600 if dests:
1601 raise error.InputError(
1601 raise error.InputError(
1602 _(b"--base is incompatible with specifying destinations")
1602 _(b"--base is incompatible with specifying destinations")
1603 )
1603 )
1604 common = [repo[rev].node() for rev in base]
1604 common = [repo[rev].node() for rev in base]
1605 heads = [repo[r].node() for r in revs] if revs else None
1605 heads = [repo[r].node() for r in revs] if revs else None
1606 outgoing = discovery.outgoing(repo, common, heads)
1606 outgoing = discovery.outgoing(repo, common, heads)
1607 missing = outgoing.missing
1607 missing = outgoing.missing
1608 excluded = outgoing.excluded
1608 excluded = outgoing.excluded
1609 else:
1609 else:
1610 missing = set()
1610 missing = set()
1611 excluded = set()
1611 excluded = set()
1612 for path in urlutil.get_push_paths(repo, ui, dests):
1612 for path in urlutil.get_push_paths(repo, ui, dests):
1613 other = hg.peer(repo, opts, path.rawloc)
1613 other = hg.peer(repo, opts, path.rawloc)
1614 if revs is not None:
1614 if revs is not None:
1615 hex_revs = [repo[r].hex() for r in revs]
1615 hex_revs = [repo[r].hex() for r in revs]
1616 else:
1616 else:
1617 hex_revs = None
1617 hex_revs = None
1618 branches = (path.branch, [])
1618 branches = (path.branch, [])
1619 head_revs, checkout = hg.addbranchrevs(
1619 head_revs, checkout = hg.addbranchrevs(
1620 repo, repo, branches, hex_revs
1620 repo, repo, branches, hex_revs
1621 )
1621 )
1622 heads = (
1622 heads = (
1623 head_revs
1623 head_revs
1624 and pycompat.maplist(repo.lookup, head_revs)
1624 and pycompat.maplist(repo.lookup, head_revs)
1625 or head_revs
1625 or head_revs
1626 )
1626 )
1627 outgoing = discovery.findcommonoutgoing(
1627 outgoing = discovery.findcommonoutgoing(
1628 repo,
1628 repo,
1629 other,
1629 other,
1630 onlyheads=heads,
1630 onlyheads=heads,
1631 force=opts.get(b'force'),
1631 force=opts.get(b'force'),
1632 portable=True,
1632 portable=True,
1633 )
1633 )
1634 missing.update(outgoing.missing)
1634 missing.update(outgoing.missing)
1635 excluded.update(outgoing.excluded)
1635 excluded.update(outgoing.excluded)
1636
1636
1637 if not missing:
1637 if not missing:
1638 scmutil.nochangesfound(ui, repo, not base and excluded)
1638 scmutil.nochangesfound(ui, repo, not base and excluded)
1639 return 1
1639 return 1
1640
1640
1641 if heads:
1641 if heads:
1642 outgoing = discovery.outgoing(
1642 outgoing = discovery.outgoing(
1643 repo, missingroots=missing, ancestorsof=heads
1643 repo, missingroots=missing, ancestorsof=heads
1644 )
1644 )
1645 else:
1645 else:
1646 outgoing = discovery.outgoing(repo, missingroots=missing)
1646 outgoing = discovery.outgoing(repo, missingroots=missing)
1647 outgoing.excluded = sorted(excluded)
1647 outgoing.excluded = sorted(excluded)
1648
1648
1649 if cgversion == b'01': # bundle1
1649 if cgversion == b'01': # bundle1
1650 bversion = b'HG10' + bundlespec.wirecompression
1650 bversion = b'HG10' + bundlespec.wirecompression
1651 bcompression = None
1651 bcompression = None
1652 elif cgversion in (b'02', b'03'):
1652 elif cgversion in (b'02', b'03'):
1653 bversion = b'HG20'
1653 bversion = b'HG20'
1654 bcompression = bundlespec.wirecompression
1654 bcompression = bundlespec.wirecompression
1655 else:
1655 else:
1656 raise error.ProgrammingError(
1656 raise error.ProgrammingError(
1657 b'bundle: unexpected changegroup version %s' % cgversion
1657 b'bundle: unexpected changegroup version %s' % cgversion
1658 )
1658 )
1659
1659
1660 # TODO compression options should be derived from bundlespec parsing.
1660 # TODO compression options should be derived from bundlespec parsing.
1661 # This is a temporary hack to allow adjusting bundle compression
1661 # This is a temporary hack to allow adjusting bundle compression
1662 # level without a) formalizing the bundlespec changes to declare it
1662 # level without a) formalizing the bundlespec changes to declare it
1663 # b) introducing a command flag.
1663 # b) introducing a command flag.
1664 compopts = {}
1664 compopts = {}
1665 complevel = ui.configint(
1665 complevel = ui.configint(
1666 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1666 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1667 )
1667 )
1668 if complevel is None:
1668 if complevel is None:
1669 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1669 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1670 if complevel is not None:
1670 if complevel is not None:
1671 compopts[b'level'] = complevel
1671 compopts[b'level'] = complevel
1672
1672
1673 compthreads = ui.configint(
1673 compthreads = ui.configint(
1674 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1674 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1675 )
1675 )
1676 if compthreads is None:
1676 if compthreads is None:
1677 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1677 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1678 if compthreads is not None:
1678 if compthreads is not None:
1679 compopts[b'threads'] = compthreads
1679 compopts[b'threads'] = compthreads
1680
1680
1681 # Bundling of obsmarker and phases is optional as not all clients
1681 # Bundling of obsmarker and phases is optional as not all clients
1682 # support the necessary features.
1682 # support the necessary features.
1683 cfg = ui.configbool
1683 cfg = ui.configbool
1684 contentopts = {
1684 contentopts = {
1685 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1685 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1686 b'obsolescence-mandatory': cfg(
1686 b'obsolescence-mandatory': cfg(
1687 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1687 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1688 ),
1688 ),
1689 b'phases': cfg(b'experimental', b'bundle-phases'),
1689 b'phases': cfg(b'experimental', b'bundle-phases'),
1690 }
1690 }
1691 bundlespec.contentopts.update(contentopts)
1691 bundlespec.contentopts.update(contentopts)
1692
1692
1693 bundle2.writenewbundle(
1693 bundle2.writenewbundle(
1694 ui,
1694 ui,
1695 repo,
1695 repo,
1696 b'bundle',
1696 b'bundle',
1697 fname,
1697 fname,
1698 bversion,
1698 bversion,
1699 outgoing,
1699 outgoing,
1700 bundlespec.contentopts,
1700 bundlespec.contentopts,
1701 compression=bcompression,
1701 compression=bcompression,
1702 compopts=compopts,
1702 compopts=compopts,
1703 )
1703 )
1704
1704
1705
1705
1706 @command(
1706 @command(
1707 b'cat',
1707 b'cat',
1708 [
1708 [
1709 (
1709 (
1710 b'o',
1710 b'o',
1711 b'output',
1711 b'output',
1712 b'',
1712 b'',
1713 _(b'print output to file with formatted name'),
1713 _(b'print output to file with formatted name'),
1714 _(b'FORMAT'),
1714 _(b'FORMAT'),
1715 ),
1715 ),
1716 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1716 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1717 (b'', b'decode', None, _(b'apply any matching decode filter')),
1717 (b'', b'decode', None, _(b'apply any matching decode filter')),
1718 ]
1718 ]
1719 + walkopts
1719 + walkopts
1720 + formatteropts,
1720 + formatteropts,
1721 _(b'[OPTION]... FILE...'),
1721 _(b'[OPTION]... FILE...'),
1722 helpcategory=command.CATEGORY_FILE_CONTENTS,
1722 helpcategory=command.CATEGORY_FILE_CONTENTS,
1723 inferrepo=True,
1723 inferrepo=True,
1724 intents={INTENT_READONLY},
1724 intents={INTENT_READONLY},
1725 )
1725 )
1726 def cat(ui, repo, file1, *pats, **opts):
1726 def cat(ui, repo, file1, *pats, **opts):
1727 """output the current or given revision of files
1727 """output the current or given revision of files
1728
1728
1729 Print the specified files as they were at the given revision. If
1729 Print the specified files as they were at the given revision. If
1730 no revision is given, the parent of the working directory is used.
1730 no revision is given, the parent of the working directory is used.
1731
1731
1732 Output may be to a file, in which case the name of the file is
1732 Output may be to a file, in which case the name of the file is
1733 given using a template string. See :hg:`help templates`. In addition
1733 given using a template string. See :hg:`help templates`. In addition
1734 to the common template keywords, the following formatting rules are
1734 to the common template keywords, the following formatting rules are
1735 supported:
1735 supported:
1736
1736
1737 :``%%``: literal "%" character
1737 :``%%``: literal "%" character
1738 :``%s``: basename of file being printed
1738 :``%s``: basename of file being printed
1739 :``%d``: dirname of file being printed, or '.' if in repository root
1739 :``%d``: dirname of file being printed, or '.' if in repository root
1740 :``%p``: root-relative path name of file being printed
1740 :``%p``: root-relative path name of file being printed
1741 :``%H``: changeset hash (40 hexadecimal digits)
1741 :``%H``: changeset hash (40 hexadecimal digits)
1742 :``%R``: changeset revision number
1742 :``%R``: changeset revision number
1743 :``%h``: short-form changeset hash (12 hexadecimal digits)
1743 :``%h``: short-form changeset hash (12 hexadecimal digits)
1744 :``%r``: zero-padded changeset revision number
1744 :``%r``: zero-padded changeset revision number
1745 :``%b``: basename of the exporting repository
1745 :``%b``: basename of the exporting repository
1746 :``\\``: literal "\\" character
1746 :``\\``: literal "\\" character
1747
1747
1748 .. container:: verbose
1748 .. container:: verbose
1749
1749
1750 Template:
1750 Template:
1751
1751
1752 The following keywords are supported in addition to the common template
1752 The following keywords are supported in addition to the common template
1753 keywords and functions. See also :hg:`help templates`.
1753 keywords and functions. See also :hg:`help templates`.
1754
1754
1755 :data: String. File content.
1755 :data: String. File content.
1756 :path: String. Repository-absolute path of the file.
1756 :path: String. Repository-absolute path of the file.
1757
1757
1758 Returns 0 on success.
1758 Returns 0 on success.
1759 """
1759 """
1760 opts = pycompat.byteskwargs(opts)
1760 opts = pycompat.byteskwargs(opts)
1761 rev = opts.get(b'rev')
1761 rev = opts.get(b'rev')
1762 if rev:
1762 if rev:
1763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1764 ctx = logcmdutil.revsingle(repo, rev)
1764 ctx = logcmdutil.revsingle(repo, rev)
1765 m = scmutil.match(ctx, (file1,) + pats, opts)
1765 m = scmutil.match(ctx, (file1,) + pats, opts)
1766 fntemplate = opts.pop(b'output', b'')
1766 fntemplate = opts.pop(b'output', b'')
1767 if cmdutil.isstdiofilename(fntemplate):
1767 if cmdutil.isstdiofilename(fntemplate):
1768 fntemplate = b''
1768 fntemplate = b''
1769
1769
1770 if fntemplate:
1770 if fntemplate:
1771 fm = formatter.nullformatter(ui, b'cat', opts)
1771 fm = formatter.nullformatter(ui, b'cat', opts)
1772 else:
1772 else:
1773 ui.pager(b'cat')
1773 ui.pager(b'cat')
1774 fm = ui.formatter(b'cat', opts)
1774 fm = ui.formatter(b'cat', opts)
1775 with fm:
1775 with fm:
1776 return cmdutil.cat(
1776 return cmdutil.cat(
1777 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1777 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1778 )
1778 )
1779
1779
1780
1780
1781 @command(
1781 @command(
1782 b'clone',
1782 b'clone',
1783 [
1783 [
1784 (
1784 (
1785 b'U',
1785 b'U',
1786 b'noupdate',
1786 b'noupdate',
1787 None,
1787 None,
1788 _(
1788 _(
1789 b'the clone will include an empty working '
1789 b'the clone will include an empty working '
1790 b'directory (only a repository)'
1790 b'directory (only a repository)'
1791 ),
1791 ),
1792 ),
1792 ),
1793 (
1793 (
1794 b'u',
1794 b'u',
1795 b'updaterev',
1795 b'updaterev',
1796 b'',
1796 b'',
1797 _(b'revision, tag, or branch to check out'),
1797 _(b'revision, tag, or branch to check out'),
1798 _(b'REV'),
1798 _(b'REV'),
1799 ),
1799 ),
1800 (
1800 (
1801 b'r',
1801 b'r',
1802 b'rev',
1802 b'rev',
1803 [],
1803 [],
1804 _(
1804 _(
1805 b'do not clone everything, but include this changeset'
1805 b'do not clone everything, but include this changeset'
1806 b' and its ancestors'
1806 b' and its ancestors'
1807 ),
1807 ),
1808 _(b'REV'),
1808 _(b'REV'),
1809 ),
1809 ),
1810 (
1810 (
1811 b'b',
1811 b'b',
1812 b'branch',
1812 b'branch',
1813 [],
1813 [],
1814 _(
1814 _(
1815 b'do not clone everything, but include this branch\'s'
1815 b'do not clone everything, but include this branch\'s'
1816 b' changesets and their ancestors'
1816 b' changesets and their ancestors'
1817 ),
1817 ),
1818 _(b'BRANCH'),
1818 _(b'BRANCH'),
1819 ),
1819 ),
1820 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1820 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1821 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1821 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1822 (b'', b'stream', None, _(b'clone with minimal data processing')),
1822 (b'', b'stream', None, _(b'clone with minimal data processing')),
1823 ]
1823 ]
1824 + remoteopts,
1824 + remoteopts,
1825 _(b'[OPTION]... SOURCE [DEST]'),
1825 _(b'[OPTION]... SOURCE [DEST]'),
1826 helpcategory=command.CATEGORY_REPO_CREATION,
1826 helpcategory=command.CATEGORY_REPO_CREATION,
1827 helpbasic=True,
1827 helpbasic=True,
1828 norepo=True,
1828 norepo=True,
1829 )
1829 )
1830 def clone(ui, source, dest=None, **opts):
1830 def clone(ui, source, dest=None, **opts):
1831 """make a copy of an existing repository
1831 """make a copy of an existing repository
1832
1832
1833 Create a copy of an existing repository in a new directory.
1833 Create a copy of an existing repository in a new directory.
1834
1834
1835 If no destination directory name is specified, it defaults to the
1835 If no destination directory name is specified, it defaults to the
1836 basename of the source.
1836 basename of the source.
1837
1837
1838 The location of the source is added to the new repository's
1838 The location of the source is added to the new repository's
1839 ``.hg/hgrc`` file, as the default to be used for future pulls.
1839 ``.hg/hgrc`` file, as the default to be used for future pulls.
1840
1840
1841 Only local paths and ``ssh://`` URLs are supported as
1841 Only local paths and ``ssh://`` URLs are supported as
1842 destinations. For ``ssh://`` destinations, no working directory or
1842 destinations. For ``ssh://`` destinations, no working directory or
1843 ``.hg/hgrc`` will be created on the remote side.
1843 ``.hg/hgrc`` will be created on the remote side.
1844
1844
1845 If the source repository has a bookmark called '@' set, that
1845 If the source repository has a bookmark called '@' set, that
1846 revision will be checked out in the new repository by default.
1846 revision will be checked out in the new repository by default.
1847
1847
1848 To check out a particular version, use -u/--update, or
1848 To check out a particular version, use -u/--update, or
1849 -U/--noupdate to create a clone with no working directory.
1849 -U/--noupdate to create a clone with no working directory.
1850
1850
1851 To pull only a subset of changesets, specify one or more revisions
1851 To pull only a subset of changesets, specify one or more revisions
1852 identifiers with -r/--rev or branches with -b/--branch. The
1852 identifiers with -r/--rev or branches with -b/--branch. The
1853 resulting clone will contain only the specified changesets and
1853 resulting clone will contain only the specified changesets and
1854 their ancestors. These options (or 'clone src#rev dest') imply
1854 their ancestors. These options (or 'clone src#rev dest') imply
1855 --pull, even for local source repositories.
1855 --pull, even for local source repositories.
1856
1856
1857 In normal clone mode, the remote normalizes repository data into a common
1857 In normal clone mode, the remote normalizes repository data into a common
1858 exchange format and the receiving end translates this data into its local
1858 exchange format and the receiving end translates this data into its local
1859 storage format. --stream activates a different clone mode that essentially
1859 storage format. --stream activates a different clone mode that essentially
1860 copies repository files from the remote with minimal data processing. This
1860 copies repository files from the remote with minimal data processing. This
1861 significantly reduces the CPU cost of a clone both remotely and locally.
1861 significantly reduces the CPU cost of a clone both remotely and locally.
1862 However, it often increases the transferred data size by 30-40%. This can
1862 However, it often increases the transferred data size by 30-40%. This can
1863 result in substantially faster clones where I/O throughput is plentiful,
1863 result in substantially faster clones where I/O throughput is plentiful,
1864 especially for larger repositories. A side-effect of --stream clones is
1864 especially for larger repositories. A side-effect of --stream clones is
1865 that storage settings and requirements on the remote are applied locally:
1865 that storage settings and requirements on the remote are applied locally:
1866 a modern client may inherit legacy or inefficient storage used by the
1866 a modern client may inherit legacy or inefficient storage used by the
1867 remote or a legacy Mercurial client may not be able to clone from a
1867 remote or a legacy Mercurial client may not be able to clone from a
1868 modern Mercurial remote.
1868 modern Mercurial remote.
1869
1869
1870 .. note::
1870 .. note::
1871
1871
1872 Specifying a tag will include the tagged changeset but not the
1872 Specifying a tag will include the tagged changeset but not the
1873 changeset containing the tag.
1873 changeset containing the tag.
1874
1874
1875 .. container:: verbose
1875 .. container:: verbose
1876
1876
1877 For efficiency, hardlinks are used for cloning whenever the
1877 For efficiency, hardlinks are used for cloning whenever the
1878 source and destination are on the same filesystem (note this
1878 source and destination are on the same filesystem (note this
1879 applies only to the repository data, not to the working
1879 applies only to the repository data, not to the working
1880 directory). Some filesystems, such as AFS, implement hardlinking
1880 directory). Some filesystems, such as AFS, implement hardlinking
1881 incorrectly, but do not report errors. In these cases, use the
1881 incorrectly, but do not report errors. In these cases, use the
1882 --pull option to avoid hardlinking.
1882 --pull option to avoid hardlinking.
1883
1883
1884 Mercurial will update the working directory to the first applicable
1884 Mercurial will update the working directory to the first applicable
1885 revision from this list:
1885 revision from this list:
1886
1886
1887 a) null if -U or the source repository has no changesets
1887 a) null if -U or the source repository has no changesets
1888 b) if -u . and the source repository is local, the first parent of
1888 b) if -u . and the source repository is local, the first parent of
1889 the source repository's working directory
1889 the source repository's working directory
1890 c) the changeset specified with -u (if a branch name, this means the
1890 c) the changeset specified with -u (if a branch name, this means the
1891 latest head of that branch)
1891 latest head of that branch)
1892 d) the changeset specified with -r
1892 d) the changeset specified with -r
1893 e) the tipmost head specified with -b
1893 e) the tipmost head specified with -b
1894 f) the tipmost head specified with the url#branch source syntax
1894 f) the tipmost head specified with the url#branch source syntax
1895 g) the revision marked with the '@' bookmark, if present
1895 g) the revision marked with the '@' bookmark, if present
1896 h) the tipmost head of the default branch
1896 h) the tipmost head of the default branch
1897 i) tip
1897 i) tip
1898
1898
1899 When cloning from servers that support it, Mercurial may fetch
1899 When cloning from servers that support it, Mercurial may fetch
1900 pre-generated data from a server-advertised URL or inline from the
1900 pre-generated data from a server-advertised URL or inline from the
1901 same stream. When this is done, hooks operating on incoming changesets
1901 same stream. When this is done, hooks operating on incoming changesets
1902 and changegroups may fire more than once, once for each pre-generated
1902 and changegroups may fire more than once, once for each pre-generated
1903 bundle and as well as for any additional remaining data. In addition,
1903 bundle and as well as for any additional remaining data. In addition,
1904 if an error occurs, the repository may be rolled back to a partial
1904 if an error occurs, the repository may be rolled back to a partial
1905 clone. This behavior may change in future releases.
1905 clone. This behavior may change in future releases.
1906 See :hg:`help -e clonebundles` for more.
1906 See :hg:`help -e clonebundles` for more.
1907
1907
1908 Examples:
1908 Examples:
1909
1909
1910 - clone a remote repository to a new directory named hg/::
1910 - clone a remote repository to a new directory named hg/::
1911
1911
1912 hg clone https://www.mercurial-scm.org/repo/hg/
1912 hg clone https://www.mercurial-scm.org/repo/hg/
1913
1913
1914 - create a lightweight local clone::
1914 - create a lightweight local clone::
1915
1915
1916 hg clone project/ project-feature/
1916 hg clone project/ project-feature/
1917
1917
1918 - clone from an absolute path on an ssh server (note double-slash)::
1918 - clone from an absolute path on an ssh server (note double-slash)::
1919
1919
1920 hg clone ssh://user@server//home/projects/alpha/
1920 hg clone ssh://user@server//home/projects/alpha/
1921
1921
1922 - do a streaming clone while checking out a specified version::
1922 - do a streaming clone while checking out a specified version::
1923
1923
1924 hg clone --stream http://server/repo -u 1.5
1924 hg clone --stream http://server/repo -u 1.5
1925
1925
1926 - create a repository without changesets after a particular revision::
1926 - create a repository without changesets after a particular revision::
1927
1927
1928 hg clone -r 04e544 experimental/ good/
1928 hg clone -r 04e544 experimental/ good/
1929
1929
1930 - clone (and track) a particular named branch::
1930 - clone (and track) a particular named branch::
1931
1931
1932 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1932 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1933
1933
1934 See :hg:`help urls` for details on specifying URLs.
1934 See :hg:`help urls` for details on specifying URLs.
1935
1935
1936 Returns 0 on success.
1936 Returns 0 on success.
1937 """
1937 """
1938 opts = pycompat.byteskwargs(opts)
1938 opts = pycompat.byteskwargs(opts)
1939 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1939 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1940
1940
1941 # --include/--exclude can come from narrow or sparse.
1941 # --include/--exclude can come from narrow or sparse.
1942 includepats, excludepats = None, None
1942 includepats, excludepats = None, None
1943
1943
1944 # hg.clone() differentiates between None and an empty set. So make sure
1944 # hg.clone() differentiates between None and an empty set. So make sure
1945 # patterns are sets if narrow is requested without patterns.
1945 # patterns are sets if narrow is requested without patterns.
1946 if opts.get(b'narrow'):
1946 if opts.get(b'narrow'):
1947 includepats = set()
1947 includepats = set()
1948 excludepats = set()
1948 excludepats = set()
1949
1949
1950 if opts.get(b'include'):
1950 if opts.get(b'include'):
1951 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1951 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1952 if opts.get(b'exclude'):
1952 if opts.get(b'exclude'):
1953 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1953 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1954
1954
1955 r = hg.clone(
1955 r = hg.clone(
1956 ui,
1956 ui,
1957 opts,
1957 opts,
1958 source,
1958 source,
1959 dest,
1959 dest,
1960 pull=opts.get(b'pull'),
1960 pull=opts.get(b'pull'),
1961 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1961 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1962 revs=opts.get(b'rev'),
1962 revs=opts.get(b'rev'),
1963 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1963 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1964 branch=opts.get(b'branch'),
1964 branch=opts.get(b'branch'),
1965 shareopts=opts.get(b'shareopts'),
1965 shareopts=opts.get(b'shareopts'),
1966 storeincludepats=includepats,
1966 storeincludepats=includepats,
1967 storeexcludepats=excludepats,
1967 storeexcludepats=excludepats,
1968 depth=opts.get(b'depth') or None,
1968 depth=opts.get(b'depth') or None,
1969 )
1969 )
1970
1970
1971 return r is None
1971 return r is None
1972
1972
1973
1973
1974 @command(
1974 @command(
1975 b'commit|ci',
1975 b'commit|ci',
1976 [
1976 [
1977 (
1977 (
1978 b'A',
1978 b'A',
1979 b'addremove',
1979 b'addremove',
1980 None,
1980 None,
1981 _(b'mark new/missing files as added/removed before committing'),
1981 _(b'mark new/missing files as added/removed before committing'),
1982 ),
1982 ),
1983 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1983 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1984 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1984 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1985 (b's', b'secret', None, _(b'use the secret phase for committing')),
1985 (b's', b'secret', None, _(b'use the secret phase for committing')),
1986 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1986 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1987 (
1987 (
1988 b'',
1988 b'',
1989 b'force-close-branch',
1989 b'force-close-branch',
1990 None,
1990 None,
1991 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1991 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1992 ),
1992 ),
1993 (b'i', b'interactive', None, _(b'use interactive mode')),
1993 (b'i', b'interactive', None, _(b'use interactive mode')),
1994 ]
1994 ]
1995 + walkopts
1995 + walkopts
1996 + commitopts
1996 + commitopts
1997 + commitopts2
1997 + commitopts2
1998 + subrepoopts,
1998 + subrepoopts,
1999 _(b'[OPTION]... [FILE]...'),
1999 _(b'[OPTION]... [FILE]...'),
2000 helpcategory=command.CATEGORY_COMMITTING,
2000 helpcategory=command.CATEGORY_COMMITTING,
2001 helpbasic=True,
2001 helpbasic=True,
2002 inferrepo=True,
2002 inferrepo=True,
2003 )
2003 )
2004 def commit(ui, repo, *pats, **opts):
2004 def commit(ui, repo, *pats, **opts):
2005 """commit the specified files or all outstanding changes
2005 """commit the specified files or all outstanding changes
2006
2006
2007 Commit changes to the given files into the repository. Unlike a
2007 Commit changes to the given files into the repository. Unlike a
2008 centralized SCM, this operation is a local operation. See
2008 centralized SCM, this operation is a local operation. See
2009 :hg:`push` for a way to actively distribute your changes.
2009 :hg:`push` for a way to actively distribute your changes.
2010
2010
2011 If a list of files is omitted, all changes reported by :hg:`status`
2011 If a list of files is omitted, all changes reported by :hg:`status`
2012 will be committed.
2012 will be committed.
2013
2013
2014 If you are committing the result of a merge, do not provide any
2014 If you are committing the result of a merge, do not provide any
2015 filenames or -I/-X filters.
2015 filenames or -I/-X filters.
2016
2016
2017 If no commit message is specified, Mercurial starts your
2017 If no commit message is specified, Mercurial starts your
2018 configured editor where you can enter a message. In case your
2018 configured editor where you can enter a message. In case your
2019 commit fails, you will find a backup of your message in
2019 commit fails, you will find a backup of your message in
2020 ``.hg/last-message.txt``.
2020 ``.hg/last-message.txt``.
2021
2021
2022 The --close-branch flag can be used to mark the current branch
2022 The --close-branch flag can be used to mark the current branch
2023 head closed. When all heads of a branch are closed, the branch
2023 head closed. When all heads of a branch are closed, the branch
2024 will be considered closed and no longer listed.
2024 will be considered closed and no longer listed.
2025
2025
2026 The --amend flag can be used to amend the parent of the
2026 The --amend flag can be used to amend the parent of the
2027 working directory with a new commit that contains the changes
2027 working directory with a new commit that contains the changes
2028 in the parent in addition to those currently reported by :hg:`status`,
2028 in the parent in addition to those currently reported by :hg:`status`,
2029 if there are any. The old commit is stored in a backup bundle in
2029 if there are any. The old commit is stored in a backup bundle in
2030 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2030 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2031 on how to restore it).
2031 on how to restore it).
2032
2032
2033 Message, user and date are taken from the amended commit unless
2033 Message, user and date are taken from the amended commit unless
2034 specified. When a message isn't specified on the command line,
2034 specified. When a message isn't specified on the command line,
2035 the editor will open with the message of the amended commit.
2035 the editor will open with the message of the amended commit.
2036
2036
2037 It is not possible to amend public changesets (see :hg:`help phases`)
2037 It is not possible to amend public changesets (see :hg:`help phases`)
2038 or changesets that have children.
2038 or changesets that have children.
2039
2039
2040 See :hg:`help dates` for a list of formats valid for -d/--date.
2040 See :hg:`help dates` for a list of formats valid for -d/--date.
2041
2041
2042 Returns 0 on success, 1 if nothing changed.
2042 Returns 0 on success, 1 if nothing changed.
2043
2043
2044 .. container:: verbose
2044 .. container:: verbose
2045
2045
2046 Examples:
2046 Examples:
2047
2047
2048 - commit all files ending in .py::
2048 - commit all files ending in .py::
2049
2049
2050 hg commit --include "set:**.py"
2050 hg commit --include "set:**.py"
2051
2051
2052 - commit all non-binary files::
2052 - commit all non-binary files::
2053
2053
2054 hg commit --exclude "set:binary()"
2054 hg commit --exclude "set:binary()"
2055
2055
2056 - amend the current commit and set the date to now::
2056 - amend the current commit and set the date to now::
2057
2057
2058 hg commit --amend --date now
2058 hg commit --amend --date now
2059 """
2059 """
2060 with repo.wlock(), repo.lock():
2060 with repo.wlock(), repo.lock():
2061 return _docommit(ui, repo, *pats, **opts)
2061 return _docommit(ui, repo, *pats, **opts)
2062
2062
2063
2063
2064 def _docommit(ui, repo, *pats, **opts):
2064 def _docommit(ui, repo, *pats, **opts):
2065 if opts.get('interactive'):
2065 if opts.get('interactive'):
2066 opts.pop('interactive')
2066 opts.pop('interactive')
2067 ret = cmdutil.dorecord(
2067 ret = cmdutil.dorecord(
2068 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2068 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2069 )
2069 )
2070 # ret can be 0 (no changes to record) or the value returned by
2070 # ret can be 0 (no changes to record) or the value returned by
2071 # commit(), 1 if nothing changed or None on success.
2071 # commit(), 1 if nothing changed or None on success.
2072 return 1 if ret == 0 else ret
2072 return 1 if ret == 0 else ret
2073
2073
2074 if opts.get('subrepos'):
2074 if opts.get('subrepos'):
2075 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2075 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2076 # Let --subrepos on the command line override config setting.
2076 # Let --subrepos on the command line override config setting.
2077 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2077 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2078
2078
2079 cmdutil.checkunfinished(repo, commit=True)
2079 cmdutil.checkunfinished(repo, commit=True)
2080
2080
2081 branch = repo[None].branch()
2081 branch = repo[None].branch()
2082 bheads = repo.branchheads(branch)
2082 bheads = repo.branchheads(branch)
2083 tip = repo.changelog.tip()
2083 tip = repo.changelog.tip()
2084
2084
2085 extra = {}
2085 extra = {}
2086 if opts.get('close_branch') or opts.get('force_close_branch'):
2086 if opts.get('close_branch') or opts.get('force_close_branch'):
2087 extra[b'close'] = b'1'
2087 extra[b'close'] = b'1'
2088
2088
2089 if repo[b'.'].closesbranch():
2089 if repo[b'.'].closesbranch():
2090 raise error.InputError(
2090 # Not ideal, but let us do an extra status early to prevent early
2091 _(b'current revision is already a branch closing head')
2091 # bail out.
2092 )
2092 matcher = scmutil.match(repo[None], pats, opts)
2093 elif not bheads:
2093 s = repo.status(match=matcher)
2094 if s.modified or s.added or s.removed:
2095 bheads = repo.branchheads(branch, closed=True)
2096 else:
2097 msg = _(b'current revision is already a branch closing head')
2098 raise error.InputError(msg)
2099
2100 if not bheads:
2094 raise error.InputError(
2101 raise error.InputError(
2095 _(b'branch "%s" has no heads to close') % branch
2102 _(b'branch "%s" has no heads to close') % branch
2096 )
2103 )
2097 elif (
2104 elif (
2098 branch == repo[b'.'].branch()
2105 branch == repo[b'.'].branch()
2099 and repo[b'.'].node() not in bheads
2106 and repo[b'.'].node() not in bheads
2100 and not opts.get('force_close_branch')
2107 and not opts.get('force_close_branch')
2101 ):
2108 ):
2102 hint = _(
2109 hint = _(
2103 b'use --force-close-branch to close branch from a non-head'
2110 b'use --force-close-branch to close branch from a non-head'
2104 b' changeset'
2111 b' changeset'
2105 )
2112 )
2106 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2113 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2107 elif opts.get('amend'):
2114 elif opts.get('amend'):
2108 if (
2115 if (
2109 repo[b'.'].p1().branch() != branch
2116 repo[b'.'].p1().branch() != branch
2110 and repo[b'.'].p2().branch() != branch
2117 and repo[b'.'].p2().branch() != branch
2111 ):
2118 ):
2112 raise error.InputError(_(b'can only close branch heads'))
2119 raise error.InputError(_(b'can only close branch heads'))
2113
2120
2114 if opts.get('amend'):
2121 if opts.get('amend'):
2115 if ui.configbool(b'ui', b'commitsubrepos'):
2122 if ui.configbool(b'ui', b'commitsubrepos'):
2116 raise error.InputError(
2123 raise error.InputError(
2117 _(b'cannot amend with ui.commitsubrepos enabled')
2124 _(b'cannot amend with ui.commitsubrepos enabled')
2118 )
2125 )
2119
2126
2120 old = repo[b'.']
2127 old = repo[b'.']
2121 rewriteutil.precheck(repo, [old.rev()], b'amend')
2128 rewriteutil.precheck(repo, [old.rev()], b'amend')
2122
2129
2123 # Currently histedit gets confused if an amend happens while histedit
2130 # Currently histedit gets confused if an amend happens while histedit
2124 # is in progress. Since we have a checkunfinished command, we are
2131 # is in progress. Since we have a checkunfinished command, we are
2125 # temporarily honoring it.
2132 # temporarily honoring it.
2126 #
2133 #
2127 # Note: eventually this guard will be removed. Please do not expect
2134 # Note: eventually this guard will be removed. Please do not expect
2128 # this behavior to remain.
2135 # this behavior to remain.
2129 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2136 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2130 cmdutil.checkunfinished(repo)
2137 cmdutil.checkunfinished(repo)
2131
2138
2132 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2139 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2133 opts = pycompat.byteskwargs(opts)
2140 opts = pycompat.byteskwargs(opts)
2134 if node == old.node():
2141 if node == old.node():
2135 ui.status(_(b"nothing changed\n"))
2142 ui.status(_(b"nothing changed\n"))
2136 return 1
2143 return 1
2137 else:
2144 else:
2138
2145
2139 def commitfunc(ui, repo, message, match, opts):
2146 def commitfunc(ui, repo, message, match, opts):
2140 overrides = {}
2147 overrides = {}
2141 if opts.get(b'secret'):
2148 if opts.get(b'secret'):
2142 overrides[(b'phases', b'new-commit')] = b'secret'
2149 overrides[(b'phases', b'new-commit')] = b'secret'
2143
2150
2144 baseui = repo.baseui
2151 baseui = repo.baseui
2145 with baseui.configoverride(overrides, b'commit'):
2152 with baseui.configoverride(overrides, b'commit'):
2146 with ui.configoverride(overrides, b'commit'):
2153 with ui.configoverride(overrides, b'commit'):
2147 editform = cmdutil.mergeeditform(
2154 editform = cmdutil.mergeeditform(
2148 repo[None], b'commit.normal'
2155 repo[None], b'commit.normal'
2149 )
2156 )
2150 editor = cmdutil.getcommiteditor(
2157 editor = cmdutil.getcommiteditor(
2151 editform=editform, **pycompat.strkwargs(opts)
2158 editform=editform, **pycompat.strkwargs(opts)
2152 )
2159 )
2153 return repo.commit(
2160 return repo.commit(
2154 message,
2161 message,
2155 opts.get(b'user'),
2162 opts.get(b'user'),
2156 opts.get(b'date'),
2163 opts.get(b'date'),
2157 match,
2164 match,
2158 editor=editor,
2165 editor=editor,
2159 extra=extra,
2166 extra=extra,
2160 )
2167 )
2161
2168
2162 opts = pycompat.byteskwargs(opts)
2169 opts = pycompat.byteskwargs(opts)
2163 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2170 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2164
2171
2165 if not node:
2172 if not node:
2166 stat = cmdutil.postcommitstatus(repo, pats, opts)
2173 stat = cmdutil.postcommitstatus(repo, pats, opts)
2167 if stat.deleted:
2174 if stat.deleted:
2168 ui.status(
2175 ui.status(
2169 _(
2176 _(
2170 b"nothing changed (%d missing files, see "
2177 b"nothing changed (%d missing files, see "
2171 b"'hg status')\n"
2178 b"'hg status')\n"
2172 )
2179 )
2173 % len(stat.deleted)
2180 % len(stat.deleted)
2174 )
2181 )
2175 else:
2182 else:
2176 ui.status(_(b"nothing changed\n"))
2183 ui.status(_(b"nothing changed\n"))
2177 return 1
2184 return 1
2178
2185
2179 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2186 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2180
2187
2181 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2188 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2182 status(
2189 status(
2183 ui,
2190 ui,
2184 repo,
2191 repo,
2185 modified=True,
2192 modified=True,
2186 added=True,
2193 added=True,
2187 removed=True,
2194 removed=True,
2188 deleted=True,
2195 deleted=True,
2189 unknown=True,
2196 unknown=True,
2190 subrepos=opts.get(b'subrepos'),
2197 subrepos=opts.get(b'subrepos'),
2191 )
2198 )
2192
2199
2193
2200
2194 @command(
2201 @command(
2195 b'config|showconfig|debugconfig',
2202 b'config|showconfig|debugconfig',
2196 [
2203 [
2197 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2204 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2198 # This is experimental because we need
2205 # This is experimental because we need
2199 # * reasonable behavior around aliases,
2206 # * reasonable behavior around aliases,
2200 # * decide if we display [debug] [experimental] and [devel] section par
2207 # * decide if we display [debug] [experimental] and [devel] section par
2201 # default
2208 # default
2202 # * some way to display "generic" config entry (the one matching
2209 # * some way to display "generic" config entry (the one matching
2203 # regexp,
2210 # regexp,
2204 # * proper display of the different value type
2211 # * proper display of the different value type
2205 # * a better way to handle <DYNAMIC> values (and variable types),
2212 # * a better way to handle <DYNAMIC> values (and variable types),
2206 # * maybe some type information ?
2213 # * maybe some type information ?
2207 (
2214 (
2208 b'',
2215 b'',
2209 b'exp-all-known',
2216 b'exp-all-known',
2210 None,
2217 None,
2211 _(b'show all known config option (EXPERIMENTAL)'),
2218 _(b'show all known config option (EXPERIMENTAL)'),
2212 ),
2219 ),
2213 (b'e', b'edit', None, _(b'edit user config')),
2220 (b'e', b'edit', None, _(b'edit user config')),
2214 (b'l', b'local', None, _(b'edit repository config')),
2221 (b'l', b'local', None, _(b'edit repository config')),
2215 (b'', b'source', None, _(b'show source of configuration value')),
2222 (b'', b'source', None, _(b'show source of configuration value')),
2216 (
2223 (
2217 b'',
2224 b'',
2218 b'shared',
2225 b'shared',
2219 None,
2226 None,
2220 _(b'edit shared source repository config (EXPERIMENTAL)'),
2227 _(b'edit shared source repository config (EXPERIMENTAL)'),
2221 ),
2228 ),
2222 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2229 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2223 (b'g', b'global', None, _(b'edit global config')),
2230 (b'g', b'global', None, _(b'edit global config')),
2224 ]
2231 ]
2225 + formatteropts,
2232 + formatteropts,
2226 _(b'[-u] [NAME]...'),
2233 _(b'[-u] [NAME]...'),
2227 helpcategory=command.CATEGORY_HELP,
2234 helpcategory=command.CATEGORY_HELP,
2228 optionalrepo=True,
2235 optionalrepo=True,
2229 intents={INTENT_READONLY},
2236 intents={INTENT_READONLY},
2230 )
2237 )
2231 def config(ui, repo, *values, **opts):
2238 def config(ui, repo, *values, **opts):
2232 """show combined config settings from all hgrc files
2239 """show combined config settings from all hgrc files
2233
2240
2234 With no arguments, print names and values of all config items.
2241 With no arguments, print names and values of all config items.
2235
2242
2236 With one argument of the form section.name, print just the value
2243 With one argument of the form section.name, print just the value
2237 of that config item.
2244 of that config item.
2238
2245
2239 With multiple arguments, print names and values of all config
2246 With multiple arguments, print names and values of all config
2240 items with matching section names or section.names.
2247 items with matching section names or section.names.
2241
2248
2242 With --edit, start an editor on the user-level config file. With
2249 With --edit, start an editor on the user-level config file. With
2243 --global, edit the system-wide config file. With --local, edit the
2250 --global, edit the system-wide config file. With --local, edit the
2244 repository-level config file.
2251 repository-level config file.
2245
2252
2246 With --source, the source (filename and line number) is printed
2253 With --source, the source (filename and line number) is printed
2247 for each config item.
2254 for each config item.
2248
2255
2249 See :hg:`help config` for more information about config files.
2256 See :hg:`help config` for more information about config files.
2250
2257
2251 .. container:: verbose
2258 .. container:: verbose
2252
2259
2253 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2260 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2254 This file is not shared across shares when in share-safe mode.
2261 This file is not shared across shares when in share-safe mode.
2255
2262
2256 Template:
2263 Template:
2257
2264
2258 The following keywords are supported. See also :hg:`help templates`.
2265 The following keywords are supported. See also :hg:`help templates`.
2259
2266
2260 :name: String. Config name.
2267 :name: String. Config name.
2261 :source: String. Filename and line number where the item is defined.
2268 :source: String. Filename and line number where the item is defined.
2262 :value: String. Config value.
2269 :value: String. Config value.
2263
2270
2264 The --shared flag can be used to edit the config file of shared source
2271 The --shared flag can be used to edit the config file of shared source
2265 repository. It only works when you have shared using the experimental
2272 repository. It only works when you have shared using the experimental
2266 share safe feature.
2273 share safe feature.
2267
2274
2268 Returns 0 on success, 1 if NAME does not exist.
2275 Returns 0 on success, 1 if NAME does not exist.
2269
2276
2270 """
2277 """
2271
2278
2272 opts = pycompat.byteskwargs(opts)
2279 opts = pycompat.byteskwargs(opts)
2273 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2280 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2274 if any(opts.get(o) for o in editopts):
2281 if any(opts.get(o) for o in editopts):
2275 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2282 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2276 if opts.get(b'local'):
2283 if opts.get(b'local'):
2277 if not repo:
2284 if not repo:
2278 raise error.InputError(
2285 raise error.InputError(
2279 _(b"can't use --local outside a repository")
2286 _(b"can't use --local outside a repository")
2280 )
2287 )
2281 paths = [repo.vfs.join(b'hgrc')]
2288 paths = [repo.vfs.join(b'hgrc')]
2282 elif opts.get(b'global'):
2289 elif opts.get(b'global'):
2283 paths = rcutil.systemrcpath()
2290 paths = rcutil.systemrcpath()
2284 elif opts.get(b'shared'):
2291 elif opts.get(b'shared'):
2285 if not repo.shared():
2292 if not repo.shared():
2286 raise error.InputError(
2293 raise error.InputError(
2287 _(b"repository is not shared; can't use --shared")
2294 _(b"repository is not shared; can't use --shared")
2288 )
2295 )
2289 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2296 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2290 raise error.InputError(
2297 raise error.InputError(
2291 _(
2298 _(
2292 b"share safe feature not enabled; "
2299 b"share safe feature not enabled; "
2293 b"unable to edit shared source repository config"
2300 b"unable to edit shared source repository config"
2294 )
2301 )
2295 )
2302 )
2296 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2303 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2297 elif opts.get(b'non_shared'):
2304 elif opts.get(b'non_shared'):
2298 paths = [repo.vfs.join(b'hgrc-not-shared')]
2305 paths = [repo.vfs.join(b'hgrc-not-shared')]
2299 else:
2306 else:
2300 paths = rcutil.userrcpath()
2307 paths = rcutil.userrcpath()
2301
2308
2302 for f in paths:
2309 for f in paths:
2303 if os.path.exists(f):
2310 if os.path.exists(f):
2304 break
2311 break
2305 else:
2312 else:
2306 if opts.get(b'global'):
2313 if opts.get(b'global'):
2307 samplehgrc = uimod.samplehgrcs[b'global']
2314 samplehgrc = uimod.samplehgrcs[b'global']
2308 elif opts.get(b'local'):
2315 elif opts.get(b'local'):
2309 samplehgrc = uimod.samplehgrcs[b'local']
2316 samplehgrc = uimod.samplehgrcs[b'local']
2310 else:
2317 else:
2311 samplehgrc = uimod.samplehgrcs[b'user']
2318 samplehgrc = uimod.samplehgrcs[b'user']
2312
2319
2313 f = paths[0]
2320 f = paths[0]
2314 fp = open(f, b"wb")
2321 fp = open(f, b"wb")
2315 fp.write(util.tonativeeol(samplehgrc))
2322 fp.write(util.tonativeeol(samplehgrc))
2316 fp.close()
2323 fp.close()
2317
2324
2318 editor = ui.geteditor()
2325 editor = ui.geteditor()
2319 ui.system(
2326 ui.system(
2320 b"%s \"%s\"" % (editor, f),
2327 b"%s \"%s\"" % (editor, f),
2321 onerr=error.InputError,
2328 onerr=error.InputError,
2322 errprefix=_(b"edit failed"),
2329 errprefix=_(b"edit failed"),
2323 blockedtag=b'config_edit',
2330 blockedtag=b'config_edit',
2324 )
2331 )
2325 return
2332 return
2326 ui.pager(b'config')
2333 ui.pager(b'config')
2327 fm = ui.formatter(b'config', opts)
2334 fm = ui.formatter(b'config', opts)
2328 for t, f in rcutil.rccomponents():
2335 for t, f in rcutil.rccomponents():
2329 if t == b'path':
2336 if t == b'path':
2330 ui.debug(b'read config from: %s\n' % f)
2337 ui.debug(b'read config from: %s\n' % f)
2331 elif t == b'resource':
2338 elif t == b'resource':
2332 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2339 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2333 elif t == b'items':
2340 elif t == b'items':
2334 # Don't print anything for 'items'.
2341 # Don't print anything for 'items'.
2335 pass
2342 pass
2336 else:
2343 else:
2337 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2344 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2338 untrusted = bool(opts.get(b'untrusted'))
2345 untrusted = bool(opts.get(b'untrusted'))
2339
2346
2340 selsections = selentries = []
2347 selsections = selentries = []
2341 if values:
2348 if values:
2342 selsections = [v for v in values if b'.' not in v]
2349 selsections = [v for v in values if b'.' not in v]
2343 selentries = [v for v in values if b'.' in v]
2350 selentries = [v for v in values if b'.' in v]
2344 uniquesel = len(selentries) == 1 and not selsections
2351 uniquesel = len(selentries) == 1 and not selsections
2345 selsections = set(selsections)
2352 selsections = set(selsections)
2346 selentries = set(selentries)
2353 selentries = set(selentries)
2347
2354
2348 matched = False
2355 matched = False
2349 all_known = opts[b'exp_all_known']
2356 all_known = opts[b'exp_all_known']
2350 show_source = ui.debugflag or opts.get(b'source')
2357 show_source = ui.debugflag or opts.get(b'source')
2351 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2358 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2352 for section, name, value in entries:
2359 for section, name, value in entries:
2353 source = ui.configsource(section, name, untrusted)
2360 source = ui.configsource(section, name, untrusted)
2354 value = pycompat.bytestr(value)
2361 value = pycompat.bytestr(value)
2355 defaultvalue = ui.configdefault(section, name)
2362 defaultvalue = ui.configdefault(section, name)
2356 if fm.isplain():
2363 if fm.isplain():
2357 source = source or b'none'
2364 source = source or b'none'
2358 value = value.replace(b'\n', b'\\n')
2365 value = value.replace(b'\n', b'\\n')
2359 entryname = section + b'.' + name
2366 entryname = section + b'.' + name
2360 if values and not (section in selsections or entryname in selentries):
2367 if values and not (section in selsections or entryname in selentries):
2361 continue
2368 continue
2362 fm.startitem()
2369 fm.startitem()
2363 fm.condwrite(show_source, b'source', b'%s: ', source)
2370 fm.condwrite(show_source, b'source', b'%s: ', source)
2364 if uniquesel:
2371 if uniquesel:
2365 fm.data(name=entryname)
2372 fm.data(name=entryname)
2366 fm.write(b'value', b'%s\n', value)
2373 fm.write(b'value', b'%s\n', value)
2367 else:
2374 else:
2368 fm.write(b'name value', b'%s=%s\n', entryname, value)
2375 fm.write(b'name value', b'%s=%s\n', entryname, value)
2369 if formatter.isprintable(defaultvalue):
2376 if formatter.isprintable(defaultvalue):
2370 fm.data(defaultvalue=defaultvalue)
2377 fm.data(defaultvalue=defaultvalue)
2371 elif isinstance(defaultvalue, list) and all(
2378 elif isinstance(defaultvalue, list) and all(
2372 formatter.isprintable(e) for e in defaultvalue
2379 formatter.isprintable(e) for e in defaultvalue
2373 ):
2380 ):
2374 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2381 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2375 # TODO: no idea how to process unsupported defaultvalue types
2382 # TODO: no idea how to process unsupported defaultvalue types
2376 matched = True
2383 matched = True
2377 fm.end()
2384 fm.end()
2378 if matched:
2385 if matched:
2379 return 0
2386 return 0
2380 return 1
2387 return 1
2381
2388
2382
2389
2383 @command(
2390 @command(
2384 b'continue',
2391 b'continue',
2385 dryrunopts,
2392 dryrunopts,
2386 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2393 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2387 helpbasic=True,
2394 helpbasic=True,
2388 )
2395 )
2389 def continuecmd(ui, repo, **opts):
2396 def continuecmd(ui, repo, **opts):
2390 """resumes an interrupted operation (EXPERIMENTAL)
2397 """resumes an interrupted operation (EXPERIMENTAL)
2391
2398
2392 Finishes a multistep operation like graft, histedit, rebase, merge,
2399 Finishes a multistep operation like graft, histedit, rebase, merge,
2393 and unshelve if they are in an interrupted state.
2400 and unshelve if they are in an interrupted state.
2394
2401
2395 use --dry-run/-n to dry run the command.
2402 use --dry-run/-n to dry run the command.
2396 """
2403 """
2397 dryrun = opts.get('dry_run')
2404 dryrun = opts.get('dry_run')
2398 contstate = cmdutil.getunfinishedstate(repo)
2405 contstate = cmdutil.getunfinishedstate(repo)
2399 if not contstate:
2406 if not contstate:
2400 raise error.StateError(_(b'no operation in progress'))
2407 raise error.StateError(_(b'no operation in progress'))
2401 if not contstate.continuefunc:
2408 if not contstate.continuefunc:
2402 raise error.StateError(
2409 raise error.StateError(
2403 (
2410 (
2404 _(b"%s in progress but does not support 'hg continue'")
2411 _(b"%s in progress but does not support 'hg continue'")
2405 % (contstate._opname)
2412 % (contstate._opname)
2406 ),
2413 ),
2407 hint=contstate.continuemsg(),
2414 hint=contstate.continuemsg(),
2408 )
2415 )
2409 if dryrun:
2416 if dryrun:
2410 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2417 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2411 return
2418 return
2412 return contstate.continuefunc(ui, repo)
2419 return contstate.continuefunc(ui, repo)
2413
2420
2414
2421
2415 @command(
2422 @command(
2416 b'copy|cp',
2423 b'copy|cp',
2417 [
2424 [
2418 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2425 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2419 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2426 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2420 (
2427 (
2421 b'',
2428 b'',
2422 b'at-rev',
2429 b'at-rev',
2423 b'',
2430 b'',
2424 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2431 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2425 _(b'REV'),
2432 _(b'REV'),
2426 ),
2433 ),
2427 (
2434 (
2428 b'f',
2435 b'f',
2429 b'force',
2436 b'force',
2430 None,
2437 None,
2431 _(b'forcibly copy over an existing managed file'),
2438 _(b'forcibly copy over an existing managed file'),
2432 ),
2439 ),
2433 ]
2440 ]
2434 + walkopts
2441 + walkopts
2435 + dryrunopts,
2442 + dryrunopts,
2436 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2443 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2437 helpcategory=command.CATEGORY_FILE_CONTENTS,
2444 helpcategory=command.CATEGORY_FILE_CONTENTS,
2438 )
2445 )
2439 def copy(ui, repo, *pats, **opts):
2446 def copy(ui, repo, *pats, **opts):
2440 """mark files as copied for the next commit
2447 """mark files as copied for the next commit
2441
2448
2442 Mark dest as having copies of source files. If dest is a
2449 Mark dest as having copies of source files. If dest is a
2443 directory, copies are put in that directory. If dest is a file,
2450 directory, copies are put in that directory. If dest is a file,
2444 the source must be a single file.
2451 the source must be a single file.
2445
2452
2446 By default, this command copies the contents of files as they
2453 By default, this command copies the contents of files as they
2447 exist in the working directory. If invoked with -A/--after, the
2454 exist in the working directory. If invoked with -A/--after, the
2448 operation is recorded, but no copying is performed.
2455 operation is recorded, but no copying is performed.
2449
2456
2450 To undo marking a destination file as copied, use --forget. With that
2457 To undo marking a destination file as copied, use --forget. With that
2451 option, all given (positional) arguments are unmarked as copies. The
2458 option, all given (positional) arguments are unmarked as copies. The
2452 destination file(s) will be left in place (still tracked). Note that
2459 destination file(s) will be left in place (still tracked). Note that
2453 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2460 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2454
2461
2455 This command takes effect with the next commit by default.
2462 This command takes effect with the next commit by default.
2456
2463
2457 Returns 0 on success, 1 if errors are encountered.
2464 Returns 0 on success, 1 if errors are encountered.
2458 """
2465 """
2459 opts = pycompat.byteskwargs(opts)
2466 opts = pycompat.byteskwargs(opts)
2460 with repo.wlock():
2467 with repo.wlock():
2461 return cmdutil.copy(ui, repo, pats, opts)
2468 return cmdutil.copy(ui, repo, pats, opts)
2462
2469
2463
2470
2464 @command(
2471 @command(
2465 b'debugcommands',
2472 b'debugcommands',
2466 [],
2473 [],
2467 _(b'[COMMAND]'),
2474 _(b'[COMMAND]'),
2468 helpcategory=command.CATEGORY_HELP,
2475 helpcategory=command.CATEGORY_HELP,
2469 norepo=True,
2476 norepo=True,
2470 )
2477 )
2471 def debugcommands(ui, cmd=b'', *args):
2478 def debugcommands(ui, cmd=b'', *args):
2472 """list all available commands and options"""
2479 """list all available commands and options"""
2473 for cmd, vals in sorted(pycompat.iteritems(table)):
2480 for cmd, vals in sorted(pycompat.iteritems(table)):
2474 cmd = cmd.split(b'|')[0]
2481 cmd = cmd.split(b'|')[0]
2475 opts = b', '.join([i[1] for i in vals[1]])
2482 opts = b', '.join([i[1] for i in vals[1]])
2476 ui.write(b'%s: %s\n' % (cmd, opts))
2483 ui.write(b'%s: %s\n' % (cmd, opts))
2477
2484
2478
2485
2479 @command(
2486 @command(
2480 b'debugcomplete',
2487 b'debugcomplete',
2481 [(b'o', b'options', None, _(b'show the command options'))],
2488 [(b'o', b'options', None, _(b'show the command options'))],
2482 _(b'[-o] CMD'),
2489 _(b'[-o] CMD'),
2483 helpcategory=command.CATEGORY_HELP,
2490 helpcategory=command.CATEGORY_HELP,
2484 norepo=True,
2491 norepo=True,
2485 )
2492 )
2486 def debugcomplete(ui, cmd=b'', **opts):
2493 def debugcomplete(ui, cmd=b'', **opts):
2487 """returns the completion list associated with the given command"""
2494 """returns the completion list associated with the given command"""
2488
2495
2489 if opts.get('options'):
2496 if opts.get('options'):
2490 options = []
2497 options = []
2491 otables = [globalopts]
2498 otables = [globalopts]
2492 if cmd:
2499 if cmd:
2493 aliases, entry = cmdutil.findcmd(cmd, table, False)
2500 aliases, entry = cmdutil.findcmd(cmd, table, False)
2494 otables.append(entry[1])
2501 otables.append(entry[1])
2495 for t in otables:
2502 for t in otables:
2496 for o in t:
2503 for o in t:
2497 if b"(DEPRECATED)" in o[3]:
2504 if b"(DEPRECATED)" in o[3]:
2498 continue
2505 continue
2499 if o[0]:
2506 if o[0]:
2500 options.append(b'-%s' % o[0])
2507 options.append(b'-%s' % o[0])
2501 options.append(b'--%s' % o[1])
2508 options.append(b'--%s' % o[1])
2502 ui.write(b"%s\n" % b"\n".join(options))
2509 ui.write(b"%s\n" % b"\n".join(options))
2503 return
2510 return
2504
2511
2505 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2512 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2506 if ui.verbose:
2513 if ui.verbose:
2507 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2514 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2508 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2515 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2509
2516
2510
2517
2511 @command(
2518 @command(
2512 b'diff',
2519 b'diff',
2513 [
2520 [
2514 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2521 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2515 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2522 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2516 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2523 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2517 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2524 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2518 ]
2525 ]
2519 + diffopts
2526 + diffopts
2520 + diffopts2
2527 + diffopts2
2521 + walkopts
2528 + walkopts
2522 + subrepoopts,
2529 + subrepoopts,
2523 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2530 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2524 helpcategory=command.CATEGORY_FILE_CONTENTS,
2531 helpcategory=command.CATEGORY_FILE_CONTENTS,
2525 helpbasic=True,
2532 helpbasic=True,
2526 inferrepo=True,
2533 inferrepo=True,
2527 intents={INTENT_READONLY},
2534 intents={INTENT_READONLY},
2528 )
2535 )
2529 def diff(ui, repo, *pats, **opts):
2536 def diff(ui, repo, *pats, **opts):
2530 """diff repository (or selected files)
2537 """diff repository (or selected files)
2531
2538
2532 Show differences between revisions for the specified files.
2539 Show differences between revisions for the specified files.
2533
2540
2534 Differences between files are shown using the unified diff format.
2541 Differences between files are shown using the unified diff format.
2535
2542
2536 .. note::
2543 .. note::
2537
2544
2538 :hg:`diff` may generate unexpected results for merges, as it will
2545 :hg:`diff` may generate unexpected results for merges, as it will
2539 default to comparing against the working directory's first
2546 default to comparing against the working directory's first
2540 parent changeset if no revisions are specified.
2547 parent changeset if no revisions are specified.
2541
2548
2542 By default, the working directory files are compared to its first parent. To
2549 By default, the working directory files are compared to its first parent. To
2543 see the differences from another revision, use --from. To see the difference
2550 see the differences from another revision, use --from. To see the difference
2544 to another revision, use --to. For example, :hg:`diff --from .^` will show
2551 to another revision, use --to. For example, :hg:`diff --from .^` will show
2545 the differences from the working copy's grandparent to the working copy,
2552 the differences from the working copy's grandparent to the working copy,
2546 :hg:`diff --to .` will show the diff from the working copy to its parent
2553 :hg:`diff --to .` will show the diff from the working copy to its parent
2547 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2554 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2548 show the diff between those two revisions.
2555 show the diff between those two revisions.
2549
2556
2550 Alternatively you can specify -c/--change with a revision to see the changes
2557 Alternatively you can specify -c/--change with a revision to see the changes
2551 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2558 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2552 equivalent to :hg:`diff --from 42^ --to 42`)
2559 equivalent to :hg:`diff --from 42^ --to 42`)
2553
2560
2554 Without the -a/--text option, diff will avoid generating diffs of
2561 Without the -a/--text option, diff will avoid generating diffs of
2555 files it detects as binary. With -a, diff will generate a diff
2562 files it detects as binary. With -a, diff will generate a diff
2556 anyway, probably with undesirable results.
2563 anyway, probably with undesirable results.
2557
2564
2558 Use the -g/--git option to generate diffs in the git extended diff
2565 Use the -g/--git option to generate diffs in the git extended diff
2559 format. For more information, read :hg:`help diffs`.
2566 format. For more information, read :hg:`help diffs`.
2560
2567
2561 .. container:: verbose
2568 .. container:: verbose
2562
2569
2563 Examples:
2570 Examples:
2564
2571
2565 - compare a file in the current working directory to its parent::
2572 - compare a file in the current working directory to its parent::
2566
2573
2567 hg diff foo.c
2574 hg diff foo.c
2568
2575
2569 - compare two historical versions of a directory, with rename info::
2576 - compare two historical versions of a directory, with rename info::
2570
2577
2571 hg diff --git --from 1.0 --to 1.2 lib/
2578 hg diff --git --from 1.0 --to 1.2 lib/
2572
2579
2573 - get change stats relative to the last change on some date::
2580 - get change stats relative to the last change on some date::
2574
2581
2575 hg diff --stat --from "date('may 2')"
2582 hg diff --stat --from "date('may 2')"
2576
2583
2577 - diff all newly-added files that contain a keyword::
2584 - diff all newly-added files that contain a keyword::
2578
2585
2579 hg diff "set:added() and grep(GNU)"
2586 hg diff "set:added() and grep(GNU)"
2580
2587
2581 - compare a revision and its parents::
2588 - compare a revision and its parents::
2582
2589
2583 hg diff -c 9353 # compare against first parent
2590 hg diff -c 9353 # compare against first parent
2584 hg diff --from 9353^ --to 9353 # same using revset syntax
2591 hg diff --from 9353^ --to 9353 # same using revset syntax
2585 hg diff --from 9353^2 --to 9353 # compare against the second parent
2592 hg diff --from 9353^2 --to 9353 # compare against the second parent
2586
2593
2587 Returns 0 on success.
2594 Returns 0 on success.
2588 """
2595 """
2589
2596
2590 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2597 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2591 opts = pycompat.byteskwargs(opts)
2598 opts = pycompat.byteskwargs(opts)
2592 revs = opts.get(b'rev')
2599 revs = opts.get(b'rev')
2593 change = opts.get(b'change')
2600 change = opts.get(b'change')
2594 from_rev = opts.get(b'from')
2601 from_rev = opts.get(b'from')
2595 to_rev = opts.get(b'to')
2602 to_rev = opts.get(b'to')
2596 stat = opts.get(b'stat')
2603 stat = opts.get(b'stat')
2597 reverse = opts.get(b'reverse')
2604 reverse = opts.get(b'reverse')
2598
2605
2599 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2606 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2600 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2607 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2601 if change:
2608 if change:
2602 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2609 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2603 ctx2 = logcmdutil.revsingle(repo, change, None)
2610 ctx2 = logcmdutil.revsingle(repo, change, None)
2604 ctx1 = logcmdutil.diff_parent(ctx2)
2611 ctx1 = logcmdutil.diff_parent(ctx2)
2605 elif from_rev or to_rev:
2612 elif from_rev or to_rev:
2606 repo = scmutil.unhidehashlikerevs(
2613 repo = scmutil.unhidehashlikerevs(
2607 repo, [from_rev] + [to_rev], b'nowarn'
2614 repo, [from_rev] + [to_rev], b'nowarn'
2608 )
2615 )
2609 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2616 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2610 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2617 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2611 else:
2618 else:
2612 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2619 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2613 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2620 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2614
2621
2615 if reverse:
2622 if reverse:
2616 ctxleft = ctx2
2623 ctxleft = ctx2
2617 ctxright = ctx1
2624 ctxright = ctx1
2618 else:
2625 else:
2619 ctxleft = ctx1
2626 ctxleft = ctx1
2620 ctxright = ctx2
2627 ctxright = ctx2
2621
2628
2622 diffopts = patch.diffallopts(ui, opts)
2629 diffopts = patch.diffallopts(ui, opts)
2623 m = scmutil.match(ctx2, pats, opts)
2630 m = scmutil.match(ctx2, pats, opts)
2624 m = repo.narrowmatch(m)
2631 m = repo.narrowmatch(m)
2625 ui.pager(b'diff')
2632 ui.pager(b'diff')
2626 logcmdutil.diffordiffstat(
2633 logcmdutil.diffordiffstat(
2627 ui,
2634 ui,
2628 repo,
2635 repo,
2629 diffopts,
2636 diffopts,
2630 ctxleft,
2637 ctxleft,
2631 ctxright,
2638 ctxright,
2632 m,
2639 m,
2633 stat=stat,
2640 stat=stat,
2634 listsubrepos=opts.get(b'subrepos'),
2641 listsubrepos=opts.get(b'subrepos'),
2635 root=opts.get(b'root'),
2642 root=opts.get(b'root'),
2636 )
2643 )
2637
2644
2638
2645
2639 @command(
2646 @command(
2640 b'export',
2647 b'export',
2641 [
2648 [
2642 (
2649 (
2643 b'B',
2650 b'B',
2644 b'bookmark',
2651 b'bookmark',
2645 b'',
2652 b'',
2646 _(b'export changes only reachable by given bookmark'),
2653 _(b'export changes only reachable by given bookmark'),
2647 _(b'BOOKMARK'),
2654 _(b'BOOKMARK'),
2648 ),
2655 ),
2649 (
2656 (
2650 b'o',
2657 b'o',
2651 b'output',
2658 b'output',
2652 b'',
2659 b'',
2653 _(b'print output to file with formatted name'),
2660 _(b'print output to file with formatted name'),
2654 _(b'FORMAT'),
2661 _(b'FORMAT'),
2655 ),
2662 ),
2656 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2663 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2657 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2664 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2658 ]
2665 ]
2659 + diffopts
2666 + diffopts
2660 + formatteropts,
2667 + formatteropts,
2661 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2668 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2662 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2669 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2663 helpbasic=True,
2670 helpbasic=True,
2664 intents={INTENT_READONLY},
2671 intents={INTENT_READONLY},
2665 )
2672 )
2666 def export(ui, repo, *changesets, **opts):
2673 def export(ui, repo, *changesets, **opts):
2667 """dump the header and diffs for one or more changesets
2674 """dump the header and diffs for one or more changesets
2668
2675
2669 Print the changeset header and diffs for one or more revisions.
2676 Print the changeset header and diffs for one or more revisions.
2670 If no revision is given, the parent of the working directory is used.
2677 If no revision is given, the parent of the working directory is used.
2671
2678
2672 The information shown in the changeset header is: author, date,
2679 The information shown in the changeset header is: author, date,
2673 branch name (if non-default), changeset hash, parent(s) and commit
2680 branch name (if non-default), changeset hash, parent(s) and commit
2674 comment.
2681 comment.
2675
2682
2676 .. note::
2683 .. note::
2677
2684
2678 :hg:`export` may generate unexpected diff output for merge
2685 :hg:`export` may generate unexpected diff output for merge
2679 changesets, as it will compare the merge changeset against its
2686 changesets, as it will compare the merge changeset against its
2680 first parent only.
2687 first parent only.
2681
2688
2682 Output may be to a file, in which case the name of the file is
2689 Output may be to a file, in which case the name of the file is
2683 given using a template string. See :hg:`help templates`. In addition
2690 given using a template string. See :hg:`help templates`. In addition
2684 to the common template keywords, the following formatting rules are
2691 to the common template keywords, the following formatting rules are
2685 supported:
2692 supported:
2686
2693
2687 :``%%``: literal "%" character
2694 :``%%``: literal "%" character
2688 :``%H``: changeset hash (40 hexadecimal digits)
2695 :``%H``: changeset hash (40 hexadecimal digits)
2689 :``%N``: number of patches being generated
2696 :``%N``: number of patches being generated
2690 :``%R``: changeset revision number
2697 :``%R``: changeset revision number
2691 :``%b``: basename of the exporting repository
2698 :``%b``: basename of the exporting repository
2692 :``%h``: short-form changeset hash (12 hexadecimal digits)
2699 :``%h``: short-form changeset hash (12 hexadecimal digits)
2693 :``%m``: first line of the commit message (only alphanumeric characters)
2700 :``%m``: first line of the commit message (only alphanumeric characters)
2694 :``%n``: zero-padded sequence number, starting at 1
2701 :``%n``: zero-padded sequence number, starting at 1
2695 :``%r``: zero-padded changeset revision number
2702 :``%r``: zero-padded changeset revision number
2696 :``\\``: literal "\\" character
2703 :``\\``: literal "\\" character
2697
2704
2698 Without the -a/--text option, export will avoid generating diffs
2705 Without the -a/--text option, export will avoid generating diffs
2699 of files it detects as binary. With -a, export will generate a
2706 of files it detects as binary. With -a, export will generate a
2700 diff anyway, probably with undesirable results.
2707 diff anyway, probably with undesirable results.
2701
2708
2702 With -B/--bookmark changesets reachable by the given bookmark are
2709 With -B/--bookmark changesets reachable by the given bookmark are
2703 selected.
2710 selected.
2704
2711
2705 Use the -g/--git option to generate diffs in the git extended diff
2712 Use the -g/--git option to generate diffs in the git extended diff
2706 format. See :hg:`help diffs` for more information.
2713 format. See :hg:`help diffs` for more information.
2707
2714
2708 With the --switch-parent option, the diff will be against the
2715 With the --switch-parent option, the diff will be against the
2709 second parent. It can be useful to review a merge.
2716 second parent. It can be useful to review a merge.
2710
2717
2711 .. container:: verbose
2718 .. container:: verbose
2712
2719
2713 Template:
2720 Template:
2714
2721
2715 The following keywords are supported in addition to the common template
2722 The following keywords are supported in addition to the common template
2716 keywords and functions. See also :hg:`help templates`.
2723 keywords and functions. See also :hg:`help templates`.
2717
2724
2718 :diff: String. Diff content.
2725 :diff: String. Diff content.
2719 :parents: List of strings. Parent nodes of the changeset.
2726 :parents: List of strings. Parent nodes of the changeset.
2720
2727
2721 Examples:
2728 Examples:
2722
2729
2723 - use export and import to transplant a bugfix to the current
2730 - use export and import to transplant a bugfix to the current
2724 branch::
2731 branch::
2725
2732
2726 hg export -r 9353 | hg import -
2733 hg export -r 9353 | hg import -
2727
2734
2728 - export all the changesets between two revisions to a file with
2735 - export all the changesets between two revisions to a file with
2729 rename information::
2736 rename information::
2730
2737
2731 hg export --git -r 123:150 > changes.txt
2738 hg export --git -r 123:150 > changes.txt
2732
2739
2733 - split outgoing changes into a series of patches with
2740 - split outgoing changes into a series of patches with
2734 descriptive names::
2741 descriptive names::
2735
2742
2736 hg export -r "outgoing()" -o "%n-%m.patch"
2743 hg export -r "outgoing()" -o "%n-%m.patch"
2737
2744
2738 Returns 0 on success.
2745 Returns 0 on success.
2739 """
2746 """
2740 opts = pycompat.byteskwargs(opts)
2747 opts = pycompat.byteskwargs(opts)
2741 bookmark = opts.get(b'bookmark')
2748 bookmark = opts.get(b'bookmark')
2742 changesets += tuple(opts.get(b'rev', []))
2749 changesets += tuple(opts.get(b'rev', []))
2743
2750
2744 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2751 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2745
2752
2746 if bookmark:
2753 if bookmark:
2747 if bookmark not in repo._bookmarks:
2754 if bookmark not in repo._bookmarks:
2748 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2755 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2749
2756
2750 revs = scmutil.bookmarkrevs(repo, bookmark)
2757 revs = scmutil.bookmarkrevs(repo, bookmark)
2751 else:
2758 else:
2752 if not changesets:
2759 if not changesets:
2753 changesets = [b'.']
2760 changesets = [b'.']
2754
2761
2755 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2762 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2756 revs = logcmdutil.revrange(repo, changesets)
2763 revs = logcmdutil.revrange(repo, changesets)
2757
2764
2758 if not revs:
2765 if not revs:
2759 raise error.InputError(_(b"export requires at least one changeset"))
2766 raise error.InputError(_(b"export requires at least one changeset"))
2760 if len(revs) > 1:
2767 if len(revs) > 1:
2761 ui.note(_(b'exporting patches:\n'))
2768 ui.note(_(b'exporting patches:\n'))
2762 else:
2769 else:
2763 ui.note(_(b'exporting patch:\n'))
2770 ui.note(_(b'exporting patch:\n'))
2764
2771
2765 fntemplate = opts.get(b'output')
2772 fntemplate = opts.get(b'output')
2766 if cmdutil.isstdiofilename(fntemplate):
2773 if cmdutil.isstdiofilename(fntemplate):
2767 fntemplate = b''
2774 fntemplate = b''
2768
2775
2769 if fntemplate:
2776 if fntemplate:
2770 fm = formatter.nullformatter(ui, b'export', opts)
2777 fm = formatter.nullformatter(ui, b'export', opts)
2771 else:
2778 else:
2772 ui.pager(b'export')
2779 ui.pager(b'export')
2773 fm = ui.formatter(b'export', opts)
2780 fm = ui.formatter(b'export', opts)
2774 with fm:
2781 with fm:
2775 cmdutil.export(
2782 cmdutil.export(
2776 repo,
2783 repo,
2777 revs,
2784 revs,
2778 fm,
2785 fm,
2779 fntemplate=fntemplate,
2786 fntemplate=fntemplate,
2780 switch_parent=opts.get(b'switch_parent'),
2787 switch_parent=opts.get(b'switch_parent'),
2781 opts=patch.diffallopts(ui, opts),
2788 opts=patch.diffallopts(ui, opts),
2782 )
2789 )
2783
2790
2784
2791
2785 @command(
2792 @command(
2786 b'files',
2793 b'files',
2787 [
2794 [
2788 (
2795 (
2789 b'r',
2796 b'r',
2790 b'rev',
2797 b'rev',
2791 b'',
2798 b'',
2792 _(b'search the repository as it is in REV'),
2799 _(b'search the repository as it is in REV'),
2793 _(b'REV'),
2800 _(b'REV'),
2794 ),
2801 ),
2795 (
2802 (
2796 b'0',
2803 b'0',
2797 b'print0',
2804 b'print0',
2798 None,
2805 None,
2799 _(b'end filenames with NUL, for use with xargs'),
2806 _(b'end filenames with NUL, for use with xargs'),
2800 ),
2807 ),
2801 ]
2808 ]
2802 + walkopts
2809 + walkopts
2803 + formatteropts
2810 + formatteropts
2804 + subrepoopts,
2811 + subrepoopts,
2805 _(b'[OPTION]... [FILE]...'),
2812 _(b'[OPTION]... [FILE]...'),
2806 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2807 intents={INTENT_READONLY},
2814 intents={INTENT_READONLY},
2808 )
2815 )
2809 def files(ui, repo, *pats, **opts):
2816 def files(ui, repo, *pats, **opts):
2810 """list tracked files
2817 """list tracked files
2811
2818
2812 Print files under Mercurial control in the working directory or
2819 Print files under Mercurial control in the working directory or
2813 specified revision for given files (excluding removed files).
2820 specified revision for given files (excluding removed files).
2814 Files can be specified as filenames or filesets.
2821 Files can be specified as filenames or filesets.
2815
2822
2816 If no files are given to match, this command prints the names
2823 If no files are given to match, this command prints the names
2817 of all files under Mercurial control.
2824 of all files under Mercurial control.
2818
2825
2819 .. container:: verbose
2826 .. container:: verbose
2820
2827
2821 Template:
2828 Template:
2822
2829
2823 The following keywords are supported in addition to the common template
2830 The following keywords are supported in addition to the common template
2824 keywords and functions. See also :hg:`help templates`.
2831 keywords and functions. See also :hg:`help templates`.
2825
2832
2826 :flags: String. Character denoting file's symlink and executable bits.
2833 :flags: String. Character denoting file's symlink and executable bits.
2827 :path: String. Repository-absolute path of the file.
2834 :path: String. Repository-absolute path of the file.
2828 :size: Integer. Size of the file in bytes.
2835 :size: Integer. Size of the file in bytes.
2829
2836
2830 Examples:
2837 Examples:
2831
2838
2832 - list all files under the current directory::
2839 - list all files under the current directory::
2833
2840
2834 hg files .
2841 hg files .
2835
2842
2836 - shows sizes and flags for current revision::
2843 - shows sizes and flags for current revision::
2837
2844
2838 hg files -vr .
2845 hg files -vr .
2839
2846
2840 - list all files named README::
2847 - list all files named README::
2841
2848
2842 hg files -I "**/README"
2849 hg files -I "**/README"
2843
2850
2844 - list all binary files::
2851 - list all binary files::
2845
2852
2846 hg files "set:binary()"
2853 hg files "set:binary()"
2847
2854
2848 - find files containing a regular expression::
2855 - find files containing a regular expression::
2849
2856
2850 hg files "set:grep('bob')"
2857 hg files "set:grep('bob')"
2851
2858
2852 - search tracked file contents with xargs and grep::
2859 - search tracked file contents with xargs and grep::
2853
2860
2854 hg files -0 | xargs -0 grep foo
2861 hg files -0 | xargs -0 grep foo
2855
2862
2856 See :hg:`help patterns` and :hg:`help filesets` for more information
2863 See :hg:`help patterns` and :hg:`help filesets` for more information
2857 on specifying file patterns.
2864 on specifying file patterns.
2858
2865
2859 Returns 0 if a match is found, 1 otherwise.
2866 Returns 0 if a match is found, 1 otherwise.
2860
2867
2861 """
2868 """
2862
2869
2863 opts = pycompat.byteskwargs(opts)
2870 opts = pycompat.byteskwargs(opts)
2864 rev = opts.get(b'rev')
2871 rev = opts.get(b'rev')
2865 if rev:
2872 if rev:
2866 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2873 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2867 ctx = logcmdutil.revsingle(repo, rev, None)
2874 ctx = logcmdutil.revsingle(repo, rev, None)
2868
2875
2869 end = b'\n'
2876 end = b'\n'
2870 if opts.get(b'print0'):
2877 if opts.get(b'print0'):
2871 end = b'\0'
2878 end = b'\0'
2872 fmt = b'%s' + end
2879 fmt = b'%s' + end
2873
2880
2874 m = scmutil.match(ctx, pats, opts)
2881 m = scmutil.match(ctx, pats, opts)
2875 ui.pager(b'files')
2882 ui.pager(b'files')
2876 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2883 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2877 with ui.formatter(b'files', opts) as fm:
2884 with ui.formatter(b'files', opts) as fm:
2878 return cmdutil.files(
2885 return cmdutil.files(
2879 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2886 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2880 )
2887 )
2881
2888
2882
2889
2883 @command(
2890 @command(
2884 b'forget',
2891 b'forget',
2885 [
2892 [
2886 (b'i', b'interactive', None, _(b'use interactive mode')),
2893 (b'i', b'interactive', None, _(b'use interactive mode')),
2887 ]
2894 ]
2888 + walkopts
2895 + walkopts
2889 + dryrunopts,
2896 + dryrunopts,
2890 _(b'[OPTION]... FILE...'),
2897 _(b'[OPTION]... FILE...'),
2891 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2898 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2892 helpbasic=True,
2899 helpbasic=True,
2893 inferrepo=True,
2900 inferrepo=True,
2894 )
2901 )
2895 def forget(ui, repo, *pats, **opts):
2902 def forget(ui, repo, *pats, **opts):
2896 """forget the specified files on the next commit
2903 """forget the specified files on the next commit
2897
2904
2898 Mark the specified files so they will no longer be tracked
2905 Mark the specified files so they will no longer be tracked
2899 after the next commit.
2906 after the next commit.
2900
2907
2901 This only removes files from the current branch, not from the
2908 This only removes files from the current branch, not from the
2902 entire project history, and it does not delete them from the
2909 entire project history, and it does not delete them from the
2903 working directory.
2910 working directory.
2904
2911
2905 To delete the file from the working directory, see :hg:`remove`.
2912 To delete the file from the working directory, see :hg:`remove`.
2906
2913
2907 To undo a forget before the next commit, see :hg:`add`.
2914 To undo a forget before the next commit, see :hg:`add`.
2908
2915
2909 .. container:: verbose
2916 .. container:: verbose
2910
2917
2911 Examples:
2918 Examples:
2912
2919
2913 - forget newly-added binary files::
2920 - forget newly-added binary files::
2914
2921
2915 hg forget "set:added() and binary()"
2922 hg forget "set:added() and binary()"
2916
2923
2917 - forget files that would be excluded by .hgignore::
2924 - forget files that would be excluded by .hgignore::
2918
2925
2919 hg forget "set:hgignore()"
2926 hg forget "set:hgignore()"
2920
2927
2921 Returns 0 on success.
2928 Returns 0 on success.
2922 """
2929 """
2923
2930
2924 opts = pycompat.byteskwargs(opts)
2931 opts = pycompat.byteskwargs(opts)
2925 if not pats:
2932 if not pats:
2926 raise error.InputError(_(b'no files specified'))
2933 raise error.InputError(_(b'no files specified'))
2927
2934
2928 m = scmutil.match(repo[None], pats, opts)
2935 m = scmutil.match(repo[None], pats, opts)
2929 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2936 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2930 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2937 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2931 rejected = cmdutil.forget(
2938 rejected = cmdutil.forget(
2932 ui,
2939 ui,
2933 repo,
2940 repo,
2934 m,
2941 m,
2935 prefix=b"",
2942 prefix=b"",
2936 uipathfn=uipathfn,
2943 uipathfn=uipathfn,
2937 explicitonly=False,
2944 explicitonly=False,
2938 dryrun=dryrun,
2945 dryrun=dryrun,
2939 interactive=interactive,
2946 interactive=interactive,
2940 )[0]
2947 )[0]
2941 return rejected and 1 or 0
2948 return rejected and 1 or 0
2942
2949
2943
2950
2944 @command(
2951 @command(
2945 b'graft',
2952 b'graft',
2946 [
2953 [
2947 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2954 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2948 (
2955 (
2949 b'',
2956 b'',
2950 b'base',
2957 b'base',
2951 b'',
2958 b'',
2952 _(b'base revision when doing the graft merge (ADVANCED)'),
2959 _(b'base revision when doing the graft merge (ADVANCED)'),
2953 _(b'REV'),
2960 _(b'REV'),
2954 ),
2961 ),
2955 (b'c', b'continue', False, _(b'resume interrupted graft')),
2962 (b'c', b'continue', False, _(b'resume interrupted graft')),
2956 (b'', b'stop', False, _(b'stop interrupted graft')),
2963 (b'', b'stop', False, _(b'stop interrupted graft')),
2957 (b'', b'abort', False, _(b'abort interrupted graft')),
2964 (b'', b'abort', False, _(b'abort interrupted graft')),
2958 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2965 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2959 (b'', b'log', None, _(b'append graft info to log message')),
2966 (b'', b'log', None, _(b'append graft info to log message')),
2960 (
2967 (
2961 b'',
2968 b'',
2962 b'no-commit',
2969 b'no-commit',
2963 None,
2970 None,
2964 _(b"don't commit, just apply the changes in working directory"),
2971 _(b"don't commit, just apply the changes in working directory"),
2965 ),
2972 ),
2966 (b'f', b'force', False, _(b'force graft')),
2973 (b'f', b'force', False, _(b'force graft')),
2967 (
2974 (
2968 b'D',
2975 b'D',
2969 b'currentdate',
2976 b'currentdate',
2970 False,
2977 False,
2971 _(b'record the current date as commit date'),
2978 _(b'record the current date as commit date'),
2972 ),
2979 ),
2973 (
2980 (
2974 b'U',
2981 b'U',
2975 b'currentuser',
2982 b'currentuser',
2976 False,
2983 False,
2977 _(b'record the current user as committer'),
2984 _(b'record the current user as committer'),
2978 ),
2985 ),
2979 ]
2986 ]
2980 + commitopts2
2987 + commitopts2
2981 + mergetoolopts
2988 + mergetoolopts
2982 + dryrunopts,
2989 + dryrunopts,
2983 _(b'[OPTION]... [-r REV]... REV...'),
2990 _(b'[OPTION]... [-r REV]... REV...'),
2984 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2991 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2985 )
2992 )
2986 def graft(ui, repo, *revs, **opts):
2993 def graft(ui, repo, *revs, **opts):
2987 """copy changes from other branches onto the current branch
2994 """copy changes from other branches onto the current branch
2988
2995
2989 This command uses Mercurial's merge logic to copy individual
2996 This command uses Mercurial's merge logic to copy individual
2990 changes from other branches without merging branches in the
2997 changes from other branches without merging branches in the
2991 history graph. This is sometimes known as 'backporting' or
2998 history graph. This is sometimes known as 'backporting' or
2992 'cherry-picking'. By default, graft will copy user, date, and
2999 'cherry-picking'. By default, graft will copy user, date, and
2993 description from the source changesets.
3000 description from the source changesets.
2994
3001
2995 Changesets that are ancestors of the current revision, that have
3002 Changesets that are ancestors of the current revision, that have
2996 already been grafted, or that are merges will be skipped.
3003 already been grafted, or that are merges will be skipped.
2997
3004
2998 If --log is specified, log messages will have a comment appended
3005 If --log is specified, log messages will have a comment appended
2999 of the form::
3006 of the form::
3000
3007
3001 (grafted from CHANGESETHASH)
3008 (grafted from CHANGESETHASH)
3002
3009
3003 If --force is specified, revisions will be grafted even if they
3010 If --force is specified, revisions will be grafted even if they
3004 are already ancestors of, or have been grafted to, the destination.
3011 are already ancestors of, or have been grafted to, the destination.
3005 This is useful when the revisions have since been backed out.
3012 This is useful when the revisions have since been backed out.
3006
3013
3007 If a graft merge results in conflicts, the graft process is
3014 If a graft merge results in conflicts, the graft process is
3008 interrupted so that the current merge can be manually resolved.
3015 interrupted so that the current merge can be manually resolved.
3009 Once all conflicts are addressed, the graft process can be
3016 Once all conflicts are addressed, the graft process can be
3010 continued with the -c/--continue option.
3017 continued with the -c/--continue option.
3011
3018
3012 The -c/--continue option reapplies all the earlier options.
3019 The -c/--continue option reapplies all the earlier options.
3013
3020
3014 .. container:: verbose
3021 .. container:: verbose
3015
3022
3016 The --base option exposes more of how graft internally uses merge with a
3023 The --base option exposes more of how graft internally uses merge with a
3017 custom base revision. --base can be used to specify another ancestor than
3024 custom base revision. --base can be used to specify another ancestor than
3018 the first and only parent.
3025 the first and only parent.
3019
3026
3020 The command::
3027 The command::
3021
3028
3022 hg graft -r 345 --base 234
3029 hg graft -r 345 --base 234
3023
3030
3024 is thus pretty much the same as::
3031 is thus pretty much the same as::
3025
3032
3026 hg diff --from 234 --to 345 | hg import
3033 hg diff --from 234 --to 345 | hg import
3027
3034
3028 but using merge to resolve conflicts and track moved files.
3035 but using merge to resolve conflicts and track moved files.
3029
3036
3030 The result of a merge can thus be backported as a single commit by
3037 The result of a merge can thus be backported as a single commit by
3031 specifying one of the merge parents as base, and thus effectively
3038 specifying one of the merge parents as base, and thus effectively
3032 grafting the changes from the other side.
3039 grafting the changes from the other side.
3033
3040
3034 It is also possible to collapse multiple changesets and clean up history
3041 It is also possible to collapse multiple changesets and clean up history
3035 by specifying another ancestor as base, much like rebase --collapse
3042 by specifying another ancestor as base, much like rebase --collapse
3036 --keep.
3043 --keep.
3037
3044
3038 The commit message can be tweaked after the fact using commit --amend .
3045 The commit message can be tweaked after the fact using commit --amend .
3039
3046
3040 For using non-ancestors as the base to backout changes, see the backout
3047 For using non-ancestors as the base to backout changes, see the backout
3041 command and the hidden --parent option.
3048 command and the hidden --parent option.
3042
3049
3043 .. container:: verbose
3050 .. container:: verbose
3044
3051
3045 Examples:
3052 Examples:
3046
3053
3047 - copy a single change to the stable branch and edit its description::
3054 - copy a single change to the stable branch and edit its description::
3048
3055
3049 hg update stable
3056 hg update stable
3050 hg graft --edit 9393
3057 hg graft --edit 9393
3051
3058
3052 - graft a range of changesets with one exception, updating dates::
3059 - graft a range of changesets with one exception, updating dates::
3053
3060
3054 hg graft -D "2085::2093 and not 2091"
3061 hg graft -D "2085::2093 and not 2091"
3055
3062
3056 - continue a graft after resolving conflicts::
3063 - continue a graft after resolving conflicts::
3057
3064
3058 hg graft -c
3065 hg graft -c
3059
3066
3060 - show the source of a grafted changeset::
3067 - show the source of a grafted changeset::
3061
3068
3062 hg log --debug -r .
3069 hg log --debug -r .
3063
3070
3064 - show revisions sorted by date::
3071 - show revisions sorted by date::
3065
3072
3066 hg log -r "sort(all(), date)"
3073 hg log -r "sort(all(), date)"
3067
3074
3068 - backport the result of a merge as a single commit::
3075 - backport the result of a merge as a single commit::
3069
3076
3070 hg graft -r 123 --base 123^
3077 hg graft -r 123 --base 123^
3071
3078
3072 - land a feature branch as one changeset::
3079 - land a feature branch as one changeset::
3073
3080
3074 hg up -cr default
3081 hg up -cr default
3075 hg graft -r featureX --base "ancestor('featureX', 'default')"
3082 hg graft -r featureX --base "ancestor('featureX', 'default')"
3076
3083
3077 See :hg:`help revisions` for more about specifying revisions.
3084 See :hg:`help revisions` for more about specifying revisions.
3078
3085
3079 Returns 0 on successful completion, 1 if there are unresolved files.
3086 Returns 0 on successful completion, 1 if there are unresolved files.
3080 """
3087 """
3081 with repo.wlock():
3088 with repo.wlock():
3082 return _dograft(ui, repo, *revs, **opts)
3089 return _dograft(ui, repo, *revs, **opts)
3083
3090
3084
3091
3085 def _dograft(ui, repo, *revs, **opts):
3092 def _dograft(ui, repo, *revs, **opts):
3086 if revs and opts.get('rev'):
3093 if revs and opts.get('rev'):
3087 ui.warn(
3094 ui.warn(
3088 _(
3095 _(
3089 b'warning: inconsistent use of --rev might give unexpected '
3096 b'warning: inconsistent use of --rev might give unexpected '
3090 b'revision ordering!\n'
3097 b'revision ordering!\n'
3091 )
3098 )
3092 )
3099 )
3093
3100
3094 revs = list(revs)
3101 revs = list(revs)
3095 revs.extend(opts.get('rev'))
3102 revs.extend(opts.get('rev'))
3096 # a dict of data to be stored in state file
3103 # a dict of data to be stored in state file
3097 statedata = {}
3104 statedata = {}
3098 # list of new nodes created by ongoing graft
3105 # list of new nodes created by ongoing graft
3099 statedata[b'newnodes'] = []
3106 statedata[b'newnodes'] = []
3100
3107
3101 cmdutil.resolve_commit_options(ui, opts)
3108 cmdutil.resolve_commit_options(ui, opts)
3102
3109
3103 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3110 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3104
3111
3105 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3112 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3106
3113
3107 cont = False
3114 cont = False
3108 if opts.get('no_commit'):
3115 if opts.get('no_commit'):
3109 cmdutil.check_incompatible_arguments(
3116 cmdutil.check_incompatible_arguments(
3110 opts,
3117 opts,
3111 'no_commit',
3118 'no_commit',
3112 ['edit', 'currentuser', 'currentdate', 'log'],
3119 ['edit', 'currentuser', 'currentdate', 'log'],
3113 )
3120 )
3114
3121
3115 graftstate = statemod.cmdstate(repo, b'graftstate')
3122 graftstate = statemod.cmdstate(repo, b'graftstate')
3116
3123
3117 if opts.get('stop'):
3124 if opts.get('stop'):
3118 cmdutil.check_incompatible_arguments(
3125 cmdutil.check_incompatible_arguments(
3119 opts,
3126 opts,
3120 'stop',
3127 'stop',
3121 [
3128 [
3122 'edit',
3129 'edit',
3123 'log',
3130 'log',
3124 'user',
3131 'user',
3125 'date',
3132 'date',
3126 'currentdate',
3133 'currentdate',
3127 'currentuser',
3134 'currentuser',
3128 'rev',
3135 'rev',
3129 ],
3136 ],
3130 )
3137 )
3131 return _stopgraft(ui, repo, graftstate)
3138 return _stopgraft(ui, repo, graftstate)
3132 elif opts.get('abort'):
3139 elif opts.get('abort'):
3133 cmdutil.check_incompatible_arguments(
3140 cmdutil.check_incompatible_arguments(
3134 opts,
3141 opts,
3135 'abort',
3142 'abort',
3136 [
3143 [
3137 'edit',
3144 'edit',
3138 'log',
3145 'log',
3139 'user',
3146 'user',
3140 'date',
3147 'date',
3141 'currentdate',
3148 'currentdate',
3142 'currentuser',
3149 'currentuser',
3143 'rev',
3150 'rev',
3144 ],
3151 ],
3145 )
3152 )
3146 return cmdutil.abortgraft(ui, repo, graftstate)
3153 return cmdutil.abortgraft(ui, repo, graftstate)
3147 elif opts.get('continue'):
3154 elif opts.get('continue'):
3148 cont = True
3155 cont = True
3149 if revs:
3156 if revs:
3150 raise error.InputError(_(b"can't specify --continue and revisions"))
3157 raise error.InputError(_(b"can't specify --continue and revisions"))
3151 # read in unfinished revisions
3158 # read in unfinished revisions
3152 if graftstate.exists():
3159 if graftstate.exists():
3153 statedata = cmdutil.readgraftstate(repo, graftstate)
3160 statedata = cmdutil.readgraftstate(repo, graftstate)
3154 if statedata.get(b'date'):
3161 if statedata.get(b'date'):
3155 opts['date'] = statedata[b'date']
3162 opts['date'] = statedata[b'date']
3156 if statedata.get(b'user'):
3163 if statedata.get(b'user'):
3157 opts['user'] = statedata[b'user']
3164 opts['user'] = statedata[b'user']
3158 if statedata.get(b'log'):
3165 if statedata.get(b'log'):
3159 opts['log'] = True
3166 opts['log'] = True
3160 if statedata.get(b'no_commit'):
3167 if statedata.get(b'no_commit'):
3161 opts['no_commit'] = statedata.get(b'no_commit')
3168 opts['no_commit'] = statedata.get(b'no_commit')
3162 if statedata.get(b'base'):
3169 if statedata.get(b'base'):
3163 opts['base'] = statedata.get(b'base')
3170 opts['base'] = statedata.get(b'base')
3164 nodes = statedata[b'nodes']
3171 nodes = statedata[b'nodes']
3165 revs = [repo[node].rev() for node in nodes]
3172 revs = [repo[node].rev() for node in nodes]
3166 else:
3173 else:
3167 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3174 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3168 else:
3175 else:
3169 if not revs:
3176 if not revs:
3170 raise error.InputError(_(b'no revisions specified'))
3177 raise error.InputError(_(b'no revisions specified'))
3171 cmdutil.checkunfinished(repo)
3178 cmdutil.checkunfinished(repo)
3172 cmdutil.bailifchanged(repo)
3179 cmdutil.bailifchanged(repo)
3173 revs = logcmdutil.revrange(repo, revs)
3180 revs = logcmdutil.revrange(repo, revs)
3174
3181
3175 skipped = set()
3182 skipped = set()
3176 basectx = None
3183 basectx = None
3177 if opts.get('base'):
3184 if opts.get('base'):
3178 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3185 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3179 if basectx is None:
3186 if basectx is None:
3180 # check for merges
3187 # check for merges
3181 for rev in repo.revs(b'%ld and merge()', revs):
3188 for rev in repo.revs(b'%ld and merge()', revs):
3182 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3189 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3183 skipped.add(rev)
3190 skipped.add(rev)
3184 revs = [r for r in revs if r not in skipped]
3191 revs = [r for r in revs if r not in skipped]
3185 if not revs:
3192 if not revs:
3186 return -1
3193 return -1
3187 if basectx is not None and len(revs) != 1:
3194 if basectx is not None and len(revs) != 1:
3188 raise error.InputError(_(b'only one revision allowed with --base '))
3195 raise error.InputError(_(b'only one revision allowed with --base '))
3189
3196
3190 # Don't check in the --continue case, in effect retaining --force across
3197 # Don't check in the --continue case, in effect retaining --force across
3191 # --continues. That's because without --force, any revisions we decided to
3198 # --continues. That's because without --force, any revisions we decided to
3192 # skip would have been filtered out here, so they wouldn't have made their
3199 # skip would have been filtered out here, so they wouldn't have made their
3193 # way to the graftstate. With --force, any revisions we would have otherwise
3200 # way to the graftstate. With --force, any revisions we would have otherwise
3194 # skipped would not have been filtered out, and if they hadn't been applied
3201 # skipped would not have been filtered out, and if they hadn't been applied
3195 # already, they'd have been in the graftstate.
3202 # already, they'd have been in the graftstate.
3196 if not (cont or opts.get('force')) and basectx is None:
3203 if not (cont or opts.get('force')) and basectx is None:
3197 # check for ancestors of dest branch
3204 # check for ancestors of dest branch
3198 ancestors = repo.revs(b'%ld & (::.)', revs)
3205 ancestors = repo.revs(b'%ld & (::.)', revs)
3199 for rev in ancestors:
3206 for rev in ancestors:
3200 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3207 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3201
3208
3202 revs = [r for r in revs if r not in ancestors]
3209 revs = [r for r in revs if r not in ancestors]
3203
3210
3204 if not revs:
3211 if not revs:
3205 return -1
3212 return -1
3206
3213
3207 # analyze revs for earlier grafts
3214 # analyze revs for earlier grafts
3208 ids = {}
3215 ids = {}
3209 for ctx in repo.set(b"%ld", revs):
3216 for ctx in repo.set(b"%ld", revs):
3210 ids[ctx.hex()] = ctx.rev()
3217 ids[ctx.hex()] = ctx.rev()
3211 n = ctx.extra().get(b'source')
3218 n = ctx.extra().get(b'source')
3212 if n:
3219 if n:
3213 ids[n] = ctx.rev()
3220 ids[n] = ctx.rev()
3214
3221
3215 # check ancestors for earlier grafts
3222 # check ancestors for earlier grafts
3216 ui.debug(b'scanning for duplicate grafts\n')
3223 ui.debug(b'scanning for duplicate grafts\n')
3217
3224
3218 # The only changesets we can be sure doesn't contain grafts of any
3225 # The only changesets we can be sure doesn't contain grafts of any
3219 # revs, are the ones that are common ancestors of *all* revs:
3226 # revs, are the ones that are common ancestors of *all* revs:
3220 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3227 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3221 ctx = repo[rev]
3228 ctx = repo[rev]
3222 n = ctx.extra().get(b'source')
3229 n = ctx.extra().get(b'source')
3223 if n in ids:
3230 if n in ids:
3224 try:
3231 try:
3225 r = repo[n].rev()
3232 r = repo[n].rev()
3226 except error.RepoLookupError:
3233 except error.RepoLookupError:
3227 r = None
3234 r = None
3228 if r in revs:
3235 if r in revs:
3229 ui.warn(
3236 ui.warn(
3230 _(
3237 _(
3231 b'skipping revision %d:%s '
3238 b'skipping revision %d:%s '
3232 b'(already grafted to %d:%s)\n'
3239 b'(already grafted to %d:%s)\n'
3233 )
3240 )
3234 % (r, repo[r], rev, ctx)
3241 % (r, repo[r], rev, ctx)
3235 )
3242 )
3236 revs.remove(r)
3243 revs.remove(r)
3237 elif ids[n] in revs:
3244 elif ids[n] in revs:
3238 if r is None:
3245 if r is None:
3239 ui.warn(
3246 ui.warn(
3240 _(
3247 _(
3241 b'skipping already grafted revision %d:%s '
3248 b'skipping already grafted revision %d:%s '
3242 b'(%d:%s also has unknown origin %s)\n'
3249 b'(%d:%s also has unknown origin %s)\n'
3243 )
3250 )
3244 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3251 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3245 )
3252 )
3246 else:
3253 else:
3247 ui.warn(
3254 ui.warn(
3248 _(
3255 _(
3249 b'skipping already grafted revision %d:%s '
3256 b'skipping already grafted revision %d:%s '
3250 b'(%d:%s also has origin %d:%s)\n'
3257 b'(%d:%s also has origin %d:%s)\n'
3251 )
3258 )
3252 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3259 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3253 )
3260 )
3254 revs.remove(ids[n])
3261 revs.remove(ids[n])
3255 elif ctx.hex() in ids:
3262 elif ctx.hex() in ids:
3256 r = ids[ctx.hex()]
3263 r = ids[ctx.hex()]
3257 if r in revs:
3264 if r in revs:
3258 ui.warn(
3265 ui.warn(
3259 _(
3266 _(
3260 b'skipping already grafted revision %d:%s '
3267 b'skipping already grafted revision %d:%s '
3261 b'(was grafted from %d:%s)\n'
3268 b'(was grafted from %d:%s)\n'
3262 )
3269 )
3263 % (r, repo[r], rev, ctx)
3270 % (r, repo[r], rev, ctx)
3264 )
3271 )
3265 revs.remove(r)
3272 revs.remove(r)
3266 if not revs:
3273 if not revs:
3267 return -1
3274 return -1
3268
3275
3269 if opts.get('no_commit'):
3276 if opts.get('no_commit'):
3270 statedata[b'no_commit'] = True
3277 statedata[b'no_commit'] = True
3271 if opts.get('base'):
3278 if opts.get('base'):
3272 statedata[b'base'] = opts['base']
3279 statedata[b'base'] = opts['base']
3273 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3280 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3274 desc = b'%d:%s "%s"' % (
3281 desc = b'%d:%s "%s"' % (
3275 ctx.rev(),
3282 ctx.rev(),
3276 ctx,
3283 ctx,
3277 ctx.description().split(b'\n', 1)[0],
3284 ctx.description().split(b'\n', 1)[0],
3278 )
3285 )
3279 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3286 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3280 if names:
3287 if names:
3281 desc += b' (%s)' % b' '.join(names)
3288 desc += b' (%s)' % b' '.join(names)
3282 ui.status(_(b'grafting %s\n') % desc)
3289 ui.status(_(b'grafting %s\n') % desc)
3283 if opts.get('dry_run'):
3290 if opts.get('dry_run'):
3284 continue
3291 continue
3285
3292
3286 source = ctx.extra().get(b'source')
3293 source = ctx.extra().get(b'source')
3287 extra = {}
3294 extra = {}
3288 if source:
3295 if source:
3289 extra[b'source'] = source
3296 extra[b'source'] = source
3290 extra[b'intermediate-source'] = ctx.hex()
3297 extra[b'intermediate-source'] = ctx.hex()
3291 else:
3298 else:
3292 extra[b'source'] = ctx.hex()
3299 extra[b'source'] = ctx.hex()
3293 user = ctx.user()
3300 user = ctx.user()
3294 if opts.get('user'):
3301 if opts.get('user'):
3295 user = opts['user']
3302 user = opts['user']
3296 statedata[b'user'] = user
3303 statedata[b'user'] = user
3297 date = ctx.date()
3304 date = ctx.date()
3298 if opts.get('date'):
3305 if opts.get('date'):
3299 date = opts['date']
3306 date = opts['date']
3300 statedata[b'date'] = date
3307 statedata[b'date'] = date
3301 message = ctx.description()
3308 message = ctx.description()
3302 if opts.get('log'):
3309 if opts.get('log'):
3303 message += b'\n(grafted from %s)' % ctx.hex()
3310 message += b'\n(grafted from %s)' % ctx.hex()
3304 statedata[b'log'] = True
3311 statedata[b'log'] = True
3305
3312
3306 # we don't merge the first commit when continuing
3313 # we don't merge the first commit when continuing
3307 if not cont:
3314 if not cont:
3308 # perform the graft merge with p1(rev) as 'ancestor'
3315 # perform the graft merge with p1(rev) as 'ancestor'
3309 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3316 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3310 base = ctx.p1() if basectx is None else basectx
3317 base = ctx.p1() if basectx is None else basectx
3311 with ui.configoverride(overrides, b'graft'):
3318 with ui.configoverride(overrides, b'graft'):
3312 stats = mergemod.graft(
3319 stats = mergemod.graft(
3313 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3320 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3314 )
3321 )
3315 # report any conflicts
3322 # report any conflicts
3316 if stats.unresolvedcount > 0:
3323 if stats.unresolvedcount > 0:
3317 # write out state for --continue
3324 # write out state for --continue
3318 nodes = [repo[rev].hex() for rev in revs[pos:]]
3325 nodes = [repo[rev].hex() for rev in revs[pos:]]
3319 statedata[b'nodes'] = nodes
3326 statedata[b'nodes'] = nodes
3320 stateversion = 1
3327 stateversion = 1
3321 graftstate.save(stateversion, statedata)
3328 graftstate.save(stateversion, statedata)
3322 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3329 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3323 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3330 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3324 return 1
3331 return 1
3325 else:
3332 else:
3326 cont = False
3333 cont = False
3327
3334
3328 # commit if --no-commit is false
3335 # commit if --no-commit is false
3329 if not opts.get('no_commit'):
3336 if not opts.get('no_commit'):
3330 node = repo.commit(
3337 node = repo.commit(
3331 text=message, user=user, date=date, extra=extra, editor=editor
3338 text=message, user=user, date=date, extra=extra, editor=editor
3332 )
3339 )
3333 if node is None:
3340 if node is None:
3334 ui.warn(
3341 ui.warn(
3335 _(b'note: graft of %d:%s created no changes to commit\n')
3342 _(b'note: graft of %d:%s created no changes to commit\n')
3336 % (ctx.rev(), ctx)
3343 % (ctx.rev(), ctx)
3337 )
3344 )
3338 # checking that newnodes exist because old state files won't have it
3345 # checking that newnodes exist because old state files won't have it
3339 elif statedata.get(b'newnodes') is not None:
3346 elif statedata.get(b'newnodes') is not None:
3340 nn = statedata[b'newnodes']
3347 nn = statedata[b'newnodes']
3341 assert isinstance(nn, list) # list of bytes
3348 assert isinstance(nn, list) # list of bytes
3342 nn.append(node)
3349 nn.append(node)
3343
3350
3344 # remove state when we complete successfully
3351 # remove state when we complete successfully
3345 if not opts.get('dry_run'):
3352 if not opts.get('dry_run'):
3346 graftstate.delete()
3353 graftstate.delete()
3347
3354
3348 return 0
3355 return 0
3349
3356
3350
3357
3351 def _stopgraft(ui, repo, graftstate):
3358 def _stopgraft(ui, repo, graftstate):
3352 """stop the interrupted graft"""
3359 """stop the interrupted graft"""
3353 if not graftstate.exists():
3360 if not graftstate.exists():
3354 raise error.StateError(_(b"no interrupted graft found"))
3361 raise error.StateError(_(b"no interrupted graft found"))
3355 pctx = repo[b'.']
3362 pctx = repo[b'.']
3356 mergemod.clean_update(pctx)
3363 mergemod.clean_update(pctx)
3357 graftstate.delete()
3364 graftstate.delete()
3358 ui.status(_(b"stopped the interrupted graft\n"))
3365 ui.status(_(b"stopped the interrupted graft\n"))
3359 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3366 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3360 return 0
3367 return 0
3361
3368
3362
3369
3363 statemod.addunfinished(
3370 statemod.addunfinished(
3364 b'graft',
3371 b'graft',
3365 fname=b'graftstate',
3372 fname=b'graftstate',
3366 clearable=True,
3373 clearable=True,
3367 stopflag=True,
3374 stopflag=True,
3368 continueflag=True,
3375 continueflag=True,
3369 abortfunc=cmdutil.hgabortgraft,
3376 abortfunc=cmdutil.hgabortgraft,
3370 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3377 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3371 )
3378 )
3372
3379
3373
3380
3374 @command(
3381 @command(
3375 b'grep',
3382 b'grep',
3376 [
3383 [
3377 (b'0', b'print0', None, _(b'end fields with NUL')),
3384 (b'0', b'print0', None, _(b'end fields with NUL')),
3378 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3385 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3379 (
3386 (
3380 b'',
3387 b'',
3381 b'diff',
3388 b'diff',
3382 None,
3389 None,
3383 _(
3390 _(
3384 b'search revision differences for when the pattern was added '
3391 b'search revision differences for when the pattern was added '
3385 b'or removed'
3392 b'or removed'
3386 ),
3393 ),
3387 ),
3394 ),
3388 (b'a', b'text', None, _(b'treat all files as text')),
3395 (b'a', b'text', None, _(b'treat all files as text')),
3389 (
3396 (
3390 b'f',
3397 b'f',
3391 b'follow',
3398 b'follow',
3392 None,
3399 None,
3393 _(
3400 _(
3394 b'follow changeset history,'
3401 b'follow changeset history,'
3395 b' or file history across copies and renames'
3402 b' or file history across copies and renames'
3396 ),
3403 ),
3397 ),
3404 ),
3398 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3405 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3399 (
3406 (
3400 b'l',
3407 b'l',
3401 b'files-with-matches',
3408 b'files-with-matches',
3402 None,
3409 None,
3403 _(b'print only filenames and revisions that match'),
3410 _(b'print only filenames and revisions that match'),
3404 ),
3411 ),
3405 (b'n', b'line-number', None, _(b'print matching line numbers')),
3412 (b'n', b'line-number', None, _(b'print matching line numbers')),
3406 (
3413 (
3407 b'r',
3414 b'r',
3408 b'rev',
3415 b'rev',
3409 [],
3416 [],
3410 _(b'search files changed within revision range'),
3417 _(b'search files changed within revision range'),
3411 _(b'REV'),
3418 _(b'REV'),
3412 ),
3419 ),
3413 (
3420 (
3414 b'',
3421 b'',
3415 b'all-files',
3422 b'all-files',
3416 None,
3423 None,
3417 _(
3424 _(
3418 b'include all files in the changeset while grepping (DEPRECATED)'
3425 b'include all files in the changeset while grepping (DEPRECATED)'
3419 ),
3426 ),
3420 ),
3427 ),
3421 (b'u', b'user', None, _(b'list the author (long with -v)')),
3428 (b'u', b'user', None, _(b'list the author (long with -v)')),
3422 (b'd', b'date', None, _(b'list the date (short with -q)')),
3429 (b'd', b'date', None, _(b'list the date (short with -q)')),
3423 ]
3430 ]
3424 + formatteropts
3431 + formatteropts
3425 + walkopts,
3432 + walkopts,
3426 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3433 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3427 helpcategory=command.CATEGORY_FILE_CONTENTS,
3434 helpcategory=command.CATEGORY_FILE_CONTENTS,
3428 inferrepo=True,
3435 inferrepo=True,
3429 intents={INTENT_READONLY},
3436 intents={INTENT_READONLY},
3430 )
3437 )
3431 def grep(ui, repo, pattern, *pats, **opts):
3438 def grep(ui, repo, pattern, *pats, **opts):
3432 """search for a pattern in specified files
3439 """search for a pattern in specified files
3433
3440
3434 Search the working directory or revision history for a regular
3441 Search the working directory or revision history for a regular
3435 expression in the specified files for the entire repository.
3442 expression in the specified files for the entire repository.
3436
3443
3437 By default, grep searches the repository files in the working
3444 By default, grep searches the repository files in the working
3438 directory and prints the files where it finds a match. To specify
3445 directory and prints the files where it finds a match. To specify
3439 historical revisions instead of the working directory, use the
3446 historical revisions instead of the working directory, use the
3440 --rev flag.
3447 --rev flag.
3441
3448
3442 To search instead historical revision differences that contains a
3449 To search instead historical revision differences that contains a
3443 change in match status ("-" for a match that becomes a non-match,
3450 change in match status ("-" for a match that becomes a non-match,
3444 or "+" for a non-match that becomes a match), use the --diff flag.
3451 or "+" for a non-match that becomes a match), use the --diff flag.
3445
3452
3446 PATTERN can be any Python (roughly Perl-compatible) regular
3453 PATTERN can be any Python (roughly Perl-compatible) regular
3447 expression.
3454 expression.
3448
3455
3449 If no FILEs are specified and the --rev flag isn't supplied, all
3456 If no FILEs are specified and the --rev flag isn't supplied, all
3450 files in the working directory are searched. When using the --rev
3457 files in the working directory are searched. When using the --rev
3451 flag and specifying FILEs, use the --follow argument to also
3458 flag and specifying FILEs, use the --follow argument to also
3452 follow the specified FILEs across renames and copies.
3459 follow the specified FILEs across renames and copies.
3453
3460
3454 .. container:: verbose
3461 .. container:: verbose
3455
3462
3456 Template:
3463 Template:
3457
3464
3458 The following keywords are supported in addition to the common template
3465 The following keywords are supported in addition to the common template
3459 keywords and functions. See also :hg:`help templates`.
3466 keywords and functions. See also :hg:`help templates`.
3460
3467
3461 :change: String. Character denoting insertion ``+`` or removal ``-``.
3468 :change: String. Character denoting insertion ``+`` or removal ``-``.
3462 Available if ``--diff`` is specified.
3469 Available if ``--diff`` is specified.
3463 :lineno: Integer. Line number of the match.
3470 :lineno: Integer. Line number of the match.
3464 :path: String. Repository-absolute path of the file.
3471 :path: String. Repository-absolute path of the file.
3465 :texts: List of text chunks.
3472 :texts: List of text chunks.
3466
3473
3467 And each entry of ``{texts}`` provides the following sub-keywords.
3474 And each entry of ``{texts}`` provides the following sub-keywords.
3468
3475
3469 :matched: Boolean. True if the chunk matches the specified pattern.
3476 :matched: Boolean. True if the chunk matches the specified pattern.
3470 :text: String. Chunk content.
3477 :text: String. Chunk content.
3471
3478
3472 See :hg:`help templates.operators` for the list expansion syntax.
3479 See :hg:`help templates.operators` for the list expansion syntax.
3473
3480
3474 Returns 0 if a match is found, 1 otherwise.
3481 Returns 0 if a match is found, 1 otherwise.
3475
3482
3476 """
3483 """
3477 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3484 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3478 opts = pycompat.byteskwargs(opts)
3485 opts = pycompat.byteskwargs(opts)
3479 diff = opts.get(b'all') or opts.get(b'diff')
3486 diff = opts.get(b'all') or opts.get(b'diff')
3480 follow = opts.get(b'follow')
3487 follow = opts.get(b'follow')
3481 if opts.get(b'all_files') is None and not diff:
3488 if opts.get(b'all_files') is None and not diff:
3482 opts[b'all_files'] = True
3489 opts[b'all_files'] = True
3483 plaingrep = (
3490 plaingrep = (
3484 opts.get(b'all_files')
3491 opts.get(b'all_files')
3485 and not opts.get(b'rev')
3492 and not opts.get(b'rev')
3486 and not opts.get(b'follow')
3493 and not opts.get(b'follow')
3487 )
3494 )
3488 all_files = opts.get(b'all_files')
3495 all_files = opts.get(b'all_files')
3489 if plaingrep:
3496 if plaingrep:
3490 opts[b'rev'] = [b'wdir()']
3497 opts[b'rev'] = [b'wdir()']
3491
3498
3492 reflags = re.M
3499 reflags = re.M
3493 if opts.get(b'ignore_case'):
3500 if opts.get(b'ignore_case'):
3494 reflags |= re.I
3501 reflags |= re.I
3495 try:
3502 try:
3496 regexp = util.re.compile(pattern, reflags)
3503 regexp = util.re.compile(pattern, reflags)
3497 except re.error as inst:
3504 except re.error as inst:
3498 ui.warn(
3505 ui.warn(
3499 _(b"grep: invalid match pattern: %s\n")
3506 _(b"grep: invalid match pattern: %s\n")
3500 % stringutil.forcebytestr(inst)
3507 % stringutil.forcebytestr(inst)
3501 )
3508 )
3502 return 1
3509 return 1
3503 sep, eol = b':', b'\n'
3510 sep, eol = b':', b'\n'
3504 if opts.get(b'print0'):
3511 if opts.get(b'print0'):
3505 sep = eol = b'\0'
3512 sep = eol = b'\0'
3506
3513
3507 searcher = grepmod.grepsearcher(
3514 searcher = grepmod.grepsearcher(
3508 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3515 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3509 )
3516 )
3510
3517
3511 getfile = searcher._getfile
3518 getfile = searcher._getfile
3512
3519
3513 uipathfn = scmutil.getuipathfn(repo)
3520 uipathfn = scmutil.getuipathfn(repo)
3514
3521
3515 def display(fm, fn, ctx, pstates, states):
3522 def display(fm, fn, ctx, pstates, states):
3516 rev = scmutil.intrev(ctx)
3523 rev = scmutil.intrev(ctx)
3517 if fm.isplain():
3524 if fm.isplain():
3518 formatuser = ui.shortuser
3525 formatuser = ui.shortuser
3519 else:
3526 else:
3520 formatuser = pycompat.bytestr
3527 formatuser = pycompat.bytestr
3521 if ui.quiet:
3528 if ui.quiet:
3522 datefmt = b'%Y-%m-%d'
3529 datefmt = b'%Y-%m-%d'
3523 else:
3530 else:
3524 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3531 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3525 found = False
3532 found = False
3526
3533
3527 @util.cachefunc
3534 @util.cachefunc
3528 def binary():
3535 def binary():
3529 flog = getfile(fn)
3536 flog = getfile(fn)
3530 try:
3537 try:
3531 return stringutil.binary(flog.read(ctx.filenode(fn)))
3538 return stringutil.binary(flog.read(ctx.filenode(fn)))
3532 except error.WdirUnsupported:
3539 except error.WdirUnsupported:
3533 return ctx[fn].isbinary()
3540 return ctx[fn].isbinary()
3534
3541
3535 fieldnamemap = {b'linenumber': b'lineno'}
3542 fieldnamemap = {b'linenumber': b'lineno'}
3536 if diff:
3543 if diff:
3537 iter = grepmod.difflinestates(pstates, states)
3544 iter = grepmod.difflinestates(pstates, states)
3538 else:
3545 else:
3539 iter = [(b'', l) for l in states]
3546 iter = [(b'', l) for l in states]
3540 for change, l in iter:
3547 for change, l in iter:
3541 fm.startitem()
3548 fm.startitem()
3542 fm.context(ctx=ctx)
3549 fm.context(ctx=ctx)
3543 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3550 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3544 fm.plain(uipathfn(fn), label=b'grep.filename')
3551 fm.plain(uipathfn(fn), label=b'grep.filename')
3545
3552
3546 cols = [
3553 cols = [
3547 (b'rev', b'%d', rev, not plaingrep, b''),
3554 (b'rev', b'%d', rev, not plaingrep, b''),
3548 (
3555 (
3549 b'linenumber',
3556 b'linenumber',
3550 b'%d',
3557 b'%d',
3551 l.linenum,
3558 l.linenum,
3552 opts.get(b'line_number'),
3559 opts.get(b'line_number'),
3553 b'',
3560 b'',
3554 ),
3561 ),
3555 ]
3562 ]
3556 if diff:
3563 if diff:
3557 cols.append(
3564 cols.append(
3558 (
3565 (
3559 b'change',
3566 b'change',
3560 b'%s',
3567 b'%s',
3561 change,
3568 change,
3562 True,
3569 True,
3563 b'grep.inserted '
3570 b'grep.inserted '
3564 if change == b'+'
3571 if change == b'+'
3565 else b'grep.deleted ',
3572 else b'grep.deleted ',
3566 )
3573 )
3567 )
3574 )
3568 cols.extend(
3575 cols.extend(
3569 [
3576 [
3570 (
3577 (
3571 b'user',
3578 b'user',
3572 b'%s',
3579 b'%s',
3573 formatuser(ctx.user()),
3580 formatuser(ctx.user()),
3574 opts.get(b'user'),
3581 opts.get(b'user'),
3575 b'',
3582 b'',
3576 ),
3583 ),
3577 (
3584 (
3578 b'date',
3585 b'date',
3579 b'%s',
3586 b'%s',
3580 fm.formatdate(ctx.date(), datefmt),
3587 fm.formatdate(ctx.date(), datefmt),
3581 opts.get(b'date'),
3588 opts.get(b'date'),
3582 b'',
3589 b'',
3583 ),
3590 ),
3584 ]
3591 ]
3585 )
3592 )
3586 for name, fmt, data, cond, extra_label in cols:
3593 for name, fmt, data, cond, extra_label in cols:
3587 if cond:
3594 if cond:
3588 fm.plain(sep, label=b'grep.sep')
3595 fm.plain(sep, label=b'grep.sep')
3589 field = fieldnamemap.get(name, name)
3596 field = fieldnamemap.get(name, name)
3590 label = extra_label + (b'grep.%s' % name)
3597 label = extra_label + (b'grep.%s' % name)
3591 fm.condwrite(cond, field, fmt, data, label=label)
3598 fm.condwrite(cond, field, fmt, data, label=label)
3592 if not opts.get(b'files_with_matches'):
3599 if not opts.get(b'files_with_matches'):
3593 fm.plain(sep, label=b'grep.sep')
3600 fm.plain(sep, label=b'grep.sep')
3594 if not opts.get(b'text') and binary():
3601 if not opts.get(b'text') and binary():
3595 fm.plain(_(b" Binary file matches"))
3602 fm.plain(_(b" Binary file matches"))
3596 else:
3603 else:
3597 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3604 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3598 fm.plain(eol)
3605 fm.plain(eol)
3599 found = True
3606 found = True
3600 if opts.get(b'files_with_matches'):
3607 if opts.get(b'files_with_matches'):
3601 break
3608 break
3602 return found
3609 return found
3603
3610
3604 def displaymatches(fm, l):
3611 def displaymatches(fm, l):
3605 p = 0
3612 p = 0
3606 for s, e in l.findpos(regexp):
3613 for s, e in l.findpos(regexp):
3607 if p < s:
3614 if p < s:
3608 fm.startitem()
3615 fm.startitem()
3609 fm.write(b'text', b'%s', l.line[p:s])
3616 fm.write(b'text', b'%s', l.line[p:s])
3610 fm.data(matched=False)
3617 fm.data(matched=False)
3611 fm.startitem()
3618 fm.startitem()
3612 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3619 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3613 fm.data(matched=True)
3620 fm.data(matched=True)
3614 p = e
3621 p = e
3615 if p < len(l.line):
3622 if p < len(l.line):
3616 fm.startitem()
3623 fm.startitem()
3617 fm.write(b'text', b'%s', l.line[p:])
3624 fm.write(b'text', b'%s', l.line[p:])
3618 fm.data(matched=False)
3625 fm.data(matched=False)
3619 fm.end()
3626 fm.end()
3620
3627
3621 found = False
3628 found = False
3622
3629
3623 wopts = logcmdutil.walkopts(
3630 wopts = logcmdutil.walkopts(
3624 pats=pats,
3631 pats=pats,
3625 opts=opts,
3632 opts=opts,
3626 revspec=opts[b'rev'],
3633 revspec=opts[b'rev'],
3627 include_pats=opts[b'include'],
3634 include_pats=opts[b'include'],
3628 exclude_pats=opts[b'exclude'],
3635 exclude_pats=opts[b'exclude'],
3629 follow=follow,
3636 follow=follow,
3630 force_changelog_traversal=all_files,
3637 force_changelog_traversal=all_files,
3631 filter_revisions_by_pats=not all_files,
3638 filter_revisions_by_pats=not all_files,
3632 )
3639 )
3633 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3640 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3634
3641
3635 ui.pager(b'grep')
3642 ui.pager(b'grep')
3636 fm = ui.formatter(b'grep', opts)
3643 fm = ui.formatter(b'grep', opts)
3637 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3644 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3638 r = display(fm, fn, ctx, pstates, states)
3645 r = display(fm, fn, ctx, pstates, states)
3639 found = found or r
3646 found = found or r
3640 if r and not diff and not all_files:
3647 if r and not diff and not all_files:
3641 searcher.skipfile(fn, ctx.rev())
3648 searcher.skipfile(fn, ctx.rev())
3642 fm.end()
3649 fm.end()
3643
3650
3644 return not found
3651 return not found
3645
3652
3646
3653
3647 @command(
3654 @command(
3648 b'heads',
3655 b'heads',
3649 [
3656 [
3650 (
3657 (
3651 b'r',
3658 b'r',
3652 b'rev',
3659 b'rev',
3653 b'',
3660 b'',
3654 _(b'show only heads which are descendants of STARTREV'),
3661 _(b'show only heads which are descendants of STARTREV'),
3655 _(b'STARTREV'),
3662 _(b'STARTREV'),
3656 ),
3663 ),
3657 (b't', b'topo', False, _(b'show topological heads only')),
3664 (b't', b'topo', False, _(b'show topological heads only')),
3658 (
3665 (
3659 b'a',
3666 b'a',
3660 b'active',
3667 b'active',
3661 False,
3668 False,
3662 _(b'show active branchheads only (DEPRECATED)'),
3669 _(b'show active branchheads only (DEPRECATED)'),
3663 ),
3670 ),
3664 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3671 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3665 ]
3672 ]
3666 + templateopts,
3673 + templateopts,
3667 _(b'[-ct] [-r STARTREV] [REV]...'),
3674 _(b'[-ct] [-r STARTREV] [REV]...'),
3668 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3675 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3669 intents={INTENT_READONLY},
3676 intents={INTENT_READONLY},
3670 )
3677 )
3671 def heads(ui, repo, *branchrevs, **opts):
3678 def heads(ui, repo, *branchrevs, **opts):
3672 """show branch heads
3679 """show branch heads
3673
3680
3674 With no arguments, show all open branch heads in the repository.
3681 With no arguments, show all open branch heads in the repository.
3675 Branch heads are changesets that have no descendants on the
3682 Branch heads are changesets that have no descendants on the
3676 same branch. They are where development generally takes place and
3683 same branch. They are where development generally takes place and
3677 are the usual targets for update and merge operations.
3684 are the usual targets for update and merge operations.
3678
3685
3679 If one or more REVs are given, only open branch heads on the
3686 If one or more REVs are given, only open branch heads on the
3680 branches associated with the specified changesets are shown. This
3687 branches associated with the specified changesets are shown. This
3681 means that you can use :hg:`heads .` to see the heads on the
3688 means that you can use :hg:`heads .` to see the heads on the
3682 currently checked-out branch.
3689 currently checked-out branch.
3683
3690
3684 If -c/--closed is specified, also show branch heads marked closed
3691 If -c/--closed is specified, also show branch heads marked closed
3685 (see :hg:`commit --close-branch`).
3692 (see :hg:`commit --close-branch`).
3686
3693
3687 If STARTREV is specified, only those heads that are descendants of
3694 If STARTREV is specified, only those heads that are descendants of
3688 STARTREV will be displayed.
3695 STARTREV will be displayed.
3689
3696
3690 If -t/--topo is specified, named branch mechanics will be ignored and only
3697 If -t/--topo is specified, named branch mechanics will be ignored and only
3691 topological heads (changesets with no children) will be shown.
3698 topological heads (changesets with no children) will be shown.
3692
3699
3693 Returns 0 if matching heads are found, 1 if not.
3700 Returns 0 if matching heads are found, 1 if not.
3694 """
3701 """
3695
3702
3696 opts = pycompat.byteskwargs(opts)
3703 opts = pycompat.byteskwargs(opts)
3697 start = None
3704 start = None
3698 rev = opts.get(b'rev')
3705 rev = opts.get(b'rev')
3699 if rev:
3706 if rev:
3700 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3707 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3701 start = logcmdutil.revsingle(repo, rev, None).node()
3708 start = logcmdutil.revsingle(repo, rev, None).node()
3702
3709
3703 if opts.get(b'topo'):
3710 if opts.get(b'topo'):
3704 heads = [repo[h] for h in repo.heads(start)]
3711 heads = [repo[h] for h in repo.heads(start)]
3705 else:
3712 else:
3706 heads = []
3713 heads = []
3707 for branch in repo.branchmap():
3714 for branch in repo.branchmap():
3708 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3715 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3709 heads = [repo[h] for h in heads]
3716 heads = [repo[h] for h in heads]
3710
3717
3711 if branchrevs:
3718 if branchrevs:
3712 branches = {
3719 branches = {
3713 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3720 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3714 }
3721 }
3715 heads = [h for h in heads if h.branch() in branches]
3722 heads = [h for h in heads if h.branch() in branches]
3716
3723
3717 if opts.get(b'active') and branchrevs:
3724 if opts.get(b'active') and branchrevs:
3718 dagheads = repo.heads(start)
3725 dagheads = repo.heads(start)
3719 heads = [h for h in heads if h.node() in dagheads]
3726 heads = [h for h in heads if h.node() in dagheads]
3720
3727
3721 if branchrevs:
3728 if branchrevs:
3722 haveheads = {h.branch() for h in heads}
3729 haveheads = {h.branch() for h in heads}
3723 if branches - haveheads:
3730 if branches - haveheads:
3724 headless = b', '.join(b for b in branches - haveheads)
3731 headless = b', '.join(b for b in branches - haveheads)
3725 msg = _(b'no open branch heads found on branches %s')
3732 msg = _(b'no open branch heads found on branches %s')
3726 if opts.get(b'rev'):
3733 if opts.get(b'rev'):
3727 msg += _(b' (started at %s)') % opts[b'rev']
3734 msg += _(b' (started at %s)') % opts[b'rev']
3728 ui.warn((msg + b'\n') % headless)
3735 ui.warn((msg + b'\n') % headless)
3729
3736
3730 if not heads:
3737 if not heads:
3731 return 1
3738 return 1
3732
3739
3733 ui.pager(b'heads')
3740 ui.pager(b'heads')
3734 heads = sorted(heads, key=lambda x: -(x.rev()))
3741 heads = sorted(heads, key=lambda x: -(x.rev()))
3735 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3742 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3736 for ctx in heads:
3743 for ctx in heads:
3737 displayer.show(ctx)
3744 displayer.show(ctx)
3738 displayer.close()
3745 displayer.close()
3739
3746
3740
3747
3741 @command(
3748 @command(
3742 b'help',
3749 b'help',
3743 [
3750 [
3744 (b'e', b'extension', None, _(b'show only help for extensions')),
3751 (b'e', b'extension', None, _(b'show only help for extensions')),
3745 (b'c', b'command', None, _(b'show only help for commands')),
3752 (b'c', b'command', None, _(b'show only help for commands')),
3746 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3753 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3747 (
3754 (
3748 b's',
3755 b's',
3749 b'system',
3756 b'system',
3750 [],
3757 [],
3751 _(b'show help for specific platform(s)'),
3758 _(b'show help for specific platform(s)'),
3752 _(b'PLATFORM'),
3759 _(b'PLATFORM'),
3753 ),
3760 ),
3754 ],
3761 ],
3755 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3762 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3756 helpcategory=command.CATEGORY_HELP,
3763 helpcategory=command.CATEGORY_HELP,
3757 norepo=True,
3764 norepo=True,
3758 intents={INTENT_READONLY},
3765 intents={INTENT_READONLY},
3759 )
3766 )
3760 def help_(ui, name=None, **opts):
3767 def help_(ui, name=None, **opts):
3761 """show help for a given topic or a help overview
3768 """show help for a given topic or a help overview
3762
3769
3763 With no arguments, print a list of commands with short help messages.
3770 With no arguments, print a list of commands with short help messages.
3764
3771
3765 Given a topic, extension, or command name, print help for that
3772 Given a topic, extension, or command name, print help for that
3766 topic.
3773 topic.
3767
3774
3768 Returns 0 if successful.
3775 Returns 0 if successful.
3769 """
3776 """
3770
3777
3771 keep = opts.get('system') or []
3778 keep = opts.get('system') or []
3772 if len(keep) == 0:
3779 if len(keep) == 0:
3773 if pycompat.sysplatform.startswith(b'win'):
3780 if pycompat.sysplatform.startswith(b'win'):
3774 keep.append(b'windows')
3781 keep.append(b'windows')
3775 elif pycompat.sysplatform == b'OpenVMS':
3782 elif pycompat.sysplatform == b'OpenVMS':
3776 keep.append(b'vms')
3783 keep.append(b'vms')
3777 elif pycompat.sysplatform == b'plan9':
3784 elif pycompat.sysplatform == b'plan9':
3778 keep.append(b'plan9')
3785 keep.append(b'plan9')
3779 else:
3786 else:
3780 keep.append(b'unix')
3787 keep.append(b'unix')
3781 keep.append(pycompat.sysplatform.lower())
3788 keep.append(pycompat.sysplatform.lower())
3782 if ui.verbose:
3789 if ui.verbose:
3783 keep.append(b'verbose')
3790 keep.append(b'verbose')
3784
3791
3785 commands = sys.modules[__name__]
3792 commands = sys.modules[__name__]
3786 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3793 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3787 ui.pager(b'help')
3794 ui.pager(b'help')
3788 ui.write(formatted)
3795 ui.write(formatted)
3789
3796
3790
3797
3791 @command(
3798 @command(
3792 b'identify|id',
3799 b'identify|id',
3793 [
3800 [
3794 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3801 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3795 (b'n', b'num', None, _(b'show local revision number')),
3802 (b'n', b'num', None, _(b'show local revision number')),
3796 (b'i', b'id', None, _(b'show global revision id')),
3803 (b'i', b'id', None, _(b'show global revision id')),
3797 (b'b', b'branch', None, _(b'show branch')),
3804 (b'b', b'branch', None, _(b'show branch')),
3798 (b't', b'tags', None, _(b'show tags')),
3805 (b't', b'tags', None, _(b'show tags')),
3799 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3806 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3800 ]
3807 ]
3801 + remoteopts
3808 + remoteopts
3802 + formatteropts,
3809 + formatteropts,
3803 _(b'[-nibtB] [-r REV] [SOURCE]'),
3810 _(b'[-nibtB] [-r REV] [SOURCE]'),
3804 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3811 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3805 optionalrepo=True,
3812 optionalrepo=True,
3806 intents={INTENT_READONLY},
3813 intents={INTENT_READONLY},
3807 )
3814 )
3808 def identify(
3815 def identify(
3809 ui,
3816 ui,
3810 repo,
3817 repo,
3811 source=None,
3818 source=None,
3812 rev=None,
3819 rev=None,
3813 num=None,
3820 num=None,
3814 id=None,
3821 id=None,
3815 branch=None,
3822 branch=None,
3816 tags=None,
3823 tags=None,
3817 bookmarks=None,
3824 bookmarks=None,
3818 **opts
3825 **opts
3819 ):
3826 ):
3820 """identify the working directory or specified revision
3827 """identify the working directory or specified revision
3821
3828
3822 Print a summary identifying the repository state at REV using one or
3829 Print a summary identifying the repository state at REV using one or
3823 two parent hash identifiers, followed by a "+" if the working
3830 two parent hash identifiers, followed by a "+" if the working
3824 directory has uncommitted changes, the branch name (if not default),
3831 directory has uncommitted changes, the branch name (if not default),
3825 a list of tags, and a list of bookmarks.
3832 a list of tags, and a list of bookmarks.
3826
3833
3827 When REV is not given, print a summary of the current state of the
3834 When REV is not given, print a summary of the current state of the
3828 repository including the working directory. Specify -r. to get information
3835 repository including the working directory. Specify -r. to get information
3829 of the working directory parent without scanning uncommitted changes.
3836 of the working directory parent without scanning uncommitted changes.
3830
3837
3831 Specifying a path to a repository root or Mercurial bundle will
3838 Specifying a path to a repository root or Mercurial bundle will
3832 cause lookup to operate on that repository/bundle.
3839 cause lookup to operate on that repository/bundle.
3833
3840
3834 .. container:: verbose
3841 .. container:: verbose
3835
3842
3836 Template:
3843 Template:
3837
3844
3838 The following keywords are supported in addition to the common template
3845 The following keywords are supported in addition to the common template
3839 keywords and functions. See also :hg:`help templates`.
3846 keywords and functions. See also :hg:`help templates`.
3840
3847
3841 :dirty: String. Character ``+`` denoting if the working directory has
3848 :dirty: String. Character ``+`` denoting if the working directory has
3842 uncommitted changes.
3849 uncommitted changes.
3843 :id: String. One or two nodes, optionally followed by ``+``.
3850 :id: String. One or two nodes, optionally followed by ``+``.
3844 :parents: List of strings. Parent nodes of the changeset.
3851 :parents: List of strings. Parent nodes of the changeset.
3845
3852
3846 Examples:
3853 Examples:
3847
3854
3848 - generate a build identifier for the working directory::
3855 - generate a build identifier for the working directory::
3849
3856
3850 hg id --id > build-id.dat
3857 hg id --id > build-id.dat
3851
3858
3852 - find the revision corresponding to a tag::
3859 - find the revision corresponding to a tag::
3853
3860
3854 hg id -n -r 1.3
3861 hg id -n -r 1.3
3855
3862
3856 - check the most recent revision of a remote repository::
3863 - check the most recent revision of a remote repository::
3857
3864
3858 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3865 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3859
3866
3860 See :hg:`log` for generating more information about specific revisions,
3867 See :hg:`log` for generating more information about specific revisions,
3861 including full hash identifiers.
3868 including full hash identifiers.
3862
3869
3863 Returns 0 if successful.
3870 Returns 0 if successful.
3864 """
3871 """
3865
3872
3866 opts = pycompat.byteskwargs(opts)
3873 opts = pycompat.byteskwargs(opts)
3867 if not repo and not source:
3874 if not repo and not source:
3868 raise error.InputError(
3875 raise error.InputError(
3869 _(b"there is no Mercurial repository here (.hg not found)")
3876 _(b"there is no Mercurial repository here (.hg not found)")
3870 )
3877 )
3871
3878
3872 default = not (num or id or branch or tags or bookmarks)
3879 default = not (num or id or branch or tags or bookmarks)
3873 output = []
3880 output = []
3874 revs = []
3881 revs = []
3875
3882
3876 peer = None
3883 peer = None
3877 try:
3884 try:
3878 if source:
3885 if source:
3879 source, branches = urlutil.get_unique_pull_path(
3886 source, branches = urlutil.get_unique_pull_path(
3880 b'identify', repo, ui, source
3887 b'identify', repo, ui, source
3881 )
3888 )
3882 # only pass ui when no repo
3889 # only pass ui when no repo
3883 peer = hg.peer(repo or ui, opts, source)
3890 peer = hg.peer(repo or ui, opts, source)
3884 repo = peer.local()
3891 repo = peer.local()
3885 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3892 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3886
3893
3887 fm = ui.formatter(b'identify', opts)
3894 fm = ui.formatter(b'identify', opts)
3888 fm.startitem()
3895 fm.startitem()
3889
3896
3890 if not repo:
3897 if not repo:
3891 if num or branch or tags:
3898 if num or branch or tags:
3892 raise error.InputError(
3899 raise error.InputError(
3893 _(b"can't query remote revision number, branch, or tags")
3900 _(b"can't query remote revision number, branch, or tags")
3894 )
3901 )
3895 if not rev and revs:
3902 if not rev and revs:
3896 rev = revs[0]
3903 rev = revs[0]
3897 if not rev:
3904 if not rev:
3898 rev = b"tip"
3905 rev = b"tip"
3899
3906
3900 remoterev = peer.lookup(rev)
3907 remoterev = peer.lookup(rev)
3901 hexrev = fm.hexfunc(remoterev)
3908 hexrev = fm.hexfunc(remoterev)
3902 if default or id:
3909 if default or id:
3903 output = [hexrev]
3910 output = [hexrev]
3904 fm.data(id=hexrev)
3911 fm.data(id=hexrev)
3905
3912
3906 @util.cachefunc
3913 @util.cachefunc
3907 def getbms():
3914 def getbms():
3908 bms = []
3915 bms = []
3909
3916
3910 if b'bookmarks' in peer.listkeys(b'namespaces'):
3917 if b'bookmarks' in peer.listkeys(b'namespaces'):
3911 hexremoterev = hex(remoterev)
3918 hexremoterev = hex(remoterev)
3912 bms = [
3919 bms = [
3913 bm
3920 bm
3914 for bm, bmr in pycompat.iteritems(
3921 for bm, bmr in pycompat.iteritems(
3915 peer.listkeys(b'bookmarks')
3922 peer.listkeys(b'bookmarks')
3916 )
3923 )
3917 if bmr == hexremoterev
3924 if bmr == hexremoterev
3918 ]
3925 ]
3919
3926
3920 return sorted(bms)
3927 return sorted(bms)
3921
3928
3922 if fm.isplain():
3929 if fm.isplain():
3923 if bookmarks:
3930 if bookmarks:
3924 output.extend(getbms())
3931 output.extend(getbms())
3925 elif default and not ui.quiet:
3932 elif default and not ui.quiet:
3926 # multiple bookmarks for a single parent separated by '/'
3933 # multiple bookmarks for a single parent separated by '/'
3927 bm = b'/'.join(getbms())
3934 bm = b'/'.join(getbms())
3928 if bm:
3935 if bm:
3929 output.append(bm)
3936 output.append(bm)
3930 else:
3937 else:
3931 fm.data(node=hex(remoterev))
3938 fm.data(node=hex(remoterev))
3932 if bookmarks or b'bookmarks' in fm.datahint():
3939 if bookmarks or b'bookmarks' in fm.datahint():
3933 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3940 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3934 else:
3941 else:
3935 if rev:
3942 if rev:
3936 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3943 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3937 ctx = logcmdutil.revsingle(repo, rev, None)
3944 ctx = logcmdutil.revsingle(repo, rev, None)
3938
3945
3939 if ctx.rev() is None:
3946 if ctx.rev() is None:
3940 ctx = repo[None]
3947 ctx = repo[None]
3941 parents = ctx.parents()
3948 parents = ctx.parents()
3942 taglist = []
3949 taglist = []
3943 for p in parents:
3950 for p in parents:
3944 taglist.extend(p.tags())
3951 taglist.extend(p.tags())
3945
3952
3946 dirty = b""
3953 dirty = b""
3947 if ctx.dirty(missing=True, merge=False, branch=False):
3954 if ctx.dirty(missing=True, merge=False, branch=False):
3948 dirty = b'+'
3955 dirty = b'+'
3949 fm.data(dirty=dirty)
3956 fm.data(dirty=dirty)
3950
3957
3951 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3958 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3952 if default or id:
3959 if default or id:
3953 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3960 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3954 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3961 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3955
3962
3956 if num:
3963 if num:
3957 numoutput = [b"%d" % p.rev() for p in parents]
3964 numoutput = [b"%d" % p.rev() for p in parents]
3958 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3965 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3959
3966
3960 fm.data(
3967 fm.data(
3961 parents=fm.formatlist(
3968 parents=fm.formatlist(
3962 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3969 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3963 )
3970 )
3964 )
3971 )
3965 else:
3972 else:
3966 hexoutput = fm.hexfunc(ctx.node())
3973 hexoutput = fm.hexfunc(ctx.node())
3967 if default or id:
3974 if default or id:
3968 output = [hexoutput]
3975 output = [hexoutput]
3969 fm.data(id=hexoutput)
3976 fm.data(id=hexoutput)
3970
3977
3971 if num:
3978 if num:
3972 output.append(pycompat.bytestr(ctx.rev()))
3979 output.append(pycompat.bytestr(ctx.rev()))
3973 taglist = ctx.tags()
3980 taglist = ctx.tags()
3974
3981
3975 if default and not ui.quiet:
3982 if default and not ui.quiet:
3976 b = ctx.branch()
3983 b = ctx.branch()
3977 if b != b'default':
3984 if b != b'default':
3978 output.append(b"(%s)" % b)
3985 output.append(b"(%s)" % b)
3979
3986
3980 # multiple tags for a single parent separated by '/'
3987 # multiple tags for a single parent separated by '/'
3981 t = b'/'.join(taglist)
3988 t = b'/'.join(taglist)
3982 if t:
3989 if t:
3983 output.append(t)
3990 output.append(t)
3984
3991
3985 # multiple bookmarks for a single parent separated by '/'
3992 # multiple bookmarks for a single parent separated by '/'
3986 bm = b'/'.join(ctx.bookmarks())
3993 bm = b'/'.join(ctx.bookmarks())
3987 if bm:
3994 if bm:
3988 output.append(bm)
3995 output.append(bm)
3989 else:
3996 else:
3990 if branch:
3997 if branch:
3991 output.append(ctx.branch())
3998 output.append(ctx.branch())
3992
3999
3993 if tags:
4000 if tags:
3994 output.extend(taglist)
4001 output.extend(taglist)
3995
4002
3996 if bookmarks:
4003 if bookmarks:
3997 output.extend(ctx.bookmarks())
4004 output.extend(ctx.bookmarks())
3998
4005
3999 fm.data(node=ctx.hex())
4006 fm.data(node=ctx.hex())
4000 fm.data(branch=ctx.branch())
4007 fm.data(branch=ctx.branch())
4001 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4008 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4002 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4009 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4003 fm.context(ctx=ctx)
4010 fm.context(ctx=ctx)
4004
4011
4005 fm.plain(b"%s\n" % b' '.join(output))
4012 fm.plain(b"%s\n" % b' '.join(output))
4006 fm.end()
4013 fm.end()
4007 finally:
4014 finally:
4008 if peer:
4015 if peer:
4009 peer.close()
4016 peer.close()
4010
4017
4011
4018
4012 @command(
4019 @command(
4013 b'import|patch',
4020 b'import|patch',
4014 [
4021 [
4015 (
4022 (
4016 b'p',
4023 b'p',
4017 b'strip',
4024 b'strip',
4018 1,
4025 1,
4019 _(
4026 _(
4020 b'directory strip option for patch. This has the same '
4027 b'directory strip option for patch. This has the same '
4021 b'meaning as the corresponding patch option'
4028 b'meaning as the corresponding patch option'
4022 ),
4029 ),
4023 _(b'NUM'),
4030 _(b'NUM'),
4024 ),
4031 ),
4025 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4032 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4026 (b'', b'secret', None, _(b'use the secret phase for committing')),
4033 (b'', b'secret', None, _(b'use the secret phase for committing')),
4027 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4034 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4028 (
4035 (
4029 b'f',
4036 b'f',
4030 b'force',
4037 b'force',
4031 None,
4038 None,
4032 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4039 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4033 ),
4040 ),
4034 (
4041 (
4035 b'',
4042 b'',
4036 b'no-commit',
4043 b'no-commit',
4037 None,
4044 None,
4038 _(b"don't commit, just update the working directory"),
4045 _(b"don't commit, just update the working directory"),
4039 ),
4046 ),
4040 (
4047 (
4041 b'',
4048 b'',
4042 b'bypass',
4049 b'bypass',
4043 None,
4050 None,
4044 _(b"apply patch without touching the working directory"),
4051 _(b"apply patch without touching the working directory"),
4045 ),
4052 ),
4046 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4053 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4047 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4054 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4048 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4055 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4049 (
4056 (
4050 b'',
4057 b'',
4051 b'import-branch',
4058 b'import-branch',
4052 None,
4059 None,
4053 _(b'use any branch information in patch (implied by --exact)'),
4060 _(b'use any branch information in patch (implied by --exact)'),
4054 ),
4061 ),
4055 ]
4062 ]
4056 + commitopts
4063 + commitopts
4057 + commitopts2
4064 + commitopts2
4058 + similarityopts,
4065 + similarityopts,
4059 _(b'[OPTION]... PATCH...'),
4066 _(b'[OPTION]... PATCH...'),
4060 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4067 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4061 )
4068 )
4062 def import_(ui, repo, patch1=None, *patches, **opts):
4069 def import_(ui, repo, patch1=None, *patches, **opts):
4063 """import an ordered set of patches
4070 """import an ordered set of patches
4064
4071
4065 Import a list of patches and commit them individually (unless
4072 Import a list of patches and commit them individually (unless
4066 --no-commit is specified).
4073 --no-commit is specified).
4067
4074
4068 To read a patch from standard input (stdin), use "-" as the patch
4075 To read a patch from standard input (stdin), use "-" as the patch
4069 name. If a URL is specified, the patch will be downloaded from
4076 name. If a URL is specified, the patch will be downloaded from
4070 there.
4077 there.
4071
4078
4072 Import first applies changes to the working directory (unless
4079 Import first applies changes to the working directory (unless
4073 --bypass is specified), import will abort if there are outstanding
4080 --bypass is specified), import will abort if there are outstanding
4074 changes.
4081 changes.
4075
4082
4076 Use --bypass to apply and commit patches directly to the
4083 Use --bypass to apply and commit patches directly to the
4077 repository, without affecting the working directory. Without
4084 repository, without affecting the working directory. Without
4078 --exact, patches will be applied on top of the working directory
4085 --exact, patches will be applied on top of the working directory
4079 parent revision.
4086 parent revision.
4080
4087
4081 You can import a patch straight from a mail message. Even patches
4088 You can import a patch straight from a mail message. Even patches
4082 as attachments work (to use the body part, it must have type
4089 as attachments work (to use the body part, it must have type
4083 text/plain or text/x-patch). From and Subject headers of email
4090 text/plain or text/x-patch). From and Subject headers of email
4084 message are used as default committer and commit message. All
4091 message are used as default committer and commit message. All
4085 text/plain body parts before first diff are added to the commit
4092 text/plain body parts before first diff are added to the commit
4086 message.
4093 message.
4087
4094
4088 If the imported patch was generated by :hg:`export`, user and
4095 If the imported patch was generated by :hg:`export`, user and
4089 description from patch override values from message headers and
4096 description from patch override values from message headers and
4090 body. Values given on command line with -m/--message and -u/--user
4097 body. Values given on command line with -m/--message and -u/--user
4091 override these.
4098 override these.
4092
4099
4093 If --exact is specified, import will set the working directory to
4100 If --exact is specified, import will set the working directory to
4094 the parent of each patch before applying it, and will abort if the
4101 the parent of each patch before applying it, and will abort if the
4095 resulting changeset has a different ID than the one recorded in
4102 resulting changeset has a different ID than the one recorded in
4096 the patch. This will guard against various ways that portable
4103 the patch. This will guard against various ways that portable
4097 patch formats and mail systems might fail to transfer Mercurial
4104 patch formats and mail systems might fail to transfer Mercurial
4098 data or metadata. See :hg:`bundle` for lossless transmission.
4105 data or metadata. See :hg:`bundle` for lossless transmission.
4099
4106
4100 Use --partial to ensure a changeset will be created from the patch
4107 Use --partial to ensure a changeset will be created from the patch
4101 even if some hunks fail to apply. Hunks that fail to apply will be
4108 even if some hunks fail to apply. Hunks that fail to apply will be
4102 written to a <target-file>.rej file. Conflicts can then be resolved
4109 written to a <target-file>.rej file. Conflicts can then be resolved
4103 by hand before :hg:`commit --amend` is run to update the created
4110 by hand before :hg:`commit --amend` is run to update the created
4104 changeset. This flag exists to let people import patches that
4111 changeset. This flag exists to let people import patches that
4105 partially apply without losing the associated metadata (author,
4112 partially apply without losing the associated metadata (author,
4106 date, description, ...).
4113 date, description, ...).
4107
4114
4108 .. note::
4115 .. note::
4109
4116
4110 When no hunks apply cleanly, :hg:`import --partial` will create
4117 When no hunks apply cleanly, :hg:`import --partial` will create
4111 an empty changeset, importing only the patch metadata.
4118 an empty changeset, importing only the patch metadata.
4112
4119
4113 With -s/--similarity, hg will attempt to discover renames and
4120 With -s/--similarity, hg will attempt to discover renames and
4114 copies in the patch in the same way as :hg:`addremove`.
4121 copies in the patch in the same way as :hg:`addremove`.
4115
4122
4116 It is possible to use external patch programs to perform the patch
4123 It is possible to use external patch programs to perform the patch
4117 by setting the ``ui.patch`` configuration option. For the default
4124 by setting the ``ui.patch`` configuration option. For the default
4118 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4125 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4119 See :hg:`help config` for more information about configuration
4126 See :hg:`help config` for more information about configuration
4120 files and how to use these options.
4127 files and how to use these options.
4121
4128
4122 See :hg:`help dates` for a list of formats valid for -d/--date.
4129 See :hg:`help dates` for a list of formats valid for -d/--date.
4123
4130
4124 .. container:: verbose
4131 .. container:: verbose
4125
4132
4126 Examples:
4133 Examples:
4127
4134
4128 - import a traditional patch from a website and detect renames::
4135 - import a traditional patch from a website and detect renames::
4129
4136
4130 hg import -s 80 http://example.com/bugfix.patch
4137 hg import -s 80 http://example.com/bugfix.patch
4131
4138
4132 - import a changeset from an hgweb server::
4139 - import a changeset from an hgweb server::
4133
4140
4134 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4141 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4135
4142
4136 - import all the patches in an Unix-style mbox::
4143 - import all the patches in an Unix-style mbox::
4137
4144
4138 hg import incoming-patches.mbox
4145 hg import incoming-patches.mbox
4139
4146
4140 - import patches from stdin::
4147 - import patches from stdin::
4141
4148
4142 hg import -
4149 hg import -
4143
4150
4144 - attempt to exactly restore an exported changeset (not always
4151 - attempt to exactly restore an exported changeset (not always
4145 possible)::
4152 possible)::
4146
4153
4147 hg import --exact proposed-fix.patch
4154 hg import --exact proposed-fix.patch
4148
4155
4149 - use an external tool to apply a patch which is too fuzzy for
4156 - use an external tool to apply a patch which is too fuzzy for
4150 the default internal tool.
4157 the default internal tool.
4151
4158
4152 hg import --config ui.patch="patch --merge" fuzzy.patch
4159 hg import --config ui.patch="patch --merge" fuzzy.patch
4153
4160
4154 - change the default fuzzing from 2 to a less strict 7
4161 - change the default fuzzing from 2 to a less strict 7
4155
4162
4156 hg import --config ui.fuzz=7 fuzz.patch
4163 hg import --config ui.fuzz=7 fuzz.patch
4157
4164
4158 Returns 0 on success, 1 on partial success (see --partial).
4165 Returns 0 on success, 1 on partial success (see --partial).
4159 """
4166 """
4160
4167
4161 cmdutil.check_incompatible_arguments(
4168 cmdutil.check_incompatible_arguments(
4162 opts, 'no_commit', ['bypass', 'secret']
4169 opts, 'no_commit', ['bypass', 'secret']
4163 )
4170 )
4164 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4171 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4165 opts = pycompat.byteskwargs(opts)
4172 opts = pycompat.byteskwargs(opts)
4166 if not patch1:
4173 if not patch1:
4167 raise error.InputError(_(b'need at least one patch to import'))
4174 raise error.InputError(_(b'need at least one patch to import'))
4168
4175
4169 patches = (patch1,) + patches
4176 patches = (patch1,) + patches
4170
4177
4171 date = opts.get(b'date')
4178 date = opts.get(b'date')
4172 if date:
4179 if date:
4173 opts[b'date'] = dateutil.parsedate(date)
4180 opts[b'date'] = dateutil.parsedate(date)
4174
4181
4175 exact = opts.get(b'exact')
4182 exact = opts.get(b'exact')
4176 update = not opts.get(b'bypass')
4183 update = not opts.get(b'bypass')
4177 try:
4184 try:
4178 sim = float(opts.get(b'similarity') or 0)
4185 sim = float(opts.get(b'similarity') or 0)
4179 except ValueError:
4186 except ValueError:
4180 raise error.InputError(_(b'similarity must be a number'))
4187 raise error.InputError(_(b'similarity must be a number'))
4181 if sim < 0 or sim > 100:
4188 if sim < 0 or sim > 100:
4182 raise error.InputError(_(b'similarity must be between 0 and 100'))
4189 raise error.InputError(_(b'similarity must be between 0 and 100'))
4183 if sim and not update:
4190 if sim and not update:
4184 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4191 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4185
4192
4186 base = opts[b"base"]
4193 base = opts[b"base"]
4187 msgs = []
4194 msgs = []
4188 ret = 0
4195 ret = 0
4189
4196
4190 with repo.wlock():
4197 with repo.wlock():
4191 if update:
4198 if update:
4192 cmdutil.checkunfinished(repo)
4199 cmdutil.checkunfinished(repo)
4193 if exact or not opts.get(b'force'):
4200 if exact or not opts.get(b'force'):
4194 cmdutil.bailifchanged(repo)
4201 cmdutil.bailifchanged(repo)
4195
4202
4196 if not opts.get(b'no_commit'):
4203 if not opts.get(b'no_commit'):
4197 lock = repo.lock
4204 lock = repo.lock
4198 tr = lambda: repo.transaction(b'import')
4205 tr = lambda: repo.transaction(b'import')
4199 dsguard = util.nullcontextmanager
4206 dsguard = util.nullcontextmanager
4200 else:
4207 else:
4201 lock = util.nullcontextmanager
4208 lock = util.nullcontextmanager
4202 tr = util.nullcontextmanager
4209 tr = util.nullcontextmanager
4203 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4210 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4204 with lock(), tr(), dsguard():
4211 with lock(), tr(), dsguard():
4205 parents = repo[None].parents()
4212 parents = repo[None].parents()
4206 for patchurl in patches:
4213 for patchurl in patches:
4207 if patchurl == b'-':
4214 if patchurl == b'-':
4208 ui.status(_(b'applying patch from stdin\n'))
4215 ui.status(_(b'applying patch from stdin\n'))
4209 patchfile = ui.fin
4216 patchfile = ui.fin
4210 patchurl = b'stdin' # for error message
4217 patchurl = b'stdin' # for error message
4211 else:
4218 else:
4212 patchurl = os.path.join(base, patchurl)
4219 patchurl = os.path.join(base, patchurl)
4213 ui.status(_(b'applying %s\n') % patchurl)
4220 ui.status(_(b'applying %s\n') % patchurl)
4214 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4221 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4215
4222
4216 haspatch = False
4223 haspatch = False
4217 for hunk in patch.split(patchfile):
4224 for hunk in patch.split(patchfile):
4218 with patch.extract(ui, hunk) as patchdata:
4225 with patch.extract(ui, hunk) as patchdata:
4219 msg, node, rej = cmdutil.tryimportone(
4226 msg, node, rej = cmdutil.tryimportone(
4220 ui, repo, patchdata, parents, opts, msgs, hg.clean
4227 ui, repo, patchdata, parents, opts, msgs, hg.clean
4221 )
4228 )
4222 if msg:
4229 if msg:
4223 haspatch = True
4230 haspatch = True
4224 ui.note(msg + b'\n')
4231 ui.note(msg + b'\n')
4225 if update or exact:
4232 if update or exact:
4226 parents = repo[None].parents()
4233 parents = repo[None].parents()
4227 else:
4234 else:
4228 parents = [repo[node]]
4235 parents = [repo[node]]
4229 if rej:
4236 if rej:
4230 ui.write_err(_(b"patch applied partially\n"))
4237 ui.write_err(_(b"patch applied partially\n"))
4231 ui.write_err(
4238 ui.write_err(
4232 _(
4239 _(
4233 b"(fix the .rej files and run "
4240 b"(fix the .rej files and run "
4234 b"`hg commit --amend`)\n"
4241 b"`hg commit --amend`)\n"
4235 )
4242 )
4236 )
4243 )
4237 ret = 1
4244 ret = 1
4238 break
4245 break
4239
4246
4240 if not haspatch:
4247 if not haspatch:
4241 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4248 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4242
4249
4243 if msgs:
4250 if msgs:
4244 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4251 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4245 return ret
4252 return ret
4246
4253
4247
4254
4248 @command(
4255 @command(
4249 b'incoming|in',
4256 b'incoming|in',
4250 [
4257 [
4251 (
4258 (
4252 b'f',
4259 b'f',
4253 b'force',
4260 b'force',
4254 None,
4261 None,
4255 _(b'run even if remote repository is unrelated'),
4262 _(b'run even if remote repository is unrelated'),
4256 ),
4263 ),
4257 (b'n', b'newest-first', None, _(b'show newest record first')),
4264 (b'n', b'newest-first', None, _(b'show newest record first')),
4258 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4265 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4259 (
4266 (
4260 b'r',
4267 b'r',
4261 b'rev',
4268 b'rev',
4262 [],
4269 [],
4263 _(b'a remote changeset intended to be added'),
4270 _(b'a remote changeset intended to be added'),
4264 _(b'REV'),
4271 _(b'REV'),
4265 ),
4272 ),
4266 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4273 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4267 (
4274 (
4268 b'b',
4275 b'b',
4269 b'branch',
4276 b'branch',
4270 [],
4277 [],
4271 _(b'a specific branch you would like to pull'),
4278 _(b'a specific branch you would like to pull'),
4272 _(b'BRANCH'),
4279 _(b'BRANCH'),
4273 ),
4280 ),
4274 ]
4281 ]
4275 + logopts
4282 + logopts
4276 + remoteopts
4283 + remoteopts
4277 + subrepoopts,
4284 + subrepoopts,
4278 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4285 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4279 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4286 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4280 )
4287 )
4281 def incoming(ui, repo, source=b"default", **opts):
4288 def incoming(ui, repo, source=b"default", **opts):
4282 """show new changesets found in source
4289 """show new changesets found in source
4283
4290
4284 Show new changesets found in the specified path/URL or the default
4291 Show new changesets found in the specified path/URL or the default
4285 pull location. These are the changesets that would have been pulled
4292 pull location. These are the changesets that would have been pulled
4286 by :hg:`pull` at the time you issued this command.
4293 by :hg:`pull` at the time you issued this command.
4287
4294
4288 See pull for valid source format details.
4295 See pull for valid source format details.
4289
4296
4290 .. container:: verbose
4297 .. container:: verbose
4291
4298
4292 With -B/--bookmarks, the result of bookmark comparison between
4299 With -B/--bookmarks, the result of bookmark comparison between
4293 local and remote repositories is displayed. With -v/--verbose,
4300 local and remote repositories is displayed. With -v/--verbose,
4294 status is also displayed for each bookmark like below::
4301 status is also displayed for each bookmark like below::
4295
4302
4296 BM1 01234567890a added
4303 BM1 01234567890a added
4297 BM2 1234567890ab advanced
4304 BM2 1234567890ab advanced
4298 BM3 234567890abc diverged
4305 BM3 234567890abc diverged
4299 BM4 34567890abcd changed
4306 BM4 34567890abcd changed
4300
4307
4301 The action taken locally when pulling depends on the
4308 The action taken locally when pulling depends on the
4302 status of each bookmark:
4309 status of each bookmark:
4303
4310
4304 :``added``: pull will create it
4311 :``added``: pull will create it
4305 :``advanced``: pull will update it
4312 :``advanced``: pull will update it
4306 :``diverged``: pull will create a divergent bookmark
4313 :``diverged``: pull will create a divergent bookmark
4307 :``changed``: result depends on remote changesets
4314 :``changed``: result depends on remote changesets
4308
4315
4309 From the point of view of pulling behavior, bookmark
4316 From the point of view of pulling behavior, bookmark
4310 existing only in the remote repository are treated as ``added``,
4317 existing only in the remote repository are treated as ``added``,
4311 even if it is in fact locally deleted.
4318 even if it is in fact locally deleted.
4312
4319
4313 .. container:: verbose
4320 .. container:: verbose
4314
4321
4315 For remote repository, using --bundle avoids downloading the
4322 For remote repository, using --bundle avoids downloading the
4316 changesets twice if the incoming is followed by a pull.
4323 changesets twice if the incoming is followed by a pull.
4317
4324
4318 Examples:
4325 Examples:
4319
4326
4320 - show incoming changes with patches and full description::
4327 - show incoming changes with patches and full description::
4321
4328
4322 hg incoming -vp
4329 hg incoming -vp
4323
4330
4324 - show incoming changes excluding merges, store a bundle::
4331 - show incoming changes excluding merges, store a bundle::
4325
4332
4326 hg in -vpM --bundle incoming.hg
4333 hg in -vpM --bundle incoming.hg
4327 hg pull incoming.hg
4334 hg pull incoming.hg
4328
4335
4329 - briefly list changes inside a bundle::
4336 - briefly list changes inside a bundle::
4330
4337
4331 hg in changes.hg -T "{desc|firstline}\\n"
4338 hg in changes.hg -T "{desc|firstline}\\n"
4332
4339
4333 Returns 0 if there are incoming changes, 1 otherwise.
4340 Returns 0 if there are incoming changes, 1 otherwise.
4334 """
4341 """
4335 opts = pycompat.byteskwargs(opts)
4342 opts = pycompat.byteskwargs(opts)
4336 if opts.get(b'graph'):
4343 if opts.get(b'graph'):
4337 logcmdutil.checkunsupportedgraphflags([], opts)
4344 logcmdutil.checkunsupportedgraphflags([], opts)
4338
4345
4339 def display(other, chlist, displayer):
4346 def display(other, chlist, displayer):
4340 revdag = logcmdutil.graphrevs(other, chlist, opts)
4347 revdag = logcmdutil.graphrevs(other, chlist, opts)
4341 logcmdutil.displaygraph(
4348 logcmdutil.displaygraph(
4342 ui, repo, revdag, displayer, graphmod.asciiedges
4349 ui, repo, revdag, displayer, graphmod.asciiedges
4343 )
4350 )
4344
4351
4345 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4346 return 0
4353 return 0
4347
4354
4348 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4355 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4349
4356
4350 if opts.get(b'bookmarks'):
4357 if opts.get(b'bookmarks'):
4351 srcs = urlutil.get_pull_paths(repo, ui, [source])
4358 srcs = urlutil.get_pull_paths(repo, ui, [source])
4352 for path in srcs:
4359 for path in srcs:
4353 source, branches = urlutil.parseurl(
4360 source, branches = urlutil.parseurl(
4354 path.rawloc, opts.get(b'branch')
4361 path.rawloc, opts.get(b'branch')
4355 )
4362 )
4356 other = hg.peer(repo, opts, source)
4363 other = hg.peer(repo, opts, source)
4357 try:
4364 try:
4358 if b'bookmarks' not in other.listkeys(b'namespaces'):
4365 if b'bookmarks' not in other.listkeys(b'namespaces'):
4359 ui.warn(_(b"remote doesn't support bookmarks\n"))
4366 ui.warn(_(b"remote doesn't support bookmarks\n"))
4360 return 0
4367 return 0
4361 ui.pager(b'incoming')
4368 ui.pager(b'incoming')
4362 ui.status(
4369 ui.status(
4363 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4370 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4364 )
4371 )
4365 return bookmarks.incoming(
4372 return bookmarks.incoming(
4366 ui, repo, other, mode=path.bookmarks_mode
4373 ui, repo, other, mode=path.bookmarks_mode
4367 )
4374 )
4368 finally:
4375 finally:
4369 other.close()
4376 other.close()
4370
4377
4371 return hg.incoming(ui, repo, source, opts)
4378 return hg.incoming(ui, repo, source, opts)
4372
4379
4373
4380
4374 @command(
4381 @command(
4375 b'init',
4382 b'init',
4376 remoteopts,
4383 remoteopts,
4377 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4384 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4378 helpcategory=command.CATEGORY_REPO_CREATION,
4385 helpcategory=command.CATEGORY_REPO_CREATION,
4379 helpbasic=True,
4386 helpbasic=True,
4380 norepo=True,
4387 norepo=True,
4381 )
4388 )
4382 def init(ui, dest=b".", **opts):
4389 def init(ui, dest=b".", **opts):
4383 """create a new repository in the given directory
4390 """create a new repository in the given directory
4384
4391
4385 Initialize a new repository in the given directory. If the given
4392 Initialize a new repository in the given directory. If the given
4386 directory does not exist, it will be created.
4393 directory does not exist, it will be created.
4387
4394
4388 If no directory is given, the current directory is used.
4395 If no directory is given, the current directory is used.
4389
4396
4390 It is possible to specify an ``ssh://`` URL as the destination.
4397 It is possible to specify an ``ssh://`` URL as the destination.
4391 See :hg:`help urls` for more information.
4398 See :hg:`help urls` for more information.
4392
4399
4393 Returns 0 on success.
4400 Returns 0 on success.
4394 """
4401 """
4395 opts = pycompat.byteskwargs(opts)
4402 opts = pycompat.byteskwargs(opts)
4396 path = urlutil.get_clone_path(ui, dest)[1]
4403 path = urlutil.get_clone_path(ui, dest)[1]
4397 peer = hg.peer(ui, opts, path, create=True)
4404 peer = hg.peer(ui, opts, path, create=True)
4398 peer.close()
4405 peer.close()
4399
4406
4400
4407
4401 @command(
4408 @command(
4402 b'locate',
4409 b'locate',
4403 [
4410 [
4404 (
4411 (
4405 b'r',
4412 b'r',
4406 b'rev',
4413 b'rev',
4407 b'',
4414 b'',
4408 _(b'search the repository as it is in REV'),
4415 _(b'search the repository as it is in REV'),
4409 _(b'REV'),
4416 _(b'REV'),
4410 ),
4417 ),
4411 (
4418 (
4412 b'0',
4419 b'0',
4413 b'print0',
4420 b'print0',
4414 None,
4421 None,
4415 _(b'end filenames with NUL, for use with xargs'),
4422 _(b'end filenames with NUL, for use with xargs'),
4416 ),
4423 ),
4417 (
4424 (
4418 b'f',
4425 b'f',
4419 b'fullpath',
4426 b'fullpath',
4420 None,
4427 None,
4421 _(b'print complete paths from the filesystem root'),
4428 _(b'print complete paths from the filesystem root'),
4422 ),
4429 ),
4423 ]
4430 ]
4424 + walkopts,
4431 + walkopts,
4425 _(b'[OPTION]... [PATTERN]...'),
4432 _(b'[OPTION]... [PATTERN]...'),
4426 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4433 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4427 )
4434 )
4428 def locate(ui, repo, *pats, **opts):
4435 def locate(ui, repo, *pats, **opts):
4429 """locate files matching specific patterns (DEPRECATED)
4436 """locate files matching specific patterns (DEPRECATED)
4430
4437
4431 Print files under Mercurial control in the working directory whose
4438 Print files under Mercurial control in the working directory whose
4432 names match the given patterns.
4439 names match the given patterns.
4433
4440
4434 By default, this command searches all directories in the working
4441 By default, this command searches all directories in the working
4435 directory. To search just the current directory and its
4442 directory. To search just the current directory and its
4436 subdirectories, use "--include .".
4443 subdirectories, use "--include .".
4437
4444
4438 If no patterns are given to match, this command prints the names
4445 If no patterns are given to match, this command prints the names
4439 of all files under Mercurial control in the working directory.
4446 of all files under Mercurial control in the working directory.
4440
4447
4441 If you want to feed the output of this command into the "xargs"
4448 If you want to feed the output of this command into the "xargs"
4442 command, use the -0 option to both this command and "xargs". This
4449 command, use the -0 option to both this command and "xargs". This
4443 will avoid the problem of "xargs" treating single filenames that
4450 will avoid the problem of "xargs" treating single filenames that
4444 contain whitespace as multiple filenames.
4451 contain whitespace as multiple filenames.
4445
4452
4446 See :hg:`help files` for a more versatile command.
4453 See :hg:`help files` for a more versatile command.
4447
4454
4448 Returns 0 if a match is found, 1 otherwise.
4455 Returns 0 if a match is found, 1 otherwise.
4449 """
4456 """
4450 opts = pycompat.byteskwargs(opts)
4457 opts = pycompat.byteskwargs(opts)
4451 if opts.get(b'print0'):
4458 if opts.get(b'print0'):
4452 end = b'\0'
4459 end = b'\0'
4453 else:
4460 else:
4454 end = b'\n'
4461 end = b'\n'
4455 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4462 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4456
4463
4457 ret = 1
4464 ret = 1
4458 m = scmutil.match(
4465 m = scmutil.match(
4459 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4466 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4460 )
4467 )
4461
4468
4462 ui.pager(b'locate')
4469 ui.pager(b'locate')
4463 if ctx.rev() is None:
4470 if ctx.rev() is None:
4464 # When run on the working copy, "locate" includes removed files, so
4471 # When run on the working copy, "locate" includes removed files, so
4465 # we get the list of files from the dirstate.
4472 # we get the list of files from the dirstate.
4466 filesgen = sorted(repo.dirstate.matches(m))
4473 filesgen = sorted(repo.dirstate.matches(m))
4467 else:
4474 else:
4468 filesgen = ctx.matches(m)
4475 filesgen = ctx.matches(m)
4469 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4476 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4470 for abs in filesgen:
4477 for abs in filesgen:
4471 if opts.get(b'fullpath'):
4478 if opts.get(b'fullpath'):
4472 ui.write(repo.wjoin(abs), end)
4479 ui.write(repo.wjoin(abs), end)
4473 else:
4480 else:
4474 ui.write(uipathfn(abs), end)
4481 ui.write(uipathfn(abs), end)
4475 ret = 0
4482 ret = 0
4476
4483
4477 return ret
4484 return ret
4478
4485
4479
4486
4480 @command(
4487 @command(
4481 b'log|history',
4488 b'log|history',
4482 [
4489 [
4483 (
4490 (
4484 b'f',
4491 b'f',
4485 b'follow',
4492 b'follow',
4486 None,
4493 None,
4487 _(
4494 _(
4488 b'follow changeset history, or file history across copies and renames'
4495 b'follow changeset history, or file history across copies and renames'
4489 ),
4496 ),
4490 ),
4497 ),
4491 (
4498 (
4492 b'',
4499 b'',
4493 b'follow-first',
4500 b'follow-first',
4494 None,
4501 None,
4495 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4502 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4496 ),
4503 ),
4497 (
4504 (
4498 b'd',
4505 b'd',
4499 b'date',
4506 b'date',
4500 b'',
4507 b'',
4501 _(b'show revisions matching date spec'),
4508 _(b'show revisions matching date spec'),
4502 _(b'DATE'),
4509 _(b'DATE'),
4503 ),
4510 ),
4504 (b'C', b'copies', None, _(b'show copied files')),
4511 (b'C', b'copies', None, _(b'show copied files')),
4505 (
4512 (
4506 b'k',
4513 b'k',
4507 b'keyword',
4514 b'keyword',
4508 [],
4515 [],
4509 _(b'do case-insensitive search for a given text'),
4516 _(b'do case-insensitive search for a given text'),
4510 _(b'TEXT'),
4517 _(b'TEXT'),
4511 ),
4518 ),
4512 (
4519 (
4513 b'r',
4520 b'r',
4514 b'rev',
4521 b'rev',
4515 [],
4522 [],
4516 _(b'revisions to select or follow from'),
4523 _(b'revisions to select or follow from'),
4517 _(b'REV'),
4524 _(b'REV'),
4518 ),
4525 ),
4519 (
4526 (
4520 b'L',
4527 b'L',
4521 b'line-range',
4528 b'line-range',
4522 [],
4529 [],
4523 _(b'follow line range of specified file (EXPERIMENTAL)'),
4530 _(b'follow line range of specified file (EXPERIMENTAL)'),
4524 _(b'FILE,RANGE'),
4531 _(b'FILE,RANGE'),
4525 ),
4532 ),
4526 (
4533 (
4527 b'',
4534 b'',
4528 b'removed',
4535 b'removed',
4529 None,
4536 None,
4530 _(b'include revisions where files were removed'),
4537 _(b'include revisions where files were removed'),
4531 ),
4538 ),
4532 (
4539 (
4533 b'm',
4540 b'm',
4534 b'only-merges',
4541 b'only-merges',
4535 None,
4542 None,
4536 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4543 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4537 ),
4544 ),
4538 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4545 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4539 (
4546 (
4540 b'',
4547 b'',
4541 b'only-branch',
4548 b'only-branch',
4542 [],
4549 [],
4543 _(
4550 _(
4544 b'show only changesets within the given named branch (DEPRECATED)'
4551 b'show only changesets within the given named branch (DEPRECATED)'
4545 ),
4552 ),
4546 _(b'BRANCH'),
4553 _(b'BRANCH'),
4547 ),
4554 ),
4548 (
4555 (
4549 b'b',
4556 b'b',
4550 b'branch',
4557 b'branch',
4551 [],
4558 [],
4552 _(b'show changesets within the given named branch'),
4559 _(b'show changesets within the given named branch'),
4553 _(b'BRANCH'),
4560 _(b'BRANCH'),
4554 ),
4561 ),
4555 (
4562 (
4556 b'B',
4563 b'B',
4557 b'bookmark',
4564 b'bookmark',
4558 [],
4565 [],
4559 _(b"show changesets within the given bookmark"),
4566 _(b"show changesets within the given bookmark"),
4560 _(b'BOOKMARK'),
4567 _(b'BOOKMARK'),
4561 ),
4568 ),
4562 (
4569 (
4563 b'P',
4570 b'P',
4564 b'prune',
4571 b'prune',
4565 [],
4572 [],
4566 _(b'do not display revision or any of its ancestors'),
4573 _(b'do not display revision or any of its ancestors'),
4567 _(b'REV'),
4574 _(b'REV'),
4568 ),
4575 ),
4569 ]
4576 ]
4570 + logopts
4577 + logopts
4571 + walkopts,
4578 + walkopts,
4572 _(b'[OPTION]... [FILE]'),
4579 _(b'[OPTION]... [FILE]'),
4573 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4580 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4574 helpbasic=True,
4581 helpbasic=True,
4575 inferrepo=True,
4582 inferrepo=True,
4576 intents={INTENT_READONLY},
4583 intents={INTENT_READONLY},
4577 )
4584 )
4578 def log(ui, repo, *pats, **opts):
4585 def log(ui, repo, *pats, **opts):
4579 """show revision history of entire repository or files
4586 """show revision history of entire repository or files
4580
4587
4581 Print the revision history of the specified files or the entire
4588 Print the revision history of the specified files or the entire
4582 project.
4589 project.
4583
4590
4584 If no revision range is specified, the default is ``tip:0`` unless
4591 If no revision range is specified, the default is ``tip:0`` unless
4585 --follow is set.
4592 --follow is set.
4586
4593
4587 File history is shown without following rename or copy history of
4594 File history is shown without following rename or copy history of
4588 files. Use -f/--follow with a filename to follow history across
4595 files. Use -f/--follow with a filename to follow history across
4589 renames and copies. --follow without a filename will only show
4596 renames and copies. --follow without a filename will only show
4590 ancestors of the starting revisions. The starting revisions can be
4597 ancestors of the starting revisions. The starting revisions can be
4591 specified by -r/--rev, which default to the working directory parent.
4598 specified by -r/--rev, which default to the working directory parent.
4592
4599
4593 By default this command prints revision number and changeset id,
4600 By default this command prints revision number and changeset id,
4594 tags, non-trivial parents, user, date and time, and a summary for
4601 tags, non-trivial parents, user, date and time, and a summary for
4595 each commit. When the -v/--verbose switch is used, the list of
4602 each commit. When the -v/--verbose switch is used, the list of
4596 changed files and full commit message are shown.
4603 changed files and full commit message are shown.
4597
4604
4598 With --graph the revisions are shown as an ASCII art DAG with the most
4605 With --graph the revisions are shown as an ASCII art DAG with the most
4599 recent changeset at the top.
4606 recent changeset at the top.
4600 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4607 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4601 involved in an unresolved merge conflict, '_' closes a branch,
4608 involved in an unresolved merge conflict, '_' closes a branch,
4602 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4609 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4603 changeset from the lines below is a parent of the 'o' merge on the same
4610 changeset from the lines below is a parent of the 'o' merge on the same
4604 line.
4611 line.
4605 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4612 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4606 of a '|' indicates one or more revisions in a path are omitted.
4613 of a '|' indicates one or more revisions in a path are omitted.
4607
4614
4608 .. container:: verbose
4615 .. container:: verbose
4609
4616
4610 Use -L/--line-range FILE,M:N options to follow the history of lines
4617 Use -L/--line-range FILE,M:N options to follow the history of lines
4611 from M to N in FILE. With -p/--patch only diff hunks affecting
4618 from M to N in FILE. With -p/--patch only diff hunks affecting
4612 specified line range will be shown. This option requires --follow;
4619 specified line range will be shown. This option requires --follow;
4613 it can be specified multiple times. Currently, this option is not
4620 it can be specified multiple times. Currently, this option is not
4614 compatible with --graph. This option is experimental.
4621 compatible with --graph. This option is experimental.
4615
4622
4616 .. note::
4623 .. note::
4617
4624
4618 :hg:`log --patch` may generate unexpected diff output for merge
4625 :hg:`log --patch` may generate unexpected diff output for merge
4619 changesets, as it will only compare the merge changeset against
4626 changesets, as it will only compare the merge changeset against
4620 its first parent. Also, only files different from BOTH parents
4627 its first parent. Also, only files different from BOTH parents
4621 will appear in files:.
4628 will appear in files:.
4622
4629
4623 .. note::
4630 .. note::
4624
4631
4625 For performance reasons, :hg:`log FILE` may omit duplicate changes
4632 For performance reasons, :hg:`log FILE` may omit duplicate changes
4626 made on branches and will not show removals or mode changes. To
4633 made on branches and will not show removals or mode changes. To
4627 see all such changes, use the --removed switch.
4634 see all such changes, use the --removed switch.
4628
4635
4629 .. container:: verbose
4636 .. container:: verbose
4630
4637
4631 .. note::
4638 .. note::
4632
4639
4633 The history resulting from -L/--line-range options depends on diff
4640 The history resulting from -L/--line-range options depends on diff
4634 options; for instance if white-spaces are ignored, respective changes
4641 options; for instance if white-spaces are ignored, respective changes
4635 with only white-spaces in specified line range will not be listed.
4642 with only white-spaces in specified line range will not be listed.
4636
4643
4637 .. container:: verbose
4644 .. container:: verbose
4638
4645
4639 Some examples:
4646 Some examples:
4640
4647
4641 - changesets with full descriptions and file lists::
4648 - changesets with full descriptions and file lists::
4642
4649
4643 hg log -v
4650 hg log -v
4644
4651
4645 - changesets ancestral to the working directory::
4652 - changesets ancestral to the working directory::
4646
4653
4647 hg log -f
4654 hg log -f
4648
4655
4649 - last 10 commits on the current branch::
4656 - last 10 commits on the current branch::
4650
4657
4651 hg log -l 10 -b .
4658 hg log -l 10 -b .
4652
4659
4653 - changesets showing all modifications of a file, including removals::
4660 - changesets showing all modifications of a file, including removals::
4654
4661
4655 hg log --removed file.c
4662 hg log --removed file.c
4656
4663
4657 - all changesets that touch a directory, with diffs, excluding merges::
4664 - all changesets that touch a directory, with diffs, excluding merges::
4658
4665
4659 hg log -Mp lib/
4666 hg log -Mp lib/
4660
4667
4661 - all revision numbers that match a keyword::
4668 - all revision numbers that match a keyword::
4662
4669
4663 hg log -k bug --template "{rev}\\n"
4670 hg log -k bug --template "{rev}\\n"
4664
4671
4665 - the full hash identifier of the working directory parent::
4672 - the full hash identifier of the working directory parent::
4666
4673
4667 hg log -r . --template "{node}\\n"
4674 hg log -r . --template "{node}\\n"
4668
4675
4669 - list available log templates::
4676 - list available log templates::
4670
4677
4671 hg log -T list
4678 hg log -T list
4672
4679
4673 - check if a given changeset is included in a tagged release::
4680 - check if a given changeset is included in a tagged release::
4674
4681
4675 hg log -r "a21ccf and ancestor(1.9)"
4682 hg log -r "a21ccf and ancestor(1.9)"
4676
4683
4677 - find all changesets by some user in a date range::
4684 - find all changesets by some user in a date range::
4678
4685
4679 hg log -k alice -d "may 2008 to jul 2008"
4686 hg log -k alice -d "may 2008 to jul 2008"
4680
4687
4681 - summary of all changesets after the last tag::
4688 - summary of all changesets after the last tag::
4682
4689
4683 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4690 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4684
4691
4685 - changesets touching lines 13 to 23 for file.c::
4692 - changesets touching lines 13 to 23 for file.c::
4686
4693
4687 hg log -L file.c,13:23
4694 hg log -L file.c,13:23
4688
4695
4689 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4696 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4690 main.c with patch::
4697 main.c with patch::
4691
4698
4692 hg log -L file.c,13:23 -L main.c,2:6 -p
4699 hg log -L file.c,13:23 -L main.c,2:6 -p
4693
4700
4694 See :hg:`help dates` for a list of formats valid for -d/--date.
4701 See :hg:`help dates` for a list of formats valid for -d/--date.
4695
4702
4696 See :hg:`help revisions` for more about specifying and ordering
4703 See :hg:`help revisions` for more about specifying and ordering
4697 revisions.
4704 revisions.
4698
4705
4699 See :hg:`help templates` for more about pre-packaged styles and
4706 See :hg:`help templates` for more about pre-packaged styles and
4700 specifying custom templates. The default template used by the log
4707 specifying custom templates. The default template used by the log
4701 command can be customized via the ``command-templates.log`` configuration
4708 command can be customized via the ``command-templates.log`` configuration
4702 setting.
4709 setting.
4703
4710
4704 Returns 0 on success.
4711 Returns 0 on success.
4705
4712
4706 """
4713 """
4707 opts = pycompat.byteskwargs(opts)
4714 opts = pycompat.byteskwargs(opts)
4708 linerange = opts.get(b'line_range')
4715 linerange = opts.get(b'line_range')
4709
4716
4710 if linerange and not opts.get(b'follow'):
4717 if linerange and not opts.get(b'follow'):
4711 raise error.InputError(_(b'--line-range requires --follow'))
4718 raise error.InputError(_(b'--line-range requires --follow'))
4712
4719
4713 if linerange and pats:
4720 if linerange and pats:
4714 # TODO: take pats as patterns with no line-range filter
4721 # TODO: take pats as patterns with no line-range filter
4715 raise error.InputError(
4722 raise error.InputError(
4716 _(b'FILE arguments are not compatible with --line-range option')
4723 _(b'FILE arguments are not compatible with --line-range option')
4717 )
4724 )
4718
4725
4719 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4726 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4720 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4727 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4721 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4728 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4722 if linerange:
4729 if linerange:
4723 # TODO: should follow file history from logcmdutil._initialrevs(),
4730 # TODO: should follow file history from logcmdutil._initialrevs(),
4724 # then filter the result by logcmdutil._makerevset() and --limit
4731 # then filter the result by logcmdutil._makerevset() and --limit
4725 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4732 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4726
4733
4727 getcopies = None
4734 getcopies = None
4728 if opts.get(b'copies'):
4735 if opts.get(b'copies'):
4729 endrev = None
4736 endrev = None
4730 if revs:
4737 if revs:
4731 endrev = revs.max() + 1
4738 endrev = revs.max() + 1
4732 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4739 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4733
4740
4734 ui.pager(b'log')
4741 ui.pager(b'log')
4735 displayer = logcmdutil.changesetdisplayer(
4742 displayer = logcmdutil.changesetdisplayer(
4736 ui, repo, opts, differ, buffered=True
4743 ui, repo, opts, differ, buffered=True
4737 )
4744 )
4738 if opts.get(b'graph'):
4745 if opts.get(b'graph'):
4739 displayfn = logcmdutil.displaygraphrevs
4746 displayfn = logcmdutil.displaygraphrevs
4740 else:
4747 else:
4741 displayfn = logcmdutil.displayrevs
4748 displayfn = logcmdutil.displayrevs
4742 displayfn(ui, repo, revs, displayer, getcopies)
4749 displayfn(ui, repo, revs, displayer, getcopies)
4743
4750
4744
4751
4745 @command(
4752 @command(
4746 b'manifest',
4753 b'manifest',
4747 [
4754 [
4748 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4755 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4749 (b'', b'all', False, _(b"list files from all revisions")),
4756 (b'', b'all', False, _(b"list files from all revisions")),
4750 ]
4757 ]
4751 + formatteropts,
4758 + formatteropts,
4752 _(b'[-r REV]'),
4759 _(b'[-r REV]'),
4753 helpcategory=command.CATEGORY_MAINTENANCE,
4760 helpcategory=command.CATEGORY_MAINTENANCE,
4754 intents={INTENT_READONLY},
4761 intents={INTENT_READONLY},
4755 )
4762 )
4756 def manifest(ui, repo, node=None, rev=None, **opts):
4763 def manifest(ui, repo, node=None, rev=None, **opts):
4757 """output the current or given revision of the project manifest
4764 """output the current or given revision of the project manifest
4758
4765
4759 Print a list of version controlled files for the given revision.
4766 Print a list of version controlled files for the given revision.
4760 If no revision is given, the first parent of the working directory
4767 If no revision is given, the first parent of the working directory
4761 is used, or the null revision if no revision is checked out.
4768 is used, or the null revision if no revision is checked out.
4762
4769
4763 With -v, print file permissions, symlink and executable bits.
4770 With -v, print file permissions, symlink and executable bits.
4764 With --debug, print file revision hashes.
4771 With --debug, print file revision hashes.
4765
4772
4766 If option --all is specified, the list of all files from all revisions
4773 If option --all is specified, the list of all files from all revisions
4767 is printed. This includes deleted and renamed files.
4774 is printed. This includes deleted and renamed files.
4768
4775
4769 Returns 0 on success.
4776 Returns 0 on success.
4770 """
4777 """
4771 opts = pycompat.byteskwargs(opts)
4778 opts = pycompat.byteskwargs(opts)
4772 fm = ui.formatter(b'manifest', opts)
4779 fm = ui.formatter(b'manifest', opts)
4773
4780
4774 if opts.get(b'all'):
4781 if opts.get(b'all'):
4775 if rev or node:
4782 if rev or node:
4776 raise error.InputError(_(b"can't specify a revision with --all"))
4783 raise error.InputError(_(b"can't specify a revision with --all"))
4777
4784
4778 res = set()
4785 res = set()
4779 for rev in repo:
4786 for rev in repo:
4780 ctx = repo[rev]
4787 ctx = repo[rev]
4781 res |= set(ctx.files())
4788 res |= set(ctx.files())
4782
4789
4783 ui.pager(b'manifest')
4790 ui.pager(b'manifest')
4784 for f in sorted(res):
4791 for f in sorted(res):
4785 fm.startitem()
4792 fm.startitem()
4786 fm.write(b"path", b'%s\n', f)
4793 fm.write(b"path", b'%s\n', f)
4787 fm.end()
4794 fm.end()
4788 return
4795 return
4789
4796
4790 if rev and node:
4797 if rev and node:
4791 raise error.InputError(_(b"please specify just one revision"))
4798 raise error.InputError(_(b"please specify just one revision"))
4792
4799
4793 if not node:
4800 if not node:
4794 node = rev
4801 node = rev
4795
4802
4796 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4803 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4797 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4804 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4798 if node:
4805 if node:
4799 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4806 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4800 ctx = logcmdutil.revsingle(repo, node)
4807 ctx = logcmdutil.revsingle(repo, node)
4801 mf = ctx.manifest()
4808 mf = ctx.manifest()
4802 ui.pager(b'manifest')
4809 ui.pager(b'manifest')
4803 for f in ctx:
4810 for f in ctx:
4804 fm.startitem()
4811 fm.startitem()
4805 fm.context(ctx=ctx)
4812 fm.context(ctx=ctx)
4806 fl = ctx[f].flags()
4813 fl = ctx[f].flags()
4807 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4814 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4808 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4815 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4809 fm.write(b'path', b'%s\n', f)
4816 fm.write(b'path', b'%s\n', f)
4810 fm.end()
4817 fm.end()
4811
4818
4812
4819
4813 @command(
4820 @command(
4814 b'merge',
4821 b'merge',
4815 [
4822 [
4816 (
4823 (
4817 b'f',
4824 b'f',
4818 b'force',
4825 b'force',
4819 None,
4826 None,
4820 _(b'force a merge including outstanding changes (DEPRECATED)'),
4827 _(b'force a merge including outstanding changes (DEPRECATED)'),
4821 ),
4828 ),
4822 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4829 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4823 (
4830 (
4824 b'P',
4831 b'P',
4825 b'preview',
4832 b'preview',
4826 None,
4833 None,
4827 _(b'review revisions to merge (no merge is performed)'),
4834 _(b'review revisions to merge (no merge is performed)'),
4828 ),
4835 ),
4829 (b'', b'abort', None, _(b'abort the ongoing merge')),
4836 (b'', b'abort', None, _(b'abort the ongoing merge')),
4830 ]
4837 ]
4831 + mergetoolopts,
4838 + mergetoolopts,
4832 _(b'[-P] [[-r] REV]'),
4839 _(b'[-P] [[-r] REV]'),
4833 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4840 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4834 helpbasic=True,
4841 helpbasic=True,
4835 )
4842 )
4836 def merge(ui, repo, node=None, **opts):
4843 def merge(ui, repo, node=None, **opts):
4837 """merge another revision into working directory
4844 """merge another revision into working directory
4838
4845
4839 The current working directory is updated with all changes made in
4846 The current working directory is updated with all changes made in
4840 the requested revision since the last common predecessor revision.
4847 the requested revision since the last common predecessor revision.
4841
4848
4842 Files that changed between either parent are marked as changed for
4849 Files that changed between either parent are marked as changed for
4843 the next commit and a commit must be performed before any further
4850 the next commit and a commit must be performed before any further
4844 updates to the repository are allowed. The next commit will have
4851 updates to the repository are allowed. The next commit will have
4845 two parents.
4852 two parents.
4846
4853
4847 ``--tool`` can be used to specify the merge tool used for file
4854 ``--tool`` can be used to specify the merge tool used for file
4848 merges. It overrides the HGMERGE environment variable and your
4855 merges. It overrides the HGMERGE environment variable and your
4849 configuration files. See :hg:`help merge-tools` for options.
4856 configuration files. See :hg:`help merge-tools` for options.
4850
4857
4851 If no revision is specified, the working directory's parent is a
4858 If no revision is specified, the working directory's parent is a
4852 head revision, and the current branch contains exactly one other
4859 head revision, and the current branch contains exactly one other
4853 head, the other head is merged with by default. Otherwise, an
4860 head, the other head is merged with by default. Otherwise, an
4854 explicit revision with which to merge must be provided.
4861 explicit revision with which to merge must be provided.
4855
4862
4856 See :hg:`help resolve` for information on handling file conflicts.
4863 See :hg:`help resolve` for information on handling file conflicts.
4857
4864
4858 To undo an uncommitted merge, use :hg:`merge --abort` which
4865 To undo an uncommitted merge, use :hg:`merge --abort` which
4859 will check out a clean copy of the original merge parent, losing
4866 will check out a clean copy of the original merge parent, losing
4860 all changes.
4867 all changes.
4861
4868
4862 Returns 0 on success, 1 if there are unresolved files.
4869 Returns 0 on success, 1 if there are unresolved files.
4863 """
4870 """
4864
4871
4865 opts = pycompat.byteskwargs(opts)
4872 opts = pycompat.byteskwargs(opts)
4866 abort = opts.get(b'abort')
4873 abort = opts.get(b'abort')
4867 if abort and repo.dirstate.p2() == repo.nullid:
4874 if abort and repo.dirstate.p2() == repo.nullid:
4868 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4875 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4869 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4876 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4870 if abort:
4877 if abort:
4871 state = cmdutil.getunfinishedstate(repo)
4878 state = cmdutil.getunfinishedstate(repo)
4872 if state and state._opname != b'merge':
4879 if state and state._opname != b'merge':
4873 raise error.StateError(
4880 raise error.StateError(
4874 _(b'cannot abort merge with %s in progress') % (state._opname),
4881 _(b'cannot abort merge with %s in progress') % (state._opname),
4875 hint=state.hint(),
4882 hint=state.hint(),
4876 )
4883 )
4877 if node:
4884 if node:
4878 raise error.InputError(_(b"cannot specify a node with --abort"))
4885 raise error.InputError(_(b"cannot specify a node with --abort"))
4879 return hg.abortmerge(repo.ui, repo)
4886 return hg.abortmerge(repo.ui, repo)
4880
4887
4881 if opts.get(b'rev') and node:
4888 if opts.get(b'rev') and node:
4882 raise error.InputError(_(b"please specify just one revision"))
4889 raise error.InputError(_(b"please specify just one revision"))
4883 if not node:
4890 if not node:
4884 node = opts.get(b'rev')
4891 node = opts.get(b'rev')
4885
4892
4886 if node:
4893 if node:
4887 ctx = logcmdutil.revsingle(repo, node)
4894 ctx = logcmdutil.revsingle(repo, node)
4888 else:
4895 else:
4889 if ui.configbool(b'commands', b'merge.require-rev'):
4896 if ui.configbool(b'commands', b'merge.require-rev'):
4890 raise error.InputError(
4897 raise error.InputError(
4891 _(
4898 _(
4892 b'configuration requires specifying revision to merge '
4899 b'configuration requires specifying revision to merge '
4893 b'with'
4900 b'with'
4894 )
4901 )
4895 )
4902 )
4896 ctx = repo[destutil.destmerge(repo)]
4903 ctx = repo[destutil.destmerge(repo)]
4897
4904
4898 if ctx.node() is None:
4905 if ctx.node() is None:
4899 raise error.InputError(
4906 raise error.InputError(
4900 _(b'merging with the working copy has no effect')
4907 _(b'merging with the working copy has no effect')
4901 )
4908 )
4902
4909
4903 if opts.get(b'preview'):
4910 if opts.get(b'preview'):
4904 # find nodes that are ancestors of p2 but not of p1
4911 # find nodes that are ancestors of p2 but not of p1
4905 p1 = repo[b'.'].node()
4912 p1 = repo[b'.'].node()
4906 p2 = ctx.node()
4913 p2 = ctx.node()
4907 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4914 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4908
4915
4909 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4916 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4910 for node in nodes:
4917 for node in nodes:
4911 displayer.show(repo[node])
4918 displayer.show(repo[node])
4912 displayer.close()
4919 displayer.close()
4913 return 0
4920 return 0
4914
4921
4915 # ui.forcemerge is an internal variable, do not document
4922 # ui.forcemerge is an internal variable, do not document
4916 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4923 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4917 with ui.configoverride(overrides, b'merge'):
4924 with ui.configoverride(overrides, b'merge'):
4918 force = opts.get(b'force')
4925 force = opts.get(b'force')
4919 labels = [b'working copy', b'merge rev', b'common ancestor']
4926 labels = [b'working copy', b'merge rev', b'common ancestor']
4920 return hg.merge(ctx, force=force, labels=labels)
4927 return hg.merge(ctx, force=force, labels=labels)
4921
4928
4922
4929
4923 statemod.addunfinished(
4930 statemod.addunfinished(
4924 b'merge',
4931 b'merge',
4925 fname=None,
4932 fname=None,
4926 clearable=True,
4933 clearable=True,
4927 allowcommit=True,
4934 allowcommit=True,
4928 cmdmsg=_(b'outstanding uncommitted merge'),
4935 cmdmsg=_(b'outstanding uncommitted merge'),
4929 abortfunc=hg.abortmerge,
4936 abortfunc=hg.abortmerge,
4930 statushint=_(
4937 statushint=_(
4931 b'To continue: hg commit\nTo abort: hg merge --abort'
4938 b'To continue: hg commit\nTo abort: hg merge --abort'
4932 ),
4939 ),
4933 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4940 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4934 )
4941 )
4935
4942
4936
4943
4937 @command(
4944 @command(
4938 b'outgoing|out',
4945 b'outgoing|out',
4939 [
4946 [
4940 (
4947 (
4941 b'f',
4948 b'f',
4942 b'force',
4949 b'force',
4943 None,
4950 None,
4944 _(b'run even when the destination is unrelated'),
4951 _(b'run even when the destination is unrelated'),
4945 ),
4952 ),
4946 (
4953 (
4947 b'r',
4954 b'r',
4948 b'rev',
4955 b'rev',
4949 [],
4956 [],
4950 _(b'a changeset intended to be included in the destination'),
4957 _(b'a changeset intended to be included in the destination'),
4951 _(b'REV'),
4958 _(b'REV'),
4952 ),
4959 ),
4953 (b'n', b'newest-first', None, _(b'show newest record first')),
4960 (b'n', b'newest-first', None, _(b'show newest record first')),
4954 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4961 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4955 (
4962 (
4956 b'b',
4963 b'b',
4957 b'branch',
4964 b'branch',
4958 [],
4965 [],
4959 _(b'a specific branch you would like to push'),
4966 _(b'a specific branch you would like to push'),
4960 _(b'BRANCH'),
4967 _(b'BRANCH'),
4961 ),
4968 ),
4962 ]
4969 ]
4963 + logopts
4970 + logopts
4964 + remoteopts
4971 + remoteopts
4965 + subrepoopts,
4972 + subrepoopts,
4966 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4973 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4967 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4974 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4968 )
4975 )
4969 def outgoing(ui, repo, *dests, **opts):
4976 def outgoing(ui, repo, *dests, **opts):
4970 """show changesets not found in the destination
4977 """show changesets not found in the destination
4971
4978
4972 Show changesets not found in the specified destination repository
4979 Show changesets not found in the specified destination repository
4973 or the default push location. These are the changesets that would
4980 or the default push location. These are the changesets that would
4974 be pushed if a push was requested.
4981 be pushed if a push was requested.
4975
4982
4976 See pull for details of valid destination formats.
4983 See pull for details of valid destination formats.
4977
4984
4978 .. container:: verbose
4985 .. container:: verbose
4979
4986
4980 With -B/--bookmarks, the result of bookmark comparison between
4987 With -B/--bookmarks, the result of bookmark comparison between
4981 local and remote repositories is displayed. With -v/--verbose,
4988 local and remote repositories is displayed. With -v/--verbose,
4982 status is also displayed for each bookmark like below::
4989 status is also displayed for each bookmark like below::
4983
4990
4984 BM1 01234567890a added
4991 BM1 01234567890a added
4985 BM2 deleted
4992 BM2 deleted
4986 BM3 234567890abc advanced
4993 BM3 234567890abc advanced
4987 BM4 34567890abcd diverged
4994 BM4 34567890abcd diverged
4988 BM5 4567890abcde changed
4995 BM5 4567890abcde changed
4989
4996
4990 The action taken when pushing depends on the
4997 The action taken when pushing depends on the
4991 status of each bookmark:
4998 status of each bookmark:
4992
4999
4993 :``added``: push with ``-B`` will create it
5000 :``added``: push with ``-B`` will create it
4994 :``deleted``: push with ``-B`` will delete it
5001 :``deleted``: push with ``-B`` will delete it
4995 :``advanced``: push will update it
5002 :``advanced``: push will update it
4996 :``diverged``: push with ``-B`` will update it
5003 :``diverged``: push with ``-B`` will update it
4997 :``changed``: push with ``-B`` will update it
5004 :``changed``: push with ``-B`` will update it
4998
5005
4999 From the point of view of pushing behavior, bookmarks
5006 From the point of view of pushing behavior, bookmarks
5000 existing only in the remote repository are treated as
5007 existing only in the remote repository are treated as
5001 ``deleted``, even if it is in fact added remotely.
5008 ``deleted``, even if it is in fact added remotely.
5002
5009
5003 Returns 0 if there are outgoing changes, 1 otherwise.
5010 Returns 0 if there are outgoing changes, 1 otherwise.
5004 """
5011 """
5005 opts = pycompat.byteskwargs(opts)
5012 opts = pycompat.byteskwargs(opts)
5006 if opts.get(b'bookmarks'):
5013 if opts.get(b'bookmarks'):
5007 for path in urlutil.get_push_paths(repo, ui, dests):
5014 for path in urlutil.get_push_paths(repo, ui, dests):
5008 dest = path.pushloc or path.loc
5015 dest = path.pushloc or path.loc
5009 other = hg.peer(repo, opts, dest)
5016 other = hg.peer(repo, opts, dest)
5010 try:
5017 try:
5011 if b'bookmarks' not in other.listkeys(b'namespaces'):
5018 if b'bookmarks' not in other.listkeys(b'namespaces'):
5012 ui.warn(_(b"remote doesn't support bookmarks\n"))
5019 ui.warn(_(b"remote doesn't support bookmarks\n"))
5013 return 0
5020 return 0
5014 ui.status(
5021 ui.status(
5015 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5022 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5016 )
5023 )
5017 ui.pager(b'outgoing')
5024 ui.pager(b'outgoing')
5018 return bookmarks.outgoing(ui, repo, other)
5025 return bookmarks.outgoing(ui, repo, other)
5019 finally:
5026 finally:
5020 other.close()
5027 other.close()
5021
5028
5022 return hg.outgoing(ui, repo, dests, opts)
5029 return hg.outgoing(ui, repo, dests, opts)
5023
5030
5024
5031
5025 @command(
5032 @command(
5026 b'parents',
5033 b'parents',
5027 [
5034 [
5028 (
5035 (
5029 b'r',
5036 b'r',
5030 b'rev',
5037 b'rev',
5031 b'',
5038 b'',
5032 _(b'show parents of the specified revision'),
5039 _(b'show parents of the specified revision'),
5033 _(b'REV'),
5040 _(b'REV'),
5034 ),
5041 ),
5035 ]
5042 ]
5036 + templateopts,
5043 + templateopts,
5037 _(b'[-r REV] [FILE]'),
5044 _(b'[-r REV] [FILE]'),
5038 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5045 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5039 inferrepo=True,
5046 inferrepo=True,
5040 )
5047 )
5041 def parents(ui, repo, file_=None, **opts):
5048 def parents(ui, repo, file_=None, **opts):
5042 """show the parents of the working directory or revision (DEPRECATED)
5049 """show the parents of the working directory or revision (DEPRECATED)
5043
5050
5044 Print the working directory's parent revisions. If a revision is
5051 Print the working directory's parent revisions. If a revision is
5045 given via -r/--rev, the parent of that revision will be printed.
5052 given via -r/--rev, the parent of that revision will be printed.
5046 If a file argument is given, the revision in which the file was
5053 If a file argument is given, the revision in which the file was
5047 last changed (before the working directory revision or the
5054 last changed (before the working directory revision or the
5048 argument to --rev if given) is printed.
5055 argument to --rev if given) is printed.
5049
5056
5050 This command is equivalent to::
5057 This command is equivalent to::
5051
5058
5052 hg log -r "p1()+p2()" or
5059 hg log -r "p1()+p2()" or
5053 hg log -r "p1(REV)+p2(REV)" or
5060 hg log -r "p1(REV)+p2(REV)" or
5054 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5061 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5055 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5062 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5056
5063
5057 See :hg:`summary` and :hg:`help revsets` for related information.
5064 See :hg:`summary` and :hg:`help revsets` for related information.
5058
5065
5059 Returns 0 on success.
5066 Returns 0 on success.
5060 """
5067 """
5061
5068
5062 opts = pycompat.byteskwargs(opts)
5069 opts = pycompat.byteskwargs(opts)
5063 rev = opts.get(b'rev')
5070 rev = opts.get(b'rev')
5064 if rev:
5071 if rev:
5065 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5072 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5066 ctx = logcmdutil.revsingle(repo, rev, None)
5073 ctx = logcmdutil.revsingle(repo, rev, None)
5067
5074
5068 if file_:
5075 if file_:
5069 m = scmutil.match(ctx, (file_,), opts)
5076 m = scmutil.match(ctx, (file_,), opts)
5070 if m.anypats() or len(m.files()) != 1:
5077 if m.anypats() or len(m.files()) != 1:
5071 raise error.InputError(_(b'can only specify an explicit filename'))
5078 raise error.InputError(_(b'can only specify an explicit filename'))
5072 file_ = m.files()[0]
5079 file_ = m.files()[0]
5073 filenodes = []
5080 filenodes = []
5074 for cp in ctx.parents():
5081 for cp in ctx.parents():
5075 if not cp:
5082 if not cp:
5076 continue
5083 continue
5077 try:
5084 try:
5078 filenodes.append(cp.filenode(file_))
5085 filenodes.append(cp.filenode(file_))
5079 except error.LookupError:
5086 except error.LookupError:
5080 pass
5087 pass
5081 if not filenodes:
5088 if not filenodes:
5082 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5089 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5083 p = []
5090 p = []
5084 for fn in filenodes:
5091 for fn in filenodes:
5085 fctx = repo.filectx(file_, fileid=fn)
5092 fctx = repo.filectx(file_, fileid=fn)
5086 p.append(fctx.node())
5093 p.append(fctx.node())
5087 else:
5094 else:
5088 p = [cp.node() for cp in ctx.parents()]
5095 p = [cp.node() for cp in ctx.parents()]
5089
5096
5090 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5097 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5091 for n in p:
5098 for n in p:
5092 if n != repo.nullid:
5099 if n != repo.nullid:
5093 displayer.show(repo[n])
5100 displayer.show(repo[n])
5094 displayer.close()
5101 displayer.close()
5095
5102
5096
5103
5097 @command(
5104 @command(
5098 b'paths',
5105 b'paths',
5099 formatteropts,
5106 formatteropts,
5100 _(b'[NAME]'),
5107 _(b'[NAME]'),
5101 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5108 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5102 optionalrepo=True,
5109 optionalrepo=True,
5103 intents={INTENT_READONLY},
5110 intents={INTENT_READONLY},
5104 )
5111 )
5105 def paths(ui, repo, search=None, **opts):
5112 def paths(ui, repo, search=None, **opts):
5106 """show aliases for remote repositories
5113 """show aliases for remote repositories
5107
5114
5108 Show definition of symbolic path name NAME. If no name is given,
5115 Show definition of symbolic path name NAME. If no name is given,
5109 show definition of all available names.
5116 show definition of all available names.
5110
5117
5111 Option -q/--quiet suppresses all output when searching for NAME
5118 Option -q/--quiet suppresses all output when searching for NAME
5112 and shows only the path names when listing all definitions.
5119 and shows only the path names when listing all definitions.
5113
5120
5114 Path names are defined in the [paths] section of your
5121 Path names are defined in the [paths] section of your
5115 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5122 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5116 repository, ``.hg/hgrc`` is used, too.
5123 repository, ``.hg/hgrc`` is used, too.
5117
5124
5118 The path names ``default`` and ``default-push`` have a special
5125 The path names ``default`` and ``default-push`` have a special
5119 meaning. When performing a push or pull operation, they are used
5126 meaning. When performing a push or pull operation, they are used
5120 as fallbacks if no location is specified on the command-line.
5127 as fallbacks if no location is specified on the command-line.
5121 When ``default-push`` is set, it will be used for push and
5128 When ``default-push`` is set, it will be used for push and
5122 ``default`` will be used for pull; otherwise ``default`` is used
5129 ``default`` will be used for pull; otherwise ``default`` is used
5123 as the fallback for both. When cloning a repository, the clone
5130 as the fallback for both. When cloning a repository, the clone
5124 source is written as ``default`` in ``.hg/hgrc``.
5131 source is written as ``default`` in ``.hg/hgrc``.
5125
5132
5126 .. note::
5133 .. note::
5127
5134
5128 ``default`` and ``default-push`` apply to all inbound (e.g.
5135 ``default`` and ``default-push`` apply to all inbound (e.g.
5129 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5136 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5130 and :hg:`bundle`) operations.
5137 and :hg:`bundle`) operations.
5131
5138
5132 See :hg:`help urls` for more information.
5139 See :hg:`help urls` for more information.
5133
5140
5134 .. container:: verbose
5141 .. container:: verbose
5135
5142
5136 Template:
5143 Template:
5137
5144
5138 The following keywords are supported. See also :hg:`help templates`.
5145 The following keywords are supported. See also :hg:`help templates`.
5139
5146
5140 :name: String. Symbolic name of the path alias.
5147 :name: String. Symbolic name of the path alias.
5141 :pushurl: String. URL for push operations.
5148 :pushurl: String. URL for push operations.
5142 :url: String. URL or directory path for the other operations.
5149 :url: String. URL or directory path for the other operations.
5143
5150
5144 Returns 0 on success.
5151 Returns 0 on success.
5145 """
5152 """
5146
5153
5147 opts = pycompat.byteskwargs(opts)
5154 opts = pycompat.byteskwargs(opts)
5148
5155
5149 pathitems = urlutil.list_paths(ui, search)
5156 pathitems = urlutil.list_paths(ui, search)
5150 ui.pager(b'paths')
5157 ui.pager(b'paths')
5151
5158
5152 fm = ui.formatter(b'paths', opts)
5159 fm = ui.formatter(b'paths', opts)
5153 if fm.isplain():
5160 if fm.isplain():
5154 hidepassword = urlutil.hidepassword
5161 hidepassword = urlutil.hidepassword
5155 else:
5162 else:
5156 hidepassword = bytes
5163 hidepassword = bytes
5157 if ui.quiet:
5164 if ui.quiet:
5158 namefmt = b'%s\n'
5165 namefmt = b'%s\n'
5159 else:
5166 else:
5160 namefmt = b'%s = '
5167 namefmt = b'%s = '
5161 showsubopts = not search and not ui.quiet
5168 showsubopts = not search and not ui.quiet
5162
5169
5163 for name, path in pathitems:
5170 for name, path in pathitems:
5164 fm.startitem()
5171 fm.startitem()
5165 fm.condwrite(not search, b'name', namefmt, name)
5172 fm.condwrite(not search, b'name', namefmt, name)
5166 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5173 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5167 for subopt, value in sorted(path.suboptions.items()):
5174 for subopt, value in sorted(path.suboptions.items()):
5168 assert subopt not in (b'name', b'url')
5175 assert subopt not in (b'name', b'url')
5169 if showsubopts:
5176 if showsubopts:
5170 fm.plain(b'%s:%s = ' % (name, subopt))
5177 fm.plain(b'%s:%s = ' % (name, subopt))
5171 if isinstance(value, bool):
5178 if isinstance(value, bool):
5172 if value:
5179 if value:
5173 value = b'yes'
5180 value = b'yes'
5174 else:
5181 else:
5175 value = b'no'
5182 value = b'no'
5176 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5183 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5177
5184
5178 fm.end()
5185 fm.end()
5179
5186
5180 if search and not pathitems:
5187 if search and not pathitems:
5181 if not ui.quiet:
5188 if not ui.quiet:
5182 ui.warn(_(b"not found!\n"))
5189 ui.warn(_(b"not found!\n"))
5183 return 1
5190 return 1
5184 else:
5191 else:
5185 return 0
5192 return 0
5186
5193
5187
5194
5188 @command(
5195 @command(
5189 b'phase',
5196 b'phase',
5190 [
5197 [
5191 (b'p', b'public', False, _(b'set changeset phase to public')),
5198 (b'p', b'public', False, _(b'set changeset phase to public')),
5192 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5199 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5193 (b's', b'secret', False, _(b'set changeset phase to secret')),
5200 (b's', b'secret', False, _(b'set changeset phase to secret')),
5194 (b'f', b'force', False, _(b'allow to move boundary backward')),
5201 (b'f', b'force', False, _(b'allow to move boundary backward')),
5195 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5202 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5196 ],
5203 ],
5197 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5204 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5198 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5205 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5199 )
5206 )
5200 def phase(ui, repo, *revs, **opts):
5207 def phase(ui, repo, *revs, **opts):
5201 """set or show the current phase name
5208 """set or show the current phase name
5202
5209
5203 With no argument, show the phase name of the current revision(s).
5210 With no argument, show the phase name of the current revision(s).
5204
5211
5205 With one of -p/--public, -d/--draft or -s/--secret, change the
5212 With one of -p/--public, -d/--draft or -s/--secret, change the
5206 phase value of the specified revisions.
5213 phase value of the specified revisions.
5207
5214
5208 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5215 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5209 lower phase to a higher phase. Phases are ordered as follows::
5216 lower phase to a higher phase. Phases are ordered as follows::
5210
5217
5211 public < draft < secret
5218 public < draft < secret
5212
5219
5213 Returns 0 on success, 1 if some phases could not be changed.
5220 Returns 0 on success, 1 if some phases could not be changed.
5214
5221
5215 (For more information about the phases concept, see :hg:`help phases`.)
5222 (For more information about the phases concept, see :hg:`help phases`.)
5216 """
5223 """
5217 opts = pycompat.byteskwargs(opts)
5224 opts = pycompat.byteskwargs(opts)
5218 # search for a unique phase argument
5225 # search for a unique phase argument
5219 targetphase = None
5226 targetphase = None
5220 for idx, name in enumerate(phases.cmdphasenames):
5227 for idx, name in enumerate(phases.cmdphasenames):
5221 if opts[name]:
5228 if opts[name]:
5222 if targetphase is not None:
5229 if targetphase is not None:
5223 raise error.InputError(_(b'only one phase can be specified'))
5230 raise error.InputError(_(b'only one phase can be specified'))
5224 targetphase = idx
5231 targetphase = idx
5225
5232
5226 # look for specified revision
5233 # look for specified revision
5227 revs = list(revs)
5234 revs = list(revs)
5228 revs.extend(opts[b'rev'])
5235 revs.extend(opts[b'rev'])
5229 if revs:
5236 if revs:
5230 revs = logcmdutil.revrange(repo, revs)
5237 revs = logcmdutil.revrange(repo, revs)
5231 else:
5238 else:
5232 # display both parents as the second parent phase can influence
5239 # display both parents as the second parent phase can influence
5233 # the phase of a merge commit
5240 # the phase of a merge commit
5234 revs = [c.rev() for c in repo[None].parents()]
5241 revs = [c.rev() for c in repo[None].parents()]
5235
5242
5236 ret = 0
5243 ret = 0
5237 if targetphase is None:
5244 if targetphase is None:
5238 # display
5245 # display
5239 for r in revs:
5246 for r in revs:
5240 ctx = repo[r]
5247 ctx = repo[r]
5241 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5248 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5242 else:
5249 else:
5243 with repo.lock(), repo.transaction(b"phase") as tr:
5250 with repo.lock(), repo.transaction(b"phase") as tr:
5244 # set phase
5251 # set phase
5245 if not revs:
5252 if not revs:
5246 raise error.InputError(_(b'empty revision set'))
5253 raise error.InputError(_(b'empty revision set'))
5247 nodes = [repo[r].node() for r in revs]
5254 nodes = [repo[r].node() for r in revs]
5248 # moving revision from public to draft may hide them
5255 # moving revision from public to draft may hide them
5249 # We have to check result on an unfiltered repository
5256 # We have to check result on an unfiltered repository
5250 unfi = repo.unfiltered()
5257 unfi = repo.unfiltered()
5251 getphase = unfi._phasecache.phase
5258 getphase = unfi._phasecache.phase
5252 olddata = [getphase(unfi, r) for r in unfi]
5259 olddata = [getphase(unfi, r) for r in unfi]
5253 phases.advanceboundary(repo, tr, targetphase, nodes)
5260 phases.advanceboundary(repo, tr, targetphase, nodes)
5254 if opts[b'force']:
5261 if opts[b'force']:
5255 phases.retractboundary(repo, tr, targetphase, nodes)
5262 phases.retractboundary(repo, tr, targetphase, nodes)
5256 getphase = unfi._phasecache.phase
5263 getphase = unfi._phasecache.phase
5257 newdata = [getphase(unfi, r) for r in unfi]
5264 newdata = [getphase(unfi, r) for r in unfi]
5258 changes = sum(newdata[r] != olddata[r] for r in unfi)
5265 changes = sum(newdata[r] != olddata[r] for r in unfi)
5259 cl = unfi.changelog
5266 cl = unfi.changelog
5260 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5267 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5261 if rejected:
5268 if rejected:
5262 ui.warn(
5269 ui.warn(
5263 _(
5270 _(
5264 b'cannot move %i changesets to a higher '
5271 b'cannot move %i changesets to a higher '
5265 b'phase, use --force\n'
5272 b'phase, use --force\n'
5266 )
5273 )
5267 % len(rejected)
5274 % len(rejected)
5268 )
5275 )
5269 ret = 1
5276 ret = 1
5270 if changes:
5277 if changes:
5271 msg = _(b'phase changed for %i changesets\n') % changes
5278 msg = _(b'phase changed for %i changesets\n') % changes
5272 if ret:
5279 if ret:
5273 ui.status(msg)
5280 ui.status(msg)
5274 else:
5281 else:
5275 ui.note(msg)
5282 ui.note(msg)
5276 else:
5283 else:
5277 ui.warn(_(b'no phases changed\n'))
5284 ui.warn(_(b'no phases changed\n'))
5278 return ret
5285 return ret
5279
5286
5280
5287
5281 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5288 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5282 """Run after a changegroup has been added via pull/unbundle
5289 """Run after a changegroup has been added via pull/unbundle
5283
5290
5284 This takes arguments below:
5291 This takes arguments below:
5285
5292
5286 :modheads: change of heads by pull/unbundle
5293 :modheads: change of heads by pull/unbundle
5287 :optupdate: updating working directory is needed or not
5294 :optupdate: updating working directory is needed or not
5288 :checkout: update destination revision (or None to default destination)
5295 :checkout: update destination revision (or None to default destination)
5289 :brev: a name, which might be a bookmark to be activated after updating
5296 :brev: a name, which might be a bookmark to be activated after updating
5290
5297
5291 return True if update raise any conflict, False otherwise.
5298 return True if update raise any conflict, False otherwise.
5292 """
5299 """
5293 if modheads == 0:
5300 if modheads == 0:
5294 return False
5301 return False
5295 if optupdate:
5302 if optupdate:
5296 try:
5303 try:
5297 return hg.updatetotally(ui, repo, checkout, brev)
5304 return hg.updatetotally(ui, repo, checkout, brev)
5298 except error.UpdateAbort as inst:
5305 except error.UpdateAbort as inst:
5299 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5306 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5300 hint = inst.hint
5307 hint = inst.hint
5301 raise error.UpdateAbort(msg, hint=hint)
5308 raise error.UpdateAbort(msg, hint=hint)
5302 if modheads is not None and modheads > 1:
5309 if modheads is not None and modheads > 1:
5303 currentbranchheads = len(repo.branchheads())
5310 currentbranchheads = len(repo.branchheads())
5304 if currentbranchheads == modheads:
5311 if currentbranchheads == modheads:
5305 ui.status(
5312 ui.status(
5306 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5313 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5307 )
5314 )
5308 elif currentbranchheads > 1:
5315 elif currentbranchheads > 1:
5309 ui.status(
5316 ui.status(
5310 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5317 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5311 )
5318 )
5312 else:
5319 else:
5313 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5320 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5314 elif not ui.configbool(b'commands', b'update.requiredest'):
5321 elif not ui.configbool(b'commands', b'update.requiredest'):
5315 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5322 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5316 return False
5323 return False
5317
5324
5318
5325
5319 @command(
5326 @command(
5320 b'pull',
5327 b'pull',
5321 [
5328 [
5322 (
5329 (
5323 b'u',
5330 b'u',
5324 b'update',
5331 b'update',
5325 None,
5332 None,
5326 _(b'update to new branch head if new descendants were pulled'),
5333 _(b'update to new branch head if new descendants were pulled'),
5327 ),
5334 ),
5328 (
5335 (
5329 b'f',
5336 b'f',
5330 b'force',
5337 b'force',
5331 None,
5338 None,
5332 _(b'run even when remote repository is unrelated'),
5339 _(b'run even when remote repository is unrelated'),
5333 ),
5340 ),
5334 (
5341 (
5335 b'',
5342 b'',
5336 b'confirm',
5343 b'confirm',
5337 None,
5344 None,
5338 _(b'confirm pull before applying changes'),
5345 _(b'confirm pull before applying changes'),
5339 ),
5346 ),
5340 (
5347 (
5341 b'r',
5348 b'r',
5342 b'rev',
5349 b'rev',
5343 [],
5350 [],
5344 _(b'a remote changeset intended to be added'),
5351 _(b'a remote changeset intended to be added'),
5345 _(b'REV'),
5352 _(b'REV'),
5346 ),
5353 ),
5347 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5354 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5348 (
5355 (
5349 b'b',
5356 b'b',
5350 b'branch',
5357 b'branch',
5351 [],
5358 [],
5352 _(b'a specific branch you would like to pull'),
5359 _(b'a specific branch you would like to pull'),
5353 _(b'BRANCH'),
5360 _(b'BRANCH'),
5354 ),
5361 ),
5355 ]
5362 ]
5356 + remoteopts,
5363 + remoteopts,
5357 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5364 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5358 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5365 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5359 helpbasic=True,
5366 helpbasic=True,
5360 )
5367 )
5361 def pull(ui, repo, *sources, **opts):
5368 def pull(ui, repo, *sources, **opts):
5362 """pull changes from the specified source
5369 """pull changes from the specified source
5363
5370
5364 Pull changes from a remote repository to a local one.
5371 Pull changes from a remote repository to a local one.
5365
5372
5366 This finds all changes from the repository at the specified path
5373 This finds all changes from the repository at the specified path
5367 or URL and adds them to a local repository (the current one unless
5374 or URL and adds them to a local repository (the current one unless
5368 -R is specified). By default, this does not update the copy of the
5375 -R is specified). By default, this does not update the copy of the
5369 project in the working directory.
5376 project in the working directory.
5370
5377
5371 When cloning from servers that support it, Mercurial may fetch
5378 When cloning from servers that support it, Mercurial may fetch
5372 pre-generated data. When this is done, hooks operating on incoming
5379 pre-generated data. When this is done, hooks operating on incoming
5373 changesets and changegroups may fire more than once, once for each
5380 changesets and changegroups may fire more than once, once for each
5374 pre-generated bundle and as well as for any additional remaining
5381 pre-generated bundle and as well as for any additional remaining
5375 data. See :hg:`help -e clonebundles` for more.
5382 data. See :hg:`help -e clonebundles` for more.
5376
5383
5377 Use :hg:`incoming` if you want to see what would have been added
5384 Use :hg:`incoming` if you want to see what would have been added
5378 by a pull at the time you issued this command. If you then decide
5385 by a pull at the time you issued this command. If you then decide
5379 to add those changes to the repository, you should use :hg:`pull
5386 to add those changes to the repository, you should use :hg:`pull
5380 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5387 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5381
5388
5382 If SOURCE is omitted, the 'default' path will be used.
5389 If SOURCE is omitted, the 'default' path will be used.
5383 See :hg:`help urls` for more information.
5390 See :hg:`help urls` for more information.
5384
5391
5385 If multiple sources are specified, they will be pulled sequentially as if
5392 If multiple sources are specified, they will be pulled sequentially as if
5386 the command was run multiple time. If --update is specify and the command
5393 the command was run multiple time. If --update is specify and the command
5387 will stop at the first failed --update.
5394 will stop at the first failed --update.
5388
5395
5389 Specifying bookmark as ``.`` is equivalent to specifying the active
5396 Specifying bookmark as ``.`` is equivalent to specifying the active
5390 bookmark's name.
5397 bookmark's name.
5391
5398
5392 Returns 0 on success, 1 if an update had unresolved files.
5399 Returns 0 on success, 1 if an update had unresolved files.
5393 """
5400 """
5394
5401
5395 opts = pycompat.byteskwargs(opts)
5402 opts = pycompat.byteskwargs(opts)
5396 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5403 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5397 b'update'
5404 b'update'
5398 ):
5405 ):
5399 msg = _(b'update destination required by configuration')
5406 msg = _(b'update destination required by configuration')
5400 hint = _(b'use hg pull followed by hg update DEST')
5407 hint = _(b'use hg pull followed by hg update DEST')
5401 raise error.InputError(msg, hint=hint)
5408 raise error.InputError(msg, hint=hint)
5402
5409
5403 for path in urlutil.get_pull_paths(repo, ui, sources):
5410 for path in urlutil.get_pull_paths(repo, ui, sources):
5404 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5411 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5405 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5412 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5406 ui.flush()
5413 ui.flush()
5407 other = hg.peer(repo, opts, source)
5414 other = hg.peer(repo, opts, source)
5408 update_conflict = None
5415 update_conflict = None
5409 try:
5416 try:
5410 revs, checkout = hg.addbranchrevs(
5417 revs, checkout = hg.addbranchrevs(
5411 repo, other, branches, opts.get(b'rev')
5418 repo, other, branches, opts.get(b'rev')
5412 )
5419 )
5413
5420
5414 pullopargs = {}
5421 pullopargs = {}
5415
5422
5416 nodes = None
5423 nodes = None
5417 if opts.get(b'bookmark') or revs:
5424 if opts.get(b'bookmark') or revs:
5418 # The list of bookmark used here is the same used to actually update
5425 # The list of bookmark used here is the same used to actually update
5419 # the bookmark names, to avoid the race from issue 4689 and we do
5426 # the bookmark names, to avoid the race from issue 4689 and we do
5420 # all lookup and bookmark queries in one go so they see the same
5427 # all lookup and bookmark queries in one go so they see the same
5421 # version of the server state (issue 4700).
5428 # version of the server state (issue 4700).
5422 nodes = []
5429 nodes = []
5423 fnodes = []
5430 fnodes = []
5424 revs = revs or []
5431 revs = revs or []
5425 if revs and not other.capable(b'lookup'):
5432 if revs and not other.capable(b'lookup'):
5426 err = _(
5433 err = _(
5427 b"other repository doesn't support revision lookup, "
5434 b"other repository doesn't support revision lookup, "
5428 b"so a rev cannot be specified."
5435 b"so a rev cannot be specified."
5429 )
5436 )
5430 raise error.Abort(err)
5437 raise error.Abort(err)
5431 with other.commandexecutor() as e:
5438 with other.commandexecutor() as e:
5432 fremotebookmarks = e.callcommand(
5439 fremotebookmarks = e.callcommand(
5433 b'listkeys', {b'namespace': b'bookmarks'}
5440 b'listkeys', {b'namespace': b'bookmarks'}
5434 )
5441 )
5435 for r in revs:
5442 for r in revs:
5436 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5443 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5437 remotebookmarks = fremotebookmarks.result()
5444 remotebookmarks = fremotebookmarks.result()
5438 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5445 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5439 pullopargs[b'remotebookmarks'] = remotebookmarks
5446 pullopargs[b'remotebookmarks'] = remotebookmarks
5440 for b in opts.get(b'bookmark', []):
5447 for b in opts.get(b'bookmark', []):
5441 b = repo._bookmarks.expandname(b)
5448 b = repo._bookmarks.expandname(b)
5442 if b not in remotebookmarks:
5449 if b not in remotebookmarks:
5443 raise error.InputError(
5450 raise error.InputError(
5444 _(b'remote bookmark %s not found!') % b
5451 _(b'remote bookmark %s not found!') % b
5445 )
5452 )
5446 nodes.append(remotebookmarks[b])
5453 nodes.append(remotebookmarks[b])
5447 for i, rev in enumerate(revs):
5454 for i, rev in enumerate(revs):
5448 node = fnodes[i].result()
5455 node = fnodes[i].result()
5449 nodes.append(node)
5456 nodes.append(node)
5450 if rev == checkout:
5457 if rev == checkout:
5451 checkout = node
5458 checkout = node
5452
5459
5453 wlock = util.nullcontextmanager()
5460 wlock = util.nullcontextmanager()
5454 if opts.get(b'update'):
5461 if opts.get(b'update'):
5455 wlock = repo.wlock()
5462 wlock = repo.wlock()
5456 with wlock:
5463 with wlock:
5457 pullopargs.update(opts.get(b'opargs', {}))
5464 pullopargs.update(opts.get(b'opargs', {}))
5458 modheads = exchange.pull(
5465 modheads = exchange.pull(
5459 repo,
5466 repo,
5460 other,
5467 other,
5461 path=path,
5468 path=path,
5462 heads=nodes,
5469 heads=nodes,
5463 force=opts.get(b'force'),
5470 force=opts.get(b'force'),
5464 bookmarks=opts.get(b'bookmark', ()),
5471 bookmarks=opts.get(b'bookmark', ()),
5465 opargs=pullopargs,
5472 opargs=pullopargs,
5466 confirm=opts.get(b'confirm'),
5473 confirm=opts.get(b'confirm'),
5467 ).cgresult
5474 ).cgresult
5468
5475
5469 # brev is a name, which might be a bookmark to be activated at
5476 # brev is a name, which might be a bookmark to be activated at
5470 # the end of the update. In other words, it is an explicit
5477 # the end of the update. In other words, it is an explicit
5471 # destination of the update
5478 # destination of the update
5472 brev = None
5479 brev = None
5473
5480
5474 if checkout:
5481 if checkout:
5475 checkout = repo.unfiltered().changelog.rev(checkout)
5482 checkout = repo.unfiltered().changelog.rev(checkout)
5476
5483
5477 # order below depends on implementation of
5484 # order below depends on implementation of
5478 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5485 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5479 # because 'checkout' is determined without it.
5486 # because 'checkout' is determined without it.
5480 if opts.get(b'rev'):
5487 if opts.get(b'rev'):
5481 brev = opts[b'rev'][0]
5488 brev = opts[b'rev'][0]
5482 elif opts.get(b'branch'):
5489 elif opts.get(b'branch'):
5483 brev = opts[b'branch'][0]
5490 brev = opts[b'branch'][0]
5484 else:
5491 else:
5485 brev = branches[0]
5492 brev = branches[0]
5486 repo._subtoppath = source
5493 repo._subtoppath = source
5487 try:
5494 try:
5488 update_conflict = postincoming(
5495 update_conflict = postincoming(
5489 ui, repo, modheads, opts.get(b'update'), checkout, brev
5496 ui, repo, modheads, opts.get(b'update'), checkout, brev
5490 )
5497 )
5491 except error.FilteredRepoLookupError as exc:
5498 except error.FilteredRepoLookupError as exc:
5492 msg = _(b'cannot update to target: %s') % exc.args[0]
5499 msg = _(b'cannot update to target: %s') % exc.args[0]
5493 exc.args = (msg,) + exc.args[1:]
5500 exc.args = (msg,) + exc.args[1:]
5494 raise
5501 raise
5495 finally:
5502 finally:
5496 del repo._subtoppath
5503 del repo._subtoppath
5497
5504
5498 finally:
5505 finally:
5499 other.close()
5506 other.close()
5500 # skip the remaining pull source if they are some conflict.
5507 # skip the remaining pull source if they are some conflict.
5501 if update_conflict:
5508 if update_conflict:
5502 break
5509 break
5503 if update_conflict:
5510 if update_conflict:
5504 return 1
5511 return 1
5505 else:
5512 else:
5506 return 0
5513 return 0
5507
5514
5508
5515
5509 @command(
5516 @command(
5510 b'purge|clean',
5517 b'purge|clean',
5511 [
5518 [
5512 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5519 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5513 (b'', b'all', None, _(b'purge ignored files too')),
5520 (b'', b'all', None, _(b'purge ignored files too')),
5514 (b'i', b'ignored', None, _(b'purge only ignored files')),
5521 (b'i', b'ignored', None, _(b'purge only ignored files')),
5515 (b'', b'dirs', None, _(b'purge empty directories')),
5522 (b'', b'dirs', None, _(b'purge empty directories')),
5516 (b'', b'files', None, _(b'purge files')),
5523 (b'', b'files', None, _(b'purge files')),
5517 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5524 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5518 (
5525 (
5519 b'0',
5526 b'0',
5520 b'print0',
5527 b'print0',
5521 None,
5528 None,
5522 _(
5529 _(
5523 b'end filenames with NUL, for use with xargs'
5530 b'end filenames with NUL, for use with xargs'
5524 b' (implies -p/--print)'
5531 b' (implies -p/--print)'
5525 ),
5532 ),
5526 ),
5533 ),
5527 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5534 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5528 ]
5535 ]
5529 + cmdutil.walkopts,
5536 + cmdutil.walkopts,
5530 _(b'hg purge [OPTION]... [DIR]...'),
5537 _(b'hg purge [OPTION]... [DIR]...'),
5531 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5538 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5532 )
5539 )
5533 def purge(ui, repo, *dirs, **opts):
5540 def purge(ui, repo, *dirs, **opts):
5534 """removes files not tracked by Mercurial
5541 """removes files not tracked by Mercurial
5535
5542
5536 Delete files not known to Mercurial. This is useful to test local
5543 Delete files not known to Mercurial. This is useful to test local
5537 and uncommitted changes in an otherwise-clean source tree.
5544 and uncommitted changes in an otherwise-clean source tree.
5538
5545
5539 This means that purge will delete the following by default:
5546 This means that purge will delete the following by default:
5540
5547
5541 - Unknown files: files marked with "?" by :hg:`status`
5548 - Unknown files: files marked with "?" by :hg:`status`
5542 - Empty directories: in fact Mercurial ignores directories unless
5549 - Empty directories: in fact Mercurial ignores directories unless
5543 they contain files under source control management
5550 they contain files under source control management
5544
5551
5545 But it will leave untouched:
5552 But it will leave untouched:
5546
5553
5547 - Modified and unmodified tracked files
5554 - Modified and unmodified tracked files
5548 - Ignored files (unless -i or --all is specified)
5555 - Ignored files (unless -i or --all is specified)
5549 - New files added to the repository (with :hg:`add`)
5556 - New files added to the repository (with :hg:`add`)
5550
5557
5551 The --files and --dirs options can be used to direct purge to delete
5558 The --files and --dirs options can be used to direct purge to delete
5552 only files, only directories, or both. If neither option is given,
5559 only files, only directories, or both. If neither option is given,
5553 both will be deleted.
5560 both will be deleted.
5554
5561
5555 If directories are given on the command line, only files in these
5562 If directories are given on the command line, only files in these
5556 directories are considered.
5563 directories are considered.
5557
5564
5558 Be careful with purge, as you could irreversibly delete some files
5565 Be careful with purge, as you could irreversibly delete some files
5559 you forgot to add to the repository. If you only want to print the
5566 you forgot to add to the repository. If you only want to print the
5560 list of files that this program would delete, use the --print
5567 list of files that this program would delete, use the --print
5561 option.
5568 option.
5562 """
5569 """
5563 opts = pycompat.byteskwargs(opts)
5570 opts = pycompat.byteskwargs(opts)
5564 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5571 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5565
5572
5566 act = not opts.get(b'print')
5573 act = not opts.get(b'print')
5567 eol = b'\n'
5574 eol = b'\n'
5568 if opts.get(b'print0'):
5575 if opts.get(b'print0'):
5569 eol = b'\0'
5576 eol = b'\0'
5570 act = False # --print0 implies --print
5577 act = False # --print0 implies --print
5571 if opts.get(b'all', False):
5578 if opts.get(b'all', False):
5572 ignored = True
5579 ignored = True
5573 unknown = True
5580 unknown = True
5574 else:
5581 else:
5575 ignored = opts.get(b'ignored', False)
5582 ignored = opts.get(b'ignored', False)
5576 unknown = not ignored
5583 unknown = not ignored
5577
5584
5578 removefiles = opts.get(b'files')
5585 removefiles = opts.get(b'files')
5579 removedirs = opts.get(b'dirs')
5586 removedirs = opts.get(b'dirs')
5580 confirm = opts.get(b'confirm')
5587 confirm = opts.get(b'confirm')
5581 if confirm is None:
5588 if confirm is None:
5582 try:
5589 try:
5583 extensions.find(b'purge')
5590 extensions.find(b'purge')
5584 confirm = False
5591 confirm = False
5585 except KeyError:
5592 except KeyError:
5586 confirm = True
5593 confirm = True
5587
5594
5588 if not removefiles and not removedirs:
5595 if not removefiles and not removedirs:
5589 removefiles = True
5596 removefiles = True
5590 removedirs = True
5597 removedirs = True
5591
5598
5592 match = scmutil.match(repo[None], dirs, opts)
5599 match = scmutil.match(repo[None], dirs, opts)
5593
5600
5594 paths = mergemod.purge(
5601 paths = mergemod.purge(
5595 repo,
5602 repo,
5596 match,
5603 match,
5597 unknown=unknown,
5604 unknown=unknown,
5598 ignored=ignored,
5605 ignored=ignored,
5599 removeemptydirs=removedirs,
5606 removeemptydirs=removedirs,
5600 removefiles=removefiles,
5607 removefiles=removefiles,
5601 abortonerror=opts.get(b'abort_on_err'),
5608 abortonerror=opts.get(b'abort_on_err'),
5602 noop=not act,
5609 noop=not act,
5603 confirm=confirm,
5610 confirm=confirm,
5604 )
5611 )
5605
5612
5606 for path in paths:
5613 for path in paths:
5607 if not act:
5614 if not act:
5608 ui.write(b'%s%s' % (path, eol))
5615 ui.write(b'%s%s' % (path, eol))
5609
5616
5610
5617
5611 @command(
5618 @command(
5612 b'push',
5619 b'push',
5613 [
5620 [
5614 (b'f', b'force', None, _(b'force push')),
5621 (b'f', b'force', None, _(b'force push')),
5615 (
5622 (
5616 b'r',
5623 b'r',
5617 b'rev',
5624 b'rev',
5618 [],
5625 [],
5619 _(b'a changeset intended to be included in the destination'),
5626 _(b'a changeset intended to be included in the destination'),
5620 _(b'REV'),
5627 _(b'REV'),
5621 ),
5628 ),
5622 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5629 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5623 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5630 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5624 (
5631 (
5625 b'b',
5632 b'b',
5626 b'branch',
5633 b'branch',
5627 [],
5634 [],
5628 _(b'a specific branch you would like to push'),
5635 _(b'a specific branch you would like to push'),
5629 _(b'BRANCH'),
5636 _(b'BRANCH'),
5630 ),
5637 ),
5631 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5638 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5632 (
5639 (
5633 b'',
5640 b'',
5634 b'pushvars',
5641 b'pushvars',
5635 [],
5642 [],
5636 _(b'variables that can be sent to server (ADVANCED)'),
5643 _(b'variables that can be sent to server (ADVANCED)'),
5637 ),
5644 ),
5638 (
5645 (
5639 b'',
5646 b'',
5640 b'publish',
5647 b'publish',
5641 False,
5648 False,
5642 _(b'push the changeset as public (EXPERIMENTAL)'),
5649 _(b'push the changeset as public (EXPERIMENTAL)'),
5643 ),
5650 ),
5644 ]
5651 ]
5645 + remoteopts,
5652 + remoteopts,
5646 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5653 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5647 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5654 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5648 helpbasic=True,
5655 helpbasic=True,
5649 )
5656 )
5650 def push(ui, repo, *dests, **opts):
5657 def push(ui, repo, *dests, **opts):
5651 """push changes to the specified destination
5658 """push changes to the specified destination
5652
5659
5653 Push changesets from the local repository to the specified
5660 Push changesets from the local repository to the specified
5654 destination.
5661 destination.
5655
5662
5656 This operation is symmetrical to pull: it is identical to a pull
5663 This operation is symmetrical to pull: it is identical to a pull
5657 in the destination repository from the current one.
5664 in the destination repository from the current one.
5658
5665
5659 By default, push will not allow creation of new heads at the
5666 By default, push will not allow creation of new heads at the
5660 destination, since multiple heads would make it unclear which head
5667 destination, since multiple heads would make it unclear which head
5661 to use. In this situation, it is recommended to pull and merge
5668 to use. In this situation, it is recommended to pull and merge
5662 before pushing.
5669 before pushing.
5663
5670
5664 Use --new-branch if you want to allow push to create a new named
5671 Use --new-branch if you want to allow push to create a new named
5665 branch that is not present at the destination. This allows you to
5672 branch that is not present at the destination. This allows you to
5666 only create a new branch without forcing other changes.
5673 only create a new branch without forcing other changes.
5667
5674
5668 .. note::
5675 .. note::
5669
5676
5670 Extra care should be taken with the -f/--force option,
5677 Extra care should be taken with the -f/--force option,
5671 which will push all new heads on all branches, an action which will
5678 which will push all new heads on all branches, an action which will
5672 almost always cause confusion for collaborators.
5679 almost always cause confusion for collaborators.
5673
5680
5674 If -r/--rev is used, the specified revision and all its ancestors
5681 If -r/--rev is used, the specified revision and all its ancestors
5675 will be pushed to the remote repository.
5682 will be pushed to the remote repository.
5676
5683
5677 If -B/--bookmark is used, the specified bookmarked revision, its
5684 If -B/--bookmark is used, the specified bookmarked revision, its
5678 ancestors, and the bookmark will be pushed to the remote
5685 ancestors, and the bookmark will be pushed to the remote
5679 repository. Specifying ``.`` is equivalent to specifying the active
5686 repository. Specifying ``.`` is equivalent to specifying the active
5680 bookmark's name. Use the --all-bookmarks option for pushing all
5687 bookmark's name. Use the --all-bookmarks option for pushing all
5681 current bookmarks.
5688 current bookmarks.
5682
5689
5683 Please see :hg:`help urls` for important details about ``ssh://``
5690 Please see :hg:`help urls` for important details about ``ssh://``
5684 URLs. If DESTINATION is omitted, a default path will be used.
5691 URLs. If DESTINATION is omitted, a default path will be used.
5685
5692
5686 When passed multiple destinations, push will process them one after the
5693 When passed multiple destinations, push will process them one after the
5687 other, but stop should an error occur.
5694 other, but stop should an error occur.
5688
5695
5689 .. container:: verbose
5696 .. container:: verbose
5690
5697
5691 The --pushvars option sends strings to the server that become
5698 The --pushvars option sends strings to the server that become
5692 environment variables prepended with ``HG_USERVAR_``. For example,
5699 environment variables prepended with ``HG_USERVAR_``. For example,
5693 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5700 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5694 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5701 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5695
5702
5696 pushvars can provide for user-overridable hooks as well as set debug
5703 pushvars can provide for user-overridable hooks as well as set debug
5697 levels. One example is having a hook that blocks commits containing
5704 levels. One example is having a hook that blocks commits containing
5698 conflict markers, but enables the user to override the hook if the file
5705 conflict markers, but enables the user to override the hook if the file
5699 is using conflict markers for testing purposes or the file format has
5706 is using conflict markers for testing purposes or the file format has
5700 strings that look like conflict markers.
5707 strings that look like conflict markers.
5701
5708
5702 By default, servers will ignore `--pushvars`. To enable it add the
5709 By default, servers will ignore `--pushvars`. To enable it add the
5703 following to your configuration file::
5710 following to your configuration file::
5704
5711
5705 [push]
5712 [push]
5706 pushvars.server = true
5713 pushvars.server = true
5707
5714
5708 Returns 0 if push was successful, 1 if nothing to push.
5715 Returns 0 if push was successful, 1 if nothing to push.
5709 """
5716 """
5710
5717
5711 opts = pycompat.byteskwargs(opts)
5718 opts = pycompat.byteskwargs(opts)
5712
5719
5713 if opts.get(b'all_bookmarks'):
5720 if opts.get(b'all_bookmarks'):
5714 cmdutil.check_incompatible_arguments(
5721 cmdutil.check_incompatible_arguments(
5715 opts,
5722 opts,
5716 b'all_bookmarks',
5723 b'all_bookmarks',
5717 [b'bookmark', b'rev'],
5724 [b'bookmark', b'rev'],
5718 )
5725 )
5719 opts[b'bookmark'] = list(repo._bookmarks)
5726 opts[b'bookmark'] = list(repo._bookmarks)
5720
5727
5721 if opts.get(b'bookmark'):
5728 if opts.get(b'bookmark'):
5722 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5729 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5723 for b in opts[b'bookmark']:
5730 for b in opts[b'bookmark']:
5724 # translate -B options to -r so changesets get pushed
5731 # translate -B options to -r so changesets get pushed
5725 b = repo._bookmarks.expandname(b)
5732 b = repo._bookmarks.expandname(b)
5726 if b in repo._bookmarks:
5733 if b in repo._bookmarks:
5727 opts.setdefault(b'rev', []).append(b)
5734 opts.setdefault(b'rev', []).append(b)
5728 else:
5735 else:
5729 # if we try to push a deleted bookmark, translate it to null
5736 # if we try to push a deleted bookmark, translate it to null
5730 # this lets simultaneous -r, -b options continue working
5737 # this lets simultaneous -r, -b options continue working
5731 opts.setdefault(b'rev', []).append(b"null")
5738 opts.setdefault(b'rev', []).append(b"null")
5732
5739
5733 some_pushed = False
5740 some_pushed = False
5734 result = 0
5741 result = 0
5735 for path in urlutil.get_push_paths(repo, ui, dests):
5742 for path in urlutil.get_push_paths(repo, ui, dests):
5736 dest = path.pushloc or path.loc
5743 dest = path.pushloc or path.loc
5737 branches = (path.branch, opts.get(b'branch') or [])
5744 branches = (path.branch, opts.get(b'branch') or [])
5738 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5745 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5739 revs, checkout = hg.addbranchrevs(
5746 revs, checkout = hg.addbranchrevs(
5740 repo, repo, branches, opts.get(b'rev')
5747 repo, repo, branches, opts.get(b'rev')
5741 )
5748 )
5742 other = hg.peer(repo, opts, dest)
5749 other = hg.peer(repo, opts, dest)
5743
5750
5744 try:
5751 try:
5745 if revs:
5752 if revs:
5746 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5753 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5747 if not revs:
5754 if not revs:
5748 raise error.InputError(
5755 raise error.InputError(
5749 _(b"specified revisions evaluate to an empty set"),
5756 _(b"specified revisions evaluate to an empty set"),
5750 hint=_(b"use different revision arguments"),
5757 hint=_(b"use different revision arguments"),
5751 )
5758 )
5752 elif path.pushrev:
5759 elif path.pushrev:
5753 # It doesn't make any sense to specify ancestor revisions. So limit
5760 # It doesn't make any sense to specify ancestor revisions. So limit
5754 # to DAG heads to make discovery simpler.
5761 # to DAG heads to make discovery simpler.
5755 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5762 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5756 revs = scmutil.revrange(repo, [expr])
5763 revs = scmutil.revrange(repo, [expr])
5757 revs = [repo[rev].node() for rev in revs]
5764 revs = [repo[rev].node() for rev in revs]
5758 if not revs:
5765 if not revs:
5759 raise error.InputError(
5766 raise error.InputError(
5760 _(
5767 _(
5761 b'default push revset for path evaluates to an empty set'
5768 b'default push revset for path evaluates to an empty set'
5762 )
5769 )
5763 )
5770 )
5764 elif ui.configbool(b'commands', b'push.require-revs'):
5771 elif ui.configbool(b'commands', b'push.require-revs'):
5765 raise error.InputError(
5772 raise error.InputError(
5766 _(b'no revisions specified to push'),
5773 _(b'no revisions specified to push'),
5767 hint=_(b'did you mean "hg push -r ."?'),
5774 hint=_(b'did you mean "hg push -r ."?'),
5768 )
5775 )
5769
5776
5770 repo._subtoppath = dest
5777 repo._subtoppath = dest
5771 try:
5778 try:
5772 # push subrepos depth-first for coherent ordering
5779 # push subrepos depth-first for coherent ordering
5773 c = repo[b'.']
5780 c = repo[b'.']
5774 subs = c.substate # only repos that are committed
5781 subs = c.substate # only repos that are committed
5775 for s in sorted(subs):
5782 for s in sorted(subs):
5776 sub_result = c.sub(s).push(opts)
5783 sub_result = c.sub(s).push(opts)
5777 if sub_result == 0:
5784 if sub_result == 0:
5778 return 1
5785 return 1
5779 finally:
5786 finally:
5780 del repo._subtoppath
5787 del repo._subtoppath
5781
5788
5782 opargs = dict(
5789 opargs = dict(
5783 opts.get(b'opargs', {})
5790 opts.get(b'opargs', {})
5784 ) # copy opargs since we may mutate it
5791 ) # copy opargs since we may mutate it
5785 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5792 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5786
5793
5787 pushop = exchange.push(
5794 pushop = exchange.push(
5788 repo,
5795 repo,
5789 other,
5796 other,
5790 opts.get(b'force'),
5797 opts.get(b'force'),
5791 revs=revs,
5798 revs=revs,
5792 newbranch=opts.get(b'new_branch'),
5799 newbranch=opts.get(b'new_branch'),
5793 bookmarks=opts.get(b'bookmark', ()),
5800 bookmarks=opts.get(b'bookmark', ()),
5794 publish=opts.get(b'publish'),
5801 publish=opts.get(b'publish'),
5795 opargs=opargs,
5802 opargs=opargs,
5796 )
5803 )
5797
5804
5798 if pushop.cgresult == 0:
5805 if pushop.cgresult == 0:
5799 result = 1
5806 result = 1
5800 elif pushop.cgresult is not None:
5807 elif pushop.cgresult is not None:
5801 some_pushed = True
5808 some_pushed = True
5802
5809
5803 if pushop.bkresult is not None:
5810 if pushop.bkresult is not None:
5804 if pushop.bkresult == 2:
5811 if pushop.bkresult == 2:
5805 result = 2
5812 result = 2
5806 elif not result and pushop.bkresult:
5813 elif not result and pushop.bkresult:
5807 result = 2
5814 result = 2
5808
5815
5809 if result:
5816 if result:
5810 break
5817 break
5811
5818
5812 finally:
5819 finally:
5813 other.close()
5820 other.close()
5814 if result == 0 and not some_pushed:
5821 if result == 0 and not some_pushed:
5815 result = 1
5822 result = 1
5816 return result
5823 return result
5817
5824
5818
5825
5819 @command(
5826 @command(
5820 b'recover',
5827 b'recover',
5821 [
5828 [
5822 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5829 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5823 ],
5830 ],
5824 helpcategory=command.CATEGORY_MAINTENANCE,
5831 helpcategory=command.CATEGORY_MAINTENANCE,
5825 )
5832 )
5826 def recover(ui, repo, **opts):
5833 def recover(ui, repo, **opts):
5827 """roll back an interrupted transaction
5834 """roll back an interrupted transaction
5828
5835
5829 Recover from an interrupted commit or pull.
5836 Recover from an interrupted commit or pull.
5830
5837
5831 This command tries to fix the repository status after an
5838 This command tries to fix the repository status after an
5832 interrupted operation. It should only be necessary when Mercurial
5839 interrupted operation. It should only be necessary when Mercurial
5833 suggests it.
5840 suggests it.
5834
5841
5835 Returns 0 if successful, 1 if nothing to recover or verify fails.
5842 Returns 0 if successful, 1 if nothing to recover or verify fails.
5836 """
5843 """
5837 ret = repo.recover()
5844 ret = repo.recover()
5838 if ret:
5845 if ret:
5839 if opts['verify']:
5846 if opts['verify']:
5840 return hg.verify(repo)
5847 return hg.verify(repo)
5841 else:
5848 else:
5842 msg = _(
5849 msg = _(
5843 b"(verify step skipped, run `hg verify` to check your "
5850 b"(verify step skipped, run `hg verify` to check your "
5844 b"repository content)\n"
5851 b"repository content)\n"
5845 )
5852 )
5846 ui.warn(msg)
5853 ui.warn(msg)
5847 return 0
5854 return 0
5848 return 1
5855 return 1
5849
5856
5850
5857
5851 @command(
5858 @command(
5852 b'remove|rm',
5859 b'remove|rm',
5853 [
5860 [
5854 (b'A', b'after', None, _(b'record delete for missing files')),
5861 (b'A', b'after', None, _(b'record delete for missing files')),
5855 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5862 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5856 ]
5863 ]
5857 + subrepoopts
5864 + subrepoopts
5858 + walkopts
5865 + walkopts
5859 + dryrunopts,
5866 + dryrunopts,
5860 _(b'[OPTION]... FILE...'),
5867 _(b'[OPTION]... FILE...'),
5861 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5868 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5862 helpbasic=True,
5869 helpbasic=True,
5863 inferrepo=True,
5870 inferrepo=True,
5864 )
5871 )
5865 def remove(ui, repo, *pats, **opts):
5872 def remove(ui, repo, *pats, **opts):
5866 """remove the specified files on the next commit
5873 """remove the specified files on the next commit
5867
5874
5868 Schedule the indicated files for removal from the current branch.
5875 Schedule the indicated files for removal from the current branch.
5869
5876
5870 This command schedules the files to be removed at the next commit.
5877 This command schedules the files to be removed at the next commit.
5871 To undo a remove before that, see :hg:`revert`. To undo added
5878 To undo a remove before that, see :hg:`revert`. To undo added
5872 files, see :hg:`forget`.
5879 files, see :hg:`forget`.
5873
5880
5874 .. container:: verbose
5881 .. container:: verbose
5875
5882
5876 -A/--after can be used to remove only files that have already
5883 -A/--after can be used to remove only files that have already
5877 been deleted, -f/--force can be used to force deletion, and -Af
5884 been deleted, -f/--force can be used to force deletion, and -Af
5878 can be used to remove files from the next revision without
5885 can be used to remove files from the next revision without
5879 deleting them from the working directory.
5886 deleting them from the working directory.
5880
5887
5881 The following table details the behavior of remove for different
5888 The following table details the behavior of remove for different
5882 file states (columns) and option combinations (rows). The file
5889 file states (columns) and option combinations (rows). The file
5883 states are Added [A], Clean [C], Modified [M] and Missing [!]
5890 states are Added [A], Clean [C], Modified [M] and Missing [!]
5884 (as reported by :hg:`status`). The actions are Warn, Remove
5891 (as reported by :hg:`status`). The actions are Warn, Remove
5885 (from branch) and Delete (from disk):
5892 (from branch) and Delete (from disk):
5886
5893
5887 ========= == == == ==
5894 ========= == == == ==
5888 opt/state A C M !
5895 opt/state A C M !
5889 ========= == == == ==
5896 ========= == == == ==
5890 none W RD W R
5897 none W RD W R
5891 -f R RD RD R
5898 -f R RD RD R
5892 -A W W W R
5899 -A W W W R
5893 -Af R R R R
5900 -Af R R R R
5894 ========= == == == ==
5901 ========= == == == ==
5895
5902
5896 .. note::
5903 .. note::
5897
5904
5898 :hg:`remove` never deletes files in Added [A] state from the
5905 :hg:`remove` never deletes files in Added [A] state from the
5899 working directory, not even if ``--force`` is specified.
5906 working directory, not even if ``--force`` is specified.
5900
5907
5901 Returns 0 on success, 1 if any warnings encountered.
5908 Returns 0 on success, 1 if any warnings encountered.
5902 """
5909 """
5903
5910
5904 opts = pycompat.byteskwargs(opts)
5911 opts = pycompat.byteskwargs(opts)
5905 after, force = opts.get(b'after'), opts.get(b'force')
5912 after, force = opts.get(b'after'), opts.get(b'force')
5906 dryrun = opts.get(b'dry_run')
5913 dryrun = opts.get(b'dry_run')
5907 if not pats and not after:
5914 if not pats and not after:
5908 raise error.InputError(_(b'no files specified'))
5915 raise error.InputError(_(b'no files specified'))
5909
5916
5910 m = scmutil.match(repo[None], pats, opts)
5917 m = scmutil.match(repo[None], pats, opts)
5911 subrepos = opts.get(b'subrepos')
5918 subrepos = opts.get(b'subrepos')
5912 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5919 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5913 return cmdutil.remove(
5920 return cmdutil.remove(
5914 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5921 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5915 )
5922 )
5916
5923
5917
5924
5918 @command(
5925 @command(
5919 b'rename|move|mv',
5926 b'rename|move|mv',
5920 [
5927 [
5921 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5928 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5922 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5929 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5923 (
5930 (
5924 b'',
5931 b'',
5925 b'at-rev',
5932 b'at-rev',
5926 b'',
5933 b'',
5927 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5934 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5928 _(b'REV'),
5935 _(b'REV'),
5929 ),
5936 ),
5930 (
5937 (
5931 b'f',
5938 b'f',
5932 b'force',
5939 b'force',
5933 None,
5940 None,
5934 _(b'forcibly move over an existing managed file'),
5941 _(b'forcibly move over an existing managed file'),
5935 ),
5942 ),
5936 ]
5943 ]
5937 + walkopts
5944 + walkopts
5938 + dryrunopts,
5945 + dryrunopts,
5939 _(b'[OPTION]... SOURCE... DEST'),
5946 _(b'[OPTION]... SOURCE... DEST'),
5940 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5947 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5941 )
5948 )
5942 def rename(ui, repo, *pats, **opts):
5949 def rename(ui, repo, *pats, **opts):
5943 """rename files; equivalent of copy + remove
5950 """rename files; equivalent of copy + remove
5944
5951
5945 Mark dest as copies of sources; mark sources for deletion. If dest
5952 Mark dest as copies of sources; mark sources for deletion. If dest
5946 is a directory, copies are put in that directory. If dest is a
5953 is a directory, copies are put in that directory. If dest is a
5947 file, there can only be one source.
5954 file, there can only be one source.
5948
5955
5949 By default, this command copies the contents of files as they
5956 By default, this command copies the contents of files as they
5950 exist in the working directory. If invoked with -A/--after, the
5957 exist in the working directory. If invoked with -A/--after, the
5951 operation is recorded, but no copying is performed.
5958 operation is recorded, but no copying is performed.
5952
5959
5953 To undo marking a destination file as renamed, use --forget. With that
5960 To undo marking a destination file as renamed, use --forget. With that
5954 option, all given (positional) arguments are unmarked as renames. The
5961 option, all given (positional) arguments are unmarked as renames. The
5955 destination file(s) will be left in place (still tracked). The source
5962 destination file(s) will be left in place (still tracked). The source
5956 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5963 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5957 the same way as :hg:`copy --forget`.
5964 the same way as :hg:`copy --forget`.
5958
5965
5959 This command takes effect with the next commit by default.
5966 This command takes effect with the next commit by default.
5960
5967
5961 Returns 0 on success, 1 if errors are encountered.
5968 Returns 0 on success, 1 if errors are encountered.
5962 """
5969 """
5963 opts = pycompat.byteskwargs(opts)
5970 opts = pycompat.byteskwargs(opts)
5964 with repo.wlock():
5971 with repo.wlock():
5965 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5972 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5966
5973
5967
5974
5968 @command(
5975 @command(
5969 b'resolve',
5976 b'resolve',
5970 [
5977 [
5971 (b'a', b'all', None, _(b'select all unresolved files')),
5978 (b'a', b'all', None, _(b'select all unresolved files')),
5972 (b'l', b'list', None, _(b'list state of files needing merge')),
5979 (b'l', b'list', None, _(b'list state of files needing merge')),
5973 (b'm', b'mark', None, _(b'mark files as resolved')),
5980 (b'm', b'mark', None, _(b'mark files as resolved')),
5974 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5981 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5975 (b'n', b'no-status', None, _(b'hide status prefix')),
5982 (b'n', b'no-status', None, _(b'hide status prefix')),
5976 (b'', b're-merge', None, _(b're-merge files')),
5983 (b'', b're-merge', None, _(b're-merge files')),
5977 ]
5984 ]
5978 + mergetoolopts
5985 + mergetoolopts
5979 + walkopts
5986 + walkopts
5980 + formatteropts,
5987 + formatteropts,
5981 _(b'[OPTION]... [FILE]...'),
5988 _(b'[OPTION]... [FILE]...'),
5982 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5989 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5983 inferrepo=True,
5990 inferrepo=True,
5984 )
5991 )
5985 def resolve(ui, repo, *pats, **opts):
5992 def resolve(ui, repo, *pats, **opts):
5986 """redo merges or set/view the merge status of files
5993 """redo merges or set/view the merge status of files
5987
5994
5988 Merges with unresolved conflicts are often the result of
5995 Merges with unresolved conflicts are often the result of
5989 non-interactive merging using the ``internal:merge`` configuration
5996 non-interactive merging using the ``internal:merge`` configuration
5990 setting, or a command-line merge tool like ``diff3``. The resolve
5997 setting, or a command-line merge tool like ``diff3``. The resolve
5991 command is used to manage the files involved in a merge, after
5998 command is used to manage the files involved in a merge, after
5992 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5999 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5993 working directory must have two parents). See :hg:`help
6000 working directory must have two parents). See :hg:`help
5994 merge-tools` for information on configuring merge tools.
6001 merge-tools` for information on configuring merge tools.
5995
6002
5996 The resolve command can be used in the following ways:
6003 The resolve command can be used in the following ways:
5997
6004
5998 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6005 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5999 the specified files, discarding any previous merge attempts. Re-merging
6006 the specified files, discarding any previous merge attempts. Re-merging
6000 is not performed for files already marked as resolved. Use ``--all/-a``
6007 is not performed for files already marked as resolved. Use ``--all/-a``
6001 to select all unresolved files. ``--tool`` can be used to specify
6008 to select all unresolved files. ``--tool`` can be used to specify
6002 the merge tool used for the given files. It overrides the HGMERGE
6009 the merge tool used for the given files. It overrides the HGMERGE
6003 environment variable and your configuration files. Previous file
6010 environment variable and your configuration files. Previous file
6004 contents are saved with a ``.orig`` suffix.
6011 contents are saved with a ``.orig`` suffix.
6005
6012
6006 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6013 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6007 (e.g. after having manually fixed-up the files). The default is
6014 (e.g. after having manually fixed-up the files). The default is
6008 to mark all unresolved files.
6015 to mark all unresolved files.
6009
6016
6010 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6017 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6011 default is to mark all resolved files.
6018 default is to mark all resolved files.
6012
6019
6013 - :hg:`resolve -l`: list files which had or still have conflicts.
6020 - :hg:`resolve -l`: list files which had or still have conflicts.
6014 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6021 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6015 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6022 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6016 the list. See :hg:`help filesets` for details.
6023 the list. See :hg:`help filesets` for details.
6017
6024
6018 .. note::
6025 .. note::
6019
6026
6020 Mercurial will not let you commit files with unresolved merge
6027 Mercurial will not let you commit files with unresolved merge
6021 conflicts. You must use :hg:`resolve -m ...` before you can
6028 conflicts. You must use :hg:`resolve -m ...` before you can
6022 commit after a conflicting merge.
6029 commit after a conflicting merge.
6023
6030
6024 .. container:: verbose
6031 .. container:: verbose
6025
6032
6026 Template:
6033 Template:
6027
6034
6028 The following keywords are supported in addition to the common template
6035 The following keywords are supported in addition to the common template
6029 keywords and functions. See also :hg:`help templates`.
6036 keywords and functions. See also :hg:`help templates`.
6030
6037
6031 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6038 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6032 :path: String. Repository-absolute path of the file.
6039 :path: String. Repository-absolute path of the file.
6033
6040
6034 Returns 0 on success, 1 if any files fail a resolve attempt.
6041 Returns 0 on success, 1 if any files fail a resolve attempt.
6035 """
6042 """
6036
6043
6037 opts = pycompat.byteskwargs(opts)
6044 opts = pycompat.byteskwargs(opts)
6038 confirm = ui.configbool(b'commands', b'resolve.confirm')
6045 confirm = ui.configbool(b'commands', b'resolve.confirm')
6039 flaglist = b'all mark unmark list no_status re_merge'.split()
6046 flaglist = b'all mark unmark list no_status re_merge'.split()
6040 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6047 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6041
6048
6042 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6049 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6043 if actioncount > 1:
6050 if actioncount > 1:
6044 raise error.InputError(_(b"too many actions specified"))
6051 raise error.InputError(_(b"too many actions specified"))
6045 elif actioncount == 0 and ui.configbool(
6052 elif actioncount == 0 and ui.configbool(
6046 b'commands', b'resolve.explicit-re-merge'
6053 b'commands', b'resolve.explicit-re-merge'
6047 ):
6054 ):
6048 hint = _(b'use --mark, --unmark, --list or --re-merge')
6055 hint = _(b'use --mark, --unmark, --list or --re-merge')
6049 raise error.InputError(_(b'no action specified'), hint=hint)
6056 raise error.InputError(_(b'no action specified'), hint=hint)
6050 if pats and all:
6057 if pats and all:
6051 raise error.InputError(_(b"can't specify --all and patterns"))
6058 raise error.InputError(_(b"can't specify --all and patterns"))
6052 if not (all or pats or show or mark or unmark):
6059 if not (all or pats or show or mark or unmark):
6053 raise error.InputError(
6060 raise error.InputError(
6054 _(b'no files or directories specified'),
6061 _(b'no files or directories specified'),
6055 hint=b'use --all to re-merge all unresolved files',
6062 hint=b'use --all to re-merge all unresolved files',
6056 )
6063 )
6057
6064
6058 if confirm:
6065 if confirm:
6059 if all:
6066 if all:
6060 if ui.promptchoice(
6067 if ui.promptchoice(
6061 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6068 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6062 ):
6069 ):
6063 raise error.CanceledError(_(b'user quit'))
6070 raise error.CanceledError(_(b'user quit'))
6064 if mark and not pats:
6071 if mark and not pats:
6065 if ui.promptchoice(
6072 if ui.promptchoice(
6066 _(
6073 _(
6067 b'mark all unresolved files as resolved (yn)?'
6074 b'mark all unresolved files as resolved (yn)?'
6068 b'$$ &Yes $$ &No'
6075 b'$$ &Yes $$ &No'
6069 )
6076 )
6070 ):
6077 ):
6071 raise error.CanceledError(_(b'user quit'))
6078 raise error.CanceledError(_(b'user quit'))
6072 if unmark and not pats:
6079 if unmark and not pats:
6073 if ui.promptchoice(
6080 if ui.promptchoice(
6074 _(
6081 _(
6075 b'mark all resolved files as unresolved (yn)?'
6082 b'mark all resolved files as unresolved (yn)?'
6076 b'$$ &Yes $$ &No'
6083 b'$$ &Yes $$ &No'
6077 )
6084 )
6078 ):
6085 ):
6079 raise error.CanceledError(_(b'user quit'))
6086 raise error.CanceledError(_(b'user quit'))
6080
6087
6081 uipathfn = scmutil.getuipathfn(repo)
6088 uipathfn = scmutil.getuipathfn(repo)
6082
6089
6083 if show:
6090 if show:
6084 ui.pager(b'resolve')
6091 ui.pager(b'resolve')
6085 fm = ui.formatter(b'resolve', opts)
6092 fm = ui.formatter(b'resolve', opts)
6086 ms = mergestatemod.mergestate.read(repo)
6093 ms = mergestatemod.mergestate.read(repo)
6087 wctx = repo[None]
6094 wctx = repo[None]
6088 m = scmutil.match(wctx, pats, opts)
6095 m = scmutil.match(wctx, pats, opts)
6089
6096
6090 # Labels and keys based on merge state. Unresolved path conflicts show
6097 # Labels and keys based on merge state. Unresolved path conflicts show
6091 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6098 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6092 # resolved conflicts.
6099 # resolved conflicts.
6093 mergestateinfo = {
6100 mergestateinfo = {
6094 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6101 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6095 b'resolve.unresolved',
6102 b'resolve.unresolved',
6096 b'U',
6103 b'U',
6097 ),
6104 ),
6098 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6105 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6099 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6106 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6100 b'resolve.unresolved',
6107 b'resolve.unresolved',
6101 b'P',
6108 b'P',
6102 ),
6109 ),
6103 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6110 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6104 b'resolve.resolved',
6111 b'resolve.resolved',
6105 b'R',
6112 b'R',
6106 ),
6113 ),
6107 }
6114 }
6108
6115
6109 for f in ms:
6116 for f in ms:
6110 if not m(f):
6117 if not m(f):
6111 continue
6118 continue
6112
6119
6113 label, key = mergestateinfo[ms[f]]
6120 label, key = mergestateinfo[ms[f]]
6114 fm.startitem()
6121 fm.startitem()
6115 fm.context(ctx=wctx)
6122 fm.context(ctx=wctx)
6116 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6123 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6117 fm.data(path=f)
6124 fm.data(path=f)
6118 fm.plain(b'%s\n' % uipathfn(f), label=label)
6125 fm.plain(b'%s\n' % uipathfn(f), label=label)
6119 fm.end()
6126 fm.end()
6120 return 0
6127 return 0
6121
6128
6122 with repo.wlock():
6129 with repo.wlock():
6123 ms = mergestatemod.mergestate.read(repo)
6130 ms = mergestatemod.mergestate.read(repo)
6124
6131
6125 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6132 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6126 raise error.StateError(
6133 raise error.StateError(
6127 _(b'resolve command not applicable when not merging')
6134 _(b'resolve command not applicable when not merging')
6128 )
6135 )
6129
6136
6130 wctx = repo[None]
6137 wctx = repo[None]
6131 m = scmutil.match(wctx, pats, opts)
6138 m = scmutil.match(wctx, pats, opts)
6132 ret = 0
6139 ret = 0
6133 didwork = False
6140 didwork = False
6134
6141
6135 hasconflictmarkers = []
6142 hasconflictmarkers = []
6136 if mark:
6143 if mark:
6137 markcheck = ui.config(b'commands', b'resolve.mark-check')
6144 markcheck = ui.config(b'commands', b'resolve.mark-check')
6138 if markcheck not in [b'warn', b'abort']:
6145 if markcheck not in [b'warn', b'abort']:
6139 # Treat all invalid / unrecognized values as 'none'.
6146 # Treat all invalid / unrecognized values as 'none'.
6140 markcheck = False
6147 markcheck = False
6141 for f in ms:
6148 for f in ms:
6142 if not m(f):
6149 if not m(f):
6143 continue
6150 continue
6144
6151
6145 didwork = True
6152 didwork = True
6146
6153
6147 # path conflicts must be resolved manually
6154 # path conflicts must be resolved manually
6148 if ms[f] in (
6155 if ms[f] in (
6149 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6156 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6150 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6157 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6151 ):
6158 ):
6152 if mark:
6159 if mark:
6153 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6160 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6154 elif unmark:
6161 elif unmark:
6155 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6162 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6156 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6163 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6157 ui.warn(
6164 ui.warn(
6158 _(b'%s: path conflict must be resolved manually\n')
6165 _(b'%s: path conflict must be resolved manually\n')
6159 % uipathfn(f)
6166 % uipathfn(f)
6160 )
6167 )
6161 continue
6168 continue
6162
6169
6163 if mark:
6170 if mark:
6164 if markcheck:
6171 if markcheck:
6165 fdata = repo.wvfs.tryread(f)
6172 fdata = repo.wvfs.tryread(f)
6166 if (
6173 if (
6167 filemerge.hasconflictmarkers(fdata)
6174 filemerge.hasconflictmarkers(fdata)
6168 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6175 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6169 ):
6176 ):
6170 hasconflictmarkers.append(f)
6177 hasconflictmarkers.append(f)
6171 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6178 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6172 elif unmark:
6179 elif unmark:
6173 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6180 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6174 else:
6181 else:
6175 # backup pre-resolve (merge uses .orig for its own purposes)
6182 # backup pre-resolve (merge uses .orig for its own purposes)
6176 a = repo.wjoin(f)
6183 a = repo.wjoin(f)
6177 try:
6184 try:
6178 util.copyfile(a, a + b".resolve")
6185 util.copyfile(a, a + b".resolve")
6179 except (IOError, OSError) as inst:
6186 except (IOError, OSError) as inst:
6180 if inst.errno != errno.ENOENT:
6187 if inst.errno != errno.ENOENT:
6181 raise
6188 raise
6182
6189
6183 try:
6190 try:
6184 # preresolve file
6191 # preresolve file
6185 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6192 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6186 with ui.configoverride(overrides, b'resolve'):
6193 with ui.configoverride(overrides, b'resolve'):
6187 r = ms.resolve(f, wctx)
6194 r = ms.resolve(f, wctx)
6188 if r:
6195 if r:
6189 ret = 1
6196 ret = 1
6190 finally:
6197 finally:
6191 ms.commit()
6198 ms.commit()
6192
6199
6193 # replace filemerge's .orig file with our resolve file
6200 # replace filemerge's .orig file with our resolve file
6194 try:
6201 try:
6195 util.rename(
6202 util.rename(
6196 a + b".resolve", scmutil.backuppath(ui, repo, f)
6203 a + b".resolve", scmutil.backuppath(ui, repo, f)
6197 )
6204 )
6198 except OSError as inst:
6205 except OSError as inst:
6199 if inst.errno != errno.ENOENT:
6206 if inst.errno != errno.ENOENT:
6200 raise
6207 raise
6201
6208
6202 if hasconflictmarkers:
6209 if hasconflictmarkers:
6203 ui.warn(
6210 ui.warn(
6204 _(
6211 _(
6205 b'warning: the following files still have conflict '
6212 b'warning: the following files still have conflict '
6206 b'markers:\n'
6213 b'markers:\n'
6207 )
6214 )
6208 + b''.join(
6215 + b''.join(
6209 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6216 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6210 )
6217 )
6211 )
6218 )
6212 if markcheck == b'abort' and not all and not pats:
6219 if markcheck == b'abort' and not all and not pats:
6213 raise error.StateError(
6220 raise error.StateError(
6214 _(b'conflict markers detected'),
6221 _(b'conflict markers detected'),
6215 hint=_(b'use --all to mark anyway'),
6222 hint=_(b'use --all to mark anyway'),
6216 )
6223 )
6217
6224
6218 ms.commit()
6225 ms.commit()
6219 branchmerge = repo.dirstate.p2() != repo.nullid
6226 branchmerge = repo.dirstate.p2() != repo.nullid
6220 # resolve is not doing a parent change here, however, `record updates`
6227 # resolve is not doing a parent change here, however, `record updates`
6221 # will call some dirstate API that at intended for parent changes call.
6228 # will call some dirstate API that at intended for parent changes call.
6222 # Ideally we would not need this and could implement a lighter version
6229 # Ideally we would not need this and could implement a lighter version
6223 # of the recordupdateslogic that will not have to deal with the part
6230 # of the recordupdateslogic that will not have to deal with the part
6224 # related to parent changes. However this would requires that:
6231 # related to parent changes. However this would requires that:
6225 # - we are sure we passed around enough information at update/merge
6232 # - we are sure we passed around enough information at update/merge
6226 # time to no longer needs it at `hg resolve time`
6233 # time to no longer needs it at `hg resolve time`
6227 # - we are sure we store that information well enough to be able to reuse it
6234 # - we are sure we store that information well enough to be able to reuse it
6228 # - we are the necessary logic to reuse it right.
6235 # - we are the necessary logic to reuse it right.
6229 #
6236 #
6230 # All this should eventually happens, but in the mean time, we use this
6237 # All this should eventually happens, but in the mean time, we use this
6231 # context manager slightly out of the context it should be.
6238 # context manager slightly out of the context it should be.
6232 with repo.dirstate.parentchange():
6239 with repo.dirstate.parentchange():
6233 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6240 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6234
6241
6235 if not didwork and pats:
6242 if not didwork and pats:
6236 hint = None
6243 hint = None
6237 if not any([p for p in pats if p.find(b':') >= 0]):
6244 if not any([p for p in pats if p.find(b':') >= 0]):
6238 pats = [b'path:%s' % p for p in pats]
6245 pats = [b'path:%s' % p for p in pats]
6239 m = scmutil.match(wctx, pats, opts)
6246 m = scmutil.match(wctx, pats, opts)
6240 for f in ms:
6247 for f in ms:
6241 if not m(f):
6248 if not m(f):
6242 continue
6249 continue
6243
6250
6244 def flag(o):
6251 def flag(o):
6245 if o == b're_merge':
6252 if o == b're_merge':
6246 return b'--re-merge '
6253 return b'--re-merge '
6247 return b'-%s ' % o[0:1]
6254 return b'-%s ' % o[0:1]
6248
6255
6249 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6256 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6250 hint = _(b"(try: hg resolve %s%s)\n") % (
6257 hint = _(b"(try: hg resolve %s%s)\n") % (
6251 flags,
6258 flags,
6252 b' '.join(pats),
6259 b' '.join(pats),
6253 )
6260 )
6254 break
6261 break
6255 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6262 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6256 if hint:
6263 if hint:
6257 ui.warn(hint)
6264 ui.warn(hint)
6258
6265
6259 unresolvedf = ms.unresolvedcount()
6266 unresolvedf = ms.unresolvedcount()
6260 if not unresolvedf:
6267 if not unresolvedf:
6261 ui.status(_(b'(no more unresolved files)\n'))
6268 ui.status(_(b'(no more unresolved files)\n'))
6262 cmdutil.checkafterresolved(repo)
6269 cmdutil.checkafterresolved(repo)
6263
6270
6264 return ret
6271 return ret
6265
6272
6266
6273
6267 @command(
6274 @command(
6268 b'revert',
6275 b'revert',
6269 [
6276 [
6270 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6277 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6271 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6278 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6272 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6279 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6273 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6280 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6274 (b'i', b'interactive', None, _(b'interactively select the changes')),
6281 (b'i', b'interactive', None, _(b'interactively select the changes')),
6275 ]
6282 ]
6276 + walkopts
6283 + walkopts
6277 + dryrunopts,
6284 + dryrunopts,
6278 _(b'[OPTION]... [-r REV] [NAME]...'),
6285 _(b'[OPTION]... [-r REV] [NAME]...'),
6279 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6286 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6280 )
6287 )
6281 def revert(ui, repo, *pats, **opts):
6288 def revert(ui, repo, *pats, **opts):
6282 """restore files to their checkout state
6289 """restore files to their checkout state
6283
6290
6284 .. note::
6291 .. note::
6285
6292
6286 To check out earlier revisions, you should use :hg:`update REV`.
6293 To check out earlier revisions, you should use :hg:`update REV`.
6287 To cancel an uncommitted merge (and lose your changes),
6294 To cancel an uncommitted merge (and lose your changes),
6288 use :hg:`merge --abort`.
6295 use :hg:`merge --abort`.
6289
6296
6290 With no revision specified, revert the specified files or directories
6297 With no revision specified, revert the specified files or directories
6291 to the contents they had in the parent of the working directory.
6298 to the contents they had in the parent of the working directory.
6292 This restores the contents of files to an unmodified
6299 This restores the contents of files to an unmodified
6293 state and unschedules adds, removes, copies, and renames. If the
6300 state and unschedules adds, removes, copies, and renames. If the
6294 working directory has two parents, you must explicitly specify a
6301 working directory has two parents, you must explicitly specify a
6295 revision.
6302 revision.
6296
6303
6297 Using the -r/--rev or -d/--date options, revert the given files or
6304 Using the -r/--rev or -d/--date options, revert the given files or
6298 directories to their states as of a specific revision. Because
6305 directories to their states as of a specific revision. Because
6299 revert does not change the working directory parents, this will
6306 revert does not change the working directory parents, this will
6300 cause these files to appear modified. This can be helpful to "back
6307 cause these files to appear modified. This can be helpful to "back
6301 out" some or all of an earlier change. See :hg:`backout` for a
6308 out" some or all of an earlier change. See :hg:`backout` for a
6302 related method.
6309 related method.
6303
6310
6304 Modified files are saved with a .orig suffix before reverting.
6311 Modified files are saved with a .orig suffix before reverting.
6305 To disable these backups, use --no-backup. It is possible to store
6312 To disable these backups, use --no-backup. It is possible to store
6306 the backup files in a custom directory relative to the root of the
6313 the backup files in a custom directory relative to the root of the
6307 repository by setting the ``ui.origbackuppath`` configuration
6314 repository by setting the ``ui.origbackuppath`` configuration
6308 option.
6315 option.
6309
6316
6310 See :hg:`help dates` for a list of formats valid for -d/--date.
6317 See :hg:`help dates` for a list of formats valid for -d/--date.
6311
6318
6312 See :hg:`help backout` for a way to reverse the effect of an
6319 See :hg:`help backout` for a way to reverse the effect of an
6313 earlier changeset.
6320 earlier changeset.
6314
6321
6315 Returns 0 on success.
6322 Returns 0 on success.
6316 """
6323 """
6317
6324
6318 opts = pycompat.byteskwargs(opts)
6325 opts = pycompat.byteskwargs(opts)
6319 if opts.get(b"date"):
6326 if opts.get(b"date"):
6320 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6327 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6321 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6328 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6322
6329
6323 parent, p2 = repo.dirstate.parents()
6330 parent, p2 = repo.dirstate.parents()
6324 if not opts.get(b'rev') and p2 != repo.nullid:
6331 if not opts.get(b'rev') and p2 != repo.nullid:
6325 # revert after merge is a trap for new users (issue2915)
6332 # revert after merge is a trap for new users (issue2915)
6326 raise error.InputError(
6333 raise error.InputError(
6327 _(b'uncommitted merge with no revision specified'),
6334 _(b'uncommitted merge with no revision specified'),
6328 hint=_(b"use 'hg update' or see 'hg help revert'"),
6335 hint=_(b"use 'hg update' or see 'hg help revert'"),
6329 )
6336 )
6330
6337
6331 rev = opts.get(b'rev')
6338 rev = opts.get(b'rev')
6332 if rev:
6339 if rev:
6333 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6340 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6334 ctx = logcmdutil.revsingle(repo, rev)
6341 ctx = logcmdutil.revsingle(repo, rev)
6335
6342
6336 if not (
6343 if not (
6337 pats
6344 pats
6338 or opts.get(b'include')
6345 or opts.get(b'include')
6339 or opts.get(b'exclude')
6346 or opts.get(b'exclude')
6340 or opts.get(b'all')
6347 or opts.get(b'all')
6341 or opts.get(b'interactive')
6348 or opts.get(b'interactive')
6342 ):
6349 ):
6343 msg = _(b"no files or directories specified")
6350 msg = _(b"no files or directories specified")
6344 if p2 != repo.nullid:
6351 if p2 != repo.nullid:
6345 hint = _(
6352 hint = _(
6346 b"uncommitted merge, use --all to discard all changes,"
6353 b"uncommitted merge, use --all to discard all changes,"
6347 b" or 'hg update -C .' to abort the merge"
6354 b" or 'hg update -C .' to abort the merge"
6348 )
6355 )
6349 raise error.InputError(msg, hint=hint)
6356 raise error.InputError(msg, hint=hint)
6350 dirty = any(repo.status())
6357 dirty = any(repo.status())
6351 node = ctx.node()
6358 node = ctx.node()
6352 if node != parent:
6359 if node != parent:
6353 if dirty:
6360 if dirty:
6354 hint = (
6361 hint = (
6355 _(
6362 _(
6356 b"uncommitted changes, use --all to discard all"
6363 b"uncommitted changes, use --all to discard all"
6357 b" changes, or 'hg update %d' to update"
6364 b" changes, or 'hg update %d' to update"
6358 )
6365 )
6359 % ctx.rev()
6366 % ctx.rev()
6360 )
6367 )
6361 else:
6368 else:
6362 hint = (
6369 hint = (
6363 _(
6370 _(
6364 b"use --all to revert all files,"
6371 b"use --all to revert all files,"
6365 b" or 'hg update %d' to update"
6372 b" or 'hg update %d' to update"
6366 )
6373 )
6367 % ctx.rev()
6374 % ctx.rev()
6368 )
6375 )
6369 elif dirty:
6376 elif dirty:
6370 hint = _(b"uncommitted changes, use --all to discard all changes")
6377 hint = _(b"uncommitted changes, use --all to discard all changes")
6371 else:
6378 else:
6372 hint = _(b"use --all to revert all files")
6379 hint = _(b"use --all to revert all files")
6373 raise error.InputError(msg, hint=hint)
6380 raise error.InputError(msg, hint=hint)
6374
6381
6375 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6382 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6376
6383
6377
6384
6378 @command(
6385 @command(
6379 b'rollback',
6386 b'rollback',
6380 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6387 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6381 helpcategory=command.CATEGORY_MAINTENANCE,
6388 helpcategory=command.CATEGORY_MAINTENANCE,
6382 )
6389 )
6383 def rollback(ui, repo, **opts):
6390 def rollback(ui, repo, **opts):
6384 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6391 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6385
6392
6386 Please use :hg:`commit --amend` instead of rollback to correct
6393 Please use :hg:`commit --amend` instead of rollback to correct
6387 mistakes in the last commit.
6394 mistakes in the last commit.
6388
6395
6389 This command should be used with care. There is only one level of
6396 This command should be used with care. There is only one level of
6390 rollback, and there is no way to undo a rollback. It will also
6397 rollback, and there is no way to undo a rollback. It will also
6391 restore the dirstate at the time of the last transaction, losing
6398 restore the dirstate at the time of the last transaction, losing
6392 any dirstate changes since that time. This command does not alter
6399 any dirstate changes since that time. This command does not alter
6393 the working directory.
6400 the working directory.
6394
6401
6395 Transactions are used to encapsulate the effects of all commands
6402 Transactions are used to encapsulate the effects of all commands
6396 that create new changesets or propagate existing changesets into a
6403 that create new changesets or propagate existing changesets into a
6397 repository.
6404 repository.
6398
6405
6399 .. container:: verbose
6406 .. container:: verbose
6400
6407
6401 For example, the following commands are transactional, and their
6408 For example, the following commands are transactional, and their
6402 effects can be rolled back:
6409 effects can be rolled back:
6403
6410
6404 - commit
6411 - commit
6405 - import
6412 - import
6406 - pull
6413 - pull
6407 - push (with this repository as the destination)
6414 - push (with this repository as the destination)
6408 - unbundle
6415 - unbundle
6409
6416
6410 To avoid permanent data loss, rollback will refuse to rollback a
6417 To avoid permanent data loss, rollback will refuse to rollback a
6411 commit transaction if it isn't checked out. Use --force to
6418 commit transaction if it isn't checked out. Use --force to
6412 override this protection.
6419 override this protection.
6413
6420
6414 The rollback command can be entirely disabled by setting the
6421 The rollback command can be entirely disabled by setting the
6415 ``ui.rollback`` configuration setting to false. If you're here
6422 ``ui.rollback`` configuration setting to false. If you're here
6416 because you want to use rollback and it's disabled, you can
6423 because you want to use rollback and it's disabled, you can
6417 re-enable the command by setting ``ui.rollback`` to true.
6424 re-enable the command by setting ``ui.rollback`` to true.
6418
6425
6419 This command is not intended for use on public repositories. Once
6426 This command is not intended for use on public repositories. Once
6420 changes are visible for pull by other users, rolling a transaction
6427 changes are visible for pull by other users, rolling a transaction
6421 back locally is ineffective (someone else may already have pulled
6428 back locally is ineffective (someone else may already have pulled
6422 the changes). Furthermore, a race is possible with readers of the
6429 the changes). Furthermore, a race is possible with readers of the
6423 repository; for example an in-progress pull from the repository
6430 repository; for example an in-progress pull from the repository
6424 may fail if a rollback is performed.
6431 may fail if a rollback is performed.
6425
6432
6426 Returns 0 on success, 1 if no rollback data is available.
6433 Returns 0 on success, 1 if no rollback data is available.
6427 """
6434 """
6428 if not ui.configbool(b'ui', b'rollback'):
6435 if not ui.configbool(b'ui', b'rollback'):
6429 raise error.Abort(
6436 raise error.Abort(
6430 _(b'rollback is disabled because it is unsafe'),
6437 _(b'rollback is disabled because it is unsafe'),
6431 hint=b'see `hg help -v rollback` for information',
6438 hint=b'see `hg help -v rollback` for information',
6432 )
6439 )
6433 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6440 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6434
6441
6435
6442
6436 @command(
6443 @command(
6437 b'root',
6444 b'root',
6438 [] + formatteropts,
6445 [] + formatteropts,
6439 intents={INTENT_READONLY},
6446 intents={INTENT_READONLY},
6440 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6447 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6441 )
6448 )
6442 def root(ui, repo, **opts):
6449 def root(ui, repo, **opts):
6443 """print the root (top) of the current working directory
6450 """print the root (top) of the current working directory
6444
6451
6445 Print the root directory of the current repository.
6452 Print the root directory of the current repository.
6446
6453
6447 .. container:: verbose
6454 .. container:: verbose
6448
6455
6449 Template:
6456 Template:
6450
6457
6451 The following keywords are supported in addition to the common template
6458 The following keywords are supported in addition to the common template
6452 keywords and functions. See also :hg:`help templates`.
6459 keywords and functions. See also :hg:`help templates`.
6453
6460
6454 :hgpath: String. Path to the .hg directory.
6461 :hgpath: String. Path to the .hg directory.
6455 :storepath: String. Path to the directory holding versioned data.
6462 :storepath: String. Path to the directory holding versioned data.
6456
6463
6457 Returns 0 on success.
6464 Returns 0 on success.
6458 """
6465 """
6459 opts = pycompat.byteskwargs(opts)
6466 opts = pycompat.byteskwargs(opts)
6460 with ui.formatter(b'root', opts) as fm:
6467 with ui.formatter(b'root', opts) as fm:
6461 fm.startitem()
6468 fm.startitem()
6462 fm.write(b'reporoot', b'%s\n', repo.root)
6469 fm.write(b'reporoot', b'%s\n', repo.root)
6463 fm.data(hgpath=repo.path, storepath=repo.spath)
6470 fm.data(hgpath=repo.path, storepath=repo.spath)
6464
6471
6465
6472
6466 @command(
6473 @command(
6467 b'serve',
6474 b'serve',
6468 [
6475 [
6469 (
6476 (
6470 b'A',
6477 b'A',
6471 b'accesslog',
6478 b'accesslog',
6472 b'',
6479 b'',
6473 _(b'name of access log file to write to'),
6480 _(b'name of access log file to write to'),
6474 _(b'FILE'),
6481 _(b'FILE'),
6475 ),
6482 ),
6476 (b'd', b'daemon', None, _(b'run server in background')),
6483 (b'd', b'daemon', None, _(b'run server in background')),
6477 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6484 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6478 (
6485 (
6479 b'E',
6486 b'E',
6480 b'errorlog',
6487 b'errorlog',
6481 b'',
6488 b'',
6482 _(b'name of error log file to write to'),
6489 _(b'name of error log file to write to'),
6483 _(b'FILE'),
6490 _(b'FILE'),
6484 ),
6491 ),
6485 # use string type, then we can check if something was passed
6492 # use string type, then we can check if something was passed
6486 (
6493 (
6487 b'p',
6494 b'p',
6488 b'port',
6495 b'port',
6489 b'',
6496 b'',
6490 _(b'port to listen on (default: 8000)'),
6497 _(b'port to listen on (default: 8000)'),
6491 _(b'PORT'),
6498 _(b'PORT'),
6492 ),
6499 ),
6493 (
6500 (
6494 b'a',
6501 b'a',
6495 b'address',
6502 b'address',
6496 b'',
6503 b'',
6497 _(b'address to listen on (default: all interfaces)'),
6504 _(b'address to listen on (default: all interfaces)'),
6498 _(b'ADDR'),
6505 _(b'ADDR'),
6499 ),
6506 ),
6500 (
6507 (
6501 b'',
6508 b'',
6502 b'prefix',
6509 b'prefix',
6503 b'',
6510 b'',
6504 _(b'prefix path to serve from (default: server root)'),
6511 _(b'prefix path to serve from (default: server root)'),
6505 _(b'PREFIX'),
6512 _(b'PREFIX'),
6506 ),
6513 ),
6507 (
6514 (
6508 b'n',
6515 b'n',
6509 b'name',
6516 b'name',
6510 b'',
6517 b'',
6511 _(b'name to show in web pages (default: working directory)'),
6518 _(b'name to show in web pages (default: working directory)'),
6512 _(b'NAME'),
6519 _(b'NAME'),
6513 ),
6520 ),
6514 (
6521 (
6515 b'',
6522 b'',
6516 b'web-conf',
6523 b'web-conf',
6517 b'',
6524 b'',
6518 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6525 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6519 _(b'FILE'),
6526 _(b'FILE'),
6520 ),
6527 ),
6521 (
6528 (
6522 b'',
6529 b'',
6523 b'webdir-conf',
6530 b'webdir-conf',
6524 b'',
6531 b'',
6525 _(b'name of the hgweb config file (DEPRECATED)'),
6532 _(b'name of the hgweb config file (DEPRECATED)'),
6526 _(b'FILE'),
6533 _(b'FILE'),
6527 ),
6534 ),
6528 (
6535 (
6529 b'',
6536 b'',
6530 b'pid-file',
6537 b'pid-file',
6531 b'',
6538 b'',
6532 _(b'name of file to write process ID to'),
6539 _(b'name of file to write process ID to'),
6533 _(b'FILE'),
6540 _(b'FILE'),
6534 ),
6541 ),
6535 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6542 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6536 (
6543 (
6537 b'',
6544 b'',
6538 b'cmdserver',
6545 b'cmdserver',
6539 b'',
6546 b'',
6540 _(b'for remote clients (ADVANCED)'),
6547 _(b'for remote clients (ADVANCED)'),
6541 _(b'MODE'),
6548 _(b'MODE'),
6542 ),
6549 ),
6543 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6550 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6544 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6551 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6545 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6552 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6546 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6553 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6547 (b'', b'print-url', None, _(b'start and print only the URL')),
6554 (b'', b'print-url', None, _(b'start and print only the URL')),
6548 ]
6555 ]
6549 + subrepoopts,
6556 + subrepoopts,
6550 _(b'[OPTION]...'),
6557 _(b'[OPTION]...'),
6551 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6558 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6552 helpbasic=True,
6559 helpbasic=True,
6553 optionalrepo=True,
6560 optionalrepo=True,
6554 )
6561 )
6555 def serve(ui, repo, **opts):
6562 def serve(ui, repo, **opts):
6556 """start stand-alone webserver
6563 """start stand-alone webserver
6557
6564
6558 Start a local HTTP repository browser and pull server. You can use
6565 Start a local HTTP repository browser and pull server. You can use
6559 this for ad-hoc sharing and browsing of repositories. It is
6566 this for ad-hoc sharing and browsing of repositories. It is
6560 recommended to use a real web server to serve a repository for
6567 recommended to use a real web server to serve a repository for
6561 longer periods of time.
6568 longer periods of time.
6562
6569
6563 Please note that the server does not implement access control.
6570 Please note that the server does not implement access control.
6564 This means that, by default, anybody can read from the server and
6571 This means that, by default, anybody can read from the server and
6565 nobody can write to it by default. Set the ``web.allow-push``
6572 nobody can write to it by default. Set the ``web.allow-push``
6566 option to ``*`` to allow everybody to push to the server. You
6573 option to ``*`` to allow everybody to push to the server. You
6567 should use a real web server if you need to authenticate users.
6574 should use a real web server if you need to authenticate users.
6568
6575
6569 By default, the server logs accesses to stdout and errors to
6576 By default, the server logs accesses to stdout and errors to
6570 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6577 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6571 files.
6578 files.
6572
6579
6573 To have the server choose a free port number to listen on, specify
6580 To have the server choose a free port number to listen on, specify
6574 a port number of 0; in this case, the server will print the port
6581 a port number of 0; in this case, the server will print the port
6575 number it uses.
6582 number it uses.
6576
6583
6577 Returns 0 on success.
6584 Returns 0 on success.
6578 """
6585 """
6579
6586
6580 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6587 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6581 opts = pycompat.byteskwargs(opts)
6588 opts = pycompat.byteskwargs(opts)
6582 if opts[b"print_url"] and ui.verbose:
6589 if opts[b"print_url"] and ui.verbose:
6583 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6590 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6584
6591
6585 if opts[b"stdio"]:
6592 if opts[b"stdio"]:
6586 if repo is None:
6593 if repo is None:
6587 raise error.RepoError(
6594 raise error.RepoError(
6588 _(b"there is no Mercurial repository here (.hg not found)")
6595 _(b"there is no Mercurial repository here (.hg not found)")
6589 )
6596 )
6590 s = wireprotoserver.sshserver(ui, repo)
6597 s = wireprotoserver.sshserver(ui, repo)
6591 s.serve_forever()
6598 s.serve_forever()
6592 return
6599 return
6593
6600
6594 service = server.createservice(ui, repo, opts)
6601 service = server.createservice(ui, repo, opts)
6595 return server.runservice(opts, initfn=service.init, runfn=service.run)
6602 return server.runservice(opts, initfn=service.init, runfn=service.run)
6596
6603
6597
6604
6598 @command(
6605 @command(
6599 b'shelve',
6606 b'shelve',
6600 [
6607 [
6601 (
6608 (
6602 b'A',
6609 b'A',
6603 b'addremove',
6610 b'addremove',
6604 None,
6611 None,
6605 _(b'mark new/missing files as added/removed before shelving'),
6612 _(b'mark new/missing files as added/removed before shelving'),
6606 ),
6613 ),
6607 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6614 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6608 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6615 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6609 (
6616 (
6610 b'',
6617 b'',
6611 b'date',
6618 b'date',
6612 b'',
6619 b'',
6613 _(b'shelve with the specified commit date'),
6620 _(b'shelve with the specified commit date'),
6614 _(b'DATE'),
6621 _(b'DATE'),
6615 ),
6622 ),
6616 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6623 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6617 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6624 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6618 (
6625 (
6619 b'k',
6626 b'k',
6620 b'keep',
6627 b'keep',
6621 False,
6628 False,
6622 _(b'shelve, but keep changes in the working directory'),
6629 _(b'shelve, but keep changes in the working directory'),
6623 ),
6630 ),
6624 (b'l', b'list', None, _(b'list current shelves')),
6631 (b'l', b'list', None, _(b'list current shelves')),
6625 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6632 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6626 (
6633 (
6627 b'n',
6634 b'n',
6628 b'name',
6635 b'name',
6629 b'',
6636 b'',
6630 _(b'use the given name for the shelved commit'),
6637 _(b'use the given name for the shelved commit'),
6631 _(b'NAME'),
6638 _(b'NAME'),
6632 ),
6639 ),
6633 (
6640 (
6634 b'p',
6641 b'p',
6635 b'patch',
6642 b'patch',
6636 None,
6643 None,
6637 _(
6644 _(
6638 b'output patches for changes (provide the names of the shelved '
6645 b'output patches for changes (provide the names of the shelved '
6639 b'changes as positional arguments)'
6646 b'changes as positional arguments)'
6640 ),
6647 ),
6641 ),
6648 ),
6642 (b'i', b'interactive', None, _(b'interactive mode')),
6649 (b'i', b'interactive', None, _(b'interactive mode')),
6643 (
6650 (
6644 b'',
6651 b'',
6645 b'stat',
6652 b'stat',
6646 None,
6653 None,
6647 _(
6654 _(
6648 b'output diffstat-style summary of changes (provide the names of '
6655 b'output diffstat-style summary of changes (provide the names of '
6649 b'the shelved changes as positional arguments)'
6656 b'the shelved changes as positional arguments)'
6650 ),
6657 ),
6651 ),
6658 ),
6652 ]
6659 ]
6653 + cmdutil.walkopts,
6660 + cmdutil.walkopts,
6654 _(b'hg shelve [OPTION]... [FILE]...'),
6661 _(b'hg shelve [OPTION]... [FILE]...'),
6655 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6662 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6656 )
6663 )
6657 def shelve(ui, repo, *pats, **opts):
6664 def shelve(ui, repo, *pats, **opts):
6658 """save and set aside changes from the working directory
6665 """save and set aside changes from the working directory
6659
6666
6660 Shelving takes files that "hg status" reports as not clean, saves
6667 Shelving takes files that "hg status" reports as not clean, saves
6661 the modifications to a bundle (a shelved change), and reverts the
6668 the modifications to a bundle (a shelved change), and reverts the
6662 files so that their state in the working directory becomes clean.
6669 files so that their state in the working directory becomes clean.
6663
6670
6664 To restore these changes to the working directory, using "hg
6671 To restore these changes to the working directory, using "hg
6665 unshelve"; this will work even if you switch to a different
6672 unshelve"; this will work even if you switch to a different
6666 commit.
6673 commit.
6667
6674
6668 When no files are specified, "hg shelve" saves all not-clean
6675 When no files are specified, "hg shelve" saves all not-clean
6669 files. If specific files or directories are named, only changes to
6676 files. If specific files or directories are named, only changes to
6670 those files are shelved.
6677 those files are shelved.
6671
6678
6672 In bare shelve (when no files are specified, without interactive,
6679 In bare shelve (when no files are specified, without interactive,
6673 include and exclude option), shelving remembers information if the
6680 include and exclude option), shelving remembers information if the
6674 working directory was on newly created branch, in other words working
6681 working directory was on newly created branch, in other words working
6675 directory was on different branch than its first parent. In this
6682 directory was on different branch than its first parent. In this
6676 situation unshelving restores branch information to the working directory.
6683 situation unshelving restores branch information to the working directory.
6677
6684
6678 Each shelved change has a name that makes it easier to find later.
6685 Each shelved change has a name that makes it easier to find later.
6679 The name of a shelved change defaults to being based on the active
6686 The name of a shelved change defaults to being based on the active
6680 bookmark, or if there is no active bookmark, the current named
6687 bookmark, or if there is no active bookmark, the current named
6681 branch. To specify a different name, use ``--name``.
6688 branch. To specify a different name, use ``--name``.
6682
6689
6683 To see a list of existing shelved changes, use the ``--list``
6690 To see a list of existing shelved changes, use the ``--list``
6684 option. For each shelved change, this will print its name, age,
6691 option. For each shelved change, this will print its name, age,
6685 and description; use ``--patch`` or ``--stat`` for more details.
6692 and description; use ``--patch`` or ``--stat`` for more details.
6686
6693
6687 To delete specific shelved changes, use ``--delete``. To delete
6694 To delete specific shelved changes, use ``--delete``. To delete
6688 all shelved changes, use ``--cleanup``.
6695 all shelved changes, use ``--cleanup``.
6689 """
6696 """
6690 opts = pycompat.byteskwargs(opts)
6697 opts = pycompat.byteskwargs(opts)
6691 allowables = [
6698 allowables = [
6692 (b'addremove', {b'create'}), # 'create' is pseudo action
6699 (b'addremove', {b'create'}), # 'create' is pseudo action
6693 (b'unknown', {b'create'}),
6700 (b'unknown', {b'create'}),
6694 (b'cleanup', {b'cleanup'}),
6701 (b'cleanup', {b'cleanup'}),
6695 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6702 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6696 (b'delete', {b'delete'}),
6703 (b'delete', {b'delete'}),
6697 (b'edit', {b'create'}),
6704 (b'edit', {b'create'}),
6698 (b'keep', {b'create'}),
6705 (b'keep', {b'create'}),
6699 (b'list', {b'list'}),
6706 (b'list', {b'list'}),
6700 (b'message', {b'create'}),
6707 (b'message', {b'create'}),
6701 (b'name', {b'create'}),
6708 (b'name', {b'create'}),
6702 (b'patch', {b'patch', b'list'}),
6709 (b'patch', {b'patch', b'list'}),
6703 (b'stat', {b'stat', b'list'}),
6710 (b'stat', {b'stat', b'list'}),
6704 ]
6711 ]
6705
6712
6706 def checkopt(opt):
6713 def checkopt(opt):
6707 if opts.get(opt):
6714 if opts.get(opt):
6708 for i, allowable in allowables:
6715 for i, allowable in allowables:
6709 if opts[i] and opt not in allowable:
6716 if opts[i] and opt not in allowable:
6710 raise error.InputError(
6717 raise error.InputError(
6711 _(
6718 _(
6712 b"options '--%s' and '--%s' may not be "
6719 b"options '--%s' and '--%s' may not be "
6713 b"used together"
6720 b"used together"
6714 )
6721 )
6715 % (opt, i)
6722 % (opt, i)
6716 )
6723 )
6717 return True
6724 return True
6718
6725
6719 if checkopt(b'cleanup'):
6726 if checkopt(b'cleanup'):
6720 if pats:
6727 if pats:
6721 raise error.InputError(
6728 raise error.InputError(
6722 _(b"cannot specify names when using '--cleanup'")
6729 _(b"cannot specify names when using '--cleanup'")
6723 )
6730 )
6724 return shelvemod.cleanupcmd(ui, repo)
6731 return shelvemod.cleanupcmd(ui, repo)
6725 elif checkopt(b'delete'):
6732 elif checkopt(b'delete'):
6726 return shelvemod.deletecmd(ui, repo, pats)
6733 return shelvemod.deletecmd(ui, repo, pats)
6727 elif checkopt(b'list'):
6734 elif checkopt(b'list'):
6728 return shelvemod.listcmd(ui, repo, pats, opts)
6735 return shelvemod.listcmd(ui, repo, pats, opts)
6729 elif checkopt(b'patch') or checkopt(b'stat'):
6736 elif checkopt(b'patch') or checkopt(b'stat'):
6730 return shelvemod.patchcmds(ui, repo, pats, opts)
6737 return shelvemod.patchcmds(ui, repo, pats, opts)
6731 else:
6738 else:
6732 return shelvemod.createcmd(ui, repo, pats, opts)
6739 return shelvemod.createcmd(ui, repo, pats, opts)
6733
6740
6734
6741
6735 _NOTTERSE = b'nothing'
6742 _NOTTERSE = b'nothing'
6736
6743
6737
6744
6738 @command(
6745 @command(
6739 b'status|st',
6746 b'status|st',
6740 [
6747 [
6741 (b'A', b'all', None, _(b'show status of all files')),
6748 (b'A', b'all', None, _(b'show status of all files')),
6742 (b'm', b'modified', None, _(b'show only modified files')),
6749 (b'm', b'modified', None, _(b'show only modified files')),
6743 (b'a', b'added', None, _(b'show only added files')),
6750 (b'a', b'added', None, _(b'show only added files')),
6744 (b'r', b'removed', None, _(b'show only removed files')),
6751 (b'r', b'removed', None, _(b'show only removed files')),
6745 (b'd', b'deleted', None, _(b'show only missing files')),
6752 (b'd', b'deleted', None, _(b'show only missing files')),
6746 (b'c', b'clean', None, _(b'show only files without changes')),
6753 (b'c', b'clean', None, _(b'show only files without changes')),
6747 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6754 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6748 (b'i', b'ignored', None, _(b'show only ignored files')),
6755 (b'i', b'ignored', None, _(b'show only ignored files')),
6749 (b'n', b'no-status', None, _(b'hide status prefix')),
6756 (b'n', b'no-status', None, _(b'hide status prefix')),
6750 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6757 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6751 (
6758 (
6752 b'C',
6759 b'C',
6753 b'copies',
6760 b'copies',
6754 None,
6761 None,
6755 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6762 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6756 ),
6763 ),
6757 (
6764 (
6758 b'0',
6765 b'0',
6759 b'print0',
6766 b'print0',
6760 None,
6767 None,
6761 _(b'end filenames with NUL, for use with xargs'),
6768 _(b'end filenames with NUL, for use with xargs'),
6762 ),
6769 ),
6763 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6770 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6764 (
6771 (
6765 b'',
6772 b'',
6766 b'change',
6773 b'change',
6767 b'',
6774 b'',
6768 _(b'list the changed files of a revision'),
6775 _(b'list the changed files of a revision'),
6769 _(b'REV'),
6776 _(b'REV'),
6770 ),
6777 ),
6771 ]
6778 ]
6772 + walkopts
6779 + walkopts
6773 + subrepoopts
6780 + subrepoopts
6774 + formatteropts,
6781 + formatteropts,
6775 _(b'[OPTION]... [FILE]...'),
6782 _(b'[OPTION]... [FILE]...'),
6776 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6783 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6777 helpbasic=True,
6784 helpbasic=True,
6778 inferrepo=True,
6785 inferrepo=True,
6779 intents={INTENT_READONLY},
6786 intents={INTENT_READONLY},
6780 )
6787 )
6781 def status(ui, repo, *pats, **opts):
6788 def status(ui, repo, *pats, **opts):
6782 """show changed files in the working directory
6789 """show changed files in the working directory
6783
6790
6784 Show status of files in the repository. If names are given, only
6791 Show status of files in the repository. If names are given, only
6785 files that match are shown. Files that are clean or ignored or
6792 files that match are shown. Files that are clean or ignored or
6786 the source of a copy/move operation, are not listed unless
6793 the source of a copy/move operation, are not listed unless
6787 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6794 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6788 Unless options described with "show only ..." are given, the
6795 Unless options described with "show only ..." are given, the
6789 options -mardu are used.
6796 options -mardu are used.
6790
6797
6791 Option -q/--quiet hides untracked (unknown and ignored) files
6798 Option -q/--quiet hides untracked (unknown and ignored) files
6792 unless explicitly requested with -u/--unknown or -i/--ignored.
6799 unless explicitly requested with -u/--unknown or -i/--ignored.
6793
6800
6794 .. note::
6801 .. note::
6795
6802
6796 :hg:`status` may appear to disagree with diff if permissions have
6803 :hg:`status` may appear to disagree with diff if permissions have
6797 changed or a merge has occurred. The standard diff format does
6804 changed or a merge has occurred. The standard diff format does
6798 not report permission changes and diff only reports changes
6805 not report permission changes and diff only reports changes
6799 relative to one merge parent.
6806 relative to one merge parent.
6800
6807
6801 If one revision is given, it is used as the base revision.
6808 If one revision is given, it is used as the base revision.
6802 If two revisions are given, the differences between them are
6809 If two revisions are given, the differences between them are
6803 shown. The --change option can also be used as a shortcut to list
6810 shown. The --change option can also be used as a shortcut to list
6804 the changed files of a revision from its first parent.
6811 the changed files of a revision from its first parent.
6805
6812
6806 The codes used to show the status of files are::
6813 The codes used to show the status of files are::
6807
6814
6808 M = modified
6815 M = modified
6809 A = added
6816 A = added
6810 R = removed
6817 R = removed
6811 C = clean
6818 C = clean
6812 ! = missing (deleted by non-hg command, but still tracked)
6819 ! = missing (deleted by non-hg command, but still tracked)
6813 ? = not tracked
6820 ? = not tracked
6814 I = ignored
6821 I = ignored
6815 = origin of the previous file (with --copies)
6822 = origin of the previous file (with --copies)
6816
6823
6817 .. container:: verbose
6824 .. container:: verbose
6818
6825
6819 The -t/--terse option abbreviates the output by showing only the directory
6826 The -t/--terse option abbreviates the output by showing only the directory
6820 name if all the files in it share the same status. The option takes an
6827 name if all the files in it share the same status. The option takes an
6821 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6828 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6822 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6829 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6823 for 'ignored' and 'c' for clean.
6830 for 'ignored' and 'c' for clean.
6824
6831
6825 It abbreviates only those statuses which are passed. Note that clean and
6832 It abbreviates only those statuses which are passed. Note that clean and
6826 ignored files are not displayed with '--terse ic' unless the -c/--clean
6833 ignored files are not displayed with '--terse ic' unless the -c/--clean
6827 and -i/--ignored options are also used.
6834 and -i/--ignored options are also used.
6828
6835
6829 The -v/--verbose option shows information when the repository is in an
6836 The -v/--verbose option shows information when the repository is in an
6830 unfinished merge, shelve, rebase state etc. You can have this behavior
6837 unfinished merge, shelve, rebase state etc. You can have this behavior
6831 turned on by default by enabling the ``commands.status.verbose`` option.
6838 turned on by default by enabling the ``commands.status.verbose`` option.
6832
6839
6833 You can skip displaying some of these states by setting
6840 You can skip displaying some of these states by setting
6834 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6841 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6835 'histedit', 'merge', 'rebase', or 'unshelve'.
6842 'histedit', 'merge', 'rebase', or 'unshelve'.
6836
6843
6837 Template:
6844 Template:
6838
6845
6839 The following keywords are supported in addition to the common template
6846 The following keywords are supported in addition to the common template
6840 keywords and functions. See also :hg:`help templates`.
6847 keywords and functions. See also :hg:`help templates`.
6841
6848
6842 :path: String. Repository-absolute path of the file.
6849 :path: String. Repository-absolute path of the file.
6843 :source: String. Repository-absolute path of the file originated from.
6850 :source: String. Repository-absolute path of the file originated from.
6844 Available if ``--copies`` is specified.
6851 Available if ``--copies`` is specified.
6845 :status: String. Character denoting file's status.
6852 :status: String. Character denoting file's status.
6846
6853
6847 Examples:
6854 Examples:
6848
6855
6849 - show changes in the working directory relative to a
6856 - show changes in the working directory relative to a
6850 changeset::
6857 changeset::
6851
6858
6852 hg status --rev 9353
6859 hg status --rev 9353
6853
6860
6854 - show changes in the working directory relative to the
6861 - show changes in the working directory relative to the
6855 current directory (see :hg:`help patterns` for more information)::
6862 current directory (see :hg:`help patterns` for more information)::
6856
6863
6857 hg status re:
6864 hg status re:
6858
6865
6859 - show all changes including copies in an existing changeset::
6866 - show all changes including copies in an existing changeset::
6860
6867
6861 hg status --copies --change 9353
6868 hg status --copies --change 9353
6862
6869
6863 - get a NUL separated list of added files, suitable for xargs::
6870 - get a NUL separated list of added files, suitable for xargs::
6864
6871
6865 hg status -an0
6872 hg status -an0
6866
6873
6867 - show more information about the repository status, abbreviating
6874 - show more information about the repository status, abbreviating
6868 added, removed, modified, deleted, and untracked paths::
6875 added, removed, modified, deleted, and untracked paths::
6869
6876
6870 hg status -v -t mardu
6877 hg status -v -t mardu
6871
6878
6872 Returns 0 on success.
6879 Returns 0 on success.
6873
6880
6874 """
6881 """
6875
6882
6876 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6883 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6877 opts = pycompat.byteskwargs(opts)
6884 opts = pycompat.byteskwargs(opts)
6878 revs = opts.get(b'rev', [])
6885 revs = opts.get(b'rev', [])
6879 change = opts.get(b'change', b'')
6886 change = opts.get(b'change', b'')
6880 terse = opts.get(b'terse', _NOTTERSE)
6887 terse = opts.get(b'terse', _NOTTERSE)
6881 if terse is _NOTTERSE:
6888 if terse is _NOTTERSE:
6882 if revs:
6889 if revs:
6883 terse = b''
6890 terse = b''
6884 else:
6891 else:
6885 terse = ui.config(b'commands', b'status.terse')
6892 terse = ui.config(b'commands', b'status.terse')
6886
6893
6887 if revs and terse:
6894 if revs and terse:
6888 msg = _(b'cannot use --terse with --rev')
6895 msg = _(b'cannot use --terse with --rev')
6889 raise error.InputError(msg)
6896 raise error.InputError(msg)
6890 elif change:
6897 elif change:
6891 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6898 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6892 ctx2 = logcmdutil.revsingle(repo, change, None)
6899 ctx2 = logcmdutil.revsingle(repo, change, None)
6893 ctx1 = ctx2.p1()
6900 ctx1 = ctx2.p1()
6894 else:
6901 else:
6895 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6902 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6896 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6903 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6897
6904
6898 forcerelativevalue = None
6905 forcerelativevalue = None
6899 if ui.hasconfig(b'commands', b'status.relative'):
6906 if ui.hasconfig(b'commands', b'status.relative'):
6900 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6907 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6901 uipathfn = scmutil.getuipathfn(
6908 uipathfn = scmutil.getuipathfn(
6902 repo,
6909 repo,
6903 legacyrelativevalue=bool(pats),
6910 legacyrelativevalue=bool(pats),
6904 forcerelativevalue=forcerelativevalue,
6911 forcerelativevalue=forcerelativevalue,
6905 )
6912 )
6906
6913
6907 if opts.get(b'print0'):
6914 if opts.get(b'print0'):
6908 end = b'\0'
6915 end = b'\0'
6909 else:
6916 else:
6910 end = b'\n'
6917 end = b'\n'
6911 states = b'modified added removed deleted unknown ignored clean'.split()
6918 states = b'modified added removed deleted unknown ignored clean'.split()
6912 show = [k for k in states if opts.get(k)]
6919 show = [k for k in states if opts.get(k)]
6913 if opts.get(b'all'):
6920 if opts.get(b'all'):
6914 show += ui.quiet and (states[:4] + [b'clean']) or states
6921 show += ui.quiet and (states[:4] + [b'clean']) or states
6915
6922
6916 if not show:
6923 if not show:
6917 if ui.quiet:
6924 if ui.quiet:
6918 show = states[:4]
6925 show = states[:4]
6919 else:
6926 else:
6920 show = states[:5]
6927 show = states[:5]
6921
6928
6922 m = scmutil.match(ctx2, pats, opts)
6929 m = scmutil.match(ctx2, pats, opts)
6923 if terse:
6930 if terse:
6924 # we need to compute clean and unknown to terse
6931 # we need to compute clean and unknown to terse
6925 stat = repo.status(
6932 stat = repo.status(
6926 ctx1.node(),
6933 ctx1.node(),
6927 ctx2.node(),
6934 ctx2.node(),
6928 m,
6935 m,
6929 b'ignored' in show or b'i' in terse,
6936 b'ignored' in show or b'i' in terse,
6930 clean=True,
6937 clean=True,
6931 unknown=True,
6938 unknown=True,
6932 listsubrepos=opts.get(b'subrepos'),
6939 listsubrepos=opts.get(b'subrepos'),
6933 )
6940 )
6934
6941
6935 stat = cmdutil.tersedir(stat, terse)
6942 stat = cmdutil.tersedir(stat, terse)
6936 else:
6943 else:
6937 stat = repo.status(
6944 stat = repo.status(
6938 ctx1.node(),
6945 ctx1.node(),
6939 ctx2.node(),
6946 ctx2.node(),
6940 m,
6947 m,
6941 b'ignored' in show,
6948 b'ignored' in show,
6942 b'clean' in show,
6949 b'clean' in show,
6943 b'unknown' in show,
6950 b'unknown' in show,
6944 opts.get(b'subrepos'),
6951 opts.get(b'subrepos'),
6945 )
6952 )
6946
6953
6947 changestates = zip(
6954 changestates = zip(
6948 states,
6955 states,
6949 pycompat.iterbytestr(b'MAR!?IC'),
6956 pycompat.iterbytestr(b'MAR!?IC'),
6950 [getattr(stat, s.decode('utf8')) for s in states],
6957 [getattr(stat, s.decode('utf8')) for s in states],
6951 )
6958 )
6952
6959
6953 copy = {}
6960 copy = {}
6954 if (
6961 if (
6955 opts.get(b'all')
6962 opts.get(b'all')
6956 or opts.get(b'copies')
6963 or opts.get(b'copies')
6957 or ui.configbool(b'ui', b'statuscopies')
6964 or ui.configbool(b'ui', b'statuscopies')
6958 ) and not opts.get(b'no_status'):
6965 ) and not opts.get(b'no_status'):
6959 copy = copies.pathcopies(ctx1, ctx2, m)
6966 copy = copies.pathcopies(ctx1, ctx2, m)
6960
6967
6961 morestatus = None
6968 morestatus = None
6962 if (
6969 if (
6963 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6970 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6964 and not ui.plain()
6971 and not ui.plain()
6965 and not opts.get(b'print0')
6972 and not opts.get(b'print0')
6966 ):
6973 ):
6967 morestatus = cmdutil.readmorestatus(repo)
6974 morestatus = cmdutil.readmorestatus(repo)
6968
6975
6969 ui.pager(b'status')
6976 ui.pager(b'status')
6970 fm = ui.formatter(b'status', opts)
6977 fm = ui.formatter(b'status', opts)
6971 fmt = b'%s' + end
6978 fmt = b'%s' + end
6972 showchar = not opts.get(b'no_status')
6979 showchar = not opts.get(b'no_status')
6973
6980
6974 for state, char, files in changestates:
6981 for state, char, files in changestates:
6975 if state in show:
6982 if state in show:
6976 label = b'status.' + state
6983 label = b'status.' + state
6977 for f in files:
6984 for f in files:
6978 fm.startitem()
6985 fm.startitem()
6979 fm.context(ctx=ctx2)
6986 fm.context(ctx=ctx2)
6980 fm.data(itemtype=b'file', path=f)
6987 fm.data(itemtype=b'file', path=f)
6981 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6988 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6982 fm.plain(fmt % uipathfn(f), label=label)
6989 fm.plain(fmt % uipathfn(f), label=label)
6983 if f in copy:
6990 if f in copy:
6984 fm.data(source=copy[f])
6991 fm.data(source=copy[f])
6985 fm.plain(
6992 fm.plain(
6986 (b' %s' + end) % uipathfn(copy[f]),
6993 (b' %s' + end) % uipathfn(copy[f]),
6987 label=b'status.copied',
6994 label=b'status.copied',
6988 )
6995 )
6989 if morestatus:
6996 if morestatus:
6990 morestatus.formatfile(f, fm)
6997 morestatus.formatfile(f, fm)
6991
6998
6992 if morestatus:
6999 if morestatus:
6993 morestatus.formatfooter(fm)
7000 morestatus.formatfooter(fm)
6994 fm.end()
7001 fm.end()
6995
7002
6996
7003
6997 @command(
7004 @command(
6998 b'summary|sum',
7005 b'summary|sum',
6999 [(b'', b'remote', None, _(b'check for push and pull'))],
7006 [(b'', b'remote', None, _(b'check for push and pull'))],
7000 b'[--remote]',
7007 b'[--remote]',
7001 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7008 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7002 helpbasic=True,
7009 helpbasic=True,
7003 intents={INTENT_READONLY},
7010 intents={INTENT_READONLY},
7004 )
7011 )
7005 def summary(ui, repo, **opts):
7012 def summary(ui, repo, **opts):
7006 """summarize working directory state
7013 """summarize working directory state
7007
7014
7008 This generates a brief summary of the working directory state,
7015 This generates a brief summary of the working directory state,
7009 including parents, branch, commit status, phase and available updates.
7016 including parents, branch, commit status, phase and available updates.
7010
7017
7011 With the --remote option, this will check the default paths for
7018 With the --remote option, this will check the default paths for
7012 incoming and outgoing changes. This can be time-consuming.
7019 incoming and outgoing changes. This can be time-consuming.
7013
7020
7014 Returns 0 on success.
7021 Returns 0 on success.
7015 """
7022 """
7016
7023
7017 opts = pycompat.byteskwargs(opts)
7024 opts = pycompat.byteskwargs(opts)
7018 ui.pager(b'summary')
7025 ui.pager(b'summary')
7019 ctx = repo[None]
7026 ctx = repo[None]
7020 parents = ctx.parents()
7027 parents = ctx.parents()
7021 pnode = parents[0].node()
7028 pnode = parents[0].node()
7022 marks = []
7029 marks = []
7023
7030
7024 try:
7031 try:
7025 ms = mergestatemod.mergestate.read(repo)
7032 ms = mergestatemod.mergestate.read(repo)
7026 except error.UnsupportedMergeRecords as e:
7033 except error.UnsupportedMergeRecords as e:
7027 s = b' '.join(e.recordtypes)
7034 s = b' '.join(e.recordtypes)
7028 ui.warn(
7035 ui.warn(
7029 _(b'warning: merge state has unsupported record types: %s\n') % s
7036 _(b'warning: merge state has unsupported record types: %s\n') % s
7030 )
7037 )
7031 unresolved = []
7038 unresolved = []
7032 else:
7039 else:
7033 unresolved = list(ms.unresolved())
7040 unresolved = list(ms.unresolved())
7034
7041
7035 for p in parents:
7042 for p in parents:
7036 # label with log.changeset (instead of log.parent) since this
7043 # label with log.changeset (instead of log.parent) since this
7037 # shows a working directory parent *changeset*:
7044 # shows a working directory parent *changeset*:
7038 # i18n: column positioning for "hg summary"
7045 # i18n: column positioning for "hg summary"
7039 ui.write(
7046 ui.write(
7040 _(b'parent: %d:%s ') % (p.rev(), p),
7047 _(b'parent: %d:%s ') % (p.rev(), p),
7041 label=logcmdutil.changesetlabels(p),
7048 label=logcmdutil.changesetlabels(p),
7042 )
7049 )
7043 ui.write(b' '.join(p.tags()), label=b'log.tag')
7050 ui.write(b' '.join(p.tags()), label=b'log.tag')
7044 if p.bookmarks():
7051 if p.bookmarks():
7045 marks.extend(p.bookmarks())
7052 marks.extend(p.bookmarks())
7046 if p.rev() == -1:
7053 if p.rev() == -1:
7047 if not len(repo):
7054 if not len(repo):
7048 ui.write(_(b' (empty repository)'))
7055 ui.write(_(b' (empty repository)'))
7049 else:
7056 else:
7050 ui.write(_(b' (no revision checked out)'))
7057 ui.write(_(b' (no revision checked out)'))
7051 if p.obsolete():
7058 if p.obsolete():
7052 ui.write(_(b' (obsolete)'))
7059 ui.write(_(b' (obsolete)'))
7053 if p.isunstable():
7060 if p.isunstable():
7054 instabilities = (
7061 instabilities = (
7055 ui.label(instability, b'trouble.%s' % instability)
7062 ui.label(instability, b'trouble.%s' % instability)
7056 for instability in p.instabilities()
7063 for instability in p.instabilities()
7057 )
7064 )
7058 ui.write(b' (' + b', '.join(instabilities) + b')')
7065 ui.write(b' (' + b', '.join(instabilities) + b')')
7059 ui.write(b'\n')
7066 ui.write(b'\n')
7060 if p.description():
7067 if p.description():
7061 ui.status(
7068 ui.status(
7062 b' ' + p.description().splitlines()[0].strip() + b'\n',
7069 b' ' + p.description().splitlines()[0].strip() + b'\n',
7063 label=b'log.summary',
7070 label=b'log.summary',
7064 )
7071 )
7065
7072
7066 branch = ctx.branch()
7073 branch = ctx.branch()
7067 bheads = repo.branchheads(branch)
7074 bheads = repo.branchheads(branch)
7068 # i18n: column positioning for "hg summary"
7075 # i18n: column positioning for "hg summary"
7069 m = _(b'branch: %s\n') % branch
7076 m = _(b'branch: %s\n') % branch
7070 if branch != b'default':
7077 if branch != b'default':
7071 ui.write(m, label=b'log.branch')
7078 ui.write(m, label=b'log.branch')
7072 else:
7079 else:
7073 ui.status(m, label=b'log.branch')
7080 ui.status(m, label=b'log.branch')
7074
7081
7075 if marks:
7082 if marks:
7076 active = repo._activebookmark
7083 active = repo._activebookmark
7077 # i18n: column positioning for "hg summary"
7084 # i18n: column positioning for "hg summary"
7078 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7085 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7079 if active is not None:
7086 if active is not None:
7080 if active in marks:
7087 if active in marks:
7081 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7088 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7082 marks.remove(active)
7089 marks.remove(active)
7083 else:
7090 else:
7084 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7091 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7085 for m in marks:
7092 for m in marks:
7086 ui.write(b' ' + m, label=b'log.bookmark')
7093 ui.write(b' ' + m, label=b'log.bookmark')
7087 ui.write(b'\n', label=b'log.bookmark')
7094 ui.write(b'\n', label=b'log.bookmark')
7088
7095
7089 status = repo.status(unknown=True)
7096 status = repo.status(unknown=True)
7090
7097
7091 c = repo.dirstate.copies()
7098 c = repo.dirstate.copies()
7092 copied, renamed = [], []
7099 copied, renamed = [], []
7093 for d, s in pycompat.iteritems(c):
7100 for d, s in pycompat.iteritems(c):
7094 if s in status.removed:
7101 if s in status.removed:
7095 status.removed.remove(s)
7102 status.removed.remove(s)
7096 renamed.append(d)
7103 renamed.append(d)
7097 else:
7104 else:
7098 copied.append(d)
7105 copied.append(d)
7099 if d in status.added:
7106 if d in status.added:
7100 status.added.remove(d)
7107 status.added.remove(d)
7101
7108
7102 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7109 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7103
7110
7104 labels = [
7111 labels = [
7105 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7112 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7106 (ui.label(_(b'%d added'), b'status.added'), status.added),
7113 (ui.label(_(b'%d added'), b'status.added'), status.added),
7107 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7114 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7108 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7115 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7109 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7116 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7110 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7117 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7111 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7118 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7112 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7119 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7113 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7120 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7114 ]
7121 ]
7115 t = []
7122 t = []
7116 for l, s in labels:
7123 for l, s in labels:
7117 if s:
7124 if s:
7118 t.append(l % len(s))
7125 t.append(l % len(s))
7119
7126
7120 t = b', '.join(t)
7127 t = b', '.join(t)
7121 cleanworkdir = False
7128 cleanworkdir = False
7122
7129
7123 if repo.vfs.exists(b'graftstate'):
7130 if repo.vfs.exists(b'graftstate'):
7124 t += _(b' (graft in progress)')
7131 t += _(b' (graft in progress)')
7125 if repo.vfs.exists(b'updatestate'):
7132 if repo.vfs.exists(b'updatestate'):
7126 t += _(b' (interrupted update)')
7133 t += _(b' (interrupted update)')
7127 elif len(parents) > 1:
7134 elif len(parents) > 1:
7128 t += _(b' (merge)')
7135 t += _(b' (merge)')
7129 elif branch != parents[0].branch():
7136 elif branch != parents[0].branch():
7130 t += _(b' (new branch)')
7137 t += _(b' (new branch)')
7131 elif parents[0].closesbranch() and pnode in repo.branchheads(
7138 elif parents[0].closesbranch() and pnode in repo.branchheads(
7132 branch, closed=True
7139 branch, closed=True
7133 ):
7140 ):
7134 t += _(b' (head closed)')
7141 t += _(b' (head closed)')
7135 elif not (
7142 elif not (
7136 status.modified
7143 status.modified
7137 or status.added
7144 or status.added
7138 or status.removed
7145 or status.removed
7139 or renamed
7146 or renamed
7140 or copied
7147 or copied
7141 or subs
7148 or subs
7142 ):
7149 ):
7143 t += _(b' (clean)')
7150 t += _(b' (clean)')
7144 cleanworkdir = True
7151 cleanworkdir = True
7145 elif pnode not in bheads:
7152 elif pnode not in bheads:
7146 t += _(b' (new branch head)')
7153 t += _(b' (new branch head)')
7147
7154
7148 if parents:
7155 if parents:
7149 pendingphase = max(p.phase() for p in parents)
7156 pendingphase = max(p.phase() for p in parents)
7150 else:
7157 else:
7151 pendingphase = phases.public
7158 pendingphase = phases.public
7152
7159
7153 if pendingphase > phases.newcommitphase(ui):
7160 if pendingphase > phases.newcommitphase(ui):
7154 t += b' (%s)' % phases.phasenames[pendingphase]
7161 t += b' (%s)' % phases.phasenames[pendingphase]
7155
7162
7156 if cleanworkdir:
7163 if cleanworkdir:
7157 # i18n: column positioning for "hg summary"
7164 # i18n: column positioning for "hg summary"
7158 ui.status(_(b'commit: %s\n') % t.strip())
7165 ui.status(_(b'commit: %s\n') % t.strip())
7159 else:
7166 else:
7160 # i18n: column positioning for "hg summary"
7167 # i18n: column positioning for "hg summary"
7161 ui.write(_(b'commit: %s\n') % t.strip())
7168 ui.write(_(b'commit: %s\n') % t.strip())
7162
7169
7163 # all ancestors of branch heads - all ancestors of parent = new csets
7170 # all ancestors of branch heads - all ancestors of parent = new csets
7164 new = len(
7171 new = len(
7165 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7172 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7166 )
7173 )
7167
7174
7168 if new == 0:
7175 if new == 0:
7169 # i18n: column positioning for "hg summary"
7176 # i18n: column positioning for "hg summary"
7170 ui.status(_(b'update: (current)\n'))
7177 ui.status(_(b'update: (current)\n'))
7171 elif pnode not in bheads:
7178 elif pnode not in bheads:
7172 # i18n: column positioning for "hg summary"
7179 # i18n: column positioning for "hg summary"
7173 ui.write(_(b'update: %d new changesets (update)\n') % new)
7180 ui.write(_(b'update: %d new changesets (update)\n') % new)
7174 else:
7181 else:
7175 # i18n: column positioning for "hg summary"
7182 # i18n: column positioning for "hg summary"
7176 ui.write(
7183 ui.write(
7177 _(b'update: %d new changesets, %d branch heads (merge)\n')
7184 _(b'update: %d new changesets, %d branch heads (merge)\n')
7178 % (new, len(bheads))
7185 % (new, len(bheads))
7179 )
7186 )
7180
7187
7181 t = []
7188 t = []
7182 draft = len(repo.revs(b'draft()'))
7189 draft = len(repo.revs(b'draft()'))
7183 if draft:
7190 if draft:
7184 t.append(_(b'%d draft') % draft)
7191 t.append(_(b'%d draft') % draft)
7185 secret = len(repo.revs(b'secret()'))
7192 secret = len(repo.revs(b'secret()'))
7186 if secret:
7193 if secret:
7187 t.append(_(b'%d secret') % secret)
7194 t.append(_(b'%d secret') % secret)
7188
7195
7189 if draft or secret:
7196 if draft or secret:
7190 ui.status(_(b'phases: %s\n') % b', '.join(t))
7197 ui.status(_(b'phases: %s\n') % b', '.join(t))
7191
7198
7192 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7199 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7193 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7200 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7194 numtrouble = len(repo.revs(trouble + b"()"))
7201 numtrouble = len(repo.revs(trouble + b"()"))
7195 # We write all the possibilities to ease translation
7202 # We write all the possibilities to ease translation
7196 troublemsg = {
7203 troublemsg = {
7197 b"orphan": _(b"orphan: %d changesets"),
7204 b"orphan": _(b"orphan: %d changesets"),
7198 b"contentdivergent": _(b"content-divergent: %d changesets"),
7205 b"contentdivergent": _(b"content-divergent: %d changesets"),
7199 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7206 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7200 }
7207 }
7201 if numtrouble > 0:
7208 if numtrouble > 0:
7202 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7209 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7203
7210
7204 cmdutil.summaryhooks(ui, repo)
7211 cmdutil.summaryhooks(ui, repo)
7205
7212
7206 if opts.get(b'remote'):
7213 if opts.get(b'remote'):
7207 needsincoming, needsoutgoing = True, True
7214 needsincoming, needsoutgoing = True, True
7208 else:
7215 else:
7209 needsincoming, needsoutgoing = False, False
7216 needsincoming, needsoutgoing = False, False
7210 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7217 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7211 if i:
7218 if i:
7212 needsincoming = True
7219 needsincoming = True
7213 if o:
7220 if o:
7214 needsoutgoing = True
7221 needsoutgoing = True
7215 if not needsincoming and not needsoutgoing:
7222 if not needsincoming and not needsoutgoing:
7216 return
7223 return
7217
7224
7218 def getincoming():
7225 def getincoming():
7219 # XXX We should actually skip this if no default is specified, instead
7226 # XXX We should actually skip this if no default is specified, instead
7220 # of passing "default" which will resolve as "./default/" if no default
7227 # of passing "default" which will resolve as "./default/" if no default
7221 # path is defined.
7228 # path is defined.
7222 source, branches = urlutil.get_unique_pull_path(
7229 source, branches = urlutil.get_unique_pull_path(
7223 b'summary', repo, ui, b'default'
7230 b'summary', repo, ui, b'default'
7224 )
7231 )
7225 sbranch = branches[0]
7232 sbranch = branches[0]
7226 try:
7233 try:
7227 other = hg.peer(repo, {}, source)
7234 other = hg.peer(repo, {}, source)
7228 except error.RepoError:
7235 except error.RepoError:
7229 if opts.get(b'remote'):
7236 if opts.get(b'remote'):
7230 raise
7237 raise
7231 return source, sbranch, None, None, None
7238 return source, sbranch, None, None, None
7232 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7239 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7233 if revs:
7240 if revs:
7234 revs = [other.lookup(rev) for rev in revs]
7241 revs = [other.lookup(rev) for rev in revs]
7235 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7242 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7236 with repo.ui.silent():
7243 with repo.ui.silent():
7237 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7244 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7238 return source, sbranch, other, commoninc, commoninc[1]
7245 return source, sbranch, other, commoninc, commoninc[1]
7239
7246
7240 if needsincoming:
7247 if needsincoming:
7241 source, sbranch, sother, commoninc, incoming = getincoming()
7248 source, sbranch, sother, commoninc, incoming = getincoming()
7242 else:
7249 else:
7243 source = sbranch = sother = commoninc = incoming = None
7250 source = sbranch = sother = commoninc = incoming = None
7244
7251
7245 def getoutgoing():
7252 def getoutgoing():
7246 # XXX We should actually skip this if no default is specified, instead
7253 # XXX We should actually skip this if no default is specified, instead
7247 # of passing "default" which will resolve as "./default/" if no default
7254 # of passing "default" which will resolve as "./default/" if no default
7248 # path is defined.
7255 # path is defined.
7249 d = None
7256 d = None
7250 if b'default-push' in ui.paths:
7257 if b'default-push' in ui.paths:
7251 d = b'default-push'
7258 d = b'default-push'
7252 elif b'default' in ui.paths:
7259 elif b'default' in ui.paths:
7253 d = b'default'
7260 d = b'default'
7254 if d is not None:
7261 if d is not None:
7255 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7262 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7256 dest = path.pushloc or path.loc
7263 dest = path.pushloc or path.loc
7257 dbranch = path.branch
7264 dbranch = path.branch
7258 else:
7265 else:
7259 dest = b'default'
7266 dest = b'default'
7260 dbranch = None
7267 dbranch = None
7261 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7268 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7262 if source != dest:
7269 if source != dest:
7263 try:
7270 try:
7264 dother = hg.peer(repo, {}, dest)
7271 dother = hg.peer(repo, {}, dest)
7265 except error.RepoError:
7272 except error.RepoError:
7266 if opts.get(b'remote'):
7273 if opts.get(b'remote'):
7267 raise
7274 raise
7268 return dest, dbranch, None, None
7275 return dest, dbranch, None, None
7269 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7276 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7270 elif sother is None:
7277 elif sother is None:
7271 # there is no explicit destination peer, but source one is invalid
7278 # there is no explicit destination peer, but source one is invalid
7272 return dest, dbranch, None, None
7279 return dest, dbranch, None, None
7273 else:
7280 else:
7274 dother = sother
7281 dother = sother
7275 if source != dest or (sbranch is not None and sbranch != dbranch):
7282 if source != dest or (sbranch is not None and sbranch != dbranch):
7276 common = None
7283 common = None
7277 else:
7284 else:
7278 common = commoninc
7285 common = commoninc
7279 if revs:
7286 if revs:
7280 revs = [repo.lookup(rev) for rev in revs]
7287 revs = [repo.lookup(rev) for rev in revs]
7281 with repo.ui.silent():
7288 with repo.ui.silent():
7282 outgoing = discovery.findcommonoutgoing(
7289 outgoing = discovery.findcommonoutgoing(
7283 repo, dother, onlyheads=revs, commoninc=common
7290 repo, dother, onlyheads=revs, commoninc=common
7284 )
7291 )
7285 return dest, dbranch, dother, outgoing
7292 return dest, dbranch, dother, outgoing
7286
7293
7287 if needsoutgoing:
7294 if needsoutgoing:
7288 dest, dbranch, dother, outgoing = getoutgoing()
7295 dest, dbranch, dother, outgoing = getoutgoing()
7289 else:
7296 else:
7290 dest = dbranch = dother = outgoing = None
7297 dest = dbranch = dother = outgoing = None
7291
7298
7292 if opts.get(b'remote'):
7299 if opts.get(b'remote'):
7293 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7300 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7294 # The former always sets `sother` (or raises an exception if it can't);
7301 # The former always sets `sother` (or raises an exception if it can't);
7295 # the latter always sets `outgoing`.
7302 # the latter always sets `outgoing`.
7296 assert sother is not None
7303 assert sother is not None
7297 assert outgoing is not None
7304 assert outgoing is not None
7298
7305
7299 t = []
7306 t = []
7300 if incoming:
7307 if incoming:
7301 t.append(_(b'1 or more incoming'))
7308 t.append(_(b'1 or more incoming'))
7302 o = outgoing.missing
7309 o = outgoing.missing
7303 if o:
7310 if o:
7304 t.append(_(b'%d outgoing') % len(o))
7311 t.append(_(b'%d outgoing') % len(o))
7305 other = dother or sother
7312 other = dother or sother
7306 if b'bookmarks' in other.listkeys(b'namespaces'):
7313 if b'bookmarks' in other.listkeys(b'namespaces'):
7307 counts = bookmarks.summary(repo, other)
7314 counts = bookmarks.summary(repo, other)
7308 if counts[0] > 0:
7315 if counts[0] > 0:
7309 t.append(_(b'%d incoming bookmarks') % counts[0])
7316 t.append(_(b'%d incoming bookmarks') % counts[0])
7310 if counts[1] > 0:
7317 if counts[1] > 0:
7311 t.append(_(b'%d outgoing bookmarks') % counts[1])
7318 t.append(_(b'%d outgoing bookmarks') % counts[1])
7312
7319
7313 if t:
7320 if t:
7314 # i18n: column positioning for "hg summary"
7321 # i18n: column positioning for "hg summary"
7315 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7322 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7316 else:
7323 else:
7317 # i18n: column positioning for "hg summary"
7324 # i18n: column positioning for "hg summary"
7318 ui.status(_(b'remote: (synced)\n'))
7325 ui.status(_(b'remote: (synced)\n'))
7319
7326
7320 cmdutil.summaryremotehooks(
7327 cmdutil.summaryremotehooks(
7321 ui,
7328 ui,
7322 repo,
7329 repo,
7323 opts,
7330 opts,
7324 (
7331 (
7325 (source, sbranch, sother, commoninc),
7332 (source, sbranch, sother, commoninc),
7326 (dest, dbranch, dother, outgoing),
7333 (dest, dbranch, dother, outgoing),
7327 ),
7334 ),
7328 )
7335 )
7329
7336
7330
7337
7331 @command(
7338 @command(
7332 b'tag',
7339 b'tag',
7333 [
7340 [
7334 (b'f', b'force', None, _(b'force tag')),
7341 (b'f', b'force', None, _(b'force tag')),
7335 (b'l', b'local', None, _(b'make the tag local')),
7342 (b'l', b'local', None, _(b'make the tag local')),
7336 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7343 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7337 (b'', b'remove', None, _(b'remove a tag')),
7344 (b'', b'remove', None, _(b'remove a tag')),
7338 # -l/--local is already there, commitopts cannot be used
7345 # -l/--local is already there, commitopts cannot be used
7339 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7346 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7340 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7347 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7341 ]
7348 ]
7342 + commitopts2,
7349 + commitopts2,
7343 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7350 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7344 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7351 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7345 )
7352 )
7346 def tag(ui, repo, name1, *names, **opts):
7353 def tag(ui, repo, name1, *names, **opts):
7347 """add one or more tags for the current or given revision
7354 """add one or more tags for the current or given revision
7348
7355
7349 Name a particular revision using <name>.
7356 Name a particular revision using <name>.
7350
7357
7351 Tags are used to name particular revisions of the repository and are
7358 Tags are used to name particular revisions of the repository and are
7352 very useful to compare different revisions, to go back to significant
7359 very useful to compare different revisions, to go back to significant
7353 earlier versions or to mark branch points as releases, etc. Changing
7360 earlier versions or to mark branch points as releases, etc. Changing
7354 an existing tag is normally disallowed; use -f/--force to override.
7361 an existing tag is normally disallowed; use -f/--force to override.
7355
7362
7356 If no revision is given, the parent of the working directory is
7363 If no revision is given, the parent of the working directory is
7357 used.
7364 used.
7358
7365
7359 To facilitate version control, distribution, and merging of tags,
7366 To facilitate version control, distribution, and merging of tags,
7360 they are stored as a file named ".hgtags" which is managed similarly
7367 they are stored as a file named ".hgtags" which is managed similarly
7361 to other project files and can be hand-edited if necessary. This
7368 to other project files and can be hand-edited if necessary. This
7362 also means that tagging creates a new commit. The file
7369 also means that tagging creates a new commit. The file
7363 ".hg/localtags" is used for local tags (not shared among
7370 ".hg/localtags" is used for local tags (not shared among
7364 repositories).
7371 repositories).
7365
7372
7366 Tag commits are usually made at the head of a branch. If the parent
7373 Tag commits are usually made at the head of a branch. If the parent
7367 of the working directory is not a branch head, :hg:`tag` aborts; use
7374 of the working directory is not a branch head, :hg:`tag` aborts; use
7368 -f/--force to force the tag commit to be based on a non-head
7375 -f/--force to force the tag commit to be based on a non-head
7369 changeset.
7376 changeset.
7370
7377
7371 See :hg:`help dates` for a list of formats valid for -d/--date.
7378 See :hg:`help dates` for a list of formats valid for -d/--date.
7372
7379
7373 Since tag names have priority over branch names during revision
7380 Since tag names have priority over branch names during revision
7374 lookup, using an existing branch name as a tag name is discouraged.
7381 lookup, using an existing branch name as a tag name is discouraged.
7375
7382
7376 Returns 0 on success.
7383 Returns 0 on success.
7377 """
7384 """
7378 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7385 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7379 opts = pycompat.byteskwargs(opts)
7386 opts = pycompat.byteskwargs(opts)
7380 with repo.wlock(), repo.lock():
7387 with repo.wlock(), repo.lock():
7381 rev_ = b"."
7388 rev_ = b"."
7382 names = [t.strip() for t in (name1,) + names]
7389 names = [t.strip() for t in (name1,) + names]
7383 if len(names) != len(set(names)):
7390 if len(names) != len(set(names)):
7384 raise error.InputError(_(b'tag names must be unique'))
7391 raise error.InputError(_(b'tag names must be unique'))
7385 for n in names:
7392 for n in names:
7386 scmutil.checknewlabel(repo, n, b'tag')
7393 scmutil.checknewlabel(repo, n, b'tag')
7387 if not n:
7394 if not n:
7388 raise error.InputError(
7395 raise error.InputError(
7389 _(b'tag names cannot consist entirely of whitespace')
7396 _(b'tag names cannot consist entirely of whitespace')
7390 )
7397 )
7391 if opts.get(b'rev'):
7398 if opts.get(b'rev'):
7392 rev_ = opts[b'rev']
7399 rev_ = opts[b'rev']
7393 message = opts.get(b'message')
7400 message = opts.get(b'message')
7394 if opts.get(b'remove'):
7401 if opts.get(b'remove'):
7395 if opts.get(b'local'):
7402 if opts.get(b'local'):
7396 expectedtype = b'local'
7403 expectedtype = b'local'
7397 else:
7404 else:
7398 expectedtype = b'global'
7405 expectedtype = b'global'
7399
7406
7400 for n in names:
7407 for n in names:
7401 if repo.tagtype(n) == b'global':
7408 if repo.tagtype(n) == b'global':
7402 alltags = tagsmod.findglobaltags(ui, repo)
7409 alltags = tagsmod.findglobaltags(ui, repo)
7403 if alltags[n][0] == repo.nullid:
7410 if alltags[n][0] == repo.nullid:
7404 raise error.InputError(
7411 raise error.InputError(
7405 _(b"tag '%s' is already removed") % n
7412 _(b"tag '%s' is already removed") % n
7406 )
7413 )
7407 if not repo.tagtype(n):
7414 if not repo.tagtype(n):
7408 raise error.InputError(_(b"tag '%s' does not exist") % n)
7415 raise error.InputError(_(b"tag '%s' does not exist") % n)
7409 if repo.tagtype(n) != expectedtype:
7416 if repo.tagtype(n) != expectedtype:
7410 if expectedtype == b'global':
7417 if expectedtype == b'global':
7411 raise error.InputError(
7418 raise error.InputError(
7412 _(b"tag '%s' is not a global tag") % n
7419 _(b"tag '%s' is not a global tag") % n
7413 )
7420 )
7414 else:
7421 else:
7415 raise error.InputError(
7422 raise error.InputError(
7416 _(b"tag '%s' is not a local tag") % n
7423 _(b"tag '%s' is not a local tag") % n
7417 )
7424 )
7418 rev_ = b'null'
7425 rev_ = b'null'
7419 if not message:
7426 if not message:
7420 # we don't translate commit messages
7427 # we don't translate commit messages
7421 message = b'Removed tag %s' % b', '.join(names)
7428 message = b'Removed tag %s' % b', '.join(names)
7422 elif not opts.get(b'force'):
7429 elif not opts.get(b'force'):
7423 for n in names:
7430 for n in names:
7424 if n in repo.tags():
7431 if n in repo.tags():
7425 raise error.InputError(
7432 raise error.InputError(
7426 _(b"tag '%s' already exists (use -f to force)") % n
7433 _(b"tag '%s' already exists (use -f to force)") % n
7427 )
7434 )
7428 if not opts.get(b'local'):
7435 if not opts.get(b'local'):
7429 p1, p2 = repo.dirstate.parents()
7436 p1, p2 = repo.dirstate.parents()
7430 if p2 != repo.nullid:
7437 if p2 != repo.nullid:
7431 raise error.StateError(_(b'uncommitted merge'))
7438 raise error.StateError(_(b'uncommitted merge'))
7432 bheads = repo.branchheads()
7439 bheads = repo.branchheads()
7433 if not opts.get(b'force') and bheads and p1 not in bheads:
7440 if not opts.get(b'force') and bheads and p1 not in bheads:
7434 raise error.InputError(
7441 raise error.InputError(
7435 _(
7442 _(
7436 b'working directory is not at a branch head '
7443 b'working directory is not at a branch head '
7437 b'(use -f to force)'
7444 b'(use -f to force)'
7438 )
7445 )
7439 )
7446 )
7440 node = logcmdutil.revsingle(repo, rev_).node()
7447 node = logcmdutil.revsingle(repo, rev_).node()
7441
7448
7442 if not message:
7449 if not message:
7443 # we don't translate commit messages
7450 # we don't translate commit messages
7444 message = b'Added tag %s for changeset %s' % (
7451 message = b'Added tag %s for changeset %s' % (
7445 b', '.join(names),
7452 b', '.join(names),
7446 short(node),
7453 short(node),
7447 )
7454 )
7448
7455
7449 date = opts.get(b'date')
7456 date = opts.get(b'date')
7450 if date:
7457 if date:
7451 date = dateutil.parsedate(date)
7458 date = dateutil.parsedate(date)
7452
7459
7453 if opts.get(b'remove'):
7460 if opts.get(b'remove'):
7454 editform = b'tag.remove'
7461 editform = b'tag.remove'
7455 else:
7462 else:
7456 editform = b'tag.add'
7463 editform = b'tag.add'
7457 editor = cmdutil.getcommiteditor(
7464 editor = cmdutil.getcommiteditor(
7458 editform=editform, **pycompat.strkwargs(opts)
7465 editform=editform, **pycompat.strkwargs(opts)
7459 )
7466 )
7460
7467
7461 # don't allow tagging the null rev
7468 # don't allow tagging the null rev
7462 if (
7469 if (
7463 not opts.get(b'remove')
7470 not opts.get(b'remove')
7464 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7471 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7465 ):
7472 ):
7466 raise error.InputError(_(b"cannot tag null revision"))
7473 raise error.InputError(_(b"cannot tag null revision"))
7467
7474
7468 tagsmod.tag(
7475 tagsmod.tag(
7469 repo,
7476 repo,
7470 names,
7477 names,
7471 node,
7478 node,
7472 message,
7479 message,
7473 opts.get(b'local'),
7480 opts.get(b'local'),
7474 opts.get(b'user'),
7481 opts.get(b'user'),
7475 date,
7482 date,
7476 editor=editor,
7483 editor=editor,
7477 )
7484 )
7478
7485
7479
7486
7480 @command(
7487 @command(
7481 b'tags',
7488 b'tags',
7482 formatteropts,
7489 formatteropts,
7483 b'',
7490 b'',
7484 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7491 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7485 intents={INTENT_READONLY},
7492 intents={INTENT_READONLY},
7486 )
7493 )
7487 def tags(ui, repo, **opts):
7494 def tags(ui, repo, **opts):
7488 """list repository tags
7495 """list repository tags
7489
7496
7490 This lists both regular and local tags. When the -v/--verbose
7497 This lists both regular and local tags. When the -v/--verbose
7491 switch is used, a third column "local" is printed for local tags.
7498 switch is used, a third column "local" is printed for local tags.
7492 When the -q/--quiet switch is used, only the tag name is printed.
7499 When the -q/--quiet switch is used, only the tag name is printed.
7493
7500
7494 .. container:: verbose
7501 .. container:: verbose
7495
7502
7496 Template:
7503 Template:
7497
7504
7498 The following keywords are supported in addition to the common template
7505 The following keywords are supported in addition to the common template
7499 keywords and functions such as ``{tag}``. See also
7506 keywords and functions such as ``{tag}``. See also
7500 :hg:`help templates`.
7507 :hg:`help templates`.
7501
7508
7502 :type: String. ``local`` for local tags.
7509 :type: String. ``local`` for local tags.
7503
7510
7504 Returns 0 on success.
7511 Returns 0 on success.
7505 """
7512 """
7506
7513
7507 opts = pycompat.byteskwargs(opts)
7514 opts = pycompat.byteskwargs(opts)
7508 ui.pager(b'tags')
7515 ui.pager(b'tags')
7509 fm = ui.formatter(b'tags', opts)
7516 fm = ui.formatter(b'tags', opts)
7510 hexfunc = fm.hexfunc
7517 hexfunc = fm.hexfunc
7511
7518
7512 for t, n in reversed(repo.tagslist()):
7519 for t, n in reversed(repo.tagslist()):
7513 hn = hexfunc(n)
7520 hn = hexfunc(n)
7514 label = b'tags.normal'
7521 label = b'tags.normal'
7515 tagtype = repo.tagtype(t)
7522 tagtype = repo.tagtype(t)
7516 if not tagtype or tagtype == b'global':
7523 if not tagtype or tagtype == b'global':
7517 tagtype = b''
7524 tagtype = b''
7518 else:
7525 else:
7519 label = b'tags.' + tagtype
7526 label = b'tags.' + tagtype
7520
7527
7521 fm.startitem()
7528 fm.startitem()
7522 fm.context(repo=repo)
7529 fm.context(repo=repo)
7523 fm.write(b'tag', b'%s', t, label=label)
7530 fm.write(b'tag', b'%s', t, label=label)
7524 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7531 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7525 fm.condwrite(
7532 fm.condwrite(
7526 not ui.quiet,
7533 not ui.quiet,
7527 b'rev node',
7534 b'rev node',
7528 fmt,
7535 fmt,
7529 repo.changelog.rev(n),
7536 repo.changelog.rev(n),
7530 hn,
7537 hn,
7531 label=label,
7538 label=label,
7532 )
7539 )
7533 fm.condwrite(
7540 fm.condwrite(
7534 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7541 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7535 )
7542 )
7536 fm.plain(b'\n')
7543 fm.plain(b'\n')
7537 fm.end()
7544 fm.end()
7538
7545
7539
7546
7540 @command(
7547 @command(
7541 b'tip',
7548 b'tip',
7542 [
7549 [
7543 (b'p', b'patch', None, _(b'show patch')),
7550 (b'p', b'patch', None, _(b'show patch')),
7544 (b'g', b'git', None, _(b'use git extended diff format')),
7551 (b'g', b'git', None, _(b'use git extended diff format')),
7545 ]
7552 ]
7546 + templateopts,
7553 + templateopts,
7547 _(b'[-p] [-g]'),
7554 _(b'[-p] [-g]'),
7548 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7555 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7549 )
7556 )
7550 def tip(ui, repo, **opts):
7557 def tip(ui, repo, **opts):
7551 """show the tip revision (DEPRECATED)
7558 """show the tip revision (DEPRECATED)
7552
7559
7553 The tip revision (usually just called the tip) is the changeset
7560 The tip revision (usually just called the tip) is the changeset
7554 most recently added to the repository (and therefore the most
7561 most recently added to the repository (and therefore the most
7555 recently changed head).
7562 recently changed head).
7556
7563
7557 If you have just made a commit, that commit will be the tip. If
7564 If you have just made a commit, that commit will be the tip. If
7558 you have just pulled changes from another repository, the tip of
7565 you have just pulled changes from another repository, the tip of
7559 that repository becomes the current tip. The "tip" tag is special
7566 that repository becomes the current tip. The "tip" tag is special
7560 and cannot be renamed or assigned to a different changeset.
7567 and cannot be renamed or assigned to a different changeset.
7561
7568
7562 This command is deprecated, please use :hg:`heads` instead.
7569 This command is deprecated, please use :hg:`heads` instead.
7563
7570
7564 Returns 0 on success.
7571 Returns 0 on success.
7565 """
7572 """
7566 opts = pycompat.byteskwargs(opts)
7573 opts = pycompat.byteskwargs(opts)
7567 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7574 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7568 displayer.show(repo[b'tip'])
7575 displayer.show(repo[b'tip'])
7569 displayer.close()
7576 displayer.close()
7570
7577
7571
7578
7572 @command(
7579 @command(
7573 b'unbundle',
7580 b'unbundle',
7574 [
7581 [
7575 (
7582 (
7576 b'u',
7583 b'u',
7577 b'update',
7584 b'update',
7578 None,
7585 None,
7579 _(b'update to new branch head if changesets were unbundled'),
7586 _(b'update to new branch head if changesets were unbundled'),
7580 )
7587 )
7581 ],
7588 ],
7582 _(b'[-u] FILE...'),
7589 _(b'[-u] FILE...'),
7583 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7590 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7584 )
7591 )
7585 def unbundle(ui, repo, fname1, *fnames, **opts):
7592 def unbundle(ui, repo, fname1, *fnames, **opts):
7586 """apply one or more bundle files
7593 """apply one or more bundle files
7587
7594
7588 Apply one or more bundle files generated by :hg:`bundle`.
7595 Apply one or more bundle files generated by :hg:`bundle`.
7589
7596
7590 Returns 0 on success, 1 if an update has unresolved files.
7597 Returns 0 on success, 1 if an update has unresolved files.
7591 """
7598 """
7592 fnames = (fname1,) + fnames
7599 fnames = (fname1,) + fnames
7593
7600
7594 with repo.lock():
7601 with repo.lock():
7595 for fname in fnames:
7602 for fname in fnames:
7596 f = hg.openpath(ui, fname)
7603 f = hg.openpath(ui, fname)
7597 gen = exchange.readbundle(ui, f, fname)
7604 gen = exchange.readbundle(ui, f, fname)
7598 if isinstance(gen, streamclone.streamcloneapplier):
7605 if isinstance(gen, streamclone.streamcloneapplier):
7599 raise error.InputError(
7606 raise error.InputError(
7600 _(
7607 _(
7601 b'packed bundles cannot be applied with '
7608 b'packed bundles cannot be applied with '
7602 b'"hg unbundle"'
7609 b'"hg unbundle"'
7603 ),
7610 ),
7604 hint=_(b'use "hg debugapplystreamclonebundle"'),
7611 hint=_(b'use "hg debugapplystreamclonebundle"'),
7605 )
7612 )
7606 url = b'bundle:' + fname
7613 url = b'bundle:' + fname
7607 try:
7614 try:
7608 txnname = b'unbundle'
7615 txnname = b'unbundle'
7609 if not isinstance(gen, bundle2.unbundle20):
7616 if not isinstance(gen, bundle2.unbundle20):
7610 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7617 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7611 with repo.transaction(txnname) as tr:
7618 with repo.transaction(txnname) as tr:
7612 op = bundle2.applybundle(
7619 op = bundle2.applybundle(
7613 repo, gen, tr, source=b'unbundle', url=url
7620 repo, gen, tr, source=b'unbundle', url=url
7614 )
7621 )
7615 except error.BundleUnknownFeatureError as exc:
7622 except error.BundleUnknownFeatureError as exc:
7616 raise error.Abort(
7623 raise error.Abort(
7617 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7624 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7618 hint=_(
7625 hint=_(
7619 b"see https://mercurial-scm.org/"
7626 b"see https://mercurial-scm.org/"
7620 b"wiki/BundleFeature for more "
7627 b"wiki/BundleFeature for more "
7621 b"information"
7628 b"information"
7622 ),
7629 ),
7623 )
7630 )
7624 modheads = bundle2.combinechangegroupresults(op)
7631 modheads = bundle2.combinechangegroupresults(op)
7625
7632
7626 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7633 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7627 return 1
7634 return 1
7628 else:
7635 else:
7629 return 0
7636 return 0
7630
7637
7631
7638
7632 @command(
7639 @command(
7633 b'unshelve',
7640 b'unshelve',
7634 [
7641 [
7635 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7642 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7636 (
7643 (
7637 b'c',
7644 b'c',
7638 b'continue',
7645 b'continue',
7639 None,
7646 None,
7640 _(b'continue an incomplete unshelve operation'),
7647 _(b'continue an incomplete unshelve operation'),
7641 ),
7648 ),
7642 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7649 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7643 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7650 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7644 (
7651 (
7645 b'n',
7652 b'n',
7646 b'name',
7653 b'name',
7647 b'',
7654 b'',
7648 _(b'restore shelved change with given name'),
7655 _(b'restore shelved change with given name'),
7649 _(b'NAME'),
7656 _(b'NAME'),
7650 ),
7657 ),
7651 (b't', b'tool', b'', _(b'specify merge tool')),
7658 (b't', b'tool', b'', _(b'specify merge tool')),
7652 (
7659 (
7653 b'',
7660 b'',
7654 b'date',
7661 b'date',
7655 b'',
7662 b'',
7656 _(b'set date for temporary commits (DEPRECATED)'),
7663 _(b'set date for temporary commits (DEPRECATED)'),
7657 _(b'DATE'),
7664 _(b'DATE'),
7658 ),
7665 ),
7659 ],
7666 ],
7660 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7667 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7661 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7668 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7662 )
7669 )
7663 def unshelve(ui, repo, *shelved, **opts):
7670 def unshelve(ui, repo, *shelved, **opts):
7664 """restore a shelved change to the working directory
7671 """restore a shelved change to the working directory
7665
7672
7666 This command accepts an optional name of a shelved change to
7673 This command accepts an optional name of a shelved change to
7667 restore. If none is given, the most recent shelved change is used.
7674 restore. If none is given, the most recent shelved change is used.
7668
7675
7669 If a shelved change is applied successfully, the bundle that
7676 If a shelved change is applied successfully, the bundle that
7670 contains the shelved changes is moved to a backup location
7677 contains the shelved changes is moved to a backup location
7671 (.hg/shelve-backup).
7678 (.hg/shelve-backup).
7672
7679
7673 Since you can restore a shelved change on top of an arbitrary
7680 Since you can restore a shelved change on top of an arbitrary
7674 commit, it is possible that unshelving will result in a conflict
7681 commit, it is possible that unshelving will result in a conflict
7675 between your changes and the commits you are unshelving onto. If
7682 between your changes and the commits you are unshelving onto. If
7676 this occurs, you must resolve the conflict, then use
7683 this occurs, you must resolve the conflict, then use
7677 ``--continue`` to complete the unshelve operation. (The bundle
7684 ``--continue`` to complete the unshelve operation. (The bundle
7678 will not be moved until you successfully complete the unshelve.)
7685 will not be moved until you successfully complete the unshelve.)
7679
7686
7680 (Alternatively, you can use ``--abort`` to abandon an unshelve
7687 (Alternatively, you can use ``--abort`` to abandon an unshelve
7681 that causes a conflict. This reverts the unshelved changes, and
7688 that causes a conflict. This reverts the unshelved changes, and
7682 leaves the bundle in place.)
7689 leaves the bundle in place.)
7683
7690
7684 If bare shelved change (without interactive, include and exclude
7691 If bare shelved change (without interactive, include and exclude
7685 option) was done on newly created branch it would restore branch
7692 option) was done on newly created branch it would restore branch
7686 information to the working directory.
7693 information to the working directory.
7687
7694
7688 After a successful unshelve, the shelved changes are stored in a
7695 After a successful unshelve, the shelved changes are stored in a
7689 backup directory. Only the N most recent backups are kept. N
7696 backup directory. Only the N most recent backups are kept. N
7690 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7697 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7691 configuration option.
7698 configuration option.
7692
7699
7693 .. container:: verbose
7700 .. container:: verbose
7694
7701
7695 Timestamp in seconds is used to decide order of backups. More
7702 Timestamp in seconds is used to decide order of backups. More
7696 than ``maxbackups`` backups are kept, if same timestamp
7703 than ``maxbackups`` backups are kept, if same timestamp
7697 prevents from deciding exact order of them, for safety.
7704 prevents from deciding exact order of them, for safety.
7698
7705
7699 Selected changes can be unshelved with ``--interactive`` flag.
7706 Selected changes can be unshelved with ``--interactive`` flag.
7700 The working directory is updated with the selected changes, and
7707 The working directory is updated with the selected changes, and
7701 only the unselected changes remain shelved.
7708 only the unselected changes remain shelved.
7702 Note: The whole shelve is applied to working directory first before
7709 Note: The whole shelve is applied to working directory first before
7703 running interactively. So, this will bring up all the conflicts between
7710 running interactively. So, this will bring up all the conflicts between
7704 working directory and the shelve, irrespective of which changes will be
7711 working directory and the shelve, irrespective of which changes will be
7705 unshelved.
7712 unshelved.
7706 """
7713 """
7707 with repo.wlock():
7714 with repo.wlock():
7708 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7715 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7709
7716
7710
7717
7711 statemod.addunfinished(
7718 statemod.addunfinished(
7712 b'unshelve',
7719 b'unshelve',
7713 fname=b'shelvedstate',
7720 fname=b'shelvedstate',
7714 continueflag=True,
7721 continueflag=True,
7715 abortfunc=shelvemod.hgabortunshelve,
7722 abortfunc=shelvemod.hgabortunshelve,
7716 continuefunc=shelvemod.hgcontinueunshelve,
7723 continuefunc=shelvemod.hgcontinueunshelve,
7717 cmdmsg=_(b'unshelve already in progress'),
7724 cmdmsg=_(b'unshelve already in progress'),
7718 )
7725 )
7719
7726
7720
7727
7721 @command(
7728 @command(
7722 b'update|up|checkout|co',
7729 b'update|up|checkout|co',
7723 [
7730 [
7724 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7731 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7725 (b'c', b'check', None, _(b'require clean working directory')),
7732 (b'c', b'check', None, _(b'require clean working directory')),
7726 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7733 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7727 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7734 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7728 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7735 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7729 ]
7736 ]
7730 + mergetoolopts,
7737 + mergetoolopts,
7731 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7738 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7732 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7739 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7733 helpbasic=True,
7740 helpbasic=True,
7734 )
7741 )
7735 def update(ui, repo, node=None, **opts):
7742 def update(ui, repo, node=None, **opts):
7736 """update working directory (or switch revisions)
7743 """update working directory (or switch revisions)
7737
7744
7738 Update the repository's working directory to the specified
7745 Update the repository's working directory to the specified
7739 changeset. If no changeset is specified, update to the tip of the
7746 changeset. If no changeset is specified, update to the tip of the
7740 current named branch and move the active bookmark (see :hg:`help
7747 current named branch and move the active bookmark (see :hg:`help
7741 bookmarks`).
7748 bookmarks`).
7742
7749
7743 Update sets the working directory's parent revision to the specified
7750 Update sets the working directory's parent revision to the specified
7744 changeset (see :hg:`help parents`).
7751 changeset (see :hg:`help parents`).
7745
7752
7746 If the changeset is not a descendant or ancestor of the working
7753 If the changeset is not a descendant or ancestor of the working
7747 directory's parent and there are uncommitted changes, the update is
7754 directory's parent and there are uncommitted changes, the update is
7748 aborted. With the -c/--check option, the working directory is checked
7755 aborted. With the -c/--check option, the working directory is checked
7749 for uncommitted changes; if none are found, the working directory is
7756 for uncommitted changes; if none are found, the working directory is
7750 updated to the specified changeset.
7757 updated to the specified changeset.
7751
7758
7752 .. container:: verbose
7759 .. container:: verbose
7753
7760
7754 The -C/--clean, -c/--check, and -m/--merge options control what
7761 The -C/--clean, -c/--check, and -m/--merge options control what
7755 happens if the working directory contains uncommitted changes.
7762 happens if the working directory contains uncommitted changes.
7756 At most of one of them can be specified.
7763 At most of one of them can be specified.
7757
7764
7758 1. If no option is specified, and if
7765 1. If no option is specified, and if
7759 the requested changeset is an ancestor or descendant of
7766 the requested changeset is an ancestor or descendant of
7760 the working directory's parent, the uncommitted changes
7767 the working directory's parent, the uncommitted changes
7761 are merged into the requested changeset and the merged
7768 are merged into the requested changeset and the merged
7762 result is left uncommitted. If the requested changeset is
7769 result is left uncommitted. If the requested changeset is
7763 not an ancestor or descendant (that is, it is on another
7770 not an ancestor or descendant (that is, it is on another
7764 branch), the update is aborted and the uncommitted changes
7771 branch), the update is aborted and the uncommitted changes
7765 are preserved.
7772 are preserved.
7766
7773
7767 2. With the -m/--merge option, the update is allowed even if the
7774 2. With the -m/--merge option, the update is allowed even if the
7768 requested changeset is not an ancestor or descendant of
7775 requested changeset is not an ancestor or descendant of
7769 the working directory's parent.
7776 the working directory's parent.
7770
7777
7771 3. With the -c/--check option, the update is aborted and the
7778 3. With the -c/--check option, the update is aborted and the
7772 uncommitted changes are preserved.
7779 uncommitted changes are preserved.
7773
7780
7774 4. With the -C/--clean option, uncommitted changes are discarded and
7781 4. With the -C/--clean option, uncommitted changes are discarded and
7775 the working directory is updated to the requested changeset.
7782 the working directory is updated to the requested changeset.
7776
7783
7777 To cancel an uncommitted merge (and lose your changes), use
7784 To cancel an uncommitted merge (and lose your changes), use
7778 :hg:`merge --abort`.
7785 :hg:`merge --abort`.
7779
7786
7780 Use null as the changeset to remove the working directory (like
7787 Use null as the changeset to remove the working directory (like
7781 :hg:`clone -U`).
7788 :hg:`clone -U`).
7782
7789
7783 If you want to revert just one file to an older revision, use
7790 If you want to revert just one file to an older revision, use
7784 :hg:`revert [-r REV] NAME`.
7791 :hg:`revert [-r REV] NAME`.
7785
7792
7786 See :hg:`help dates` for a list of formats valid for -d/--date.
7793 See :hg:`help dates` for a list of formats valid for -d/--date.
7787
7794
7788 Returns 0 on success, 1 if there are unresolved files.
7795 Returns 0 on success, 1 if there are unresolved files.
7789 """
7796 """
7790 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7797 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7791 rev = opts.get('rev')
7798 rev = opts.get('rev')
7792 date = opts.get('date')
7799 date = opts.get('date')
7793 clean = opts.get('clean')
7800 clean = opts.get('clean')
7794 check = opts.get('check')
7801 check = opts.get('check')
7795 merge = opts.get('merge')
7802 merge = opts.get('merge')
7796 if rev and node:
7803 if rev and node:
7797 raise error.InputError(_(b"please specify just one revision"))
7804 raise error.InputError(_(b"please specify just one revision"))
7798
7805
7799 if ui.configbool(b'commands', b'update.requiredest'):
7806 if ui.configbool(b'commands', b'update.requiredest'):
7800 if not node and not rev and not date:
7807 if not node and not rev and not date:
7801 raise error.InputError(
7808 raise error.InputError(
7802 _(b'you must specify a destination'),
7809 _(b'you must specify a destination'),
7803 hint=_(b'for example: hg update ".::"'),
7810 hint=_(b'for example: hg update ".::"'),
7804 )
7811 )
7805
7812
7806 if rev is None or rev == b'':
7813 if rev is None or rev == b'':
7807 rev = node
7814 rev = node
7808
7815
7809 if date and rev is not None:
7816 if date and rev is not None:
7810 raise error.InputError(_(b"you can't specify a revision and a date"))
7817 raise error.InputError(_(b"you can't specify a revision and a date"))
7811
7818
7812 updatecheck = None
7819 updatecheck = None
7813 if check or merge is not None and not merge:
7820 if check or merge is not None and not merge:
7814 updatecheck = b'abort'
7821 updatecheck = b'abort'
7815 elif merge or check is not None and not check:
7822 elif merge or check is not None and not check:
7816 updatecheck = b'none'
7823 updatecheck = b'none'
7817
7824
7818 with repo.wlock():
7825 with repo.wlock():
7819 cmdutil.clearunfinished(repo)
7826 cmdutil.clearunfinished(repo)
7820 if date:
7827 if date:
7821 rev = cmdutil.finddate(ui, repo, date)
7828 rev = cmdutil.finddate(ui, repo, date)
7822
7829
7823 # if we defined a bookmark, we have to remember the original name
7830 # if we defined a bookmark, we have to remember the original name
7824 brev = rev
7831 brev = rev
7825 if rev:
7832 if rev:
7826 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7833 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7827 ctx = logcmdutil.revsingle(repo, rev, default=None)
7834 ctx = logcmdutil.revsingle(repo, rev, default=None)
7828 rev = ctx.rev()
7835 rev = ctx.rev()
7829 hidden = ctx.hidden()
7836 hidden = ctx.hidden()
7830 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7837 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7831 with ui.configoverride(overrides, b'update'):
7838 with ui.configoverride(overrides, b'update'):
7832 ret = hg.updatetotally(
7839 ret = hg.updatetotally(
7833 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7840 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7834 )
7841 )
7835 if hidden:
7842 if hidden:
7836 ctxstr = ctx.hex()[:12]
7843 ctxstr = ctx.hex()[:12]
7837 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7844 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7838
7845
7839 if ctx.obsolete():
7846 if ctx.obsolete():
7840 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7847 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7841 ui.warn(b"(%s)\n" % obsfatemsg)
7848 ui.warn(b"(%s)\n" % obsfatemsg)
7842 return ret
7849 return ret
7843
7850
7844
7851
7845 @command(
7852 @command(
7846 b'verify',
7853 b'verify',
7847 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7854 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7848 helpcategory=command.CATEGORY_MAINTENANCE,
7855 helpcategory=command.CATEGORY_MAINTENANCE,
7849 )
7856 )
7850 def verify(ui, repo, **opts):
7857 def verify(ui, repo, **opts):
7851 """verify the integrity of the repository
7858 """verify the integrity of the repository
7852
7859
7853 Verify the integrity of the current repository.
7860 Verify the integrity of the current repository.
7854
7861
7855 This will perform an extensive check of the repository's
7862 This will perform an extensive check of the repository's
7856 integrity, validating the hashes and checksums of each entry in
7863 integrity, validating the hashes and checksums of each entry in
7857 the changelog, manifest, and tracked files, as well as the
7864 the changelog, manifest, and tracked files, as well as the
7858 integrity of their crosslinks and indices.
7865 integrity of their crosslinks and indices.
7859
7866
7860 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7867 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7861 for more information about recovery from corruption of the
7868 for more information about recovery from corruption of the
7862 repository.
7869 repository.
7863
7870
7864 Returns 0 on success, 1 if errors are encountered.
7871 Returns 0 on success, 1 if errors are encountered.
7865 """
7872 """
7866 opts = pycompat.byteskwargs(opts)
7873 opts = pycompat.byteskwargs(opts)
7867
7874
7868 level = None
7875 level = None
7869 if opts[b'full']:
7876 if opts[b'full']:
7870 level = verifymod.VERIFY_FULL
7877 level = verifymod.VERIFY_FULL
7871 return hg.verify(repo, level)
7878 return hg.verify(repo, level)
7872
7879
7873
7880
7874 @command(
7881 @command(
7875 b'version',
7882 b'version',
7876 [] + formatteropts,
7883 [] + formatteropts,
7877 helpcategory=command.CATEGORY_HELP,
7884 helpcategory=command.CATEGORY_HELP,
7878 norepo=True,
7885 norepo=True,
7879 intents={INTENT_READONLY},
7886 intents={INTENT_READONLY},
7880 )
7887 )
7881 def version_(ui, **opts):
7888 def version_(ui, **opts):
7882 """output version and copyright information
7889 """output version and copyright information
7883
7890
7884 .. container:: verbose
7891 .. container:: verbose
7885
7892
7886 Template:
7893 Template:
7887
7894
7888 The following keywords are supported. See also :hg:`help templates`.
7895 The following keywords are supported. See also :hg:`help templates`.
7889
7896
7890 :extensions: List of extensions.
7897 :extensions: List of extensions.
7891 :ver: String. Version number.
7898 :ver: String. Version number.
7892
7899
7893 And each entry of ``{extensions}`` provides the following sub-keywords
7900 And each entry of ``{extensions}`` provides the following sub-keywords
7894 in addition to ``{ver}``.
7901 in addition to ``{ver}``.
7895
7902
7896 :bundled: Boolean. True if included in the release.
7903 :bundled: Boolean. True if included in the release.
7897 :name: String. Extension name.
7904 :name: String. Extension name.
7898 """
7905 """
7899 opts = pycompat.byteskwargs(opts)
7906 opts = pycompat.byteskwargs(opts)
7900 if ui.verbose:
7907 if ui.verbose:
7901 ui.pager(b'version')
7908 ui.pager(b'version')
7902 fm = ui.formatter(b"version", opts)
7909 fm = ui.formatter(b"version", opts)
7903 fm.startitem()
7910 fm.startitem()
7904 fm.write(
7911 fm.write(
7905 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7912 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7906 )
7913 )
7907 license = _(
7914 license = _(
7908 b"(see https://mercurial-scm.org for more information)\n"
7915 b"(see https://mercurial-scm.org for more information)\n"
7909 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7916 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7910 b"This is free software; see the source for copying conditions. "
7917 b"This is free software; see the source for copying conditions. "
7911 b"There is NO\nwarranty; "
7918 b"There is NO\nwarranty; "
7912 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7919 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7913 )
7920 )
7914 if not ui.quiet:
7921 if not ui.quiet:
7915 fm.plain(license)
7922 fm.plain(license)
7916
7923
7917 if ui.verbose:
7924 if ui.verbose:
7918 fm.plain(_(b"\nEnabled extensions:\n\n"))
7925 fm.plain(_(b"\nEnabled extensions:\n\n"))
7919 # format names and versions into columns
7926 # format names and versions into columns
7920 names = []
7927 names = []
7921 vers = []
7928 vers = []
7922 isinternals = []
7929 isinternals = []
7923 for name, module in sorted(extensions.extensions()):
7930 for name, module in sorted(extensions.extensions()):
7924 names.append(name)
7931 names.append(name)
7925 vers.append(extensions.moduleversion(module) or None)
7932 vers.append(extensions.moduleversion(module) or None)
7926 isinternals.append(extensions.ismoduleinternal(module))
7933 isinternals.append(extensions.ismoduleinternal(module))
7927 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7934 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7928 if names:
7935 if names:
7929 namefmt = b" %%-%ds " % max(len(n) for n in names)
7936 namefmt = b" %%-%ds " % max(len(n) for n in names)
7930 places = [_(b"external"), _(b"internal")]
7937 places = [_(b"external"), _(b"internal")]
7931 for n, v, p in zip(names, vers, isinternals):
7938 for n, v, p in zip(names, vers, isinternals):
7932 fn.startitem()
7939 fn.startitem()
7933 fn.condwrite(ui.verbose, b"name", namefmt, n)
7940 fn.condwrite(ui.verbose, b"name", namefmt, n)
7934 if ui.verbose:
7941 if ui.verbose:
7935 fn.plain(b"%s " % places[p])
7942 fn.plain(b"%s " % places[p])
7936 fn.data(bundled=p)
7943 fn.data(bundled=p)
7937 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7944 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7938 if ui.verbose:
7945 if ui.verbose:
7939 fn.plain(b"\n")
7946 fn.plain(b"\n")
7940 fn.end()
7947 fn.end()
7941 fm.end()
7948 fm.end()
7942
7949
7943
7950
7944 def loadcmdtable(ui, name, cmdtable):
7951 def loadcmdtable(ui, name, cmdtable):
7945 """Load command functions from specified cmdtable"""
7952 """Load command functions from specified cmdtable"""
7946 overrides = [cmd for cmd in cmdtable if cmd in table]
7953 overrides = [cmd for cmd in cmdtable if cmd in table]
7947 if overrides:
7954 if overrides:
7948 ui.warn(
7955 ui.warn(
7949 _(b"extension '%s' overrides commands: %s\n")
7956 _(b"extension '%s' overrides commands: %s\n")
7950 % (name, b" ".join(overrides))
7957 % (name, b" ".join(overrides))
7951 )
7958 )
7952 table.update(cmdtable)
7959 table.update(cmdtable)
@@ -1,1340 +1,1353 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
6
7 Basic test
7 Basic test
8 $ echo 'root' >root
8 $ echo 'root' >root
9 $ hg add root
9 $ hg add root
10 $ hg commit -d '0 0' -m "Adding root node"
10 $ hg commit -d '0 0' -m "Adding root node"
11
11
12 $ echo 'a' >a
12 $ echo 'a' >a
13 $ hg add a
13 $ hg add a
14 $ hg branch a
14 $ hg branch a
15 marked working directory as branch a
15 marked working directory as branch a
16 (branches are permanent and global, did you want a bookmark?)
16 (branches are permanent and global, did you want a bookmark?)
17 $ hg commit -d '1 0' -m "Adding a branch"
17 $ hg commit -d '1 0' -m "Adding a branch"
18
18
19 $ hg branch q
19 $ hg branch q
20 marked working directory as branch q
20 marked working directory as branch q
21 $ echo 'aa' >a
21 $ echo 'aa' >a
22 $ hg branch -C
22 $ hg branch -C
23 reset working directory to branch a
23 reset working directory to branch a
24 $ hg commit -d '2 0' -m "Adding to a branch"
24 $ hg commit -d '2 0' -m "Adding to a branch"
25
25
26 $ hg update -C 0
26 $ hg update -C 0
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 $ echo 'b' >b
28 $ echo 'b' >b
29 $ hg add b
29 $ hg add b
30 $ hg branch b
30 $ hg branch b
31 marked working directory as branch b
31 marked working directory as branch b
32 $ hg commit -d '2 0' -m "Adding b branch"
32 $ hg commit -d '2 0' -m "Adding b branch"
33
33
34 $ echo 'bh1' >bh1
34 $ echo 'bh1' >bh1
35 $ hg add bh1
35 $ hg add bh1
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
37
37
38 $ hg update -C 2
38 $ hg update -C 2
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
40 $ echo 'bh2' >bh2
40 $ echo 'bh2' >bh2
41 $ hg add bh2
41 $ hg add bh2
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
43
43
44 $ echo 'c' >c
44 $ echo 'c' >c
45 $ hg add c
45 $ hg add c
46 $ hg branch c
46 $ hg branch c
47 marked working directory as branch c
47 marked working directory as branch c
48 $ hg commit -d '5 0' -m "Adding c branch"
48 $ hg commit -d '5 0' -m "Adding c branch"
49
49
50 reserved names
50 reserved names
51
51
52 $ hg branch tip
52 $ hg branch tip
53 abort: the name 'tip' is reserved
53 abort: the name 'tip' is reserved
54 [10]
54 [10]
55 $ hg branch null
55 $ hg branch null
56 abort: the name 'null' is reserved
56 abort: the name 'null' is reserved
57 [10]
57 [10]
58 $ hg branch .
58 $ hg branch .
59 abort: the name '.' is reserved
59 abort: the name '.' is reserved
60 [10]
60 [10]
61
61
62 invalid characters
62 invalid characters
63
63
64 $ hg branch 'foo:bar'
64 $ hg branch 'foo:bar'
65 abort: ':' cannot be used in a name
65 abort: ':' cannot be used in a name
66 [10]
66 [10]
67
67
68 $ hg branch 'foo
68 $ hg branch 'foo
69 > bar'
69 > bar'
70 abort: '\n' cannot be used in a name
70 abort: '\n' cannot be used in a name
71 [10]
71 [10]
72
72
73 trailing or leading spaces should be stripped before testing duplicates
73 trailing or leading spaces should be stripped before testing duplicates
74
74
75 $ hg branch 'b '
75 $ hg branch 'b '
76 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
78 [10]
78 [10]
79
79
80 $ hg branch ' b'
80 $ hg branch ' b'
81 abort: a branch of the same name already exists
81 abort: a branch of the same name already exists
82 (use 'hg update' to switch to it)
82 (use 'hg update' to switch to it)
83 [10]
83 [10]
84
84
85 verify update will accept invalid legacy branch names
85 verify update will accept invalid legacy branch names
86
86
87 $ hg init test-invalid-branch-name
87 $ hg init test-invalid-branch-name
88 $ cd test-invalid-branch-name
88 $ cd test-invalid-branch-name
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 3 changesets with 3 changes to 2 files
93 added 3 changesets with 3 changes to 2 files
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96
96
97 $ hg update '"colon:test"'
97 $ hg update '"colon:test"'
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 $ cd ..
99 $ cd ..
100
100
101 $ echo 'd' >d
101 $ echo 'd' >d
102 $ hg add d
102 $ hg add d
103 $ hg branch 'a branch name much longer than the default justification used by branches'
103 $ hg branch 'a branch name much longer than the default justification used by branches'
104 marked working directory as branch a branch name much longer than the default justification used by branches
104 marked working directory as branch a branch name much longer than the default justification used by branches
105 $ hg commit -d '6 0' -m "Adding d branch"
105 $ hg commit -d '6 0' -m "Adding d branch"
106
106
107 $ hg branches
107 $ hg branches
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
109 b 4:aee39cd168d0
109 b 4:aee39cd168d0
110 c 6:589736a22561 (inactive)
110 c 6:589736a22561 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
112 default 0:19709c5a4e75 (inactive)
112 default 0:19709c5a4e75 (inactive)
113
113
114 -------
114 -------
115
115
116 $ hg branches -a
116 $ hg branches -a
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 b 4:aee39cd168d0
118 b 4:aee39cd168d0
119
119
120 --- Branch a
120 --- Branch a
121
121
122 $ hg log -b a
122 $ hg log -b a
123 changeset: 5:d8cbc61dbaa6
123 changeset: 5:d8cbc61dbaa6
124 branch: a
124 branch: a
125 parent: 2:881fe2b92ad0
125 parent: 2:881fe2b92ad0
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:04 1970 +0000
127 date: Thu Jan 01 00:00:04 1970 +0000
128 summary: Adding b branch head 2
128 summary: Adding b branch head 2
129
129
130 changeset: 2:881fe2b92ad0
130 changeset: 2:881fe2b92ad0
131 branch: a
131 branch: a
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:02 1970 +0000
133 date: Thu Jan 01 00:00:02 1970 +0000
134 summary: Adding to a branch
134 summary: Adding to a branch
135
135
136 changeset: 1:dd6b440dd85a
136 changeset: 1:dd6b440dd85a
137 branch: a
137 branch: a
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:01 1970 +0000
139 date: Thu Jan 01 00:00:01 1970 +0000
140 summary: Adding a branch
140 summary: Adding a branch
141
141
142
142
143 ---- Branch b
143 ---- Branch b
144
144
145 $ hg log -b b
145 $ hg log -b b
146 changeset: 4:aee39cd168d0
146 changeset: 4:aee39cd168d0
147 branch: b
147 branch: b
148 user: test
148 user: test
149 date: Thu Jan 01 00:00:03 1970 +0000
149 date: Thu Jan 01 00:00:03 1970 +0000
150 summary: Adding b branch head 1
150 summary: Adding b branch head 1
151
151
152 changeset: 3:ac22033332d1
152 changeset: 3:ac22033332d1
153 branch: b
153 branch: b
154 parent: 0:19709c5a4e75
154 parent: 0:19709c5a4e75
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:02 1970 +0000
156 date: Thu Jan 01 00:00:02 1970 +0000
157 summary: Adding b branch
157 summary: Adding b branch
158
158
159
159
160 ---- going to test branch listing by rev
160 ---- going to test branch listing by rev
161 $ hg branches -r0
161 $ hg branches -r0
162 default 0:19709c5a4e75 (inactive)
162 default 0:19709c5a4e75 (inactive)
163 $ hg branches -qr0
163 $ hg branches -qr0
164 default
164 default
165 --- now more than one rev
165 --- now more than one rev
166 $ hg branches -r2:5
166 $ hg branches -r2:5
167 b 4:aee39cd168d0
167 b 4:aee39cd168d0
168 a 5:d8cbc61dbaa6 (inactive)
168 a 5:d8cbc61dbaa6 (inactive)
169 $ hg branches -qr2:5
169 $ hg branches -qr2:5
170 b
170 b
171 a
171 a
172 ---- going to test branch closing
172 ---- going to test branch closing
173
173
174 $ hg branches
174 $ hg branches
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
176 b 4:aee39cd168d0
176 b 4:aee39cd168d0
177 c 6:589736a22561 (inactive)
177 c 6:589736a22561 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
179 default 0:19709c5a4e75 (inactive)
179 default 0:19709c5a4e75 (inactive)
180 $ hg up -C b
180 $ hg up -C b
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
182 $ echo 'xxx1' >> b
182 $ echo 'xxx1' >> b
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
184 $ hg up -C aee39cd168d0
184 $ hg up -C aee39cd168d0
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 $ echo 'xxx2' >> b
186 $ echo 'xxx2' >> b
187 $ hg commit -d '8 0' -m 'adding head to branch b'
187 $ hg commit -d '8 0' -m 'adding head to branch b'
188 created new head
188 created new head
189 $ echo 'xxx3' >> b
189 $ echo 'xxx3' >> b
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
191 $ hg branches
191 $ hg branches
192 b 10:bfbe841b666e
192 b 10:bfbe841b666e
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
194 c 6:589736a22561 (inactive)
194 c 6:589736a22561 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
196 default 0:19709c5a4e75 (inactive)
196 default 0:19709c5a4e75 (inactive)
197 $ hg heads --closed
197 $ hg heads --closed
198 changeset: 10:bfbe841b666e
198 changeset: 10:bfbe841b666e
199 branch: b
199 branch: b
200 tag: tip
200 tag: tip
201 user: test
201 user: test
202 date: Thu Jan 01 00:00:09 1970 +0000
202 date: Thu Jan 01 00:00:09 1970 +0000
203 summary: adding another cset to branch b
203 summary: adding another cset to branch b
204
204
205 changeset: 8:eebb944467c9
205 changeset: 8:eebb944467c9
206 branch: b
206 branch: b
207 parent: 4:aee39cd168d0
207 parent: 4:aee39cd168d0
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:07 1970 +0000
209 date: Thu Jan 01 00:00:07 1970 +0000
210 summary: adding cset to branch b
210 summary: adding cset to branch b
211
211
212 changeset: 7:10ff5895aa57
212 changeset: 7:10ff5895aa57
213 branch: a branch name much longer than the default justification used by branches
213 branch: a branch name much longer than the default justification used by branches
214 user: test
214 user: test
215 date: Thu Jan 01 00:00:06 1970 +0000
215 date: Thu Jan 01 00:00:06 1970 +0000
216 summary: Adding d branch
216 summary: Adding d branch
217
217
218 changeset: 6:589736a22561
218 changeset: 6:589736a22561
219 branch: c
219 branch: c
220 user: test
220 user: test
221 date: Thu Jan 01 00:00:05 1970 +0000
221 date: Thu Jan 01 00:00:05 1970 +0000
222 summary: Adding c branch
222 summary: Adding c branch
223
223
224 changeset: 5:d8cbc61dbaa6
224 changeset: 5:d8cbc61dbaa6
225 branch: a
225 branch: a
226 parent: 2:881fe2b92ad0
226 parent: 2:881fe2b92ad0
227 user: test
227 user: test
228 date: Thu Jan 01 00:00:04 1970 +0000
228 date: Thu Jan 01 00:00:04 1970 +0000
229 summary: Adding b branch head 2
229 summary: Adding b branch head 2
230
230
231 changeset: 0:19709c5a4e75
231 changeset: 0:19709c5a4e75
232 user: test
232 user: test
233 date: Thu Jan 01 00:00:00 1970 +0000
233 date: Thu Jan 01 00:00:00 1970 +0000
234 summary: Adding root node
234 summary: Adding root node
235
235
236 $ hg heads
236 $ hg heads
237 changeset: 10:bfbe841b666e
237 changeset: 10:bfbe841b666e
238 branch: b
238 branch: b
239 tag: tip
239 tag: tip
240 user: test
240 user: test
241 date: Thu Jan 01 00:00:09 1970 +0000
241 date: Thu Jan 01 00:00:09 1970 +0000
242 summary: adding another cset to branch b
242 summary: adding another cset to branch b
243
243
244 changeset: 8:eebb944467c9
244 changeset: 8:eebb944467c9
245 branch: b
245 branch: b
246 parent: 4:aee39cd168d0
246 parent: 4:aee39cd168d0
247 user: test
247 user: test
248 date: Thu Jan 01 00:00:07 1970 +0000
248 date: Thu Jan 01 00:00:07 1970 +0000
249 summary: adding cset to branch b
249 summary: adding cset to branch b
250
250
251 changeset: 7:10ff5895aa57
251 changeset: 7:10ff5895aa57
252 branch: a branch name much longer than the default justification used by branches
252 branch: a branch name much longer than the default justification used by branches
253 user: test
253 user: test
254 date: Thu Jan 01 00:00:06 1970 +0000
254 date: Thu Jan 01 00:00:06 1970 +0000
255 summary: Adding d branch
255 summary: Adding d branch
256
256
257 changeset: 6:589736a22561
257 changeset: 6:589736a22561
258 branch: c
258 branch: c
259 user: test
259 user: test
260 date: Thu Jan 01 00:00:05 1970 +0000
260 date: Thu Jan 01 00:00:05 1970 +0000
261 summary: Adding c branch
261 summary: Adding c branch
262
262
263 changeset: 5:d8cbc61dbaa6
263 changeset: 5:d8cbc61dbaa6
264 branch: a
264 branch: a
265 parent: 2:881fe2b92ad0
265 parent: 2:881fe2b92ad0
266 user: test
266 user: test
267 date: Thu Jan 01 00:00:04 1970 +0000
267 date: Thu Jan 01 00:00:04 1970 +0000
268 summary: Adding b branch head 2
268 summary: Adding b branch head 2
269
269
270 changeset: 0:19709c5a4e75
270 changeset: 0:19709c5a4e75
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:00 1970 +0000
272 date: Thu Jan 01 00:00:00 1970 +0000
273 summary: Adding root node
273 summary: Adding root node
274
274
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
276 $ hg branches -a
276 $ hg branches -a
277 b 8:eebb944467c9
277 b 8:eebb944467c9
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
279 $ hg up -C b
279 $ hg up -C b
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
283 abort: current revision is already a branch closing head
283 abort: current revision is already a branch closing head
284 [10]
284 [10]
285
285
286 $ echo foo > b
287 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
288
289 $ echo bar > b
290 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' bh1
291 abort: current revision is already a branch closing head
292 [10]
293 $ hg commit -d '9 0' --close-branch -m 're-closing this branch' b
294
295 $ hg debugstrip --rev 13: --no-backup
296 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 $ hg revert --all --no-backup
298
286 $ hg log -r tip --debug
299 $ hg log -r tip --debug
287 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
300 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
288 branch: b
301 branch: b
289 tag: tip
302 tag: tip
290 phase: draft
303 phase: draft
291 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
304 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
292 parent: -1:0000000000000000000000000000000000000000
305 parent: -1:0000000000000000000000000000000000000000
293 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
306 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
294 user: test
307 user: test
295 date: Thu Jan 01 00:00:09 1970 +0000
308 date: Thu Jan 01 00:00:09 1970 +0000
296 extra: branch=b
309 extra: branch=b
297 extra: close=1
310 extra: close=1
298 description:
311 description:
299 close this part branch too
312 close this part branch too
300
313
301
314
302 --- b branch should be inactive
315 --- b branch should be inactive
303
316
304 $ hg branches
317 $ hg branches
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
318 a branch name much longer than the default justification used by branches 7:10ff5895aa57
306 c 6:589736a22561 (inactive)
319 c 6:589736a22561 (inactive)
307 a 5:d8cbc61dbaa6 (inactive)
320 a 5:d8cbc61dbaa6 (inactive)
308 default 0:19709c5a4e75 (inactive)
321 default 0:19709c5a4e75 (inactive)
309 $ hg branches -c
322 $ hg branches -c
310 a branch name much longer than the default justification used by branches 7:10ff5895aa57
323 a branch name much longer than the default justification used by branches 7:10ff5895aa57
311 b 12:e3d49c0575d8 (closed)
324 b 12:e3d49c0575d8 (closed)
312 c 6:589736a22561 (inactive)
325 c 6:589736a22561 (inactive)
313 a 5:d8cbc61dbaa6 (inactive)
326 a 5:d8cbc61dbaa6 (inactive)
314 default 0:19709c5a4e75 (inactive)
327 default 0:19709c5a4e75 (inactive)
315 $ hg branches -a
328 $ hg branches -a
316 a branch name much longer than the default justification used by branches 7:10ff5895aa57
329 a branch name much longer than the default justification used by branches 7:10ff5895aa57
317 $ hg branches -q
330 $ hg branches -q
318 a branch name much longer than the default justification used by branches
331 a branch name much longer than the default justification used by branches
319 c
332 c
320 a
333 a
321 default
334 default
322 $ hg heads b
335 $ hg heads b
323 no open branch heads found on branches b
336 no open branch heads found on branches b
324 [1]
337 [1]
325 $ hg heads --closed b
338 $ hg heads --closed b
326 changeset: 12:e3d49c0575d8
339 changeset: 12:e3d49c0575d8
327 branch: b
340 branch: b
328 tag: tip
341 tag: tip
329 parent: 8:eebb944467c9
342 parent: 8:eebb944467c9
330 user: test
343 user: test
331 date: Thu Jan 01 00:00:09 1970 +0000
344 date: Thu Jan 01 00:00:09 1970 +0000
332 summary: close this part branch too
345 summary: close this part branch too
333
346
334 changeset: 11:d3f163457ebf
347 changeset: 11:d3f163457ebf
335 branch: b
348 branch: b
336 user: test
349 user: test
337 date: Thu Jan 01 00:00:09 1970 +0000
350 date: Thu Jan 01 00:00:09 1970 +0000
338 summary: prune bad branch
351 summary: prune bad branch
339
352
340 $ echo 'xxx4' >> b
353 $ echo 'xxx4' >> b
341 $ hg commit -d '9 0' -m 'reopen branch with a change'
354 $ hg commit -d '9 0' -m 'reopen branch with a change'
342 reopening closed branch head 12
355 reopening closed branch head 12
343
356
344 --- branch b is back in action
357 --- branch b is back in action
345
358
346 $ hg branches -a
359 $ hg branches -a
347 b 13:e23b5505d1ad
360 b 13:e23b5505d1ad
348 a branch name much longer than the default justification used by branches 7:10ff5895aa57
361 a branch name much longer than the default justification used by branches 7:10ff5895aa57
349
362
350 ---- test heads listings
363 ---- test heads listings
351
364
352 $ hg heads
365 $ hg heads
353 changeset: 13:e23b5505d1ad
366 changeset: 13:e23b5505d1ad
354 branch: b
367 branch: b
355 tag: tip
368 tag: tip
356 user: test
369 user: test
357 date: Thu Jan 01 00:00:09 1970 +0000
370 date: Thu Jan 01 00:00:09 1970 +0000
358 summary: reopen branch with a change
371 summary: reopen branch with a change
359
372
360 changeset: 7:10ff5895aa57
373 changeset: 7:10ff5895aa57
361 branch: a branch name much longer than the default justification used by branches
374 branch: a branch name much longer than the default justification used by branches
362 user: test
375 user: test
363 date: Thu Jan 01 00:00:06 1970 +0000
376 date: Thu Jan 01 00:00:06 1970 +0000
364 summary: Adding d branch
377 summary: Adding d branch
365
378
366 changeset: 6:589736a22561
379 changeset: 6:589736a22561
367 branch: c
380 branch: c
368 user: test
381 user: test
369 date: Thu Jan 01 00:00:05 1970 +0000
382 date: Thu Jan 01 00:00:05 1970 +0000
370 summary: Adding c branch
383 summary: Adding c branch
371
384
372 changeset: 5:d8cbc61dbaa6
385 changeset: 5:d8cbc61dbaa6
373 branch: a
386 branch: a
374 parent: 2:881fe2b92ad0
387 parent: 2:881fe2b92ad0
375 user: test
388 user: test
376 date: Thu Jan 01 00:00:04 1970 +0000
389 date: Thu Jan 01 00:00:04 1970 +0000
377 summary: Adding b branch head 2
390 summary: Adding b branch head 2
378
391
379 changeset: 0:19709c5a4e75
392 changeset: 0:19709c5a4e75
380 user: test
393 user: test
381 date: Thu Jan 01 00:00:00 1970 +0000
394 date: Thu Jan 01 00:00:00 1970 +0000
382 summary: Adding root node
395 summary: Adding root node
383
396
384
397
385 branch default
398 branch default
386
399
387 $ hg heads default
400 $ hg heads default
388 changeset: 0:19709c5a4e75
401 changeset: 0:19709c5a4e75
389 user: test
402 user: test
390 date: Thu Jan 01 00:00:00 1970 +0000
403 date: Thu Jan 01 00:00:00 1970 +0000
391 summary: Adding root node
404 summary: Adding root node
392
405
393
406
394 branch a
407 branch a
395
408
396 $ hg heads a
409 $ hg heads a
397 changeset: 5:d8cbc61dbaa6
410 changeset: 5:d8cbc61dbaa6
398 branch: a
411 branch: a
399 parent: 2:881fe2b92ad0
412 parent: 2:881fe2b92ad0
400 user: test
413 user: test
401 date: Thu Jan 01 00:00:04 1970 +0000
414 date: Thu Jan 01 00:00:04 1970 +0000
402 summary: Adding b branch head 2
415 summary: Adding b branch head 2
403
416
404 $ hg heads --active a
417 $ hg heads --active a
405 no open branch heads found on branches a
418 no open branch heads found on branches a
406 [1]
419 [1]
407
420
408 branch b
421 branch b
409
422
410 $ hg heads b
423 $ hg heads b
411 changeset: 13:e23b5505d1ad
424 changeset: 13:e23b5505d1ad
412 branch: b
425 branch: b
413 tag: tip
426 tag: tip
414 user: test
427 user: test
415 date: Thu Jan 01 00:00:09 1970 +0000
428 date: Thu Jan 01 00:00:09 1970 +0000
416 summary: reopen branch with a change
429 summary: reopen branch with a change
417
430
418 $ hg heads --closed b
431 $ hg heads --closed b
419 changeset: 13:e23b5505d1ad
432 changeset: 13:e23b5505d1ad
420 branch: b
433 branch: b
421 tag: tip
434 tag: tip
422 user: test
435 user: test
423 date: Thu Jan 01 00:00:09 1970 +0000
436 date: Thu Jan 01 00:00:09 1970 +0000
424 summary: reopen branch with a change
437 summary: reopen branch with a change
425
438
426 changeset: 11:d3f163457ebf
439 changeset: 11:d3f163457ebf
427 branch: b
440 branch: b
428 user: test
441 user: test
429 date: Thu Jan 01 00:00:09 1970 +0000
442 date: Thu Jan 01 00:00:09 1970 +0000
430 summary: prune bad branch
443 summary: prune bad branch
431
444
432
445
433 reclose branch
446 reclose branch
434
447
435 $ hg up -C c
448 $ hg up -C c
436 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
449 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
437 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
450 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
438 $ hg branches
451 $ hg branches
439 b 13:e23b5505d1ad
452 b 13:e23b5505d1ad
440 a branch name much longer than the default justification used by branches 7:10ff5895aa57
453 a branch name much longer than the default justification used by branches 7:10ff5895aa57
441 a 5:d8cbc61dbaa6 (inactive)
454 a 5:d8cbc61dbaa6 (inactive)
442 default 0:19709c5a4e75 (inactive)
455 default 0:19709c5a4e75 (inactive)
443 $ hg branches --closed
456 $ hg branches --closed
444 b 13:e23b5505d1ad
457 b 13:e23b5505d1ad
445 a branch name much longer than the default justification used by branches 7:10ff5895aa57
458 a branch name much longer than the default justification used by branches 7:10ff5895aa57
446 c 14:f894c25619d3 (closed)
459 c 14:f894c25619d3 (closed)
447 a 5:d8cbc61dbaa6 (inactive)
460 a 5:d8cbc61dbaa6 (inactive)
448 default 0:19709c5a4e75 (inactive)
461 default 0:19709c5a4e75 (inactive)
449
462
450 multihead branch
463 multihead branch
451
464
452 $ hg up -C default
465 $ hg up -C default
453 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
466 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
454 $ hg branch m
467 $ hg branch m
455 marked working directory as branch m
468 marked working directory as branch m
456 $ touch m
469 $ touch m
457 $ hg add m
470 $ hg add m
458 $ hg commit -d '10 0' -m 'multihead base'
471 $ hg commit -d '10 0' -m 'multihead base'
459 $ echo "m1" >m
472 $ echo "m1" >m
460 $ hg commit -d '10 0' -m 'head 1'
473 $ hg commit -d '10 0' -m 'head 1'
461 $ hg up -C '.^'
474 $ hg up -C '.^'
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ echo "m2" >m
476 $ echo "m2" >m
464 $ hg commit -d '10 0' -m 'head 2'
477 $ hg commit -d '10 0' -m 'head 2'
465 created new head
478 created new head
466 $ hg log -b m
479 $ hg log -b m
467 changeset: 17:df343b0df04f
480 changeset: 17:df343b0df04f
468 branch: m
481 branch: m
469 tag: tip
482 tag: tip
470 parent: 15:f3447637f53e
483 parent: 15:f3447637f53e
471 user: test
484 user: test
472 date: Thu Jan 01 00:00:10 1970 +0000
485 date: Thu Jan 01 00:00:10 1970 +0000
473 summary: head 2
486 summary: head 2
474
487
475 changeset: 16:a58ca5d3bdf3
488 changeset: 16:a58ca5d3bdf3
476 branch: m
489 branch: m
477 user: test
490 user: test
478 date: Thu Jan 01 00:00:10 1970 +0000
491 date: Thu Jan 01 00:00:10 1970 +0000
479 summary: head 1
492 summary: head 1
480
493
481 changeset: 15:f3447637f53e
494 changeset: 15:f3447637f53e
482 branch: m
495 branch: m
483 parent: 0:19709c5a4e75
496 parent: 0:19709c5a4e75
484 user: test
497 user: test
485 date: Thu Jan 01 00:00:10 1970 +0000
498 date: Thu Jan 01 00:00:10 1970 +0000
486 summary: multihead base
499 summary: multihead base
487
500
488 $ hg heads --topo m
501 $ hg heads --topo m
489 changeset: 17:df343b0df04f
502 changeset: 17:df343b0df04f
490 branch: m
503 branch: m
491 tag: tip
504 tag: tip
492 parent: 15:f3447637f53e
505 parent: 15:f3447637f53e
493 user: test
506 user: test
494 date: Thu Jan 01 00:00:10 1970 +0000
507 date: Thu Jan 01 00:00:10 1970 +0000
495 summary: head 2
508 summary: head 2
496
509
497 changeset: 16:a58ca5d3bdf3
510 changeset: 16:a58ca5d3bdf3
498 branch: m
511 branch: m
499 user: test
512 user: test
500 date: Thu Jan 01 00:00:10 1970 +0000
513 date: Thu Jan 01 00:00:10 1970 +0000
501 summary: head 1
514 summary: head 1
502
515
503 $ hg branches
516 $ hg branches
504 m 17:df343b0df04f
517 m 17:df343b0df04f
505 b 13:e23b5505d1ad
518 b 13:e23b5505d1ad
506 a branch name much longer than the default justification used by branches 7:10ff5895aa57
519 a branch name much longer than the default justification used by branches 7:10ff5895aa57
507 a 5:d8cbc61dbaa6 (inactive)
520 a 5:d8cbc61dbaa6 (inactive)
508 default 0:19709c5a4e75 (inactive)
521 default 0:19709c5a4e75 (inactive)
509
522
510 partially merge multihead branch
523 partially merge multihead branch
511
524
512 $ hg up -C default
525 $ hg up -C default
513 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
526 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
514 $ hg branch md
527 $ hg branch md
515 marked working directory as branch md
528 marked working directory as branch md
516 $ hg merge m
529 $ hg merge m
517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 (branch merge, don't forget to commit)
531 (branch merge, don't forget to commit)
519 $ hg commit -d '11 0' -m 'merge head 2'
532 $ hg commit -d '11 0' -m 'merge head 2'
520 $ hg heads --topo m
533 $ hg heads --topo m
521 changeset: 16:a58ca5d3bdf3
534 changeset: 16:a58ca5d3bdf3
522 branch: m
535 branch: m
523 user: test
536 user: test
524 date: Thu Jan 01 00:00:10 1970 +0000
537 date: Thu Jan 01 00:00:10 1970 +0000
525 summary: head 1
538 summary: head 1
526
539
527 $ hg branches
540 $ hg branches
528 md 18:c914c99f1fbb
541 md 18:c914c99f1fbb
529 m 17:df343b0df04f
542 m 17:df343b0df04f
530 b 13:e23b5505d1ad
543 b 13:e23b5505d1ad
531 a branch name much longer than the default justification used by branches 7:10ff5895aa57
544 a branch name much longer than the default justification used by branches 7:10ff5895aa57
532 a 5:d8cbc61dbaa6 (inactive)
545 a 5:d8cbc61dbaa6 (inactive)
533 default 0:19709c5a4e75 (inactive)
546 default 0:19709c5a4e75 (inactive)
534
547
535 partially close multihead branch
548 partially close multihead branch
536
549
537 $ hg up -C a58ca5d3bdf3
550 $ hg up -C a58ca5d3bdf3
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
551 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 $ hg commit -d '12 0' -m 'close head 1' --close-branch
552 $ hg commit -d '12 0' -m 'close head 1' --close-branch
540 $ hg heads --topo m
553 $ hg heads --topo m
541 changeset: 19:cd21a80baa3d
554 changeset: 19:cd21a80baa3d
542 branch: m
555 branch: m
543 tag: tip
556 tag: tip
544 parent: 16:a58ca5d3bdf3
557 parent: 16:a58ca5d3bdf3
545 user: test
558 user: test
546 date: Thu Jan 01 00:00:12 1970 +0000
559 date: Thu Jan 01 00:00:12 1970 +0000
547 summary: close head 1
560 summary: close head 1
548
561
549 $ hg branches
562 $ hg branches
550 md 18:c914c99f1fbb
563 md 18:c914c99f1fbb
551 b 13:e23b5505d1ad
564 b 13:e23b5505d1ad
552 a branch name much longer than the default justification used by branches 7:10ff5895aa57
565 a branch name much longer than the default justification used by branches 7:10ff5895aa57
553 m 17:df343b0df04f (inactive)
566 m 17:df343b0df04f (inactive)
554 a 5:d8cbc61dbaa6 (inactive)
567 a 5:d8cbc61dbaa6 (inactive)
555 default 0:19709c5a4e75 (inactive)
568 default 0:19709c5a4e75 (inactive)
556
569
557 default branch colors:
570 default branch colors:
558
571
559 $ cat <<EOF >> $HGRCPATH
572 $ cat <<EOF >> $HGRCPATH
560 > [extensions]
573 > [extensions]
561 > color =
574 > color =
562 > [color]
575 > [color]
563 > mode = ansi
576 > mode = ansi
564 > EOF
577 > EOF
565
578
566 $ hg up -C b
579 $ hg up -C b
567 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
580 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
568 $ hg branches --color=always
581 $ hg branches --color=always
569 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
582 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
570 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
583 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
571 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
584 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
572 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
585 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
586 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
587 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
575
588
576 default closed branch color:
589 default closed branch color:
577
590
578 $ hg branches --color=always --closed
591 $ hg branches --color=always --closed
579 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
592 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
580 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
593 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
581 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
594 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
582 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
595 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
583 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
596 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
584 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
597 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
585 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
598 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
586
599
587 $ cat <<EOF >> $HGRCPATH
600 $ cat <<EOF >> $HGRCPATH
588 > [extensions]
601 > [extensions]
589 > color =
602 > color =
590 > [color]
603 > [color]
591 > branches.active = green
604 > branches.active = green
592 > branches.closed = blue
605 > branches.closed = blue
593 > branches.current = red
606 > branches.current = red
594 > branches.inactive = magenta
607 > branches.inactive = magenta
595 > log.changeset = cyan
608 > log.changeset = cyan
596 > EOF
609 > EOF
597
610
598 custom branch colors:
611 custom branch colors:
599
612
600 $ hg branches --color=always
613 $ hg branches --color=always
601 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
614 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
602 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
615 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
603 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
616 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
604 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
617 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
618 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
619 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
607
620
608 custom closed branch color:
621 custom closed branch color:
609
622
610 $ hg branches --color=always --closed
623 $ hg branches --color=always --closed
611 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
624 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
612 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
625 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
613 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
626 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
614 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
627 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
615 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
628 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
616 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
629 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
617 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
630 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
618
631
619 template output:
632 template output:
620
633
621 $ hg branches -Tjson --closed
634 $ hg branches -Tjson --closed
622 [
635 [
623 {
636 {
624 "active": true,
637 "active": true,
625 "branch": "md",
638 "branch": "md",
626 "closed": false,
639 "closed": false,
627 "current": false,
640 "current": false,
628 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
641 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
629 "rev": 18
642 "rev": 18
630 },
643 },
631 {
644 {
632 "active": true,
645 "active": true,
633 "branch": "b",
646 "branch": "b",
634 "closed": false,
647 "closed": false,
635 "current": true,
648 "current": true,
636 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
649 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
637 "rev": 13
650 "rev": 13
638 },
651 },
639 {
652 {
640 "active": true,
653 "active": true,
641 "branch": "a branch name much longer than the default justification used by branches",
654 "branch": "a branch name much longer than the default justification used by branches",
642 "closed": false,
655 "closed": false,
643 "current": false,
656 "current": false,
644 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
657 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
645 "rev": 7
658 "rev": 7
646 },
659 },
647 {
660 {
648 "active": false,
661 "active": false,
649 "branch": "m",
662 "branch": "m",
650 "closed": false,
663 "closed": false,
651 "current": false,
664 "current": false,
652 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
665 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
653 "rev": 17
666 "rev": 17
654 },
667 },
655 {
668 {
656 "active": false,
669 "active": false,
657 "branch": "c",
670 "branch": "c",
658 "closed": true,
671 "closed": true,
659 "current": false,
672 "current": false,
660 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
673 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
661 "rev": 14
674 "rev": 14
662 },
675 },
663 {
676 {
664 "active": false,
677 "active": false,
665 "branch": "a",
678 "branch": "a",
666 "closed": false,
679 "closed": false,
667 "current": false,
680 "current": false,
668 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
681 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
669 "rev": 5
682 "rev": 5
670 },
683 },
671 {
684 {
672 "active": false,
685 "active": false,
673 "branch": "default",
686 "branch": "default",
674 "closed": false,
687 "closed": false,
675 "current": false,
688 "current": false,
676 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
689 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
677 "rev": 0
690 "rev": 0
678 }
691 }
679 ]
692 ]
680
693
681 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
694 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
682 c
695 c
683
696
684 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
697 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
685 md: merge head 2
698 md: merge head 2
686 b: reopen branch with a change
699 b: reopen branch with a change
687 a: Adding d branch
700 a: Adding d branch
688 m: head 2
701 m: head 2
689 a: Adding b branch head 2
702 a: Adding b branch head 2
690 default: Adding root node
703 default: Adding root node
691
704
692 $ cat <<'EOF' > "$TESTTMP/map-myjson"
705 $ cat <<'EOF' > "$TESTTMP/map-myjson"
693 > docheader = '\{\n'
706 > docheader = '\{\n'
694 > docfooter = '\n}\n'
707 > docfooter = '\n}\n'
695 > separator = ',\n'
708 > separator = ',\n'
696 > branches = ' {dict(branch, node|short)|json}'
709 > branches = ' {dict(branch, node|short)|json}'
697 > EOF
710 > EOF
698 $ hg branches -T "$TESTTMP/map-myjson"
711 $ hg branches -T "$TESTTMP/map-myjson"
699 {
712 {
700 {"branch": "md", "node": "c914c99f1fbb"},
713 {"branch": "md", "node": "c914c99f1fbb"},
701 {"branch": "b", "node": "e23b5505d1ad"},
714 {"branch": "b", "node": "e23b5505d1ad"},
702 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
715 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
703 {"branch": "m", "node": "df343b0df04f"},
716 {"branch": "m", "node": "df343b0df04f"},
704 {"branch": "a", "node": "d8cbc61dbaa6"},
717 {"branch": "a", "node": "d8cbc61dbaa6"},
705 {"branch": "default", "node": "19709c5a4e75"}
718 {"branch": "default", "node": "19709c5a4e75"}
706 }
719 }
707
720
708 $ cat <<'EOF' >> .hg/hgrc
721 $ cat <<'EOF' >> .hg/hgrc
709 > [templates]
722 > [templates]
710 > myjson = ' {dict(branch, node|short)|json}'
723 > myjson = ' {dict(branch, node|short)|json}'
711 > myjson:docheader = '\{\n'
724 > myjson:docheader = '\{\n'
712 > myjson:docfooter = '\n}\n'
725 > myjson:docfooter = '\n}\n'
713 > myjson:separator = ',\n'
726 > myjson:separator = ',\n'
714 > EOF
727 > EOF
715 $ hg branches -T myjson
728 $ hg branches -T myjson
716 {
729 {
717 {"branch": "md", "node": "c914c99f1fbb"},
730 {"branch": "md", "node": "c914c99f1fbb"},
718 {"branch": "b", "node": "e23b5505d1ad"},
731 {"branch": "b", "node": "e23b5505d1ad"},
719 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
732 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
720 {"branch": "m", "node": "df343b0df04f"},
733 {"branch": "m", "node": "df343b0df04f"},
721 {"branch": "a", "node": "d8cbc61dbaa6"},
734 {"branch": "a", "node": "d8cbc61dbaa6"},
722 {"branch": "default", "node": "19709c5a4e75"}
735 {"branch": "default", "node": "19709c5a4e75"}
723 }
736 }
724
737
725 $ cat <<'EOF' >> .hg/hgrc
738 $ cat <<'EOF' >> .hg/hgrc
726 > [templates]
739 > [templates]
727 > :docheader = 'should not be selected as a docheader for literal templates\n'
740 > :docheader = 'should not be selected as a docheader for literal templates\n'
728 > EOF
741 > EOF
729 $ hg branches -T '{branch}\n'
742 $ hg branches -T '{branch}\n'
730 md
743 md
731 b
744 b
732 a branch name much longer than the default justification used by branches
745 a branch name much longer than the default justification used by branches
733 m
746 m
734 a
747 a
735 default
748 default
736
749
737 Tests of revision branch name caching
750 Tests of revision branch name caching
738
751
739 We rev branch cache is updated automatically. In these tests we use a trick to
752 We rev branch cache is updated automatically. In these tests we use a trick to
740 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
753 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
741 rebuild that also will populate the rev branch cache.
754 rebuild that also will populate the rev branch cache.
742
755
743 revision branch cache is created when building the branch head cache
756 revision branch cache is created when building the branch head cache
744 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
757 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
745 5
758 5
746 $ f --hexdump --size .hg/cache/rbc-*
759 $ f --hexdump --size .hg/cache/rbc-*
747 .hg/cache/rbc-names-v1: size=92
760 .hg/cache/rbc-names-v1: size=92
748 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
761 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
749 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
762 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
750 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
763 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
751 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
764 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
752 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
765 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
753 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
766 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
754 .hg/cache/rbc-revs-v1: size=160
767 .hg/cache/rbc-revs-v1: size=160
755 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
768 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
756 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
769 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
757 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
770 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
758 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
771 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
759 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
772 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
760 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
773 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
761 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
774 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
762 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
775 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
763 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
776 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
764 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
777 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
765
778
766 no errors when revbranchcache is not writable
779 no errors when revbranchcache is not writable
767
780
768 $ echo >> .hg/cache/rbc-revs-v1
781 $ echo >> .hg/cache/rbc-revs-v1
769 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
782 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
770 $ mkdir .hg/cache/rbc-revs-v1
783 $ mkdir .hg/cache/rbc-revs-v1
771 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
784 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
772 5
785 5
773 $ rmdir .hg/cache/rbc-revs-v1
786 $ rmdir .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
787 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
775
788
776 no errors when wlock cannot be acquired
789 no errors when wlock cannot be acquired
777
790
778 #if unix-permissions
791 #if unix-permissions
779 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
792 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
780 $ rm -f .hg/cache/branch*
793 $ rm -f .hg/cache/branch*
781 $ chmod 555 .hg
794 $ chmod 555 .hg
782 $ hg head a -T '{rev}\n'
795 $ hg head a -T '{rev}\n'
783 5
796 5
784 $ chmod 755 .hg
797 $ chmod 755 .hg
785 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
798 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
786 #endif
799 #endif
787
800
788 recovery from invalid cache revs file with trailing data
801 recovery from invalid cache revs file with trailing data
789 $ echo >> .hg/cache/rbc-revs-v1
802 $ echo >> .hg/cache/rbc-revs-v1
790 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
803 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
791 5
804 5
792 truncating cache/rbc-revs-v1 to 160
805 truncating cache/rbc-revs-v1 to 160
793 $ f --size .hg/cache/rbc-revs*
806 $ f --size .hg/cache/rbc-revs*
794 .hg/cache/rbc-revs-v1: size=160
807 .hg/cache/rbc-revs-v1: size=160
795 recovery from invalid cache file with partial last record
808 recovery from invalid cache file with partial last record
796 $ mv .hg/cache/rbc-revs-v1 .
809 $ mv .hg/cache/rbc-revs-v1 .
797 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
810 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
798 $ f --size .hg/cache/rbc-revs*
811 $ f --size .hg/cache/rbc-revs*
799 .hg/cache/rbc-revs-v1: size=119
812 .hg/cache/rbc-revs-v1: size=119
800 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
813 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
801 5
814 5
802 truncating cache/rbc-revs-v1 to 112
815 truncating cache/rbc-revs-v1 to 112
803 $ f --size .hg/cache/rbc-revs*
816 $ f --size .hg/cache/rbc-revs*
804 .hg/cache/rbc-revs-v1: size=160
817 .hg/cache/rbc-revs-v1: size=160
805 recovery from invalid cache file with missing record - no truncation
818 recovery from invalid cache file with missing record - no truncation
806 $ mv .hg/cache/rbc-revs-v1 .
819 $ mv .hg/cache/rbc-revs-v1 .
807 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
820 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
808 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
821 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
809 5
822 5
810 $ f --size .hg/cache/rbc-revs*
823 $ f --size .hg/cache/rbc-revs*
811 .hg/cache/rbc-revs-v1: size=160
824 .hg/cache/rbc-revs-v1: size=160
812 recovery from invalid cache file with some bad records
825 recovery from invalid cache file with some bad records
813 $ mv .hg/cache/rbc-revs-v1 .
826 $ mv .hg/cache/rbc-revs-v1 .
814 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
827 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
815 $ f --size .hg/cache/rbc-revs*
828 $ f --size .hg/cache/rbc-revs*
816 .hg/cache/rbc-revs-v1: size=8
829 .hg/cache/rbc-revs-v1: size=8
817 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
830 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
818 $ f --size .hg/cache/rbc-revs*
831 $ f --size .hg/cache/rbc-revs*
819 .hg/cache/rbc-revs-v1: size=120
832 .hg/cache/rbc-revs-v1: size=120
820 $ hg log -r 'branch(.)' -T '{rev} ' --debug
833 $ hg log -r 'branch(.)' -T '{rev} ' --debug
821 history modification detected - truncating revision branch cache to revision 13
834 history modification detected - truncating revision branch cache to revision 13
822 history modification detected - truncating revision branch cache to revision 1
835 history modification detected - truncating revision branch cache to revision 1
823 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
836 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
824 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
837 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
825 5
838 5
826 truncating cache/rbc-revs-v1 to 104
839 truncating cache/rbc-revs-v1 to 104
827 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
840 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
828 .hg/cache/rbc-revs-v1: size=160
841 .hg/cache/rbc-revs-v1: size=160
829 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
842 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
830 cache is updated when committing
843 cache is updated when committing
831 $ hg branch i-will-regret-this
844 $ hg branch i-will-regret-this
832 marked working directory as branch i-will-regret-this
845 marked working directory as branch i-will-regret-this
833 $ hg ci -m regrets
846 $ hg ci -m regrets
834 $ f --size .hg/cache/rbc-*
847 $ f --size .hg/cache/rbc-*
835 .hg/cache/rbc-names-v1: size=111
848 .hg/cache/rbc-names-v1: size=111
836 .hg/cache/rbc-revs-v1: size=168
849 .hg/cache/rbc-revs-v1: size=168
837 update after rollback - the cache will be correct but rbc-names will will still
850 update after rollback - the cache will be correct but rbc-names will will still
838 contain the branch name even though it no longer is used
851 contain the branch name even though it no longer is used
839 $ hg up -qr '.^'
852 $ hg up -qr '.^'
840 $ hg rollback -qf
853 $ hg rollback -qf
841 $ f --size --hexdump .hg/cache/rbc-*
854 $ f --size --hexdump .hg/cache/rbc-*
842 .hg/cache/rbc-names-v1: size=111
855 .hg/cache/rbc-names-v1: size=111
843 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
856 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
844 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
857 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
845 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
858 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
846 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
859 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
847 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
860 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
848 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
861 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
849 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
862 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
850 .hg/cache/rbc-revs-v1: size=160
863 .hg/cache/rbc-revs-v1: size=160
851 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
864 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
852 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
865 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
853 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
866 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
854 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
867 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
855 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
868 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
856 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
869 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
857 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
870 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
858 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
871 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
859 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
872 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
860 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
873 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
861 cache is updated/truncated when stripping - it is thus very hard to get in a
874 cache is updated/truncated when stripping - it is thus very hard to get in a
862 situation where the cache is out of sync and the hash check detects it
875 situation where the cache is out of sync and the hash check detects it
863 $ hg --config extensions.strip= strip -r tip --nob
876 $ hg --config extensions.strip= strip -r tip --nob
864 $ f --size .hg/cache/rbc-revs*
877 $ f --size .hg/cache/rbc-revs*
865 .hg/cache/rbc-revs-v1: size=152
878 .hg/cache/rbc-revs-v1: size=152
866
879
867 cache is rebuilt when corruption is detected
880 cache is rebuilt when corruption is detected
868 $ echo > .hg/cache/rbc-names-v1
881 $ echo > .hg/cache/rbc-names-v1
869 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
882 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
870 referenced branch names not found - rebuilding revision branch cache from scratch
883 referenced branch names not found - rebuilding revision branch cache from scratch
871 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
884 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
872 $ f --size --hexdump .hg/cache/rbc-*
885 $ f --size --hexdump .hg/cache/rbc-*
873 .hg/cache/rbc-names-v1: size=84
886 .hg/cache/rbc-names-v1: size=84
874 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
887 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
875 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
888 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
876 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
889 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
877 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
890 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
878 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
891 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
879 0050: 6d 00 6d 64 |m.md|
892 0050: 6d 00 6d 64 |m.md|
880 .hg/cache/rbc-revs-v1: size=152
893 .hg/cache/rbc-revs-v1: size=152
881 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
894 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
882 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
895 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
883 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
896 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
884 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
897 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
885 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
898 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
886 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
899 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
887 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
900 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
888 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
901 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
889 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
902 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
890 0090: c9 14 c9 9f 00 00 00 05 |........|
903 0090: c9 14 c9 9f 00 00 00 05 |........|
891
904
892 Test that cache files are created and grows correctly:
905 Test that cache files are created and grows correctly:
893
906
894 $ rm .hg/cache/rbc*
907 $ rm .hg/cache/rbc*
895 $ hg log -r "5 & branch(5)" -T "{rev}\n"
908 $ hg log -r "5 & branch(5)" -T "{rev}\n"
896 5
909 5
897 $ f --size --hexdump .hg/cache/rbc-*
910 $ f --size --hexdump .hg/cache/rbc-*
898 .hg/cache/rbc-names-v1: size=1
911 .hg/cache/rbc-names-v1: size=1
899 0000: 61 |a|
912 0000: 61 |a|
900 .hg/cache/rbc-revs-v1: size=152
913 .hg/cache/rbc-revs-v1: size=152
901 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
914 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
902 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
915 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
903 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
916 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
904 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
917 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
905 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
918 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
906 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
919 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
907 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
920 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
908 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
921 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
909 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
922 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
910 0090: 00 00 00 00 00 00 00 00 |........|
923 0090: 00 00 00 00 00 00 00 00 |........|
911
924
912 $ cd ..
925 $ cd ..
913
926
914 Test for multiple incorrect branch cache entries:
927 Test for multiple incorrect branch cache entries:
915
928
916 $ hg init b
929 $ hg init b
917 $ cd b
930 $ cd b
918 $ touch f
931 $ touch f
919 $ hg ci -Aqmf
932 $ hg ci -Aqmf
920 $ echo >> f
933 $ echo >> f
921 $ hg ci -Amf
934 $ hg ci -Amf
922 $ hg branch -q branch
935 $ hg branch -q branch
923 $ hg ci -Amf
936 $ hg ci -Amf
924
937
925 $ f --size --hexdump .hg/cache/rbc-*
938 $ f --size --hexdump .hg/cache/rbc-*
926 .hg/cache/rbc-names-v1: size=14
939 .hg/cache/rbc-names-v1: size=14
927 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
940 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
928 .hg/cache/rbc-revs-v1: size=24
941 .hg/cache/rbc-revs-v1: size=24
929 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
942 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
930 0010: 56 46 78 69 00 00 00 01 |VFxi....|
943 0010: 56 46 78 69 00 00 00 01 |VFxi....|
931 $ : > .hg/cache/rbc-revs-v1
944 $ : > .hg/cache/rbc-revs-v1
932
945
933 No superfluous rebuilding of cache:
946 No superfluous rebuilding of cache:
934 $ hg log -r "branch(null)&branch(branch)" --debug
947 $ hg log -r "branch(null)&branch(branch)" --debug
935 $ f --size --hexdump .hg/cache/rbc-*
948 $ f --size --hexdump .hg/cache/rbc-*
936 .hg/cache/rbc-names-v1: size=14
949 .hg/cache/rbc-names-v1: size=14
937 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
950 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
938 .hg/cache/rbc-revs-v1: size=24
951 .hg/cache/rbc-revs-v1: size=24
939 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
952 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
940 0010: 56 46 78 69 00 00 00 01 |VFxi....|
953 0010: 56 46 78 69 00 00 00 01 |VFxi....|
941
954
942 $ cd ..
955 $ cd ..
943
956
944 Test to make sure that `--close-branch` only works on a branch head:
957 Test to make sure that `--close-branch` only works on a branch head:
945 --------------------------------------------------------------------
958 --------------------------------------------------------------------
946 $ hg init closebranch
959 $ hg init closebranch
947 $ cd closebranch
960 $ cd closebranch
948 $ for ch in a b c; do
961 $ for ch in a b c; do
949 > echo $ch > $ch
962 > echo $ch > $ch
950 > hg add $ch
963 > hg add $ch
951 > hg ci -m "added "$ch
964 > hg ci -m "added "$ch
952 > done;
965 > done;
953
966
954 $ hg up -r "desc('added b')"
967 $ hg up -r "desc('added b')"
955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
968 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
956
969
957 trying to close branch from a cset which is not a branch head
970 trying to close branch from a cset which is not a branch head
958 it should abort:
971 it should abort:
959 $ hg ci -m "closing branch" --close-branch
972 $ hg ci -m "closing branch" --close-branch
960 abort: can only close branch heads
973 abort: can only close branch heads
961 (use --force-close-branch to close branch from a non-head changeset)
974 (use --force-close-branch to close branch from a non-head changeset)
962 [10]
975 [10]
963
976
964 $ hg up 0
977 $ hg up 0
965 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
978 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
966 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
979 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
967 o 2: 155349b645be added c
980 o 2: 155349b645be added c
968 | default
981 | default
969 |
982 |
970 o 1: 5f6d8a4bf34a added b
983 o 1: 5f6d8a4bf34a added b
971 | default
984 | default
972 |
985 |
973 @ 0: 9092f1db7931 added a
986 @ 0: 9092f1db7931 added a
974 default
987 default
975
988
976 Test --force-close-branch to close a branch from a non-head changeset:
989 Test --force-close-branch to close a branch from a non-head changeset:
977 ---------------------------------------------------------------------
990 ---------------------------------------------------------------------
978
991
979 $ hg show stack --config extensions.show=
992 $ hg show stack --config extensions.show=
980 o 1553 added c
993 o 1553 added c
981 o 5f6d added b
994 o 5f6d added b
982 @ 9092 added a
995 @ 9092 added a
983
996
984 $ hg ci -m "branch closed" --close-branch
997 $ hg ci -m "branch closed" --close-branch
985 abort: can only close branch heads
998 abort: can only close branch heads
986 (use --force-close-branch to close branch from a non-head changeset)
999 (use --force-close-branch to close branch from a non-head changeset)
987 [10]
1000 [10]
988
1001
989 $ hg ci -m "branch closed" --force-close-branch
1002 $ hg ci -m "branch closed" --force-close-branch
990 created new head
1003 created new head
991 $ cd ..
1004 $ cd ..
992
1005
993 Test various special cases for the branchmap
1006 Test various special cases for the branchmap
994 --------------------------------------------
1007 --------------------------------------------
995
1008
996 Basic fork of the same branch
1009 Basic fork of the same branch
997
1010
998 $ hg init branchmap-testing1
1011 $ hg init branchmap-testing1
999 $ cd branchmap-testing1
1012 $ cd branchmap-testing1
1000 $ hg debugbuild '@A . :base . :p1 *base /p1'
1013 $ hg debugbuild '@A . :base . :p1 *base /p1'
1001 $ hg log -G
1014 $ hg log -G
1002 o changeset: 3:71ca9a6d524e
1015 o changeset: 3:71ca9a6d524e
1003 |\ branch: A
1016 |\ branch: A
1004 | | tag: tip
1017 | | tag: tip
1005 | | parent: 2:a3b807b3ff0b
1018 | | parent: 2:a3b807b3ff0b
1006 | | parent: 1:99ba08759bc7
1019 | | parent: 1:99ba08759bc7
1007 | | user: debugbuilddag
1020 | | user: debugbuilddag
1008 | | date: Thu Jan 01 00:00:03 1970 +0000
1021 | | date: Thu Jan 01 00:00:03 1970 +0000
1009 | | summary: r3
1022 | | summary: r3
1010 | |
1023 | |
1011 | o changeset: 2:a3b807b3ff0b
1024 | o changeset: 2:a3b807b3ff0b
1012 | | branch: A
1025 | | branch: A
1013 | | parent: 0:2ab8003a1750
1026 | | parent: 0:2ab8003a1750
1014 | | user: debugbuilddag
1027 | | user: debugbuilddag
1015 | | date: Thu Jan 01 00:00:02 1970 +0000
1028 | | date: Thu Jan 01 00:00:02 1970 +0000
1016 | | summary: r2
1029 | | summary: r2
1017 | |
1030 | |
1018 o | changeset: 1:99ba08759bc7
1031 o | changeset: 1:99ba08759bc7
1019 |/ branch: A
1032 |/ branch: A
1020 | tag: p1
1033 | tag: p1
1021 | user: debugbuilddag
1034 | user: debugbuilddag
1022 | date: Thu Jan 01 00:00:01 1970 +0000
1035 | date: Thu Jan 01 00:00:01 1970 +0000
1023 | summary: r1
1036 | summary: r1
1024 |
1037 |
1025 o changeset: 0:2ab8003a1750
1038 o changeset: 0:2ab8003a1750
1026 branch: A
1039 branch: A
1027 tag: base
1040 tag: base
1028 user: debugbuilddag
1041 user: debugbuilddag
1029 date: Thu Jan 01 00:00:00 1970 +0000
1042 date: Thu Jan 01 00:00:00 1970 +0000
1030 summary: r0
1043 summary: r0
1031
1044
1032 $ hg branches
1045 $ hg branches
1033 A 3:71ca9a6d524e
1046 A 3:71ca9a6d524e
1034 $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone
1047 $ hg clone -r 1 -r 2 . ../branchmap-testing1-clone
1035 adding changesets
1048 adding changesets
1036 adding manifests
1049 adding manifests
1037 adding file changes
1050 adding file changes
1038 added 3 changesets with 0 changes to 0 files (+1 heads)
1051 added 3 changesets with 0 changes to 0 files (+1 heads)
1039 new changesets 2ab8003a1750:a3b807b3ff0b
1052 new changesets 2ab8003a1750:a3b807b3ff0b
1040 updating to branch A
1053 updating to branch A
1041 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1054 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1042 $ cd ../branchmap-testing1-clone
1055 $ cd ../branchmap-testing1-clone
1043 $ hg pull ../branchmap-testing1
1056 $ hg pull ../branchmap-testing1
1044 pulling from ../branchmap-testing1
1057 pulling from ../branchmap-testing1
1045 searching for changes
1058 searching for changes
1046 adding changesets
1059 adding changesets
1047 adding manifests
1060 adding manifests
1048 adding file changes
1061 adding file changes
1049 added 1 changesets with 0 changes to 0 files (-1 heads)
1062 added 1 changesets with 0 changes to 0 files (-1 heads)
1050 new changesets 71ca9a6d524e
1063 new changesets 71ca9a6d524e
1051 (run 'hg update' to get a working copy)
1064 (run 'hg update' to get a working copy)
1052 $ hg branches
1065 $ hg branches
1053 A 3:71ca9a6d524e
1066 A 3:71ca9a6d524e
1054 $ cd ..
1067 $ cd ..
1055
1068
1056 Switching to a different branch and back
1069 Switching to a different branch and back
1057
1070
1058 $ hg init branchmap-testing2
1071 $ hg init branchmap-testing2
1059 $ cd branchmap-testing2
1072 $ cd branchmap-testing2
1060 $ hg debugbuild '@A . @B . @A .'
1073 $ hg debugbuild '@A . @B . @A .'
1061 $ hg log -G
1074 $ hg log -G
1062 o changeset: 2:9699e9f260b5
1075 o changeset: 2:9699e9f260b5
1063 | branch: A
1076 | branch: A
1064 | tag: tip
1077 | tag: tip
1065 | user: debugbuilddag
1078 | user: debugbuilddag
1066 | date: Thu Jan 01 00:00:02 1970 +0000
1079 | date: Thu Jan 01 00:00:02 1970 +0000
1067 | summary: r2
1080 | summary: r2
1068 |
1081 |
1069 o changeset: 1:0bc7d348d965
1082 o changeset: 1:0bc7d348d965
1070 | branch: B
1083 | branch: B
1071 | user: debugbuilddag
1084 | user: debugbuilddag
1072 | date: Thu Jan 01 00:00:01 1970 +0000
1085 | date: Thu Jan 01 00:00:01 1970 +0000
1073 | summary: r1
1086 | summary: r1
1074 |
1087 |
1075 o changeset: 0:2ab8003a1750
1088 o changeset: 0:2ab8003a1750
1076 branch: A
1089 branch: A
1077 user: debugbuilddag
1090 user: debugbuilddag
1078 date: Thu Jan 01 00:00:00 1970 +0000
1091 date: Thu Jan 01 00:00:00 1970 +0000
1079 summary: r0
1092 summary: r0
1080
1093
1081 $ hg branches
1094 $ hg branches
1082 A 2:9699e9f260b5
1095 A 2:9699e9f260b5
1083 B 1:0bc7d348d965 (inactive)
1096 B 1:0bc7d348d965 (inactive)
1084 $ hg clone -r 1 . ../branchmap-testing2-clone
1097 $ hg clone -r 1 . ../branchmap-testing2-clone
1085 adding changesets
1098 adding changesets
1086 adding manifests
1099 adding manifests
1087 adding file changes
1100 adding file changes
1088 added 2 changesets with 0 changes to 0 files
1101 added 2 changesets with 0 changes to 0 files
1089 new changesets 2ab8003a1750:0bc7d348d965
1102 new changesets 2ab8003a1750:0bc7d348d965
1090 updating to branch B
1103 updating to branch B
1091 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1104 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1092 $ cd ../branchmap-testing2-clone
1105 $ cd ../branchmap-testing2-clone
1093 $ hg pull ../branchmap-testing2
1106 $ hg pull ../branchmap-testing2
1094 pulling from ../branchmap-testing2
1107 pulling from ../branchmap-testing2
1095 searching for changes
1108 searching for changes
1096 adding changesets
1109 adding changesets
1097 adding manifests
1110 adding manifests
1098 adding file changes
1111 adding file changes
1099 added 1 changesets with 0 changes to 0 files
1112 added 1 changesets with 0 changes to 0 files
1100 new changesets 9699e9f260b5
1113 new changesets 9699e9f260b5
1101 (run 'hg update' to get a working copy)
1114 (run 'hg update' to get a working copy)
1102 $ hg branches
1115 $ hg branches
1103 A 2:9699e9f260b5
1116 A 2:9699e9f260b5
1104 B 1:0bc7d348d965 (inactive)
1117 B 1:0bc7d348d965 (inactive)
1105 $ cd ..
1118 $ cd ..
1106
1119
1107 A fork on a branch switching to a different branch and back
1120 A fork on a branch switching to a different branch and back
1108 is still collecting the fork.
1121 is still collecting the fork.
1109
1122
1110 $ hg init branchmap-testing3
1123 $ hg init branchmap-testing3
1111 $ cd branchmap-testing3
1124 $ cd branchmap-testing3
1112 $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1'
1125 $ hg debugbuild '@A . :base . :p1 *base @B . @A /p1'
1113 $ hg log -G
1126 $ hg log -G
1114 o changeset: 4:3614a1711d23
1127 o changeset: 4:3614a1711d23
1115 |\ branch: A
1128 |\ branch: A
1116 | | tag: tip
1129 | | tag: tip
1117 | | parent: 3:e9c8abcf65aa
1130 | | parent: 3:e9c8abcf65aa
1118 | | parent: 1:99ba08759bc7
1131 | | parent: 1:99ba08759bc7
1119 | | user: debugbuilddag
1132 | | user: debugbuilddag
1120 | | date: Thu Jan 01 00:00:04 1970 +0000
1133 | | date: Thu Jan 01 00:00:04 1970 +0000
1121 | | summary: r4
1134 | | summary: r4
1122 | |
1135 | |
1123 | o changeset: 3:e9c8abcf65aa
1136 | o changeset: 3:e9c8abcf65aa
1124 | | branch: B
1137 | | branch: B
1125 | | user: debugbuilddag
1138 | | user: debugbuilddag
1126 | | date: Thu Jan 01 00:00:03 1970 +0000
1139 | | date: Thu Jan 01 00:00:03 1970 +0000
1127 | | summary: r3
1140 | | summary: r3
1128 | |
1141 | |
1129 | o changeset: 2:a3b807b3ff0b
1142 | o changeset: 2:a3b807b3ff0b
1130 | | branch: A
1143 | | branch: A
1131 | | parent: 0:2ab8003a1750
1144 | | parent: 0:2ab8003a1750
1132 | | user: debugbuilddag
1145 | | user: debugbuilddag
1133 | | date: Thu Jan 01 00:00:02 1970 +0000
1146 | | date: Thu Jan 01 00:00:02 1970 +0000
1134 | | summary: r2
1147 | | summary: r2
1135 | |
1148 | |
1136 o | changeset: 1:99ba08759bc7
1149 o | changeset: 1:99ba08759bc7
1137 |/ branch: A
1150 |/ branch: A
1138 | tag: p1
1151 | tag: p1
1139 | user: debugbuilddag
1152 | user: debugbuilddag
1140 | date: Thu Jan 01 00:00:01 1970 +0000
1153 | date: Thu Jan 01 00:00:01 1970 +0000
1141 | summary: r1
1154 | summary: r1
1142 |
1155 |
1143 o changeset: 0:2ab8003a1750
1156 o changeset: 0:2ab8003a1750
1144 branch: A
1157 branch: A
1145 tag: base
1158 tag: base
1146 user: debugbuilddag
1159 user: debugbuilddag
1147 date: Thu Jan 01 00:00:00 1970 +0000
1160 date: Thu Jan 01 00:00:00 1970 +0000
1148 summary: r0
1161 summary: r0
1149
1162
1150 $ hg branches
1163 $ hg branches
1151 A 4:3614a1711d23
1164 A 4:3614a1711d23
1152 B 3:e9c8abcf65aa (inactive)
1165 B 3:e9c8abcf65aa (inactive)
1153 $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone
1166 $ hg clone -r 1 -r 3 . ../branchmap-testing3-clone
1154 adding changesets
1167 adding changesets
1155 adding manifests
1168 adding manifests
1156 adding file changes
1169 adding file changes
1157 added 4 changesets with 0 changes to 0 files (+1 heads)
1170 added 4 changesets with 0 changes to 0 files (+1 heads)
1158 new changesets 2ab8003a1750:e9c8abcf65aa
1171 new changesets 2ab8003a1750:e9c8abcf65aa
1159 updating to branch A
1172 updating to branch A
1160 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1173 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1161 $ cd ../branchmap-testing3-clone
1174 $ cd ../branchmap-testing3-clone
1162 $ hg pull ../branchmap-testing3
1175 $ hg pull ../branchmap-testing3
1163 pulling from ../branchmap-testing3
1176 pulling from ../branchmap-testing3
1164 searching for changes
1177 searching for changes
1165 adding changesets
1178 adding changesets
1166 adding manifests
1179 adding manifests
1167 adding file changes
1180 adding file changes
1168 added 1 changesets with 0 changes to 0 files (-1 heads)
1181 added 1 changesets with 0 changes to 0 files (-1 heads)
1169 new changesets 3614a1711d23
1182 new changesets 3614a1711d23
1170 (run 'hg update' to get a working copy)
1183 (run 'hg update' to get a working copy)
1171 $ hg branches
1184 $ hg branches
1172 A 4:3614a1711d23
1185 A 4:3614a1711d23
1173 B 3:e9c8abcf65aa (inactive)
1186 B 3:e9c8abcf65aa (inactive)
1174 $ cd ..
1187 $ cd ..
1175
1188
1176 Intermediary parents are on different branches.
1189 Intermediary parents are on different branches.
1177
1190
1178 $ hg init branchmap-testing4
1191 $ hg init branchmap-testing4
1179 $ cd branchmap-testing4
1192 $ cd branchmap-testing4
1180 $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1'
1193 $ hg debugbuild '@A . @B :base . @A :p1 *base @C . @A /p1'
1181 $ hg log -G
1194 $ hg log -G
1182 o changeset: 4:4bf67499b70a
1195 o changeset: 4:4bf67499b70a
1183 |\ branch: A
1196 |\ branch: A
1184 | | tag: tip
1197 | | tag: tip
1185 | | parent: 3:4a546028fa8f
1198 | | parent: 3:4a546028fa8f
1186 | | parent: 1:0bc7d348d965
1199 | | parent: 1:0bc7d348d965
1187 | | user: debugbuilddag
1200 | | user: debugbuilddag
1188 | | date: Thu Jan 01 00:00:04 1970 +0000
1201 | | date: Thu Jan 01 00:00:04 1970 +0000
1189 | | summary: r4
1202 | | summary: r4
1190 | |
1203 | |
1191 | o changeset: 3:4a546028fa8f
1204 | o changeset: 3:4a546028fa8f
1192 | | branch: C
1205 | | branch: C
1193 | | user: debugbuilddag
1206 | | user: debugbuilddag
1194 | | date: Thu Jan 01 00:00:03 1970 +0000
1207 | | date: Thu Jan 01 00:00:03 1970 +0000
1195 | | summary: r3
1208 | | summary: r3
1196 | |
1209 | |
1197 | o changeset: 2:a3b807b3ff0b
1210 | o changeset: 2:a3b807b3ff0b
1198 | | branch: A
1211 | | branch: A
1199 | | parent: 0:2ab8003a1750
1212 | | parent: 0:2ab8003a1750
1200 | | user: debugbuilddag
1213 | | user: debugbuilddag
1201 | | date: Thu Jan 01 00:00:02 1970 +0000
1214 | | date: Thu Jan 01 00:00:02 1970 +0000
1202 | | summary: r2
1215 | | summary: r2
1203 | |
1216 | |
1204 o | changeset: 1:0bc7d348d965
1217 o | changeset: 1:0bc7d348d965
1205 |/ branch: B
1218 |/ branch: B
1206 | tag: p1
1219 | tag: p1
1207 | user: debugbuilddag
1220 | user: debugbuilddag
1208 | date: Thu Jan 01 00:00:01 1970 +0000
1221 | date: Thu Jan 01 00:00:01 1970 +0000
1209 | summary: r1
1222 | summary: r1
1210 |
1223 |
1211 o changeset: 0:2ab8003a1750
1224 o changeset: 0:2ab8003a1750
1212 branch: A
1225 branch: A
1213 tag: base
1226 tag: base
1214 user: debugbuilddag
1227 user: debugbuilddag
1215 date: Thu Jan 01 00:00:00 1970 +0000
1228 date: Thu Jan 01 00:00:00 1970 +0000
1216 summary: r0
1229 summary: r0
1217
1230
1218 $ hg branches
1231 $ hg branches
1219 A 4:4bf67499b70a
1232 A 4:4bf67499b70a
1220 C 3:4a546028fa8f (inactive)
1233 C 3:4a546028fa8f (inactive)
1221 B 1:0bc7d348d965 (inactive)
1234 B 1:0bc7d348d965 (inactive)
1222 $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone
1235 $ hg clone -r 1 -r 3 . ../branchmap-testing4-clone
1223 adding changesets
1236 adding changesets
1224 adding manifests
1237 adding manifests
1225 adding file changes
1238 adding file changes
1226 added 4 changesets with 0 changes to 0 files (+1 heads)
1239 added 4 changesets with 0 changes to 0 files (+1 heads)
1227 new changesets 2ab8003a1750:4a546028fa8f
1240 new changesets 2ab8003a1750:4a546028fa8f
1228 updating to branch B
1241 updating to branch B
1229 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1242 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1230 $ cd ../branchmap-testing4-clone
1243 $ cd ../branchmap-testing4-clone
1231 $ hg pull ../branchmap-testing4
1244 $ hg pull ../branchmap-testing4
1232 pulling from ../branchmap-testing4
1245 pulling from ../branchmap-testing4
1233 searching for changes
1246 searching for changes
1234 adding changesets
1247 adding changesets
1235 adding manifests
1248 adding manifests
1236 adding file changes
1249 adding file changes
1237 added 1 changesets with 0 changes to 0 files (-1 heads)
1250 added 1 changesets with 0 changes to 0 files (-1 heads)
1238 new changesets 4bf67499b70a
1251 new changesets 4bf67499b70a
1239 (run 'hg update' to get a working copy)
1252 (run 'hg update' to get a working copy)
1240 $ hg branches
1253 $ hg branches
1241 A 4:4bf67499b70a
1254 A 4:4bf67499b70a
1242 C 3:4a546028fa8f (inactive)
1255 C 3:4a546028fa8f (inactive)
1243 B 1:0bc7d348d965 (inactive)
1256 B 1:0bc7d348d965 (inactive)
1244 $ cd ..
1257 $ cd ..
1245
1258
1246 Check that the cache are not written too early
1259 Check that the cache are not written too early
1247 ----------------------------------------------
1260 ----------------------------------------------
1248
1261
1249 $ hg log -R branchmap-testing1 -G
1262 $ hg log -R branchmap-testing1 -G
1250 o changeset: 3:71ca9a6d524e
1263 o changeset: 3:71ca9a6d524e
1251 |\ branch: A
1264 |\ branch: A
1252 | | tag: tip
1265 | | tag: tip
1253 | | parent: 2:a3b807b3ff0b
1266 | | parent: 2:a3b807b3ff0b
1254 | | parent: 1:99ba08759bc7
1267 | | parent: 1:99ba08759bc7
1255 | | user: debugbuilddag
1268 | | user: debugbuilddag
1256 | | date: Thu Jan 01 00:00:03 1970 +0000
1269 | | date: Thu Jan 01 00:00:03 1970 +0000
1257 | | summary: r3
1270 | | summary: r3
1258 | |
1271 | |
1259 | o changeset: 2:a3b807b3ff0b
1272 | o changeset: 2:a3b807b3ff0b
1260 | | branch: A
1273 | | branch: A
1261 | | parent: 0:2ab8003a1750
1274 | | parent: 0:2ab8003a1750
1262 | | user: debugbuilddag
1275 | | user: debugbuilddag
1263 | | date: Thu Jan 01 00:00:02 1970 +0000
1276 | | date: Thu Jan 01 00:00:02 1970 +0000
1264 | | summary: r2
1277 | | summary: r2
1265 | |
1278 | |
1266 o | changeset: 1:99ba08759bc7
1279 o | changeset: 1:99ba08759bc7
1267 |/ branch: A
1280 |/ branch: A
1268 | tag: p1
1281 | tag: p1
1269 | user: debugbuilddag
1282 | user: debugbuilddag
1270 | date: Thu Jan 01 00:00:01 1970 +0000
1283 | date: Thu Jan 01 00:00:01 1970 +0000
1271 | summary: r1
1284 | summary: r1
1272 |
1285 |
1273 o changeset: 0:2ab8003a1750
1286 o changeset: 0:2ab8003a1750
1274 branch: A
1287 branch: A
1275 tag: base
1288 tag: base
1276 user: debugbuilddag
1289 user: debugbuilddag
1277 date: Thu Jan 01 00:00:00 1970 +0000
1290 date: Thu Jan 01 00:00:00 1970 +0000
1278 summary: r0
1291 summary: r0
1279
1292
1280 $ hg bundle -R branchmap-testing1 --base 1 bundle.hg --rev 'head()'
1293 $ hg bundle -R branchmap-testing1 --base 1 bundle.hg --rev 'head()'
1281 2 changesets found
1294 2 changesets found
1282
1295
1283 Unbundling revision should warm the served cache
1296 Unbundling revision should warm the served cache
1284
1297
1285 $ hg clone branchmap-testing1 --rev 1 branchmap-update-01
1298 $ hg clone branchmap-testing1 --rev 1 branchmap-update-01
1286 adding changesets
1299 adding changesets
1287 adding manifests
1300 adding manifests
1288 adding file changes
1301 adding file changes
1289 added 2 changesets with 0 changes to 0 files
1302 added 2 changesets with 0 changes to 0 files
1290 new changesets 2ab8003a1750:99ba08759bc7
1303 new changesets 2ab8003a1750:99ba08759bc7
1291 updating to branch A
1304 updating to branch A
1292 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1305 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1293 $ cat branchmap-update-01/.hg/cache/branch2-served
1306 $ cat branchmap-update-01/.hg/cache/branch2-served
1294 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1307 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1295 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1308 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1296 $ hg -R branchmap-update-01 unbundle bundle.hg
1309 $ hg -R branchmap-update-01 unbundle bundle.hg
1297 adding changesets
1310 adding changesets
1298 adding manifests
1311 adding manifests
1299 adding file changes
1312 adding file changes
1300 added 2 changesets with 0 changes to 0 files
1313 added 2 changesets with 0 changes to 0 files
1301 new changesets a3b807b3ff0b:71ca9a6d524e (2 drafts)
1314 new changesets a3b807b3ff0b:71ca9a6d524e (2 drafts)
1302 (run 'hg update' to get a working copy)
1315 (run 'hg update' to get a working copy)
1303 $ cat branchmap-update-01/.hg/cache/branch2-served
1316 $ cat branchmap-update-01/.hg/cache/branch2-served
1304 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 3
1317 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 3
1305 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 o A
1318 71ca9a6d524ed3c2a215119b2086ac3b8c4c8286 o A
1306
1319
1307 aborted Unbundle should not update the on disk cache
1320 aborted Unbundle should not update the on disk cache
1308
1321
1309 $ cat >> simplehook.py << EOF
1322 $ cat >> simplehook.py << EOF
1310 > import sys
1323 > import sys
1311 > from mercurial import node
1324 > from mercurial import node
1312 > from mercurial import branchmap
1325 > from mercurial import branchmap
1313 > def hook(ui, repo, *args, **kwargs):
1326 > def hook(ui, repo, *args, **kwargs):
1314 > s = repo.filtered(b"served")
1327 > s = repo.filtered(b"served")
1315 > s.branchmap()
1328 > s.branchmap()
1316 > return 1
1329 > return 1
1317 > EOF
1330 > EOF
1318 $ hg clone branchmap-testing1 --rev 1 branchmap-update-02
1331 $ hg clone branchmap-testing1 --rev 1 branchmap-update-02
1319 adding changesets
1332 adding changesets
1320 adding manifests
1333 adding manifests
1321 adding file changes
1334 adding file changes
1322 added 2 changesets with 0 changes to 0 files
1335 added 2 changesets with 0 changes to 0 files
1323 new changesets 2ab8003a1750:99ba08759bc7
1336 new changesets 2ab8003a1750:99ba08759bc7
1324 updating to branch A
1337 updating to branch A
1325 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1338 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1326
1339
1327 $ cat branchmap-update-02/.hg/cache/branch2-served
1340 $ cat branchmap-update-02/.hg/cache/branch2-served
1328 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1341 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1329 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1342 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1330 $ hg -R branchmap-update-02 unbundle bundle.hg --config "hooks.pretxnclose=python:$TESTTMP/simplehook.py:hook"
1343 $ hg -R branchmap-update-02 unbundle bundle.hg --config "hooks.pretxnclose=python:$TESTTMP/simplehook.py:hook"
1331 adding changesets
1344 adding changesets
1332 adding manifests
1345 adding manifests
1333 adding file changes
1346 adding file changes
1334 transaction abort!
1347 transaction abort!
1335 rollback completed
1348 rollback completed
1336 abort: pretxnclose hook failed
1349 abort: pretxnclose hook failed
1337 [40]
1350 [40]
1338 $ cat branchmap-update-02/.hg/cache/branch2-served
1351 $ cat branchmap-update-02/.hg/cache/branch2-served
1339 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1352 99ba08759bc7f6fdbe5304e83d0387f35c082479 1
1340 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
1353 99ba08759bc7f6fdbe5304e83d0387f35c082479 o A
General Comments 0
You need to be logged in to leave comments. Login now