##// END OF EJS Templates
grep: move readfile() to grepsearcher class
Yuya Nishihara -
r46291:888e633f default
parent child Browse files
Show More
@@ -1,7763 +1,7743 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 copies,
31 copies,
32 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 discovery,
35 discovery,
36 encoding,
36 encoding,
37 error,
37 error,
38 exchange,
38 exchange,
39 extensions,
39 extensions,
40 filemerge,
40 filemerge,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 grep as grepmod,
43 grep as grepmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 match as matchmod,
48 match as matchmod,
49 merge as mergemod,
49 merge as mergemod,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 narrowspec,
51 narrowspec,
52 obsolete,
52 obsolete,
53 obsutil,
53 obsutil,
54 patch,
54 patch,
55 phases,
55 phases,
56 pycompat,
56 pycompat,
57 rcutil,
57 rcutil,
58 registrar,
58 registrar,
59 requirements,
59 requirements,
60 revsetlang,
60 revsetlang,
61 rewriteutil,
61 rewriteutil,
62 scmutil,
62 scmutil,
63 server,
63 server,
64 shelve as shelvemod,
64 shelve as shelvemod,
65 state as statemod,
65 state as statemod,
66 streamclone,
66 streamclone,
67 tags as tagsmod,
67 tags as tagsmod,
68 ui as uimod,
68 ui as uimod,
69 util,
69 util,
70 verify as verifymod,
70 verify as verifymod,
71 vfs as vfsmod,
71 vfs as vfsmod,
72 wireprotoserver,
72 wireprotoserver,
73 )
73 )
74 from .utils import (
74 from .utils import (
75 dateutil,
75 dateutil,
76 stringutil,
76 stringutil,
77 )
77 )
78
78
79 table = {}
79 table = {}
80 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
81
81
82 command = registrar.command(table)
82 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
83 INTENT_READONLY = registrar.INTENT_READONLY
84
84
85 # common command options
85 # common command options
86
86
87 globalopts = [
87 globalopts = [
88 (
88 (
89 b'R',
89 b'R',
90 b'repository',
90 b'repository',
91 b'',
91 b'',
92 _(b'repository root directory or name of overlay bundle file'),
92 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
93 _(b'REPO'),
94 ),
94 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
96 (
97 b'y',
97 b'y',
98 b'noninteractive',
98 b'noninteractive',
99 None,
99 None,
100 _(
100 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
101 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
102 ),
103 ),
103 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
106 (
107 b'',
107 b'',
108 b'color',
108 b'color',
109 b'',
109 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
111 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
113 _(b'TYPE'),
114 ),
114 ),
115 (
115 (
116 b'',
116 b'',
117 b'config',
117 b'config',
118 [],
118 [],
119 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
120 _(b'CONFIG'),
121 ),
121 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
123 (b'', b'debugger', None, _(b'start debugger')),
124 (
124 (
125 b'',
125 b'',
126 b'encoding',
126 b'encoding',
127 encoding.encoding,
127 encoding.encoding,
128 _(b'set the charset encoding'),
128 _(b'set the charset encoding'),
129 _(b'ENCODE'),
129 _(b'ENCODE'),
130 ),
130 ),
131 (
131 (
132 b'',
132 b'',
133 b'encodingmode',
133 b'encodingmode',
134 encoding.encodingmode,
134 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
135 _(b'set the charset encoding mode'),
136 _(b'MODE'),
136 _(b'MODE'),
137 ),
137 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
141 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
144 (
145 b'',
145 b'',
146 b'pager',
146 b'pager',
147 b'auto',
147 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
149 _(b'TYPE'),
150 ),
150 ),
151 ]
151 ]
152
152
153 dryrunopts = cmdutil.dryrunopts
153 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
154 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
155 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
156 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
157 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
158 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
159 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
160 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
161 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
162 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
163 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
164 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
165 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
166 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
167 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
168 debugrevlogopts = cmdutil.debugrevlogopts
169
169
170 # Commands start here, listed alphabetically
170 # Commands start here, listed alphabetically
171
171
172
172
173 @command(
173 @command(
174 b'abort',
174 b'abort',
175 dryrunopts,
175 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
177 helpbasic=True,
178 )
178 )
179 def abort(ui, repo, **opts):
179 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
180 """abort an unfinished operation (EXPERIMENTAL)
181
181
182 Aborts a multistep operation like graft, histedit, rebase, merge,
182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
183 and unshelve if they are in an unfinished state.
184
184
185 use --dry-run/-n to dry run the command.
185 use --dry-run/-n to dry run the command.
186 """
186 """
187 dryrun = opts.get('dry_run')
187 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
188 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
189 if not abortstate:
190 raise error.Abort(_(b'no operation in progress'))
190 raise error.Abort(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
191 if not abortstate.abortfunc:
192 raise error.Abort(
192 raise error.Abort(
193 (
193 (
194 _(b"%s in progress but does not support 'hg abort'")
194 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
195 % (abortstate._opname)
196 ),
196 ),
197 hint=abortstate.hint(),
197 hint=abortstate.hint(),
198 )
198 )
199 if dryrun:
199 if dryrun:
200 ui.status(
200 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
202 )
203 return
203 return
204 return abortstate.abortfunc(ui, repo)
204 return abortstate.abortfunc(ui, repo)
205
205
206
206
207 @command(
207 @command(
208 b'add',
208 b'add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
210 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
212 helpbasic=True,
213 inferrepo=True,
213 inferrepo=True,
214 )
214 )
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 relative = scmutil.anypats(pats, opts)
337 relative = scmutil.anypats(pats, opts)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340
340
341
341
342 @command(
342 @command(
343 b'annotate|blame',
343 b'annotate|blame',
344 [
344 [
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (
346 (
347 b'',
347 b'',
348 b'follow',
348 b'follow',
349 None,
349 None,
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 ),
351 ),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'f', b'file', None, _(b'list the filename')),
355 (b'f', b'file', None, _(b'list the filename')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
359 (
359 (
360 b'l',
360 b'l',
361 b'line-number',
361 b'line-number',
362 None,
362 None,
363 _(b'show line number at the first appearance'),
363 _(b'show line number at the first appearance'),
364 ),
364 ),
365 (
365 (
366 b'',
366 b'',
367 b'skip',
367 b'skip',
368 [],
368 [],
369 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'REV'),
370 _(b'REV'),
371 ),
371 ),
372 ]
372 ]
373 + diffwsopts
373 + diffwsopts
374 + walkopts
374 + walkopts
375 + formatteropts,
375 + formatteropts,
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpbasic=True,
378 helpbasic=True,
379 inferrepo=True,
379 inferrepo=True,
380 )
380 )
381 def annotate(ui, repo, *pats, **opts):
381 def annotate(ui, repo, *pats, **opts):
382 """show changeset information by line for each file
382 """show changeset information by line for each file
383
383
384 List changes in files, showing the revision id responsible for
384 List changes in files, showing the revision id responsible for
385 each line.
385 each line.
386
386
387 This command is useful for discovering when a change was made and
387 This command is useful for discovering when a change was made and
388 by whom.
388 by whom.
389
389
390 If you include --file, --user, or --date, the revision number is
390 If you include --file, --user, or --date, the revision number is
391 suppressed unless you also include --number.
391 suppressed unless you also include --number.
392
392
393 Without the -a/--text option, annotate will avoid processing files
393 Without the -a/--text option, annotate will avoid processing files
394 it detects as binary. With -a, annotate will annotate the file
394 it detects as binary. With -a, annotate will annotate the file
395 anyway, although the results will probably be neither useful
395 anyway, although the results will probably be neither useful
396 nor desirable.
396 nor desirable.
397
397
398 .. container:: verbose
398 .. container:: verbose
399
399
400 Template:
400 Template:
401
401
402 The following keywords are supported in addition to the common template
402 The following keywords are supported in addition to the common template
403 keywords and functions. See also :hg:`help templates`.
403 keywords and functions. See also :hg:`help templates`.
404
404
405 :lines: List of lines with annotation data.
405 :lines: List of lines with annotation data.
406 :path: String. Repository-absolute path of the specified file.
406 :path: String. Repository-absolute path of the specified file.
407
407
408 And each entry of ``{lines}`` provides the following sub-keywords in
408 And each entry of ``{lines}`` provides the following sub-keywords in
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410
410
411 :line: String. Line content.
411 :line: String. Line content.
412 :lineno: Integer. Line number at that revision.
412 :lineno: Integer. Line number at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
414
414
415 See :hg:`help templates.operators` for the list expansion syntax.
415 See :hg:`help templates.operators` for the list expansion syntax.
416
416
417 Returns 0 on success.
417 Returns 0 on success.
418 """
418 """
419 opts = pycompat.byteskwargs(opts)
419 opts = pycompat.byteskwargs(opts)
420 if not pats:
420 if not pats:
421 raise error.Abort(_(b'at least one filename or pattern is required'))
421 raise error.Abort(_(b'at least one filename or pattern is required'))
422
422
423 if opts.get(b'follow'):
423 if opts.get(b'follow'):
424 # --follow is deprecated and now just an alias for -f/--file
424 # --follow is deprecated and now just an alias for -f/--file
425 # to mimic the behavior of Mercurial before version 1.5
425 # to mimic the behavior of Mercurial before version 1.5
426 opts[b'file'] = True
426 opts[b'file'] = True
427
427
428 if (
428 if (
429 not opts.get(b'user')
429 not opts.get(b'user')
430 and not opts.get(b'changeset')
430 and not opts.get(b'changeset')
431 and not opts.get(b'date')
431 and not opts.get(b'date')
432 and not opts.get(b'file')
432 and not opts.get(b'file')
433 ):
433 ):
434 opts[b'number'] = True
434 opts[b'number'] = True
435
435
436 linenumber = opts.get(b'line_number') is not None
436 linenumber = opts.get(b'line_number') is not None
437 if (
437 if (
438 linenumber
438 linenumber
439 and (not opts.get(b'changeset'))
439 and (not opts.get(b'changeset'))
440 and (not opts.get(b'number'))
440 and (not opts.get(b'number'))
441 ):
441 ):
442 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
442 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
443
443
444 rev = opts.get(b'rev')
444 rev = opts.get(b'rev')
445 if rev:
445 if rev:
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 ctx = scmutil.revsingle(repo, rev)
447 ctx = scmutil.revsingle(repo, rev)
448
448
449 ui.pager(b'annotate')
449 ui.pager(b'annotate')
450 rootfm = ui.formatter(b'annotate', opts)
450 rootfm = ui.formatter(b'annotate', opts)
451 if ui.debugflag:
451 if ui.debugflag:
452 shorthex = pycompat.identity
452 shorthex = pycompat.identity
453 else:
453 else:
454
454
455 def shorthex(h):
455 def shorthex(h):
456 return h[:12]
456 return h[:12]
457
457
458 if ui.quiet:
458 if ui.quiet:
459 datefunc = dateutil.shortdate
459 datefunc = dateutil.shortdate
460 else:
460 else:
461 datefunc = dateutil.datestr
461 datefunc = dateutil.datestr
462 if ctx.rev() is None:
462 if ctx.rev() is None:
463 if opts.get(b'changeset'):
463 if opts.get(b'changeset'):
464 # omit "+" suffix which is appended to node hex
464 # omit "+" suffix which is appended to node hex
465 def formatrev(rev):
465 def formatrev(rev):
466 if rev == wdirrev:
466 if rev == wdirrev:
467 return b'%d' % ctx.p1().rev()
467 return b'%d' % ctx.p1().rev()
468 else:
468 else:
469 return b'%d' % rev
469 return b'%d' % rev
470
470
471 else:
471 else:
472
472
473 def formatrev(rev):
473 def formatrev(rev):
474 if rev == wdirrev:
474 if rev == wdirrev:
475 return b'%d+' % ctx.p1().rev()
475 return b'%d+' % ctx.p1().rev()
476 else:
476 else:
477 return b'%d ' % rev
477 return b'%d ' % rev
478
478
479 def formathex(h):
479 def formathex(h):
480 if h == wdirhex:
480 if h == wdirhex:
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 else:
482 else:
483 return b'%s ' % shorthex(h)
483 return b'%s ' % shorthex(h)
484
484
485 else:
485 else:
486 formatrev = b'%d'.__mod__
486 formatrev = b'%d'.__mod__
487 formathex = shorthex
487 formathex = shorthex
488
488
489 opmap = [
489 opmap = [
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 ]
496 ]
497 opnamemap = {
497 opnamemap = {
498 b'rev': b'number',
498 b'rev': b'number',
499 b'node': b'changeset',
499 b'node': b'changeset',
500 b'path': b'file',
500 b'path': b'file',
501 b'lineno': b'line_number',
501 b'lineno': b'line_number',
502 }
502 }
503
503
504 if rootfm.isplain():
504 if rootfm.isplain():
505
505
506 def makefunc(get, fmt):
506 def makefunc(get, fmt):
507 return lambda x: fmt(get(x))
507 return lambda x: fmt(get(x))
508
508
509 else:
509 else:
510
510
511 def makefunc(get, fmt):
511 def makefunc(get, fmt):
512 return get
512 return get
513
513
514 datahint = rootfm.datahint()
514 datahint = rootfm.datahint()
515 funcmap = [
515 funcmap = [
516 (makefunc(get, fmt), sep)
516 (makefunc(get, fmt), sep)
517 for fn, sep, get, fmt in opmap
517 for fn, sep, get, fmt in opmap
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 ]
519 ]
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 fields = b' '.join(
521 fields = b' '.join(
522 fn
522 fn
523 for fn, sep, get, fmt in opmap
523 for fn, sep, get, fmt in opmap
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 )
525 )
526
526
527 def bad(x, y):
527 def bad(x, y):
528 raise error.Abort(b"%s: %s" % (x, y))
528 raise error.Abort(b"%s: %s" % (x, y))
529
529
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
531
531
532 follow = not opts.get(b'no_follow')
532 follow = not opts.get(b'no_follow')
533 diffopts = patch.difffeatureopts(
533 diffopts = patch.difffeatureopts(
534 ui, opts, section=b'annotate', whitespace=True
534 ui, opts, section=b'annotate', whitespace=True
535 )
535 )
536 skiprevs = opts.get(b'skip')
536 skiprevs = opts.get(b'skip')
537 if skiprevs:
537 if skiprevs:
538 skiprevs = scmutil.revrange(repo, skiprevs)
538 skiprevs = scmutil.revrange(repo, skiprevs)
539
539
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 for abs in ctx.walk(m):
541 for abs in ctx.walk(m):
542 fctx = ctx[abs]
542 fctx = ctx[abs]
543 rootfm.startitem()
543 rootfm.startitem()
544 rootfm.data(path=abs)
544 rootfm.data(path=abs)
545 if not opts.get(b'text') and fctx.isbinary():
545 if not opts.get(b'text') and fctx.isbinary():
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 continue
547 continue
548
548
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 lines = fctx.annotate(
550 lines = fctx.annotate(
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 )
552 )
553 if not lines:
553 if not lines:
554 fm.end()
554 fm.end()
555 continue
555 continue
556 formats = []
556 formats = []
557 pieces = []
557 pieces = []
558
558
559 for f, sep in funcmap:
559 for f, sep in funcmap:
560 l = [f(n) for n in lines]
560 l = [f(n) for n in lines]
561 if fm.isplain():
561 if fm.isplain():
562 sizes = [encoding.colwidth(x) for x in l]
562 sizes = [encoding.colwidth(x) for x in l]
563 ml = max(sizes)
563 ml = max(sizes)
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 else:
565 else:
566 formats.append([b'%s'] * len(l))
566 formats.append([b'%s'] * len(l))
567 pieces.append(l)
567 pieces.append(l)
568
568
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 fm.startitem()
570 fm.startitem()
571 fm.context(fctx=n.fctx)
571 fm.context(fctx=n.fctx)
572 fm.write(fields, b"".join(f), *p)
572 fm.write(fields, b"".join(f), *p)
573 if n.skip:
573 if n.skip:
574 fmt = b"* %s"
574 fmt = b"* %s"
575 else:
575 else:
576 fmt = b": %s"
576 fmt = b": %s"
577 fm.write(b'line', fmt, n.text)
577 fm.write(b'line', fmt, n.text)
578
578
579 if not lines[-1].text.endswith(b'\n'):
579 if not lines[-1].text.endswith(b'\n'):
580 fm.plain(b'\n')
580 fm.plain(b'\n')
581 fm.end()
581 fm.end()
582
582
583 rootfm.end()
583 rootfm.end()
584
584
585
585
586 @command(
586 @command(
587 b'archive',
587 b'archive',
588 [
588 [
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (
590 (
591 b'p',
591 b'p',
592 b'prefix',
592 b'prefix',
593 b'',
593 b'',
594 _(b'directory prefix for files in archive'),
594 _(b'directory prefix for files in archive'),
595 _(b'PREFIX'),
595 _(b'PREFIX'),
596 ),
596 ),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
598 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
599 ]
599 ]
600 + subrepoopts
600 + subrepoopts
601 + walkopts,
601 + walkopts,
602 _(b'[OPTION]... DEST'),
602 _(b'[OPTION]... DEST'),
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 )
604 )
605 def archive(ui, repo, dest, **opts):
605 def archive(ui, repo, dest, **opts):
606 '''create an unversioned archive of a repository revision
606 '''create an unversioned archive of a repository revision
607
607
608 By default, the revision used is the parent of the working
608 By default, the revision used is the parent of the working
609 directory; use -r/--rev to specify a different revision.
609 directory; use -r/--rev to specify a different revision.
610
610
611 The archive type is automatically detected based on file
611 The archive type is automatically detected based on file
612 extension (to override, use -t/--type).
612 extension (to override, use -t/--type).
613
613
614 .. container:: verbose
614 .. container:: verbose
615
615
616 Examples:
616 Examples:
617
617
618 - create a zip file containing the 1.0 release::
618 - create a zip file containing the 1.0 release::
619
619
620 hg archive -r 1.0 project-1.0.zip
620 hg archive -r 1.0 project-1.0.zip
621
621
622 - create a tarball excluding .hg files::
622 - create a tarball excluding .hg files::
623
623
624 hg archive project.tar.gz -X ".hg*"
624 hg archive project.tar.gz -X ".hg*"
625
625
626 Valid types are:
626 Valid types are:
627
627
628 :``files``: a directory full of files (default)
628 :``files``: a directory full of files (default)
629 :``tar``: tar archive, uncompressed
629 :``tar``: tar archive, uncompressed
630 :``tbz2``: tar archive, compressed using bzip2
630 :``tbz2``: tar archive, compressed using bzip2
631 :``tgz``: tar archive, compressed using gzip
631 :``tgz``: tar archive, compressed using gzip
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``uzip``: zip archive, uncompressed
633 :``uzip``: zip archive, uncompressed
634 :``zip``: zip archive, compressed using deflate
634 :``zip``: zip archive, compressed using deflate
635
635
636 The exact name of the destination archive or directory is given
636 The exact name of the destination archive or directory is given
637 using a format string; see :hg:`help export` for details.
637 using a format string; see :hg:`help export` for details.
638
638
639 Each member added to an archive file has a directory prefix
639 Each member added to an archive file has a directory prefix
640 prepended. Use -p/--prefix to specify a format string for the
640 prepended. Use -p/--prefix to specify a format string for the
641 prefix. The default is the basename of the archive, with suffixes
641 prefix. The default is the basename of the archive, with suffixes
642 removed.
642 removed.
643
643
644 Returns 0 on success.
644 Returns 0 on success.
645 '''
645 '''
646
646
647 opts = pycompat.byteskwargs(opts)
647 opts = pycompat.byteskwargs(opts)
648 rev = opts.get(b'rev')
648 rev = opts.get(b'rev')
649 if rev:
649 if rev:
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 ctx = scmutil.revsingle(repo, rev)
651 ctx = scmutil.revsingle(repo, rev)
652 if not ctx:
652 if not ctx:
653 raise error.Abort(_(b'no working directory: please specify a revision'))
653 raise error.Abort(_(b'no working directory: please specify a revision'))
654 node = ctx.node()
654 node = ctx.node()
655 dest = cmdutil.makefilename(ctx, dest)
655 dest = cmdutil.makefilename(ctx, dest)
656 if os.path.realpath(dest) == repo.root:
656 if os.path.realpath(dest) == repo.root:
657 raise error.Abort(_(b'repository root cannot be destination'))
657 raise error.Abort(_(b'repository root cannot be destination'))
658
658
659 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
659 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
660 prefix = opts.get(b'prefix')
660 prefix = opts.get(b'prefix')
661
661
662 if dest == b'-':
662 if dest == b'-':
663 if kind == b'files':
663 if kind == b'files':
664 raise error.Abort(_(b'cannot archive plain files to stdout'))
664 raise error.Abort(_(b'cannot archive plain files to stdout'))
665 dest = cmdutil.makefileobj(ctx, dest)
665 dest = cmdutil.makefileobj(ctx, dest)
666 if not prefix:
666 if not prefix:
667 prefix = os.path.basename(repo.root) + b'-%h'
667 prefix = os.path.basename(repo.root) + b'-%h'
668
668
669 prefix = cmdutil.makefilename(ctx, prefix)
669 prefix = cmdutil.makefilename(ctx, prefix)
670 match = scmutil.match(ctx, [], opts)
670 match = scmutil.match(ctx, [], opts)
671 archival.archive(
671 archival.archive(
672 repo,
672 repo,
673 dest,
673 dest,
674 node,
674 node,
675 kind,
675 kind,
676 not opts.get(b'no_decode'),
676 not opts.get(b'no_decode'),
677 match,
677 match,
678 prefix,
678 prefix,
679 subrepos=opts.get(b'subrepos'),
679 subrepos=opts.get(b'subrepos'),
680 )
680 )
681
681
682
682
683 @command(
683 @command(
684 b'backout',
684 b'backout',
685 [
685 [
686 (
686 (
687 b'',
687 b'',
688 b'merge',
688 b'merge',
689 None,
689 None,
690 _(b'merge with old dirstate parent after backout'),
690 _(b'merge with old dirstate parent after backout'),
691 ),
691 ),
692 (
692 (
693 b'',
693 b'',
694 b'commit',
694 b'commit',
695 None,
695 None,
696 _(b'commit if no conflicts were encountered (DEPRECATED)'),
696 _(b'commit if no conflicts were encountered (DEPRECATED)'),
697 ),
697 ),
698 (b'', b'no-commit', None, _(b'do not commit')),
698 (b'', b'no-commit', None, _(b'do not commit')),
699 (
699 (
700 b'',
700 b'',
701 b'parent',
701 b'parent',
702 b'',
702 b'',
703 _(b'parent to choose when backing out merge (DEPRECATED)'),
703 _(b'parent to choose when backing out merge (DEPRECATED)'),
704 _(b'REV'),
704 _(b'REV'),
705 ),
705 ),
706 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
706 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
707 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
707 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
708 ]
708 ]
709 + mergetoolopts
709 + mergetoolopts
710 + walkopts
710 + walkopts
711 + commitopts
711 + commitopts
712 + commitopts2,
712 + commitopts2,
713 _(b'[OPTION]... [-r] REV'),
713 _(b'[OPTION]... [-r] REV'),
714 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
714 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
715 )
715 )
716 def backout(ui, repo, node=None, rev=None, **opts):
716 def backout(ui, repo, node=None, rev=None, **opts):
717 '''reverse effect of earlier changeset
717 '''reverse effect of earlier changeset
718
718
719 Prepare a new changeset with the effect of REV undone in the
719 Prepare a new changeset with the effect of REV undone in the
720 current working directory. If no conflicts were encountered,
720 current working directory. If no conflicts were encountered,
721 it will be committed immediately.
721 it will be committed immediately.
722
722
723 If REV is the parent of the working directory, then this new changeset
723 If REV is the parent of the working directory, then this new changeset
724 is committed automatically (unless --no-commit is specified).
724 is committed automatically (unless --no-commit is specified).
725
725
726 .. note::
726 .. note::
727
727
728 :hg:`backout` cannot be used to fix either an unwanted or
728 :hg:`backout` cannot be used to fix either an unwanted or
729 incorrect merge.
729 incorrect merge.
730
730
731 .. container:: verbose
731 .. container:: verbose
732
732
733 Examples:
733 Examples:
734
734
735 - Reverse the effect of the parent of the working directory.
735 - Reverse the effect of the parent of the working directory.
736 This backout will be committed immediately::
736 This backout will be committed immediately::
737
737
738 hg backout -r .
738 hg backout -r .
739
739
740 - Reverse the effect of previous bad revision 23::
740 - Reverse the effect of previous bad revision 23::
741
741
742 hg backout -r 23
742 hg backout -r 23
743
743
744 - Reverse the effect of previous bad revision 23 and
744 - Reverse the effect of previous bad revision 23 and
745 leave changes uncommitted::
745 leave changes uncommitted::
746
746
747 hg backout -r 23 --no-commit
747 hg backout -r 23 --no-commit
748 hg commit -m "Backout revision 23"
748 hg commit -m "Backout revision 23"
749
749
750 By default, the pending changeset will have one parent,
750 By default, the pending changeset will have one parent,
751 maintaining a linear history. With --merge, the pending
751 maintaining a linear history. With --merge, the pending
752 changeset will instead have two parents: the old parent of the
752 changeset will instead have two parents: the old parent of the
753 working directory and a new child of REV that simply undoes REV.
753 working directory and a new child of REV that simply undoes REV.
754
754
755 Before version 1.7, the behavior without --merge was equivalent
755 Before version 1.7, the behavior without --merge was equivalent
756 to specifying --merge followed by :hg:`update --clean .` to
756 to specifying --merge followed by :hg:`update --clean .` to
757 cancel the merge and leave the child of REV as a head to be
757 cancel the merge and leave the child of REV as a head to be
758 merged separately.
758 merged separately.
759
759
760 See :hg:`help dates` for a list of formats valid for -d/--date.
760 See :hg:`help dates` for a list of formats valid for -d/--date.
761
761
762 See :hg:`help revert` for a way to restore files to the state
762 See :hg:`help revert` for a way to restore files to the state
763 of another revision.
763 of another revision.
764
764
765 Returns 0 on success, 1 if nothing to backout or there are unresolved
765 Returns 0 on success, 1 if nothing to backout or there are unresolved
766 files.
766 files.
767 '''
767 '''
768 with repo.wlock(), repo.lock():
768 with repo.wlock(), repo.lock():
769 return _dobackout(ui, repo, node, rev, **opts)
769 return _dobackout(ui, repo, node, rev, **opts)
770
770
771
771
772 def _dobackout(ui, repo, node=None, rev=None, **opts):
772 def _dobackout(ui, repo, node=None, rev=None, **opts):
773 opts = pycompat.byteskwargs(opts)
773 opts = pycompat.byteskwargs(opts)
774 if opts.get(b'commit') and opts.get(b'no_commit'):
774 if opts.get(b'commit') and opts.get(b'no_commit'):
775 raise error.Abort(_(b"cannot use --commit with --no-commit"))
775 raise error.Abort(_(b"cannot use --commit with --no-commit"))
776 if opts.get(b'merge') and opts.get(b'no_commit'):
776 if opts.get(b'merge') and opts.get(b'no_commit'):
777 raise error.Abort(_(b"cannot use --merge with --no-commit"))
777 raise error.Abort(_(b"cannot use --merge with --no-commit"))
778
778
779 if rev and node:
779 if rev and node:
780 raise error.Abort(_(b"please specify just one revision"))
780 raise error.Abort(_(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.Abort(_(b"please specify a revision to backout"))
786 raise error.Abort(_(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 = scmutil.revsingle(repo, rev)
794 ctx = scmutil.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.Abort(_(b'cannot backout change that is not an ancestor'))
799 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
800
800
801 p1, p2 = repo.changelog.parents(node)
801 p1, p2 = repo.changelog.parents(node)
802 if p1 == nullid:
802 if p1 == nullid:
803 raise error.Abort(_(b'cannot backout a change with no parents'))
803 raise error.Abort(_(b'cannot backout a change with no parents'))
804 if p2 != nullid:
804 if p2 != nullid:
805 if not opts.get(b'parent'):
805 if not opts.get(b'parent'):
806 raise error.Abort(_(b'cannot backout a merge changeset'))
806 raise error.Abort(_(b'cannot backout a merge changeset'))
807 p = repo.lookup(opts[b'parent'])
807 p = repo.lookup(opts[b'parent'])
808 if p not in (p1, p2):
808 if p not in (p1, p2):
809 raise error.Abort(
809 raise error.Abort(
810 _(b'%s is not a parent of %s') % (short(p), short(node))
810 _(b'%s is not a parent of %s') % (short(p), short(node))
811 )
811 )
812 parent = p
812 parent = p
813 else:
813 else:
814 if opts.get(b'parent'):
814 if opts.get(b'parent'):
815 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
815 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
816 parent = p1
816 parent = p1
817
817
818 # the backout should appear on the same branch
818 # the backout should appear on the same branch
819 branch = repo.dirstate.branch()
819 branch = repo.dirstate.branch()
820 bheads = repo.branchheads(branch)
820 bheads = repo.branchheads(branch)
821 rctx = scmutil.revsingle(repo, hex(parent))
821 rctx = scmutil.revsingle(repo, hex(parent))
822 if not opts.get(b'merge') and op1 != node:
822 if not opts.get(b'merge') and op1 != node:
823 with dirstateguard.dirstateguard(repo, b'backout'):
823 with dirstateguard.dirstateguard(repo, b'backout'):
824 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
824 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
825 with ui.configoverride(overrides, b'backout'):
825 with ui.configoverride(overrides, b'backout'):
826 stats = mergemod.back_out(ctx, parent=repo[parent])
826 stats = mergemod.back_out(ctx, parent=repo[parent])
827 repo.setparents(op1, op2)
827 repo.setparents(op1, op2)
828 hg._showstats(repo, stats)
828 hg._showstats(repo, stats)
829 if stats.unresolvedcount:
829 if stats.unresolvedcount:
830 repo.ui.status(
830 repo.ui.status(
831 _(b"use 'hg resolve' to retry unresolved file merges\n")
831 _(b"use 'hg resolve' to retry unresolved file merges\n")
832 )
832 )
833 return 1
833 return 1
834 else:
834 else:
835 hg.clean(repo, node, show_stats=False)
835 hg.clean(repo, node, show_stats=False)
836 repo.dirstate.setbranch(branch)
836 repo.dirstate.setbranch(branch)
837 cmdutil.revert(ui, repo, rctx)
837 cmdutil.revert(ui, repo, rctx)
838
838
839 if opts.get(b'no_commit'):
839 if opts.get(b'no_commit'):
840 msg = _(b"changeset %s backed out, don't forget to commit.\n")
840 msg = _(b"changeset %s backed out, don't forget to commit.\n")
841 ui.status(msg % short(node))
841 ui.status(msg % short(node))
842 return 0
842 return 0
843
843
844 def commitfunc(ui, repo, message, match, opts):
844 def commitfunc(ui, repo, message, match, opts):
845 editform = b'backout'
845 editform = b'backout'
846 e = cmdutil.getcommiteditor(
846 e = cmdutil.getcommiteditor(
847 editform=editform, **pycompat.strkwargs(opts)
847 editform=editform, **pycompat.strkwargs(opts)
848 )
848 )
849 if not message:
849 if not message:
850 # we don't translate commit messages
850 # we don't translate commit messages
851 message = b"Backed out changeset %s" % short(node)
851 message = b"Backed out changeset %s" % short(node)
852 e = cmdutil.getcommiteditor(edit=True, editform=editform)
852 e = cmdutil.getcommiteditor(edit=True, editform=editform)
853 return repo.commit(
853 return repo.commit(
854 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
854 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
855 )
855 )
856
856
857 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
857 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
858 if not newnode:
858 if not newnode:
859 ui.status(_(b"nothing changed\n"))
859 ui.status(_(b"nothing changed\n"))
860 return 1
860 return 1
861 cmdutil.commitstatus(repo, newnode, branch, bheads)
861 cmdutil.commitstatus(repo, newnode, branch, bheads)
862
862
863 def nice(node):
863 def nice(node):
864 return b'%d:%s' % (repo.changelog.rev(node), short(node))
864 return b'%d:%s' % (repo.changelog.rev(node), short(node))
865
865
866 ui.status(
866 ui.status(
867 _(b'changeset %s backs out changeset %s\n')
867 _(b'changeset %s backs out changeset %s\n')
868 % (nice(repo.changelog.tip()), nice(node))
868 % (nice(repo.changelog.tip()), nice(node))
869 )
869 )
870 if opts.get(b'merge') and op1 != node:
870 if opts.get(b'merge') and op1 != node:
871 hg.clean(repo, op1, show_stats=False)
871 hg.clean(repo, op1, show_stats=False)
872 ui.status(
872 ui.status(
873 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
873 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
874 )
874 )
875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
876 with ui.configoverride(overrides, b'backout'):
876 with ui.configoverride(overrides, b'backout'):
877 return hg.merge(repo[b'tip'])
877 return hg.merge(repo[b'tip'])
878 return 0
878 return 0
879
879
880
880
881 @command(
881 @command(
882 b'bisect',
882 b'bisect',
883 [
883 [
884 (b'r', b'reset', False, _(b'reset bisect state')),
884 (b'r', b'reset', False, _(b'reset bisect state')),
885 (b'g', b'good', False, _(b'mark changeset good')),
885 (b'g', b'good', False, _(b'mark changeset good')),
886 (b'b', b'bad', False, _(b'mark changeset bad')),
886 (b'b', b'bad', False, _(b'mark changeset bad')),
887 (b's', b'skip', False, _(b'skip testing changeset')),
887 (b's', b'skip', False, _(b'skip testing changeset')),
888 (b'e', b'extend', False, _(b'extend the bisect range')),
888 (b'e', b'extend', False, _(b'extend the bisect range')),
889 (
889 (
890 b'c',
890 b'c',
891 b'command',
891 b'command',
892 b'',
892 b'',
893 _(b'use command to check changeset state'),
893 _(b'use command to check changeset state'),
894 _(b'CMD'),
894 _(b'CMD'),
895 ),
895 ),
896 (b'U', b'noupdate', False, _(b'do not update to target')),
896 (b'U', b'noupdate', False, _(b'do not update to target')),
897 ],
897 ],
898 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
898 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
899 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
899 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
900 )
900 )
901 def bisect(
901 def bisect(
902 ui,
902 ui,
903 repo,
903 repo,
904 rev=None,
904 rev=None,
905 extra=None,
905 extra=None,
906 command=None,
906 command=None,
907 reset=None,
907 reset=None,
908 good=None,
908 good=None,
909 bad=None,
909 bad=None,
910 skip=None,
910 skip=None,
911 extend=None,
911 extend=None,
912 noupdate=None,
912 noupdate=None,
913 ):
913 ):
914 """subdivision search of changesets
914 """subdivision search of changesets
915
915
916 This command helps to find changesets which introduce problems. To
916 This command helps to find changesets which introduce problems. To
917 use, mark the earliest changeset you know exhibits the problem as
917 use, mark the earliest changeset you know exhibits the problem as
918 bad, then mark the latest changeset which is free from the problem
918 bad, then mark the latest changeset which is free from the problem
919 as good. Bisect will update your working directory to a revision
919 as good. Bisect will update your working directory to a revision
920 for testing (unless the -U/--noupdate option is specified). Once
920 for testing (unless the -U/--noupdate option is specified). Once
921 you have performed tests, mark the working directory as good or
921 you have performed tests, mark the working directory as good or
922 bad, and bisect will either update to another candidate changeset
922 bad, and bisect will either update to another candidate changeset
923 or announce that it has found the bad revision.
923 or announce that it has found the bad revision.
924
924
925 As a shortcut, you can also use the revision argument to mark a
925 As a shortcut, you can also use the revision argument to mark a
926 revision as good or bad without checking it out first.
926 revision as good or bad without checking it out first.
927
927
928 If you supply a command, it will be used for automatic bisection.
928 If you supply a command, it will be used for automatic bisection.
929 The environment variable HG_NODE will contain the ID of the
929 The environment variable HG_NODE will contain the ID of the
930 changeset being tested. The exit status of the command will be
930 changeset being tested. The exit status of the command will be
931 used to mark revisions as good or bad: status 0 means good, 125
931 used to mark revisions as good or bad: status 0 means good, 125
932 means to skip the revision, 127 (command not found) will abort the
932 means to skip the revision, 127 (command not found) will abort the
933 bisection, and any other non-zero exit status means the revision
933 bisection, and any other non-zero exit status means the revision
934 is bad.
934 is bad.
935
935
936 .. container:: verbose
936 .. container:: verbose
937
937
938 Some examples:
938 Some examples:
939
939
940 - start a bisection with known bad revision 34, and good revision 12::
940 - start a bisection with known bad revision 34, and good revision 12::
941
941
942 hg bisect --bad 34
942 hg bisect --bad 34
943 hg bisect --good 12
943 hg bisect --good 12
944
944
945 - advance the current bisection by marking current revision as good or
945 - advance the current bisection by marking current revision as good or
946 bad::
946 bad::
947
947
948 hg bisect --good
948 hg bisect --good
949 hg bisect --bad
949 hg bisect --bad
950
950
951 - mark the current revision, or a known revision, to be skipped (e.g. if
951 - mark the current revision, or a known revision, to be skipped (e.g. if
952 that revision is not usable because of another issue)::
952 that revision is not usable because of another issue)::
953
953
954 hg bisect --skip
954 hg bisect --skip
955 hg bisect --skip 23
955 hg bisect --skip 23
956
956
957 - skip all revisions that do not touch directories ``foo`` or ``bar``::
957 - skip all revisions that do not touch directories ``foo`` or ``bar``::
958
958
959 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
959 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
960
960
961 - forget the current bisection::
961 - forget the current bisection::
962
962
963 hg bisect --reset
963 hg bisect --reset
964
964
965 - use 'make && make tests' to automatically find the first broken
965 - use 'make && make tests' to automatically find the first broken
966 revision::
966 revision::
967
967
968 hg bisect --reset
968 hg bisect --reset
969 hg bisect --bad 34
969 hg bisect --bad 34
970 hg bisect --good 12
970 hg bisect --good 12
971 hg bisect --command "make && make tests"
971 hg bisect --command "make && make tests"
972
972
973 - see all changesets whose states are already known in the current
973 - see all changesets whose states are already known in the current
974 bisection::
974 bisection::
975
975
976 hg log -r "bisect(pruned)"
976 hg log -r "bisect(pruned)"
977
977
978 - see the changeset currently being bisected (especially useful
978 - see the changeset currently being bisected (especially useful
979 if running with -U/--noupdate)::
979 if running with -U/--noupdate)::
980
980
981 hg log -r "bisect(current)"
981 hg log -r "bisect(current)"
982
982
983 - see all changesets that took part in the current bisection::
983 - see all changesets that took part in the current bisection::
984
984
985 hg log -r "bisect(range)"
985 hg log -r "bisect(range)"
986
986
987 - you can even get a nice graph::
987 - you can even get a nice graph::
988
988
989 hg log --graph -r "bisect(range)"
989 hg log --graph -r "bisect(range)"
990
990
991 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
991 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
992
992
993 Returns 0 on success.
993 Returns 0 on success.
994 """
994 """
995 # backward compatibility
995 # backward compatibility
996 if rev in b"good bad reset init".split():
996 if rev in b"good bad reset init".split():
997 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
997 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
998 cmd, rev, extra = rev, extra, None
998 cmd, rev, extra = rev, extra, None
999 if cmd == b"good":
999 if cmd == b"good":
1000 good = True
1000 good = True
1001 elif cmd == b"bad":
1001 elif cmd == b"bad":
1002 bad = True
1002 bad = True
1003 else:
1003 else:
1004 reset = True
1004 reset = True
1005 elif extra:
1005 elif extra:
1006 raise error.Abort(_(b'incompatible arguments'))
1006 raise error.Abort(_(b'incompatible arguments'))
1007
1007
1008 incompatibles = {
1008 incompatibles = {
1009 b'--bad': bad,
1009 b'--bad': bad,
1010 b'--command': bool(command),
1010 b'--command': bool(command),
1011 b'--extend': extend,
1011 b'--extend': extend,
1012 b'--good': good,
1012 b'--good': good,
1013 b'--reset': reset,
1013 b'--reset': reset,
1014 b'--skip': skip,
1014 b'--skip': skip,
1015 }
1015 }
1016
1016
1017 enabled = [x for x in incompatibles if incompatibles[x]]
1017 enabled = [x for x in incompatibles if incompatibles[x]]
1018
1018
1019 if len(enabled) > 1:
1019 if len(enabled) > 1:
1020 raise error.Abort(
1020 raise error.Abort(
1021 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1021 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1022 )
1022 )
1023
1023
1024 if reset:
1024 if reset:
1025 hbisect.resetstate(repo)
1025 hbisect.resetstate(repo)
1026 return
1026 return
1027
1027
1028 state = hbisect.load_state(repo)
1028 state = hbisect.load_state(repo)
1029
1029
1030 # update state
1030 # update state
1031 if good or bad or skip:
1031 if good or bad or skip:
1032 if rev:
1032 if rev:
1033 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1033 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1034 else:
1034 else:
1035 nodes = [repo.lookup(b'.')]
1035 nodes = [repo.lookup(b'.')]
1036 if good:
1036 if good:
1037 state[b'good'] += nodes
1037 state[b'good'] += nodes
1038 elif bad:
1038 elif bad:
1039 state[b'bad'] += nodes
1039 state[b'bad'] += nodes
1040 elif skip:
1040 elif skip:
1041 state[b'skip'] += nodes
1041 state[b'skip'] += nodes
1042 hbisect.save_state(repo, state)
1042 hbisect.save_state(repo, state)
1043 if not (state[b'good'] and state[b'bad']):
1043 if not (state[b'good'] and state[b'bad']):
1044 return
1044 return
1045
1045
1046 def mayupdate(repo, node, show_stats=True):
1046 def mayupdate(repo, node, show_stats=True):
1047 """common used update sequence"""
1047 """common used update sequence"""
1048 if noupdate:
1048 if noupdate:
1049 return
1049 return
1050 cmdutil.checkunfinished(repo)
1050 cmdutil.checkunfinished(repo)
1051 cmdutil.bailifchanged(repo)
1051 cmdutil.bailifchanged(repo)
1052 return hg.clean(repo, node, show_stats=show_stats)
1052 return hg.clean(repo, node, show_stats=show_stats)
1053
1053
1054 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1054 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1055
1055
1056 if command:
1056 if command:
1057 changesets = 1
1057 changesets = 1
1058 if noupdate:
1058 if noupdate:
1059 try:
1059 try:
1060 node = state[b'current'][0]
1060 node = state[b'current'][0]
1061 except LookupError:
1061 except LookupError:
1062 raise error.Abort(
1062 raise error.Abort(
1063 _(
1063 _(
1064 b'current bisect revision is unknown - '
1064 b'current bisect revision is unknown - '
1065 b'start a new bisect to fix'
1065 b'start a new bisect to fix'
1066 )
1066 )
1067 )
1067 )
1068 else:
1068 else:
1069 node, p2 = repo.dirstate.parents()
1069 node, p2 = repo.dirstate.parents()
1070 if p2 != nullid:
1070 if p2 != nullid:
1071 raise error.Abort(_(b'current bisect revision is a merge'))
1071 raise error.Abort(_(b'current bisect revision is a merge'))
1072 if rev:
1072 if rev:
1073 node = repo[scmutil.revsingle(repo, rev, node)].node()
1073 node = repo[scmutil.revsingle(repo, rev, node)].node()
1074 with hbisect.restore_state(repo, state, node):
1074 with hbisect.restore_state(repo, state, node):
1075 while changesets:
1075 while changesets:
1076 # update state
1076 # update state
1077 state[b'current'] = [node]
1077 state[b'current'] = [node]
1078 hbisect.save_state(repo, state)
1078 hbisect.save_state(repo, state)
1079 status = ui.system(
1079 status = ui.system(
1080 command,
1080 command,
1081 environ={b'HG_NODE': hex(node)},
1081 environ={b'HG_NODE': hex(node)},
1082 blockedtag=b'bisect_check',
1082 blockedtag=b'bisect_check',
1083 )
1083 )
1084 if status == 125:
1084 if status == 125:
1085 transition = b"skip"
1085 transition = b"skip"
1086 elif status == 0:
1086 elif status == 0:
1087 transition = b"good"
1087 transition = b"good"
1088 # status < 0 means process was killed
1088 # status < 0 means process was killed
1089 elif status == 127:
1089 elif status == 127:
1090 raise error.Abort(_(b"failed to execute %s") % command)
1090 raise error.Abort(_(b"failed to execute %s") % command)
1091 elif status < 0:
1091 elif status < 0:
1092 raise error.Abort(_(b"%s killed") % command)
1092 raise error.Abort(_(b"%s killed") % command)
1093 else:
1093 else:
1094 transition = b"bad"
1094 transition = b"bad"
1095 state[transition].append(node)
1095 state[transition].append(node)
1096 ctx = repo[node]
1096 ctx = repo[node]
1097 ui.status(
1097 ui.status(
1098 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1098 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1099 )
1099 )
1100 hbisect.checkstate(state)
1100 hbisect.checkstate(state)
1101 # bisect
1101 # bisect
1102 nodes, changesets, bgood = hbisect.bisect(repo, state)
1102 nodes, changesets, bgood = hbisect.bisect(repo, state)
1103 # update to next check
1103 # update to next check
1104 node = nodes[0]
1104 node = nodes[0]
1105 mayupdate(repo, node, show_stats=False)
1105 mayupdate(repo, node, show_stats=False)
1106 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1106 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1107 return
1107 return
1108
1108
1109 hbisect.checkstate(state)
1109 hbisect.checkstate(state)
1110
1110
1111 # actually bisect
1111 # actually bisect
1112 nodes, changesets, good = hbisect.bisect(repo, state)
1112 nodes, changesets, good = hbisect.bisect(repo, state)
1113 if extend:
1113 if extend:
1114 if not changesets:
1114 if not changesets:
1115 extendnode = hbisect.extendrange(repo, state, nodes, good)
1115 extendnode = hbisect.extendrange(repo, state, nodes, good)
1116 if extendnode is not None:
1116 if extendnode is not None:
1117 ui.write(
1117 ui.write(
1118 _(b"Extending search to changeset %d:%s\n")
1118 _(b"Extending search to changeset %d:%s\n")
1119 % (extendnode.rev(), extendnode)
1119 % (extendnode.rev(), extendnode)
1120 )
1120 )
1121 state[b'current'] = [extendnode.node()]
1121 state[b'current'] = [extendnode.node()]
1122 hbisect.save_state(repo, state)
1122 hbisect.save_state(repo, state)
1123 return mayupdate(repo, extendnode.node())
1123 return mayupdate(repo, extendnode.node())
1124 raise error.Abort(_(b"nothing to extend"))
1124 raise error.Abort(_(b"nothing to extend"))
1125
1125
1126 if changesets == 0:
1126 if changesets == 0:
1127 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1127 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1128 else:
1128 else:
1129 assert len(nodes) == 1 # only a single node can be tested next
1129 assert len(nodes) == 1 # only a single node can be tested next
1130 node = nodes[0]
1130 node = nodes[0]
1131 # compute the approximate number of remaining tests
1131 # compute the approximate number of remaining tests
1132 tests, size = 0, 2
1132 tests, size = 0, 2
1133 while size <= changesets:
1133 while size <= changesets:
1134 tests, size = tests + 1, size * 2
1134 tests, size = tests + 1, size * 2
1135 rev = repo.changelog.rev(node)
1135 rev = repo.changelog.rev(node)
1136 ui.write(
1136 ui.write(
1137 _(
1137 _(
1138 b"Testing changeset %d:%s "
1138 b"Testing changeset %d:%s "
1139 b"(%d changesets remaining, ~%d tests)\n"
1139 b"(%d changesets remaining, ~%d tests)\n"
1140 )
1140 )
1141 % (rev, short(node), changesets, tests)
1141 % (rev, short(node), changesets, tests)
1142 )
1142 )
1143 state[b'current'] = [node]
1143 state[b'current'] = [node]
1144 hbisect.save_state(repo, state)
1144 hbisect.save_state(repo, state)
1145 return mayupdate(repo, node)
1145 return mayupdate(repo, node)
1146
1146
1147
1147
1148 @command(
1148 @command(
1149 b'bookmarks|bookmark',
1149 b'bookmarks|bookmark',
1150 [
1150 [
1151 (b'f', b'force', False, _(b'force')),
1151 (b'f', b'force', False, _(b'force')),
1152 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1152 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1153 (b'd', b'delete', False, _(b'delete a given bookmark')),
1153 (b'd', b'delete', False, _(b'delete a given bookmark')),
1154 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1154 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1155 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1155 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1156 (b'l', b'list', False, _(b'list existing bookmarks')),
1156 (b'l', b'list', False, _(b'list existing bookmarks')),
1157 ]
1157 ]
1158 + formatteropts,
1158 + formatteropts,
1159 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1159 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1160 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1160 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1161 )
1161 )
1162 def bookmark(ui, repo, *names, **opts):
1162 def bookmark(ui, repo, *names, **opts):
1163 '''create a new bookmark or list existing bookmarks
1163 '''create a new bookmark or list existing bookmarks
1164
1164
1165 Bookmarks are labels on changesets to help track lines of development.
1165 Bookmarks are labels on changesets to help track lines of development.
1166 Bookmarks are unversioned and can be moved, renamed and deleted.
1166 Bookmarks are unversioned and can be moved, renamed and deleted.
1167 Deleting or moving a bookmark has no effect on the associated changesets.
1167 Deleting or moving a bookmark has no effect on the associated changesets.
1168
1168
1169 Creating or updating to a bookmark causes it to be marked as 'active'.
1169 Creating or updating to a bookmark causes it to be marked as 'active'.
1170 The active bookmark is indicated with a '*'.
1170 The active bookmark is indicated with a '*'.
1171 When a commit is made, the active bookmark will advance to the new commit.
1171 When a commit is made, the active bookmark will advance to the new commit.
1172 A plain :hg:`update` will also advance an active bookmark, if possible.
1172 A plain :hg:`update` will also advance an active bookmark, if possible.
1173 Updating away from a bookmark will cause it to be deactivated.
1173 Updating away from a bookmark will cause it to be deactivated.
1174
1174
1175 Bookmarks can be pushed and pulled between repositories (see
1175 Bookmarks can be pushed and pulled between repositories (see
1176 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1176 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1177 diverged, a new 'divergent bookmark' of the form 'name@path' will
1177 diverged, a new 'divergent bookmark' of the form 'name@path' will
1178 be created. Using :hg:`merge` will resolve the divergence.
1178 be created. Using :hg:`merge` will resolve the divergence.
1179
1179
1180 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1180 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1181 the active bookmark's name.
1181 the active bookmark's name.
1182
1182
1183 A bookmark named '@' has the special property that :hg:`clone` will
1183 A bookmark named '@' has the special property that :hg:`clone` will
1184 check it out by default if it exists.
1184 check it out by default if it exists.
1185
1185
1186 .. container:: verbose
1186 .. container:: verbose
1187
1187
1188 Template:
1188 Template:
1189
1189
1190 The following keywords are supported in addition to the common template
1190 The following keywords are supported in addition to the common template
1191 keywords and functions such as ``{bookmark}``. See also
1191 keywords and functions such as ``{bookmark}``. See also
1192 :hg:`help templates`.
1192 :hg:`help templates`.
1193
1193
1194 :active: Boolean. True if the bookmark is active.
1194 :active: Boolean. True if the bookmark is active.
1195
1195
1196 Examples:
1196 Examples:
1197
1197
1198 - create an active bookmark for a new line of development::
1198 - create an active bookmark for a new line of development::
1199
1199
1200 hg book new-feature
1200 hg book new-feature
1201
1201
1202 - create an inactive bookmark as a place marker::
1202 - create an inactive bookmark as a place marker::
1203
1203
1204 hg book -i reviewed
1204 hg book -i reviewed
1205
1205
1206 - create an inactive bookmark on another changeset::
1206 - create an inactive bookmark on another changeset::
1207
1207
1208 hg book -r .^ tested
1208 hg book -r .^ tested
1209
1209
1210 - rename bookmark turkey to dinner::
1210 - rename bookmark turkey to dinner::
1211
1211
1212 hg book -m turkey dinner
1212 hg book -m turkey dinner
1213
1213
1214 - move the '@' bookmark from another branch::
1214 - move the '@' bookmark from another branch::
1215
1215
1216 hg book -f @
1216 hg book -f @
1217
1217
1218 - print only the active bookmark name::
1218 - print only the active bookmark name::
1219
1219
1220 hg book -ql .
1220 hg book -ql .
1221 '''
1221 '''
1222 opts = pycompat.byteskwargs(opts)
1222 opts = pycompat.byteskwargs(opts)
1223 force = opts.get(b'force')
1223 force = opts.get(b'force')
1224 rev = opts.get(b'rev')
1224 rev = opts.get(b'rev')
1225 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1225 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1226
1226
1227 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1227 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1228 if action:
1228 if action:
1229 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1229 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1230 elif names or rev:
1230 elif names or rev:
1231 action = b'add'
1231 action = b'add'
1232 elif inactive:
1232 elif inactive:
1233 action = b'inactive' # meaning deactivate
1233 action = b'inactive' # meaning deactivate
1234 else:
1234 else:
1235 action = b'list'
1235 action = b'list'
1236
1236
1237 cmdutil.check_incompatible_arguments(
1237 cmdutil.check_incompatible_arguments(
1238 opts, b'inactive', [b'delete', b'list']
1238 opts, b'inactive', [b'delete', b'list']
1239 )
1239 )
1240 if not names and action in {b'add', b'delete'}:
1240 if not names and action in {b'add', b'delete'}:
1241 raise error.Abort(_(b"bookmark name required"))
1241 raise error.Abort(_(b"bookmark name required"))
1242
1242
1243 if action in {b'add', b'delete', b'rename', b'inactive'}:
1243 if action in {b'add', b'delete', b'rename', b'inactive'}:
1244 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1244 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1245 if action == b'delete':
1245 if action == b'delete':
1246 names = pycompat.maplist(repo._bookmarks.expandname, names)
1246 names = pycompat.maplist(repo._bookmarks.expandname, names)
1247 bookmarks.delete(repo, tr, names)
1247 bookmarks.delete(repo, tr, names)
1248 elif action == b'rename':
1248 elif action == b'rename':
1249 if not names:
1249 if not names:
1250 raise error.Abort(_(b"new bookmark name required"))
1250 raise error.Abort(_(b"new bookmark name required"))
1251 elif len(names) > 1:
1251 elif len(names) > 1:
1252 raise error.Abort(_(b"only one new bookmark name allowed"))
1252 raise error.Abort(_(b"only one new bookmark name allowed"))
1253 oldname = repo._bookmarks.expandname(opts[b'rename'])
1253 oldname = repo._bookmarks.expandname(opts[b'rename'])
1254 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1254 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1255 elif action == b'add':
1255 elif action == b'add':
1256 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1256 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1257 elif action == b'inactive':
1257 elif action == b'inactive':
1258 if len(repo._bookmarks) == 0:
1258 if len(repo._bookmarks) == 0:
1259 ui.status(_(b"no bookmarks set\n"))
1259 ui.status(_(b"no bookmarks set\n"))
1260 elif not repo._activebookmark:
1260 elif not repo._activebookmark:
1261 ui.status(_(b"no active bookmark\n"))
1261 ui.status(_(b"no active bookmark\n"))
1262 else:
1262 else:
1263 bookmarks.deactivate(repo)
1263 bookmarks.deactivate(repo)
1264 elif action == b'list':
1264 elif action == b'list':
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1266 with ui.formatter(b'bookmarks', opts) as fm:
1266 with ui.formatter(b'bookmarks', opts) as fm:
1267 bookmarks.printbookmarks(ui, repo, fm, names)
1267 bookmarks.printbookmarks(ui, repo, fm, names)
1268 else:
1268 else:
1269 raise error.ProgrammingError(b'invalid action: %s' % action)
1269 raise error.ProgrammingError(b'invalid action: %s' % action)
1270
1270
1271
1271
1272 @command(
1272 @command(
1273 b'branch',
1273 b'branch',
1274 [
1274 [
1275 (
1275 (
1276 b'f',
1276 b'f',
1277 b'force',
1277 b'force',
1278 None,
1278 None,
1279 _(b'set branch name even if it shadows an existing branch'),
1279 _(b'set branch name even if it shadows an existing branch'),
1280 ),
1280 ),
1281 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1281 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1282 (
1282 (
1283 b'r',
1283 b'r',
1284 b'rev',
1284 b'rev',
1285 [],
1285 [],
1286 _(b'change branches of the given revs (EXPERIMENTAL)'),
1286 _(b'change branches of the given revs (EXPERIMENTAL)'),
1287 ),
1287 ),
1288 ],
1288 ],
1289 _(b'[-fC] [NAME]'),
1289 _(b'[-fC] [NAME]'),
1290 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1290 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1291 )
1291 )
1292 def branch(ui, repo, label=None, **opts):
1292 def branch(ui, repo, label=None, **opts):
1293 """set or show the current branch name
1293 """set or show the current branch name
1294
1294
1295 .. note::
1295 .. note::
1296
1296
1297 Branch names are permanent and global. Use :hg:`bookmark` to create a
1297 Branch names are permanent and global. Use :hg:`bookmark` to create a
1298 light-weight bookmark instead. See :hg:`help glossary` for more
1298 light-weight bookmark instead. See :hg:`help glossary` for more
1299 information about named branches and bookmarks.
1299 information about named branches and bookmarks.
1300
1300
1301 With no argument, show the current branch name. With one argument,
1301 With no argument, show the current branch name. With one argument,
1302 set the working directory branch name (the branch will not exist
1302 set the working directory branch name (the branch will not exist
1303 in the repository until the next commit). Standard practice
1303 in the repository until the next commit). Standard practice
1304 recommends that primary development take place on the 'default'
1304 recommends that primary development take place on the 'default'
1305 branch.
1305 branch.
1306
1306
1307 Unless -f/--force is specified, branch will not let you set a
1307 Unless -f/--force is specified, branch will not let you set a
1308 branch name that already exists.
1308 branch name that already exists.
1309
1309
1310 Use -C/--clean to reset the working directory branch to that of
1310 Use -C/--clean to reset the working directory branch to that of
1311 the parent of the working directory, negating a previous branch
1311 the parent of the working directory, negating a previous branch
1312 change.
1312 change.
1313
1313
1314 Use the command :hg:`update` to switch to an existing branch. Use
1314 Use the command :hg:`update` to switch to an existing branch. Use
1315 :hg:`commit --close-branch` to mark this branch head as closed.
1315 :hg:`commit --close-branch` to mark this branch head as closed.
1316 When all heads of a branch are closed, the branch will be
1316 When all heads of a branch are closed, the branch will be
1317 considered closed.
1317 considered closed.
1318
1318
1319 Returns 0 on success.
1319 Returns 0 on success.
1320 """
1320 """
1321 opts = pycompat.byteskwargs(opts)
1321 opts = pycompat.byteskwargs(opts)
1322 revs = opts.get(b'rev')
1322 revs = opts.get(b'rev')
1323 if label:
1323 if label:
1324 label = label.strip()
1324 label = label.strip()
1325
1325
1326 if not opts.get(b'clean') and not label:
1326 if not opts.get(b'clean') and not label:
1327 if revs:
1327 if revs:
1328 raise error.Abort(_(b"no branch name specified for the revisions"))
1328 raise error.Abort(_(b"no branch name specified for the revisions"))
1329 ui.write(b"%s\n" % repo.dirstate.branch())
1329 ui.write(b"%s\n" % repo.dirstate.branch())
1330 return
1330 return
1331
1331
1332 with repo.wlock():
1332 with repo.wlock():
1333 if opts.get(b'clean'):
1333 if opts.get(b'clean'):
1334 label = repo[b'.'].branch()
1334 label = repo[b'.'].branch()
1335 repo.dirstate.setbranch(label)
1335 repo.dirstate.setbranch(label)
1336 ui.status(_(b'reset working directory to branch %s\n') % label)
1336 ui.status(_(b'reset working directory to branch %s\n') % label)
1337 elif label:
1337 elif label:
1338
1338
1339 scmutil.checknewlabel(repo, label, b'branch')
1339 scmutil.checknewlabel(repo, label, b'branch')
1340 if revs:
1340 if revs:
1341 return cmdutil.changebranch(ui, repo, revs, label, opts)
1341 return cmdutil.changebranch(ui, repo, revs, label, opts)
1342
1342
1343 if not opts.get(b'force') and label in repo.branchmap():
1343 if not opts.get(b'force') and label in repo.branchmap():
1344 if label not in [p.branch() for p in repo[None].parents()]:
1344 if label not in [p.branch() for p in repo[None].parents()]:
1345 raise error.Abort(
1345 raise error.Abort(
1346 _(b'a branch of the same name already exists'),
1346 _(b'a branch of the same name already exists'),
1347 # i18n: "it" refers to an existing branch
1347 # i18n: "it" refers to an existing branch
1348 hint=_(b"use 'hg update' to switch to it"),
1348 hint=_(b"use 'hg update' to switch to it"),
1349 )
1349 )
1350
1350
1351 repo.dirstate.setbranch(label)
1351 repo.dirstate.setbranch(label)
1352 ui.status(_(b'marked working directory as branch %s\n') % label)
1352 ui.status(_(b'marked working directory as branch %s\n') % label)
1353
1353
1354 # find any open named branches aside from default
1354 # find any open named branches aside from default
1355 for n, h, t, c in repo.branchmap().iterbranches():
1355 for n, h, t, c in repo.branchmap().iterbranches():
1356 if n != b"default" and not c:
1356 if n != b"default" and not c:
1357 return 0
1357 return 0
1358 ui.status(
1358 ui.status(
1359 _(
1359 _(
1360 b'(branches are permanent and global, '
1360 b'(branches are permanent and global, '
1361 b'did you want a bookmark?)\n'
1361 b'did you want a bookmark?)\n'
1362 )
1362 )
1363 )
1363 )
1364
1364
1365
1365
1366 @command(
1366 @command(
1367 b'branches',
1367 b'branches',
1368 [
1368 [
1369 (
1369 (
1370 b'a',
1370 b'a',
1371 b'active',
1371 b'active',
1372 False,
1372 False,
1373 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1373 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1374 ),
1374 ),
1375 (b'c', b'closed', False, _(b'show normal and closed branches')),
1375 (b'c', b'closed', False, _(b'show normal and closed branches')),
1376 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1376 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1377 ]
1377 ]
1378 + formatteropts,
1378 + formatteropts,
1379 _(b'[-c]'),
1379 _(b'[-c]'),
1380 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1380 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1381 intents={INTENT_READONLY},
1381 intents={INTENT_READONLY},
1382 )
1382 )
1383 def branches(ui, repo, active=False, closed=False, **opts):
1383 def branches(ui, repo, active=False, closed=False, **opts):
1384 """list repository named branches
1384 """list repository named branches
1385
1385
1386 List the repository's named branches, indicating which ones are
1386 List the repository's named branches, indicating which ones are
1387 inactive. If -c/--closed is specified, also list branches which have
1387 inactive. If -c/--closed is specified, also list branches which have
1388 been marked closed (see :hg:`commit --close-branch`).
1388 been marked closed (see :hg:`commit --close-branch`).
1389
1389
1390 Use the command :hg:`update` to switch to an existing branch.
1390 Use the command :hg:`update` to switch to an existing branch.
1391
1391
1392 .. container:: verbose
1392 .. container:: verbose
1393
1393
1394 Template:
1394 Template:
1395
1395
1396 The following keywords are supported in addition to the common template
1396 The following keywords are supported in addition to the common template
1397 keywords and functions such as ``{branch}``. See also
1397 keywords and functions such as ``{branch}``. See also
1398 :hg:`help templates`.
1398 :hg:`help templates`.
1399
1399
1400 :active: Boolean. True if the branch is active.
1400 :active: Boolean. True if the branch is active.
1401 :closed: Boolean. True if the branch is closed.
1401 :closed: Boolean. True if the branch is closed.
1402 :current: Boolean. True if it is the current branch.
1402 :current: Boolean. True if it is the current branch.
1403
1403
1404 Returns 0.
1404 Returns 0.
1405 """
1405 """
1406
1406
1407 opts = pycompat.byteskwargs(opts)
1407 opts = pycompat.byteskwargs(opts)
1408 revs = opts.get(b'rev')
1408 revs = opts.get(b'rev')
1409 selectedbranches = None
1409 selectedbranches = None
1410 if revs:
1410 if revs:
1411 revs = scmutil.revrange(repo, revs)
1411 revs = scmutil.revrange(repo, revs)
1412 getbi = repo.revbranchcache().branchinfo
1412 getbi = repo.revbranchcache().branchinfo
1413 selectedbranches = {getbi(r)[0] for r in revs}
1413 selectedbranches = {getbi(r)[0] for r in revs}
1414
1414
1415 ui.pager(b'branches')
1415 ui.pager(b'branches')
1416 fm = ui.formatter(b'branches', opts)
1416 fm = ui.formatter(b'branches', opts)
1417 hexfunc = fm.hexfunc
1417 hexfunc = fm.hexfunc
1418
1418
1419 allheads = set(repo.heads())
1419 allheads = set(repo.heads())
1420 branches = []
1420 branches = []
1421 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1421 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1422 if selectedbranches is not None and tag not in selectedbranches:
1422 if selectedbranches is not None and tag not in selectedbranches:
1423 continue
1423 continue
1424 isactive = False
1424 isactive = False
1425 if not isclosed:
1425 if not isclosed:
1426 openheads = set(repo.branchmap().iteropen(heads))
1426 openheads = set(repo.branchmap().iteropen(heads))
1427 isactive = bool(openheads & allheads)
1427 isactive = bool(openheads & allheads)
1428 branches.append((tag, repo[tip], isactive, not isclosed))
1428 branches.append((tag, repo[tip], isactive, not isclosed))
1429 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1429 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1430
1430
1431 for tag, ctx, isactive, isopen in branches:
1431 for tag, ctx, isactive, isopen in branches:
1432 if active and not isactive:
1432 if active and not isactive:
1433 continue
1433 continue
1434 if isactive:
1434 if isactive:
1435 label = b'branches.active'
1435 label = b'branches.active'
1436 notice = b''
1436 notice = b''
1437 elif not isopen:
1437 elif not isopen:
1438 if not closed:
1438 if not closed:
1439 continue
1439 continue
1440 label = b'branches.closed'
1440 label = b'branches.closed'
1441 notice = _(b' (closed)')
1441 notice = _(b' (closed)')
1442 else:
1442 else:
1443 label = b'branches.inactive'
1443 label = b'branches.inactive'
1444 notice = _(b' (inactive)')
1444 notice = _(b' (inactive)')
1445 current = tag == repo.dirstate.branch()
1445 current = tag == repo.dirstate.branch()
1446 if current:
1446 if current:
1447 label = b'branches.current'
1447 label = b'branches.current'
1448
1448
1449 fm.startitem()
1449 fm.startitem()
1450 fm.write(b'branch', b'%s', tag, label=label)
1450 fm.write(b'branch', b'%s', tag, label=label)
1451 rev = ctx.rev()
1451 rev = ctx.rev()
1452 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1452 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1453 fmt = b' ' * padsize + b' %d:%s'
1453 fmt = b' ' * padsize + b' %d:%s'
1454 fm.condwrite(
1454 fm.condwrite(
1455 not ui.quiet,
1455 not ui.quiet,
1456 b'rev node',
1456 b'rev node',
1457 fmt,
1457 fmt,
1458 rev,
1458 rev,
1459 hexfunc(ctx.node()),
1459 hexfunc(ctx.node()),
1460 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1460 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1461 )
1461 )
1462 fm.context(ctx=ctx)
1462 fm.context(ctx=ctx)
1463 fm.data(active=isactive, closed=not isopen, current=current)
1463 fm.data(active=isactive, closed=not isopen, current=current)
1464 if not ui.quiet:
1464 if not ui.quiet:
1465 fm.plain(notice)
1465 fm.plain(notice)
1466 fm.plain(b'\n')
1466 fm.plain(b'\n')
1467 fm.end()
1467 fm.end()
1468
1468
1469
1469
1470 @command(
1470 @command(
1471 b'bundle',
1471 b'bundle',
1472 [
1472 [
1473 (
1473 (
1474 b'f',
1474 b'f',
1475 b'force',
1475 b'force',
1476 None,
1476 None,
1477 _(b'run even when the destination is unrelated'),
1477 _(b'run even when the destination is unrelated'),
1478 ),
1478 ),
1479 (
1479 (
1480 b'r',
1480 b'r',
1481 b'rev',
1481 b'rev',
1482 [],
1482 [],
1483 _(b'a changeset intended to be added to the destination'),
1483 _(b'a changeset intended to be added to the destination'),
1484 _(b'REV'),
1484 _(b'REV'),
1485 ),
1485 ),
1486 (
1486 (
1487 b'b',
1487 b'b',
1488 b'branch',
1488 b'branch',
1489 [],
1489 [],
1490 _(b'a specific branch you would like to bundle'),
1490 _(b'a specific branch you would like to bundle'),
1491 _(b'BRANCH'),
1491 _(b'BRANCH'),
1492 ),
1492 ),
1493 (
1493 (
1494 b'',
1494 b'',
1495 b'base',
1495 b'base',
1496 [],
1496 [],
1497 _(b'a base changeset assumed to be available at the destination'),
1497 _(b'a base changeset assumed to be available at the destination'),
1498 _(b'REV'),
1498 _(b'REV'),
1499 ),
1499 ),
1500 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1500 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1501 (
1501 (
1502 b't',
1502 b't',
1503 b'type',
1503 b'type',
1504 b'bzip2',
1504 b'bzip2',
1505 _(b'bundle compression type to use'),
1505 _(b'bundle compression type to use'),
1506 _(b'TYPE'),
1506 _(b'TYPE'),
1507 ),
1507 ),
1508 ]
1508 ]
1509 + remoteopts,
1509 + remoteopts,
1510 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1510 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1511 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1511 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1512 )
1512 )
1513 def bundle(ui, repo, fname, dest=None, **opts):
1513 def bundle(ui, repo, fname, dest=None, **opts):
1514 """create a bundle file
1514 """create a bundle file
1515
1515
1516 Generate a bundle file containing data to be transferred to another
1516 Generate a bundle file containing data to be transferred to another
1517 repository.
1517 repository.
1518
1518
1519 To create a bundle containing all changesets, use -a/--all
1519 To create a bundle containing all changesets, use -a/--all
1520 (or --base null). Otherwise, hg assumes the destination will have
1520 (or --base null). Otherwise, hg assumes the destination will have
1521 all the nodes you specify with --base parameters. Otherwise, hg
1521 all the nodes you specify with --base parameters. Otherwise, hg
1522 will assume the repository has all the nodes in destination, or
1522 will assume the repository has all the nodes in destination, or
1523 default-push/default if no destination is specified, where destination
1523 default-push/default if no destination is specified, where destination
1524 is the repository you provide through DEST option.
1524 is the repository you provide through DEST option.
1525
1525
1526 You can change bundle format with the -t/--type option. See
1526 You can change bundle format with the -t/--type option. See
1527 :hg:`help bundlespec` for documentation on this format. By default,
1527 :hg:`help bundlespec` for documentation on this format. By default,
1528 the most appropriate format is used and compression defaults to
1528 the most appropriate format is used and compression defaults to
1529 bzip2.
1529 bzip2.
1530
1530
1531 The bundle file can then be transferred using conventional means
1531 The bundle file can then be transferred using conventional means
1532 and applied to another repository with the unbundle or pull
1532 and applied to another repository with the unbundle or pull
1533 command. This is useful when direct push and pull are not
1533 command. This is useful when direct push and pull are not
1534 available or when exporting an entire repository is undesirable.
1534 available or when exporting an entire repository is undesirable.
1535
1535
1536 Applying bundles preserves all changeset contents including
1536 Applying bundles preserves all changeset contents including
1537 permissions, copy/rename information, and revision history.
1537 permissions, copy/rename information, and revision history.
1538
1538
1539 Returns 0 on success, 1 if no changes found.
1539 Returns 0 on success, 1 if no changes found.
1540 """
1540 """
1541 opts = pycompat.byteskwargs(opts)
1541 opts = pycompat.byteskwargs(opts)
1542 revs = None
1542 revs = None
1543 if b'rev' in opts:
1543 if b'rev' in opts:
1544 revstrings = opts[b'rev']
1544 revstrings = opts[b'rev']
1545 revs = scmutil.revrange(repo, revstrings)
1545 revs = scmutil.revrange(repo, revstrings)
1546 if revstrings and not revs:
1546 if revstrings and not revs:
1547 raise error.Abort(_(b'no commits to bundle'))
1547 raise error.Abort(_(b'no commits to bundle'))
1548
1548
1549 bundletype = opts.get(b'type', b'bzip2').lower()
1549 bundletype = opts.get(b'type', b'bzip2').lower()
1550 try:
1550 try:
1551 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1551 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1552 except error.UnsupportedBundleSpecification as e:
1552 except error.UnsupportedBundleSpecification as e:
1553 raise error.Abort(
1553 raise error.Abort(
1554 pycompat.bytestr(e),
1554 pycompat.bytestr(e),
1555 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1555 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1556 )
1556 )
1557 cgversion = bundlespec.contentopts[b"cg.version"]
1557 cgversion = bundlespec.contentopts[b"cg.version"]
1558
1558
1559 # Packed bundles are a pseudo bundle format for now.
1559 # Packed bundles are a pseudo bundle format for now.
1560 if cgversion == b's1':
1560 if cgversion == b's1':
1561 raise error.Abort(
1561 raise error.Abort(
1562 _(b'packed bundles cannot be produced by "hg bundle"'),
1562 _(b'packed bundles cannot be produced by "hg bundle"'),
1563 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1563 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1564 )
1564 )
1565
1565
1566 if opts.get(b'all'):
1566 if opts.get(b'all'):
1567 if dest:
1567 if dest:
1568 raise error.Abort(
1568 raise error.Abort(
1569 _(b"--all is incompatible with specifying a destination")
1569 _(b"--all is incompatible with specifying a destination")
1570 )
1570 )
1571 if opts.get(b'base'):
1571 if opts.get(b'base'):
1572 ui.warn(_(b"ignoring --base because --all was specified\n"))
1572 ui.warn(_(b"ignoring --base because --all was specified\n"))
1573 base = [nullrev]
1573 base = [nullrev]
1574 else:
1574 else:
1575 base = scmutil.revrange(repo, opts.get(b'base'))
1575 base = scmutil.revrange(repo, opts.get(b'base'))
1576 if cgversion not in changegroup.supportedoutgoingversions(repo):
1576 if cgversion not in changegroup.supportedoutgoingversions(repo):
1577 raise error.Abort(
1577 raise error.Abort(
1578 _(b"repository does not support bundle version %s") % cgversion
1578 _(b"repository does not support bundle version %s") % cgversion
1579 )
1579 )
1580
1580
1581 if base:
1581 if base:
1582 if dest:
1582 if dest:
1583 raise error.Abort(
1583 raise error.Abort(
1584 _(b"--base is incompatible with specifying a destination")
1584 _(b"--base is incompatible with specifying a destination")
1585 )
1585 )
1586 common = [repo[rev].node() for rev in base]
1586 common = [repo[rev].node() for rev in base]
1587 heads = [repo[r].node() for r in revs] if revs else None
1587 heads = [repo[r].node() for r in revs] if revs else None
1588 outgoing = discovery.outgoing(repo, common, heads)
1588 outgoing = discovery.outgoing(repo, common, heads)
1589 else:
1589 else:
1590 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1590 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1591 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1591 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1592 other = hg.peer(repo, opts, dest)
1592 other = hg.peer(repo, opts, dest)
1593 revs = [repo[r].hex() for r in revs]
1593 revs = [repo[r].hex() for r in revs]
1594 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1594 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1595 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1595 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1596 outgoing = discovery.findcommonoutgoing(
1596 outgoing = discovery.findcommonoutgoing(
1597 repo,
1597 repo,
1598 other,
1598 other,
1599 onlyheads=heads,
1599 onlyheads=heads,
1600 force=opts.get(b'force'),
1600 force=opts.get(b'force'),
1601 portable=True,
1601 portable=True,
1602 )
1602 )
1603
1603
1604 if not outgoing.missing:
1604 if not outgoing.missing:
1605 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1605 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1606 return 1
1606 return 1
1607
1607
1608 if cgversion == b'01': # bundle1
1608 if cgversion == b'01': # bundle1
1609 bversion = b'HG10' + bundlespec.wirecompression
1609 bversion = b'HG10' + bundlespec.wirecompression
1610 bcompression = None
1610 bcompression = None
1611 elif cgversion in (b'02', b'03'):
1611 elif cgversion in (b'02', b'03'):
1612 bversion = b'HG20'
1612 bversion = b'HG20'
1613 bcompression = bundlespec.wirecompression
1613 bcompression = bundlespec.wirecompression
1614 else:
1614 else:
1615 raise error.ProgrammingError(
1615 raise error.ProgrammingError(
1616 b'bundle: unexpected changegroup version %s' % cgversion
1616 b'bundle: unexpected changegroup version %s' % cgversion
1617 )
1617 )
1618
1618
1619 # TODO compression options should be derived from bundlespec parsing.
1619 # TODO compression options should be derived from bundlespec parsing.
1620 # This is a temporary hack to allow adjusting bundle compression
1620 # This is a temporary hack to allow adjusting bundle compression
1621 # level without a) formalizing the bundlespec changes to declare it
1621 # level without a) formalizing the bundlespec changes to declare it
1622 # b) introducing a command flag.
1622 # b) introducing a command flag.
1623 compopts = {}
1623 compopts = {}
1624 complevel = ui.configint(
1624 complevel = ui.configint(
1625 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1625 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1626 )
1626 )
1627 if complevel is None:
1627 if complevel is None:
1628 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1628 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1629 if complevel is not None:
1629 if complevel is not None:
1630 compopts[b'level'] = complevel
1630 compopts[b'level'] = complevel
1631
1631
1632 # Allow overriding the bundling of obsmarker in phases through
1632 # Allow overriding the bundling of obsmarker in phases through
1633 # configuration while we don't have a bundle version that include them
1633 # configuration while we don't have a bundle version that include them
1634 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1634 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1635 bundlespec.contentopts[b'obsolescence'] = True
1635 bundlespec.contentopts[b'obsolescence'] = True
1636 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1636 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1637 bundlespec.contentopts[b'phases'] = True
1637 bundlespec.contentopts[b'phases'] = True
1638
1638
1639 bundle2.writenewbundle(
1639 bundle2.writenewbundle(
1640 ui,
1640 ui,
1641 repo,
1641 repo,
1642 b'bundle',
1642 b'bundle',
1643 fname,
1643 fname,
1644 bversion,
1644 bversion,
1645 outgoing,
1645 outgoing,
1646 bundlespec.contentopts,
1646 bundlespec.contentopts,
1647 compression=bcompression,
1647 compression=bcompression,
1648 compopts=compopts,
1648 compopts=compopts,
1649 )
1649 )
1650
1650
1651
1651
1652 @command(
1652 @command(
1653 b'cat',
1653 b'cat',
1654 [
1654 [
1655 (
1655 (
1656 b'o',
1656 b'o',
1657 b'output',
1657 b'output',
1658 b'',
1658 b'',
1659 _(b'print output to file with formatted name'),
1659 _(b'print output to file with formatted name'),
1660 _(b'FORMAT'),
1660 _(b'FORMAT'),
1661 ),
1661 ),
1662 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1662 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1663 (b'', b'decode', None, _(b'apply any matching decode filter')),
1663 (b'', b'decode', None, _(b'apply any matching decode filter')),
1664 ]
1664 ]
1665 + walkopts
1665 + walkopts
1666 + formatteropts,
1666 + formatteropts,
1667 _(b'[OPTION]... FILE...'),
1667 _(b'[OPTION]... FILE...'),
1668 helpcategory=command.CATEGORY_FILE_CONTENTS,
1668 helpcategory=command.CATEGORY_FILE_CONTENTS,
1669 inferrepo=True,
1669 inferrepo=True,
1670 intents={INTENT_READONLY},
1670 intents={INTENT_READONLY},
1671 )
1671 )
1672 def cat(ui, repo, file1, *pats, **opts):
1672 def cat(ui, repo, file1, *pats, **opts):
1673 """output the current or given revision of files
1673 """output the current or given revision of files
1674
1674
1675 Print the specified files as they were at the given revision. If
1675 Print the specified files as they were at the given revision. If
1676 no revision is given, the parent of the working directory is used.
1676 no revision is given, the parent of the working directory is used.
1677
1677
1678 Output may be to a file, in which case the name of the file is
1678 Output may be to a file, in which case the name of the file is
1679 given using a template string. See :hg:`help templates`. In addition
1679 given using a template string. See :hg:`help templates`. In addition
1680 to the common template keywords, the following formatting rules are
1680 to the common template keywords, the following formatting rules are
1681 supported:
1681 supported:
1682
1682
1683 :``%%``: literal "%" character
1683 :``%%``: literal "%" character
1684 :``%s``: basename of file being printed
1684 :``%s``: basename of file being printed
1685 :``%d``: dirname of file being printed, or '.' if in repository root
1685 :``%d``: dirname of file being printed, or '.' if in repository root
1686 :``%p``: root-relative path name of file being printed
1686 :``%p``: root-relative path name of file being printed
1687 :``%H``: changeset hash (40 hexadecimal digits)
1687 :``%H``: changeset hash (40 hexadecimal digits)
1688 :``%R``: changeset revision number
1688 :``%R``: changeset revision number
1689 :``%h``: short-form changeset hash (12 hexadecimal digits)
1689 :``%h``: short-form changeset hash (12 hexadecimal digits)
1690 :``%r``: zero-padded changeset revision number
1690 :``%r``: zero-padded changeset revision number
1691 :``%b``: basename of the exporting repository
1691 :``%b``: basename of the exporting repository
1692 :``\\``: literal "\\" character
1692 :``\\``: literal "\\" character
1693
1693
1694 .. container:: verbose
1694 .. container:: verbose
1695
1695
1696 Template:
1696 Template:
1697
1697
1698 The following keywords are supported in addition to the common template
1698 The following keywords are supported in addition to the common template
1699 keywords and functions. See also :hg:`help templates`.
1699 keywords and functions. See also :hg:`help templates`.
1700
1700
1701 :data: String. File content.
1701 :data: String. File content.
1702 :path: String. Repository-absolute path of the file.
1702 :path: String. Repository-absolute path of the file.
1703
1703
1704 Returns 0 on success.
1704 Returns 0 on success.
1705 """
1705 """
1706 opts = pycompat.byteskwargs(opts)
1706 opts = pycompat.byteskwargs(opts)
1707 rev = opts.get(b'rev')
1707 rev = opts.get(b'rev')
1708 if rev:
1708 if rev:
1709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1710 ctx = scmutil.revsingle(repo, rev)
1710 ctx = scmutil.revsingle(repo, rev)
1711 m = scmutil.match(ctx, (file1,) + pats, opts)
1711 m = scmutil.match(ctx, (file1,) + pats, opts)
1712 fntemplate = opts.pop(b'output', b'')
1712 fntemplate = opts.pop(b'output', b'')
1713 if cmdutil.isstdiofilename(fntemplate):
1713 if cmdutil.isstdiofilename(fntemplate):
1714 fntemplate = b''
1714 fntemplate = b''
1715
1715
1716 if fntemplate:
1716 if fntemplate:
1717 fm = formatter.nullformatter(ui, b'cat', opts)
1717 fm = formatter.nullformatter(ui, b'cat', opts)
1718 else:
1718 else:
1719 ui.pager(b'cat')
1719 ui.pager(b'cat')
1720 fm = ui.formatter(b'cat', opts)
1720 fm = ui.formatter(b'cat', opts)
1721 with fm:
1721 with fm:
1722 return cmdutil.cat(
1722 return cmdutil.cat(
1723 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1723 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1724 )
1724 )
1725
1725
1726
1726
1727 @command(
1727 @command(
1728 b'clone',
1728 b'clone',
1729 [
1729 [
1730 (
1730 (
1731 b'U',
1731 b'U',
1732 b'noupdate',
1732 b'noupdate',
1733 None,
1733 None,
1734 _(
1734 _(
1735 b'the clone will include an empty working '
1735 b'the clone will include an empty working '
1736 b'directory (only a repository)'
1736 b'directory (only a repository)'
1737 ),
1737 ),
1738 ),
1738 ),
1739 (
1739 (
1740 b'u',
1740 b'u',
1741 b'updaterev',
1741 b'updaterev',
1742 b'',
1742 b'',
1743 _(b'revision, tag, or branch to check out'),
1743 _(b'revision, tag, or branch to check out'),
1744 _(b'REV'),
1744 _(b'REV'),
1745 ),
1745 ),
1746 (
1746 (
1747 b'r',
1747 b'r',
1748 b'rev',
1748 b'rev',
1749 [],
1749 [],
1750 _(
1750 _(
1751 b'do not clone everything, but include this changeset'
1751 b'do not clone everything, but include this changeset'
1752 b' and its ancestors'
1752 b' and its ancestors'
1753 ),
1753 ),
1754 _(b'REV'),
1754 _(b'REV'),
1755 ),
1755 ),
1756 (
1756 (
1757 b'b',
1757 b'b',
1758 b'branch',
1758 b'branch',
1759 [],
1759 [],
1760 _(
1760 _(
1761 b'do not clone everything, but include this branch\'s'
1761 b'do not clone everything, but include this branch\'s'
1762 b' changesets and their ancestors'
1762 b' changesets and their ancestors'
1763 ),
1763 ),
1764 _(b'BRANCH'),
1764 _(b'BRANCH'),
1765 ),
1765 ),
1766 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1766 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1767 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1767 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1768 (b'', b'stream', None, _(b'clone with minimal data processing')),
1768 (b'', b'stream', None, _(b'clone with minimal data processing')),
1769 ]
1769 ]
1770 + remoteopts,
1770 + remoteopts,
1771 _(b'[OPTION]... SOURCE [DEST]'),
1771 _(b'[OPTION]... SOURCE [DEST]'),
1772 helpcategory=command.CATEGORY_REPO_CREATION,
1772 helpcategory=command.CATEGORY_REPO_CREATION,
1773 helpbasic=True,
1773 helpbasic=True,
1774 norepo=True,
1774 norepo=True,
1775 )
1775 )
1776 def clone(ui, source, dest=None, **opts):
1776 def clone(ui, source, dest=None, **opts):
1777 """make a copy of an existing repository
1777 """make a copy of an existing repository
1778
1778
1779 Create a copy of an existing repository in a new directory.
1779 Create a copy of an existing repository in a new directory.
1780
1780
1781 If no destination directory name is specified, it defaults to the
1781 If no destination directory name is specified, it defaults to the
1782 basename of the source.
1782 basename of the source.
1783
1783
1784 The location of the source is added to the new repository's
1784 The location of the source is added to the new repository's
1785 ``.hg/hgrc`` file, as the default to be used for future pulls.
1785 ``.hg/hgrc`` file, as the default to be used for future pulls.
1786
1786
1787 Only local paths and ``ssh://`` URLs are supported as
1787 Only local paths and ``ssh://`` URLs are supported as
1788 destinations. For ``ssh://`` destinations, no working directory or
1788 destinations. For ``ssh://`` destinations, no working directory or
1789 ``.hg/hgrc`` will be created on the remote side.
1789 ``.hg/hgrc`` will be created on the remote side.
1790
1790
1791 If the source repository has a bookmark called '@' set, that
1791 If the source repository has a bookmark called '@' set, that
1792 revision will be checked out in the new repository by default.
1792 revision will be checked out in the new repository by default.
1793
1793
1794 To check out a particular version, use -u/--update, or
1794 To check out a particular version, use -u/--update, or
1795 -U/--noupdate to create a clone with no working directory.
1795 -U/--noupdate to create a clone with no working directory.
1796
1796
1797 To pull only a subset of changesets, specify one or more revisions
1797 To pull only a subset of changesets, specify one or more revisions
1798 identifiers with -r/--rev or branches with -b/--branch. The
1798 identifiers with -r/--rev or branches with -b/--branch. The
1799 resulting clone will contain only the specified changesets and
1799 resulting clone will contain only the specified changesets and
1800 their ancestors. These options (or 'clone src#rev dest') imply
1800 their ancestors. These options (or 'clone src#rev dest') imply
1801 --pull, even for local source repositories.
1801 --pull, even for local source repositories.
1802
1802
1803 In normal clone mode, the remote normalizes repository data into a common
1803 In normal clone mode, the remote normalizes repository data into a common
1804 exchange format and the receiving end translates this data into its local
1804 exchange format and the receiving end translates this data into its local
1805 storage format. --stream activates a different clone mode that essentially
1805 storage format. --stream activates a different clone mode that essentially
1806 copies repository files from the remote with minimal data processing. This
1806 copies repository files from the remote with minimal data processing. This
1807 significantly reduces the CPU cost of a clone both remotely and locally.
1807 significantly reduces the CPU cost of a clone both remotely and locally.
1808 However, it often increases the transferred data size by 30-40%. This can
1808 However, it often increases the transferred data size by 30-40%. This can
1809 result in substantially faster clones where I/O throughput is plentiful,
1809 result in substantially faster clones where I/O throughput is plentiful,
1810 especially for larger repositories. A side-effect of --stream clones is
1810 especially for larger repositories. A side-effect of --stream clones is
1811 that storage settings and requirements on the remote are applied locally:
1811 that storage settings and requirements on the remote are applied locally:
1812 a modern client may inherit legacy or inefficient storage used by the
1812 a modern client may inherit legacy or inefficient storage used by the
1813 remote or a legacy Mercurial client may not be able to clone from a
1813 remote or a legacy Mercurial client may not be able to clone from a
1814 modern Mercurial remote.
1814 modern Mercurial remote.
1815
1815
1816 .. note::
1816 .. note::
1817
1817
1818 Specifying a tag will include the tagged changeset but not the
1818 Specifying a tag will include the tagged changeset but not the
1819 changeset containing the tag.
1819 changeset containing the tag.
1820
1820
1821 .. container:: verbose
1821 .. container:: verbose
1822
1822
1823 For efficiency, hardlinks are used for cloning whenever the
1823 For efficiency, hardlinks are used for cloning whenever the
1824 source and destination are on the same filesystem (note this
1824 source and destination are on the same filesystem (note this
1825 applies only to the repository data, not to the working
1825 applies only to the repository data, not to the working
1826 directory). Some filesystems, such as AFS, implement hardlinking
1826 directory). Some filesystems, such as AFS, implement hardlinking
1827 incorrectly, but do not report errors. In these cases, use the
1827 incorrectly, but do not report errors. In these cases, use the
1828 --pull option to avoid hardlinking.
1828 --pull option to avoid hardlinking.
1829
1829
1830 Mercurial will update the working directory to the first applicable
1830 Mercurial will update the working directory to the first applicable
1831 revision from this list:
1831 revision from this list:
1832
1832
1833 a) null if -U or the source repository has no changesets
1833 a) null if -U or the source repository has no changesets
1834 b) if -u . and the source repository is local, the first parent of
1834 b) if -u . and the source repository is local, the first parent of
1835 the source repository's working directory
1835 the source repository's working directory
1836 c) the changeset specified with -u (if a branch name, this means the
1836 c) the changeset specified with -u (if a branch name, this means the
1837 latest head of that branch)
1837 latest head of that branch)
1838 d) the changeset specified with -r
1838 d) the changeset specified with -r
1839 e) the tipmost head specified with -b
1839 e) the tipmost head specified with -b
1840 f) the tipmost head specified with the url#branch source syntax
1840 f) the tipmost head specified with the url#branch source syntax
1841 g) the revision marked with the '@' bookmark, if present
1841 g) the revision marked with the '@' bookmark, if present
1842 h) the tipmost head of the default branch
1842 h) the tipmost head of the default branch
1843 i) tip
1843 i) tip
1844
1844
1845 When cloning from servers that support it, Mercurial may fetch
1845 When cloning from servers that support it, Mercurial may fetch
1846 pre-generated data from a server-advertised URL or inline from the
1846 pre-generated data from a server-advertised URL or inline from the
1847 same stream. When this is done, hooks operating on incoming changesets
1847 same stream. When this is done, hooks operating on incoming changesets
1848 and changegroups may fire more than once, once for each pre-generated
1848 and changegroups may fire more than once, once for each pre-generated
1849 bundle and as well as for any additional remaining data. In addition,
1849 bundle and as well as for any additional remaining data. In addition,
1850 if an error occurs, the repository may be rolled back to a partial
1850 if an error occurs, the repository may be rolled back to a partial
1851 clone. This behavior may change in future releases.
1851 clone. This behavior may change in future releases.
1852 See :hg:`help -e clonebundles` for more.
1852 See :hg:`help -e clonebundles` for more.
1853
1853
1854 Examples:
1854 Examples:
1855
1855
1856 - clone a remote repository to a new directory named hg/::
1856 - clone a remote repository to a new directory named hg/::
1857
1857
1858 hg clone https://www.mercurial-scm.org/repo/hg/
1858 hg clone https://www.mercurial-scm.org/repo/hg/
1859
1859
1860 - create a lightweight local clone::
1860 - create a lightweight local clone::
1861
1861
1862 hg clone project/ project-feature/
1862 hg clone project/ project-feature/
1863
1863
1864 - clone from an absolute path on an ssh server (note double-slash)::
1864 - clone from an absolute path on an ssh server (note double-slash)::
1865
1865
1866 hg clone ssh://user@server//home/projects/alpha/
1866 hg clone ssh://user@server//home/projects/alpha/
1867
1867
1868 - do a streaming clone while checking out a specified version::
1868 - do a streaming clone while checking out a specified version::
1869
1869
1870 hg clone --stream http://server/repo -u 1.5
1870 hg clone --stream http://server/repo -u 1.5
1871
1871
1872 - create a repository without changesets after a particular revision::
1872 - create a repository without changesets after a particular revision::
1873
1873
1874 hg clone -r 04e544 experimental/ good/
1874 hg clone -r 04e544 experimental/ good/
1875
1875
1876 - clone (and track) a particular named branch::
1876 - clone (and track) a particular named branch::
1877
1877
1878 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1878 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1879
1879
1880 See :hg:`help urls` for details on specifying URLs.
1880 See :hg:`help urls` for details on specifying URLs.
1881
1881
1882 Returns 0 on success.
1882 Returns 0 on success.
1883 """
1883 """
1884 opts = pycompat.byteskwargs(opts)
1884 opts = pycompat.byteskwargs(opts)
1885 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1885 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1886
1886
1887 # --include/--exclude can come from narrow or sparse.
1887 # --include/--exclude can come from narrow or sparse.
1888 includepats, excludepats = None, None
1888 includepats, excludepats = None, None
1889
1889
1890 # hg.clone() differentiates between None and an empty set. So make sure
1890 # hg.clone() differentiates between None and an empty set. So make sure
1891 # patterns are sets if narrow is requested without patterns.
1891 # patterns are sets if narrow is requested without patterns.
1892 if opts.get(b'narrow'):
1892 if opts.get(b'narrow'):
1893 includepats = set()
1893 includepats = set()
1894 excludepats = set()
1894 excludepats = set()
1895
1895
1896 if opts.get(b'include'):
1896 if opts.get(b'include'):
1897 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1897 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1898 if opts.get(b'exclude'):
1898 if opts.get(b'exclude'):
1899 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1899 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1900
1900
1901 r = hg.clone(
1901 r = hg.clone(
1902 ui,
1902 ui,
1903 opts,
1903 opts,
1904 source,
1904 source,
1905 dest,
1905 dest,
1906 pull=opts.get(b'pull'),
1906 pull=opts.get(b'pull'),
1907 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1907 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1908 revs=opts.get(b'rev'),
1908 revs=opts.get(b'rev'),
1909 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1909 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1910 branch=opts.get(b'branch'),
1910 branch=opts.get(b'branch'),
1911 shareopts=opts.get(b'shareopts'),
1911 shareopts=opts.get(b'shareopts'),
1912 storeincludepats=includepats,
1912 storeincludepats=includepats,
1913 storeexcludepats=excludepats,
1913 storeexcludepats=excludepats,
1914 depth=opts.get(b'depth') or None,
1914 depth=opts.get(b'depth') or None,
1915 )
1915 )
1916
1916
1917 return r is None
1917 return r is None
1918
1918
1919
1919
1920 @command(
1920 @command(
1921 b'commit|ci',
1921 b'commit|ci',
1922 [
1922 [
1923 (
1923 (
1924 b'A',
1924 b'A',
1925 b'addremove',
1925 b'addremove',
1926 None,
1926 None,
1927 _(b'mark new/missing files as added/removed before committing'),
1927 _(b'mark new/missing files as added/removed before committing'),
1928 ),
1928 ),
1929 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1929 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1930 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1930 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1931 (b's', b'secret', None, _(b'use the secret phase for committing')),
1931 (b's', b'secret', None, _(b'use the secret phase for committing')),
1932 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1932 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1933 (
1933 (
1934 b'',
1934 b'',
1935 b'force-close-branch',
1935 b'force-close-branch',
1936 None,
1936 None,
1937 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1937 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1938 ),
1938 ),
1939 (b'i', b'interactive', None, _(b'use interactive mode')),
1939 (b'i', b'interactive', None, _(b'use interactive mode')),
1940 ]
1940 ]
1941 + walkopts
1941 + walkopts
1942 + commitopts
1942 + commitopts
1943 + commitopts2
1943 + commitopts2
1944 + subrepoopts,
1944 + subrepoopts,
1945 _(b'[OPTION]... [FILE]...'),
1945 _(b'[OPTION]... [FILE]...'),
1946 helpcategory=command.CATEGORY_COMMITTING,
1946 helpcategory=command.CATEGORY_COMMITTING,
1947 helpbasic=True,
1947 helpbasic=True,
1948 inferrepo=True,
1948 inferrepo=True,
1949 )
1949 )
1950 def commit(ui, repo, *pats, **opts):
1950 def commit(ui, repo, *pats, **opts):
1951 """commit the specified files or all outstanding changes
1951 """commit the specified files or all outstanding changes
1952
1952
1953 Commit changes to the given files into the repository. Unlike a
1953 Commit changes to the given files into the repository. Unlike a
1954 centralized SCM, this operation is a local operation. See
1954 centralized SCM, this operation is a local operation. See
1955 :hg:`push` for a way to actively distribute your changes.
1955 :hg:`push` for a way to actively distribute your changes.
1956
1956
1957 If a list of files is omitted, all changes reported by :hg:`status`
1957 If a list of files is omitted, all changes reported by :hg:`status`
1958 will be committed.
1958 will be committed.
1959
1959
1960 If you are committing the result of a merge, do not provide any
1960 If you are committing the result of a merge, do not provide any
1961 filenames or -I/-X filters.
1961 filenames or -I/-X filters.
1962
1962
1963 If no commit message is specified, Mercurial starts your
1963 If no commit message is specified, Mercurial starts your
1964 configured editor where you can enter a message. In case your
1964 configured editor where you can enter a message. In case your
1965 commit fails, you will find a backup of your message in
1965 commit fails, you will find a backup of your message in
1966 ``.hg/last-message.txt``.
1966 ``.hg/last-message.txt``.
1967
1967
1968 The --close-branch flag can be used to mark the current branch
1968 The --close-branch flag can be used to mark the current branch
1969 head closed. When all heads of a branch are closed, the branch
1969 head closed. When all heads of a branch are closed, the branch
1970 will be considered closed and no longer listed.
1970 will be considered closed and no longer listed.
1971
1971
1972 The --amend flag can be used to amend the parent of the
1972 The --amend flag can be used to amend the parent of the
1973 working directory with a new commit that contains the changes
1973 working directory with a new commit that contains the changes
1974 in the parent in addition to those currently reported by :hg:`status`,
1974 in the parent in addition to those currently reported by :hg:`status`,
1975 if there are any. The old commit is stored in a backup bundle in
1975 if there are any. The old commit is stored in a backup bundle in
1976 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1976 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1977 on how to restore it).
1977 on how to restore it).
1978
1978
1979 Message, user and date are taken from the amended commit unless
1979 Message, user and date are taken from the amended commit unless
1980 specified. When a message isn't specified on the command line,
1980 specified. When a message isn't specified on the command line,
1981 the editor will open with the message of the amended commit.
1981 the editor will open with the message of the amended commit.
1982
1982
1983 It is not possible to amend public changesets (see :hg:`help phases`)
1983 It is not possible to amend public changesets (see :hg:`help phases`)
1984 or changesets that have children.
1984 or changesets that have children.
1985
1985
1986 See :hg:`help dates` for a list of formats valid for -d/--date.
1986 See :hg:`help dates` for a list of formats valid for -d/--date.
1987
1987
1988 Returns 0 on success, 1 if nothing changed.
1988 Returns 0 on success, 1 if nothing changed.
1989
1989
1990 .. container:: verbose
1990 .. container:: verbose
1991
1991
1992 Examples:
1992 Examples:
1993
1993
1994 - commit all files ending in .py::
1994 - commit all files ending in .py::
1995
1995
1996 hg commit --include "set:**.py"
1996 hg commit --include "set:**.py"
1997
1997
1998 - commit all non-binary files::
1998 - commit all non-binary files::
1999
1999
2000 hg commit --exclude "set:binary()"
2000 hg commit --exclude "set:binary()"
2001
2001
2002 - amend the current commit and set the date to now::
2002 - amend the current commit and set the date to now::
2003
2003
2004 hg commit --amend --date now
2004 hg commit --amend --date now
2005 """
2005 """
2006 with repo.wlock(), repo.lock():
2006 with repo.wlock(), repo.lock():
2007 return _docommit(ui, repo, *pats, **opts)
2007 return _docommit(ui, repo, *pats, **opts)
2008
2008
2009
2009
2010 def _docommit(ui, repo, *pats, **opts):
2010 def _docommit(ui, repo, *pats, **opts):
2011 if opts.get('interactive'):
2011 if opts.get('interactive'):
2012 opts.pop('interactive')
2012 opts.pop('interactive')
2013 ret = cmdutil.dorecord(
2013 ret = cmdutil.dorecord(
2014 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2014 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2015 )
2015 )
2016 # ret can be 0 (no changes to record) or the value returned by
2016 # ret can be 0 (no changes to record) or the value returned by
2017 # commit(), 1 if nothing changed or None on success.
2017 # commit(), 1 if nothing changed or None on success.
2018 return 1 if ret == 0 else ret
2018 return 1 if ret == 0 else ret
2019
2019
2020 opts = pycompat.byteskwargs(opts)
2020 opts = pycompat.byteskwargs(opts)
2021 if opts.get(b'subrepos'):
2021 if opts.get(b'subrepos'):
2022 if opts.get(b'amend'):
2022 if opts.get(b'amend'):
2023 raise error.Abort(_(b'cannot amend with --subrepos'))
2023 raise error.Abort(_(b'cannot amend with --subrepos'))
2024 # Let --subrepos on the command line override config setting.
2024 # Let --subrepos on the command line override config setting.
2025 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2025 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2026
2026
2027 cmdutil.checkunfinished(repo, commit=True)
2027 cmdutil.checkunfinished(repo, commit=True)
2028
2028
2029 branch = repo[None].branch()
2029 branch = repo[None].branch()
2030 bheads = repo.branchheads(branch)
2030 bheads = repo.branchheads(branch)
2031
2031
2032 extra = {}
2032 extra = {}
2033 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2033 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2034 extra[b'close'] = b'1'
2034 extra[b'close'] = b'1'
2035
2035
2036 if repo[b'.'].closesbranch():
2036 if repo[b'.'].closesbranch():
2037 raise error.Abort(
2037 raise error.Abort(
2038 _(b'current revision is already a branch closing head')
2038 _(b'current revision is already a branch closing head')
2039 )
2039 )
2040 elif not bheads:
2040 elif not bheads:
2041 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2041 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2042 elif (
2042 elif (
2043 branch == repo[b'.'].branch()
2043 branch == repo[b'.'].branch()
2044 and repo[b'.'].node() not in bheads
2044 and repo[b'.'].node() not in bheads
2045 and not opts.get(b'force_close_branch')
2045 and not opts.get(b'force_close_branch')
2046 ):
2046 ):
2047 hint = _(
2047 hint = _(
2048 b'use --force-close-branch to close branch from a non-head'
2048 b'use --force-close-branch to close branch from a non-head'
2049 b' changeset'
2049 b' changeset'
2050 )
2050 )
2051 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2051 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2052 elif opts.get(b'amend'):
2052 elif opts.get(b'amend'):
2053 if (
2053 if (
2054 repo[b'.'].p1().branch() != branch
2054 repo[b'.'].p1().branch() != branch
2055 and repo[b'.'].p2().branch() != branch
2055 and repo[b'.'].p2().branch() != branch
2056 ):
2056 ):
2057 raise error.Abort(_(b'can only close branch heads'))
2057 raise error.Abort(_(b'can only close branch heads'))
2058
2058
2059 if opts.get(b'amend'):
2059 if opts.get(b'amend'):
2060 if ui.configbool(b'ui', b'commitsubrepos'):
2060 if ui.configbool(b'ui', b'commitsubrepos'):
2061 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2061 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2062
2062
2063 old = repo[b'.']
2063 old = repo[b'.']
2064 rewriteutil.precheck(repo, [old.rev()], b'amend')
2064 rewriteutil.precheck(repo, [old.rev()], b'amend')
2065
2065
2066 # Currently histedit gets confused if an amend happens while histedit
2066 # Currently histedit gets confused if an amend happens while histedit
2067 # is in progress. Since we have a checkunfinished command, we are
2067 # is in progress. Since we have a checkunfinished command, we are
2068 # temporarily honoring it.
2068 # temporarily honoring it.
2069 #
2069 #
2070 # Note: eventually this guard will be removed. Please do not expect
2070 # Note: eventually this guard will be removed. Please do not expect
2071 # this behavior to remain.
2071 # this behavior to remain.
2072 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2072 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2073 cmdutil.checkunfinished(repo)
2073 cmdutil.checkunfinished(repo)
2074
2074
2075 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2075 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2076 if node == old.node():
2076 if node == old.node():
2077 ui.status(_(b"nothing changed\n"))
2077 ui.status(_(b"nothing changed\n"))
2078 return 1
2078 return 1
2079 else:
2079 else:
2080
2080
2081 def commitfunc(ui, repo, message, match, opts):
2081 def commitfunc(ui, repo, message, match, opts):
2082 overrides = {}
2082 overrides = {}
2083 if opts.get(b'secret'):
2083 if opts.get(b'secret'):
2084 overrides[(b'phases', b'new-commit')] = b'secret'
2084 overrides[(b'phases', b'new-commit')] = b'secret'
2085
2085
2086 baseui = repo.baseui
2086 baseui = repo.baseui
2087 with baseui.configoverride(overrides, b'commit'):
2087 with baseui.configoverride(overrides, b'commit'):
2088 with ui.configoverride(overrides, b'commit'):
2088 with ui.configoverride(overrides, b'commit'):
2089 editform = cmdutil.mergeeditform(
2089 editform = cmdutil.mergeeditform(
2090 repo[None], b'commit.normal'
2090 repo[None], b'commit.normal'
2091 )
2091 )
2092 editor = cmdutil.getcommiteditor(
2092 editor = cmdutil.getcommiteditor(
2093 editform=editform, **pycompat.strkwargs(opts)
2093 editform=editform, **pycompat.strkwargs(opts)
2094 )
2094 )
2095 return repo.commit(
2095 return repo.commit(
2096 message,
2096 message,
2097 opts.get(b'user'),
2097 opts.get(b'user'),
2098 opts.get(b'date'),
2098 opts.get(b'date'),
2099 match,
2099 match,
2100 editor=editor,
2100 editor=editor,
2101 extra=extra,
2101 extra=extra,
2102 )
2102 )
2103
2103
2104 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2104 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2105
2105
2106 if not node:
2106 if not node:
2107 stat = cmdutil.postcommitstatus(repo, pats, opts)
2107 stat = cmdutil.postcommitstatus(repo, pats, opts)
2108 if stat.deleted:
2108 if stat.deleted:
2109 ui.status(
2109 ui.status(
2110 _(
2110 _(
2111 b"nothing changed (%d missing files, see "
2111 b"nothing changed (%d missing files, see "
2112 b"'hg status')\n"
2112 b"'hg status')\n"
2113 )
2113 )
2114 % len(stat.deleted)
2114 % len(stat.deleted)
2115 )
2115 )
2116 else:
2116 else:
2117 ui.status(_(b"nothing changed\n"))
2117 ui.status(_(b"nothing changed\n"))
2118 return 1
2118 return 1
2119
2119
2120 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2120 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2121
2121
2122 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2122 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2123 status(
2123 status(
2124 ui,
2124 ui,
2125 repo,
2125 repo,
2126 modified=True,
2126 modified=True,
2127 added=True,
2127 added=True,
2128 removed=True,
2128 removed=True,
2129 deleted=True,
2129 deleted=True,
2130 unknown=True,
2130 unknown=True,
2131 subrepos=opts.get(b'subrepos'),
2131 subrepos=opts.get(b'subrepos'),
2132 )
2132 )
2133
2133
2134
2134
2135 @command(
2135 @command(
2136 b'config|showconfig|debugconfig',
2136 b'config|showconfig|debugconfig',
2137 [
2137 [
2138 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2138 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2139 (b'e', b'edit', None, _(b'edit user config')),
2139 (b'e', b'edit', None, _(b'edit user config')),
2140 (b'l', b'local', None, _(b'edit repository config')),
2140 (b'l', b'local', None, _(b'edit repository config')),
2141 (
2141 (
2142 b'',
2142 b'',
2143 b'shared',
2143 b'shared',
2144 None,
2144 None,
2145 _(b'edit shared source repository config (EXPERIMENTAL)'),
2145 _(b'edit shared source repository config (EXPERIMENTAL)'),
2146 ),
2146 ),
2147 (b'g', b'global', None, _(b'edit global config')),
2147 (b'g', b'global', None, _(b'edit global config')),
2148 ]
2148 ]
2149 + formatteropts,
2149 + formatteropts,
2150 _(b'[-u] [NAME]...'),
2150 _(b'[-u] [NAME]...'),
2151 helpcategory=command.CATEGORY_HELP,
2151 helpcategory=command.CATEGORY_HELP,
2152 optionalrepo=True,
2152 optionalrepo=True,
2153 intents={INTENT_READONLY},
2153 intents={INTENT_READONLY},
2154 )
2154 )
2155 def config(ui, repo, *values, **opts):
2155 def config(ui, repo, *values, **opts):
2156 """show combined config settings from all hgrc files
2156 """show combined config settings from all hgrc files
2157
2157
2158 With no arguments, print names and values of all config items.
2158 With no arguments, print names and values of all config items.
2159
2159
2160 With one argument of the form section.name, print just the value
2160 With one argument of the form section.name, print just the value
2161 of that config item.
2161 of that config item.
2162
2162
2163 With multiple arguments, print names and values of all config
2163 With multiple arguments, print names and values of all config
2164 items with matching section names or section.names.
2164 items with matching section names or section.names.
2165
2165
2166 With --edit, start an editor on the user-level config file. With
2166 With --edit, start an editor on the user-level config file. With
2167 --global, edit the system-wide config file. With --local, edit the
2167 --global, edit the system-wide config file. With --local, edit the
2168 repository-level config file.
2168 repository-level config file.
2169
2169
2170 With --debug, the source (filename and line number) is printed
2170 With --debug, the source (filename and line number) is printed
2171 for each config item.
2171 for each config item.
2172
2172
2173 See :hg:`help config` for more information about config files.
2173 See :hg:`help config` for more information about config files.
2174
2174
2175 .. container:: verbose
2175 .. container:: verbose
2176
2176
2177 Template:
2177 Template:
2178
2178
2179 The following keywords are supported. See also :hg:`help templates`.
2179 The following keywords are supported. See also :hg:`help templates`.
2180
2180
2181 :name: String. Config name.
2181 :name: String. Config name.
2182 :source: String. Filename and line number where the item is defined.
2182 :source: String. Filename and line number where the item is defined.
2183 :value: String. Config value.
2183 :value: String. Config value.
2184
2184
2185 The --shared flag can be used to edit the config file of shared source
2185 The --shared flag can be used to edit the config file of shared source
2186 repository. It only works when you have shared using the experimental
2186 repository. It only works when you have shared using the experimental
2187 share safe feature.
2187 share safe feature.
2188
2188
2189 Returns 0 on success, 1 if NAME does not exist.
2189 Returns 0 on success, 1 if NAME does not exist.
2190
2190
2191 """
2191 """
2192
2192
2193 opts = pycompat.byteskwargs(opts)
2193 opts = pycompat.byteskwargs(opts)
2194 editopts = (b'edit', b'local', b'global', b'shared')
2194 editopts = (b'edit', b'local', b'global', b'shared')
2195 if any(opts.get(o) for o in editopts):
2195 if any(opts.get(o) for o in editopts):
2196 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2196 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2197 if opts.get(b'local'):
2197 if opts.get(b'local'):
2198 if not repo:
2198 if not repo:
2199 raise error.Abort(_(b"can't use --local outside a repository"))
2199 raise error.Abort(_(b"can't use --local outside a repository"))
2200 paths = [repo.vfs.join(b'hgrc')]
2200 paths = [repo.vfs.join(b'hgrc')]
2201 elif opts.get(b'global'):
2201 elif opts.get(b'global'):
2202 paths = rcutil.systemrcpath()
2202 paths = rcutil.systemrcpath()
2203 elif opts.get(b'shared'):
2203 elif opts.get(b'shared'):
2204 if not repo.shared():
2204 if not repo.shared():
2205 raise error.Abort(
2205 raise error.Abort(
2206 _(b"repository is not shared; can't use --shared")
2206 _(b"repository is not shared; can't use --shared")
2207 )
2207 )
2208 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2208 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2209 raise error.Abort(
2209 raise error.Abort(
2210 _(
2210 _(
2211 b"share safe feature not unabled; "
2211 b"share safe feature not unabled; "
2212 b"unable to edit shared source repository config"
2212 b"unable to edit shared source repository config"
2213 )
2213 )
2214 )
2214 )
2215 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2215 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2216 else:
2216 else:
2217 paths = rcutil.userrcpath()
2217 paths = rcutil.userrcpath()
2218
2218
2219 for f in paths:
2219 for f in paths:
2220 if os.path.exists(f):
2220 if os.path.exists(f):
2221 break
2221 break
2222 else:
2222 else:
2223 if opts.get(b'global'):
2223 if opts.get(b'global'):
2224 samplehgrc = uimod.samplehgrcs[b'global']
2224 samplehgrc = uimod.samplehgrcs[b'global']
2225 elif opts.get(b'local'):
2225 elif opts.get(b'local'):
2226 samplehgrc = uimod.samplehgrcs[b'local']
2226 samplehgrc = uimod.samplehgrcs[b'local']
2227 else:
2227 else:
2228 samplehgrc = uimod.samplehgrcs[b'user']
2228 samplehgrc = uimod.samplehgrcs[b'user']
2229
2229
2230 f = paths[0]
2230 f = paths[0]
2231 fp = open(f, b"wb")
2231 fp = open(f, b"wb")
2232 fp.write(util.tonativeeol(samplehgrc))
2232 fp.write(util.tonativeeol(samplehgrc))
2233 fp.close()
2233 fp.close()
2234
2234
2235 editor = ui.geteditor()
2235 editor = ui.geteditor()
2236 ui.system(
2236 ui.system(
2237 b"%s \"%s\"" % (editor, f),
2237 b"%s \"%s\"" % (editor, f),
2238 onerr=error.Abort,
2238 onerr=error.Abort,
2239 errprefix=_(b"edit failed"),
2239 errprefix=_(b"edit failed"),
2240 blockedtag=b'config_edit',
2240 blockedtag=b'config_edit',
2241 )
2241 )
2242 return
2242 return
2243 ui.pager(b'config')
2243 ui.pager(b'config')
2244 fm = ui.formatter(b'config', opts)
2244 fm = ui.formatter(b'config', opts)
2245 for t, f in rcutil.rccomponents():
2245 for t, f in rcutil.rccomponents():
2246 if t == b'path':
2246 if t == b'path':
2247 ui.debug(b'read config from: %s\n' % f)
2247 ui.debug(b'read config from: %s\n' % f)
2248 elif t == b'resource':
2248 elif t == b'resource':
2249 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2249 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2250 elif t == b'items':
2250 elif t == b'items':
2251 # Don't print anything for 'items'.
2251 # Don't print anything for 'items'.
2252 pass
2252 pass
2253 else:
2253 else:
2254 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2254 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2255 untrusted = bool(opts.get(b'untrusted'))
2255 untrusted = bool(opts.get(b'untrusted'))
2256
2256
2257 selsections = selentries = []
2257 selsections = selentries = []
2258 if values:
2258 if values:
2259 selsections = [v for v in values if b'.' not in v]
2259 selsections = [v for v in values if b'.' not in v]
2260 selentries = [v for v in values if b'.' in v]
2260 selentries = [v for v in values if b'.' in v]
2261 uniquesel = len(selentries) == 1 and not selsections
2261 uniquesel = len(selentries) == 1 and not selsections
2262 selsections = set(selsections)
2262 selsections = set(selsections)
2263 selentries = set(selentries)
2263 selentries = set(selentries)
2264
2264
2265 matched = False
2265 matched = False
2266 for section, name, value in ui.walkconfig(untrusted=untrusted):
2266 for section, name, value in ui.walkconfig(untrusted=untrusted):
2267 source = ui.configsource(section, name, untrusted)
2267 source = ui.configsource(section, name, untrusted)
2268 value = pycompat.bytestr(value)
2268 value = pycompat.bytestr(value)
2269 defaultvalue = ui.configdefault(section, name)
2269 defaultvalue = ui.configdefault(section, name)
2270 if fm.isplain():
2270 if fm.isplain():
2271 source = source or b'none'
2271 source = source or b'none'
2272 value = value.replace(b'\n', b'\\n')
2272 value = value.replace(b'\n', b'\\n')
2273 entryname = section + b'.' + name
2273 entryname = section + b'.' + name
2274 if values and not (section in selsections or entryname in selentries):
2274 if values and not (section in selsections or entryname in selentries):
2275 continue
2275 continue
2276 fm.startitem()
2276 fm.startitem()
2277 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2277 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2278 if uniquesel:
2278 if uniquesel:
2279 fm.data(name=entryname)
2279 fm.data(name=entryname)
2280 fm.write(b'value', b'%s\n', value)
2280 fm.write(b'value', b'%s\n', value)
2281 else:
2281 else:
2282 fm.write(b'name value', b'%s=%s\n', entryname, value)
2282 fm.write(b'name value', b'%s=%s\n', entryname, value)
2283 if formatter.isprintable(defaultvalue):
2283 if formatter.isprintable(defaultvalue):
2284 fm.data(defaultvalue=defaultvalue)
2284 fm.data(defaultvalue=defaultvalue)
2285 elif isinstance(defaultvalue, list) and all(
2285 elif isinstance(defaultvalue, list) and all(
2286 formatter.isprintable(e) for e in defaultvalue
2286 formatter.isprintable(e) for e in defaultvalue
2287 ):
2287 ):
2288 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2288 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2289 # TODO: no idea how to process unsupported defaultvalue types
2289 # TODO: no idea how to process unsupported defaultvalue types
2290 matched = True
2290 matched = True
2291 fm.end()
2291 fm.end()
2292 if matched:
2292 if matched:
2293 return 0
2293 return 0
2294 return 1
2294 return 1
2295
2295
2296
2296
2297 @command(
2297 @command(
2298 b'continue',
2298 b'continue',
2299 dryrunopts,
2299 dryrunopts,
2300 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2300 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2301 helpbasic=True,
2301 helpbasic=True,
2302 )
2302 )
2303 def continuecmd(ui, repo, **opts):
2303 def continuecmd(ui, repo, **opts):
2304 """resumes an interrupted operation (EXPERIMENTAL)
2304 """resumes an interrupted operation (EXPERIMENTAL)
2305
2305
2306 Finishes a multistep operation like graft, histedit, rebase, merge,
2306 Finishes a multistep operation like graft, histedit, rebase, merge,
2307 and unshelve if they are in an interrupted state.
2307 and unshelve if they are in an interrupted state.
2308
2308
2309 use --dry-run/-n to dry run the command.
2309 use --dry-run/-n to dry run the command.
2310 """
2310 """
2311 dryrun = opts.get('dry_run')
2311 dryrun = opts.get('dry_run')
2312 contstate = cmdutil.getunfinishedstate(repo)
2312 contstate = cmdutil.getunfinishedstate(repo)
2313 if not contstate:
2313 if not contstate:
2314 raise error.Abort(_(b'no operation in progress'))
2314 raise error.Abort(_(b'no operation in progress'))
2315 if not contstate.continuefunc:
2315 if not contstate.continuefunc:
2316 raise error.Abort(
2316 raise error.Abort(
2317 (
2317 (
2318 _(b"%s in progress but does not support 'hg continue'")
2318 _(b"%s in progress but does not support 'hg continue'")
2319 % (contstate._opname)
2319 % (contstate._opname)
2320 ),
2320 ),
2321 hint=contstate.continuemsg(),
2321 hint=contstate.continuemsg(),
2322 )
2322 )
2323 if dryrun:
2323 if dryrun:
2324 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2324 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2325 return
2325 return
2326 return contstate.continuefunc(ui, repo)
2326 return contstate.continuefunc(ui, repo)
2327
2327
2328
2328
2329 @command(
2329 @command(
2330 b'copy|cp',
2330 b'copy|cp',
2331 [
2331 [
2332 (b'', b'forget', None, _(b'unmark a file as copied')),
2332 (b'', b'forget', None, _(b'unmark a file as copied')),
2333 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2333 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2334 (
2334 (
2335 b'',
2335 b'',
2336 b'at-rev',
2336 b'at-rev',
2337 b'',
2337 b'',
2338 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2338 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2339 _(b'REV'),
2339 _(b'REV'),
2340 ),
2340 ),
2341 (
2341 (
2342 b'f',
2342 b'f',
2343 b'force',
2343 b'force',
2344 None,
2344 None,
2345 _(b'forcibly copy over an existing managed file'),
2345 _(b'forcibly copy over an existing managed file'),
2346 ),
2346 ),
2347 ]
2347 ]
2348 + walkopts
2348 + walkopts
2349 + dryrunopts,
2349 + dryrunopts,
2350 _(b'[OPTION]... SOURCE... DEST'),
2350 _(b'[OPTION]... SOURCE... DEST'),
2351 helpcategory=command.CATEGORY_FILE_CONTENTS,
2351 helpcategory=command.CATEGORY_FILE_CONTENTS,
2352 )
2352 )
2353 def copy(ui, repo, *pats, **opts):
2353 def copy(ui, repo, *pats, **opts):
2354 """mark files as copied for the next commit
2354 """mark files as copied for the next commit
2355
2355
2356 Mark dest as having copies of source files. If dest is a
2356 Mark dest as having copies of source files. If dest is a
2357 directory, copies are put in that directory. If dest is a file,
2357 directory, copies are put in that directory. If dest is a file,
2358 the source must be a single file.
2358 the source must be a single file.
2359
2359
2360 By default, this command copies the contents of files as they
2360 By default, this command copies the contents of files as they
2361 exist in the working directory. If invoked with -A/--after, the
2361 exist in the working directory. If invoked with -A/--after, the
2362 operation is recorded, but no copying is performed.
2362 operation is recorded, but no copying is performed.
2363
2363
2364 To undo marking a file as copied, use --forget. With that option,
2364 To undo marking a file as copied, use --forget. With that option,
2365 all given (positional) arguments are unmarked as copies. The destination
2365 all given (positional) arguments are unmarked as copies. The destination
2366 file(s) will be left in place (still tracked).
2366 file(s) will be left in place (still tracked).
2367
2367
2368 This command takes effect with the next commit by default.
2368 This command takes effect with the next commit by default.
2369
2369
2370 Returns 0 on success, 1 if errors are encountered.
2370 Returns 0 on success, 1 if errors are encountered.
2371 """
2371 """
2372 opts = pycompat.byteskwargs(opts)
2372 opts = pycompat.byteskwargs(opts)
2373 with repo.wlock():
2373 with repo.wlock():
2374 return cmdutil.copy(ui, repo, pats, opts)
2374 return cmdutil.copy(ui, repo, pats, opts)
2375
2375
2376
2376
2377 @command(
2377 @command(
2378 b'debugcommands',
2378 b'debugcommands',
2379 [],
2379 [],
2380 _(b'[COMMAND]'),
2380 _(b'[COMMAND]'),
2381 helpcategory=command.CATEGORY_HELP,
2381 helpcategory=command.CATEGORY_HELP,
2382 norepo=True,
2382 norepo=True,
2383 )
2383 )
2384 def debugcommands(ui, cmd=b'', *args):
2384 def debugcommands(ui, cmd=b'', *args):
2385 """list all available commands and options"""
2385 """list all available commands and options"""
2386 for cmd, vals in sorted(pycompat.iteritems(table)):
2386 for cmd, vals in sorted(pycompat.iteritems(table)):
2387 cmd = cmd.split(b'|')[0]
2387 cmd = cmd.split(b'|')[0]
2388 opts = b', '.join([i[1] for i in vals[1]])
2388 opts = b', '.join([i[1] for i in vals[1]])
2389 ui.write(b'%s: %s\n' % (cmd, opts))
2389 ui.write(b'%s: %s\n' % (cmd, opts))
2390
2390
2391
2391
2392 @command(
2392 @command(
2393 b'debugcomplete',
2393 b'debugcomplete',
2394 [(b'o', b'options', None, _(b'show the command options'))],
2394 [(b'o', b'options', None, _(b'show the command options'))],
2395 _(b'[-o] CMD'),
2395 _(b'[-o] CMD'),
2396 helpcategory=command.CATEGORY_HELP,
2396 helpcategory=command.CATEGORY_HELP,
2397 norepo=True,
2397 norepo=True,
2398 )
2398 )
2399 def debugcomplete(ui, cmd=b'', **opts):
2399 def debugcomplete(ui, cmd=b'', **opts):
2400 """returns the completion list associated with the given command"""
2400 """returns the completion list associated with the given command"""
2401
2401
2402 if opts.get('options'):
2402 if opts.get('options'):
2403 options = []
2403 options = []
2404 otables = [globalopts]
2404 otables = [globalopts]
2405 if cmd:
2405 if cmd:
2406 aliases, entry = cmdutil.findcmd(cmd, table, False)
2406 aliases, entry = cmdutil.findcmd(cmd, table, False)
2407 otables.append(entry[1])
2407 otables.append(entry[1])
2408 for t in otables:
2408 for t in otables:
2409 for o in t:
2409 for o in t:
2410 if b"(DEPRECATED)" in o[3]:
2410 if b"(DEPRECATED)" in o[3]:
2411 continue
2411 continue
2412 if o[0]:
2412 if o[0]:
2413 options.append(b'-%s' % o[0])
2413 options.append(b'-%s' % o[0])
2414 options.append(b'--%s' % o[1])
2414 options.append(b'--%s' % o[1])
2415 ui.write(b"%s\n" % b"\n".join(options))
2415 ui.write(b"%s\n" % b"\n".join(options))
2416 return
2416 return
2417
2417
2418 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2418 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2419 if ui.verbose:
2419 if ui.verbose:
2420 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2420 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2421 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2421 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2422
2422
2423
2423
2424 @command(
2424 @command(
2425 b'diff',
2425 b'diff',
2426 [
2426 [
2427 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2427 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2428 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2428 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2429 ]
2429 ]
2430 + diffopts
2430 + diffopts
2431 + diffopts2
2431 + diffopts2
2432 + walkopts
2432 + walkopts
2433 + subrepoopts,
2433 + subrepoopts,
2434 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2434 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2435 helpcategory=command.CATEGORY_FILE_CONTENTS,
2435 helpcategory=command.CATEGORY_FILE_CONTENTS,
2436 helpbasic=True,
2436 helpbasic=True,
2437 inferrepo=True,
2437 inferrepo=True,
2438 intents={INTENT_READONLY},
2438 intents={INTENT_READONLY},
2439 )
2439 )
2440 def diff(ui, repo, *pats, **opts):
2440 def diff(ui, repo, *pats, **opts):
2441 """diff repository (or selected files)
2441 """diff repository (or selected files)
2442
2442
2443 Show differences between revisions for the specified files.
2443 Show differences between revisions for the specified files.
2444
2444
2445 Differences between files are shown using the unified diff format.
2445 Differences between files are shown using the unified diff format.
2446
2446
2447 .. note::
2447 .. note::
2448
2448
2449 :hg:`diff` may generate unexpected results for merges, as it will
2449 :hg:`diff` may generate unexpected results for merges, as it will
2450 default to comparing against the working directory's first
2450 default to comparing against the working directory's first
2451 parent changeset if no revisions are specified.
2451 parent changeset if no revisions are specified.
2452
2452
2453 When two revision arguments are given, then changes are shown
2453 When two revision arguments are given, then changes are shown
2454 between those revisions. If only one revision is specified then
2454 between those revisions. If only one revision is specified then
2455 that revision is compared to the working directory, and, when no
2455 that revision is compared to the working directory, and, when no
2456 revisions are specified, the working directory files are compared
2456 revisions are specified, the working directory files are compared
2457 to its first parent.
2457 to its first parent.
2458
2458
2459 Alternatively you can specify -c/--change with a revision to see
2459 Alternatively you can specify -c/--change with a revision to see
2460 the changes in that changeset relative to its first parent.
2460 the changes in that changeset relative to its first parent.
2461
2461
2462 Without the -a/--text option, diff will avoid generating diffs of
2462 Without the -a/--text option, diff will avoid generating diffs of
2463 files it detects as binary. With -a, diff will generate a diff
2463 files it detects as binary. With -a, diff will generate a diff
2464 anyway, probably with undesirable results.
2464 anyway, probably with undesirable results.
2465
2465
2466 Use the -g/--git option to generate diffs in the git extended diff
2466 Use the -g/--git option to generate diffs in the git extended diff
2467 format. For more information, read :hg:`help diffs`.
2467 format. For more information, read :hg:`help diffs`.
2468
2468
2469 .. container:: verbose
2469 .. container:: verbose
2470
2470
2471 Examples:
2471 Examples:
2472
2472
2473 - compare a file in the current working directory to its parent::
2473 - compare a file in the current working directory to its parent::
2474
2474
2475 hg diff foo.c
2475 hg diff foo.c
2476
2476
2477 - compare two historical versions of a directory, with rename info::
2477 - compare two historical versions of a directory, with rename info::
2478
2478
2479 hg diff --git -r 1.0:1.2 lib/
2479 hg diff --git -r 1.0:1.2 lib/
2480
2480
2481 - get change stats relative to the last change on some date::
2481 - get change stats relative to the last change on some date::
2482
2482
2483 hg diff --stat -r "date('may 2')"
2483 hg diff --stat -r "date('may 2')"
2484
2484
2485 - diff all newly-added files that contain a keyword::
2485 - diff all newly-added files that contain a keyword::
2486
2486
2487 hg diff "set:added() and grep(GNU)"
2487 hg diff "set:added() and grep(GNU)"
2488
2488
2489 - compare a revision and its parents::
2489 - compare a revision and its parents::
2490
2490
2491 hg diff -c 9353 # compare against first parent
2491 hg diff -c 9353 # compare against first parent
2492 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^:9353 # same using revset syntax
2493 hg diff -r 9353^2:9353 # compare against the second parent
2493 hg diff -r 9353^2:9353 # compare against the second parent
2494
2494
2495 Returns 0 on success.
2495 Returns 0 on success.
2496 """
2496 """
2497
2497
2498 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2498 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2499 opts = pycompat.byteskwargs(opts)
2499 opts = pycompat.byteskwargs(opts)
2500 revs = opts.get(b'rev')
2500 revs = opts.get(b'rev')
2501 change = opts.get(b'change')
2501 change = opts.get(b'change')
2502 stat = opts.get(b'stat')
2502 stat = opts.get(b'stat')
2503 reverse = opts.get(b'reverse')
2503 reverse = opts.get(b'reverse')
2504
2504
2505 if change:
2505 if change:
2506 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2506 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2507 ctx2 = scmutil.revsingle(repo, change, None)
2507 ctx2 = scmutil.revsingle(repo, change, None)
2508 ctx1 = ctx2.p1()
2508 ctx1 = ctx2.p1()
2509 else:
2509 else:
2510 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2510 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2511 ctx1, ctx2 = scmutil.revpair(repo, revs)
2511 ctx1, ctx2 = scmutil.revpair(repo, revs)
2512
2512
2513 if reverse:
2513 if reverse:
2514 ctxleft = ctx2
2514 ctxleft = ctx2
2515 ctxright = ctx1
2515 ctxright = ctx1
2516 else:
2516 else:
2517 ctxleft = ctx1
2517 ctxleft = ctx1
2518 ctxright = ctx2
2518 ctxright = ctx2
2519
2519
2520 diffopts = patch.diffallopts(ui, opts)
2520 diffopts = patch.diffallopts(ui, opts)
2521 m = scmutil.match(ctx2, pats, opts)
2521 m = scmutil.match(ctx2, pats, opts)
2522 m = repo.narrowmatch(m)
2522 m = repo.narrowmatch(m)
2523 ui.pager(b'diff')
2523 ui.pager(b'diff')
2524 logcmdutil.diffordiffstat(
2524 logcmdutil.diffordiffstat(
2525 ui,
2525 ui,
2526 repo,
2526 repo,
2527 diffopts,
2527 diffopts,
2528 ctxleft,
2528 ctxleft,
2529 ctxright,
2529 ctxright,
2530 m,
2530 m,
2531 stat=stat,
2531 stat=stat,
2532 listsubrepos=opts.get(b'subrepos'),
2532 listsubrepos=opts.get(b'subrepos'),
2533 root=opts.get(b'root'),
2533 root=opts.get(b'root'),
2534 )
2534 )
2535
2535
2536
2536
2537 @command(
2537 @command(
2538 b'export',
2538 b'export',
2539 [
2539 [
2540 (
2540 (
2541 b'B',
2541 b'B',
2542 b'bookmark',
2542 b'bookmark',
2543 b'',
2543 b'',
2544 _(b'export changes only reachable by given bookmark'),
2544 _(b'export changes only reachable by given bookmark'),
2545 _(b'BOOKMARK'),
2545 _(b'BOOKMARK'),
2546 ),
2546 ),
2547 (
2547 (
2548 b'o',
2548 b'o',
2549 b'output',
2549 b'output',
2550 b'',
2550 b'',
2551 _(b'print output to file with formatted name'),
2551 _(b'print output to file with formatted name'),
2552 _(b'FORMAT'),
2552 _(b'FORMAT'),
2553 ),
2553 ),
2554 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2554 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2555 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2555 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2556 ]
2556 ]
2557 + diffopts
2557 + diffopts
2558 + formatteropts,
2558 + formatteropts,
2559 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2559 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2560 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2560 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2561 helpbasic=True,
2561 helpbasic=True,
2562 intents={INTENT_READONLY},
2562 intents={INTENT_READONLY},
2563 )
2563 )
2564 def export(ui, repo, *changesets, **opts):
2564 def export(ui, repo, *changesets, **opts):
2565 """dump the header and diffs for one or more changesets
2565 """dump the header and diffs for one or more changesets
2566
2566
2567 Print the changeset header and diffs for one or more revisions.
2567 Print the changeset header and diffs for one or more revisions.
2568 If no revision is given, the parent of the working directory is used.
2568 If no revision is given, the parent of the working directory is used.
2569
2569
2570 The information shown in the changeset header is: author, date,
2570 The information shown in the changeset header is: author, date,
2571 branch name (if non-default), changeset hash, parent(s) and commit
2571 branch name (if non-default), changeset hash, parent(s) and commit
2572 comment.
2572 comment.
2573
2573
2574 .. note::
2574 .. note::
2575
2575
2576 :hg:`export` may generate unexpected diff output for merge
2576 :hg:`export` may generate unexpected diff output for merge
2577 changesets, as it will compare the merge changeset against its
2577 changesets, as it will compare the merge changeset against its
2578 first parent only.
2578 first parent only.
2579
2579
2580 Output may be to a file, in which case the name of the file is
2580 Output may be to a file, in which case the name of the file is
2581 given using a template string. See :hg:`help templates`. In addition
2581 given using a template string. See :hg:`help templates`. In addition
2582 to the common template keywords, the following formatting rules are
2582 to the common template keywords, the following formatting rules are
2583 supported:
2583 supported:
2584
2584
2585 :``%%``: literal "%" character
2585 :``%%``: literal "%" character
2586 :``%H``: changeset hash (40 hexadecimal digits)
2586 :``%H``: changeset hash (40 hexadecimal digits)
2587 :``%N``: number of patches being generated
2587 :``%N``: number of patches being generated
2588 :``%R``: changeset revision number
2588 :``%R``: changeset revision number
2589 :``%b``: basename of the exporting repository
2589 :``%b``: basename of the exporting repository
2590 :``%h``: short-form changeset hash (12 hexadecimal digits)
2590 :``%h``: short-form changeset hash (12 hexadecimal digits)
2591 :``%m``: first line of the commit message (only alphanumeric characters)
2591 :``%m``: first line of the commit message (only alphanumeric characters)
2592 :``%n``: zero-padded sequence number, starting at 1
2592 :``%n``: zero-padded sequence number, starting at 1
2593 :``%r``: zero-padded changeset revision number
2593 :``%r``: zero-padded changeset revision number
2594 :``\\``: literal "\\" character
2594 :``\\``: literal "\\" character
2595
2595
2596 Without the -a/--text option, export will avoid generating diffs
2596 Without the -a/--text option, export will avoid generating diffs
2597 of files it detects as binary. With -a, export will generate a
2597 of files it detects as binary. With -a, export will generate a
2598 diff anyway, probably with undesirable results.
2598 diff anyway, probably with undesirable results.
2599
2599
2600 With -B/--bookmark changesets reachable by the given bookmark are
2600 With -B/--bookmark changesets reachable by the given bookmark are
2601 selected.
2601 selected.
2602
2602
2603 Use the -g/--git option to generate diffs in the git extended diff
2603 Use the -g/--git option to generate diffs in the git extended diff
2604 format. See :hg:`help diffs` for more information.
2604 format. See :hg:`help diffs` for more information.
2605
2605
2606 With the --switch-parent option, the diff will be against the
2606 With the --switch-parent option, the diff will be against the
2607 second parent. It can be useful to review a merge.
2607 second parent. It can be useful to review a merge.
2608
2608
2609 .. container:: verbose
2609 .. container:: verbose
2610
2610
2611 Template:
2611 Template:
2612
2612
2613 The following keywords are supported in addition to the common template
2613 The following keywords are supported in addition to the common template
2614 keywords and functions. See also :hg:`help templates`.
2614 keywords and functions. See also :hg:`help templates`.
2615
2615
2616 :diff: String. Diff content.
2616 :diff: String. Diff content.
2617 :parents: List of strings. Parent nodes of the changeset.
2617 :parents: List of strings. Parent nodes of the changeset.
2618
2618
2619 Examples:
2619 Examples:
2620
2620
2621 - use export and import to transplant a bugfix to the current
2621 - use export and import to transplant a bugfix to the current
2622 branch::
2622 branch::
2623
2623
2624 hg export -r 9353 | hg import -
2624 hg export -r 9353 | hg import -
2625
2625
2626 - export all the changesets between two revisions to a file with
2626 - export all the changesets between two revisions to a file with
2627 rename information::
2627 rename information::
2628
2628
2629 hg export --git -r 123:150 > changes.txt
2629 hg export --git -r 123:150 > changes.txt
2630
2630
2631 - split outgoing changes into a series of patches with
2631 - split outgoing changes into a series of patches with
2632 descriptive names::
2632 descriptive names::
2633
2633
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2635
2635
2636 Returns 0 on success.
2636 Returns 0 on success.
2637 """
2637 """
2638 opts = pycompat.byteskwargs(opts)
2638 opts = pycompat.byteskwargs(opts)
2639 bookmark = opts.get(b'bookmark')
2639 bookmark = opts.get(b'bookmark')
2640 changesets += tuple(opts.get(b'rev', []))
2640 changesets += tuple(opts.get(b'rev', []))
2641
2641
2642 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2642 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2643
2643
2644 if bookmark:
2644 if bookmark:
2645 if bookmark not in repo._bookmarks:
2645 if bookmark not in repo._bookmarks:
2646 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2646 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2647
2647
2648 revs = scmutil.bookmarkrevs(repo, bookmark)
2648 revs = scmutil.bookmarkrevs(repo, bookmark)
2649 else:
2649 else:
2650 if not changesets:
2650 if not changesets:
2651 changesets = [b'.']
2651 changesets = [b'.']
2652
2652
2653 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2653 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2654 revs = scmutil.revrange(repo, changesets)
2654 revs = scmutil.revrange(repo, changesets)
2655
2655
2656 if not revs:
2656 if not revs:
2657 raise error.Abort(_(b"export requires at least one changeset"))
2657 raise error.Abort(_(b"export requires at least one changeset"))
2658 if len(revs) > 1:
2658 if len(revs) > 1:
2659 ui.note(_(b'exporting patches:\n'))
2659 ui.note(_(b'exporting patches:\n'))
2660 else:
2660 else:
2661 ui.note(_(b'exporting patch:\n'))
2661 ui.note(_(b'exporting patch:\n'))
2662
2662
2663 fntemplate = opts.get(b'output')
2663 fntemplate = opts.get(b'output')
2664 if cmdutil.isstdiofilename(fntemplate):
2664 if cmdutil.isstdiofilename(fntemplate):
2665 fntemplate = b''
2665 fntemplate = b''
2666
2666
2667 if fntemplate:
2667 if fntemplate:
2668 fm = formatter.nullformatter(ui, b'export', opts)
2668 fm = formatter.nullformatter(ui, b'export', opts)
2669 else:
2669 else:
2670 ui.pager(b'export')
2670 ui.pager(b'export')
2671 fm = ui.formatter(b'export', opts)
2671 fm = ui.formatter(b'export', opts)
2672 with fm:
2672 with fm:
2673 cmdutil.export(
2673 cmdutil.export(
2674 repo,
2674 repo,
2675 revs,
2675 revs,
2676 fm,
2676 fm,
2677 fntemplate=fntemplate,
2677 fntemplate=fntemplate,
2678 switch_parent=opts.get(b'switch_parent'),
2678 switch_parent=opts.get(b'switch_parent'),
2679 opts=patch.diffallopts(ui, opts),
2679 opts=patch.diffallopts(ui, opts),
2680 )
2680 )
2681
2681
2682
2682
2683 @command(
2683 @command(
2684 b'files',
2684 b'files',
2685 [
2685 [
2686 (
2686 (
2687 b'r',
2687 b'r',
2688 b'rev',
2688 b'rev',
2689 b'',
2689 b'',
2690 _(b'search the repository as it is in REV'),
2690 _(b'search the repository as it is in REV'),
2691 _(b'REV'),
2691 _(b'REV'),
2692 ),
2692 ),
2693 (
2693 (
2694 b'0',
2694 b'0',
2695 b'print0',
2695 b'print0',
2696 None,
2696 None,
2697 _(b'end filenames with NUL, for use with xargs'),
2697 _(b'end filenames with NUL, for use with xargs'),
2698 ),
2698 ),
2699 ]
2699 ]
2700 + walkopts
2700 + walkopts
2701 + formatteropts
2701 + formatteropts
2702 + subrepoopts,
2702 + subrepoopts,
2703 _(b'[OPTION]... [FILE]...'),
2703 _(b'[OPTION]... [FILE]...'),
2704 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2704 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2705 intents={INTENT_READONLY},
2705 intents={INTENT_READONLY},
2706 )
2706 )
2707 def files(ui, repo, *pats, **opts):
2707 def files(ui, repo, *pats, **opts):
2708 """list tracked files
2708 """list tracked files
2709
2709
2710 Print files under Mercurial control in the working directory or
2710 Print files under Mercurial control in the working directory or
2711 specified revision for given files (excluding removed files).
2711 specified revision for given files (excluding removed files).
2712 Files can be specified as filenames or filesets.
2712 Files can be specified as filenames or filesets.
2713
2713
2714 If no files are given to match, this command prints the names
2714 If no files are given to match, this command prints the names
2715 of all files under Mercurial control.
2715 of all files under Mercurial control.
2716
2716
2717 .. container:: verbose
2717 .. container:: verbose
2718
2718
2719 Template:
2719 Template:
2720
2720
2721 The following keywords are supported in addition to the common template
2721 The following keywords are supported in addition to the common template
2722 keywords and functions. See also :hg:`help templates`.
2722 keywords and functions. See also :hg:`help templates`.
2723
2723
2724 :flags: String. Character denoting file's symlink and executable bits.
2724 :flags: String. Character denoting file's symlink and executable bits.
2725 :path: String. Repository-absolute path of the file.
2725 :path: String. Repository-absolute path of the file.
2726 :size: Integer. Size of the file in bytes.
2726 :size: Integer. Size of the file in bytes.
2727
2727
2728 Examples:
2728 Examples:
2729
2729
2730 - list all files under the current directory::
2730 - list all files under the current directory::
2731
2731
2732 hg files .
2732 hg files .
2733
2733
2734 - shows sizes and flags for current revision::
2734 - shows sizes and flags for current revision::
2735
2735
2736 hg files -vr .
2736 hg files -vr .
2737
2737
2738 - list all files named README::
2738 - list all files named README::
2739
2739
2740 hg files -I "**/README"
2740 hg files -I "**/README"
2741
2741
2742 - list all binary files::
2742 - list all binary files::
2743
2743
2744 hg files "set:binary()"
2744 hg files "set:binary()"
2745
2745
2746 - find files containing a regular expression::
2746 - find files containing a regular expression::
2747
2747
2748 hg files "set:grep('bob')"
2748 hg files "set:grep('bob')"
2749
2749
2750 - search tracked file contents with xargs and grep::
2750 - search tracked file contents with xargs and grep::
2751
2751
2752 hg files -0 | xargs -0 grep foo
2752 hg files -0 | xargs -0 grep foo
2753
2753
2754 See :hg:`help patterns` and :hg:`help filesets` for more information
2754 See :hg:`help patterns` and :hg:`help filesets` for more information
2755 on specifying file patterns.
2755 on specifying file patterns.
2756
2756
2757 Returns 0 if a match is found, 1 otherwise.
2757 Returns 0 if a match is found, 1 otherwise.
2758
2758
2759 """
2759 """
2760
2760
2761 opts = pycompat.byteskwargs(opts)
2761 opts = pycompat.byteskwargs(opts)
2762 rev = opts.get(b'rev')
2762 rev = opts.get(b'rev')
2763 if rev:
2763 if rev:
2764 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2764 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2765 ctx = scmutil.revsingle(repo, rev, None)
2765 ctx = scmutil.revsingle(repo, rev, None)
2766
2766
2767 end = b'\n'
2767 end = b'\n'
2768 if opts.get(b'print0'):
2768 if opts.get(b'print0'):
2769 end = b'\0'
2769 end = b'\0'
2770 fmt = b'%s' + end
2770 fmt = b'%s' + end
2771
2771
2772 m = scmutil.match(ctx, pats, opts)
2772 m = scmutil.match(ctx, pats, opts)
2773 ui.pager(b'files')
2773 ui.pager(b'files')
2774 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2774 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2775 with ui.formatter(b'files', opts) as fm:
2775 with ui.formatter(b'files', opts) as fm:
2776 return cmdutil.files(
2776 return cmdutil.files(
2777 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2777 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2778 )
2778 )
2779
2779
2780
2780
2781 @command(
2781 @command(
2782 b'forget',
2782 b'forget',
2783 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2783 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2784 + walkopts
2784 + walkopts
2785 + dryrunopts,
2785 + dryrunopts,
2786 _(b'[OPTION]... FILE...'),
2786 _(b'[OPTION]... FILE...'),
2787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2788 helpbasic=True,
2788 helpbasic=True,
2789 inferrepo=True,
2789 inferrepo=True,
2790 )
2790 )
2791 def forget(ui, repo, *pats, **opts):
2791 def forget(ui, repo, *pats, **opts):
2792 """forget the specified files on the next commit
2792 """forget the specified files on the next commit
2793
2793
2794 Mark the specified files so they will no longer be tracked
2794 Mark the specified files so they will no longer be tracked
2795 after the next commit.
2795 after the next commit.
2796
2796
2797 This only removes files from the current branch, not from the
2797 This only removes files from the current branch, not from the
2798 entire project history, and it does not delete them from the
2798 entire project history, and it does not delete them from the
2799 working directory.
2799 working directory.
2800
2800
2801 To delete the file from the working directory, see :hg:`remove`.
2801 To delete the file from the working directory, see :hg:`remove`.
2802
2802
2803 To undo a forget before the next commit, see :hg:`add`.
2803 To undo a forget before the next commit, see :hg:`add`.
2804
2804
2805 .. container:: verbose
2805 .. container:: verbose
2806
2806
2807 Examples:
2807 Examples:
2808
2808
2809 - forget newly-added binary files::
2809 - forget newly-added binary files::
2810
2810
2811 hg forget "set:added() and binary()"
2811 hg forget "set:added() and binary()"
2812
2812
2813 - forget files that would be excluded by .hgignore::
2813 - forget files that would be excluded by .hgignore::
2814
2814
2815 hg forget "set:hgignore()"
2815 hg forget "set:hgignore()"
2816
2816
2817 Returns 0 on success.
2817 Returns 0 on success.
2818 """
2818 """
2819
2819
2820 opts = pycompat.byteskwargs(opts)
2820 opts = pycompat.byteskwargs(opts)
2821 if not pats:
2821 if not pats:
2822 raise error.Abort(_(b'no files specified'))
2822 raise error.Abort(_(b'no files specified'))
2823
2823
2824 m = scmutil.match(repo[None], pats, opts)
2824 m = scmutil.match(repo[None], pats, opts)
2825 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2825 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2826 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2826 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2827 rejected = cmdutil.forget(
2827 rejected = cmdutil.forget(
2828 ui,
2828 ui,
2829 repo,
2829 repo,
2830 m,
2830 m,
2831 prefix=b"",
2831 prefix=b"",
2832 uipathfn=uipathfn,
2832 uipathfn=uipathfn,
2833 explicitonly=False,
2833 explicitonly=False,
2834 dryrun=dryrun,
2834 dryrun=dryrun,
2835 interactive=interactive,
2835 interactive=interactive,
2836 )[0]
2836 )[0]
2837 return rejected and 1 or 0
2837 return rejected and 1 or 0
2838
2838
2839
2839
2840 @command(
2840 @command(
2841 b'graft',
2841 b'graft',
2842 [
2842 [
2843 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2843 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2844 (
2844 (
2845 b'',
2845 b'',
2846 b'base',
2846 b'base',
2847 b'',
2847 b'',
2848 _(b'base revision when doing the graft merge (ADVANCED)'),
2848 _(b'base revision when doing the graft merge (ADVANCED)'),
2849 _(b'REV'),
2849 _(b'REV'),
2850 ),
2850 ),
2851 (b'c', b'continue', False, _(b'resume interrupted graft')),
2851 (b'c', b'continue', False, _(b'resume interrupted graft')),
2852 (b'', b'stop', False, _(b'stop interrupted graft')),
2852 (b'', b'stop', False, _(b'stop interrupted graft')),
2853 (b'', b'abort', False, _(b'abort interrupted graft')),
2853 (b'', b'abort', False, _(b'abort interrupted graft')),
2854 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2854 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2855 (b'', b'log', None, _(b'append graft info to log message')),
2855 (b'', b'log', None, _(b'append graft info to log message')),
2856 (
2856 (
2857 b'',
2857 b'',
2858 b'no-commit',
2858 b'no-commit',
2859 None,
2859 None,
2860 _(b"don't commit, just apply the changes in working directory"),
2860 _(b"don't commit, just apply the changes in working directory"),
2861 ),
2861 ),
2862 (b'f', b'force', False, _(b'force graft')),
2862 (b'f', b'force', False, _(b'force graft')),
2863 (
2863 (
2864 b'D',
2864 b'D',
2865 b'currentdate',
2865 b'currentdate',
2866 False,
2866 False,
2867 _(b'record the current date as commit date'),
2867 _(b'record the current date as commit date'),
2868 ),
2868 ),
2869 (
2869 (
2870 b'U',
2870 b'U',
2871 b'currentuser',
2871 b'currentuser',
2872 False,
2872 False,
2873 _(b'record the current user as committer'),
2873 _(b'record the current user as committer'),
2874 ),
2874 ),
2875 ]
2875 ]
2876 + commitopts2
2876 + commitopts2
2877 + mergetoolopts
2877 + mergetoolopts
2878 + dryrunopts,
2878 + dryrunopts,
2879 _(b'[OPTION]... [-r REV]... REV...'),
2879 _(b'[OPTION]... [-r REV]... REV...'),
2880 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2880 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2881 )
2881 )
2882 def graft(ui, repo, *revs, **opts):
2882 def graft(ui, repo, *revs, **opts):
2883 '''copy changes from other branches onto the current branch
2883 '''copy changes from other branches onto the current branch
2884
2884
2885 This command uses Mercurial's merge logic to copy individual
2885 This command uses Mercurial's merge logic to copy individual
2886 changes from other branches without merging branches in the
2886 changes from other branches without merging branches in the
2887 history graph. This is sometimes known as 'backporting' or
2887 history graph. This is sometimes known as 'backporting' or
2888 'cherry-picking'. By default, graft will copy user, date, and
2888 'cherry-picking'. By default, graft will copy user, date, and
2889 description from the source changesets.
2889 description from the source changesets.
2890
2890
2891 Changesets that are ancestors of the current revision, that have
2891 Changesets that are ancestors of the current revision, that have
2892 already been grafted, or that are merges will be skipped.
2892 already been grafted, or that are merges will be skipped.
2893
2893
2894 If --log is specified, log messages will have a comment appended
2894 If --log is specified, log messages will have a comment appended
2895 of the form::
2895 of the form::
2896
2896
2897 (grafted from CHANGESETHASH)
2897 (grafted from CHANGESETHASH)
2898
2898
2899 If --force is specified, revisions will be grafted even if they
2899 If --force is specified, revisions will be grafted even if they
2900 are already ancestors of, or have been grafted to, the destination.
2900 are already ancestors of, or have been grafted to, the destination.
2901 This is useful when the revisions have since been backed out.
2901 This is useful when the revisions have since been backed out.
2902
2902
2903 If a graft merge results in conflicts, the graft process is
2903 If a graft merge results in conflicts, the graft process is
2904 interrupted so that the current merge can be manually resolved.
2904 interrupted so that the current merge can be manually resolved.
2905 Once all conflicts are addressed, the graft process can be
2905 Once all conflicts are addressed, the graft process can be
2906 continued with the -c/--continue option.
2906 continued with the -c/--continue option.
2907
2907
2908 The -c/--continue option reapplies all the earlier options.
2908 The -c/--continue option reapplies all the earlier options.
2909
2909
2910 .. container:: verbose
2910 .. container:: verbose
2911
2911
2912 The --base option exposes more of how graft internally uses merge with a
2912 The --base option exposes more of how graft internally uses merge with a
2913 custom base revision. --base can be used to specify another ancestor than
2913 custom base revision. --base can be used to specify another ancestor than
2914 the first and only parent.
2914 the first and only parent.
2915
2915
2916 The command::
2916 The command::
2917
2917
2918 hg graft -r 345 --base 234
2918 hg graft -r 345 --base 234
2919
2919
2920 is thus pretty much the same as::
2920 is thus pretty much the same as::
2921
2921
2922 hg diff -r 234 -r 345 | hg import
2922 hg diff -r 234 -r 345 | hg import
2923
2923
2924 but using merge to resolve conflicts and track moved files.
2924 but using merge to resolve conflicts and track moved files.
2925
2925
2926 The result of a merge can thus be backported as a single commit by
2926 The result of a merge can thus be backported as a single commit by
2927 specifying one of the merge parents as base, and thus effectively
2927 specifying one of the merge parents as base, and thus effectively
2928 grafting the changes from the other side.
2928 grafting the changes from the other side.
2929
2929
2930 It is also possible to collapse multiple changesets and clean up history
2930 It is also possible to collapse multiple changesets and clean up history
2931 by specifying another ancestor as base, much like rebase --collapse
2931 by specifying another ancestor as base, much like rebase --collapse
2932 --keep.
2932 --keep.
2933
2933
2934 The commit message can be tweaked after the fact using commit --amend .
2934 The commit message can be tweaked after the fact using commit --amend .
2935
2935
2936 For using non-ancestors as the base to backout changes, see the backout
2936 For using non-ancestors as the base to backout changes, see the backout
2937 command and the hidden --parent option.
2937 command and the hidden --parent option.
2938
2938
2939 .. container:: verbose
2939 .. container:: verbose
2940
2940
2941 Examples:
2941 Examples:
2942
2942
2943 - copy a single change to the stable branch and edit its description::
2943 - copy a single change to the stable branch and edit its description::
2944
2944
2945 hg update stable
2945 hg update stable
2946 hg graft --edit 9393
2946 hg graft --edit 9393
2947
2947
2948 - graft a range of changesets with one exception, updating dates::
2948 - graft a range of changesets with one exception, updating dates::
2949
2949
2950 hg graft -D "2085::2093 and not 2091"
2950 hg graft -D "2085::2093 and not 2091"
2951
2951
2952 - continue a graft after resolving conflicts::
2952 - continue a graft after resolving conflicts::
2953
2953
2954 hg graft -c
2954 hg graft -c
2955
2955
2956 - show the source of a grafted changeset::
2956 - show the source of a grafted changeset::
2957
2957
2958 hg log --debug -r .
2958 hg log --debug -r .
2959
2959
2960 - show revisions sorted by date::
2960 - show revisions sorted by date::
2961
2961
2962 hg log -r "sort(all(), date)"
2962 hg log -r "sort(all(), date)"
2963
2963
2964 - backport the result of a merge as a single commit::
2964 - backport the result of a merge as a single commit::
2965
2965
2966 hg graft -r 123 --base 123^
2966 hg graft -r 123 --base 123^
2967
2967
2968 - land a feature branch as one changeset::
2968 - land a feature branch as one changeset::
2969
2969
2970 hg up -cr default
2970 hg up -cr default
2971 hg graft -r featureX --base "ancestor('featureX', 'default')"
2971 hg graft -r featureX --base "ancestor('featureX', 'default')"
2972
2972
2973 See :hg:`help revisions` for more about specifying revisions.
2973 See :hg:`help revisions` for more about specifying revisions.
2974
2974
2975 Returns 0 on successful completion, 1 if there are unresolved files.
2975 Returns 0 on successful completion, 1 if there are unresolved files.
2976 '''
2976 '''
2977 with repo.wlock():
2977 with repo.wlock():
2978 return _dograft(ui, repo, *revs, **opts)
2978 return _dograft(ui, repo, *revs, **opts)
2979
2979
2980
2980
2981 def _dograft(ui, repo, *revs, **opts):
2981 def _dograft(ui, repo, *revs, **opts):
2982 opts = pycompat.byteskwargs(opts)
2982 opts = pycompat.byteskwargs(opts)
2983 if revs and opts.get(b'rev'):
2983 if revs and opts.get(b'rev'):
2984 ui.warn(
2984 ui.warn(
2985 _(
2985 _(
2986 b'warning: inconsistent use of --rev might give unexpected '
2986 b'warning: inconsistent use of --rev might give unexpected '
2987 b'revision ordering!\n'
2987 b'revision ordering!\n'
2988 )
2988 )
2989 )
2989 )
2990
2990
2991 revs = list(revs)
2991 revs = list(revs)
2992 revs.extend(opts.get(b'rev'))
2992 revs.extend(opts.get(b'rev'))
2993 # a dict of data to be stored in state file
2993 # a dict of data to be stored in state file
2994 statedata = {}
2994 statedata = {}
2995 # list of new nodes created by ongoing graft
2995 # list of new nodes created by ongoing graft
2996 statedata[b'newnodes'] = []
2996 statedata[b'newnodes'] = []
2997
2997
2998 cmdutil.resolvecommitoptions(ui, opts)
2998 cmdutil.resolvecommitoptions(ui, opts)
2999
2999
3000 editor = cmdutil.getcommiteditor(
3000 editor = cmdutil.getcommiteditor(
3001 editform=b'graft', **pycompat.strkwargs(opts)
3001 editform=b'graft', **pycompat.strkwargs(opts)
3002 )
3002 )
3003
3003
3004 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3004 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3005
3005
3006 cont = False
3006 cont = False
3007 if opts.get(b'no_commit'):
3007 if opts.get(b'no_commit'):
3008 cmdutil.check_incompatible_arguments(
3008 cmdutil.check_incompatible_arguments(
3009 opts,
3009 opts,
3010 b'no_commit',
3010 b'no_commit',
3011 [b'edit', b'currentuser', b'currentdate', b'log'],
3011 [b'edit', b'currentuser', b'currentdate', b'log'],
3012 )
3012 )
3013
3013
3014 graftstate = statemod.cmdstate(repo, b'graftstate')
3014 graftstate = statemod.cmdstate(repo, b'graftstate')
3015
3015
3016 if opts.get(b'stop'):
3016 if opts.get(b'stop'):
3017 cmdutil.check_incompatible_arguments(
3017 cmdutil.check_incompatible_arguments(
3018 opts,
3018 opts,
3019 b'stop',
3019 b'stop',
3020 [
3020 [
3021 b'edit',
3021 b'edit',
3022 b'log',
3022 b'log',
3023 b'user',
3023 b'user',
3024 b'date',
3024 b'date',
3025 b'currentdate',
3025 b'currentdate',
3026 b'currentuser',
3026 b'currentuser',
3027 b'rev',
3027 b'rev',
3028 ],
3028 ],
3029 )
3029 )
3030 return _stopgraft(ui, repo, graftstate)
3030 return _stopgraft(ui, repo, graftstate)
3031 elif opts.get(b'abort'):
3031 elif opts.get(b'abort'):
3032 cmdutil.check_incompatible_arguments(
3032 cmdutil.check_incompatible_arguments(
3033 opts,
3033 opts,
3034 b'abort',
3034 b'abort',
3035 [
3035 [
3036 b'edit',
3036 b'edit',
3037 b'log',
3037 b'log',
3038 b'user',
3038 b'user',
3039 b'date',
3039 b'date',
3040 b'currentdate',
3040 b'currentdate',
3041 b'currentuser',
3041 b'currentuser',
3042 b'rev',
3042 b'rev',
3043 ],
3043 ],
3044 )
3044 )
3045 return cmdutil.abortgraft(ui, repo, graftstate)
3045 return cmdutil.abortgraft(ui, repo, graftstate)
3046 elif opts.get(b'continue'):
3046 elif opts.get(b'continue'):
3047 cont = True
3047 cont = True
3048 if revs:
3048 if revs:
3049 raise error.Abort(_(b"can't specify --continue and revisions"))
3049 raise error.Abort(_(b"can't specify --continue and revisions"))
3050 # read in unfinished revisions
3050 # read in unfinished revisions
3051 if graftstate.exists():
3051 if graftstate.exists():
3052 statedata = cmdutil.readgraftstate(repo, graftstate)
3052 statedata = cmdutil.readgraftstate(repo, graftstate)
3053 if statedata.get(b'date'):
3053 if statedata.get(b'date'):
3054 opts[b'date'] = statedata[b'date']
3054 opts[b'date'] = statedata[b'date']
3055 if statedata.get(b'user'):
3055 if statedata.get(b'user'):
3056 opts[b'user'] = statedata[b'user']
3056 opts[b'user'] = statedata[b'user']
3057 if statedata.get(b'log'):
3057 if statedata.get(b'log'):
3058 opts[b'log'] = True
3058 opts[b'log'] = True
3059 if statedata.get(b'no_commit'):
3059 if statedata.get(b'no_commit'):
3060 opts[b'no_commit'] = statedata.get(b'no_commit')
3060 opts[b'no_commit'] = statedata.get(b'no_commit')
3061 if statedata.get(b'base'):
3061 if statedata.get(b'base'):
3062 opts[b'base'] = statedata.get(b'base')
3062 opts[b'base'] = statedata.get(b'base')
3063 nodes = statedata[b'nodes']
3063 nodes = statedata[b'nodes']
3064 revs = [repo[node].rev() for node in nodes]
3064 revs = [repo[node].rev() for node in nodes]
3065 else:
3065 else:
3066 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3066 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3067 else:
3067 else:
3068 if not revs:
3068 if not revs:
3069 raise error.Abort(_(b'no revisions specified'))
3069 raise error.Abort(_(b'no revisions specified'))
3070 cmdutil.checkunfinished(repo)
3070 cmdutil.checkunfinished(repo)
3071 cmdutil.bailifchanged(repo)
3071 cmdutil.bailifchanged(repo)
3072 revs = scmutil.revrange(repo, revs)
3072 revs = scmutil.revrange(repo, revs)
3073
3073
3074 skipped = set()
3074 skipped = set()
3075 basectx = None
3075 basectx = None
3076 if opts.get(b'base'):
3076 if opts.get(b'base'):
3077 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3077 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3078 if basectx is None:
3078 if basectx is None:
3079 # check for merges
3079 # check for merges
3080 for rev in repo.revs(b'%ld and merge()', revs):
3080 for rev in repo.revs(b'%ld and merge()', revs):
3081 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3081 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3082 skipped.add(rev)
3082 skipped.add(rev)
3083 revs = [r for r in revs if r not in skipped]
3083 revs = [r for r in revs if r not in skipped]
3084 if not revs:
3084 if not revs:
3085 return -1
3085 return -1
3086 if basectx is not None and len(revs) != 1:
3086 if basectx is not None and len(revs) != 1:
3087 raise error.Abort(_(b'only one revision allowed with --base '))
3087 raise error.Abort(_(b'only one revision allowed with --base '))
3088
3088
3089 # Don't check in the --continue case, in effect retaining --force across
3089 # Don't check in the --continue case, in effect retaining --force across
3090 # --continues. That's because without --force, any revisions we decided to
3090 # --continues. That's because without --force, any revisions we decided to
3091 # skip would have been filtered out here, so they wouldn't have made their
3091 # skip would have been filtered out here, so they wouldn't have made their
3092 # way to the graftstate. With --force, any revisions we would have otherwise
3092 # way to the graftstate. With --force, any revisions we would have otherwise
3093 # skipped would not have been filtered out, and if they hadn't been applied
3093 # skipped would not have been filtered out, and if they hadn't been applied
3094 # already, they'd have been in the graftstate.
3094 # already, they'd have been in the graftstate.
3095 if not (cont or opts.get(b'force')) and basectx is None:
3095 if not (cont or opts.get(b'force')) and basectx is None:
3096 # check for ancestors of dest branch
3096 # check for ancestors of dest branch
3097 ancestors = repo.revs(b'%ld & (::.)', revs)
3097 ancestors = repo.revs(b'%ld & (::.)', revs)
3098 for rev in ancestors:
3098 for rev in ancestors:
3099 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3099 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3100
3100
3101 revs = [r for r in revs if r not in ancestors]
3101 revs = [r for r in revs if r not in ancestors]
3102
3102
3103 if not revs:
3103 if not revs:
3104 return -1
3104 return -1
3105
3105
3106 # analyze revs for earlier grafts
3106 # analyze revs for earlier grafts
3107 ids = {}
3107 ids = {}
3108 for ctx in repo.set(b"%ld", revs):
3108 for ctx in repo.set(b"%ld", revs):
3109 ids[ctx.hex()] = ctx.rev()
3109 ids[ctx.hex()] = ctx.rev()
3110 n = ctx.extra().get(b'source')
3110 n = ctx.extra().get(b'source')
3111 if n:
3111 if n:
3112 ids[n] = ctx.rev()
3112 ids[n] = ctx.rev()
3113
3113
3114 # check ancestors for earlier grafts
3114 # check ancestors for earlier grafts
3115 ui.debug(b'scanning for duplicate grafts\n')
3115 ui.debug(b'scanning for duplicate grafts\n')
3116
3116
3117 # The only changesets we can be sure doesn't contain grafts of any
3117 # The only changesets we can be sure doesn't contain grafts of any
3118 # revs, are the ones that are common ancestors of *all* revs:
3118 # revs, are the ones that are common ancestors of *all* revs:
3119 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3119 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3120 ctx = repo[rev]
3120 ctx = repo[rev]
3121 n = ctx.extra().get(b'source')
3121 n = ctx.extra().get(b'source')
3122 if n in ids:
3122 if n in ids:
3123 try:
3123 try:
3124 r = repo[n].rev()
3124 r = repo[n].rev()
3125 except error.RepoLookupError:
3125 except error.RepoLookupError:
3126 r = None
3126 r = None
3127 if r in revs:
3127 if r in revs:
3128 ui.warn(
3128 ui.warn(
3129 _(
3129 _(
3130 b'skipping revision %d:%s '
3130 b'skipping revision %d:%s '
3131 b'(already grafted to %d:%s)\n'
3131 b'(already grafted to %d:%s)\n'
3132 )
3132 )
3133 % (r, repo[r], rev, ctx)
3133 % (r, repo[r], rev, ctx)
3134 )
3134 )
3135 revs.remove(r)
3135 revs.remove(r)
3136 elif ids[n] in revs:
3136 elif ids[n] in revs:
3137 if r is None:
3137 if r is None:
3138 ui.warn(
3138 ui.warn(
3139 _(
3139 _(
3140 b'skipping already grafted revision %d:%s '
3140 b'skipping already grafted revision %d:%s '
3141 b'(%d:%s also has unknown origin %s)\n'
3141 b'(%d:%s also has unknown origin %s)\n'
3142 )
3142 )
3143 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3143 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3144 )
3144 )
3145 else:
3145 else:
3146 ui.warn(
3146 ui.warn(
3147 _(
3147 _(
3148 b'skipping already grafted revision %d:%s '
3148 b'skipping already grafted revision %d:%s '
3149 b'(%d:%s also has origin %d:%s)\n'
3149 b'(%d:%s also has origin %d:%s)\n'
3150 )
3150 )
3151 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3151 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3152 )
3152 )
3153 revs.remove(ids[n])
3153 revs.remove(ids[n])
3154 elif ctx.hex() in ids:
3154 elif ctx.hex() in ids:
3155 r = ids[ctx.hex()]
3155 r = ids[ctx.hex()]
3156 if r in revs:
3156 if r in revs:
3157 ui.warn(
3157 ui.warn(
3158 _(
3158 _(
3159 b'skipping already grafted revision %d:%s '
3159 b'skipping already grafted revision %d:%s '
3160 b'(was grafted from %d:%s)\n'
3160 b'(was grafted from %d:%s)\n'
3161 )
3161 )
3162 % (r, repo[r], rev, ctx)
3162 % (r, repo[r], rev, ctx)
3163 )
3163 )
3164 revs.remove(r)
3164 revs.remove(r)
3165 if not revs:
3165 if not revs:
3166 return -1
3166 return -1
3167
3167
3168 if opts.get(b'no_commit'):
3168 if opts.get(b'no_commit'):
3169 statedata[b'no_commit'] = True
3169 statedata[b'no_commit'] = True
3170 if opts.get(b'base'):
3170 if opts.get(b'base'):
3171 statedata[b'base'] = opts[b'base']
3171 statedata[b'base'] = opts[b'base']
3172 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3172 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3173 desc = b'%d:%s "%s"' % (
3173 desc = b'%d:%s "%s"' % (
3174 ctx.rev(),
3174 ctx.rev(),
3175 ctx,
3175 ctx,
3176 ctx.description().split(b'\n', 1)[0],
3176 ctx.description().split(b'\n', 1)[0],
3177 )
3177 )
3178 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3178 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3179 if names:
3179 if names:
3180 desc += b' (%s)' % b' '.join(names)
3180 desc += b' (%s)' % b' '.join(names)
3181 ui.status(_(b'grafting %s\n') % desc)
3181 ui.status(_(b'grafting %s\n') % desc)
3182 if opts.get(b'dry_run'):
3182 if opts.get(b'dry_run'):
3183 continue
3183 continue
3184
3184
3185 source = ctx.extra().get(b'source')
3185 source = ctx.extra().get(b'source')
3186 extra = {}
3186 extra = {}
3187 if source:
3187 if source:
3188 extra[b'source'] = source
3188 extra[b'source'] = source
3189 extra[b'intermediate-source'] = ctx.hex()
3189 extra[b'intermediate-source'] = ctx.hex()
3190 else:
3190 else:
3191 extra[b'source'] = ctx.hex()
3191 extra[b'source'] = ctx.hex()
3192 user = ctx.user()
3192 user = ctx.user()
3193 if opts.get(b'user'):
3193 if opts.get(b'user'):
3194 user = opts[b'user']
3194 user = opts[b'user']
3195 statedata[b'user'] = user
3195 statedata[b'user'] = user
3196 date = ctx.date()
3196 date = ctx.date()
3197 if opts.get(b'date'):
3197 if opts.get(b'date'):
3198 date = opts[b'date']
3198 date = opts[b'date']
3199 statedata[b'date'] = date
3199 statedata[b'date'] = date
3200 message = ctx.description()
3200 message = ctx.description()
3201 if opts.get(b'log'):
3201 if opts.get(b'log'):
3202 message += b'\n(grafted from %s)' % ctx.hex()
3202 message += b'\n(grafted from %s)' % ctx.hex()
3203 statedata[b'log'] = True
3203 statedata[b'log'] = True
3204
3204
3205 # we don't merge the first commit when continuing
3205 # we don't merge the first commit when continuing
3206 if not cont:
3206 if not cont:
3207 # perform the graft merge with p1(rev) as 'ancestor'
3207 # perform the graft merge with p1(rev) as 'ancestor'
3208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3209 base = ctx.p1() if basectx is None else basectx
3209 base = ctx.p1() if basectx is None else basectx
3210 with ui.configoverride(overrides, b'graft'):
3210 with ui.configoverride(overrides, b'graft'):
3211 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3211 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3212 # report any conflicts
3212 # report any conflicts
3213 if stats.unresolvedcount > 0:
3213 if stats.unresolvedcount > 0:
3214 # write out state for --continue
3214 # write out state for --continue
3215 nodes = [repo[rev].hex() for rev in revs[pos:]]
3215 nodes = [repo[rev].hex() for rev in revs[pos:]]
3216 statedata[b'nodes'] = nodes
3216 statedata[b'nodes'] = nodes
3217 stateversion = 1
3217 stateversion = 1
3218 graftstate.save(stateversion, statedata)
3218 graftstate.save(stateversion, statedata)
3219 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3219 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3220 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3220 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3221 return 1
3221 return 1
3222 else:
3222 else:
3223 cont = False
3223 cont = False
3224
3224
3225 # commit if --no-commit is false
3225 # commit if --no-commit is false
3226 if not opts.get(b'no_commit'):
3226 if not opts.get(b'no_commit'):
3227 node = repo.commit(
3227 node = repo.commit(
3228 text=message, user=user, date=date, extra=extra, editor=editor
3228 text=message, user=user, date=date, extra=extra, editor=editor
3229 )
3229 )
3230 if node is None:
3230 if node is None:
3231 ui.warn(
3231 ui.warn(
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3233 % (ctx.rev(), ctx)
3233 % (ctx.rev(), ctx)
3234 )
3234 )
3235 # checking that newnodes exist because old state files won't have it
3235 # checking that newnodes exist because old state files won't have it
3236 elif statedata.get(b'newnodes') is not None:
3236 elif statedata.get(b'newnodes') is not None:
3237 statedata[b'newnodes'].append(node)
3237 statedata[b'newnodes'].append(node)
3238
3238
3239 # remove state when we complete successfully
3239 # remove state when we complete successfully
3240 if not opts.get(b'dry_run'):
3240 if not opts.get(b'dry_run'):
3241 graftstate.delete()
3241 graftstate.delete()
3242
3242
3243 return 0
3243 return 0
3244
3244
3245
3245
3246 def _stopgraft(ui, repo, graftstate):
3246 def _stopgraft(ui, repo, graftstate):
3247 """stop the interrupted graft"""
3247 """stop the interrupted graft"""
3248 if not graftstate.exists():
3248 if not graftstate.exists():
3249 raise error.Abort(_(b"no interrupted graft found"))
3249 raise error.Abort(_(b"no interrupted graft found"))
3250 pctx = repo[b'.']
3250 pctx = repo[b'.']
3251 mergemod.clean_update(pctx)
3251 mergemod.clean_update(pctx)
3252 graftstate.delete()
3252 graftstate.delete()
3253 ui.status(_(b"stopped the interrupted graft\n"))
3253 ui.status(_(b"stopped the interrupted graft\n"))
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3255 return 0
3255 return 0
3256
3256
3257
3257
3258 statemod.addunfinished(
3258 statemod.addunfinished(
3259 b'graft',
3259 b'graft',
3260 fname=b'graftstate',
3260 fname=b'graftstate',
3261 clearable=True,
3261 clearable=True,
3262 stopflag=True,
3262 stopflag=True,
3263 continueflag=True,
3263 continueflag=True,
3264 abortfunc=cmdutil.hgabortgraft,
3264 abortfunc=cmdutil.hgabortgraft,
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3266 )
3266 )
3267
3267
3268
3268
3269 @command(
3269 @command(
3270 b'grep',
3270 b'grep',
3271 [
3271 [
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3273 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3273 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3274 (
3274 (
3275 b'',
3275 b'',
3276 b'diff',
3276 b'diff',
3277 None,
3277 None,
3278 _(
3278 _(
3279 b'search revision differences for when the pattern was added '
3279 b'search revision differences for when the pattern was added '
3280 b'or removed'
3280 b'or removed'
3281 ),
3281 ),
3282 ),
3282 ),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3284 (
3284 (
3285 b'f',
3285 b'f',
3286 b'follow',
3286 b'follow',
3287 None,
3287 None,
3288 _(
3288 _(
3289 b'follow changeset history,'
3289 b'follow changeset history,'
3290 b' or file history across copies and renames'
3290 b' or file history across copies and renames'
3291 ),
3291 ),
3292 ),
3292 ),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3294 (
3294 (
3295 b'l',
3295 b'l',
3296 b'files-with-matches',
3296 b'files-with-matches',
3297 None,
3297 None,
3298 _(b'print only filenames and revisions that match'),
3298 _(b'print only filenames and revisions that match'),
3299 ),
3299 ),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3301 (
3301 (
3302 b'r',
3302 b'r',
3303 b'rev',
3303 b'rev',
3304 [],
3304 [],
3305 _(b'search files changed within revision range'),
3305 _(b'search files changed within revision range'),
3306 _(b'REV'),
3306 _(b'REV'),
3307 ),
3307 ),
3308 (
3308 (
3309 b'',
3309 b'',
3310 b'all-files',
3310 b'all-files',
3311 None,
3311 None,
3312 _(
3312 _(
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3314 ),
3314 ),
3315 ),
3315 ),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3317 (b'd', b'date', None, _(b'list the date (short with -q)')),
3318 ]
3318 ]
3319 + formatteropts
3319 + formatteropts
3320 + walkopts,
3320 + walkopts,
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3323 inferrepo=True,
3323 inferrepo=True,
3324 intents={INTENT_READONLY},
3324 intents={INTENT_READONLY},
3325 )
3325 )
3326 def grep(ui, repo, pattern, *pats, **opts):
3326 def grep(ui, repo, pattern, *pats, **opts):
3327 """search for a pattern in specified files
3327 """search for a pattern in specified files
3328
3328
3329 Search the working directory or revision history for a regular
3329 Search the working directory or revision history for a regular
3330 expression in the specified files for the entire repository.
3330 expression in the specified files for the entire repository.
3331
3331
3332 By default, grep searches the repository files in the working
3332 By default, grep searches the repository files in the working
3333 directory and prints the files where it finds a match. To specify
3333 directory and prints the files where it finds a match. To specify
3334 historical revisions instead of the working directory, use the
3334 historical revisions instead of the working directory, use the
3335 --rev flag.
3335 --rev flag.
3336
3336
3337 To search instead historical revision differences that contains a
3337 To search instead historical revision differences that contains a
3338 change in match status ("-" for a match that becomes a non-match,
3338 change in match status ("-" for a match that becomes a non-match,
3339 or "+" for a non-match that becomes a match), use the --diff flag.
3339 or "+" for a non-match that becomes a match), use the --diff flag.
3340
3340
3341 PATTERN can be any Python (roughly Perl-compatible) regular
3341 PATTERN can be any Python (roughly Perl-compatible) regular
3342 expression.
3342 expression.
3343
3343
3344 If no FILEs are specified and the --rev flag isn't supplied, all
3344 If no FILEs are specified and the --rev flag isn't supplied, all
3345 files in the working directory are searched. When using the --rev
3345 files in the working directory are searched. When using the --rev
3346 flag and specifying FILEs, use the --follow argument to also
3346 flag and specifying FILEs, use the --follow argument to also
3347 follow the specified FILEs across renames and copies.
3347 follow the specified FILEs across renames and copies.
3348
3348
3349 .. container:: verbose
3349 .. container:: verbose
3350
3350
3351 Template:
3351 Template:
3352
3352
3353 The following keywords are supported in addition to the common template
3353 The following keywords are supported in addition to the common template
3354 keywords and functions. See also :hg:`help templates`.
3354 keywords and functions. See also :hg:`help templates`.
3355
3355
3356 :change: String. Character denoting insertion ``+`` or removal ``-``.
3356 :change: String. Character denoting insertion ``+`` or removal ``-``.
3357 Available if ``--diff`` is specified.
3357 Available if ``--diff`` is specified.
3358 :lineno: Integer. Line number of the match.
3358 :lineno: Integer. Line number of the match.
3359 :path: String. Repository-absolute path of the file.
3359 :path: String. Repository-absolute path of the file.
3360 :texts: List of text chunks.
3360 :texts: List of text chunks.
3361
3361
3362 And each entry of ``{texts}`` provides the following sub-keywords.
3362 And each entry of ``{texts}`` provides the following sub-keywords.
3363
3363
3364 :matched: Boolean. True if the chunk matches the specified pattern.
3364 :matched: Boolean. True if the chunk matches the specified pattern.
3365 :text: String. Chunk content.
3365 :text: String. Chunk content.
3366
3366
3367 See :hg:`help templates.operators` for the list expansion syntax.
3367 See :hg:`help templates.operators` for the list expansion syntax.
3368
3368
3369 Returns 0 if a match is found, 1 otherwise.
3369 Returns 0 if a match is found, 1 otherwise.
3370
3370
3371 """
3371 """
3372 opts = pycompat.byteskwargs(opts)
3372 opts = pycompat.byteskwargs(opts)
3373 diff = opts.get(b'all') or opts.get(b'diff')
3373 diff = opts.get(b'all') or opts.get(b'diff')
3374 if diff and opts.get(b'all_files'):
3374 if diff and opts.get(b'all_files'):
3375 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3375 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3376 if opts.get(b'all_files') is None and not diff:
3376 if opts.get(b'all_files') is None and not diff:
3377 opts[b'all_files'] = True
3377 opts[b'all_files'] = True
3378 plaingrep = (
3378 plaingrep = (
3379 opts.get(b'all_files')
3379 opts.get(b'all_files')
3380 and not opts.get(b'rev')
3380 and not opts.get(b'rev')
3381 and not opts.get(b'follow')
3381 and not opts.get(b'follow')
3382 )
3382 )
3383 all_files = opts.get(b'all_files')
3383 all_files = opts.get(b'all_files')
3384 if plaingrep:
3384 if plaingrep:
3385 opts[b'rev'] = [b'wdir()']
3385 opts[b'rev'] = [b'wdir()']
3386
3386
3387 reflags = re.M
3387 reflags = re.M
3388 if opts.get(b'ignore_case'):
3388 if opts.get(b'ignore_case'):
3389 reflags |= re.I
3389 reflags |= re.I
3390 try:
3390 try:
3391 regexp = util.re.compile(pattern, reflags)
3391 regexp = util.re.compile(pattern, reflags)
3392 except re.error as inst:
3392 except re.error as inst:
3393 ui.warn(
3393 ui.warn(
3394 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3394 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3395 )
3395 )
3396 return 1
3396 return 1
3397 sep, eol = b':', b'\n'
3397 sep, eol = b':', b'\n'
3398 if opts.get(b'print0'):
3398 if opts.get(b'print0'):
3399 sep = eol = b'\0'
3399 sep = eol = b'\0'
3400
3400
3401 searcher = grepmod.grepsearcher(ui, repo, regexp)
3401 searcher = grepmod.grepsearcher(ui, repo, regexp)
3402
3402
3403 getfile = searcher._getfile
3403 getfile = searcher._getfile
3404 matches = searcher._matches
3404 matches = searcher._matches
3405 copies = searcher._copies
3405 copies = searcher._copies
3406
3406
3407 uipathfn = scmutil.getuipathfn(repo)
3407 uipathfn = scmutil.getuipathfn(repo)
3408
3408
3409 def display(fm, fn, ctx, pstates, states):
3409 def display(fm, fn, ctx, pstates, states):
3410 rev = scmutil.intrev(ctx)
3410 rev = scmutil.intrev(ctx)
3411 if fm.isplain():
3411 if fm.isplain():
3412 formatuser = ui.shortuser
3412 formatuser = ui.shortuser
3413 else:
3413 else:
3414 formatuser = pycompat.bytestr
3414 formatuser = pycompat.bytestr
3415 if ui.quiet:
3415 if ui.quiet:
3416 datefmt = b'%Y-%m-%d'
3416 datefmt = b'%Y-%m-%d'
3417 else:
3417 else:
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3419 found = False
3419 found = False
3420
3420
3421 @util.cachefunc
3421 @util.cachefunc
3422 def binary():
3422 def binary():
3423 flog = getfile(fn)
3423 flog = getfile(fn)
3424 try:
3424 try:
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3426 except error.WdirUnsupported:
3426 except error.WdirUnsupported:
3427 return ctx[fn].isbinary()
3427 return ctx[fn].isbinary()
3428
3428
3429 fieldnamemap = {b'linenumber': b'lineno'}
3429 fieldnamemap = {b'linenumber': b'lineno'}
3430 if diff:
3430 if diff:
3431 iter = grepmod.difflinestates(pstates, states)
3431 iter = grepmod.difflinestates(pstates, states)
3432 else:
3432 else:
3433 iter = [(b'', l) for l in states]
3433 iter = [(b'', l) for l in states]
3434 for change, l in iter:
3434 for change, l in iter:
3435 fm.startitem()
3435 fm.startitem()
3436 fm.context(ctx=ctx)
3436 fm.context(ctx=ctx)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3439
3439
3440 cols = [
3440 cols = [
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3442 (
3442 (
3443 b'linenumber',
3443 b'linenumber',
3444 b'%d',
3444 b'%d',
3445 l.linenum,
3445 l.linenum,
3446 opts.get(b'line_number'),
3446 opts.get(b'line_number'),
3447 b'',
3447 b'',
3448 ),
3448 ),
3449 ]
3449 ]
3450 if diff:
3450 if diff:
3451 cols.append(
3451 cols.append(
3452 (
3452 (
3453 b'change',
3453 b'change',
3454 b'%s',
3454 b'%s',
3455 change,
3455 change,
3456 True,
3456 True,
3457 b'grep.inserted '
3457 b'grep.inserted '
3458 if change == b'+'
3458 if change == b'+'
3459 else b'grep.deleted ',
3459 else b'grep.deleted ',
3460 )
3460 )
3461 )
3461 )
3462 cols.extend(
3462 cols.extend(
3463 [
3463 [
3464 (
3464 (
3465 b'user',
3465 b'user',
3466 b'%s',
3466 b'%s',
3467 formatuser(ctx.user()),
3467 formatuser(ctx.user()),
3468 opts.get(b'user'),
3468 opts.get(b'user'),
3469 b'',
3469 b'',
3470 ),
3470 ),
3471 (
3471 (
3472 b'date',
3472 b'date',
3473 b'%s',
3473 b'%s',
3474 fm.formatdate(ctx.date(), datefmt),
3474 fm.formatdate(ctx.date(), datefmt),
3475 opts.get(b'date'),
3475 opts.get(b'date'),
3476 b'',
3476 b'',
3477 ),
3477 ),
3478 ]
3478 ]
3479 )
3479 )
3480 for name, fmt, data, cond, extra_label in cols:
3480 for name, fmt, data, cond, extra_label in cols:
3481 if cond:
3481 if cond:
3482 fm.plain(sep, label=b'grep.sep')
3482 fm.plain(sep, label=b'grep.sep')
3483 field = fieldnamemap.get(name, name)
3483 field = fieldnamemap.get(name, name)
3484 label = extra_label + (b'grep.%s' % name)
3484 label = extra_label + (b'grep.%s' % name)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3486 if not opts.get(b'files_with_matches'):
3486 if not opts.get(b'files_with_matches'):
3487 fm.plain(sep, label=b'grep.sep')
3487 fm.plain(sep, label=b'grep.sep')
3488 if not opts.get(b'text') and binary():
3488 if not opts.get(b'text') and binary():
3489 fm.plain(_(b" Binary file matches"))
3489 fm.plain(_(b" Binary file matches"))
3490 else:
3490 else:
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3492 fm.plain(eol)
3492 fm.plain(eol)
3493 found = True
3493 found = True
3494 if opts.get(b'files_with_matches'):
3494 if opts.get(b'files_with_matches'):
3495 break
3495 break
3496 return found
3496 return found
3497
3497
3498 def displaymatches(fm, l):
3498 def displaymatches(fm, l):
3499 p = 0
3499 p = 0
3500 for s, e in l.findpos(regexp):
3500 for s, e in l.findpos(regexp):
3501 if p < s:
3501 if p < s:
3502 fm.startitem()
3502 fm.startitem()
3503 fm.write(b'text', b'%s', l.line[p:s])
3503 fm.write(b'text', b'%s', l.line[p:s])
3504 fm.data(matched=False)
3504 fm.data(matched=False)
3505 fm.startitem()
3505 fm.startitem()
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3507 fm.data(matched=True)
3507 fm.data(matched=True)
3508 p = e
3508 p = e
3509 if p < len(l.line):
3509 if p < len(l.line):
3510 fm.startitem()
3510 fm.startitem()
3511 fm.write(b'text', b'%s', l.line[p:])
3511 fm.write(b'text', b'%s', l.line[p:])
3512 fm.data(matched=False)
3512 fm.data(matched=False)
3513 fm.end()
3513 fm.end()
3514
3514
3515 skip = searcher._skip
3515 skip = searcher._skip
3516 revfiles = searcher._revfiles
3516 revfiles = searcher._revfiles
3517 found = False
3517 found = False
3518 follow = opts.get(b'follow')
3518 follow = opts.get(b'follow')
3519
3519
3520 getrenamed = searcher._getrenamed
3520 getrenamed = searcher._getrenamed
3521
3521
3522 def readfile(ctx, fn):
3523 rev = ctx.rev()
3524 if rev is None:
3525 fctx = ctx[fn]
3526 try:
3527 return fctx.data()
3528 except IOError as e:
3529 if e.errno != errno.ENOENT:
3530 raise
3531 else:
3532 flog = getfile(fn)
3533 fnode = ctx.filenode(fn)
3534 try:
3535 return flog.read(fnode)
3536 except error.CensoredNodeError:
3537 ui.warn(
3538 _(
3539 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3540 )
3541 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3542 )
3543
3544 def prep(ctx, fmatch):
3522 def prep(ctx, fmatch):
3545 rev = ctx.rev()
3523 rev = ctx.rev()
3546 pctx = ctx.p1()
3524 pctx = ctx.p1()
3547 matches.setdefault(rev, {})
3525 matches.setdefault(rev, {})
3548 if diff:
3526 if diff:
3549 parent = pctx.rev()
3527 parent = pctx.rev()
3550 matches.setdefault(parent, {})
3528 matches.setdefault(parent, {})
3551 files = revfiles.setdefault(rev, [])
3529 files = revfiles.setdefault(rev, [])
3552 if rev is None:
3530 if rev is None:
3553 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3531 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3554 # pathauditor checks without this in mozilla-central
3532 # pathauditor checks without this in mozilla-central
3555 contextmanager = repo.wvfs.audit.cached
3533 contextmanager = repo.wvfs.audit.cached
3556 else:
3534 else:
3557 contextmanager = util.nullcontextmanager
3535 contextmanager = util.nullcontextmanager
3558 with contextmanager():
3536 with contextmanager():
3559 # TODO: maybe better to warn missing files?
3537 # TODO: maybe better to warn missing files?
3560 if all_files:
3538 if all_files:
3561 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3539 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3562 filenames = ctx.matches(fmatch)
3540 filenames = ctx.matches(fmatch)
3563 else:
3541 else:
3564 filenames = (f for f in ctx.files() if fmatch(f))
3542 filenames = (f for f in ctx.files() if fmatch(f))
3565 for fn in filenames:
3543 for fn in filenames:
3566 # fn might not exist in the revision (could be a file removed by
3544 # fn might not exist in the revision (could be a file removed by
3567 # the revision). We could check `fn not in ctx` even when rev is
3545 # the revision). We could check `fn not in ctx` even when rev is
3568 # None, but it's less racy to protect againt that in readfile.
3546 # None, but it's less racy to protect againt that in readfile.
3569 if rev is not None and fn not in ctx:
3547 if rev is not None and fn not in ctx:
3570 continue
3548 continue
3571
3549
3572 copy = None
3550 copy = None
3573 if follow:
3551 if follow:
3574 copy = getrenamed(fn, rev)
3552 copy = getrenamed(fn, rev)
3575 if copy:
3553 if copy:
3576 copies.setdefault(rev, {})[fn] = copy
3554 copies.setdefault(rev, {})[fn] = copy
3577 if fn in skip:
3555 if fn in skip:
3578 skip.add(copy)
3556 skip.add(copy)
3579 if fn in skip:
3557 if fn in skip:
3580 continue
3558 continue
3581 files.append(fn)
3559 files.append(fn)
3582
3560
3583 if fn not in matches[rev]:
3561 if fn not in matches[rev]:
3584 searcher._grepbody(fn, rev, readfile(ctx, fn))
3562 searcher._grepbody(fn, rev, searcher._readfile(ctx, fn))
3585
3563
3586 if diff:
3564 if diff:
3587 pfn = copy or fn
3565 pfn = copy or fn
3588 if pfn not in matches[parent] and pfn in pctx:
3566 if pfn not in matches[parent] and pfn in pctx:
3589 searcher._grepbody(pfn, parent, readfile(pctx, pfn))
3567 searcher._grepbody(
3568 pfn, parent, searcher._readfile(pctx, pfn)
3569 )
3590
3570
3591 wopts = logcmdutil.walkopts(
3571 wopts = logcmdutil.walkopts(
3592 pats=pats,
3572 pats=pats,
3593 opts=opts,
3573 opts=opts,
3594 revspec=opts[b'rev'],
3574 revspec=opts[b'rev'],
3595 include_pats=opts[b'include'],
3575 include_pats=opts[b'include'],
3596 exclude_pats=opts[b'exclude'],
3576 exclude_pats=opts[b'exclude'],
3597 follow=follow,
3577 follow=follow,
3598 force_changelog_traversal=all_files,
3578 force_changelog_traversal=all_files,
3599 filter_revisions_by_pats=not all_files,
3579 filter_revisions_by_pats=not all_files,
3600 )
3580 )
3601 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3581 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3602
3582
3603 ui.pager(b'grep')
3583 ui.pager(b'grep')
3604 fm = ui.formatter(b'grep', opts)
3584 fm = ui.formatter(b'grep', opts)
3605 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3585 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3606 rev = ctx.rev()
3586 rev = ctx.rev()
3607 parent = ctx.p1().rev()
3587 parent = ctx.p1().rev()
3608 for fn in sorted(revfiles.get(rev, [])):
3588 for fn in sorted(revfiles.get(rev, [])):
3609 states = matches[rev][fn]
3589 states = matches[rev][fn]
3610 copy = copies.get(rev, {}).get(fn)
3590 copy = copies.get(rev, {}).get(fn)
3611 if fn in skip:
3591 if fn in skip:
3612 if copy:
3592 if copy:
3613 skip.add(copy)
3593 skip.add(copy)
3614 continue
3594 continue
3615 pstates = matches.get(parent, {}).get(copy or fn, [])
3595 pstates = matches.get(parent, {}).get(copy or fn, [])
3616 if pstates or states:
3596 if pstates or states:
3617 r = display(fm, fn, ctx, pstates, states)
3597 r = display(fm, fn, ctx, pstates, states)
3618 found = found or r
3598 found = found or r
3619 if r and not diff and not all_files:
3599 if r and not diff and not all_files:
3620 skip.add(fn)
3600 skip.add(fn)
3621 if copy:
3601 if copy:
3622 skip.add(copy)
3602 skip.add(copy)
3623 del revfiles[rev]
3603 del revfiles[rev]
3624 # We will keep the matches dict for the duration of the window
3604 # We will keep the matches dict for the duration of the window
3625 # clear the matches dict once the window is over
3605 # clear the matches dict once the window is over
3626 if not revfiles:
3606 if not revfiles:
3627 matches.clear()
3607 matches.clear()
3628 fm.end()
3608 fm.end()
3629
3609
3630 return not found
3610 return not found
3631
3611
3632
3612
3633 @command(
3613 @command(
3634 b'heads',
3614 b'heads',
3635 [
3615 [
3636 (
3616 (
3637 b'r',
3617 b'r',
3638 b'rev',
3618 b'rev',
3639 b'',
3619 b'',
3640 _(b'show only heads which are descendants of STARTREV'),
3620 _(b'show only heads which are descendants of STARTREV'),
3641 _(b'STARTREV'),
3621 _(b'STARTREV'),
3642 ),
3622 ),
3643 (b't', b'topo', False, _(b'show topological heads only')),
3623 (b't', b'topo', False, _(b'show topological heads only')),
3644 (
3624 (
3645 b'a',
3625 b'a',
3646 b'active',
3626 b'active',
3647 False,
3627 False,
3648 _(b'show active branchheads only (DEPRECATED)'),
3628 _(b'show active branchheads only (DEPRECATED)'),
3649 ),
3629 ),
3650 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3630 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3651 ]
3631 ]
3652 + templateopts,
3632 + templateopts,
3653 _(b'[-ct] [-r STARTREV] [REV]...'),
3633 _(b'[-ct] [-r STARTREV] [REV]...'),
3654 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3634 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3655 intents={INTENT_READONLY},
3635 intents={INTENT_READONLY},
3656 )
3636 )
3657 def heads(ui, repo, *branchrevs, **opts):
3637 def heads(ui, repo, *branchrevs, **opts):
3658 """show branch heads
3638 """show branch heads
3659
3639
3660 With no arguments, show all open branch heads in the repository.
3640 With no arguments, show all open branch heads in the repository.
3661 Branch heads are changesets that have no descendants on the
3641 Branch heads are changesets that have no descendants on the
3662 same branch. They are where development generally takes place and
3642 same branch. They are where development generally takes place and
3663 are the usual targets for update and merge operations.
3643 are the usual targets for update and merge operations.
3664
3644
3665 If one or more REVs are given, only open branch heads on the
3645 If one or more REVs are given, only open branch heads on the
3666 branches associated with the specified changesets are shown. This
3646 branches associated with the specified changesets are shown. This
3667 means that you can use :hg:`heads .` to see the heads on the
3647 means that you can use :hg:`heads .` to see the heads on the
3668 currently checked-out branch.
3648 currently checked-out branch.
3669
3649
3670 If -c/--closed is specified, also show branch heads marked closed
3650 If -c/--closed is specified, also show branch heads marked closed
3671 (see :hg:`commit --close-branch`).
3651 (see :hg:`commit --close-branch`).
3672
3652
3673 If STARTREV is specified, only those heads that are descendants of
3653 If STARTREV is specified, only those heads that are descendants of
3674 STARTREV will be displayed.
3654 STARTREV will be displayed.
3675
3655
3676 If -t/--topo is specified, named branch mechanics will be ignored and only
3656 If -t/--topo is specified, named branch mechanics will be ignored and only
3677 topological heads (changesets with no children) will be shown.
3657 topological heads (changesets with no children) will be shown.
3678
3658
3679 Returns 0 if matching heads are found, 1 if not.
3659 Returns 0 if matching heads are found, 1 if not.
3680 """
3660 """
3681
3661
3682 opts = pycompat.byteskwargs(opts)
3662 opts = pycompat.byteskwargs(opts)
3683 start = None
3663 start = None
3684 rev = opts.get(b'rev')
3664 rev = opts.get(b'rev')
3685 if rev:
3665 if rev:
3686 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3666 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3687 start = scmutil.revsingle(repo, rev, None).node()
3667 start = scmutil.revsingle(repo, rev, None).node()
3688
3668
3689 if opts.get(b'topo'):
3669 if opts.get(b'topo'):
3690 heads = [repo[h] for h in repo.heads(start)]
3670 heads = [repo[h] for h in repo.heads(start)]
3691 else:
3671 else:
3692 heads = []
3672 heads = []
3693 for branch in repo.branchmap():
3673 for branch in repo.branchmap():
3694 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3674 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3695 heads = [repo[h] for h in heads]
3675 heads = [repo[h] for h in heads]
3696
3676
3697 if branchrevs:
3677 if branchrevs:
3698 branches = {
3678 branches = {
3699 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3679 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3700 }
3680 }
3701 heads = [h for h in heads if h.branch() in branches]
3681 heads = [h for h in heads if h.branch() in branches]
3702
3682
3703 if opts.get(b'active') and branchrevs:
3683 if opts.get(b'active') and branchrevs:
3704 dagheads = repo.heads(start)
3684 dagheads = repo.heads(start)
3705 heads = [h for h in heads if h.node() in dagheads]
3685 heads = [h for h in heads if h.node() in dagheads]
3706
3686
3707 if branchrevs:
3687 if branchrevs:
3708 haveheads = {h.branch() for h in heads}
3688 haveheads = {h.branch() for h in heads}
3709 if branches - haveheads:
3689 if branches - haveheads:
3710 headless = b', '.join(b for b in branches - haveheads)
3690 headless = b', '.join(b for b in branches - haveheads)
3711 msg = _(b'no open branch heads found on branches %s')
3691 msg = _(b'no open branch heads found on branches %s')
3712 if opts.get(b'rev'):
3692 if opts.get(b'rev'):
3713 msg += _(b' (started at %s)') % opts[b'rev']
3693 msg += _(b' (started at %s)') % opts[b'rev']
3714 ui.warn((msg + b'\n') % headless)
3694 ui.warn((msg + b'\n') % headless)
3715
3695
3716 if not heads:
3696 if not heads:
3717 return 1
3697 return 1
3718
3698
3719 ui.pager(b'heads')
3699 ui.pager(b'heads')
3720 heads = sorted(heads, key=lambda x: -(x.rev()))
3700 heads = sorted(heads, key=lambda x: -(x.rev()))
3721 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3701 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3722 for ctx in heads:
3702 for ctx in heads:
3723 displayer.show(ctx)
3703 displayer.show(ctx)
3724 displayer.close()
3704 displayer.close()
3725
3705
3726
3706
3727 @command(
3707 @command(
3728 b'help',
3708 b'help',
3729 [
3709 [
3730 (b'e', b'extension', None, _(b'show only help for extensions')),
3710 (b'e', b'extension', None, _(b'show only help for extensions')),
3731 (b'c', b'command', None, _(b'show only help for commands')),
3711 (b'c', b'command', None, _(b'show only help for commands')),
3732 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3712 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3733 (
3713 (
3734 b's',
3714 b's',
3735 b'system',
3715 b'system',
3736 [],
3716 [],
3737 _(b'show help for specific platform(s)'),
3717 _(b'show help for specific platform(s)'),
3738 _(b'PLATFORM'),
3718 _(b'PLATFORM'),
3739 ),
3719 ),
3740 ],
3720 ],
3741 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3721 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3742 helpcategory=command.CATEGORY_HELP,
3722 helpcategory=command.CATEGORY_HELP,
3743 norepo=True,
3723 norepo=True,
3744 intents={INTENT_READONLY},
3724 intents={INTENT_READONLY},
3745 )
3725 )
3746 def help_(ui, name=None, **opts):
3726 def help_(ui, name=None, **opts):
3747 """show help for a given topic or a help overview
3727 """show help for a given topic or a help overview
3748
3728
3749 With no arguments, print a list of commands with short help messages.
3729 With no arguments, print a list of commands with short help messages.
3750
3730
3751 Given a topic, extension, or command name, print help for that
3731 Given a topic, extension, or command name, print help for that
3752 topic.
3732 topic.
3753
3733
3754 Returns 0 if successful.
3734 Returns 0 if successful.
3755 """
3735 """
3756
3736
3757 keep = opts.get('system') or []
3737 keep = opts.get('system') or []
3758 if len(keep) == 0:
3738 if len(keep) == 0:
3759 if pycompat.sysplatform.startswith(b'win'):
3739 if pycompat.sysplatform.startswith(b'win'):
3760 keep.append(b'windows')
3740 keep.append(b'windows')
3761 elif pycompat.sysplatform == b'OpenVMS':
3741 elif pycompat.sysplatform == b'OpenVMS':
3762 keep.append(b'vms')
3742 keep.append(b'vms')
3763 elif pycompat.sysplatform == b'plan9':
3743 elif pycompat.sysplatform == b'plan9':
3764 keep.append(b'plan9')
3744 keep.append(b'plan9')
3765 else:
3745 else:
3766 keep.append(b'unix')
3746 keep.append(b'unix')
3767 keep.append(pycompat.sysplatform.lower())
3747 keep.append(pycompat.sysplatform.lower())
3768 if ui.verbose:
3748 if ui.verbose:
3769 keep.append(b'verbose')
3749 keep.append(b'verbose')
3770
3750
3771 commands = sys.modules[__name__]
3751 commands = sys.modules[__name__]
3772 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3752 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3773 ui.pager(b'help')
3753 ui.pager(b'help')
3774 ui.write(formatted)
3754 ui.write(formatted)
3775
3755
3776
3756
3777 @command(
3757 @command(
3778 b'identify|id',
3758 b'identify|id',
3779 [
3759 [
3780 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3760 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3781 (b'n', b'num', None, _(b'show local revision number')),
3761 (b'n', b'num', None, _(b'show local revision number')),
3782 (b'i', b'id', None, _(b'show global revision id')),
3762 (b'i', b'id', None, _(b'show global revision id')),
3783 (b'b', b'branch', None, _(b'show branch')),
3763 (b'b', b'branch', None, _(b'show branch')),
3784 (b't', b'tags', None, _(b'show tags')),
3764 (b't', b'tags', None, _(b'show tags')),
3785 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3765 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3786 ]
3766 ]
3787 + remoteopts
3767 + remoteopts
3788 + formatteropts,
3768 + formatteropts,
3789 _(b'[-nibtB] [-r REV] [SOURCE]'),
3769 _(b'[-nibtB] [-r REV] [SOURCE]'),
3790 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3770 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3791 optionalrepo=True,
3771 optionalrepo=True,
3792 intents={INTENT_READONLY},
3772 intents={INTENT_READONLY},
3793 )
3773 )
3794 def identify(
3774 def identify(
3795 ui,
3775 ui,
3796 repo,
3776 repo,
3797 source=None,
3777 source=None,
3798 rev=None,
3778 rev=None,
3799 num=None,
3779 num=None,
3800 id=None,
3780 id=None,
3801 branch=None,
3781 branch=None,
3802 tags=None,
3782 tags=None,
3803 bookmarks=None,
3783 bookmarks=None,
3804 **opts
3784 **opts
3805 ):
3785 ):
3806 """identify the working directory or specified revision
3786 """identify the working directory or specified revision
3807
3787
3808 Print a summary identifying the repository state at REV using one or
3788 Print a summary identifying the repository state at REV using one or
3809 two parent hash identifiers, followed by a "+" if the working
3789 two parent hash identifiers, followed by a "+" if the working
3810 directory has uncommitted changes, the branch name (if not default),
3790 directory has uncommitted changes, the branch name (if not default),
3811 a list of tags, and a list of bookmarks.
3791 a list of tags, and a list of bookmarks.
3812
3792
3813 When REV is not given, print a summary of the current state of the
3793 When REV is not given, print a summary of the current state of the
3814 repository including the working directory. Specify -r. to get information
3794 repository including the working directory. Specify -r. to get information
3815 of the working directory parent without scanning uncommitted changes.
3795 of the working directory parent without scanning uncommitted changes.
3816
3796
3817 Specifying a path to a repository root or Mercurial bundle will
3797 Specifying a path to a repository root or Mercurial bundle will
3818 cause lookup to operate on that repository/bundle.
3798 cause lookup to operate on that repository/bundle.
3819
3799
3820 .. container:: verbose
3800 .. container:: verbose
3821
3801
3822 Template:
3802 Template:
3823
3803
3824 The following keywords are supported in addition to the common template
3804 The following keywords are supported in addition to the common template
3825 keywords and functions. See also :hg:`help templates`.
3805 keywords and functions. See also :hg:`help templates`.
3826
3806
3827 :dirty: String. Character ``+`` denoting if the working directory has
3807 :dirty: String. Character ``+`` denoting if the working directory has
3828 uncommitted changes.
3808 uncommitted changes.
3829 :id: String. One or two nodes, optionally followed by ``+``.
3809 :id: String. One or two nodes, optionally followed by ``+``.
3830 :parents: List of strings. Parent nodes of the changeset.
3810 :parents: List of strings. Parent nodes of the changeset.
3831
3811
3832 Examples:
3812 Examples:
3833
3813
3834 - generate a build identifier for the working directory::
3814 - generate a build identifier for the working directory::
3835
3815
3836 hg id --id > build-id.dat
3816 hg id --id > build-id.dat
3837
3817
3838 - find the revision corresponding to a tag::
3818 - find the revision corresponding to a tag::
3839
3819
3840 hg id -n -r 1.3
3820 hg id -n -r 1.3
3841
3821
3842 - check the most recent revision of a remote repository::
3822 - check the most recent revision of a remote repository::
3843
3823
3844 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3824 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3845
3825
3846 See :hg:`log` for generating more information about specific revisions,
3826 See :hg:`log` for generating more information about specific revisions,
3847 including full hash identifiers.
3827 including full hash identifiers.
3848
3828
3849 Returns 0 if successful.
3829 Returns 0 if successful.
3850 """
3830 """
3851
3831
3852 opts = pycompat.byteskwargs(opts)
3832 opts = pycompat.byteskwargs(opts)
3853 if not repo and not source:
3833 if not repo and not source:
3854 raise error.Abort(
3834 raise error.Abort(
3855 _(b"there is no Mercurial repository here (.hg not found)")
3835 _(b"there is no Mercurial repository here (.hg not found)")
3856 )
3836 )
3857
3837
3858 default = not (num or id or branch or tags or bookmarks)
3838 default = not (num or id or branch or tags or bookmarks)
3859 output = []
3839 output = []
3860 revs = []
3840 revs = []
3861
3841
3862 if source:
3842 if source:
3863 source, branches = hg.parseurl(ui.expandpath(source))
3843 source, branches = hg.parseurl(ui.expandpath(source))
3864 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3844 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3865 repo = peer.local()
3845 repo = peer.local()
3866 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3867
3847
3868 fm = ui.formatter(b'identify', opts)
3848 fm = ui.formatter(b'identify', opts)
3869 fm.startitem()
3849 fm.startitem()
3870
3850
3871 if not repo:
3851 if not repo:
3872 if num or branch or tags:
3852 if num or branch or tags:
3873 raise error.Abort(
3853 raise error.Abort(
3874 _(b"can't query remote revision number, branch, or tags")
3854 _(b"can't query remote revision number, branch, or tags")
3875 )
3855 )
3876 if not rev and revs:
3856 if not rev and revs:
3877 rev = revs[0]
3857 rev = revs[0]
3878 if not rev:
3858 if not rev:
3879 rev = b"tip"
3859 rev = b"tip"
3880
3860
3881 remoterev = peer.lookup(rev)
3861 remoterev = peer.lookup(rev)
3882 hexrev = fm.hexfunc(remoterev)
3862 hexrev = fm.hexfunc(remoterev)
3883 if default or id:
3863 if default or id:
3884 output = [hexrev]
3864 output = [hexrev]
3885 fm.data(id=hexrev)
3865 fm.data(id=hexrev)
3886
3866
3887 @util.cachefunc
3867 @util.cachefunc
3888 def getbms():
3868 def getbms():
3889 bms = []
3869 bms = []
3890
3870
3891 if b'bookmarks' in peer.listkeys(b'namespaces'):
3871 if b'bookmarks' in peer.listkeys(b'namespaces'):
3892 hexremoterev = hex(remoterev)
3872 hexremoterev = hex(remoterev)
3893 bms = [
3873 bms = [
3894 bm
3874 bm
3895 for bm, bmr in pycompat.iteritems(
3875 for bm, bmr in pycompat.iteritems(
3896 peer.listkeys(b'bookmarks')
3876 peer.listkeys(b'bookmarks')
3897 )
3877 )
3898 if bmr == hexremoterev
3878 if bmr == hexremoterev
3899 ]
3879 ]
3900
3880
3901 return sorted(bms)
3881 return sorted(bms)
3902
3882
3903 if fm.isplain():
3883 if fm.isplain():
3904 if bookmarks:
3884 if bookmarks:
3905 output.extend(getbms())
3885 output.extend(getbms())
3906 elif default and not ui.quiet:
3886 elif default and not ui.quiet:
3907 # multiple bookmarks for a single parent separated by '/'
3887 # multiple bookmarks for a single parent separated by '/'
3908 bm = b'/'.join(getbms())
3888 bm = b'/'.join(getbms())
3909 if bm:
3889 if bm:
3910 output.append(bm)
3890 output.append(bm)
3911 else:
3891 else:
3912 fm.data(node=hex(remoterev))
3892 fm.data(node=hex(remoterev))
3913 if bookmarks or b'bookmarks' in fm.datahint():
3893 if bookmarks or b'bookmarks' in fm.datahint():
3914 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3894 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3915 else:
3895 else:
3916 if rev:
3896 if rev:
3917 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3897 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3918 ctx = scmutil.revsingle(repo, rev, None)
3898 ctx = scmutil.revsingle(repo, rev, None)
3919
3899
3920 if ctx.rev() is None:
3900 if ctx.rev() is None:
3921 ctx = repo[None]
3901 ctx = repo[None]
3922 parents = ctx.parents()
3902 parents = ctx.parents()
3923 taglist = []
3903 taglist = []
3924 for p in parents:
3904 for p in parents:
3925 taglist.extend(p.tags())
3905 taglist.extend(p.tags())
3926
3906
3927 dirty = b""
3907 dirty = b""
3928 if ctx.dirty(missing=True, merge=False, branch=False):
3908 if ctx.dirty(missing=True, merge=False, branch=False):
3929 dirty = b'+'
3909 dirty = b'+'
3930 fm.data(dirty=dirty)
3910 fm.data(dirty=dirty)
3931
3911
3932 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3912 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3933 if default or id:
3913 if default or id:
3934 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3914 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3935 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3915 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3936
3916
3937 if num:
3917 if num:
3938 numoutput = [b"%d" % p.rev() for p in parents]
3918 numoutput = [b"%d" % p.rev() for p in parents]
3939 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3919 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3940
3920
3941 fm.data(
3921 fm.data(
3942 parents=fm.formatlist(
3922 parents=fm.formatlist(
3943 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3923 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3944 )
3924 )
3945 )
3925 )
3946 else:
3926 else:
3947 hexoutput = fm.hexfunc(ctx.node())
3927 hexoutput = fm.hexfunc(ctx.node())
3948 if default or id:
3928 if default or id:
3949 output = [hexoutput]
3929 output = [hexoutput]
3950 fm.data(id=hexoutput)
3930 fm.data(id=hexoutput)
3951
3931
3952 if num:
3932 if num:
3953 output.append(pycompat.bytestr(ctx.rev()))
3933 output.append(pycompat.bytestr(ctx.rev()))
3954 taglist = ctx.tags()
3934 taglist = ctx.tags()
3955
3935
3956 if default and not ui.quiet:
3936 if default and not ui.quiet:
3957 b = ctx.branch()
3937 b = ctx.branch()
3958 if b != b'default':
3938 if b != b'default':
3959 output.append(b"(%s)" % b)
3939 output.append(b"(%s)" % b)
3960
3940
3961 # multiple tags for a single parent separated by '/'
3941 # multiple tags for a single parent separated by '/'
3962 t = b'/'.join(taglist)
3942 t = b'/'.join(taglist)
3963 if t:
3943 if t:
3964 output.append(t)
3944 output.append(t)
3965
3945
3966 # multiple bookmarks for a single parent separated by '/'
3946 # multiple bookmarks for a single parent separated by '/'
3967 bm = b'/'.join(ctx.bookmarks())
3947 bm = b'/'.join(ctx.bookmarks())
3968 if bm:
3948 if bm:
3969 output.append(bm)
3949 output.append(bm)
3970 else:
3950 else:
3971 if branch:
3951 if branch:
3972 output.append(ctx.branch())
3952 output.append(ctx.branch())
3973
3953
3974 if tags:
3954 if tags:
3975 output.extend(taglist)
3955 output.extend(taglist)
3976
3956
3977 if bookmarks:
3957 if bookmarks:
3978 output.extend(ctx.bookmarks())
3958 output.extend(ctx.bookmarks())
3979
3959
3980 fm.data(node=ctx.hex())
3960 fm.data(node=ctx.hex())
3981 fm.data(branch=ctx.branch())
3961 fm.data(branch=ctx.branch())
3982 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3962 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3983 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3963 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3984 fm.context(ctx=ctx)
3964 fm.context(ctx=ctx)
3985
3965
3986 fm.plain(b"%s\n" % b' '.join(output))
3966 fm.plain(b"%s\n" % b' '.join(output))
3987 fm.end()
3967 fm.end()
3988
3968
3989
3969
3990 @command(
3970 @command(
3991 b'import|patch',
3971 b'import|patch',
3992 [
3972 [
3993 (
3973 (
3994 b'p',
3974 b'p',
3995 b'strip',
3975 b'strip',
3996 1,
3976 1,
3997 _(
3977 _(
3998 b'directory strip option for patch. This has the same '
3978 b'directory strip option for patch. This has the same '
3999 b'meaning as the corresponding patch option'
3979 b'meaning as the corresponding patch option'
4000 ),
3980 ),
4001 _(b'NUM'),
3981 _(b'NUM'),
4002 ),
3982 ),
4003 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3983 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4004 (b'', b'secret', None, _(b'use the secret phase for committing')),
3984 (b'', b'secret', None, _(b'use the secret phase for committing')),
4005 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3985 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4006 (
3986 (
4007 b'f',
3987 b'f',
4008 b'force',
3988 b'force',
4009 None,
3989 None,
4010 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3990 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4011 ),
3991 ),
4012 (
3992 (
4013 b'',
3993 b'',
4014 b'no-commit',
3994 b'no-commit',
4015 None,
3995 None,
4016 _(b"don't commit, just update the working directory"),
3996 _(b"don't commit, just update the working directory"),
4017 ),
3997 ),
4018 (
3998 (
4019 b'',
3999 b'',
4020 b'bypass',
4000 b'bypass',
4021 None,
4001 None,
4022 _(b"apply patch without touching the working directory"),
4002 _(b"apply patch without touching the working directory"),
4023 ),
4003 ),
4024 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4004 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4025 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4005 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4026 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4006 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4027 (
4007 (
4028 b'',
4008 b'',
4029 b'import-branch',
4009 b'import-branch',
4030 None,
4010 None,
4031 _(b'use any branch information in patch (implied by --exact)'),
4011 _(b'use any branch information in patch (implied by --exact)'),
4032 ),
4012 ),
4033 ]
4013 ]
4034 + commitopts
4014 + commitopts
4035 + commitopts2
4015 + commitopts2
4036 + similarityopts,
4016 + similarityopts,
4037 _(b'[OPTION]... PATCH...'),
4017 _(b'[OPTION]... PATCH...'),
4038 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4018 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4039 )
4019 )
4040 def import_(ui, repo, patch1=None, *patches, **opts):
4020 def import_(ui, repo, patch1=None, *patches, **opts):
4041 """import an ordered set of patches
4021 """import an ordered set of patches
4042
4022
4043 Import a list of patches and commit them individually (unless
4023 Import a list of patches and commit them individually (unless
4044 --no-commit is specified).
4024 --no-commit is specified).
4045
4025
4046 To read a patch from standard input (stdin), use "-" as the patch
4026 To read a patch from standard input (stdin), use "-" as the patch
4047 name. If a URL is specified, the patch will be downloaded from
4027 name. If a URL is specified, the patch will be downloaded from
4048 there.
4028 there.
4049
4029
4050 Import first applies changes to the working directory (unless
4030 Import first applies changes to the working directory (unless
4051 --bypass is specified), import will abort if there are outstanding
4031 --bypass is specified), import will abort if there are outstanding
4052 changes.
4032 changes.
4053
4033
4054 Use --bypass to apply and commit patches directly to the
4034 Use --bypass to apply and commit patches directly to the
4055 repository, without affecting the working directory. Without
4035 repository, without affecting the working directory. Without
4056 --exact, patches will be applied on top of the working directory
4036 --exact, patches will be applied on top of the working directory
4057 parent revision.
4037 parent revision.
4058
4038
4059 You can import a patch straight from a mail message. Even patches
4039 You can import a patch straight from a mail message. Even patches
4060 as attachments work (to use the body part, it must have type
4040 as attachments work (to use the body part, it must have type
4061 text/plain or text/x-patch). From and Subject headers of email
4041 text/plain or text/x-patch). From and Subject headers of email
4062 message are used as default committer and commit message. All
4042 message are used as default committer and commit message. All
4063 text/plain body parts before first diff are added to the commit
4043 text/plain body parts before first diff are added to the commit
4064 message.
4044 message.
4065
4045
4066 If the imported patch was generated by :hg:`export`, user and
4046 If the imported patch was generated by :hg:`export`, user and
4067 description from patch override values from message headers and
4047 description from patch override values from message headers and
4068 body. Values given on command line with -m/--message and -u/--user
4048 body. Values given on command line with -m/--message and -u/--user
4069 override these.
4049 override these.
4070
4050
4071 If --exact is specified, import will set the working directory to
4051 If --exact is specified, import will set the working directory to
4072 the parent of each patch before applying it, and will abort if the
4052 the parent of each patch before applying it, and will abort if the
4073 resulting changeset has a different ID than the one recorded in
4053 resulting changeset has a different ID than the one recorded in
4074 the patch. This will guard against various ways that portable
4054 the patch. This will guard against various ways that portable
4075 patch formats and mail systems might fail to transfer Mercurial
4055 patch formats and mail systems might fail to transfer Mercurial
4076 data or metadata. See :hg:`bundle` for lossless transmission.
4056 data or metadata. See :hg:`bundle` for lossless transmission.
4077
4057
4078 Use --partial to ensure a changeset will be created from the patch
4058 Use --partial to ensure a changeset will be created from the patch
4079 even if some hunks fail to apply. Hunks that fail to apply will be
4059 even if some hunks fail to apply. Hunks that fail to apply will be
4080 written to a <target-file>.rej file. Conflicts can then be resolved
4060 written to a <target-file>.rej file. Conflicts can then be resolved
4081 by hand before :hg:`commit --amend` is run to update the created
4061 by hand before :hg:`commit --amend` is run to update the created
4082 changeset. This flag exists to let people import patches that
4062 changeset. This flag exists to let people import patches that
4083 partially apply without losing the associated metadata (author,
4063 partially apply without losing the associated metadata (author,
4084 date, description, ...).
4064 date, description, ...).
4085
4065
4086 .. note::
4066 .. note::
4087
4067
4088 When no hunks apply cleanly, :hg:`import --partial` will create
4068 When no hunks apply cleanly, :hg:`import --partial` will create
4089 an empty changeset, importing only the patch metadata.
4069 an empty changeset, importing only the patch metadata.
4090
4070
4091 With -s/--similarity, hg will attempt to discover renames and
4071 With -s/--similarity, hg will attempt to discover renames and
4092 copies in the patch in the same way as :hg:`addremove`.
4072 copies in the patch in the same way as :hg:`addremove`.
4093
4073
4094 It is possible to use external patch programs to perform the patch
4074 It is possible to use external patch programs to perform the patch
4095 by setting the ``ui.patch`` configuration option. For the default
4075 by setting the ``ui.patch`` configuration option. For the default
4096 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4076 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4097 See :hg:`help config` for more information about configuration
4077 See :hg:`help config` for more information about configuration
4098 files and how to use these options.
4078 files and how to use these options.
4099
4079
4100 See :hg:`help dates` for a list of formats valid for -d/--date.
4080 See :hg:`help dates` for a list of formats valid for -d/--date.
4101
4081
4102 .. container:: verbose
4082 .. container:: verbose
4103
4083
4104 Examples:
4084 Examples:
4105
4085
4106 - import a traditional patch from a website and detect renames::
4086 - import a traditional patch from a website and detect renames::
4107
4087
4108 hg import -s 80 http://example.com/bugfix.patch
4088 hg import -s 80 http://example.com/bugfix.patch
4109
4089
4110 - import a changeset from an hgweb server::
4090 - import a changeset from an hgweb server::
4111
4091
4112 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4092 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4113
4093
4114 - import all the patches in an Unix-style mbox::
4094 - import all the patches in an Unix-style mbox::
4115
4095
4116 hg import incoming-patches.mbox
4096 hg import incoming-patches.mbox
4117
4097
4118 - import patches from stdin::
4098 - import patches from stdin::
4119
4099
4120 hg import -
4100 hg import -
4121
4101
4122 - attempt to exactly restore an exported changeset (not always
4102 - attempt to exactly restore an exported changeset (not always
4123 possible)::
4103 possible)::
4124
4104
4125 hg import --exact proposed-fix.patch
4105 hg import --exact proposed-fix.patch
4126
4106
4127 - use an external tool to apply a patch which is too fuzzy for
4107 - use an external tool to apply a patch which is too fuzzy for
4128 the default internal tool.
4108 the default internal tool.
4129
4109
4130 hg import --config ui.patch="patch --merge" fuzzy.patch
4110 hg import --config ui.patch="patch --merge" fuzzy.patch
4131
4111
4132 - change the default fuzzing from 2 to a less strict 7
4112 - change the default fuzzing from 2 to a less strict 7
4133
4113
4134 hg import --config ui.fuzz=7 fuzz.patch
4114 hg import --config ui.fuzz=7 fuzz.patch
4135
4115
4136 Returns 0 on success, 1 on partial success (see --partial).
4116 Returns 0 on success, 1 on partial success (see --partial).
4137 """
4117 """
4138
4118
4139 opts = pycompat.byteskwargs(opts)
4119 opts = pycompat.byteskwargs(opts)
4140 if not patch1:
4120 if not patch1:
4141 raise error.Abort(_(b'need at least one patch to import'))
4121 raise error.Abort(_(b'need at least one patch to import'))
4142
4122
4143 patches = (patch1,) + patches
4123 patches = (patch1,) + patches
4144
4124
4145 date = opts.get(b'date')
4125 date = opts.get(b'date')
4146 if date:
4126 if date:
4147 opts[b'date'] = dateutil.parsedate(date)
4127 opts[b'date'] = dateutil.parsedate(date)
4148
4128
4149 exact = opts.get(b'exact')
4129 exact = opts.get(b'exact')
4150 update = not opts.get(b'bypass')
4130 update = not opts.get(b'bypass')
4151 if not update and opts.get(b'no_commit'):
4131 if not update and opts.get(b'no_commit'):
4152 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4132 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4153 if opts.get(b'secret') and opts.get(b'no_commit'):
4133 if opts.get(b'secret') and opts.get(b'no_commit'):
4154 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4134 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4155 try:
4135 try:
4156 sim = float(opts.get(b'similarity') or 0)
4136 sim = float(opts.get(b'similarity') or 0)
4157 except ValueError:
4137 except ValueError:
4158 raise error.Abort(_(b'similarity must be a number'))
4138 raise error.Abort(_(b'similarity must be a number'))
4159 if sim < 0 or sim > 100:
4139 if sim < 0 or sim > 100:
4160 raise error.Abort(_(b'similarity must be between 0 and 100'))
4140 raise error.Abort(_(b'similarity must be between 0 and 100'))
4161 if sim and not update:
4141 if sim and not update:
4162 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4142 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4163 if exact:
4143 if exact:
4164 if opts.get(b'edit'):
4144 if opts.get(b'edit'):
4165 raise error.Abort(_(b'cannot use --exact with --edit'))
4145 raise error.Abort(_(b'cannot use --exact with --edit'))
4166 if opts.get(b'prefix'):
4146 if opts.get(b'prefix'):
4167 raise error.Abort(_(b'cannot use --exact with --prefix'))
4147 raise error.Abort(_(b'cannot use --exact with --prefix'))
4168
4148
4169 base = opts[b"base"]
4149 base = opts[b"base"]
4170 msgs = []
4150 msgs = []
4171 ret = 0
4151 ret = 0
4172
4152
4173 with repo.wlock():
4153 with repo.wlock():
4174 if update:
4154 if update:
4175 cmdutil.checkunfinished(repo)
4155 cmdutil.checkunfinished(repo)
4176 if exact or not opts.get(b'force'):
4156 if exact or not opts.get(b'force'):
4177 cmdutil.bailifchanged(repo)
4157 cmdutil.bailifchanged(repo)
4178
4158
4179 if not opts.get(b'no_commit'):
4159 if not opts.get(b'no_commit'):
4180 lock = repo.lock
4160 lock = repo.lock
4181 tr = lambda: repo.transaction(b'import')
4161 tr = lambda: repo.transaction(b'import')
4182 dsguard = util.nullcontextmanager
4162 dsguard = util.nullcontextmanager
4183 else:
4163 else:
4184 lock = util.nullcontextmanager
4164 lock = util.nullcontextmanager
4185 tr = util.nullcontextmanager
4165 tr = util.nullcontextmanager
4186 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4166 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4187 with lock(), tr(), dsguard():
4167 with lock(), tr(), dsguard():
4188 parents = repo[None].parents()
4168 parents = repo[None].parents()
4189 for patchurl in patches:
4169 for patchurl in patches:
4190 if patchurl == b'-':
4170 if patchurl == b'-':
4191 ui.status(_(b'applying patch from stdin\n'))
4171 ui.status(_(b'applying patch from stdin\n'))
4192 patchfile = ui.fin
4172 patchfile = ui.fin
4193 patchurl = b'stdin' # for error message
4173 patchurl = b'stdin' # for error message
4194 else:
4174 else:
4195 patchurl = os.path.join(base, patchurl)
4175 patchurl = os.path.join(base, patchurl)
4196 ui.status(_(b'applying %s\n') % patchurl)
4176 ui.status(_(b'applying %s\n') % patchurl)
4197 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4177 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4198
4178
4199 haspatch = False
4179 haspatch = False
4200 for hunk in patch.split(patchfile):
4180 for hunk in patch.split(patchfile):
4201 with patch.extract(ui, hunk) as patchdata:
4181 with patch.extract(ui, hunk) as patchdata:
4202 msg, node, rej = cmdutil.tryimportone(
4182 msg, node, rej = cmdutil.tryimportone(
4203 ui, repo, patchdata, parents, opts, msgs, hg.clean
4183 ui, repo, patchdata, parents, opts, msgs, hg.clean
4204 )
4184 )
4205 if msg:
4185 if msg:
4206 haspatch = True
4186 haspatch = True
4207 ui.note(msg + b'\n')
4187 ui.note(msg + b'\n')
4208 if update or exact:
4188 if update or exact:
4209 parents = repo[None].parents()
4189 parents = repo[None].parents()
4210 else:
4190 else:
4211 parents = [repo[node]]
4191 parents = [repo[node]]
4212 if rej:
4192 if rej:
4213 ui.write_err(_(b"patch applied partially\n"))
4193 ui.write_err(_(b"patch applied partially\n"))
4214 ui.write_err(
4194 ui.write_err(
4215 _(
4195 _(
4216 b"(fix the .rej files and run "
4196 b"(fix the .rej files and run "
4217 b"`hg commit --amend`)\n"
4197 b"`hg commit --amend`)\n"
4218 )
4198 )
4219 )
4199 )
4220 ret = 1
4200 ret = 1
4221 break
4201 break
4222
4202
4223 if not haspatch:
4203 if not haspatch:
4224 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4204 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4225
4205
4226 if msgs:
4206 if msgs:
4227 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4207 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4228 return ret
4208 return ret
4229
4209
4230
4210
4231 @command(
4211 @command(
4232 b'incoming|in',
4212 b'incoming|in',
4233 [
4213 [
4234 (
4214 (
4235 b'f',
4215 b'f',
4236 b'force',
4216 b'force',
4237 None,
4217 None,
4238 _(b'run even if remote repository is unrelated'),
4218 _(b'run even if remote repository is unrelated'),
4239 ),
4219 ),
4240 (b'n', b'newest-first', None, _(b'show newest record first')),
4220 (b'n', b'newest-first', None, _(b'show newest record first')),
4241 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4221 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4242 (
4222 (
4243 b'r',
4223 b'r',
4244 b'rev',
4224 b'rev',
4245 [],
4225 [],
4246 _(b'a remote changeset intended to be added'),
4226 _(b'a remote changeset intended to be added'),
4247 _(b'REV'),
4227 _(b'REV'),
4248 ),
4228 ),
4249 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4229 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4250 (
4230 (
4251 b'b',
4231 b'b',
4252 b'branch',
4232 b'branch',
4253 [],
4233 [],
4254 _(b'a specific branch you would like to pull'),
4234 _(b'a specific branch you would like to pull'),
4255 _(b'BRANCH'),
4235 _(b'BRANCH'),
4256 ),
4236 ),
4257 ]
4237 ]
4258 + logopts
4238 + logopts
4259 + remoteopts
4239 + remoteopts
4260 + subrepoopts,
4240 + subrepoopts,
4261 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4241 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4262 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4242 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4263 )
4243 )
4264 def incoming(ui, repo, source=b"default", **opts):
4244 def incoming(ui, repo, source=b"default", **opts):
4265 """show new changesets found in source
4245 """show new changesets found in source
4266
4246
4267 Show new changesets found in the specified path/URL or the default
4247 Show new changesets found in the specified path/URL or the default
4268 pull location. These are the changesets that would have been pulled
4248 pull location. These are the changesets that would have been pulled
4269 by :hg:`pull` at the time you issued this command.
4249 by :hg:`pull` at the time you issued this command.
4270
4250
4271 See pull for valid source format details.
4251 See pull for valid source format details.
4272
4252
4273 .. container:: verbose
4253 .. container:: verbose
4274
4254
4275 With -B/--bookmarks, the result of bookmark comparison between
4255 With -B/--bookmarks, the result of bookmark comparison between
4276 local and remote repositories is displayed. With -v/--verbose,
4256 local and remote repositories is displayed. With -v/--verbose,
4277 status is also displayed for each bookmark like below::
4257 status is also displayed for each bookmark like below::
4278
4258
4279 BM1 01234567890a added
4259 BM1 01234567890a added
4280 BM2 1234567890ab advanced
4260 BM2 1234567890ab advanced
4281 BM3 234567890abc diverged
4261 BM3 234567890abc diverged
4282 BM4 34567890abcd changed
4262 BM4 34567890abcd changed
4283
4263
4284 The action taken locally when pulling depends on the
4264 The action taken locally when pulling depends on the
4285 status of each bookmark:
4265 status of each bookmark:
4286
4266
4287 :``added``: pull will create it
4267 :``added``: pull will create it
4288 :``advanced``: pull will update it
4268 :``advanced``: pull will update it
4289 :``diverged``: pull will create a divergent bookmark
4269 :``diverged``: pull will create a divergent bookmark
4290 :``changed``: result depends on remote changesets
4270 :``changed``: result depends on remote changesets
4291
4271
4292 From the point of view of pulling behavior, bookmark
4272 From the point of view of pulling behavior, bookmark
4293 existing only in the remote repository are treated as ``added``,
4273 existing only in the remote repository are treated as ``added``,
4294 even if it is in fact locally deleted.
4274 even if it is in fact locally deleted.
4295
4275
4296 .. container:: verbose
4276 .. container:: verbose
4297
4277
4298 For remote repository, using --bundle avoids downloading the
4278 For remote repository, using --bundle avoids downloading the
4299 changesets twice if the incoming is followed by a pull.
4279 changesets twice if the incoming is followed by a pull.
4300
4280
4301 Examples:
4281 Examples:
4302
4282
4303 - show incoming changes with patches and full description::
4283 - show incoming changes with patches and full description::
4304
4284
4305 hg incoming -vp
4285 hg incoming -vp
4306
4286
4307 - show incoming changes excluding merges, store a bundle::
4287 - show incoming changes excluding merges, store a bundle::
4308
4288
4309 hg in -vpM --bundle incoming.hg
4289 hg in -vpM --bundle incoming.hg
4310 hg pull incoming.hg
4290 hg pull incoming.hg
4311
4291
4312 - briefly list changes inside a bundle::
4292 - briefly list changes inside a bundle::
4313
4293
4314 hg in changes.hg -T "{desc|firstline}\\n"
4294 hg in changes.hg -T "{desc|firstline}\\n"
4315
4295
4316 Returns 0 if there are incoming changes, 1 otherwise.
4296 Returns 0 if there are incoming changes, 1 otherwise.
4317 """
4297 """
4318 opts = pycompat.byteskwargs(opts)
4298 opts = pycompat.byteskwargs(opts)
4319 if opts.get(b'graph'):
4299 if opts.get(b'graph'):
4320 logcmdutil.checkunsupportedgraphflags([], opts)
4300 logcmdutil.checkunsupportedgraphflags([], opts)
4321
4301
4322 def display(other, chlist, displayer):
4302 def display(other, chlist, displayer):
4323 revdag = logcmdutil.graphrevs(other, chlist, opts)
4303 revdag = logcmdutil.graphrevs(other, chlist, opts)
4324 logcmdutil.displaygraph(
4304 logcmdutil.displaygraph(
4325 ui, repo, revdag, displayer, graphmod.asciiedges
4305 ui, repo, revdag, displayer, graphmod.asciiedges
4326 )
4306 )
4327
4307
4328 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4308 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4329 return 0
4309 return 0
4330
4310
4331 if opts.get(b'bundle') and opts.get(b'subrepos'):
4311 if opts.get(b'bundle') and opts.get(b'subrepos'):
4332 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4312 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4333
4313
4334 if opts.get(b'bookmarks'):
4314 if opts.get(b'bookmarks'):
4335 source, branches = hg.parseurl(
4315 source, branches = hg.parseurl(
4336 ui.expandpath(source), opts.get(b'branch')
4316 ui.expandpath(source), opts.get(b'branch')
4337 )
4317 )
4338 other = hg.peer(repo, opts, source)
4318 other = hg.peer(repo, opts, source)
4339 if b'bookmarks' not in other.listkeys(b'namespaces'):
4319 if b'bookmarks' not in other.listkeys(b'namespaces'):
4340 ui.warn(_(b"remote doesn't support bookmarks\n"))
4320 ui.warn(_(b"remote doesn't support bookmarks\n"))
4341 return 0
4321 return 0
4342 ui.pager(b'incoming')
4322 ui.pager(b'incoming')
4343 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4323 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4344 return bookmarks.incoming(ui, repo, other)
4324 return bookmarks.incoming(ui, repo, other)
4345
4325
4346 repo._subtoppath = ui.expandpath(source)
4326 repo._subtoppath = ui.expandpath(source)
4347 try:
4327 try:
4348 return hg.incoming(ui, repo, source, opts)
4328 return hg.incoming(ui, repo, source, opts)
4349 finally:
4329 finally:
4350 del repo._subtoppath
4330 del repo._subtoppath
4351
4331
4352
4332
4353 @command(
4333 @command(
4354 b'init',
4334 b'init',
4355 remoteopts,
4335 remoteopts,
4356 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4336 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4357 helpcategory=command.CATEGORY_REPO_CREATION,
4337 helpcategory=command.CATEGORY_REPO_CREATION,
4358 helpbasic=True,
4338 helpbasic=True,
4359 norepo=True,
4339 norepo=True,
4360 )
4340 )
4361 def init(ui, dest=b".", **opts):
4341 def init(ui, dest=b".", **opts):
4362 """create a new repository in the given directory
4342 """create a new repository in the given directory
4363
4343
4364 Initialize a new repository in the given directory. If the given
4344 Initialize a new repository in the given directory. If the given
4365 directory does not exist, it will be created.
4345 directory does not exist, it will be created.
4366
4346
4367 If no directory is given, the current directory is used.
4347 If no directory is given, the current directory is used.
4368
4348
4369 It is possible to specify an ``ssh://`` URL as the destination.
4349 It is possible to specify an ``ssh://`` URL as the destination.
4370 See :hg:`help urls` for more information.
4350 See :hg:`help urls` for more information.
4371
4351
4372 Returns 0 on success.
4352 Returns 0 on success.
4373 """
4353 """
4374 opts = pycompat.byteskwargs(opts)
4354 opts = pycompat.byteskwargs(opts)
4375 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4355 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4376
4356
4377
4357
4378 @command(
4358 @command(
4379 b'locate',
4359 b'locate',
4380 [
4360 [
4381 (
4361 (
4382 b'r',
4362 b'r',
4383 b'rev',
4363 b'rev',
4384 b'',
4364 b'',
4385 _(b'search the repository as it is in REV'),
4365 _(b'search the repository as it is in REV'),
4386 _(b'REV'),
4366 _(b'REV'),
4387 ),
4367 ),
4388 (
4368 (
4389 b'0',
4369 b'0',
4390 b'print0',
4370 b'print0',
4391 None,
4371 None,
4392 _(b'end filenames with NUL, for use with xargs'),
4372 _(b'end filenames with NUL, for use with xargs'),
4393 ),
4373 ),
4394 (
4374 (
4395 b'f',
4375 b'f',
4396 b'fullpath',
4376 b'fullpath',
4397 None,
4377 None,
4398 _(b'print complete paths from the filesystem root'),
4378 _(b'print complete paths from the filesystem root'),
4399 ),
4379 ),
4400 ]
4380 ]
4401 + walkopts,
4381 + walkopts,
4402 _(b'[OPTION]... [PATTERN]...'),
4382 _(b'[OPTION]... [PATTERN]...'),
4403 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4383 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4404 )
4384 )
4405 def locate(ui, repo, *pats, **opts):
4385 def locate(ui, repo, *pats, **opts):
4406 """locate files matching specific patterns (DEPRECATED)
4386 """locate files matching specific patterns (DEPRECATED)
4407
4387
4408 Print files under Mercurial control in the working directory whose
4388 Print files under Mercurial control in the working directory whose
4409 names match the given patterns.
4389 names match the given patterns.
4410
4390
4411 By default, this command searches all directories in the working
4391 By default, this command searches all directories in the working
4412 directory. To search just the current directory and its
4392 directory. To search just the current directory and its
4413 subdirectories, use "--include .".
4393 subdirectories, use "--include .".
4414
4394
4415 If no patterns are given to match, this command prints the names
4395 If no patterns are given to match, this command prints the names
4416 of all files under Mercurial control in the working directory.
4396 of all files under Mercurial control in the working directory.
4417
4397
4418 If you want to feed the output of this command into the "xargs"
4398 If you want to feed the output of this command into the "xargs"
4419 command, use the -0 option to both this command and "xargs". This
4399 command, use the -0 option to both this command and "xargs". This
4420 will avoid the problem of "xargs" treating single filenames that
4400 will avoid the problem of "xargs" treating single filenames that
4421 contain whitespace as multiple filenames.
4401 contain whitespace as multiple filenames.
4422
4402
4423 See :hg:`help files` for a more versatile command.
4403 See :hg:`help files` for a more versatile command.
4424
4404
4425 Returns 0 if a match is found, 1 otherwise.
4405 Returns 0 if a match is found, 1 otherwise.
4426 """
4406 """
4427 opts = pycompat.byteskwargs(opts)
4407 opts = pycompat.byteskwargs(opts)
4428 if opts.get(b'print0'):
4408 if opts.get(b'print0'):
4429 end = b'\0'
4409 end = b'\0'
4430 else:
4410 else:
4431 end = b'\n'
4411 end = b'\n'
4432 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4412 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4433
4413
4434 ret = 1
4414 ret = 1
4435 m = scmutil.match(
4415 m = scmutil.match(
4436 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4416 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4437 )
4417 )
4438
4418
4439 ui.pager(b'locate')
4419 ui.pager(b'locate')
4440 if ctx.rev() is None:
4420 if ctx.rev() is None:
4441 # When run on the working copy, "locate" includes removed files, so
4421 # When run on the working copy, "locate" includes removed files, so
4442 # we get the list of files from the dirstate.
4422 # we get the list of files from the dirstate.
4443 filesgen = sorted(repo.dirstate.matches(m))
4423 filesgen = sorted(repo.dirstate.matches(m))
4444 else:
4424 else:
4445 filesgen = ctx.matches(m)
4425 filesgen = ctx.matches(m)
4446 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4426 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4447 for abs in filesgen:
4427 for abs in filesgen:
4448 if opts.get(b'fullpath'):
4428 if opts.get(b'fullpath'):
4449 ui.write(repo.wjoin(abs), end)
4429 ui.write(repo.wjoin(abs), end)
4450 else:
4430 else:
4451 ui.write(uipathfn(abs), end)
4431 ui.write(uipathfn(abs), end)
4452 ret = 0
4432 ret = 0
4453
4433
4454 return ret
4434 return ret
4455
4435
4456
4436
4457 @command(
4437 @command(
4458 b'log|history',
4438 b'log|history',
4459 [
4439 [
4460 (
4440 (
4461 b'f',
4441 b'f',
4462 b'follow',
4442 b'follow',
4463 None,
4443 None,
4464 _(
4444 _(
4465 b'follow changeset history, or file history across copies and renames'
4445 b'follow changeset history, or file history across copies and renames'
4466 ),
4446 ),
4467 ),
4447 ),
4468 (
4448 (
4469 b'',
4449 b'',
4470 b'follow-first',
4450 b'follow-first',
4471 None,
4451 None,
4472 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4452 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4473 ),
4453 ),
4474 (
4454 (
4475 b'd',
4455 b'd',
4476 b'date',
4456 b'date',
4477 b'',
4457 b'',
4478 _(b'show revisions matching date spec'),
4458 _(b'show revisions matching date spec'),
4479 _(b'DATE'),
4459 _(b'DATE'),
4480 ),
4460 ),
4481 (b'C', b'copies', None, _(b'show copied files')),
4461 (b'C', b'copies', None, _(b'show copied files')),
4482 (
4462 (
4483 b'k',
4463 b'k',
4484 b'keyword',
4464 b'keyword',
4485 [],
4465 [],
4486 _(b'do case-insensitive search for a given text'),
4466 _(b'do case-insensitive search for a given text'),
4487 _(b'TEXT'),
4467 _(b'TEXT'),
4488 ),
4468 ),
4489 (
4469 (
4490 b'r',
4470 b'r',
4491 b'rev',
4471 b'rev',
4492 [],
4472 [],
4493 _(b'show the specified revision or revset'),
4473 _(b'show the specified revision or revset'),
4494 _(b'REV'),
4474 _(b'REV'),
4495 ),
4475 ),
4496 (
4476 (
4497 b'L',
4477 b'L',
4498 b'line-range',
4478 b'line-range',
4499 [],
4479 [],
4500 _(b'follow line range of specified file (EXPERIMENTAL)'),
4480 _(b'follow line range of specified file (EXPERIMENTAL)'),
4501 _(b'FILE,RANGE'),
4481 _(b'FILE,RANGE'),
4502 ),
4482 ),
4503 (
4483 (
4504 b'',
4484 b'',
4505 b'removed',
4485 b'removed',
4506 None,
4486 None,
4507 _(b'include revisions where files were removed'),
4487 _(b'include revisions where files were removed'),
4508 ),
4488 ),
4509 (
4489 (
4510 b'm',
4490 b'm',
4511 b'only-merges',
4491 b'only-merges',
4512 None,
4492 None,
4513 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4493 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4514 ),
4494 ),
4515 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4495 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4516 (
4496 (
4517 b'',
4497 b'',
4518 b'only-branch',
4498 b'only-branch',
4519 [],
4499 [],
4520 _(
4500 _(
4521 b'show only changesets within the given named branch (DEPRECATED)'
4501 b'show only changesets within the given named branch (DEPRECATED)'
4522 ),
4502 ),
4523 _(b'BRANCH'),
4503 _(b'BRANCH'),
4524 ),
4504 ),
4525 (
4505 (
4526 b'b',
4506 b'b',
4527 b'branch',
4507 b'branch',
4528 [],
4508 [],
4529 _(b'show changesets within the given named branch'),
4509 _(b'show changesets within the given named branch'),
4530 _(b'BRANCH'),
4510 _(b'BRANCH'),
4531 ),
4511 ),
4532 (
4512 (
4533 b'P',
4513 b'P',
4534 b'prune',
4514 b'prune',
4535 [],
4515 [],
4536 _(b'do not display revision or any of its ancestors'),
4516 _(b'do not display revision or any of its ancestors'),
4537 _(b'REV'),
4517 _(b'REV'),
4538 ),
4518 ),
4539 ]
4519 ]
4540 + logopts
4520 + logopts
4541 + walkopts,
4521 + walkopts,
4542 _(b'[OPTION]... [FILE]'),
4522 _(b'[OPTION]... [FILE]'),
4543 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4523 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4544 helpbasic=True,
4524 helpbasic=True,
4545 inferrepo=True,
4525 inferrepo=True,
4546 intents={INTENT_READONLY},
4526 intents={INTENT_READONLY},
4547 )
4527 )
4548 def log(ui, repo, *pats, **opts):
4528 def log(ui, repo, *pats, **opts):
4549 """show revision history of entire repository or files
4529 """show revision history of entire repository or files
4550
4530
4551 Print the revision history of the specified files or the entire
4531 Print the revision history of the specified files or the entire
4552 project.
4532 project.
4553
4533
4554 If no revision range is specified, the default is ``tip:0`` unless
4534 If no revision range is specified, the default is ``tip:0`` unless
4555 --follow is set, in which case the working directory parent is
4535 --follow is set, in which case the working directory parent is
4556 used as the starting revision.
4536 used as the starting revision.
4557
4537
4558 File history is shown without following rename or copy history of
4538 File history is shown without following rename or copy history of
4559 files. Use -f/--follow with a filename to follow history across
4539 files. Use -f/--follow with a filename to follow history across
4560 renames and copies. --follow without a filename will only show
4540 renames and copies. --follow without a filename will only show
4561 ancestors of the starting revision.
4541 ancestors of the starting revision.
4562
4542
4563 By default this command prints revision number and changeset id,
4543 By default this command prints revision number and changeset id,
4564 tags, non-trivial parents, user, date and time, and a summary for
4544 tags, non-trivial parents, user, date and time, and a summary for
4565 each commit. When the -v/--verbose switch is used, the list of
4545 each commit. When the -v/--verbose switch is used, the list of
4566 changed files and full commit message are shown.
4546 changed files and full commit message are shown.
4567
4547
4568 With --graph the revisions are shown as an ASCII art DAG with the most
4548 With --graph the revisions are shown as an ASCII art DAG with the most
4569 recent changeset at the top.
4549 recent changeset at the top.
4570 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4550 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4571 involved in an unresolved merge conflict, '_' closes a branch,
4551 involved in an unresolved merge conflict, '_' closes a branch,
4572 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4552 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4573 changeset from the lines below is a parent of the 'o' merge on the same
4553 changeset from the lines below is a parent of the 'o' merge on the same
4574 line.
4554 line.
4575 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4555 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4576 of a '|' indicates one or more revisions in a path are omitted.
4556 of a '|' indicates one or more revisions in a path are omitted.
4577
4557
4578 .. container:: verbose
4558 .. container:: verbose
4579
4559
4580 Use -L/--line-range FILE,M:N options to follow the history of lines
4560 Use -L/--line-range FILE,M:N options to follow the history of lines
4581 from M to N in FILE. With -p/--patch only diff hunks affecting
4561 from M to N in FILE. With -p/--patch only diff hunks affecting
4582 specified line range will be shown. This option requires --follow;
4562 specified line range will be shown. This option requires --follow;
4583 it can be specified multiple times. Currently, this option is not
4563 it can be specified multiple times. Currently, this option is not
4584 compatible with --graph. This option is experimental.
4564 compatible with --graph. This option is experimental.
4585
4565
4586 .. note::
4566 .. note::
4587
4567
4588 :hg:`log --patch` may generate unexpected diff output for merge
4568 :hg:`log --patch` may generate unexpected diff output for merge
4589 changesets, as it will only compare the merge changeset against
4569 changesets, as it will only compare the merge changeset against
4590 its first parent. Also, only files different from BOTH parents
4570 its first parent. Also, only files different from BOTH parents
4591 will appear in files:.
4571 will appear in files:.
4592
4572
4593 .. note::
4573 .. note::
4594
4574
4595 For performance reasons, :hg:`log FILE` may omit duplicate changes
4575 For performance reasons, :hg:`log FILE` may omit duplicate changes
4596 made on branches and will not show removals or mode changes. To
4576 made on branches and will not show removals or mode changes. To
4597 see all such changes, use the --removed switch.
4577 see all such changes, use the --removed switch.
4598
4578
4599 .. container:: verbose
4579 .. container:: verbose
4600
4580
4601 .. note::
4581 .. note::
4602
4582
4603 The history resulting from -L/--line-range options depends on diff
4583 The history resulting from -L/--line-range options depends on diff
4604 options; for instance if white-spaces are ignored, respective changes
4584 options; for instance if white-spaces are ignored, respective changes
4605 with only white-spaces in specified line range will not be listed.
4585 with only white-spaces in specified line range will not be listed.
4606
4586
4607 .. container:: verbose
4587 .. container:: verbose
4608
4588
4609 Some examples:
4589 Some examples:
4610
4590
4611 - changesets with full descriptions and file lists::
4591 - changesets with full descriptions and file lists::
4612
4592
4613 hg log -v
4593 hg log -v
4614
4594
4615 - changesets ancestral to the working directory::
4595 - changesets ancestral to the working directory::
4616
4596
4617 hg log -f
4597 hg log -f
4618
4598
4619 - last 10 commits on the current branch::
4599 - last 10 commits on the current branch::
4620
4600
4621 hg log -l 10 -b .
4601 hg log -l 10 -b .
4622
4602
4623 - changesets showing all modifications of a file, including removals::
4603 - changesets showing all modifications of a file, including removals::
4624
4604
4625 hg log --removed file.c
4605 hg log --removed file.c
4626
4606
4627 - all changesets that touch a directory, with diffs, excluding merges::
4607 - all changesets that touch a directory, with diffs, excluding merges::
4628
4608
4629 hg log -Mp lib/
4609 hg log -Mp lib/
4630
4610
4631 - all revision numbers that match a keyword::
4611 - all revision numbers that match a keyword::
4632
4612
4633 hg log -k bug --template "{rev}\\n"
4613 hg log -k bug --template "{rev}\\n"
4634
4614
4635 - the full hash identifier of the working directory parent::
4615 - the full hash identifier of the working directory parent::
4636
4616
4637 hg log -r . --template "{node}\\n"
4617 hg log -r . --template "{node}\\n"
4638
4618
4639 - list available log templates::
4619 - list available log templates::
4640
4620
4641 hg log -T list
4621 hg log -T list
4642
4622
4643 - check if a given changeset is included in a tagged release::
4623 - check if a given changeset is included in a tagged release::
4644
4624
4645 hg log -r "a21ccf and ancestor(1.9)"
4625 hg log -r "a21ccf and ancestor(1.9)"
4646
4626
4647 - find all changesets by some user in a date range::
4627 - find all changesets by some user in a date range::
4648
4628
4649 hg log -k alice -d "may 2008 to jul 2008"
4629 hg log -k alice -d "may 2008 to jul 2008"
4650
4630
4651 - summary of all changesets after the last tag::
4631 - summary of all changesets after the last tag::
4652
4632
4653 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4633 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4654
4634
4655 - changesets touching lines 13 to 23 for file.c::
4635 - changesets touching lines 13 to 23 for file.c::
4656
4636
4657 hg log -L file.c,13:23
4637 hg log -L file.c,13:23
4658
4638
4659 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4639 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4660 main.c with patch::
4640 main.c with patch::
4661
4641
4662 hg log -L file.c,13:23 -L main.c,2:6 -p
4642 hg log -L file.c,13:23 -L main.c,2:6 -p
4663
4643
4664 See :hg:`help dates` for a list of formats valid for -d/--date.
4644 See :hg:`help dates` for a list of formats valid for -d/--date.
4665
4645
4666 See :hg:`help revisions` for more about specifying and ordering
4646 See :hg:`help revisions` for more about specifying and ordering
4667 revisions.
4647 revisions.
4668
4648
4669 See :hg:`help templates` for more about pre-packaged styles and
4649 See :hg:`help templates` for more about pre-packaged styles and
4670 specifying custom templates. The default template used by the log
4650 specifying custom templates. The default template used by the log
4671 command can be customized via the ``ui.logtemplate`` configuration
4651 command can be customized via the ``ui.logtemplate`` configuration
4672 setting.
4652 setting.
4673
4653
4674 Returns 0 on success.
4654 Returns 0 on success.
4675
4655
4676 """
4656 """
4677 opts = pycompat.byteskwargs(opts)
4657 opts = pycompat.byteskwargs(opts)
4678 linerange = opts.get(b'line_range')
4658 linerange = opts.get(b'line_range')
4679
4659
4680 if linerange and not opts.get(b'follow'):
4660 if linerange and not opts.get(b'follow'):
4681 raise error.Abort(_(b'--line-range requires --follow'))
4661 raise error.Abort(_(b'--line-range requires --follow'))
4682
4662
4683 if linerange and pats:
4663 if linerange and pats:
4684 # TODO: take pats as patterns with no line-range filter
4664 # TODO: take pats as patterns with no line-range filter
4685 raise error.Abort(
4665 raise error.Abort(
4686 _(b'FILE arguments are not compatible with --line-range option')
4666 _(b'FILE arguments are not compatible with --line-range option')
4687 )
4667 )
4688
4668
4689 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4669 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4690 revs, differ = logcmdutil.getrevs(
4670 revs, differ = logcmdutil.getrevs(
4691 repo, logcmdutil.parseopts(ui, pats, opts)
4671 repo, logcmdutil.parseopts(ui, pats, opts)
4692 )
4672 )
4693 if linerange:
4673 if linerange:
4694 # TODO: should follow file history from logcmdutil._initialrevs(),
4674 # TODO: should follow file history from logcmdutil._initialrevs(),
4695 # then filter the result by logcmdutil._makerevset() and --limit
4675 # then filter the result by logcmdutil._makerevset() and --limit
4696 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4676 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4697
4677
4698 getcopies = None
4678 getcopies = None
4699 if opts.get(b'copies'):
4679 if opts.get(b'copies'):
4700 endrev = None
4680 endrev = None
4701 if revs:
4681 if revs:
4702 endrev = revs.max() + 1
4682 endrev = revs.max() + 1
4703 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4683 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4704
4684
4705 ui.pager(b'log')
4685 ui.pager(b'log')
4706 displayer = logcmdutil.changesetdisplayer(
4686 displayer = logcmdutil.changesetdisplayer(
4707 ui, repo, opts, differ, buffered=True
4687 ui, repo, opts, differ, buffered=True
4708 )
4688 )
4709 if opts.get(b'graph'):
4689 if opts.get(b'graph'):
4710 displayfn = logcmdutil.displaygraphrevs
4690 displayfn = logcmdutil.displaygraphrevs
4711 else:
4691 else:
4712 displayfn = logcmdutil.displayrevs
4692 displayfn = logcmdutil.displayrevs
4713 displayfn(ui, repo, revs, displayer, getcopies)
4693 displayfn(ui, repo, revs, displayer, getcopies)
4714
4694
4715
4695
4716 @command(
4696 @command(
4717 b'manifest',
4697 b'manifest',
4718 [
4698 [
4719 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4699 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4720 (b'', b'all', False, _(b"list files from all revisions")),
4700 (b'', b'all', False, _(b"list files from all revisions")),
4721 ]
4701 ]
4722 + formatteropts,
4702 + formatteropts,
4723 _(b'[-r REV]'),
4703 _(b'[-r REV]'),
4724 helpcategory=command.CATEGORY_MAINTENANCE,
4704 helpcategory=command.CATEGORY_MAINTENANCE,
4725 intents={INTENT_READONLY},
4705 intents={INTENT_READONLY},
4726 )
4706 )
4727 def manifest(ui, repo, node=None, rev=None, **opts):
4707 def manifest(ui, repo, node=None, rev=None, **opts):
4728 """output the current or given revision of the project manifest
4708 """output the current or given revision of the project manifest
4729
4709
4730 Print a list of version controlled files for the given revision.
4710 Print a list of version controlled files for the given revision.
4731 If no revision is given, the first parent of the working directory
4711 If no revision is given, the first parent of the working directory
4732 is used, or the null revision if no revision is checked out.
4712 is used, or the null revision if no revision is checked out.
4733
4713
4734 With -v, print file permissions, symlink and executable bits.
4714 With -v, print file permissions, symlink and executable bits.
4735 With --debug, print file revision hashes.
4715 With --debug, print file revision hashes.
4736
4716
4737 If option --all is specified, the list of all files from all revisions
4717 If option --all is specified, the list of all files from all revisions
4738 is printed. This includes deleted and renamed files.
4718 is printed. This includes deleted and renamed files.
4739
4719
4740 Returns 0 on success.
4720 Returns 0 on success.
4741 """
4721 """
4742 opts = pycompat.byteskwargs(opts)
4722 opts = pycompat.byteskwargs(opts)
4743 fm = ui.formatter(b'manifest', opts)
4723 fm = ui.formatter(b'manifest', opts)
4744
4724
4745 if opts.get(b'all'):
4725 if opts.get(b'all'):
4746 if rev or node:
4726 if rev or node:
4747 raise error.Abort(_(b"can't specify a revision with --all"))
4727 raise error.Abort(_(b"can't specify a revision with --all"))
4748
4728
4749 res = set()
4729 res = set()
4750 for rev in repo:
4730 for rev in repo:
4751 ctx = repo[rev]
4731 ctx = repo[rev]
4752 res |= set(ctx.files())
4732 res |= set(ctx.files())
4753
4733
4754 ui.pager(b'manifest')
4734 ui.pager(b'manifest')
4755 for f in sorted(res):
4735 for f in sorted(res):
4756 fm.startitem()
4736 fm.startitem()
4757 fm.write(b"path", b'%s\n', f)
4737 fm.write(b"path", b'%s\n', f)
4758 fm.end()
4738 fm.end()
4759 return
4739 return
4760
4740
4761 if rev and node:
4741 if rev and node:
4762 raise error.Abort(_(b"please specify just one revision"))
4742 raise error.Abort(_(b"please specify just one revision"))
4763
4743
4764 if not node:
4744 if not node:
4765 node = rev
4745 node = rev
4766
4746
4767 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4747 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4768 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4748 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4769 if node:
4749 if node:
4770 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4750 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4771 ctx = scmutil.revsingle(repo, node)
4751 ctx = scmutil.revsingle(repo, node)
4772 mf = ctx.manifest()
4752 mf = ctx.manifest()
4773 ui.pager(b'manifest')
4753 ui.pager(b'manifest')
4774 for f in ctx:
4754 for f in ctx:
4775 fm.startitem()
4755 fm.startitem()
4776 fm.context(ctx=ctx)
4756 fm.context(ctx=ctx)
4777 fl = ctx[f].flags()
4757 fl = ctx[f].flags()
4778 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4758 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4779 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4759 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4780 fm.write(b'path', b'%s\n', f)
4760 fm.write(b'path', b'%s\n', f)
4781 fm.end()
4761 fm.end()
4782
4762
4783
4763
4784 @command(
4764 @command(
4785 b'merge',
4765 b'merge',
4786 [
4766 [
4787 (
4767 (
4788 b'f',
4768 b'f',
4789 b'force',
4769 b'force',
4790 None,
4770 None,
4791 _(b'force a merge including outstanding changes (DEPRECATED)'),
4771 _(b'force a merge including outstanding changes (DEPRECATED)'),
4792 ),
4772 ),
4793 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4773 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4794 (
4774 (
4795 b'P',
4775 b'P',
4796 b'preview',
4776 b'preview',
4797 None,
4777 None,
4798 _(b'review revisions to merge (no merge is performed)'),
4778 _(b'review revisions to merge (no merge is performed)'),
4799 ),
4779 ),
4800 (b'', b'abort', None, _(b'abort the ongoing merge')),
4780 (b'', b'abort', None, _(b'abort the ongoing merge')),
4801 ]
4781 ]
4802 + mergetoolopts,
4782 + mergetoolopts,
4803 _(b'[-P] [[-r] REV]'),
4783 _(b'[-P] [[-r] REV]'),
4804 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4784 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4805 helpbasic=True,
4785 helpbasic=True,
4806 )
4786 )
4807 def merge(ui, repo, node=None, **opts):
4787 def merge(ui, repo, node=None, **opts):
4808 """merge another revision into working directory
4788 """merge another revision into working directory
4809
4789
4810 The current working directory is updated with all changes made in
4790 The current working directory is updated with all changes made in
4811 the requested revision since the last common predecessor revision.
4791 the requested revision since the last common predecessor revision.
4812
4792
4813 Files that changed between either parent are marked as changed for
4793 Files that changed between either parent are marked as changed for
4814 the next commit and a commit must be performed before any further
4794 the next commit and a commit must be performed before any further
4815 updates to the repository are allowed. The next commit will have
4795 updates to the repository are allowed. The next commit will have
4816 two parents.
4796 two parents.
4817
4797
4818 ``--tool`` can be used to specify the merge tool used for file
4798 ``--tool`` can be used to specify the merge tool used for file
4819 merges. It overrides the HGMERGE environment variable and your
4799 merges. It overrides the HGMERGE environment variable and your
4820 configuration files. See :hg:`help merge-tools` for options.
4800 configuration files. See :hg:`help merge-tools` for options.
4821
4801
4822 If no revision is specified, the working directory's parent is a
4802 If no revision is specified, the working directory's parent is a
4823 head revision, and the current branch contains exactly one other
4803 head revision, and the current branch contains exactly one other
4824 head, the other head is merged with by default. Otherwise, an
4804 head, the other head is merged with by default. Otherwise, an
4825 explicit revision with which to merge must be provided.
4805 explicit revision with which to merge must be provided.
4826
4806
4827 See :hg:`help resolve` for information on handling file conflicts.
4807 See :hg:`help resolve` for information on handling file conflicts.
4828
4808
4829 To undo an uncommitted merge, use :hg:`merge --abort` which
4809 To undo an uncommitted merge, use :hg:`merge --abort` which
4830 will check out a clean copy of the original merge parent, losing
4810 will check out a clean copy of the original merge parent, losing
4831 all changes.
4811 all changes.
4832
4812
4833 Returns 0 on success, 1 if there are unresolved files.
4813 Returns 0 on success, 1 if there are unresolved files.
4834 """
4814 """
4835
4815
4836 opts = pycompat.byteskwargs(opts)
4816 opts = pycompat.byteskwargs(opts)
4837 abort = opts.get(b'abort')
4817 abort = opts.get(b'abort')
4838 if abort and repo.dirstate.p2() == nullid:
4818 if abort and repo.dirstate.p2() == nullid:
4839 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4819 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4840 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4820 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4841 if abort:
4821 if abort:
4842 state = cmdutil.getunfinishedstate(repo)
4822 state = cmdutil.getunfinishedstate(repo)
4843 if state and state._opname != b'merge':
4823 if state and state._opname != b'merge':
4844 raise error.Abort(
4824 raise error.Abort(
4845 _(b'cannot abort merge with %s in progress') % (state._opname),
4825 _(b'cannot abort merge with %s in progress') % (state._opname),
4846 hint=state.hint(),
4826 hint=state.hint(),
4847 )
4827 )
4848 if node:
4828 if node:
4849 raise error.Abort(_(b"cannot specify a node with --abort"))
4829 raise error.Abort(_(b"cannot specify a node with --abort"))
4850 return hg.abortmerge(repo.ui, repo)
4830 return hg.abortmerge(repo.ui, repo)
4851
4831
4852 if opts.get(b'rev') and node:
4832 if opts.get(b'rev') and node:
4853 raise error.Abort(_(b"please specify just one revision"))
4833 raise error.Abort(_(b"please specify just one revision"))
4854 if not node:
4834 if not node:
4855 node = opts.get(b'rev')
4835 node = opts.get(b'rev')
4856
4836
4857 if node:
4837 if node:
4858 ctx = scmutil.revsingle(repo, node)
4838 ctx = scmutil.revsingle(repo, node)
4859 else:
4839 else:
4860 if ui.configbool(b'commands', b'merge.require-rev'):
4840 if ui.configbool(b'commands', b'merge.require-rev'):
4861 raise error.Abort(
4841 raise error.Abort(
4862 _(
4842 _(
4863 b'configuration requires specifying revision to merge '
4843 b'configuration requires specifying revision to merge '
4864 b'with'
4844 b'with'
4865 )
4845 )
4866 )
4846 )
4867 ctx = repo[destutil.destmerge(repo)]
4847 ctx = repo[destutil.destmerge(repo)]
4868
4848
4869 if ctx.node() is None:
4849 if ctx.node() is None:
4870 raise error.Abort(_(b'merging with the working copy has no effect'))
4850 raise error.Abort(_(b'merging with the working copy has no effect'))
4871
4851
4872 if opts.get(b'preview'):
4852 if opts.get(b'preview'):
4873 # find nodes that are ancestors of p2 but not of p1
4853 # find nodes that are ancestors of p2 but not of p1
4874 p1 = repo[b'.'].node()
4854 p1 = repo[b'.'].node()
4875 p2 = ctx.node()
4855 p2 = ctx.node()
4876 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4856 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4877
4857
4878 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4858 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4879 for node in nodes:
4859 for node in nodes:
4880 displayer.show(repo[node])
4860 displayer.show(repo[node])
4881 displayer.close()
4861 displayer.close()
4882 return 0
4862 return 0
4883
4863
4884 # ui.forcemerge is an internal variable, do not document
4864 # ui.forcemerge is an internal variable, do not document
4885 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4865 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4886 with ui.configoverride(overrides, b'merge'):
4866 with ui.configoverride(overrides, b'merge'):
4887 force = opts.get(b'force')
4867 force = opts.get(b'force')
4888 labels = [b'working copy', b'merge rev']
4868 labels = [b'working copy', b'merge rev']
4889 return hg.merge(ctx, force=force, labels=labels)
4869 return hg.merge(ctx, force=force, labels=labels)
4890
4870
4891
4871
4892 statemod.addunfinished(
4872 statemod.addunfinished(
4893 b'merge',
4873 b'merge',
4894 fname=None,
4874 fname=None,
4895 clearable=True,
4875 clearable=True,
4896 allowcommit=True,
4876 allowcommit=True,
4897 cmdmsg=_(b'outstanding uncommitted merge'),
4877 cmdmsg=_(b'outstanding uncommitted merge'),
4898 abortfunc=hg.abortmerge,
4878 abortfunc=hg.abortmerge,
4899 statushint=_(
4879 statushint=_(
4900 b'To continue: hg commit\nTo abort: hg merge --abort'
4880 b'To continue: hg commit\nTo abort: hg merge --abort'
4901 ),
4881 ),
4902 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4882 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4903 )
4883 )
4904
4884
4905
4885
4906 @command(
4886 @command(
4907 b'outgoing|out',
4887 b'outgoing|out',
4908 [
4888 [
4909 (
4889 (
4910 b'f',
4890 b'f',
4911 b'force',
4891 b'force',
4912 None,
4892 None,
4913 _(b'run even when the destination is unrelated'),
4893 _(b'run even when the destination is unrelated'),
4914 ),
4894 ),
4915 (
4895 (
4916 b'r',
4896 b'r',
4917 b'rev',
4897 b'rev',
4918 [],
4898 [],
4919 _(b'a changeset intended to be included in the destination'),
4899 _(b'a changeset intended to be included in the destination'),
4920 _(b'REV'),
4900 _(b'REV'),
4921 ),
4901 ),
4922 (b'n', b'newest-first', None, _(b'show newest record first')),
4902 (b'n', b'newest-first', None, _(b'show newest record first')),
4923 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4903 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4924 (
4904 (
4925 b'b',
4905 b'b',
4926 b'branch',
4906 b'branch',
4927 [],
4907 [],
4928 _(b'a specific branch you would like to push'),
4908 _(b'a specific branch you would like to push'),
4929 _(b'BRANCH'),
4909 _(b'BRANCH'),
4930 ),
4910 ),
4931 ]
4911 ]
4932 + logopts
4912 + logopts
4933 + remoteopts
4913 + remoteopts
4934 + subrepoopts,
4914 + subrepoopts,
4935 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4915 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4936 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4916 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4937 )
4917 )
4938 def outgoing(ui, repo, dest=None, **opts):
4918 def outgoing(ui, repo, dest=None, **opts):
4939 """show changesets not found in the destination
4919 """show changesets not found in the destination
4940
4920
4941 Show changesets not found in the specified destination repository
4921 Show changesets not found in the specified destination repository
4942 or the default push location. These are the changesets that would
4922 or the default push location. These are the changesets that would
4943 be pushed if a push was requested.
4923 be pushed if a push was requested.
4944
4924
4945 See pull for details of valid destination formats.
4925 See pull for details of valid destination formats.
4946
4926
4947 .. container:: verbose
4927 .. container:: verbose
4948
4928
4949 With -B/--bookmarks, the result of bookmark comparison between
4929 With -B/--bookmarks, the result of bookmark comparison between
4950 local and remote repositories is displayed. With -v/--verbose,
4930 local and remote repositories is displayed. With -v/--verbose,
4951 status is also displayed for each bookmark like below::
4931 status is also displayed for each bookmark like below::
4952
4932
4953 BM1 01234567890a added
4933 BM1 01234567890a added
4954 BM2 deleted
4934 BM2 deleted
4955 BM3 234567890abc advanced
4935 BM3 234567890abc advanced
4956 BM4 34567890abcd diverged
4936 BM4 34567890abcd diverged
4957 BM5 4567890abcde changed
4937 BM5 4567890abcde changed
4958
4938
4959 The action taken when pushing depends on the
4939 The action taken when pushing depends on the
4960 status of each bookmark:
4940 status of each bookmark:
4961
4941
4962 :``added``: push with ``-B`` will create it
4942 :``added``: push with ``-B`` will create it
4963 :``deleted``: push with ``-B`` will delete it
4943 :``deleted``: push with ``-B`` will delete it
4964 :``advanced``: push will update it
4944 :``advanced``: push will update it
4965 :``diverged``: push with ``-B`` will update it
4945 :``diverged``: push with ``-B`` will update it
4966 :``changed``: push with ``-B`` will update it
4946 :``changed``: push with ``-B`` will update it
4967
4947
4968 From the point of view of pushing behavior, bookmarks
4948 From the point of view of pushing behavior, bookmarks
4969 existing only in the remote repository are treated as
4949 existing only in the remote repository are treated as
4970 ``deleted``, even if it is in fact added remotely.
4950 ``deleted``, even if it is in fact added remotely.
4971
4951
4972 Returns 0 if there are outgoing changes, 1 otherwise.
4952 Returns 0 if there are outgoing changes, 1 otherwise.
4973 """
4953 """
4974 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4954 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4975 # style URLs, so don't overwrite dest.
4955 # style URLs, so don't overwrite dest.
4976 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4956 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4977 if not path:
4957 if not path:
4978 raise error.Abort(
4958 raise error.Abort(
4979 _(b'default repository not configured!'),
4959 _(b'default repository not configured!'),
4980 hint=_(b"see 'hg help config.paths'"),
4960 hint=_(b"see 'hg help config.paths'"),
4981 )
4961 )
4982
4962
4983 opts = pycompat.byteskwargs(opts)
4963 opts = pycompat.byteskwargs(opts)
4984 if opts.get(b'graph'):
4964 if opts.get(b'graph'):
4985 logcmdutil.checkunsupportedgraphflags([], opts)
4965 logcmdutil.checkunsupportedgraphflags([], opts)
4986 o, other = hg._outgoing(ui, repo, dest, opts)
4966 o, other = hg._outgoing(ui, repo, dest, opts)
4987 if not o:
4967 if not o:
4988 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4968 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4989 return
4969 return
4990
4970
4991 revdag = logcmdutil.graphrevs(repo, o, opts)
4971 revdag = logcmdutil.graphrevs(repo, o, opts)
4992 ui.pager(b'outgoing')
4972 ui.pager(b'outgoing')
4993 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4973 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4994 logcmdutil.displaygraph(
4974 logcmdutil.displaygraph(
4995 ui, repo, revdag, displayer, graphmod.asciiedges
4975 ui, repo, revdag, displayer, graphmod.asciiedges
4996 )
4976 )
4997 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4977 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4998 return 0
4978 return 0
4999
4979
5000 if opts.get(b'bookmarks'):
4980 if opts.get(b'bookmarks'):
5001 dest = path.pushloc or path.loc
4981 dest = path.pushloc or path.loc
5002 other = hg.peer(repo, opts, dest)
4982 other = hg.peer(repo, opts, dest)
5003 if b'bookmarks' not in other.listkeys(b'namespaces'):
4983 if b'bookmarks' not in other.listkeys(b'namespaces'):
5004 ui.warn(_(b"remote doesn't support bookmarks\n"))
4984 ui.warn(_(b"remote doesn't support bookmarks\n"))
5005 return 0
4985 return 0
5006 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4986 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5007 ui.pager(b'outgoing')
4987 ui.pager(b'outgoing')
5008 return bookmarks.outgoing(ui, repo, other)
4988 return bookmarks.outgoing(ui, repo, other)
5009
4989
5010 repo._subtoppath = path.pushloc or path.loc
4990 repo._subtoppath = path.pushloc or path.loc
5011 try:
4991 try:
5012 return hg.outgoing(ui, repo, dest, opts)
4992 return hg.outgoing(ui, repo, dest, opts)
5013 finally:
4993 finally:
5014 del repo._subtoppath
4994 del repo._subtoppath
5015
4995
5016
4996
5017 @command(
4997 @command(
5018 b'parents',
4998 b'parents',
5019 [
4999 [
5020 (
5000 (
5021 b'r',
5001 b'r',
5022 b'rev',
5002 b'rev',
5023 b'',
5003 b'',
5024 _(b'show parents of the specified revision'),
5004 _(b'show parents of the specified revision'),
5025 _(b'REV'),
5005 _(b'REV'),
5026 ),
5006 ),
5027 ]
5007 ]
5028 + templateopts,
5008 + templateopts,
5029 _(b'[-r REV] [FILE]'),
5009 _(b'[-r REV] [FILE]'),
5030 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5010 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5031 inferrepo=True,
5011 inferrepo=True,
5032 )
5012 )
5033 def parents(ui, repo, file_=None, **opts):
5013 def parents(ui, repo, file_=None, **opts):
5034 """show the parents of the working directory or revision (DEPRECATED)
5014 """show the parents of the working directory or revision (DEPRECATED)
5035
5015
5036 Print the working directory's parent revisions. If a revision is
5016 Print the working directory's parent revisions. If a revision is
5037 given via -r/--rev, the parent of that revision will be printed.
5017 given via -r/--rev, the parent of that revision will be printed.
5038 If a file argument is given, the revision in which the file was
5018 If a file argument is given, the revision in which the file was
5039 last changed (before the working directory revision or the
5019 last changed (before the working directory revision or the
5040 argument to --rev if given) is printed.
5020 argument to --rev if given) is printed.
5041
5021
5042 This command is equivalent to::
5022 This command is equivalent to::
5043
5023
5044 hg log -r "p1()+p2()" or
5024 hg log -r "p1()+p2()" or
5045 hg log -r "p1(REV)+p2(REV)" or
5025 hg log -r "p1(REV)+p2(REV)" or
5046 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5026 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5047 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5027 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5048
5028
5049 See :hg:`summary` and :hg:`help revsets` for related information.
5029 See :hg:`summary` and :hg:`help revsets` for related information.
5050
5030
5051 Returns 0 on success.
5031 Returns 0 on success.
5052 """
5032 """
5053
5033
5054 opts = pycompat.byteskwargs(opts)
5034 opts = pycompat.byteskwargs(opts)
5055 rev = opts.get(b'rev')
5035 rev = opts.get(b'rev')
5056 if rev:
5036 if rev:
5057 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5037 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5058 ctx = scmutil.revsingle(repo, rev, None)
5038 ctx = scmutil.revsingle(repo, rev, None)
5059
5039
5060 if file_:
5040 if file_:
5061 m = scmutil.match(ctx, (file_,), opts)
5041 m = scmutil.match(ctx, (file_,), opts)
5062 if m.anypats() or len(m.files()) != 1:
5042 if m.anypats() or len(m.files()) != 1:
5063 raise error.Abort(_(b'can only specify an explicit filename'))
5043 raise error.Abort(_(b'can only specify an explicit filename'))
5064 file_ = m.files()[0]
5044 file_ = m.files()[0]
5065 filenodes = []
5045 filenodes = []
5066 for cp in ctx.parents():
5046 for cp in ctx.parents():
5067 if not cp:
5047 if not cp:
5068 continue
5048 continue
5069 try:
5049 try:
5070 filenodes.append(cp.filenode(file_))
5050 filenodes.append(cp.filenode(file_))
5071 except error.LookupError:
5051 except error.LookupError:
5072 pass
5052 pass
5073 if not filenodes:
5053 if not filenodes:
5074 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5054 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5075 p = []
5055 p = []
5076 for fn in filenodes:
5056 for fn in filenodes:
5077 fctx = repo.filectx(file_, fileid=fn)
5057 fctx = repo.filectx(file_, fileid=fn)
5078 p.append(fctx.node())
5058 p.append(fctx.node())
5079 else:
5059 else:
5080 p = [cp.node() for cp in ctx.parents()]
5060 p = [cp.node() for cp in ctx.parents()]
5081
5061
5082 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5062 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5083 for n in p:
5063 for n in p:
5084 if n != nullid:
5064 if n != nullid:
5085 displayer.show(repo[n])
5065 displayer.show(repo[n])
5086 displayer.close()
5066 displayer.close()
5087
5067
5088
5068
5089 @command(
5069 @command(
5090 b'paths',
5070 b'paths',
5091 formatteropts,
5071 formatteropts,
5092 _(b'[NAME]'),
5072 _(b'[NAME]'),
5093 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5073 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5094 optionalrepo=True,
5074 optionalrepo=True,
5095 intents={INTENT_READONLY},
5075 intents={INTENT_READONLY},
5096 )
5076 )
5097 def paths(ui, repo, search=None, **opts):
5077 def paths(ui, repo, search=None, **opts):
5098 """show aliases for remote repositories
5078 """show aliases for remote repositories
5099
5079
5100 Show definition of symbolic path name NAME. If no name is given,
5080 Show definition of symbolic path name NAME. If no name is given,
5101 show definition of all available names.
5081 show definition of all available names.
5102
5082
5103 Option -q/--quiet suppresses all output when searching for NAME
5083 Option -q/--quiet suppresses all output when searching for NAME
5104 and shows only the path names when listing all definitions.
5084 and shows only the path names when listing all definitions.
5105
5085
5106 Path names are defined in the [paths] section of your
5086 Path names are defined in the [paths] section of your
5107 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5087 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5108 repository, ``.hg/hgrc`` is used, too.
5088 repository, ``.hg/hgrc`` is used, too.
5109
5089
5110 The path names ``default`` and ``default-push`` have a special
5090 The path names ``default`` and ``default-push`` have a special
5111 meaning. When performing a push or pull operation, they are used
5091 meaning. When performing a push or pull operation, they are used
5112 as fallbacks if no location is specified on the command-line.
5092 as fallbacks if no location is specified on the command-line.
5113 When ``default-push`` is set, it will be used for push and
5093 When ``default-push`` is set, it will be used for push and
5114 ``default`` will be used for pull; otherwise ``default`` is used
5094 ``default`` will be used for pull; otherwise ``default`` is used
5115 as the fallback for both. When cloning a repository, the clone
5095 as the fallback for both. When cloning a repository, the clone
5116 source is written as ``default`` in ``.hg/hgrc``.
5096 source is written as ``default`` in ``.hg/hgrc``.
5117
5097
5118 .. note::
5098 .. note::
5119
5099
5120 ``default`` and ``default-push`` apply to all inbound (e.g.
5100 ``default`` and ``default-push`` apply to all inbound (e.g.
5121 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5101 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5122 and :hg:`bundle`) operations.
5102 and :hg:`bundle`) operations.
5123
5103
5124 See :hg:`help urls` for more information.
5104 See :hg:`help urls` for more information.
5125
5105
5126 .. container:: verbose
5106 .. container:: verbose
5127
5107
5128 Template:
5108 Template:
5129
5109
5130 The following keywords are supported. See also :hg:`help templates`.
5110 The following keywords are supported. See also :hg:`help templates`.
5131
5111
5132 :name: String. Symbolic name of the path alias.
5112 :name: String. Symbolic name of the path alias.
5133 :pushurl: String. URL for push operations.
5113 :pushurl: String. URL for push operations.
5134 :url: String. URL or directory path for the other operations.
5114 :url: String. URL or directory path for the other operations.
5135
5115
5136 Returns 0 on success.
5116 Returns 0 on success.
5137 """
5117 """
5138
5118
5139 opts = pycompat.byteskwargs(opts)
5119 opts = pycompat.byteskwargs(opts)
5140 ui.pager(b'paths')
5120 ui.pager(b'paths')
5141 if search:
5121 if search:
5142 pathitems = [
5122 pathitems = [
5143 (name, path)
5123 (name, path)
5144 for name, path in pycompat.iteritems(ui.paths)
5124 for name, path in pycompat.iteritems(ui.paths)
5145 if name == search
5125 if name == search
5146 ]
5126 ]
5147 else:
5127 else:
5148 pathitems = sorted(pycompat.iteritems(ui.paths))
5128 pathitems = sorted(pycompat.iteritems(ui.paths))
5149
5129
5150 fm = ui.formatter(b'paths', opts)
5130 fm = ui.formatter(b'paths', opts)
5151 if fm.isplain():
5131 if fm.isplain():
5152 hidepassword = util.hidepassword
5132 hidepassword = util.hidepassword
5153 else:
5133 else:
5154 hidepassword = bytes
5134 hidepassword = bytes
5155 if ui.quiet:
5135 if ui.quiet:
5156 namefmt = b'%s\n'
5136 namefmt = b'%s\n'
5157 else:
5137 else:
5158 namefmt = b'%s = '
5138 namefmt = b'%s = '
5159 showsubopts = not search and not ui.quiet
5139 showsubopts = not search and not ui.quiet
5160
5140
5161 for name, path in pathitems:
5141 for name, path in pathitems:
5162 fm.startitem()
5142 fm.startitem()
5163 fm.condwrite(not search, b'name', namefmt, name)
5143 fm.condwrite(not search, b'name', namefmt, name)
5164 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5144 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5165 for subopt, value in sorted(path.suboptions.items()):
5145 for subopt, value in sorted(path.suboptions.items()):
5166 assert subopt not in (b'name', b'url')
5146 assert subopt not in (b'name', b'url')
5167 if showsubopts:
5147 if showsubopts:
5168 fm.plain(b'%s:%s = ' % (name, subopt))
5148 fm.plain(b'%s:%s = ' % (name, subopt))
5169 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5149 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5170
5150
5171 fm.end()
5151 fm.end()
5172
5152
5173 if search and not pathitems:
5153 if search and not pathitems:
5174 if not ui.quiet:
5154 if not ui.quiet:
5175 ui.warn(_(b"not found!\n"))
5155 ui.warn(_(b"not found!\n"))
5176 return 1
5156 return 1
5177 else:
5157 else:
5178 return 0
5158 return 0
5179
5159
5180
5160
5181 @command(
5161 @command(
5182 b'phase',
5162 b'phase',
5183 [
5163 [
5184 (b'p', b'public', False, _(b'set changeset phase to public')),
5164 (b'p', b'public', False, _(b'set changeset phase to public')),
5185 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5165 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5186 (b's', b'secret', False, _(b'set changeset phase to secret')),
5166 (b's', b'secret', False, _(b'set changeset phase to secret')),
5187 (b'f', b'force', False, _(b'allow to move boundary backward')),
5167 (b'f', b'force', False, _(b'allow to move boundary backward')),
5188 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5168 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5189 ],
5169 ],
5190 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5170 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5191 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5171 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5192 )
5172 )
5193 def phase(ui, repo, *revs, **opts):
5173 def phase(ui, repo, *revs, **opts):
5194 """set or show the current phase name
5174 """set or show the current phase name
5195
5175
5196 With no argument, show the phase name of the current revision(s).
5176 With no argument, show the phase name of the current revision(s).
5197
5177
5198 With one of -p/--public, -d/--draft or -s/--secret, change the
5178 With one of -p/--public, -d/--draft or -s/--secret, change the
5199 phase value of the specified revisions.
5179 phase value of the specified revisions.
5200
5180
5201 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5181 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5202 lower phase to a higher phase. Phases are ordered as follows::
5182 lower phase to a higher phase. Phases are ordered as follows::
5203
5183
5204 public < draft < secret
5184 public < draft < secret
5205
5185
5206 Returns 0 on success, 1 if some phases could not be changed.
5186 Returns 0 on success, 1 if some phases could not be changed.
5207
5187
5208 (For more information about the phases concept, see :hg:`help phases`.)
5188 (For more information about the phases concept, see :hg:`help phases`.)
5209 """
5189 """
5210 opts = pycompat.byteskwargs(opts)
5190 opts = pycompat.byteskwargs(opts)
5211 # search for a unique phase argument
5191 # search for a unique phase argument
5212 targetphase = None
5192 targetphase = None
5213 for idx, name in enumerate(phases.cmdphasenames):
5193 for idx, name in enumerate(phases.cmdphasenames):
5214 if opts[name]:
5194 if opts[name]:
5215 if targetphase is not None:
5195 if targetphase is not None:
5216 raise error.Abort(_(b'only one phase can be specified'))
5196 raise error.Abort(_(b'only one phase can be specified'))
5217 targetphase = idx
5197 targetphase = idx
5218
5198
5219 # look for specified revision
5199 # look for specified revision
5220 revs = list(revs)
5200 revs = list(revs)
5221 revs.extend(opts[b'rev'])
5201 revs.extend(opts[b'rev'])
5222 if not revs:
5202 if not revs:
5223 # display both parents as the second parent phase can influence
5203 # display both parents as the second parent phase can influence
5224 # the phase of a merge commit
5204 # the phase of a merge commit
5225 revs = [c.rev() for c in repo[None].parents()]
5205 revs = [c.rev() for c in repo[None].parents()]
5226
5206
5227 revs = scmutil.revrange(repo, revs)
5207 revs = scmutil.revrange(repo, revs)
5228
5208
5229 ret = 0
5209 ret = 0
5230 if targetphase is None:
5210 if targetphase is None:
5231 # display
5211 # display
5232 for r in revs:
5212 for r in revs:
5233 ctx = repo[r]
5213 ctx = repo[r]
5234 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5214 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5235 else:
5215 else:
5236 with repo.lock(), repo.transaction(b"phase") as tr:
5216 with repo.lock(), repo.transaction(b"phase") as tr:
5237 # set phase
5217 # set phase
5238 if not revs:
5218 if not revs:
5239 raise error.Abort(_(b'empty revision set'))
5219 raise error.Abort(_(b'empty revision set'))
5240 nodes = [repo[r].node() for r in revs]
5220 nodes = [repo[r].node() for r in revs]
5241 # moving revision from public to draft may hide them
5221 # moving revision from public to draft may hide them
5242 # We have to check result on an unfiltered repository
5222 # We have to check result on an unfiltered repository
5243 unfi = repo.unfiltered()
5223 unfi = repo.unfiltered()
5244 getphase = unfi._phasecache.phase
5224 getphase = unfi._phasecache.phase
5245 olddata = [getphase(unfi, r) for r in unfi]
5225 olddata = [getphase(unfi, r) for r in unfi]
5246 phases.advanceboundary(repo, tr, targetphase, nodes)
5226 phases.advanceboundary(repo, tr, targetphase, nodes)
5247 if opts[b'force']:
5227 if opts[b'force']:
5248 phases.retractboundary(repo, tr, targetphase, nodes)
5228 phases.retractboundary(repo, tr, targetphase, nodes)
5249 getphase = unfi._phasecache.phase
5229 getphase = unfi._phasecache.phase
5250 newdata = [getphase(unfi, r) for r in unfi]
5230 newdata = [getphase(unfi, r) for r in unfi]
5251 changes = sum(newdata[r] != olddata[r] for r in unfi)
5231 changes = sum(newdata[r] != olddata[r] for r in unfi)
5252 cl = unfi.changelog
5232 cl = unfi.changelog
5253 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5233 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5254 if rejected:
5234 if rejected:
5255 ui.warn(
5235 ui.warn(
5256 _(
5236 _(
5257 b'cannot move %i changesets to a higher '
5237 b'cannot move %i changesets to a higher '
5258 b'phase, use --force\n'
5238 b'phase, use --force\n'
5259 )
5239 )
5260 % len(rejected)
5240 % len(rejected)
5261 )
5241 )
5262 ret = 1
5242 ret = 1
5263 if changes:
5243 if changes:
5264 msg = _(b'phase changed for %i changesets\n') % changes
5244 msg = _(b'phase changed for %i changesets\n') % changes
5265 if ret:
5245 if ret:
5266 ui.status(msg)
5246 ui.status(msg)
5267 else:
5247 else:
5268 ui.note(msg)
5248 ui.note(msg)
5269 else:
5249 else:
5270 ui.warn(_(b'no phases changed\n'))
5250 ui.warn(_(b'no phases changed\n'))
5271 return ret
5251 return ret
5272
5252
5273
5253
5274 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5254 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5275 """Run after a changegroup has been added via pull/unbundle
5255 """Run after a changegroup has been added via pull/unbundle
5276
5256
5277 This takes arguments below:
5257 This takes arguments below:
5278
5258
5279 :modheads: change of heads by pull/unbundle
5259 :modheads: change of heads by pull/unbundle
5280 :optupdate: updating working directory is needed or not
5260 :optupdate: updating working directory is needed or not
5281 :checkout: update destination revision (or None to default destination)
5261 :checkout: update destination revision (or None to default destination)
5282 :brev: a name, which might be a bookmark to be activated after updating
5262 :brev: a name, which might be a bookmark to be activated after updating
5283 """
5263 """
5284 if modheads == 0:
5264 if modheads == 0:
5285 return
5265 return
5286 if optupdate:
5266 if optupdate:
5287 try:
5267 try:
5288 return hg.updatetotally(ui, repo, checkout, brev)
5268 return hg.updatetotally(ui, repo, checkout, brev)
5289 except error.UpdateAbort as inst:
5269 except error.UpdateAbort as inst:
5290 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5270 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5291 hint = inst.hint
5271 hint = inst.hint
5292 raise error.UpdateAbort(msg, hint=hint)
5272 raise error.UpdateAbort(msg, hint=hint)
5293 if modheads is not None and modheads > 1:
5273 if modheads is not None and modheads > 1:
5294 currentbranchheads = len(repo.branchheads())
5274 currentbranchheads = len(repo.branchheads())
5295 if currentbranchheads == modheads:
5275 if currentbranchheads == modheads:
5296 ui.status(
5276 ui.status(
5297 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5277 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5298 )
5278 )
5299 elif currentbranchheads > 1:
5279 elif currentbranchheads > 1:
5300 ui.status(
5280 ui.status(
5301 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5281 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5302 )
5282 )
5303 else:
5283 else:
5304 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5284 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5305 elif not ui.configbool(b'commands', b'update.requiredest'):
5285 elif not ui.configbool(b'commands', b'update.requiredest'):
5306 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5286 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5307
5287
5308
5288
5309 @command(
5289 @command(
5310 b'pull',
5290 b'pull',
5311 [
5291 [
5312 (
5292 (
5313 b'u',
5293 b'u',
5314 b'update',
5294 b'update',
5315 None,
5295 None,
5316 _(b'update to new branch head if new descendants were pulled'),
5296 _(b'update to new branch head if new descendants were pulled'),
5317 ),
5297 ),
5318 (
5298 (
5319 b'f',
5299 b'f',
5320 b'force',
5300 b'force',
5321 None,
5301 None,
5322 _(b'run even when remote repository is unrelated'),
5302 _(b'run even when remote repository is unrelated'),
5323 ),
5303 ),
5324 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5304 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5325 (
5305 (
5326 b'r',
5306 b'r',
5327 b'rev',
5307 b'rev',
5328 [],
5308 [],
5329 _(b'a remote changeset intended to be added'),
5309 _(b'a remote changeset intended to be added'),
5330 _(b'REV'),
5310 _(b'REV'),
5331 ),
5311 ),
5332 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5312 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5333 (
5313 (
5334 b'b',
5314 b'b',
5335 b'branch',
5315 b'branch',
5336 [],
5316 [],
5337 _(b'a specific branch you would like to pull'),
5317 _(b'a specific branch you would like to pull'),
5338 _(b'BRANCH'),
5318 _(b'BRANCH'),
5339 ),
5319 ),
5340 ]
5320 ]
5341 + remoteopts,
5321 + remoteopts,
5342 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5322 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5343 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5323 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5344 helpbasic=True,
5324 helpbasic=True,
5345 )
5325 )
5346 def pull(ui, repo, source=b"default", **opts):
5326 def pull(ui, repo, source=b"default", **opts):
5347 """pull changes from the specified source
5327 """pull changes from the specified source
5348
5328
5349 Pull changes from a remote repository to a local one.
5329 Pull changes from a remote repository to a local one.
5350
5330
5351 This finds all changes from the repository at the specified path
5331 This finds all changes from the repository at the specified path
5352 or URL and adds them to a local repository (the current one unless
5332 or URL and adds them to a local repository (the current one unless
5353 -R is specified). By default, this does not update the copy of the
5333 -R is specified). By default, this does not update the copy of the
5354 project in the working directory.
5334 project in the working directory.
5355
5335
5356 When cloning from servers that support it, Mercurial may fetch
5336 When cloning from servers that support it, Mercurial may fetch
5357 pre-generated data. When this is done, hooks operating on incoming
5337 pre-generated data. When this is done, hooks operating on incoming
5358 changesets and changegroups may fire more than once, once for each
5338 changesets and changegroups may fire more than once, once for each
5359 pre-generated bundle and as well as for any additional remaining
5339 pre-generated bundle and as well as for any additional remaining
5360 data. See :hg:`help -e clonebundles` for more.
5340 data. See :hg:`help -e clonebundles` for more.
5361
5341
5362 Use :hg:`incoming` if you want to see what would have been added
5342 Use :hg:`incoming` if you want to see what would have been added
5363 by a pull at the time you issued this command. If you then decide
5343 by a pull at the time you issued this command. If you then decide
5364 to add those changes to the repository, you should use :hg:`pull
5344 to add those changes to the repository, you should use :hg:`pull
5365 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5345 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5366
5346
5367 If SOURCE is omitted, the 'default' path will be used.
5347 If SOURCE is omitted, the 'default' path will be used.
5368 See :hg:`help urls` for more information.
5348 See :hg:`help urls` for more information.
5369
5349
5370 Specifying bookmark as ``.`` is equivalent to specifying the active
5350 Specifying bookmark as ``.`` is equivalent to specifying the active
5371 bookmark's name.
5351 bookmark's name.
5372
5352
5373 Returns 0 on success, 1 if an update had unresolved files.
5353 Returns 0 on success, 1 if an update had unresolved files.
5374 """
5354 """
5375
5355
5376 opts = pycompat.byteskwargs(opts)
5356 opts = pycompat.byteskwargs(opts)
5377 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5357 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5378 b'update'
5358 b'update'
5379 ):
5359 ):
5380 msg = _(b'update destination required by configuration')
5360 msg = _(b'update destination required by configuration')
5381 hint = _(b'use hg pull followed by hg update DEST')
5361 hint = _(b'use hg pull followed by hg update DEST')
5382 raise error.Abort(msg, hint=hint)
5362 raise error.Abort(msg, hint=hint)
5383
5363
5384 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5364 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5385 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5365 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5386 other = hg.peer(repo, opts, source)
5366 other = hg.peer(repo, opts, source)
5387 try:
5367 try:
5388 revs, checkout = hg.addbranchrevs(
5368 revs, checkout = hg.addbranchrevs(
5389 repo, other, branches, opts.get(b'rev')
5369 repo, other, branches, opts.get(b'rev')
5390 )
5370 )
5391
5371
5392 pullopargs = {}
5372 pullopargs = {}
5393
5373
5394 nodes = None
5374 nodes = None
5395 if opts.get(b'bookmark') or revs:
5375 if opts.get(b'bookmark') or revs:
5396 # The list of bookmark used here is the same used to actually update
5376 # The list of bookmark used here is the same used to actually update
5397 # the bookmark names, to avoid the race from issue 4689 and we do
5377 # the bookmark names, to avoid the race from issue 4689 and we do
5398 # all lookup and bookmark queries in one go so they see the same
5378 # all lookup and bookmark queries in one go so they see the same
5399 # version of the server state (issue 4700).
5379 # version of the server state (issue 4700).
5400 nodes = []
5380 nodes = []
5401 fnodes = []
5381 fnodes = []
5402 revs = revs or []
5382 revs = revs or []
5403 if revs and not other.capable(b'lookup'):
5383 if revs and not other.capable(b'lookup'):
5404 err = _(
5384 err = _(
5405 b"other repository doesn't support revision lookup, "
5385 b"other repository doesn't support revision lookup, "
5406 b"so a rev cannot be specified."
5386 b"so a rev cannot be specified."
5407 )
5387 )
5408 raise error.Abort(err)
5388 raise error.Abort(err)
5409 with other.commandexecutor() as e:
5389 with other.commandexecutor() as e:
5410 fremotebookmarks = e.callcommand(
5390 fremotebookmarks = e.callcommand(
5411 b'listkeys', {b'namespace': b'bookmarks'}
5391 b'listkeys', {b'namespace': b'bookmarks'}
5412 )
5392 )
5413 for r in revs:
5393 for r in revs:
5414 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5394 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5415 remotebookmarks = fremotebookmarks.result()
5395 remotebookmarks = fremotebookmarks.result()
5416 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5396 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5417 pullopargs[b'remotebookmarks'] = remotebookmarks
5397 pullopargs[b'remotebookmarks'] = remotebookmarks
5418 for b in opts.get(b'bookmark', []):
5398 for b in opts.get(b'bookmark', []):
5419 b = repo._bookmarks.expandname(b)
5399 b = repo._bookmarks.expandname(b)
5420 if b not in remotebookmarks:
5400 if b not in remotebookmarks:
5421 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5401 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5422 nodes.append(remotebookmarks[b])
5402 nodes.append(remotebookmarks[b])
5423 for i, rev in enumerate(revs):
5403 for i, rev in enumerate(revs):
5424 node = fnodes[i].result()
5404 node = fnodes[i].result()
5425 nodes.append(node)
5405 nodes.append(node)
5426 if rev == checkout:
5406 if rev == checkout:
5427 checkout = node
5407 checkout = node
5428
5408
5429 wlock = util.nullcontextmanager()
5409 wlock = util.nullcontextmanager()
5430 if opts.get(b'update'):
5410 if opts.get(b'update'):
5431 wlock = repo.wlock()
5411 wlock = repo.wlock()
5432 with wlock:
5412 with wlock:
5433 pullopargs.update(opts.get(b'opargs', {}))
5413 pullopargs.update(opts.get(b'opargs', {}))
5434 modheads = exchange.pull(
5414 modheads = exchange.pull(
5435 repo,
5415 repo,
5436 other,
5416 other,
5437 heads=nodes,
5417 heads=nodes,
5438 force=opts.get(b'force'),
5418 force=opts.get(b'force'),
5439 bookmarks=opts.get(b'bookmark', ()),
5419 bookmarks=opts.get(b'bookmark', ()),
5440 opargs=pullopargs,
5420 opargs=pullopargs,
5441 confirm=opts.get(b'confirm'),
5421 confirm=opts.get(b'confirm'),
5442 ).cgresult
5422 ).cgresult
5443
5423
5444 # brev is a name, which might be a bookmark to be activated at
5424 # brev is a name, which might be a bookmark to be activated at
5445 # the end of the update. In other words, it is an explicit
5425 # the end of the update. In other words, it is an explicit
5446 # destination of the update
5426 # destination of the update
5447 brev = None
5427 brev = None
5448
5428
5449 if checkout:
5429 if checkout:
5450 checkout = repo.unfiltered().changelog.rev(checkout)
5430 checkout = repo.unfiltered().changelog.rev(checkout)
5451
5431
5452 # order below depends on implementation of
5432 # order below depends on implementation of
5453 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5433 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5454 # because 'checkout' is determined without it.
5434 # because 'checkout' is determined without it.
5455 if opts.get(b'rev'):
5435 if opts.get(b'rev'):
5456 brev = opts[b'rev'][0]
5436 brev = opts[b'rev'][0]
5457 elif opts.get(b'branch'):
5437 elif opts.get(b'branch'):
5458 brev = opts[b'branch'][0]
5438 brev = opts[b'branch'][0]
5459 else:
5439 else:
5460 brev = branches[0]
5440 brev = branches[0]
5461 repo._subtoppath = source
5441 repo._subtoppath = source
5462 try:
5442 try:
5463 ret = postincoming(
5443 ret = postincoming(
5464 ui, repo, modheads, opts.get(b'update'), checkout, brev
5444 ui, repo, modheads, opts.get(b'update'), checkout, brev
5465 )
5445 )
5466 except error.FilteredRepoLookupError as exc:
5446 except error.FilteredRepoLookupError as exc:
5467 msg = _(b'cannot update to target: %s') % exc.args[0]
5447 msg = _(b'cannot update to target: %s') % exc.args[0]
5468 exc.args = (msg,) + exc.args[1:]
5448 exc.args = (msg,) + exc.args[1:]
5469 raise
5449 raise
5470 finally:
5450 finally:
5471 del repo._subtoppath
5451 del repo._subtoppath
5472
5452
5473 finally:
5453 finally:
5474 other.close()
5454 other.close()
5475 return ret
5455 return ret
5476
5456
5477
5457
5478 @command(
5458 @command(
5479 b'push',
5459 b'push',
5480 [
5460 [
5481 (b'f', b'force', None, _(b'force push')),
5461 (b'f', b'force', None, _(b'force push')),
5482 (
5462 (
5483 b'r',
5463 b'r',
5484 b'rev',
5464 b'rev',
5485 [],
5465 [],
5486 _(b'a changeset intended to be included in the destination'),
5466 _(b'a changeset intended to be included in the destination'),
5487 _(b'REV'),
5467 _(b'REV'),
5488 ),
5468 ),
5489 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5469 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5490 (
5470 (
5491 b'b',
5471 b'b',
5492 b'branch',
5472 b'branch',
5493 [],
5473 [],
5494 _(b'a specific branch you would like to push'),
5474 _(b'a specific branch you would like to push'),
5495 _(b'BRANCH'),
5475 _(b'BRANCH'),
5496 ),
5476 ),
5497 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5477 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5498 (
5478 (
5499 b'',
5479 b'',
5500 b'pushvars',
5480 b'pushvars',
5501 [],
5481 [],
5502 _(b'variables that can be sent to server (ADVANCED)'),
5482 _(b'variables that can be sent to server (ADVANCED)'),
5503 ),
5483 ),
5504 (
5484 (
5505 b'',
5485 b'',
5506 b'publish',
5486 b'publish',
5507 False,
5487 False,
5508 _(b'push the changeset as public (EXPERIMENTAL)'),
5488 _(b'push the changeset as public (EXPERIMENTAL)'),
5509 ),
5489 ),
5510 ]
5490 ]
5511 + remoteopts,
5491 + remoteopts,
5512 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5492 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5513 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5493 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5514 helpbasic=True,
5494 helpbasic=True,
5515 )
5495 )
5516 def push(ui, repo, dest=None, **opts):
5496 def push(ui, repo, dest=None, **opts):
5517 """push changes to the specified destination
5497 """push changes to the specified destination
5518
5498
5519 Push changesets from the local repository to the specified
5499 Push changesets from the local repository to the specified
5520 destination.
5500 destination.
5521
5501
5522 This operation is symmetrical to pull: it is identical to a pull
5502 This operation is symmetrical to pull: it is identical to a pull
5523 in the destination repository from the current one.
5503 in the destination repository from the current one.
5524
5504
5525 By default, push will not allow creation of new heads at the
5505 By default, push will not allow creation of new heads at the
5526 destination, since multiple heads would make it unclear which head
5506 destination, since multiple heads would make it unclear which head
5527 to use. In this situation, it is recommended to pull and merge
5507 to use. In this situation, it is recommended to pull and merge
5528 before pushing.
5508 before pushing.
5529
5509
5530 Use --new-branch if you want to allow push to create a new named
5510 Use --new-branch if you want to allow push to create a new named
5531 branch that is not present at the destination. This allows you to
5511 branch that is not present at the destination. This allows you to
5532 only create a new branch without forcing other changes.
5512 only create a new branch without forcing other changes.
5533
5513
5534 .. note::
5514 .. note::
5535
5515
5536 Extra care should be taken with the -f/--force option,
5516 Extra care should be taken with the -f/--force option,
5537 which will push all new heads on all branches, an action which will
5517 which will push all new heads on all branches, an action which will
5538 almost always cause confusion for collaborators.
5518 almost always cause confusion for collaborators.
5539
5519
5540 If -r/--rev is used, the specified revision and all its ancestors
5520 If -r/--rev is used, the specified revision and all its ancestors
5541 will be pushed to the remote repository.
5521 will be pushed to the remote repository.
5542
5522
5543 If -B/--bookmark is used, the specified bookmarked revision, its
5523 If -B/--bookmark is used, the specified bookmarked revision, its
5544 ancestors, and the bookmark will be pushed to the remote
5524 ancestors, and the bookmark will be pushed to the remote
5545 repository. Specifying ``.`` is equivalent to specifying the active
5525 repository. Specifying ``.`` is equivalent to specifying the active
5546 bookmark's name.
5526 bookmark's name.
5547
5527
5548 Please see :hg:`help urls` for important details about ``ssh://``
5528 Please see :hg:`help urls` for important details about ``ssh://``
5549 URLs. If DESTINATION is omitted, a default path will be used.
5529 URLs. If DESTINATION is omitted, a default path will be used.
5550
5530
5551 .. container:: verbose
5531 .. container:: verbose
5552
5532
5553 The --pushvars option sends strings to the server that become
5533 The --pushvars option sends strings to the server that become
5554 environment variables prepended with ``HG_USERVAR_``. For example,
5534 environment variables prepended with ``HG_USERVAR_``. For example,
5555 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5535 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5556 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5536 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5557
5537
5558 pushvars can provide for user-overridable hooks as well as set debug
5538 pushvars can provide for user-overridable hooks as well as set debug
5559 levels. One example is having a hook that blocks commits containing
5539 levels. One example is having a hook that blocks commits containing
5560 conflict markers, but enables the user to override the hook if the file
5540 conflict markers, but enables the user to override the hook if the file
5561 is using conflict markers for testing purposes or the file format has
5541 is using conflict markers for testing purposes or the file format has
5562 strings that look like conflict markers.
5542 strings that look like conflict markers.
5563
5543
5564 By default, servers will ignore `--pushvars`. To enable it add the
5544 By default, servers will ignore `--pushvars`. To enable it add the
5565 following to your configuration file::
5545 following to your configuration file::
5566
5546
5567 [push]
5547 [push]
5568 pushvars.server = true
5548 pushvars.server = true
5569
5549
5570 Returns 0 if push was successful, 1 if nothing to push.
5550 Returns 0 if push was successful, 1 if nothing to push.
5571 """
5551 """
5572
5552
5573 opts = pycompat.byteskwargs(opts)
5553 opts = pycompat.byteskwargs(opts)
5574 if opts.get(b'bookmark'):
5554 if opts.get(b'bookmark'):
5575 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5555 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5576 for b in opts[b'bookmark']:
5556 for b in opts[b'bookmark']:
5577 # translate -B options to -r so changesets get pushed
5557 # translate -B options to -r so changesets get pushed
5578 b = repo._bookmarks.expandname(b)
5558 b = repo._bookmarks.expandname(b)
5579 if b in repo._bookmarks:
5559 if b in repo._bookmarks:
5580 opts.setdefault(b'rev', []).append(b)
5560 opts.setdefault(b'rev', []).append(b)
5581 else:
5561 else:
5582 # if we try to push a deleted bookmark, translate it to null
5562 # if we try to push a deleted bookmark, translate it to null
5583 # this lets simultaneous -r, -b options continue working
5563 # this lets simultaneous -r, -b options continue working
5584 opts.setdefault(b'rev', []).append(b"null")
5564 opts.setdefault(b'rev', []).append(b"null")
5585
5565
5586 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5566 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5587 if not path:
5567 if not path:
5588 raise error.Abort(
5568 raise error.Abort(
5589 _(b'default repository not configured!'),
5569 _(b'default repository not configured!'),
5590 hint=_(b"see 'hg help config.paths'"),
5570 hint=_(b"see 'hg help config.paths'"),
5591 )
5571 )
5592 dest = path.pushloc or path.loc
5572 dest = path.pushloc or path.loc
5593 branches = (path.branch, opts.get(b'branch') or [])
5573 branches = (path.branch, opts.get(b'branch') or [])
5594 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5574 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5595 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5575 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5596 other = hg.peer(repo, opts, dest)
5576 other = hg.peer(repo, opts, dest)
5597
5577
5598 if revs:
5578 if revs:
5599 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5579 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5600 if not revs:
5580 if not revs:
5601 raise error.Abort(
5581 raise error.Abort(
5602 _(b"specified revisions evaluate to an empty set"),
5582 _(b"specified revisions evaluate to an empty set"),
5603 hint=_(b"use different revision arguments"),
5583 hint=_(b"use different revision arguments"),
5604 )
5584 )
5605 elif path.pushrev:
5585 elif path.pushrev:
5606 # It doesn't make any sense to specify ancestor revisions. So limit
5586 # It doesn't make any sense to specify ancestor revisions. So limit
5607 # to DAG heads to make discovery simpler.
5587 # to DAG heads to make discovery simpler.
5608 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5588 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5609 revs = scmutil.revrange(repo, [expr])
5589 revs = scmutil.revrange(repo, [expr])
5610 revs = [repo[rev].node() for rev in revs]
5590 revs = [repo[rev].node() for rev in revs]
5611 if not revs:
5591 if not revs:
5612 raise error.Abort(
5592 raise error.Abort(
5613 _(b'default push revset for path evaluates to an empty set')
5593 _(b'default push revset for path evaluates to an empty set')
5614 )
5594 )
5615 elif ui.configbool(b'commands', b'push.require-revs'):
5595 elif ui.configbool(b'commands', b'push.require-revs'):
5616 raise error.Abort(
5596 raise error.Abort(
5617 _(b'no revisions specified to push'),
5597 _(b'no revisions specified to push'),
5618 hint=_(b'did you mean "hg push -r ."?'),
5598 hint=_(b'did you mean "hg push -r ."?'),
5619 )
5599 )
5620
5600
5621 repo._subtoppath = dest
5601 repo._subtoppath = dest
5622 try:
5602 try:
5623 # push subrepos depth-first for coherent ordering
5603 # push subrepos depth-first for coherent ordering
5624 c = repo[b'.']
5604 c = repo[b'.']
5625 subs = c.substate # only repos that are committed
5605 subs = c.substate # only repos that are committed
5626 for s in sorted(subs):
5606 for s in sorted(subs):
5627 result = c.sub(s).push(opts)
5607 result = c.sub(s).push(opts)
5628 if result == 0:
5608 if result == 0:
5629 return not result
5609 return not result
5630 finally:
5610 finally:
5631 del repo._subtoppath
5611 del repo._subtoppath
5632
5612
5633 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5613 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5634 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5614 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5635
5615
5636 pushop = exchange.push(
5616 pushop = exchange.push(
5637 repo,
5617 repo,
5638 other,
5618 other,
5639 opts.get(b'force'),
5619 opts.get(b'force'),
5640 revs=revs,
5620 revs=revs,
5641 newbranch=opts.get(b'new_branch'),
5621 newbranch=opts.get(b'new_branch'),
5642 bookmarks=opts.get(b'bookmark', ()),
5622 bookmarks=opts.get(b'bookmark', ()),
5643 publish=opts.get(b'publish'),
5623 publish=opts.get(b'publish'),
5644 opargs=opargs,
5624 opargs=opargs,
5645 )
5625 )
5646
5626
5647 result = not pushop.cgresult
5627 result = not pushop.cgresult
5648
5628
5649 if pushop.bkresult is not None:
5629 if pushop.bkresult is not None:
5650 if pushop.bkresult == 2:
5630 if pushop.bkresult == 2:
5651 result = 2
5631 result = 2
5652 elif not result and pushop.bkresult:
5632 elif not result and pushop.bkresult:
5653 result = 2
5633 result = 2
5654
5634
5655 return result
5635 return result
5656
5636
5657
5637
5658 @command(
5638 @command(
5659 b'recover',
5639 b'recover',
5660 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5640 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5661 helpcategory=command.CATEGORY_MAINTENANCE,
5641 helpcategory=command.CATEGORY_MAINTENANCE,
5662 )
5642 )
5663 def recover(ui, repo, **opts):
5643 def recover(ui, repo, **opts):
5664 """roll back an interrupted transaction
5644 """roll back an interrupted transaction
5665
5645
5666 Recover from an interrupted commit or pull.
5646 Recover from an interrupted commit or pull.
5667
5647
5668 This command tries to fix the repository status after an
5648 This command tries to fix the repository status after an
5669 interrupted operation. It should only be necessary when Mercurial
5649 interrupted operation. It should only be necessary when Mercurial
5670 suggests it.
5650 suggests it.
5671
5651
5672 Returns 0 if successful, 1 if nothing to recover or verify fails.
5652 Returns 0 if successful, 1 if nothing to recover or verify fails.
5673 """
5653 """
5674 ret = repo.recover()
5654 ret = repo.recover()
5675 if ret:
5655 if ret:
5676 if opts['verify']:
5656 if opts['verify']:
5677 return hg.verify(repo)
5657 return hg.verify(repo)
5678 else:
5658 else:
5679 msg = _(
5659 msg = _(
5680 b"(verify step skipped, run `hg verify` to check your "
5660 b"(verify step skipped, run `hg verify` to check your "
5681 b"repository content)\n"
5661 b"repository content)\n"
5682 )
5662 )
5683 ui.warn(msg)
5663 ui.warn(msg)
5684 return 0
5664 return 0
5685 return 1
5665 return 1
5686
5666
5687
5667
5688 @command(
5668 @command(
5689 b'remove|rm',
5669 b'remove|rm',
5690 [
5670 [
5691 (b'A', b'after', None, _(b'record delete for missing files')),
5671 (b'A', b'after', None, _(b'record delete for missing files')),
5692 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5672 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5693 ]
5673 ]
5694 + subrepoopts
5674 + subrepoopts
5695 + walkopts
5675 + walkopts
5696 + dryrunopts,
5676 + dryrunopts,
5697 _(b'[OPTION]... FILE...'),
5677 _(b'[OPTION]... FILE...'),
5698 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5678 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5699 helpbasic=True,
5679 helpbasic=True,
5700 inferrepo=True,
5680 inferrepo=True,
5701 )
5681 )
5702 def remove(ui, repo, *pats, **opts):
5682 def remove(ui, repo, *pats, **opts):
5703 """remove the specified files on the next commit
5683 """remove the specified files on the next commit
5704
5684
5705 Schedule the indicated files for removal from the current branch.
5685 Schedule the indicated files for removal from the current branch.
5706
5686
5707 This command schedules the files to be removed at the next commit.
5687 This command schedules the files to be removed at the next commit.
5708 To undo a remove before that, see :hg:`revert`. To undo added
5688 To undo a remove before that, see :hg:`revert`. To undo added
5709 files, see :hg:`forget`.
5689 files, see :hg:`forget`.
5710
5690
5711 .. container:: verbose
5691 .. container:: verbose
5712
5692
5713 -A/--after can be used to remove only files that have already
5693 -A/--after can be used to remove only files that have already
5714 been deleted, -f/--force can be used to force deletion, and -Af
5694 been deleted, -f/--force can be used to force deletion, and -Af
5715 can be used to remove files from the next revision without
5695 can be used to remove files from the next revision without
5716 deleting them from the working directory.
5696 deleting them from the working directory.
5717
5697
5718 The following table details the behavior of remove for different
5698 The following table details the behavior of remove for different
5719 file states (columns) and option combinations (rows). The file
5699 file states (columns) and option combinations (rows). The file
5720 states are Added [A], Clean [C], Modified [M] and Missing [!]
5700 states are Added [A], Clean [C], Modified [M] and Missing [!]
5721 (as reported by :hg:`status`). The actions are Warn, Remove
5701 (as reported by :hg:`status`). The actions are Warn, Remove
5722 (from branch) and Delete (from disk):
5702 (from branch) and Delete (from disk):
5723
5703
5724 ========= == == == ==
5704 ========= == == == ==
5725 opt/state A C M !
5705 opt/state A C M !
5726 ========= == == == ==
5706 ========= == == == ==
5727 none W RD W R
5707 none W RD W R
5728 -f R RD RD R
5708 -f R RD RD R
5729 -A W W W R
5709 -A W W W R
5730 -Af R R R R
5710 -Af R R R R
5731 ========= == == == ==
5711 ========= == == == ==
5732
5712
5733 .. note::
5713 .. note::
5734
5714
5735 :hg:`remove` never deletes files in Added [A] state from the
5715 :hg:`remove` never deletes files in Added [A] state from the
5736 working directory, not even if ``--force`` is specified.
5716 working directory, not even if ``--force`` is specified.
5737
5717
5738 Returns 0 on success, 1 if any warnings encountered.
5718 Returns 0 on success, 1 if any warnings encountered.
5739 """
5719 """
5740
5720
5741 opts = pycompat.byteskwargs(opts)
5721 opts = pycompat.byteskwargs(opts)
5742 after, force = opts.get(b'after'), opts.get(b'force')
5722 after, force = opts.get(b'after'), opts.get(b'force')
5743 dryrun = opts.get(b'dry_run')
5723 dryrun = opts.get(b'dry_run')
5744 if not pats and not after:
5724 if not pats and not after:
5745 raise error.Abort(_(b'no files specified'))
5725 raise error.Abort(_(b'no files specified'))
5746
5726
5747 m = scmutil.match(repo[None], pats, opts)
5727 m = scmutil.match(repo[None], pats, opts)
5748 subrepos = opts.get(b'subrepos')
5728 subrepos = opts.get(b'subrepos')
5749 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5729 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5750 return cmdutil.remove(
5730 return cmdutil.remove(
5751 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5731 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5752 )
5732 )
5753
5733
5754
5734
5755 @command(
5735 @command(
5756 b'rename|move|mv',
5736 b'rename|move|mv',
5757 [
5737 [
5758 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5738 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5759 (
5739 (
5760 b'',
5740 b'',
5761 b'at-rev',
5741 b'at-rev',
5762 b'',
5742 b'',
5763 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5743 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5764 _(b'REV'),
5744 _(b'REV'),
5765 ),
5745 ),
5766 (
5746 (
5767 b'f',
5747 b'f',
5768 b'force',
5748 b'force',
5769 None,
5749 None,
5770 _(b'forcibly move over an existing managed file'),
5750 _(b'forcibly move over an existing managed file'),
5771 ),
5751 ),
5772 ]
5752 ]
5773 + walkopts
5753 + walkopts
5774 + dryrunopts,
5754 + dryrunopts,
5775 _(b'[OPTION]... SOURCE... DEST'),
5755 _(b'[OPTION]... SOURCE... DEST'),
5776 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5756 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5777 )
5757 )
5778 def rename(ui, repo, *pats, **opts):
5758 def rename(ui, repo, *pats, **opts):
5779 """rename files; equivalent of copy + remove
5759 """rename files; equivalent of copy + remove
5780
5760
5781 Mark dest as copies of sources; mark sources for deletion. If dest
5761 Mark dest as copies of sources; mark sources for deletion. If dest
5782 is a directory, copies are put in that directory. If dest is a
5762 is a directory, copies are put in that directory. If dest is a
5783 file, there can only be one source.
5763 file, there can only be one source.
5784
5764
5785 By default, this command copies the contents of files as they
5765 By default, this command copies the contents of files as they
5786 exist in the working directory. If invoked with -A/--after, the
5766 exist in the working directory. If invoked with -A/--after, the
5787 operation is recorded, but no copying is performed.
5767 operation is recorded, but no copying is performed.
5788
5768
5789 This command takes effect at the next commit. To undo a rename
5769 This command takes effect at the next commit. To undo a rename
5790 before that, see :hg:`revert`.
5770 before that, see :hg:`revert`.
5791
5771
5792 Returns 0 on success, 1 if errors are encountered.
5772 Returns 0 on success, 1 if errors are encountered.
5793 """
5773 """
5794 opts = pycompat.byteskwargs(opts)
5774 opts = pycompat.byteskwargs(opts)
5795 with repo.wlock():
5775 with repo.wlock():
5796 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5776 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5797
5777
5798
5778
5799 @command(
5779 @command(
5800 b'resolve',
5780 b'resolve',
5801 [
5781 [
5802 (b'a', b'all', None, _(b'select all unresolved files')),
5782 (b'a', b'all', None, _(b'select all unresolved files')),
5803 (b'l', b'list', None, _(b'list state of files needing merge')),
5783 (b'l', b'list', None, _(b'list state of files needing merge')),
5804 (b'm', b'mark', None, _(b'mark files as resolved')),
5784 (b'm', b'mark', None, _(b'mark files as resolved')),
5805 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5785 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5806 (b'n', b'no-status', None, _(b'hide status prefix')),
5786 (b'n', b'no-status', None, _(b'hide status prefix')),
5807 (b'', b're-merge', None, _(b're-merge files')),
5787 (b'', b're-merge', None, _(b're-merge files')),
5808 ]
5788 ]
5809 + mergetoolopts
5789 + mergetoolopts
5810 + walkopts
5790 + walkopts
5811 + formatteropts,
5791 + formatteropts,
5812 _(b'[OPTION]... [FILE]...'),
5792 _(b'[OPTION]... [FILE]...'),
5813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5793 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5814 inferrepo=True,
5794 inferrepo=True,
5815 )
5795 )
5816 def resolve(ui, repo, *pats, **opts):
5796 def resolve(ui, repo, *pats, **opts):
5817 """redo merges or set/view the merge status of files
5797 """redo merges or set/view the merge status of files
5818
5798
5819 Merges with unresolved conflicts are often the result of
5799 Merges with unresolved conflicts are often the result of
5820 non-interactive merging using the ``internal:merge`` configuration
5800 non-interactive merging using the ``internal:merge`` configuration
5821 setting, or a command-line merge tool like ``diff3``. The resolve
5801 setting, or a command-line merge tool like ``diff3``. The resolve
5822 command is used to manage the files involved in a merge, after
5802 command is used to manage the files involved in a merge, after
5823 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5803 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5824 working directory must have two parents). See :hg:`help
5804 working directory must have two parents). See :hg:`help
5825 merge-tools` for information on configuring merge tools.
5805 merge-tools` for information on configuring merge tools.
5826
5806
5827 The resolve command can be used in the following ways:
5807 The resolve command can be used in the following ways:
5828
5808
5829 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5809 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5830 the specified files, discarding any previous merge attempts. Re-merging
5810 the specified files, discarding any previous merge attempts. Re-merging
5831 is not performed for files already marked as resolved. Use ``--all/-a``
5811 is not performed for files already marked as resolved. Use ``--all/-a``
5832 to select all unresolved files. ``--tool`` can be used to specify
5812 to select all unresolved files. ``--tool`` can be used to specify
5833 the merge tool used for the given files. It overrides the HGMERGE
5813 the merge tool used for the given files. It overrides the HGMERGE
5834 environment variable and your configuration files. Previous file
5814 environment variable and your configuration files. Previous file
5835 contents are saved with a ``.orig`` suffix.
5815 contents are saved with a ``.orig`` suffix.
5836
5816
5837 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5817 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5838 (e.g. after having manually fixed-up the files). The default is
5818 (e.g. after having manually fixed-up the files). The default is
5839 to mark all unresolved files.
5819 to mark all unresolved files.
5840
5820
5841 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5821 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5842 default is to mark all resolved files.
5822 default is to mark all resolved files.
5843
5823
5844 - :hg:`resolve -l`: list files which had or still have conflicts.
5824 - :hg:`resolve -l`: list files which had or still have conflicts.
5845 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5825 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5846 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5826 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5847 the list. See :hg:`help filesets` for details.
5827 the list. See :hg:`help filesets` for details.
5848
5828
5849 .. note::
5829 .. note::
5850
5830
5851 Mercurial will not let you commit files with unresolved merge
5831 Mercurial will not let you commit files with unresolved merge
5852 conflicts. You must use :hg:`resolve -m ...` before you can
5832 conflicts. You must use :hg:`resolve -m ...` before you can
5853 commit after a conflicting merge.
5833 commit after a conflicting merge.
5854
5834
5855 .. container:: verbose
5835 .. container:: verbose
5856
5836
5857 Template:
5837 Template:
5858
5838
5859 The following keywords are supported in addition to the common template
5839 The following keywords are supported in addition to the common template
5860 keywords and functions. See also :hg:`help templates`.
5840 keywords and functions. See also :hg:`help templates`.
5861
5841
5862 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5842 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5863 :path: String. Repository-absolute path of the file.
5843 :path: String. Repository-absolute path of the file.
5864
5844
5865 Returns 0 on success, 1 if any files fail a resolve attempt.
5845 Returns 0 on success, 1 if any files fail a resolve attempt.
5866 """
5846 """
5867
5847
5868 opts = pycompat.byteskwargs(opts)
5848 opts = pycompat.byteskwargs(opts)
5869 confirm = ui.configbool(b'commands', b'resolve.confirm')
5849 confirm = ui.configbool(b'commands', b'resolve.confirm')
5870 flaglist = b'all mark unmark list no_status re_merge'.split()
5850 flaglist = b'all mark unmark list no_status re_merge'.split()
5871 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5851 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5872
5852
5873 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5853 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5874 if actioncount > 1:
5854 if actioncount > 1:
5875 raise error.Abort(_(b"too many actions specified"))
5855 raise error.Abort(_(b"too many actions specified"))
5876 elif actioncount == 0 and ui.configbool(
5856 elif actioncount == 0 and ui.configbool(
5877 b'commands', b'resolve.explicit-re-merge'
5857 b'commands', b'resolve.explicit-re-merge'
5878 ):
5858 ):
5879 hint = _(b'use --mark, --unmark, --list or --re-merge')
5859 hint = _(b'use --mark, --unmark, --list or --re-merge')
5880 raise error.Abort(_(b'no action specified'), hint=hint)
5860 raise error.Abort(_(b'no action specified'), hint=hint)
5881 if pats and all:
5861 if pats and all:
5882 raise error.Abort(_(b"can't specify --all and patterns"))
5862 raise error.Abort(_(b"can't specify --all and patterns"))
5883 if not (all or pats or show or mark or unmark):
5863 if not (all or pats or show or mark or unmark):
5884 raise error.Abort(
5864 raise error.Abort(
5885 _(b'no files or directories specified'),
5865 _(b'no files or directories specified'),
5886 hint=b'use --all to re-merge all unresolved files',
5866 hint=b'use --all to re-merge all unresolved files',
5887 )
5867 )
5888
5868
5889 if confirm:
5869 if confirm:
5890 if all:
5870 if all:
5891 if ui.promptchoice(
5871 if ui.promptchoice(
5892 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5872 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5893 ):
5873 ):
5894 raise error.Abort(_(b'user quit'))
5874 raise error.Abort(_(b'user quit'))
5895 if mark and not pats:
5875 if mark and not pats:
5896 if ui.promptchoice(
5876 if ui.promptchoice(
5897 _(
5877 _(
5898 b'mark all unresolved files as resolved (yn)?'
5878 b'mark all unresolved files as resolved (yn)?'
5899 b'$$ &Yes $$ &No'
5879 b'$$ &Yes $$ &No'
5900 )
5880 )
5901 ):
5881 ):
5902 raise error.Abort(_(b'user quit'))
5882 raise error.Abort(_(b'user quit'))
5903 if unmark and not pats:
5883 if unmark and not pats:
5904 if ui.promptchoice(
5884 if ui.promptchoice(
5905 _(
5885 _(
5906 b'mark all resolved files as unresolved (yn)?'
5886 b'mark all resolved files as unresolved (yn)?'
5907 b'$$ &Yes $$ &No'
5887 b'$$ &Yes $$ &No'
5908 )
5888 )
5909 ):
5889 ):
5910 raise error.Abort(_(b'user quit'))
5890 raise error.Abort(_(b'user quit'))
5911
5891
5912 uipathfn = scmutil.getuipathfn(repo)
5892 uipathfn = scmutil.getuipathfn(repo)
5913
5893
5914 if show:
5894 if show:
5915 ui.pager(b'resolve')
5895 ui.pager(b'resolve')
5916 fm = ui.formatter(b'resolve', opts)
5896 fm = ui.formatter(b'resolve', opts)
5917 ms = mergestatemod.mergestate.read(repo)
5897 ms = mergestatemod.mergestate.read(repo)
5918 wctx = repo[None]
5898 wctx = repo[None]
5919 m = scmutil.match(wctx, pats, opts)
5899 m = scmutil.match(wctx, pats, opts)
5920
5900
5921 # Labels and keys based on merge state. Unresolved path conflicts show
5901 # Labels and keys based on merge state. Unresolved path conflicts show
5922 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5902 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5923 # resolved conflicts.
5903 # resolved conflicts.
5924 mergestateinfo = {
5904 mergestateinfo = {
5925 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5905 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5926 b'resolve.unresolved',
5906 b'resolve.unresolved',
5927 b'U',
5907 b'U',
5928 ),
5908 ),
5929 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5909 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5930 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5910 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5931 b'resolve.unresolved',
5911 b'resolve.unresolved',
5932 b'P',
5912 b'P',
5933 ),
5913 ),
5934 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5914 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5935 b'resolve.resolved',
5915 b'resolve.resolved',
5936 b'R',
5916 b'R',
5937 ),
5917 ),
5938 }
5918 }
5939
5919
5940 for f in ms:
5920 for f in ms:
5941 if not m(f):
5921 if not m(f):
5942 continue
5922 continue
5943
5923
5944 label, key = mergestateinfo[ms[f]]
5924 label, key = mergestateinfo[ms[f]]
5945 fm.startitem()
5925 fm.startitem()
5946 fm.context(ctx=wctx)
5926 fm.context(ctx=wctx)
5947 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5927 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5948 fm.data(path=f)
5928 fm.data(path=f)
5949 fm.plain(b'%s\n' % uipathfn(f), label=label)
5929 fm.plain(b'%s\n' % uipathfn(f), label=label)
5950 fm.end()
5930 fm.end()
5951 return 0
5931 return 0
5952
5932
5953 with repo.wlock():
5933 with repo.wlock():
5954 ms = mergestatemod.mergestate.read(repo)
5934 ms = mergestatemod.mergestate.read(repo)
5955
5935
5956 if not (ms.active() or repo.dirstate.p2() != nullid):
5936 if not (ms.active() or repo.dirstate.p2() != nullid):
5957 raise error.Abort(
5937 raise error.Abort(
5958 _(b'resolve command not applicable when not merging')
5938 _(b'resolve command not applicable when not merging')
5959 )
5939 )
5960
5940
5961 wctx = repo[None]
5941 wctx = repo[None]
5962 m = scmutil.match(wctx, pats, opts)
5942 m = scmutil.match(wctx, pats, opts)
5963 ret = 0
5943 ret = 0
5964 didwork = False
5944 didwork = False
5965
5945
5966 tocomplete = []
5946 tocomplete = []
5967 hasconflictmarkers = []
5947 hasconflictmarkers = []
5968 if mark:
5948 if mark:
5969 markcheck = ui.config(b'commands', b'resolve.mark-check')
5949 markcheck = ui.config(b'commands', b'resolve.mark-check')
5970 if markcheck not in [b'warn', b'abort']:
5950 if markcheck not in [b'warn', b'abort']:
5971 # Treat all invalid / unrecognized values as 'none'.
5951 # Treat all invalid / unrecognized values as 'none'.
5972 markcheck = False
5952 markcheck = False
5973 for f in ms:
5953 for f in ms:
5974 if not m(f):
5954 if not m(f):
5975 continue
5955 continue
5976
5956
5977 didwork = True
5957 didwork = True
5978
5958
5979 # path conflicts must be resolved manually
5959 # path conflicts must be resolved manually
5980 if ms[f] in (
5960 if ms[f] in (
5981 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5961 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5982 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5962 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5983 ):
5963 ):
5984 if mark:
5964 if mark:
5985 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5965 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5986 elif unmark:
5966 elif unmark:
5987 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5967 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5988 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5968 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5989 ui.warn(
5969 ui.warn(
5990 _(b'%s: path conflict must be resolved manually\n')
5970 _(b'%s: path conflict must be resolved manually\n')
5991 % uipathfn(f)
5971 % uipathfn(f)
5992 )
5972 )
5993 continue
5973 continue
5994
5974
5995 if mark:
5975 if mark:
5996 if markcheck:
5976 if markcheck:
5997 fdata = repo.wvfs.tryread(f)
5977 fdata = repo.wvfs.tryread(f)
5998 if (
5978 if (
5999 filemerge.hasconflictmarkers(fdata)
5979 filemerge.hasconflictmarkers(fdata)
6000 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5980 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6001 ):
5981 ):
6002 hasconflictmarkers.append(f)
5982 hasconflictmarkers.append(f)
6003 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5983 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6004 elif unmark:
5984 elif unmark:
6005 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5985 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6006 else:
5986 else:
6007 # backup pre-resolve (merge uses .orig for its own purposes)
5987 # backup pre-resolve (merge uses .orig for its own purposes)
6008 a = repo.wjoin(f)
5988 a = repo.wjoin(f)
6009 try:
5989 try:
6010 util.copyfile(a, a + b".resolve")
5990 util.copyfile(a, a + b".resolve")
6011 except (IOError, OSError) as inst:
5991 except (IOError, OSError) as inst:
6012 if inst.errno != errno.ENOENT:
5992 if inst.errno != errno.ENOENT:
6013 raise
5993 raise
6014
5994
6015 try:
5995 try:
6016 # preresolve file
5996 # preresolve file
6017 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5997 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6018 with ui.configoverride(overrides, b'resolve'):
5998 with ui.configoverride(overrides, b'resolve'):
6019 complete, r = ms.preresolve(f, wctx)
5999 complete, r = ms.preresolve(f, wctx)
6020 if not complete:
6000 if not complete:
6021 tocomplete.append(f)
6001 tocomplete.append(f)
6022 elif r:
6002 elif r:
6023 ret = 1
6003 ret = 1
6024 finally:
6004 finally:
6025 ms.commit()
6005 ms.commit()
6026
6006
6027 # replace filemerge's .orig file with our resolve file, but only
6007 # replace filemerge's .orig file with our resolve file, but only
6028 # for merges that are complete
6008 # for merges that are complete
6029 if complete:
6009 if complete:
6030 try:
6010 try:
6031 util.rename(
6011 util.rename(
6032 a + b".resolve", scmutil.backuppath(ui, repo, f)
6012 a + b".resolve", scmutil.backuppath(ui, repo, f)
6033 )
6013 )
6034 except OSError as inst:
6014 except OSError as inst:
6035 if inst.errno != errno.ENOENT:
6015 if inst.errno != errno.ENOENT:
6036 raise
6016 raise
6037
6017
6038 if hasconflictmarkers:
6018 if hasconflictmarkers:
6039 ui.warn(
6019 ui.warn(
6040 _(
6020 _(
6041 b'warning: the following files still have conflict '
6021 b'warning: the following files still have conflict '
6042 b'markers:\n'
6022 b'markers:\n'
6043 )
6023 )
6044 + b''.join(
6024 + b''.join(
6045 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6025 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6046 )
6026 )
6047 )
6027 )
6048 if markcheck == b'abort' and not all and not pats:
6028 if markcheck == b'abort' and not all and not pats:
6049 raise error.Abort(
6029 raise error.Abort(
6050 _(b'conflict markers detected'),
6030 _(b'conflict markers detected'),
6051 hint=_(b'use --all to mark anyway'),
6031 hint=_(b'use --all to mark anyway'),
6052 )
6032 )
6053
6033
6054 for f in tocomplete:
6034 for f in tocomplete:
6055 try:
6035 try:
6056 # resolve file
6036 # resolve file
6057 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6037 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6058 with ui.configoverride(overrides, b'resolve'):
6038 with ui.configoverride(overrides, b'resolve'):
6059 r = ms.resolve(f, wctx)
6039 r = ms.resolve(f, wctx)
6060 if r:
6040 if r:
6061 ret = 1
6041 ret = 1
6062 finally:
6042 finally:
6063 ms.commit()
6043 ms.commit()
6064
6044
6065 # replace filemerge's .orig file with our resolve file
6045 # replace filemerge's .orig file with our resolve file
6066 a = repo.wjoin(f)
6046 a = repo.wjoin(f)
6067 try:
6047 try:
6068 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6048 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6069 except OSError as inst:
6049 except OSError as inst:
6070 if inst.errno != errno.ENOENT:
6050 if inst.errno != errno.ENOENT:
6071 raise
6051 raise
6072
6052
6073 ms.commit()
6053 ms.commit()
6074 branchmerge = repo.dirstate.p2() != nullid
6054 branchmerge = repo.dirstate.p2() != nullid
6075 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6055 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6076
6056
6077 if not didwork and pats:
6057 if not didwork and pats:
6078 hint = None
6058 hint = None
6079 if not any([p for p in pats if p.find(b':') >= 0]):
6059 if not any([p for p in pats if p.find(b':') >= 0]):
6080 pats = [b'path:%s' % p for p in pats]
6060 pats = [b'path:%s' % p for p in pats]
6081 m = scmutil.match(wctx, pats, opts)
6061 m = scmutil.match(wctx, pats, opts)
6082 for f in ms:
6062 for f in ms:
6083 if not m(f):
6063 if not m(f):
6084 continue
6064 continue
6085
6065
6086 def flag(o):
6066 def flag(o):
6087 if o == b're_merge':
6067 if o == b're_merge':
6088 return b'--re-merge '
6068 return b'--re-merge '
6089 return b'-%s ' % o[0:1]
6069 return b'-%s ' % o[0:1]
6090
6070
6091 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6071 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6092 hint = _(b"(try: hg resolve %s%s)\n") % (
6072 hint = _(b"(try: hg resolve %s%s)\n") % (
6093 flags,
6073 flags,
6094 b' '.join(pats),
6074 b' '.join(pats),
6095 )
6075 )
6096 break
6076 break
6097 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6077 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6098 if hint:
6078 if hint:
6099 ui.warn(hint)
6079 ui.warn(hint)
6100
6080
6101 unresolvedf = list(ms.unresolved())
6081 unresolvedf = list(ms.unresolved())
6102 if not unresolvedf:
6082 if not unresolvedf:
6103 ui.status(_(b'(no more unresolved files)\n'))
6083 ui.status(_(b'(no more unresolved files)\n'))
6104 cmdutil.checkafterresolved(repo)
6084 cmdutil.checkafterresolved(repo)
6105
6085
6106 return ret
6086 return ret
6107
6087
6108
6088
6109 @command(
6089 @command(
6110 b'revert',
6090 b'revert',
6111 [
6091 [
6112 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6092 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6113 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6093 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6114 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6094 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6115 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6095 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6116 (b'i', b'interactive', None, _(b'interactively select the changes')),
6096 (b'i', b'interactive', None, _(b'interactively select the changes')),
6117 ]
6097 ]
6118 + walkopts
6098 + walkopts
6119 + dryrunopts,
6099 + dryrunopts,
6120 _(b'[OPTION]... [-r REV] [NAME]...'),
6100 _(b'[OPTION]... [-r REV] [NAME]...'),
6121 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6101 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6122 )
6102 )
6123 def revert(ui, repo, *pats, **opts):
6103 def revert(ui, repo, *pats, **opts):
6124 """restore files to their checkout state
6104 """restore files to their checkout state
6125
6105
6126 .. note::
6106 .. note::
6127
6107
6128 To check out earlier revisions, you should use :hg:`update REV`.
6108 To check out earlier revisions, you should use :hg:`update REV`.
6129 To cancel an uncommitted merge (and lose your changes),
6109 To cancel an uncommitted merge (and lose your changes),
6130 use :hg:`merge --abort`.
6110 use :hg:`merge --abort`.
6131
6111
6132 With no revision specified, revert the specified files or directories
6112 With no revision specified, revert the specified files or directories
6133 to the contents they had in the parent of the working directory.
6113 to the contents they had in the parent of the working directory.
6134 This restores the contents of files to an unmodified
6114 This restores the contents of files to an unmodified
6135 state and unschedules adds, removes, copies, and renames. If the
6115 state and unschedules adds, removes, copies, and renames. If the
6136 working directory has two parents, you must explicitly specify a
6116 working directory has two parents, you must explicitly specify a
6137 revision.
6117 revision.
6138
6118
6139 Using the -r/--rev or -d/--date options, revert the given files or
6119 Using the -r/--rev or -d/--date options, revert the given files or
6140 directories to their states as of a specific revision. Because
6120 directories to their states as of a specific revision. Because
6141 revert does not change the working directory parents, this will
6121 revert does not change the working directory parents, this will
6142 cause these files to appear modified. This can be helpful to "back
6122 cause these files to appear modified. This can be helpful to "back
6143 out" some or all of an earlier change. See :hg:`backout` for a
6123 out" some or all of an earlier change. See :hg:`backout` for a
6144 related method.
6124 related method.
6145
6125
6146 Modified files are saved with a .orig suffix before reverting.
6126 Modified files are saved with a .orig suffix before reverting.
6147 To disable these backups, use --no-backup. It is possible to store
6127 To disable these backups, use --no-backup. It is possible to store
6148 the backup files in a custom directory relative to the root of the
6128 the backup files in a custom directory relative to the root of the
6149 repository by setting the ``ui.origbackuppath`` configuration
6129 repository by setting the ``ui.origbackuppath`` configuration
6150 option.
6130 option.
6151
6131
6152 See :hg:`help dates` for a list of formats valid for -d/--date.
6132 See :hg:`help dates` for a list of formats valid for -d/--date.
6153
6133
6154 See :hg:`help backout` for a way to reverse the effect of an
6134 See :hg:`help backout` for a way to reverse the effect of an
6155 earlier changeset.
6135 earlier changeset.
6156
6136
6157 Returns 0 on success.
6137 Returns 0 on success.
6158 """
6138 """
6159
6139
6160 opts = pycompat.byteskwargs(opts)
6140 opts = pycompat.byteskwargs(opts)
6161 if opts.get(b"date"):
6141 if opts.get(b"date"):
6162 if opts.get(b"rev"):
6142 if opts.get(b"rev"):
6163 raise error.Abort(_(b"you can't specify a revision and a date"))
6143 raise error.Abort(_(b"you can't specify a revision and a date"))
6164 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6144 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6165
6145
6166 parent, p2 = repo.dirstate.parents()
6146 parent, p2 = repo.dirstate.parents()
6167 if not opts.get(b'rev') and p2 != nullid:
6147 if not opts.get(b'rev') and p2 != nullid:
6168 # revert after merge is a trap for new users (issue2915)
6148 # revert after merge is a trap for new users (issue2915)
6169 raise error.Abort(
6149 raise error.Abort(
6170 _(b'uncommitted merge with no revision specified'),
6150 _(b'uncommitted merge with no revision specified'),
6171 hint=_(b"use 'hg update' or see 'hg help revert'"),
6151 hint=_(b"use 'hg update' or see 'hg help revert'"),
6172 )
6152 )
6173
6153
6174 rev = opts.get(b'rev')
6154 rev = opts.get(b'rev')
6175 if rev:
6155 if rev:
6176 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6156 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6177 ctx = scmutil.revsingle(repo, rev)
6157 ctx = scmutil.revsingle(repo, rev)
6178
6158
6179 if not (
6159 if not (
6180 pats
6160 pats
6181 or opts.get(b'include')
6161 or opts.get(b'include')
6182 or opts.get(b'exclude')
6162 or opts.get(b'exclude')
6183 or opts.get(b'all')
6163 or opts.get(b'all')
6184 or opts.get(b'interactive')
6164 or opts.get(b'interactive')
6185 ):
6165 ):
6186 msg = _(b"no files or directories specified")
6166 msg = _(b"no files or directories specified")
6187 if p2 != nullid:
6167 if p2 != nullid:
6188 hint = _(
6168 hint = _(
6189 b"uncommitted merge, use --all to discard all changes,"
6169 b"uncommitted merge, use --all to discard all changes,"
6190 b" or 'hg update -C .' to abort the merge"
6170 b" or 'hg update -C .' to abort the merge"
6191 )
6171 )
6192 raise error.Abort(msg, hint=hint)
6172 raise error.Abort(msg, hint=hint)
6193 dirty = any(repo.status())
6173 dirty = any(repo.status())
6194 node = ctx.node()
6174 node = ctx.node()
6195 if node != parent:
6175 if node != parent:
6196 if dirty:
6176 if dirty:
6197 hint = (
6177 hint = (
6198 _(
6178 _(
6199 b"uncommitted changes, use --all to discard all"
6179 b"uncommitted changes, use --all to discard all"
6200 b" changes, or 'hg update %d' to update"
6180 b" changes, or 'hg update %d' to update"
6201 )
6181 )
6202 % ctx.rev()
6182 % ctx.rev()
6203 )
6183 )
6204 else:
6184 else:
6205 hint = (
6185 hint = (
6206 _(
6186 _(
6207 b"use --all to revert all files,"
6187 b"use --all to revert all files,"
6208 b" or 'hg update %d' to update"
6188 b" or 'hg update %d' to update"
6209 )
6189 )
6210 % ctx.rev()
6190 % ctx.rev()
6211 )
6191 )
6212 elif dirty:
6192 elif dirty:
6213 hint = _(b"uncommitted changes, use --all to discard all changes")
6193 hint = _(b"uncommitted changes, use --all to discard all changes")
6214 else:
6194 else:
6215 hint = _(b"use --all to revert all files")
6195 hint = _(b"use --all to revert all files")
6216 raise error.Abort(msg, hint=hint)
6196 raise error.Abort(msg, hint=hint)
6217
6197
6218 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6198 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6219
6199
6220
6200
6221 @command(
6201 @command(
6222 b'rollback',
6202 b'rollback',
6223 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6203 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6224 helpcategory=command.CATEGORY_MAINTENANCE,
6204 helpcategory=command.CATEGORY_MAINTENANCE,
6225 )
6205 )
6226 def rollback(ui, repo, **opts):
6206 def rollback(ui, repo, **opts):
6227 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6207 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6228
6208
6229 Please use :hg:`commit --amend` instead of rollback to correct
6209 Please use :hg:`commit --amend` instead of rollback to correct
6230 mistakes in the last commit.
6210 mistakes in the last commit.
6231
6211
6232 This command should be used with care. There is only one level of
6212 This command should be used with care. There is only one level of
6233 rollback, and there is no way to undo a rollback. It will also
6213 rollback, and there is no way to undo a rollback. It will also
6234 restore the dirstate at the time of the last transaction, losing
6214 restore the dirstate at the time of the last transaction, losing
6235 any dirstate changes since that time. This command does not alter
6215 any dirstate changes since that time. This command does not alter
6236 the working directory.
6216 the working directory.
6237
6217
6238 Transactions are used to encapsulate the effects of all commands
6218 Transactions are used to encapsulate the effects of all commands
6239 that create new changesets or propagate existing changesets into a
6219 that create new changesets or propagate existing changesets into a
6240 repository.
6220 repository.
6241
6221
6242 .. container:: verbose
6222 .. container:: verbose
6243
6223
6244 For example, the following commands are transactional, and their
6224 For example, the following commands are transactional, and their
6245 effects can be rolled back:
6225 effects can be rolled back:
6246
6226
6247 - commit
6227 - commit
6248 - import
6228 - import
6249 - pull
6229 - pull
6250 - push (with this repository as the destination)
6230 - push (with this repository as the destination)
6251 - unbundle
6231 - unbundle
6252
6232
6253 To avoid permanent data loss, rollback will refuse to rollback a
6233 To avoid permanent data loss, rollback will refuse to rollback a
6254 commit transaction if it isn't checked out. Use --force to
6234 commit transaction if it isn't checked out. Use --force to
6255 override this protection.
6235 override this protection.
6256
6236
6257 The rollback command can be entirely disabled by setting the
6237 The rollback command can be entirely disabled by setting the
6258 ``ui.rollback`` configuration setting to false. If you're here
6238 ``ui.rollback`` configuration setting to false. If you're here
6259 because you want to use rollback and it's disabled, you can
6239 because you want to use rollback and it's disabled, you can
6260 re-enable the command by setting ``ui.rollback`` to true.
6240 re-enable the command by setting ``ui.rollback`` to true.
6261
6241
6262 This command is not intended for use on public repositories. Once
6242 This command is not intended for use on public repositories. Once
6263 changes are visible for pull by other users, rolling a transaction
6243 changes are visible for pull by other users, rolling a transaction
6264 back locally is ineffective (someone else may already have pulled
6244 back locally is ineffective (someone else may already have pulled
6265 the changes). Furthermore, a race is possible with readers of the
6245 the changes). Furthermore, a race is possible with readers of the
6266 repository; for example an in-progress pull from the repository
6246 repository; for example an in-progress pull from the repository
6267 may fail if a rollback is performed.
6247 may fail if a rollback is performed.
6268
6248
6269 Returns 0 on success, 1 if no rollback data is available.
6249 Returns 0 on success, 1 if no rollback data is available.
6270 """
6250 """
6271 if not ui.configbool(b'ui', b'rollback'):
6251 if not ui.configbool(b'ui', b'rollback'):
6272 raise error.Abort(
6252 raise error.Abort(
6273 _(b'rollback is disabled because it is unsafe'),
6253 _(b'rollback is disabled because it is unsafe'),
6274 hint=b'see `hg help -v rollback` for information',
6254 hint=b'see `hg help -v rollback` for information',
6275 )
6255 )
6276 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6256 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6277
6257
6278
6258
6279 @command(
6259 @command(
6280 b'root',
6260 b'root',
6281 [] + formatteropts,
6261 [] + formatteropts,
6282 intents={INTENT_READONLY},
6262 intents={INTENT_READONLY},
6283 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6263 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6284 )
6264 )
6285 def root(ui, repo, **opts):
6265 def root(ui, repo, **opts):
6286 """print the root (top) of the current working directory
6266 """print the root (top) of the current working directory
6287
6267
6288 Print the root directory of the current repository.
6268 Print the root directory of the current repository.
6289
6269
6290 .. container:: verbose
6270 .. container:: verbose
6291
6271
6292 Template:
6272 Template:
6293
6273
6294 The following keywords are supported in addition to the common template
6274 The following keywords are supported in addition to the common template
6295 keywords and functions. See also :hg:`help templates`.
6275 keywords and functions. See also :hg:`help templates`.
6296
6276
6297 :hgpath: String. Path to the .hg directory.
6277 :hgpath: String. Path to the .hg directory.
6298 :storepath: String. Path to the directory holding versioned data.
6278 :storepath: String. Path to the directory holding versioned data.
6299
6279
6300 Returns 0 on success.
6280 Returns 0 on success.
6301 """
6281 """
6302 opts = pycompat.byteskwargs(opts)
6282 opts = pycompat.byteskwargs(opts)
6303 with ui.formatter(b'root', opts) as fm:
6283 with ui.formatter(b'root', opts) as fm:
6304 fm.startitem()
6284 fm.startitem()
6305 fm.write(b'reporoot', b'%s\n', repo.root)
6285 fm.write(b'reporoot', b'%s\n', repo.root)
6306 fm.data(hgpath=repo.path, storepath=repo.spath)
6286 fm.data(hgpath=repo.path, storepath=repo.spath)
6307
6287
6308
6288
6309 @command(
6289 @command(
6310 b'serve',
6290 b'serve',
6311 [
6291 [
6312 (
6292 (
6313 b'A',
6293 b'A',
6314 b'accesslog',
6294 b'accesslog',
6315 b'',
6295 b'',
6316 _(b'name of access log file to write to'),
6296 _(b'name of access log file to write to'),
6317 _(b'FILE'),
6297 _(b'FILE'),
6318 ),
6298 ),
6319 (b'd', b'daemon', None, _(b'run server in background')),
6299 (b'd', b'daemon', None, _(b'run server in background')),
6320 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6300 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6321 (
6301 (
6322 b'E',
6302 b'E',
6323 b'errorlog',
6303 b'errorlog',
6324 b'',
6304 b'',
6325 _(b'name of error log file to write to'),
6305 _(b'name of error log file to write to'),
6326 _(b'FILE'),
6306 _(b'FILE'),
6327 ),
6307 ),
6328 # use string type, then we can check if something was passed
6308 # use string type, then we can check if something was passed
6329 (
6309 (
6330 b'p',
6310 b'p',
6331 b'port',
6311 b'port',
6332 b'',
6312 b'',
6333 _(b'port to listen on (default: 8000)'),
6313 _(b'port to listen on (default: 8000)'),
6334 _(b'PORT'),
6314 _(b'PORT'),
6335 ),
6315 ),
6336 (
6316 (
6337 b'a',
6317 b'a',
6338 b'address',
6318 b'address',
6339 b'',
6319 b'',
6340 _(b'address to listen on (default: all interfaces)'),
6320 _(b'address to listen on (default: all interfaces)'),
6341 _(b'ADDR'),
6321 _(b'ADDR'),
6342 ),
6322 ),
6343 (
6323 (
6344 b'',
6324 b'',
6345 b'prefix',
6325 b'prefix',
6346 b'',
6326 b'',
6347 _(b'prefix path to serve from (default: server root)'),
6327 _(b'prefix path to serve from (default: server root)'),
6348 _(b'PREFIX'),
6328 _(b'PREFIX'),
6349 ),
6329 ),
6350 (
6330 (
6351 b'n',
6331 b'n',
6352 b'name',
6332 b'name',
6353 b'',
6333 b'',
6354 _(b'name to show in web pages (default: working directory)'),
6334 _(b'name to show in web pages (default: working directory)'),
6355 _(b'NAME'),
6335 _(b'NAME'),
6356 ),
6336 ),
6357 (
6337 (
6358 b'',
6338 b'',
6359 b'web-conf',
6339 b'web-conf',
6360 b'',
6340 b'',
6361 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6341 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6362 _(b'FILE'),
6342 _(b'FILE'),
6363 ),
6343 ),
6364 (
6344 (
6365 b'',
6345 b'',
6366 b'webdir-conf',
6346 b'webdir-conf',
6367 b'',
6347 b'',
6368 _(b'name of the hgweb config file (DEPRECATED)'),
6348 _(b'name of the hgweb config file (DEPRECATED)'),
6369 _(b'FILE'),
6349 _(b'FILE'),
6370 ),
6350 ),
6371 (
6351 (
6372 b'',
6352 b'',
6373 b'pid-file',
6353 b'pid-file',
6374 b'',
6354 b'',
6375 _(b'name of file to write process ID to'),
6355 _(b'name of file to write process ID to'),
6376 _(b'FILE'),
6356 _(b'FILE'),
6377 ),
6357 ),
6378 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6358 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6379 (
6359 (
6380 b'',
6360 b'',
6381 b'cmdserver',
6361 b'cmdserver',
6382 b'',
6362 b'',
6383 _(b'for remote clients (ADVANCED)'),
6363 _(b'for remote clients (ADVANCED)'),
6384 _(b'MODE'),
6364 _(b'MODE'),
6385 ),
6365 ),
6386 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6366 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6387 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6367 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6388 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6368 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6389 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6369 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6390 (b'', b'print-url', None, _(b'start and print only the URL')),
6370 (b'', b'print-url', None, _(b'start and print only the URL')),
6391 ]
6371 ]
6392 + subrepoopts,
6372 + subrepoopts,
6393 _(b'[OPTION]...'),
6373 _(b'[OPTION]...'),
6394 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6374 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6395 helpbasic=True,
6375 helpbasic=True,
6396 optionalrepo=True,
6376 optionalrepo=True,
6397 )
6377 )
6398 def serve(ui, repo, **opts):
6378 def serve(ui, repo, **opts):
6399 """start stand-alone webserver
6379 """start stand-alone webserver
6400
6380
6401 Start a local HTTP repository browser and pull server. You can use
6381 Start a local HTTP repository browser and pull server. You can use
6402 this for ad-hoc sharing and browsing of repositories. It is
6382 this for ad-hoc sharing and browsing of repositories. It is
6403 recommended to use a real web server to serve a repository for
6383 recommended to use a real web server to serve a repository for
6404 longer periods of time.
6384 longer periods of time.
6405
6385
6406 Please note that the server does not implement access control.
6386 Please note that the server does not implement access control.
6407 This means that, by default, anybody can read from the server and
6387 This means that, by default, anybody can read from the server and
6408 nobody can write to it by default. Set the ``web.allow-push``
6388 nobody can write to it by default. Set the ``web.allow-push``
6409 option to ``*`` to allow everybody to push to the server. You
6389 option to ``*`` to allow everybody to push to the server. You
6410 should use a real web server if you need to authenticate users.
6390 should use a real web server if you need to authenticate users.
6411
6391
6412 By default, the server logs accesses to stdout and errors to
6392 By default, the server logs accesses to stdout and errors to
6413 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6393 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6414 files.
6394 files.
6415
6395
6416 To have the server choose a free port number to listen on, specify
6396 To have the server choose a free port number to listen on, specify
6417 a port number of 0; in this case, the server will print the port
6397 a port number of 0; in this case, the server will print the port
6418 number it uses.
6398 number it uses.
6419
6399
6420 Returns 0 on success.
6400 Returns 0 on success.
6421 """
6401 """
6422
6402
6423 opts = pycompat.byteskwargs(opts)
6403 opts = pycompat.byteskwargs(opts)
6424 if opts[b"stdio"] and opts[b"cmdserver"]:
6404 if opts[b"stdio"] and opts[b"cmdserver"]:
6425 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6405 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6426 if opts[b"print_url"] and ui.verbose:
6406 if opts[b"print_url"] and ui.verbose:
6427 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6407 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6428
6408
6429 if opts[b"stdio"]:
6409 if opts[b"stdio"]:
6430 if repo is None:
6410 if repo is None:
6431 raise error.RepoError(
6411 raise error.RepoError(
6432 _(b"there is no Mercurial repository here (.hg not found)")
6412 _(b"there is no Mercurial repository here (.hg not found)")
6433 )
6413 )
6434 s = wireprotoserver.sshserver(ui, repo)
6414 s = wireprotoserver.sshserver(ui, repo)
6435 s.serve_forever()
6415 s.serve_forever()
6436
6416
6437 service = server.createservice(ui, repo, opts)
6417 service = server.createservice(ui, repo, opts)
6438 return server.runservice(opts, initfn=service.init, runfn=service.run)
6418 return server.runservice(opts, initfn=service.init, runfn=service.run)
6439
6419
6440
6420
6441 @command(
6421 @command(
6442 b'shelve',
6422 b'shelve',
6443 [
6423 [
6444 (
6424 (
6445 b'A',
6425 b'A',
6446 b'addremove',
6426 b'addremove',
6447 None,
6427 None,
6448 _(b'mark new/missing files as added/removed before shelving'),
6428 _(b'mark new/missing files as added/removed before shelving'),
6449 ),
6429 ),
6450 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6430 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6451 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6431 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6452 (
6432 (
6453 b'',
6433 b'',
6454 b'date',
6434 b'date',
6455 b'',
6435 b'',
6456 _(b'shelve with the specified commit date'),
6436 _(b'shelve with the specified commit date'),
6457 _(b'DATE'),
6437 _(b'DATE'),
6458 ),
6438 ),
6459 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6439 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6460 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6440 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6461 (
6441 (
6462 b'k',
6442 b'k',
6463 b'keep',
6443 b'keep',
6464 False,
6444 False,
6465 _(b'shelve, but keep changes in the working directory'),
6445 _(b'shelve, but keep changes in the working directory'),
6466 ),
6446 ),
6467 (b'l', b'list', None, _(b'list current shelves')),
6447 (b'l', b'list', None, _(b'list current shelves')),
6468 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6448 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6469 (
6449 (
6470 b'n',
6450 b'n',
6471 b'name',
6451 b'name',
6472 b'',
6452 b'',
6473 _(b'use the given name for the shelved commit'),
6453 _(b'use the given name for the shelved commit'),
6474 _(b'NAME'),
6454 _(b'NAME'),
6475 ),
6455 ),
6476 (
6456 (
6477 b'p',
6457 b'p',
6478 b'patch',
6458 b'patch',
6479 None,
6459 None,
6480 _(
6460 _(
6481 b'output patches for changes (provide the names of the shelved '
6461 b'output patches for changes (provide the names of the shelved '
6482 b'changes as positional arguments)'
6462 b'changes as positional arguments)'
6483 ),
6463 ),
6484 ),
6464 ),
6485 (b'i', b'interactive', None, _(b'interactive mode')),
6465 (b'i', b'interactive', None, _(b'interactive mode')),
6486 (
6466 (
6487 b'',
6467 b'',
6488 b'stat',
6468 b'stat',
6489 None,
6469 None,
6490 _(
6470 _(
6491 b'output diffstat-style summary of changes (provide the names of '
6471 b'output diffstat-style summary of changes (provide the names of '
6492 b'the shelved changes as positional arguments)'
6472 b'the shelved changes as positional arguments)'
6493 ),
6473 ),
6494 ),
6474 ),
6495 ]
6475 ]
6496 + cmdutil.walkopts,
6476 + cmdutil.walkopts,
6497 _(b'hg shelve [OPTION]... [FILE]...'),
6477 _(b'hg shelve [OPTION]... [FILE]...'),
6498 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6478 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6499 )
6479 )
6500 def shelve(ui, repo, *pats, **opts):
6480 def shelve(ui, repo, *pats, **opts):
6501 '''save and set aside changes from the working directory
6481 '''save and set aside changes from the working directory
6502
6482
6503 Shelving takes files that "hg status" reports as not clean, saves
6483 Shelving takes files that "hg status" reports as not clean, saves
6504 the modifications to a bundle (a shelved change), and reverts the
6484 the modifications to a bundle (a shelved change), and reverts the
6505 files so that their state in the working directory becomes clean.
6485 files so that their state in the working directory becomes clean.
6506
6486
6507 To restore these changes to the working directory, using "hg
6487 To restore these changes to the working directory, using "hg
6508 unshelve"; this will work even if you switch to a different
6488 unshelve"; this will work even if you switch to a different
6509 commit.
6489 commit.
6510
6490
6511 When no files are specified, "hg shelve" saves all not-clean
6491 When no files are specified, "hg shelve" saves all not-clean
6512 files. If specific files or directories are named, only changes to
6492 files. If specific files or directories are named, only changes to
6513 those files are shelved.
6493 those files are shelved.
6514
6494
6515 In bare shelve (when no files are specified, without interactive,
6495 In bare shelve (when no files are specified, without interactive,
6516 include and exclude option), shelving remembers information if the
6496 include and exclude option), shelving remembers information if the
6517 working directory was on newly created branch, in other words working
6497 working directory was on newly created branch, in other words working
6518 directory was on different branch than its first parent. In this
6498 directory was on different branch than its first parent. In this
6519 situation unshelving restores branch information to the working directory.
6499 situation unshelving restores branch information to the working directory.
6520
6500
6521 Each shelved change has a name that makes it easier to find later.
6501 Each shelved change has a name that makes it easier to find later.
6522 The name of a shelved change defaults to being based on the active
6502 The name of a shelved change defaults to being based on the active
6523 bookmark, or if there is no active bookmark, the current named
6503 bookmark, or if there is no active bookmark, the current named
6524 branch. To specify a different name, use ``--name``.
6504 branch. To specify a different name, use ``--name``.
6525
6505
6526 To see a list of existing shelved changes, use the ``--list``
6506 To see a list of existing shelved changes, use the ``--list``
6527 option. For each shelved change, this will print its name, age,
6507 option. For each shelved change, this will print its name, age,
6528 and description; use ``--patch`` or ``--stat`` for more details.
6508 and description; use ``--patch`` or ``--stat`` for more details.
6529
6509
6530 To delete specific shelved changes, use ``--delete``. To delete
6510 To delete specific shelved changes, use ``--delete``. To delete
6531 all shelved changes, use ``--cleanup``.
6511 all shelved changes, use ``--cleanup``.
6532 '''
6512 '''
6533 opts = pycompat.byteskwargs(opts)
6513 opts = pycompat.byteskwargs(opts)
6534 allowables = [
6514 allowables = [
6535 (b'addremove', {b'create'}), # 'create' is pseudo action
6515 (b'addremove', {b'create'}), # 'create' is pseudo action
6536 (b'unknown', {b'create'}),
6516 (b'unknown', {b'create'}),
6537 (b'cleanup', {b'cleanup'}),
6517 (b'cleanup', {b'cleanup'}),
6538 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6518 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6539 (b'delete', {b'delete'}),
6519 (b'delete', {b'delete'}),
6540 (b'edit', {b'create'}),
6520 (b'edit', {b'create'}),
6541 (b'keep', {b'create'}),
6521 (b'keep', {b'create'}),
6542 (b'list', {b'list'}),
6522 (b'list', {b'list'}),
6543 (b'message', {b'create'}),
6523 (b'message', {b'create'}),
6544 (b'name', {b'create'}),
6524 (b'name', {b'create'}),
6545 (b'patch', {b'patch', b'list'}),
6525 (b'patch', {b'patch', b'list'}),
6546 (b'stat', {b'stat', b'list'}),
6526 (b'stat', {b'stat', b'list'}),
6547 ]
6527 ]
6548
6528
6549 def checkopt(opt):
6529 def checkopt(opt):
6550 if opts.get(opt):
6530 if opts.get(opt):
6551 for i, allowable in allowables:
6531 for i, allowable in allowables:
6552 if opts[i] and opt not in allowable:
6532 if opts[i] and opt not in allowable:
6553 raise error.Abort(
6533 raise error.Abort(
6554 _(
6534 _(
6555 b"options '--%s' and '--%s' may not be "
6535 b"options '--%s' and '--%s' may not be "
6556 b"used together"
6536 b"used together"
6557 )
6537 )
6558 % (opt, i)
6538 % (opt, i)
6559 )
6539 )
6560 return True
6540 return True
6561
6541
6562 if checkopt(b'cleanup'):
6542 if checkopt(b'cleanup'):
6563 if pats:
6543 if pats:
6564 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6544 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6565 return shelvemod.cleanupcmd(ui, repo)
6545 return shelvemod.cleanupcmd(ui, repo)
6566 elif checkopt(b'delete'):
6546 elif checkopt(b'delete'):
6567 return shelvemod.deletecmd(ui, repo, pats)
6547 return shelvemod.deletecmd(ui, repo, pats)
6568 elif checkopt(b'list'):
6548 elif checkopt(b'list'):
6569 return shelvemod.listcmd(ui, repo, pats, opts)
6549 return shelvemod.listcmd(ui, repo, pats, opts)
6570 elif checkopt(b'patch') or checkopt(b'stat'):
6550 elif checkopt(b'patch') or checkopt(b'stat'):
6571 return shelvemod.patchcmds(ui, repo, pats, opts)
6551 return shelvemod.patchcmds(ui, repo, pats, opts)
6572 else:
6552 else:
6573 return shelvemod.createcmd(ui, repo, pats, opts)
6553 return shelvemod.createcmd(ui, repo, pats, opts)
6574
6554
6575
6555
6576 _NOTTERSE = b'nothing'
6556 _NOTTERSE = b'nothing'
6577
6557
6578
6558
6579 @command(
6559 @command(
6580 b'status|st',
6560 b'status|st',
6581 [
6561 [
6582 (b'A', b'all', None, _(b'show status of all files')),
6562 (b'A', b'all', None, _(b'show status of all files')),
6583 (b'm', b'modified', None, _(b'show only modified files')),
6563 (b'm', b'modified', None, _(b'show only modified files')),
6584 (b'a', b'added', None, _(b'show only added files')),
6564 (b'a', b'added', None, _(b'show only added files')),
6585 (b'r', b'removed', None, _(b'show only removed files')),
6565 (b'r', b'removed', None, _(b'show only removed files')),
6586 (b'd', b'deleted', None, _(b'show only missing files')),
6566 (b'd', b'deleted', None, _(b'show only missing files')),
6587 (b'c', b'clean', None, _(b'show only files without changes')),
6567 (b'c', b'clean', None, _(b'show only files without changes')),
6588 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6568 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6589 (b'i', b'ignored', None, _(b'show only ignored files')),
6569 (b'i', b'ignored', None, _(b'show only ignored files')),
6590 (b'n', b'no-status', None, _(b'hide status prefix')),
6570 (b'n', b'no-status', None, _(b'hide status prefix')),
6591 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6571 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6592 (
6572 (
6593 b'C',
6573 b'C',
6594 b'copies',
6574 b'copies',
6595 None,
6575 None,
6596 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6576 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6597 ),
6577 ),
6598 (
6578 (
6599 b'0',
6579 b'0',
6600 b'print0',
6580 b'print0',
6601 None,
6581 None,
6602 _(b'end filenames with NUL, for use with xargs'),
6582 _(b'end filenames with NUL, for use with xargs'),
6603 ),
6583 ),
6604 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6584 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6605 (
6585 (
6606 b'',
6586 b'',
6607 b'change',
6587 b'change',
6608 b'',
6588 b'',
6609 _(b'list the changed files of a revision'),
6589 _(b'list the changed files of a revision'),
6610 _(b'REV'),
6590 _(b'REV'),
6611 ),
6591 ),
6612 ]
6592 ]
6613 + walkopts
6593 + walkopts
6614 + subrepoopts
6594 + subrepoopts
6615 + formatteropts,
6595 + formatteropts,
6616 _(b'[OPTION]... [FILE]...'),
6596 _(b'[OPTION]... [FILE]...'),
6617 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6597 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6618 helpbasic=True,
6598 helpbasic=True,
6619 inferrepo=True,
6599 inferrepo=True,
6620 intents={INTENT_READONLY},
6600 intents={INTENT_READONLY},
6621 )
6601 )
6622 def status(ui, repo, *pats, **opts):
6602 def status(ui, repo, *pats, **opts):
6623 """show changed files in the working directory
6603 """show changed files in the working directory
6624
6604
6625 Show status of files in the repository. If names are given, only
6605 Show status of files in the repository. If names are given, only
6626 files that match are shown. Files that are clean or ignored or
6606 files that match are shown. Files that are clean or ignored or
6627 the source of a copy/move operation, are not listed unless
6607 the source of a copy/move operation, are not listed unless
6628 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6608 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6629 Unless options described with "show only ..." are given, the
6609 Unless options described with "show only ..." are given, the
6630 options -mardu are used.
6610 options -mardu are used.
6631
6611
6632 Option -q/--quiet hides untracked (unknown and ignored) files
6612 Option -q/--quiet hides untracked (unknown and ignored) files
6633 unless explicitly requested with -u/--unknown or -i/--ignored.
6613 unless explicitly requested with -u/--unknown or -i/--ignored.
6634
6614
6635 .. note::
6615 .. note::
6636
6616
6637 :hg:`status` may appear to disagree with diff if permissions have
6617 :hg:`status` may appear to disagree with diff if permissions have
6638 changed or a merge has occurred. The standard diff format does
6618 changed or a merge has occurred. The standard diff format does
6639 not report permission changes and diff only reports changes
6619 not report permission changes and diff only reports changes
6640 relative to one merge parent.
6620 relative to one merge parent.
6641
6621
6642 If one revision is given, it is used as the base revision.
6622 If one revision is given, it is used as the base revision.
6643 If two revisions are given, the differences between them are
6623 If two revisions are given, the differences between them are
6644 shown. The --change option can also be used as a shortcut to list
6624 shown. The --change option can also be used as a shortcut to list
6645 the changed files of a revision from its first parent.
6625 the changed files of a revision from its first parent.
6646
6626
6647 The codes used to show the status of files are::
6627 The codes used to show the status of files are::
6648
6628
6649 M = modified
6629 M = modified
6650 A = added
6630 A = added
6651 R = removed
6631 R = removed
6652 C = clean
6632 C = clean
6653 ! = missing (deleted by non-hg command, but still tracked)
6633 ! = missing (deleted by non-hg command, but still tracked)
6654 ? = not tracked
6634 ? = not tracked
6655 I = ignored
6635 I = ignored
6656 = origin of the previous file (with --copies)
6636 = origin of the previous file (with --copies)
6657
6637
6658 .. container:: verbose
6638 .. container:: verbose
6659
6639
6660 The -t/--terse option abbreviates the output by showing only the directory
6640 The -t/--terse option abbreviates the output by showing only the directory
6661 name if all the files in it share the same status. The option takes an
6641 name if all the files in it share the same status. The option takes an
6662 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6642 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6663 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6643 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6664 for 'ignored' and 'c' for clean.
6644 for 'ignored' and 'c' for clean.
6665
6645
6666 It abbreviates only those statuses which are passed. Note that clean and
6646 It abbreviates only those statuses which are passed. Note that clean and
6667 ignored files are not displayed with '--terse ic' unless the -c/--clean
6647 ignored files are not displayed with '--terse ic' unless the -c/--clean
6668 and -i/--ignored options are also used.
6648 and -i/--ignored options are also used.
6669
6649
6670 The -v/--verbose option shows information when the repository is in an
6650 The -v/--verbose option shows information when the repository is in an
6671 unfinished merge, shelve, rebase state etc. You can have this behavior
6651 unfinished merge, shelve, rebase state etc. You can have this behavior
6672 turned on by default by enabling the ``commands.status.verbose`` option.
6652 turned on by default by enabling the ``commands.status.verbose`` option.
6673
6653
6674 You can skip displaying some of these states by setting
6654 You can skip displaying some of these states by setting
6675 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6655 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6676 'histedit', 'merge', 'rebase', or 'unshelve'.
6656 'histedit', 'merge', 'rebase', or 'unshelve'.
6677
6657
6678 Template:
6658 Template:
6679
6659
6680 The following keywords are supported in addition to the common template
6660 The following keywords are supported in addition to the common template
6681 keywords and functions. See also :hg:`help templates`.
6661 keywords and functions. See also :hg:`help templates`.
6682
6662
6683 :path: String. Repository-absolute path of the file.
6663 :path: String. Repository-absolute path of the file.
6684 :source: String. Repository-absolute path of the file originated from.
6664 :source: String. Repository-absolute path of the file originated from.
6685 Available if ``--copies`` is specified.
6665 Available if ``--copies`` is specified.
6686 :status: String. Character denoting file's status.
6666 :status: String. Character denoting file's status.
6687
6667
6688 Examples:
6668 Examples:
6689
6669
6690 - show changes in the working directory relative to a
6670 - show changes in the working directory relative to a
6691 changeset::
6671 changeset::
6692
6672
6693 hg status --rev 9353
6673 hg status --rev 9353
6694
6674
6695 - show changes in the working directory relative to the
6675 - show changes in the working directory relative to the
6696 current directory (see :hg:`help patterns` for more information)::
6676 current directory (see :hg:`help patterns` for more information)::
6697
6677
6698 hg status re:
6678 hg status re:
6699
6679
6700 - show all changes including copies in an existing changeset::
6680 - show all changes including copies in an existing changeset::
6701
6681
6702 hg status --copies --change 9353
6682 hg status --copies --change 9353
6703
6683
6704 - get a NUL separated list of added files, suitable for xargs::
6684 - get a NUL separated list of added files, suitable for xargs::
6705
6685
6706 hg status -an0
6686 hg status -an0
6707
6687
6708 - show more information about the repository status, abbreviating
6688 - show more information about the repository status, abbreviating
6709 added, removed, modified, deleted, and untracked paths::
6689 added, removed, modified, deleted, and untracked paths::
6710
6690
6711 hg status -v -t mardu
6691 hg status -v -t mardu
6712
6692
6713 Returns 0 on success.
6693 Returns 0 on success.
6714
6694
6715 """
6695 """
6716
6696
6717 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6697 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6718 opts = pycompat.byteskwargs(opts)
6698 opts = pycompat.byteskwargs(opts)
6719 revs = opts.get(b'rev')
6699 revs = opts.get(b'rev')
6720 change = opts.get(b'change')
6700 change = opts.get(b'change')
6721 terse = opts.get(b'terse')
6701 terse = opts.get(b'terse')
6722 if terse is _NOTTERSE:
6702 if terse is _NOTTERSE:
6723 if revs:
6703 if revs:
6724 terse = b''
6704 terse = b''
6725 else:
6705 else:
6726 terse = ui.config(b'commands', b'status.terse')
6706 terse = ui.config(b'commands', b'status.terse')
6727
6707
6728 if revs and terse:
6708 if revs and terse:
6729 msg = _(b'cannot use --terse with --rev')
6709 msg = _(b'cannot use --terse with --rev')
6730 raise error.Abort(msg)
6710 raise error.Abort(msg)
6731 elif change:
6711 elif change:
6732 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6712 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6733 ctx2 = scmutil.revsingle(repo, change, None)
6713 ctx2 = scmutil.revsingle(repo, change, None)
6734 ctx1 = ctx2.p1()
6714 ctx1 = ctx2.p1()
6735 else:
6715 else:
6736 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6716 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6737 ctx1, ctx2 = scmutil.revpair(repo, revs)
6717 ctx1, ctx2 = scmutil.revpair(repo, revs)
6738
6718
6739 forcerelativevalue = None
6719 forcerelativevalue = None
6740 if ui.hasconfig(b'commands', b'status.relative'):
6720 if ui.hasconfig(b'commands', b'status.relative'):
6741 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6721 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6742 uipathfn = scmutil.getuipathfn(
6722 uipathfn = scmutil.getuipathfn(
6743 repo,
6723 repo,
6744 legacyrelativevalue=bool(pats),
6724 legacyrelativevalue=bool(pats),
6745 forcerelativevalue=forcerelativevalue,
6725 forcerelativevalue=forcerelativevalue,
6746 )
6726 )
6747
6727
6748 if opts.get(b'print0'):
6728 if opts.get(b'print0'):
6749 end = b'\0'
6729 end = b'\0'
6750 else:
6730 else:
6751 end = b'\n'
6731 end = b'\n'
6752 states = b'modified added removed deleted unknown ignored clean'.split()
6732 states = b'modified added removed deleted unknown ignored clean'.split()
6753 show = [k for k in states if opts.get(k)]
6733 show = [k for k in states if opts.get(k)]
6754 if opts.get(b'all'):
6734 if opts.get(b'all'):
6755 show += ui.quiet and (states[:4] + [b'clean']) or states
6735 show += ui.quiet and (states[:4] + [b'clean']) or states
6756
6736
6757 if not show:
6737 if not show:
6758 if ui.quiet:
6738 if ui.quiet:
6759 show = states[:4]
6739 show = states[:4]
6760 else:
6740 else:
6761 show = states[:5]
6741 show = states[:5]
6762
6742
6763 m = scmutil.match(ctx2, pats, opts)
6743 m = scmutil.match(ctx2, pats, opts)
6764 if terse:
6744 if terse:
6765 # we need to compute clean and unknown to terse
6745 # we need to compute clean and unknown to terse
6766 stat = repo.status(
6746 stat = repo.status(
6767 ctx1.node(),
6747 ctx1.node(),
6768 ctx2.node(),
6748 ctx2.node(),
6769 m,
6749 m,
6770 b'ignored' in show or b'i' in terse,
6750 b'ignored' in show or b'i' in terse,
6771 clean=True,
6751 clean=True,
6772 unknown=True,
6752 unknown=True,
6773 listsubrepos=opts.get(b'subrepos'),
6753 listsubrepos=opts.get(b'subrepos'),
6774 )
6754 )
6775
6755
6776 stat = cmdutil.tersedir(stat, terse)
6756 stat = cmdutil.tersedir(stat, terse)
6777 else:
6757 else:
6778 stat = repo.status(
6758 stat = repo.status(
6779 ctx1.node(),
6759 ctx1.node(),
6780 ctx2.node(),
6760 ctx2.node(),
6781 m,
6761 m,
6782 b'ignored' in show,
6762 b'ignored' in show,
6783 b'clean' in show,
6763 b'clean' in show,
6784 b'unknown' in show,
6764 b'unknown' in show,
6785 opts.get(b'subrepos'),
6765 opts.get(b'subrepos'),
6786 )
6766 )
6787
6767
6788 changestates = zip(
6768 changestates = zip(
6789 states,
6769 states,
6790 pycompat.iterbytestr(b'MAR!?IC'),
6770 pycompat.iterbytestr(b'MAR!?IC'),
6791 [getattr(stat, s.decode('utf8')) for s in states],
6771 [getattr(stat, s.decode('utf8')) for s in states],
6792 )
6772 )
6793
6773
6794 copy = {}
6774 copy = {}
6795 if (
6775 if (
6796 opts.get(b'all')
6776 opts.get(b'all')
6797 or opts.get(b'copies')
6777 or opts.get(b'copies')
6798 or ui.configbool(b'ui', b'statuscopies')
6778 or ui.configbool(b'ui', b'statuscopies')
6799 ) and not opts.get(b'no_status'):
6779 ) and not opts.get(b'no_status'):
6800 copy = copies.pathcopies(ctx1, ctx2, m)
6780 copy = copies.pathcopies(ctx1, ctx2, m)
6801
6781
6802 morestatus = None
6782 morestatus = None
6803 if (
6783 if (
6804 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6784 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6805 ) and not ui.plain():
6785 ) and not ui.plain():
6806 morestatus = cmdutil.readmorestatus(repo)
6786 morestatus = cmdutil.readmorestatus(repo)
6807
6787
6808 ui.pager(b'status')
6788 ui.pager(b'status')
6809 fm = ui.formatter(b'status', opts)
6789 fm = ui.formatter(b'status', opts)
6810 fmt = b'%s' + end
6790 fmt = b'%s' + end
6811 showchar = not opts.get(b'no_status')
6791 showchar = not opts.get(b'no_status')
6812
6792
6813 for state, char, files in changestates:
6793 for state, char, files in changestates:
6814 if state in show:
6794 if state in show:
6815 label = b'status.' + state
6795 label = b'status.' + state
6816 for f in files:
6796 for f in files:
6817 fm.startitem()
6797 fm.startitem()
6818 fm.context(ctx=ctx2)
6798 fm.context(ctx=ctx2)
6819 fm.data(itemtype=b'file', path=f)
6799 fm.data(itemtype=b'file', path=f)
6820 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6800 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6821 fm.plain(fmt % uipathfn(f), label=label)
6801 fm.plain(fmt % uipathfn(f), label=label)
6822 if f in copy:
6802 if f in copy:
6823 fm.data(source=copy[f])
6803 fm.data(source=copy[f])
6824 fm.plain(
6804 fm.plain(
6825 (b' %s' + end) % uipathfn(copy[f]),
6805 (b' %s' + end) % uipathfn(copy[f]),
6826 label=b'status.copied',
6806 label=b'status.copied',
6827 )
6807 )
6828 if morestatus:
6808 if morestatus:
6829 morestatus.formatfile(f, fm)
6809 morestatus.formatfile(f, fm)
6830
6810
6831 if morestatus:
6811 if morestatus:
6832 morestatus.formatfooter(fm)
6812 morestatus.formatfooter(fm)
6833 fm.end()
6813 fm.end()
6834
6814
6835
6815
6836 @command(
6816 @command(
6837 b'summary|sum',
6817 b'summary|sum',
6838 [(b'', b'remote', None, _(b'check for push and pull'))],
6818 [(b'', b'remote', None, _(b'check for push and pull'))],
6839 b'[--remote]',
6819 b'[--remote]',
6840 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6820 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6841 helpbasic=True,
6821 helpbasic=True,
6842 intents={INTENT_READONLY},
6822 intents={INTENT_READONLY},
6843 )
6823 )
6844 def summary(ui, repo, **opts):
6824 def summary(ui, repo, **opts):
6845 """summarize working directory state
6825 """summarize working directory state
6846
6826
6847 This generates a brief summary of the working directory state,
6827 This generates a brief summary of the working directory state,
6848 including parents, branch, commit status, phase and available updates.
6828 including parents, branch, commit status, phase and available updates.
6849
6829
6850 With the --remote option, this will check the default paths for
6830 With the --remote option, this will check the default paths for
6851 incoming and outgoing changes. This can be time-consuming.
6831 incoming and outgoing changes. This can be time-consuming.
6852
6832
6853 Returns 0 on success.
6833 Returns 0 on success.
6854 """
6834 """
6855
6835
6856 opts = pycompat.byteskwargs(opts)
6836 opts = pycompat.byteskwargs(opts)
6857 ui.pager(b'summary')
6837 ui.pager(b'summary')
6858 ctx = repo[None]
6838 ctx = repo[None]
6859 parents = ctx.parents()
6839 parents = ctx.parents()
6860 pnode = parents[0].node()
6840 pnode = parents[0].node()
6861 marks = []
6841 marks = []
6862
6842
6863 try:
6843 try:
6864 ms = mergestatemod.mergestate.read(repo)
6844 ms = mergestatemod.mergestate.read(repo)
6865 except error.UnsupportedMergeRecords as e:
6845 except error.UnsupportedMergeRecords as e:
6866 s = b' '.join(e.recordtypes)
6846 s = b' '.join(e.recordtypes)
6867 ui.warn(
6847 ui.warn(
6868 _(b'warning: merge state has unsupported record types: %s\n') % s
6848 _(b'warning: merge state has unsupported record types: %s\n') % s
6869 )
6849 )
6870 unresolved = []
6850 unresolved = []
6871 else:
6851 else:
6872 unresolved = list(ms.unresolved())
6852 unresolved = list(ms.unresolved())
6873
6853
6874 for p in parents:
6854 for p in parents:
6875 # label with log.changeset (instead of log.parent) since this
6855 # label with log.changeset (instead of log.parent) since this
6876 # shows a working directory parent *changeset*:
6856 # shows a working directory parent *changeset*:
6877 # i18n: column positioning for "hg summary"
6857 # i18n: column positioning for "hg summary"
6878 ui.write(
6858 ui.write(
6879 _(b'parent: %d:%s ') % (p.rev(), p),
6859 _(b'parent: %d:%s ') % (p.rev(), p),
6880 label=logcmdutil.changesetlabels(p),
6860 label=logcmdutil.changesetlabels(p),
6881 )
6861 )
6882 ui.write(b' '.join(p.tags()), label=b'log.tag')
6862 ui.write(b' '.join(p.tags()), label=b'log.tag')
6883 if p.bookmarks():
6863 if p.bookmarks():
6884 marks.extend(p.bookmarks())
6864 marks.extend(p.bookmarks())
6885 if p.rev() == -1:
6865 if p.rev() == -1:
6886 if not len(repo):
6866 if not len(repo):
6887 ui.write(_(b' (empty repository)'))
6867 ui.write(_(b' (empty repository)'))
6888 else:
6868 else:
6889 ui.write(_(b' (no revision checked out)'))
6869 ui.write(_(b' (no revision checked out)'))
6890 if p.obsolete():
6870 if p.obsolete():
6891 ui.write(_(b' (obsolete)'))
6871 ui.write(_(b' (obsolete)'))
6892 if p.isunstable():
6872 if p.isunstable():
6893 instabilities = (
6873 instabilities = (
6894 ui.label(instability, b'trouble.%s' % instability)
6874 ui.label(instability, b'trouble.%s' % instability)
6895 for instability in p.instabilities()
6875 for instability in p.instabilities()
6896 )
6876 )
6897 ui.write(b' (' + b', '.join(instabilities) + b')')
6877 ui.write(b' (' + b', '.join(instabilities) + b')')
6898 ui.write(b'\n')
6878 ui.write(b'\n')
6899 if p.description():
6879 if p.description():
6900 ui.status(
6880 ui.status(
6901 b' ' + p.description().splitlines()[0].strip() + b'\n',
6881 b' ' + p.description().splitlines()[0].strip() + b'\n',
6902 label=b'log.summary',
6882 label=b'log.summary',
6903 )
6883 )
6904
6884
6905 branch = ctx.branch()
6885 branch = ctx.branch()
6906 bheads = repo.branchheads(branch)
6886 bheads = repo.branchheads(branch)
6907 # i18n: column positioning for "hg summary"
6887 # i18n: column positioning for "hg summary"
6908 m = _(b'branch: %s\n') % branch
6888 m = _(b'branch: %s\n') % branch
6909 if branch != b'default':
6889 if branch != b'default':
6910 ui.write(m, label=b'log.branch')
6890 ui.write(m, label=b'log.branch')
6911 else:
6891 else:
6912 ui.status(m, label=b'log.branch')
6892 ui.status(m, label=b'log.branch')
6913
6893
6914 if marks:
6894 if marks:
6915 active = repo._activebookmark
6895 active = repo._activebookmark
6916 # i18n: column positioning for "hg summary"
6896 # i18n: column positioning for "hg summary"
6917 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6897 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6918 if active is not None:
6898 if active is not None:
6919 if active in marks:
6899 if active in marks:
6920 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6900 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6921 marks.remove(active)
6901 marks.remove(active)
6922 else:
6902 else:
6923 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6903 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6924 for m in marks:
6904 for m in marks:
6925 ui.write(b' ' + m, label=b'log.bookmark')
6905 ui.write(b' ' + m, label=b'log.bookmark')
6926 ui.write(b'\n', label=b'log.bookmark')
6906 ui.write(b'\n', label=b'log.bookmark')
6927
6907
6928 status = repo.status(unknown=True)
6908 status = repo.status(unknown=True)
6929
6909
6930 c = repo.dirstate.copies()
6910 c = repo.dirstate.copies()
6931 copied, renamed = [], []
6911 copied, renamed = [], []
6932 for d, s in pycompat.iteritems(c):
6912 for d, s in pycompat.iteritems(c):
6933 if s in status.removed:
6913 if s in status.removed:
6934 status.removed.remove(s)
6914 status.removed.remove(s)
6935 renamed.append(d)
6915 renamed.append(d)
6936 else:
6916 else:
6937 copied.append(d)
6917 copied.append(d)
6938 if d in status.added:
6918 if d in status.added:
6939 status.added.remove(d)
6919 status.added.remove(d)
6940
6920
6941 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6921 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6942
6922
6943 labels = [
6923 labels = [
6944 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6924 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6945 (ui.label(_(b'%d added'), b'status.added'), status.added),
6925 (ui.label(_(b'%d added'), b'status.added'), status.added),
6946 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6926 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6947 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6927 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6948 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6928 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6949 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6929 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6950 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6930 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6951 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6931 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6952 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6932 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6953 ]
6933 ]
6954 t = []
6934 t = []
6955 for l, s in labels:
6935 for l, s in labels:
6956 if s:
6936 if s:
6957 t.append(l % len(s))
6937 t.append(l % len(s))
6958
6938
6959 t = b', '.join(t)
6939 t = b', '.join(t)
6960 cleanworkdir = False
6940 cleanworkdir = False
6961
6941
6962 if repo.vfs.exists(b'graftstate'):
6942 if repo.vfs.exists(b'graftstate'):
6963 t += _(b' (graft in progress)')
6943 t += _(b' (graft in progress)')
6964 if repo.vfs.exists(b'updatestate'):
6944 if repo.vfs.exists(b'updatestate'):
6965 t += _(b' (interrupted update)')
6945 t += _(b' (interrupted update)')
6966 elif len(parents) > 1:
6946 elif len(parents) > 1:
6967 t += _(b' (merge)')
6947 t += _(b' (merge)')
6968 elif branch != parents[0].branch():
6948 elif branch != parents[0].branch():
6969 t += _(b' (new branch)')
6949 t += _(b' (new branch)')
6970 elif parents[0].closesbranch() and pnode in repo.branchheads(
6950 elif parents[0].closesbranch() and pnode in repo.branchheads(
6971 branch, closed=True
6951 branch, closed=True
6972 ):
6952 ):
6973 t += _(b' (head closed)')
6953 t += _(b' (head closed)')
6974 elif not (
6954 elif not (
6975 status.modified
6955 status.modified
6976 or status.added
6956 or status.added
6977 or status.removed
6957 or status.removed
6978 or renamed
6958 or renamed
6979 or copied
6959 or copied
6980 or subs
6960 or subs
6981 ):
6961 ):
6982 t += _(b' (clean)')
6962 t += _(b' (clean)')
6983 cleanworkdir = True
6963 cleanworkdir = True
6984 elif pnode not in bheads:
6964 elif pnode not in bheads:
6985 t += _(b' (new branch head)')
6965 t += _(b' (new branch head)')
6986
6966
6987 if parents:
6967 if parents:
6988 pendingphase = max(p.phase() for p in parents)
6968 pendingphase = max(p.phase() for p in parents)
6989 else:
6969 else:
6990 pendingphase = phases.public
6970 pendingphase = phases.public
6991
6971
6992 if pendingphase > phases.newcommitphase(ui):
6972 if pendingphase > phases.newcommitphase(ui):
6993 t += b' (%s)' % phases.phasenames[pendingphase]
6973 t += b' (%s)' % phases.phasenames[pendingphase]
6994
6974
6995 if cleanworkdir:
6975 if cleanworkdir:
6996 # i18n: column positioning for "hg summary"
6976 # i18n: column positioning for "hg summary"
6997 ui.status(_(b'commit: %s\n') % t.strip())
6977 ui.status(_(b'commit: %s\n') % t.strip())
6998 else:
6978 else:
6999 # i18n: column positioning for "hg summary"
6979 # i18n: column positioning for "hg summary"
7000 ui.write(_(b'commit: %s\n') % t.strip())
6980 ui.write(_(b'commit: %s\n') % t.strip())
7001
6981
7002 # all ancestors of branch heads - all ancestors of parent = new csets
6982 # all ancestors of branch heads - all ancestors of parent = new csets
7003 new = len(
6983 new = len(
7004 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6984 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7005 )
6985 )
7006
6986
7007 if new == 0:
6987 if new == 0:
7008 # i18n: column positioning for "hg summary"
6988 # i18n: column positioning for "hg summary"
7009 ui.status(_(b'update: (current)\n'))
6989 ui.status(_(b'update: (current)\n'))
7010 elif pnode not in bheads:
6990 elif pnode not in bheads:
7011 # i18n: column positioning for "hg summary"
6991 # i18n: column positioning for "hg summary"
7012 ui.write(_(b'update: %d new changesets (update)\n') % new)
6992 ui.write(_(b'update: %d new changesets (update)\n') % new)
7013 else:
6993 else:
7014 # i18n: column positioning for "hg summary"
6994 # i18n: column positioning for "hg summary"
7015 ui.write(
6995 ui.write(
7016 _(b'update: %d new changesets, %d branch heads (merge)\n')
6996 _(b'update: %d new changesets, %d branch heads (merge)\n')
7017 % (new, len(bheads))
6997 % (new, len(bheads))
7018 )
6998 )
7019
6999
7020 t = []
7000 t = []
7021 draft = len(repo.revs(b'draft()'))
7001 draft = len(repo.revs(b'draft()'))
7022 if draft:
7002 if draft:
7023 t.append(_(b'%d draft') % draft)
7003 t.append(_(b'%d draft') % draft)
7024 secret = len(repo.revs(b'secret()'))
7004 secret = len(repo.revs(b'secret()'))
7025 if secret:
7005 if secret:
7026 t.append(_(b'%d secret') % secret)
7006 t.append(_(b'%d secret') % secret)
7027
7007
7028 if draft or secret:
7008 if draft or secret:
7029 ui.status(_(b'phases: %s\n') % b', '.join(t))
7009 ui.status(_(b'phases: %s\n') % b', '.join(t))
7030
7010
7031 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7011 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7032 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7012 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7033 numtrouble = len(repo.revs(trouble + b"()"))
7013 numtrouble = len(repo.revs(trouble + b"()"))
7034 # We write all the possibilities to ease translation
7014 # We write all the possibilities to ease translation
7035 troublemsg = {
7015 troublemsg = {
7036 b"orphan": _(b"orphan: %d changesets"),
7016 b"orphan": _(b"orphan: %d changesets"),
7037 b"contentdivergent": _(b"content-divergent: %d changesets"),
7017 b"contentdivergent": _(b"content-divergent: %d changesets"),
7038 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7018 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7039 }
7019 }
7040 if numtrouble > 0:
7020 if numtrouble > 0:
7041 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7021 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7042
7022
7043 cmdutil.summaryhooks(ui, repo)
7023 cmdutil.summaryhooks(ui, repo)
7044
7024
7045 if opts.get(b'remote'):
7025 if opts.get(b'remote'):
7046 needsincoming, needsoutgoing = True, True
7026 needsincoming, needsoutgoing = True, True
7047 else:
7027 else:
7048 needsincoming, needsoutgoing = False, False
7028 needsincoming, needsoutgoing = False, False
7049 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7029 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7050 if i:
7030 if i:
7051 needsincoming = True
7031 needsincoming = True
7052 if o:
7032 if o:
7053 needsoutgoing = True
7033 needsoutgoing = True
7054 if not needsincoming and not needsoutgoing:
7034 if not needsincoming and not needsoutgoing:
7055 return
7035 return
7056
7036
7057 def getincoming():
7037 def getincoming():
7058 source, branches = hg.parseurl(ui.expandpath(b'default'))
7038 source, branches = hg.parseurl(ui.expandpath(b'default'))
7059 sbranch = branches[0]
7039 sbranch = branches[0]
7060 try:
7040 try:
7061 other = hg.peer(repo, {}, source)
7041 other = hg.peer(repo, {}, source)
7062 except error.RepoError:
7042 except error.RepoError:
7063 if opts.get(b'remote'):
7043 if opts.get(b'remote'):
7064 raise
7044 raise
7065 return source, sbranch, None, None, None
7045 return source, sbranch, None, None, None
7066 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7046 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7067 if revs:
7047 if revs:
7068 revs = [other.lookup(rev) for rev in revs]
7048 revs = [other.lookup(rev) for rev in revs]
7069 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7049 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7070 repo.ui.pushbuffer()
7050 repo.ui.pushbuffer()
7071 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7051 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7072 repo.ui.popbuffer()
7052 repo.ui.popbuffer()
7073 return source, sbranch, other, commoninc, commoninc[1]
7053 return source, sbranch, other, commoninc, commoninc[1]
7074
7054
7075 if needsincoming:
7055 if needsincoming:
7076 source, sbranch, sother, commoninc, incoming = getincoming()
7056 source, sbranch, sother, commoninc, incoming = getincoming()
7077 else:
7057 else:
7078 source = sbranch = sother = commoninc = incoming = None
7058 source = sbranch = sother = commoninc = incoming = None
7079
7059
7080 def getoutgoing():
7060 def getoutgoing():
7081 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7061 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7082 dbranch = branches[0]
7062 dbranch = branches[0]
7083 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7084 if source != dest:
7064 if source != dest:
7085 try:
7065 try:
7086 dother = hg.peer(repo, {}, dest)
7066 dother = hg.peer(repo, {}, dest)
7087 except error.RepoError:
7067 except error.RepoError:
7088 if opts.get(b'remote'):
7068 if opts.get(b'remote'):
7089 raise
7069 raise
7090 return dest, dbranch, None, None
7070 return dest, dbranch, None, None
7091 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7071 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7092 elif sother is None:
7072 elif sother is None:
7093 # there is no explicit destination peer, but source one is invalid
7073 # there is no explicit destination peer, but source one is invalid
7094 return dest, dbranch, None, None
7074 return dest, dbranch, None, None
7095 else:
7075 else:
7096 dother = sother
7076 dother = sother
7097 if source != dest or (sbranch is not None and sbranch != dbranch):
7077 if source != dest or (sbranch is not None and sbranch != dbranch):
7098 common = None
7078 common = None
7099 else:
7079 else:
7100 common = commoninc
7080 common = commoninc
7101 if revs:
7081 if revs:
7102 revs = [repo.lookup(rev) for rev in revs]
7082 revs = [repo.lookup(rev) for rev in revs]
7103 repo.ui.pushbuffer()
7083 repo.ui.pushbuffer()
7104 outgoing = discovery.findcommonoutgoing(
7084 outgoing = discovery.findcommonoutgoing(
7105 repo, dother, onlyheads=revs, commoninc=common
7085 repo, dother, onlyheads=revs, commoninc=common
7106 )
7086 )
7107 repo.ui.popbuffer()
7087 repo.ui.popbuffer()
7108 return dest, dbranch, dother, outgoing
7088 return dest, dbranch, dother, outgoing
7109
7089
7110 if needsoutgoing:
7090 if needsoutgoing:
7111 dest, dbranch, dother, outgoing = getoutgoing()
7091 dest, dbranch, dother, outgoing = getoutgoing()
7112 else:
7092 else:
7113 dest = dbranch = dother = outgoing = None
7093 dest = dbranch = dother = outgoing = None
7114
7094
7115 if opts.get(b'remote'):
7095 if opts.get(b'remote'):
7116 t = []
7096 t = []
7117 if incoming:
7097 if incoming:
7118 t.append(_(b'1 or more incoming'))
7098 t.append(_(b'1 or more incoming'))
7119 o = outgoing.missing
7099 o = outgoing.missing
7120 if o:
7100 if o:
7121 t.append(_(b'%d outgoing') % len(o))
7101 t.append(_(b'%d outgoing') % len(o))
7122 other = dother or sother
7102 other = dother or sother
7123 if b'bookmarks' in other.listkeys(b'namespaces'):
7103 if b'bookmarks' in other.listkeys(b'namespaces'):
7124 counts = bookmarks.summary(repo, other)
7104 counts = bookmarks.summary(repo, other)
7125 if counts[0] > 0:
7105 if counts[0] > 0:
7126 t.append(_(b'%d incoming bookmarks') % counts[0])
7106 t.append(_(b'%d incoming bookmarks') % counts[0])
7127 if counts[1] > 0:
7107 if counts[1] > 0:
7128 t.append(_(b'%d outgoing bookmarks') % counts[1])
7108 t.append(_(b'%d outgoing bookmarks') % counts[1])
7129
7109
7130 if t:
7110 if t:
7131 # i18n: column positioning for "hg summary"
7111 # i18n: column positioning for "hg summary"
7132 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7112 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7133 else:
7113 else:
7134 # i18n: column positioning for "hg summary"
7114 # i18n: column positioning for "hg summary"
7135 ui.status(_(b'remote: (synced)\n'))
7115 ui.status(_(b'remote: (synced)\n'))
7136
7116
7137 cmdutil.summaryremotehooks(
7117 cmdutil.summaryremotehooks(
7138 ui,
7118 ui,
7139 repo,
7119 repo,
7140 opts,
7120 opts,
7141 (
7121 (
7142 (source, sbranch, sother, commoninc),
7122 (source, sbranch, sother, commoninc),
7143 (dest, dbranch, dother, outgoing),
7123 (dest, dbranch, dother, outgoing),
7144 ),
7124 ),
7145 )
7125 )
7146
7126
7147
7127
7148 @command(
7128 @command(
7149 b'tag',
7129 b'tag',
7150 [
7130 [
7151 (b'f', b'force', None, _(b'force tag')),
7131 (b'f', b'force', None, _(b'force tag')),
7152 (b'l', b'local', None, _(b'make the tag local')),
7132 (b'l', b'local', None, _(b'make the tag local')),
7153 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7133 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7154 (b'', b'remove', None, _(b'remove a tag')),
7134 (b'', b'remove', None, _(b'remove a tag')),
7155 # -l/--local is already there, commitopts cannot be used
7135 # -l/--local is already there, commitopts cannot be used
7156 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7136 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7157 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7137 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7158 ]
7138 ]
7159 + commitopts2,
7139 + commitopts2,
7160 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7140 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7161 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7141 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7162 )
7142 )
7163 def tag(ui, repo, name1, *names, **opts):
7143 def tag(ui, repo, name1, *names, **opts):
7164 """add one or more tags for the current or given revision
7144 """add one or more tags for the current or given revision
7165
7145
7166 Name a particular revision using <name>.
7146 Name a particular revision using <name>.
7167
7147
7168 Tags are used to name particular revisions of the repository and are
7148 Tags are used to name particular revisions of the repository and are
7169 very useful to compare different revisions, to go back to significant
7149 very useful to compare different revisions, to go back to significant
7170 earlier versions or to mark branch points as releases, etc. Changing
7150 earlier versions or to mark branch points as releases, etc. Changing
7171 an existing tag is normally disallowed; use -f/--force to override.
7151 an existing tag is normally disallowed; use -f/--force to override.
7172
7152
7173 If no revision is given, the parent of the working directory is
7153 If no revision is given, the parent of the working directory is
7174 used.
7154 used.
7175
7155
7176 To facilitate version control, distribution, and merging of tags,
7156 To facilitate version control, distribution, and merging of tags,
7177 they are stored as a file named ".hgtags" which is managed similarly
7157 they are stored as a file named ".hgtags" which is managed similarly
7178 to other project files and can be hand-edited if necessary. This
7158 to other project files and can be hand-edited if necessary. This
7179 also means that tagging creates a new commit. The file
7159 also means that tagging creates a new commit. The file
7180 ".hg/localtags" is used for local tags (not shared among
7160 ".hg/localtags" is used for local tags (not shared among
7181 repositories).
7161 repositories).
7182
7162
7183 Tag commits are usually made at the head of a branch. If the parent
7163 Tag commits are usually made at the head of a branch. If the parent
7184 of the working directory is not a branch head, :hg:`tag` aborts; use
7164 of the working directory is not a branch head, :hg:`tag` aborts; use
7185 -f/--force to force the tag commit to be based on a non-head
7165 -f/--force to force the tag commit to be based on a non-head
7186 changeset.
7166 changeset.
7187
7167
7188 See :hg:`help dates` for a list of formats valid for -d/--date.
7168 See :hg:`help dates` for a list of formats valid for -d/--date.
7189
7169
7190 Since tag names have priority over branch names during revision
7170 Since tag names have priority over branch names during revision
7191 lookup, using an existing branch name as a tag name is discouraged.
7171 lookup, using an existing branch name as a tag name is discouraged.
7192
7172
7193 Returns 0 on success.
7173 Returns 0 on success.
7194 """
7174 """
7195 opts = pycompat.byteskwargs(opts)
7175 opts = pycompat.byteskwargs(opts)
7196 with repo.wlock(), repo.lock():
7176 with repo.wlock(), repo.lock():
7197 rev_ = b"."
7177 rev_ = b"."
7198 names = [t.strip() for t in (name1,) + names]
7178 names = [t.strip() for t in (name1,) + names]
7199 if len(names) != len(set(names)):
7179 if len(names) != len(set(names)):
7200 raise error.Abort(_(b'tag names must be unique'))
7180 raise error.Abort(_(b'tag names must be unique'))
7201 for n in names:
7181 for n in names:
7202 scmutil.checknewlabel(repo, n, b'tag')
7182 scmutil.checknewlabel(repo, n, b'tag')
7203 if not n:
7183 if not n:
7204 raise error.Abort(
7184 raise error.Abort(
7205 _(b'tag names cannot consist entirely of whitespace')
7185 _(b'tag names cannot consist entirely of whitespace')
7206 )
7186 )
7207 if opts.get(b'rev') and opts.get(b'remove'):
7187 if opts.get(b'rev') and opts.get(b'remove'):
7208 raise error.Abort(_(b"--rev and --remove are incompatible"))
7188 raise error.Abort(_(b"--rev and --remove are incompatible"))
7209 if opts.get(b'rev'):
7189 if opts.get(b'rev'):
7210 rev_ = opts[b'rev']
7190 rev_ = opts[b'rev']
7211 message = opts.get(b'message')
7191 message = opts.get(b'message')
7212 if opts.get(b'remove'):
7192 if opts.get(b'remove'):
7213 if opts.get(b'local'):
7193 if opts.get(b'local'):
7214 expectedtype = b'local'
7194 expectedtype = b'local'
7215 else:
7195 else:
7216 expectedtype = b'global'
7196 expectedtype = b'global'
7217
7197
7218 for n in names:
7198 for n in names:
7219 if repo.tagtype(n) == b'global':
7199 if repo.tagtype(n) == b'global':
7220 alltags = tagsmod.findglobaltags(ui, repo)
7200 alltags = tagsmod.findglobaltags(ui, repo)
7221 if alltags[n][0] == nullid:
7201 if alltags[n][0] == nullid:
7222 raise error.Abort(_(b"tag '%s' is already removed") % n)
7202 raise error.Abort(_(b"tag '%s' is already removed") % n)
7223 if not repo.tagtype(n):
7203 if not repo.tagtype(n):
7224 raise error.Abort(_(b"tag '%s' does not exist") % n)
7204 raise error.Abort(_(b"tag '%s' does not exist") % n)
7225 if repo.tagtype(n) != expectedtype:
7205 if repo.tagtype(n) != expectedtype:
7226 if expectedtype == b'global':
7206 if expectedtype == b'global':
7227 raise error.Abort(
7207 raise error.Abort(
7228 _(b"tag '%s' is not a global tag") % n
7208 _(b"tag '%s' is not a global tag") % n
7229 )
7209 )
7230 else:
7210 else:
7231 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7211 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7232 rev_ = b'null'
7212 rev_ = b'null'
7233 if not message:
7213 if not message:
7234 # we don't translate commit messages
7214 # we don't translate commit messages
7235 message = b'Removed tag %s' % b', '.join(names)
7215 message = b'Removed tag %s' % b', '.join(names)
7236 elif not opts.get(b'force'):
7216 elif not opts.get(b'force'):
7237 for n in names:
7217 for n in names:
7238 if n in repo.tags():
7218 if n in repo.tags():
7239 raise error.Abort(
7219 raise error.Abort(
7240 _(b"tag '%s' already exists (use -f to force)") % n
7220 _(b"tag '%s' already exists (use -f to force)") % n
7241 )
7221 )
7242 if not opts.get(b'local'):
7222 if not opts.get(b'local'):
7243 p1, p2 = repo.dirstate.parents()
7223 p1, p2 = repo.dirstate.parents()
7244 if p2 != nullid:
7224 if p2 != nullid:
7245 raise error.Abort(_(b'uncommitted merge'))
7225 raise error.Abort(_(b'uncommitted merge'))
7246 bheads = repo.branchheads()
7226 bheads = repo.branchheads()
7247 if not opts.get(b'force') and bheads and p1 not in bheads:
7227 if not opts.get(b'force') and bheads and p1 not in bheads:
7248 raise error.Abort(
7228 raise error.Abort(
7249 _(
7229 _(
7250 b'working directory is not at a branch head '
7230 b'working directory is not at a branch head '
7251 b'(use -f to force)'
7231 b'(use -f to force)'
7252 )
7232 )
7253 )
7233 )
7254 node = scmutil.revsingle(repo, rev_).node()
7234 node = scmutil.revsingle(repo, rev_).node()
7255
7235
7256 if not message:
7236 if not message:
7257 # we don't translate commit messages
7237 # we don't translate commit messages
7258 message = b'Added tag %s for changeset %s' % (
7238 message = b'Added tag %s for changeset %s' % (
7259 b', '.join(names),
7239 b', '.join(names),
7260 short(node),
7240 short(node),
7261 )
7241 )
7262
7242
7263 date = opts.get(b'date')
7243 date = opts.get(b'date')
7264 if date:
7244 if date:
7265 date = dateutil.parsedate(date)
7245 date = dateutil.parsedate(date)
7266
7246
7267 if opts.get(b'remove'):
7247 if opts.get(b'remove'):
7268 editform = b'tag.remove'
7248 editform = b'tag.remove'
7269 else:
7249 else:
7270 editform = b'tag.add'
7250 editform = b'tag.add'
7271 editor = cmdutil.getcommiteditor(
7251 editor = cmdutil.getcommiteditor(
7272 editform=editform, **pycompat.strkwargs(opts)
7252 editform=editform, **pycompat.strkwargs(opts)
7273 )
7253 )
7274
7254
7275 # don't allow tagging the null rev
7255 # don't allow tagging the null rev
7276 if (
7256 if (
7277 not opts.get(b'remove')
7257 not opts.get(b'remove')
7278 and scmutil.revsingle(repo, rev_).rev() == nullrev
7258 and scmutil.revsingle(repo, rev_).rev() == nullrev
7279 ):
7259 ):
7280 raise error.Abort(_(b"cannot tag null revision"))
7260 raise error.Abort(_(b"cannot tag null revision"))
7281
7261
7282 tagsmod.tag(
7262 tagsmod.tag(
7283 repo,
7263 repo,
7284 names,
7264 names,
7285 node,
7265 node,
7286 message,
7266 message,
7287 opts.get(b'local'),
7267 opts.get(b'local'),
7288 opts.get(b'user'),
7268 opts.get(b'user'),
7289 date,
7269 date,
7290 editor=editor,
7270 editor=editor,
7291 )
7271 )
7292
7272
7293
7273
7294 @command(
7274 @command(
7295 b'tags',
7275 b'tags',
7296 formatteropts,
7276 formatteropts,
7297 b'',
7277 b'',
7298 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7278 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7299 intents={INTENT_READONLY},
7279 intents={INTENT_READONLY},
7300 )
7280 )
7301 def tags(ui, repo, **opts):
7281 def tags(ui, repo, **opts):
7302 """list repository tags
7282 """list repository tags
7303
7283
7304 This lists both regular and local tags. When the -v/--verbose
7284 This lists both regular and local tags. When the -v/--verbose
7305 switch is used, a third column "local" is printed for local tags.
7285 switch is used, a third column "local" is printed for local tags.
7306 When the -q/--quiet switch is used, only the tag name is printed.
7286 When the -q/--quiet switch is used, only the tag name is printed.
7307
7287
7308 .. container:: verbose
7288 .. container:: verbose
7309
7289
7310 Template:
7290 Template:
7311
7291
7312 The following keywords are supported in addition to the common template
7292 The following keywords are supported in addition to the common template
7313 keywords and functions such as ``{tag}``. See also
7293 keywords and functions such as ``{tag}``. See also
7314 :hg:`help templates`.
7294 :hg:`help templates`.
7315
7295
7316 :type: String. ``local`` for local tags.
7296 :type: String. ``local`` for local tags.
7317
7297
7318 Returns 0 on success.
7298 Returns 0 on success.
7319 """
7299 """
7320
7300
7321 opts = pycompat.byteskwargs(opts)
7301 opts = pycompat.byteskwargs(opts)
7322 ui.pager(b'tags')
7302 ui.pager(b'tags')
7323 fm = ui.formatter(b'tags', opts)
7303 fm = ui.formatter(b'tags', opts)
7324 hexfunc = fm.hexfunc
7304 hexfunc = fm.hexfunc
7325
7305
7326 for t, n in reversed(repo.tagslist()):
7306 for t, n in reversed(repo.tagslist()):
7327 hn = hexfunc(n)
7307 hn = hexfunc(n)
7328 label = b'tags.normal'
7308 label = b'tags.normal'
7329 tagtype = b''
7309 tagtype = b''
7330 if repo.tagtype(t) == b'local':
7310 if repo.tagtype(t) == b'local':
7331 label = b'tags.local'
7311 label = b'tags.local'
7332 tagtype = b'local'
7312 tagtype = b'local'
7333
7313
7334 fm.startitem()
7314 fm.startitem()
7335 fm.context(repo=repo)
7315 fm.context(repo=repo)
7336 fm.write(b'tag', b'%s', t, label=label)
7316 fm.write(b'tag', b'%s', t, label=label)
7337 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7317 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7338 fm.condwrite(
7318 fm.condwrite(
7339 not ui.quiet,
7319 not ui.quiet,
7340 b'rev node',
7320 b'rev node',
7341 fmt,
7321 fmt,
7342 repo.changelog.rev(n),
7322 repo.changelog.rev(n),
7343 hn,
7323 hn,
7344 label=label,
7324 label=label,
7345 )
7325 )
7346 fm.condwrite(
7326 fm.condwrite(
7347 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7327 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7348 )
7328 )
7349 fm.plain(b'\n')
7329 fm.plain(b'\n')
7350 fm.end()
7330 fm.end()
7351
7331
7352
7332
7353 @command(
7333 @command(
7354 b'tip',
7334 b'tip',
7355 [
7335 [
7356 (b'p', b'patch', None, _(b'show patch')),
7336 (b'p', b'patch', None, _(b'show patch')),
7357 (b'g', b'git', None, _(b'use git extended diff format')),
7337 (b'g', b'git', None, _(b'use git extended diff format')),
7358 ]
7338 ]
7359 + templateopts,
7339 + templateopts,
7360 _(b'[-p] [-g]'),
7340 _(b'[-p] [-g]'),
7361 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7341 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7362 )
7342 )
7363 def tip(ui, repo, **opts):
7343 def tip(ui, repo, **opts):
7364 """show the tip revision (DEPRECATED)
7344 """show the tip revision (DEPRECATED)
7365
7345
7366 The tip revision (usually just called the tip) is the changeset
7346 The tip revision (usually just called the tip) is the changeset
7367 most recently added to the repository (and therefore the most
7347 most recently added to the repository (and therefore the most
7368 recently changed head).
7348 recently changed head).
7369
7349
7370 If you have just made a commit, that commit will be the tip. If
7350 If you have just made a commit, that commit will be the tip. If
7371 you have just pulled changes from another repository, the tip of
7351 you have just pulled changes from another repository, the tip of
7372 that repository becomes the current tip. The "tip" tag is special
7352 that repository becomes the current tip. The "tip" tag is special
7373 and cannot be renamed or assigned to a different changeset.
7353 and cannot be renamed or assigned to a different changeset.
7374
7354
7375 This command is deprecated, please use :hg:`heads` instead.
7355 This command is deprecated, please use :hg:`heads` instead.
7376
7356
7377 Returns 0 on success.
7357 Returns 0 on success.
7378 """
7358 """
7379 opts = pycompat.byteskwargs(opts)
7359 opts = pycompat.byteskwargs(opts)
7380 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7360 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7381 displayer.show(repo[b'tip'])
7361 displayer.show(repo[b'tip'])
7382 displayer.close()
7362 displayer.close()
7383
7363
7384
7364
7385 @command(
7365 @command(
7386 b'unbundle',
7366 b'unbundle',
7387 [
7367 [
7388 (
7368 (
7389 b'u',
7369 b'u',
7390 b'update',
7370 b'update',
7391 None,
7371 None,
7392 _(b'update to new branch head if changesets were unbundled'),
7372 _(b'update to new branch head if changesets were unbundled'),
7393 )
7373 )
7394 ],
7374 ],
7395 _(b'[-u] FILE...'),
7375 _(b'[-u] FILE...'),
7396 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7376 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7397 )
7377 )
7398 def unbundle(ui, repo, fname1, *fnames, **opts):
7378 def unbundle(ui, repo, fname1, *fnames, **opts):
7399 """apply one or more bundle files
7379 """apply one or more bundle files
7400
7380
7401 Apply one or more bundle files generated by :hg:`bundle`.
7381 Apply one or more bundle files generated by :hg:`bundle`.
7402
7382
7403 Returns 0 on success, 1 if an update has unresolved files.
7383 Returns 0 on success, 1 if an update has unresolved files.
7404 """
7384 """
7405 fnames = (fname1,) + fnames
7385 fnames = (fname1,) + fnames
7406
7386
7407 with repo.lock():
7387 with repo.lock():
7408 for fname in fnames:
7388 for fname in fnames:
7409 f = hg.openpath(ui, fname)
7389 f = hg.openpath(ui, fname)
7410 gen = exchange.readbundle(ui, f, fname)
7390 gen = exchange.readbundle(ui, f, fname)
7411 if isinstance(gen, streamclone.streamcloneapplier):
7391 if isinstance(gen, streamclone.streamcloneapplier):
7412 raise error.Abort(
7392 raise error.Abort(
7413 _(
7393 _(
7414 b'packed bundles cannot be applied with '
7394 b'packed bundles cannot be applied with '
7415 b'"hg unbundle"'
7395 b'"hg unbundle"'
7416 ),
7396 ),
7417 hint=_(b'use "hg debugapplystreamclonebundle"'),
7397 hint=_(b'use "hg debugapplystreamclonebundle"'),
7418 )
7398 )
7419 url = b'bundle:' + fname
7399 url = b'bundle:' + fname
7420 try:
7400 try:
7421 txnname = b'unbundle'
7401 txnname = b'unbundle'
7422 if not isinstance(gen, bundle2.unbundle20):
7402 if not isinstance(gen, bundle2.unbundle20):
7423 txnname = b'unbundle\n%s' % util.hidepassword(url)
7403 txnname = b'unbundle\n%s' % util.hidepassword(url)
7424 with repo.transaction(txnname) as tr:
7404 with repo.transaction(txnname) as tr:
7425 op = bundle2.applybundle(
7405 op = bundle2.applybundle(
7426 repo, gen, tr, source=b'unbundle', url=url
7406 repo, gen, tr, source=b'unbundle', url=url
7427 )
7407 )
7428 except error.BundleUnknownFeatureError as exc:
7408 except error.BundleUnknownFeatureError as exc:
7429 raise error.Abort(
7409 raise error.Abort(
7430 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7410 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7431 hint=_(
7411 hint=_(
7432 b"see https://mercurial-scm.org/"
7412 b"see https://mercurial-scm.org/"
7433 b"wiki/BundleFeature for more "
7413 b"wiki/BundleFeature for more "
7434 b"information"
7414 b"information"
7435 ),
7415 ),
7436 )
7416 )
7437 modheads = bundle2.combinechangegroupresults(op)
7417 modheads = bundle2.combinechangegroupresults(op)
7438
7418
7439 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7419 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7440
7420
7441
7421
7442 @command(
7422 @command(
7443 b'unshelve',
7423 b'unshelve',
7444 [
7424 [
7445 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7425 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7446 (
7426 (
7447 b'c',
7427 b'c',
7448 b'continue',
7428 b'continue',
7449 None,
7429 None,
7450 _(b'continue an incomplete unshelve operation'),
7430 _(b'continue an incomplete unshelve operation'),
7451 ),
7431 ),
7452 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7432 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7453 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7433 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7454 (
7434 (
7455 b'n',
7435 b'n',
7456 b'name',
7436 b'name',
7457 b'',
7437 b'',
7458 _(b'restore shelved change with given name'),
7438 _(b'restore shelved change with given name'),
7459 _(b'NAME'),
7439 _(b'NAME'),
7460 ),
7440 ),
7461 (b't', b'tool', b'', _(b'specify merge tool')),
7441 (b't', b'tool', b'', _(b'specify merge tool')),
7462 (
7442 (
7463 b'',
7443 b'',
7464 b'date',
7444 b'date',
7465 b'',
7445 b'',
7466 _(b'set date for temporary commits (DEPRECATED)'),
7446 _(b'set date for temporary commits (DEPRECATED)'),
7467 _(b'DATE'),
7447 _(b'DATE'),
7468 ),
7448 ),
7469 ],
7449 ],
7470 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7450 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7471 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7451 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7472 )
7452 )
7473 def unshelve(ui, repo, *shelved, **opts):
7453 def unshelve(ui, repo, *shelved, **opts):
7474 """restore a shelved change to the working directory
7454 """restore a shelved change to the working directory
7475
7455
7476 This command accepts an optional name of a shelved change to
7456 This command accepts an optional name of a shelved change to
7477 restore. If none is given, the most recent shelved change is used.
7457 restore. If none is given, the most recent shelved change is used.
7478
7458
7479 If a shelved change is applied successfully, the bundle that
7459 If a shelved change is applied successfully, the bundle that
7480 contains the shelved changes is moved to a backup location
7460 contains the shelved changes is moved to a backup location
7481 (.hg/shelve-backup).
7461 (.hg/shelve-backup).
7482
7462
7483 Since you can restore a shelved change on top of an arbitrary
7463 Since you can restore a shelved change on top of an arbitrary
7484 commit, it is possible that unshelving will result in a conflict
7464 commit, it is possible that unshelving will result in a conflict
7485 between your changes and the commits you are unshelving onto. If
7465 between your changes and the commits you are unshelving onto. If
7486 this occurs, you must resolve the conflict, then use
7466 this occurs, you must resolve the conflict, then use
7487 ``--continue`` to complete the unshelve operation. (The bundle
7467 ``--continue`` to complete the unshelve operation. (The bundle
7488 will not be moved until you successfully complete the unshelve.)
7468 will not be moved until you successfully complete the unshelve.)
7489
7469
7490 (Alternatively, you can use ``--abort`` to abandon an unshelve
7470 (Alternatively, you can use ``--abort`` to abandon an unshelve
7491 that causes a conflict. This reverts the unshelved changes, and
7471 that causes a conflict. This reverts the unshelved changes, and
7492 leaves the bundle in place.)
7472 leaves the bundle in place.)
7493
7473
7494 If bare shelved change (without interactive, include and exclude
7474 If bare shelved change (without interactive, include and exclude
7495 option) was done on newly created branch it would restore branch
7475 option) was done on newly created branch it would restore branch
7496 information to the working directory.
7476 information to the working directory.
7497
7477
7498 After a successful unshelve, the shelved changes are stored in a
7478 After a successful unshelve, the shelved changes are stored in a
7499 backup directory. Only the N most recent backups are kept. N
7479 backup directory. Only the N most recent backups are kept. N
7500 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7480 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7501 configuration option.
7481 configuration option.
7502
7482
7503 .. container:: verbose
7483 .. container:: verbose
7504
7484
7505 Timestamp in seconds is used to decide order of backups. More
7485 Timestamp in seconds is used to decide order of backups. More
7506 than ``maxbackups`` backups are kept, if same timestamp
7486 than ``maxbackups`` backups are kept, if same timestamp
7507 prevents from deciding exact order of them, for safety.
7487 prevents from deciding exact order of them, for safety.
7508
7488
7509 Selected changes can be unshelved with ``--interactive`` flag.
7489 Selected changes can be unshelved with ``--interactive`` flag.
7510 The working directory is updated with the selected changes, and
7490 The working directory is updated with the selected changes, and
7511 only the unselected changes remain shelved.
7491 only the unselected changes remain shelved.
7512 Note: The whole shelve is applied to working directory first before
7492 Note: The whole shelve is applied to working directory first before
7513 running interactively. So, this will bring up all the conflicts between
7493 running interactively. So, this will bring up all the conflicts between
7514 working directory and the shelve, irrespective of which changes will be
7494 working directory and the shelve, irrespective of which changes will be
7515 unshelved.
7495 unshelved.
7516 """
7496 """
7517 with repo.wlock():
7497 with repo.wlock():
7518 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7498 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7519
7499
7520
7500
7521 statemod.addunfinished(
7501 statemod.addunfinished(
7522 b'unshelve',
7502 b'unshelve',
7523 fname=b'shelvedstate',
7503 fname=b'shelvedstate',
7524 continueflag=True,
7504 continueflag=True,
7525 abortfunc=shelvemod.hgabortunshelve,
7505 abortfunc=shelvemod.hgabortunshelve,
7526 continuefunc=shelvemod.hgcontinueunshelve,
7506 continuefunc=shelvemod.hgcontinueunshelve,
7527 cmdmsg=_(b'unshelve already in progress'),
7507 cmdmsg=_(b'unshelve already in progress'),
7528 )
7508 )
7529
7509
7530
7510
7531 @command(
7511 @command(
7532 b'update|up|checkout|co',
7512 b'update|up|checkout|co',
7533 [
7513 [
7534 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7514 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7535 (b'c', b'check', None, _(b'require clean working directory')),
7515 (b'c', b'check', None, _(b'require clean working directory')),
7536 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7516 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7537 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7517 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7538 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7518 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7539 ]
7519 ]
7540 + mergetoolopts,
7520 + mergetoolopts,
7541 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7521 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7542 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7522 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7543 helpbasic=True,
7523 helpbasic=True,
7544 )
7524 )
7545 def update(ui, repo, node=None, **opts):
7525 def update(ui, repo, node=None, **opts):
7546 """update working directory (or switch revisions)
7526 """update working directory (or switch revisions)
7547
7527
7548 Update the repository's working directory to the specified
7528 Update the repository's working directory to the specified
7549 changeset. If no changeset is specified, update to the tip of the
7529 changeset. If no changeset is specified, update to the tip of the
7550 current named branch and move the active bookmark (see :hg:`help
7530 current named branch and move the active bookmark (see :hg:`help
7551 bookmarks`).
7531 bookmarks`).
7552
7532
7553 Update sets the working directory's parent revision to the specified
7533 Update sets the working directory's parent revision to the specified
7554 changeset (see :hg:`help parents`).
7534 changeset (see :hg:`help parents`).
7555
7535
7556 If the changeset is not a descendant or ancestor of the working
7536 If the changeset is not a descendant or ancestor of the working
7557 directory's parent and there are uncommitted changes, the update is
7537 directory's parent and there are uncommitted changes, the update is
7558 aborted. With the -c/--check option, the working directory is checked
7538 aborted. With the -c/--check option, the working directory is checked
7559 for uncommitted changes; if none are found, the working directory is
7539 for uncommitted changes; if none are found, the working directory is
7560 updated to the specified changeset.
7540 updated to the specified changeset.
7561
7541
7562 .. container:: verbose
7542 .. container:: verbose
7563
7543
7564 The -C/--clean, -c/--check, and -m/--merge options control what
7544 The -C/--clean, -c/--check, and -m/--merge options control what
7565 happens if the working directory contains uncommitted changes.
7545 happens if the working directory contains uncommitted changes.
7566 At most of one of them can be specified.
7546 At most of one of them can be specified.
7567
7547
7568 1. If no option is specified, and if
7548 1. If no option is specified, and if
7569 the requested changeset is an ancestor or descendant of
7549 the requested changeset is an ancestor or descendant of
7570 the working directory's parent, the uncommitted changes
7550 the working directory's parent, the uncommitted changes
7571 are merged into the requested changeset and the merged
7551 are merged into the requested changeset and the merged
7572 result is left uncommitted. If the requested changeset is
7552 result is left uncommitted. If the requested changeset is
7573 not an ancestor or descendant (that is, it is on another
7553 not an ancestor or descendant (that is, it is on another
7574 branch), the update is aborted and the uncommitted changes
7554 branch), the update is aborted and the uncommitted changes
7575 are preserved.
7555 are preserved.
7576
7556
7577 2. With the -m/--merge option, the update is allowed even if the
7557 2. With the -m/--merge option, the update is allowed even if the
7578 requested changeset is not an ancestor or descendant of
7558 requested changeset is not an ancestor or descendant of
7579 the working directory's parent.
7559 the working directory's parent.
7580
7560
7581 3. With the -c/--check option, the update is aborted and the
7561 3. With the -c/--check option, the update is aborted and the
7582 uncommitted changes are preserved.
7562 uncommitted changes are preserved.
7583
7563
7584 4. With the -C/--clean option, uncommitted changes are discarded and
7564 4. With the -C/--clean option, uncommitted changes are discarded and
7585 the working directory is updated to the requested changeset.
7565 the working directory is updated to the requested changeset.
7586
7566
7587 To cancel an uncommitted merge (and lose your changes), use
7567 To cancel an uncommitted merge (and lose your changes), use
7588 :hg:`merge --abort`.
7568 :hg:`merge --abort`.
7589
7569
7590 Use null as the changeset to remove the working directory (like
7570 Use null as the changeset to remove the working directory (like
7591 :hg:`clone -U`).
7571 :hg:`clone -U`).
7592
7572
7593 If you want to revert just one file to an older revision, use
7573 If you want to revert just one file to an older revision, use
7594 :hg:`revert [-r REV] NAME`.
7574 :hg:`revert [-r REV] NAME`.
7595
7575
7596 See :hg:`help dates` for a list of formats valid for -d/--date.
7576 See :hg:`help dates` for a list of formats valid for -d/--date.
7597
7577
7598 Returns 0 on success, 1 if there are unresolved files.
7578 Returns 0 on success, 1 if there are unresolved files.
7599 """
7579 """
7600 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7580 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7601 rev = opts.get('rev')
7581 rev = opts.get('rev')
7602 date = opts.get('date')
7582 date = opts.get('date')
7603 clean = opts.get('clean')
7583 clean = opts.get('clean')
7604 check = opts.get('check')
7584 check = opts.get('check')
7605 merge = opts.get('merge')
7585 merge = opts.get('merge')
7606 if rev and node:
7586 if rev and node:
7607 raise error.Abort(_(b"please specify just one revision"))
7587 raise error.Abort(_(b"please specify just one revision"))
7608
7588
7609 if ui.configbool(b'commands', b'update.requiredest'):
7589 if ui.configbool(b'commands', b'update.requiredest'):
7610 if not node and not rev and not date:
7590 if not node and not rev and not date:
7611 raise error.Abort(
7591 raise error.Abort(
7612 _(b'you must specify a destination'),
7592 _(b'you must specify a destination'),
7613 hint=_(b'for example: hg update ".::"'),
7593 hint=_(b'for example: hg update ".::"'),
7614 )
7594 )
7615
7595
7616 if rev is None or rev == b'':
7596 if rev is None or rev == b'':
7617 rev = node
7597 rev = node
7618
7598
7619 if date and rev is not None:
7599 if date and rev is not None:
7620 raise error.Abort(_(b"you can't specify a revision and a date"))
7600 raise error.Abort(_(b"you can't specify a revision and a date"))
7621
7601
7622 updatecheck = None
7602 updatecheck = None
7623 if check:
7603 if check:
7624 updatecheck = b'abort'
7604 updatecheck = b'abort'
7625 elif merge:
7605 elif merge:
7626 updatecheck = b'none'
7606 updatecheck = b'none'
7627
7607
7628 with repo.wlock():
7608 with repo.wlock():
7629 cmdutil.clearunfinished(repo)
7609 cmdutil.clearunfinished(repo)
7630 if date:
7610 if date:
7631 rev = cmdutil.finddate(ui, repo, date)
7611 rev = cmdutil.finddate(ui, repo, date)
7632
7612
7633 # if we defined a bookmark, we have to remember the original name
7613 # if we defined a bookmark, we have to remember the original name
7634 brev = rev
7614 brev = rev
7635 if rev:
7615 if rev:
7636 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7616 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7637 ctx = scmutil.revsingle(repo, rev, default=None)
7617 ctx = scmutil.revsingle(repo, rev, default=None)
7638 rev = ctx.rev()
7618 rev = ctx.rev()
7639 hidden = ctx.hidden()
7619 hidden = ctx.hidden()
7640 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7620 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7641 with ui.configoverride(overrides, b'update'):
7621 with ui.configoverride(overrides, b'update'):
7642 ret = hg.updatetotally(
7622 ret = hg.updatetotally(
7643 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7623 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7644 )
7624 )
7645 if hidden:
7625 if hidden:
7646 ctxstr = ctx.hex()[:12]
7626 ctxstr = ctx.hex()[:12]
7647 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7627 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7648
7628
7649 if ctx.obsolete():
7629 if ctx.obsolete():
7650 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7630 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7651 ui.warn(b"(%s)\n" % obsfatemsg)
7631 ui.warn(b"(%s)\n" % obsfatemsg)
7652 return ret
7632 return ret
7653
7633
7654
7634
7655 @command(
7635 @command(
7656 b'verify',
7636 b'verify',
7657 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7637 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7658 helpcategory=command.CATEGORY_MAINTENANCE,
7638 helpcategory=command.CATEGORY_MAINTENANCE,
7659 )
7639 )
7660 def verify(ui, repo, **opts):
7640 def verify(ui, repo, **opts):
7661 """verify the integrity of the repository
7641 """verify the integrity of the repository
7662
7642
7663 Verify the integrity of the current repository.
7643 Verify the integrity of the current repository.
7664
7644
7665 This will perform an extensive check of the repository's
7645 This will perform an extensive check of the repository's
7666 integrity, validating the hashes and checksums of each entry in
7646 integrity, validating the hashes and checksums of each entry in
7667 the changelog, manifest, and tracked files, as well as the
7647 the changelog, manifest, and tracked files, as well as the
7668 integrity of their crosslinks and indices.
7648 integrity of their crosslinks and indices.
7669
7649
7670 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7650 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7671 for more information about recovery from corruption of the
7651 for more information about recovery from corruption of the
7672 repository.
7652 repository.
7673
7653
7674 Returns 0 on success, 1 if errors are encountered.
7654 Returns 0 on success, 1 if errors are encountered.
7675 """
7655 """
7676 opts = pycompat.byteskwargs(opts)
7656 opts = pycompat.byteskwargs(opts)
7677
7657
7678 level = None
7658 level = None
7679 if opts[b'full']:
7659 if opts[b'full']:
7680 level = verifymod.VERIFY_FULL
7660 level = verifymod.VERIFY_FULL
7681 return hg.verify(repo, level)
7661 return hg.verify(repo, level)
7682
7662
7683
7663
7684 @command(
7664 @command(
7685 b'version',
7665 b'version',
7686 [] + formatteropts,
7666 [] + formatteropts,
7687 helpcategory=command.CATEGORY_HELP,
7667 helpcategory=command.CATEGORY_HELP,
7688 norepo=True,
7668 norepo=True,
7689 intents={INTENT_READONLY},
7669 intents={INTENT_READONLY},
7690 )
7670 )
7691 def version_(ui, **opts):
7671 def version_(ui, **opts):
7692 """output version and copyright information
7672 """output version and copyright information
7693
7673
7694 .. container:: verbose
7674 .. container:: verbose
7695
7675
7696 Template:
7676 Template:
7697
7677
7698 The following keywords are supported. See also :hg:`help templates`.
7678 The following keywords are supported. See also :hg:`help templates`.
7699
7679
7700 :extensions: List of extensions.
7680 :extensions: List of extensions.
7701 :ver: String. Version number.
7681 :ver: String. Version number.
7702
7682
7703 And each entry of ``{extensions}`` provides the following sub-keywords
7683 And each entry of ``{extensions}`` provides the following sub-keywords
7704 in addition to ``{ver}``.
7684 in addition to ``{ver}``.
7705
7685
7706 :bundled: Boolean. True if included in the release.
7686 :bundled: Boolean. True if included in the release.
7707 :name: String. Extension name.
7687 :name: String. Extension name.
7708 """
7688 """
7709 opts = pycompat.byteskwargs(opts)
7689 opts = pycompat.byteskwargs(opts)
7710 if ui.verbose:
7690 if ui.verbose:
7711 ui.pager(b'version')
7691 ui.pager(b'version')
7712 fm = ui.formatter(b"version", opts)
7692 fm = ui.formatter(b"version", opts)
7713 fm.startitem()
7693 fm.startitem()
7714 fm.write(
7694 fm.write(
7715 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7695 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7716 )
7696 )
7717 license = _(
7697 license = _(
7718 b"(see https://mercurial-scm.org for more information)\n"
7698 b"(see https://mercurial-scm.org for more information)\n"
7719 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7699 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7720 b"This is free software; see the source for copying conditions. "
7700 b"This is free software; see the source for copying conditions. "
7721 b"There is NO\nwarranty; "
7701 b"There is NO\nwarranty; "
7722 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7702 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7723 )
7703 )
7724 if not ui.quiet:
7704 if not ui.quiet:
7725 fm.plain(license)
7705 fm.plain(license)
7726
7706
7727 if ui.verbose:
7707 if ui.verbose:
7728 fm.plain(_(b"\nEnabled extensions:\n\n"))
7708 fm.plain(_(b"\nEnabled extensions:\n\n"))
7729 # format names and versions into columns
7709 # format names and versions into columns
7730 names = []
7710 names = []
7731 vers = []
7711 vers = []
7732 isinternals = []
7712 isinternals = []
7733 for name, module in sorted(extensions.extensions()):
7713 for name, module in sorted(extensions.extensions()):
7734 names.append(name)
7714 names.append(name)
7735 vers.append(extensions.moduleversion(module) or None)
7715 vers.append(extensions.moduleversion(module) or None)
7736 isinternals.append(extensions.ismoduleinternal(module))
7716 isinternals.append(extensions.ismoduleinternal(module))
7737 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7717 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7738 if names:
7718 if names:
7739 namefmt = b" %%-%ds " % max(len(n) for n in names)
7719 namefmt = b" %%-%ds " % max(len(n) for n in names)
7740 places = [_(b"external"), _(b"internal")]
7720 places = [_(b"external"), _(b"internal")]
7741 for n, v, p in zip(names, vers, isinternals):
7721 for n, v, p in zip(names, vers, isinternals):
7742 fn.startitem()
7722 fn.startitem()
7743 fn.condwrite(ui.verbose, b"name", namefmt, n)
7723 fn.condwrite(ui.verbose, b"name", namefmt, n)
7744 if ui.verbose:
7724 if ui.verbose:
7745 fn.plain(b"%s " % places[p])
7725 fn.plain(b"%s " % places[p])
7746 fn.data(bundled=p)
7726 fn.data(bundled=p)
7747 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7727 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7748 if ui.verbose:
7728 if ui.verbose:
7749 fn.plain(b"\n")
7729 fn.plain(b"\n")
7750 fn.end()
7730 fn.end()
7751 fm.end()
7731 fm.end()
7752
7732
7753
7733
7754 def loadcmdtable(ui, name, cmdtable):
7734 def loadcmdtable(ui, name, cmdtable):
7755 """Load command functions from specified cmdtable
7735 """Load command functions from specified cmdtable
7756 """
7736 """
7757 overrides = [cmd for cmd in cmdtable if cmd in table]
7737 overrides = [cmd for cmd in cmdtable if cmd in table]
7758 if overrides:
7738 if overrides:
7759 ui.warn(
7739 ui.warn(
7760 _(b"extension '%s' overrides commands: %s\n")
7740 _(b"extension '%s' overrides commands: %s\n")
7761 % (name, b" ".join(overrides))
7741 % (name, b" ".join(overrides))
7762 )
7742 )
7763 table.update(cmdtable)
7743 table.update(cmdtable)
@@ -1,102 +1,129 b''
1 # grep.py - logic for history walk and grep
1 # grep.py - logic for history walk and grep
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
12
13 from .i18n import _
11
14
12 from . import (
15 from . import (
16 error,
13 pycompat,
17 pycompat,
14 scmutil,
18 scmutil,
15 util,
19 util,
16 )
20 )
17
21
18
22
19 def matchlines(body, regexp):
23 def matchlines(body, regexp):
20 begin = 0
24 begin = 0
21 linenum = 0
25 linenum = 0
22 while begin < len(body):
26 while begin < len(body):
23 match = regexp.search(body, begin)
27 match = regexp.search(body, begin)
24 if not match:
28 if not match:
25 break
29 break
26 mstart, mend = match.span()
30 mstart, mend = match.span()
27 linenum += body.count(b'\n', begin, mstart) + 1
31 linenum += body.count(b'\n', begin, mstart) + 1
28 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
32 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
29 begin = body.find(b'\n', mend) + 1 or len(body) + 1
33 begin = body.find(b'\n', mend) + 1 or len(body) + 1
30 lend = begin - 1
34 lend = begin - 1
31 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
35 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
32
36
33
37
34 class linestate(object):
38 class linestate(object):
35 def __init__(self, line, linenum, colstart, colend):
39 def __init__(self, line, linenum, colstart, colend):
36 self.line = line
40 self.line = line
37 self.linenum = linenum
41 self.linenum = linenum
38 self.colstart = colstart
42 self.colstart = colstart
39 self.colend = colend
43 self.colend = colend
40
44
41 def __hash__(self):
45 def __hash__(self):
42 return hash(self.line)
46 return hash(self.line)
43
47
44 def __eq__(self, other):
48 def __eq__(self, other):
45 return self.line == other.line
49 return self.line == other.line
46
50
47 def findpos(self, regexp):
51 def findpos(self, regexp):
48 """Iterate all (start, end) indices of matches"""
52 """Iterate all (start, end) indices of matches"""
49 yield self.colstart, self.colend
53 yield self.colstart, self.colend
50 p = self.colend
54 p = self.colend
51 while p < len(self.line):
55 while p < len(self.line):
52 m = regexp.search(self.line, p)
56 m = regexp.search(self.line, p)
53 if not m:
57 if not m:
54 break
58 break
55 if m.end() == p:
59 if m.end() == p:
56 p += 1
60 p += 1
57 else:
61 else:
58 yield m.span()
62 yield m.span()
59 p = m.end()
63 p = m.end()
60
64
61
65
62 def difflinestates(a, b):
66 def difflinestates(a, b):
63 sm = difflib.SequenceMatcher(None, a, b)
67 sm = difflib.SequenceMatcher(None, a, b)
64 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
68 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
65 if tag == 'insert':
69 if tag == 'insert':
66 for i in pycompat.xrange(blo, bhi):
70 for i in pycompat.xrange(blo, bhi):
67 yield (b'+', b[i])
71 yield (b'+', b[i])
68 elif tag == 'delete':
72 elif tag == 'delete':
69 for i in pycompat.xrange(alo, ahi):
73 for i in pycompat.xrange(alo, ahi):
70 yield (b'-', a[i])
74 yield (b'-', a[i])
71 elif tag == 'replace':
75 elif tag == 'replace':
72 for i in pycompat.xrange(alo, ahi):
76 for i in pycompat.xrange(alo, ahi):
73 yield (b'-', a[i])
77 yield (b'-', a[i])
74 for i in pycompat.xrange(blo, bhi):
78 for i in pycompat.xrange(blo, bhi):
75 yield (b'+', b[i])
79 yield (b'+', b[i])
76
80
77
81
78 class grepsearcher(object):
82 class grepsearcher(object):
79 """Search files and revisions for lines matching the given pattern"""
83 """Search files and revisions for lines matching the given pattern"""
80
84
81 def __init__(self, ui, repo, regexp):
85 def __init__(self, ui, repo, regexp):
82 self._ui = ui
86 self._ui = ui
83 self._repo = repo
87 self._repo = repo
84 self._regexp = regexp
88 self._regexp = regexp
85
89
86 self._getfile = util.lrucachefunc(repo.file)
90 self._getfile = util.lrucachefunc(repo.file)
87 self._getrenamed = scmutil.getrenamedfn(repo)
91 self._getrenamed = scmutil.getrenamedfn(repo)
88
92
89 self._matches = {}
93 self._matches = {}
90 self._copies = {}
94 self._copies = {}
91 self._skip = set()
95 self._skip = set()
92 self._revfiles = {}
96 self._revfiles = {}
93
97
94 def _grepbody(self, fn, rev, body):
98 def _grepbody(self, fn, rev, body):
95 self._matches[rev].setdefault(fn, [])
99 self._matches[rev].setdefault(fn, [])
96 m = self._matches[rev][fn]
100 m = self._matches[rev][fn]
97 if body is None:
101 if body is None:
98 return
102 return
99
103
100 for lnum, cstart, cend, line in matchlines(body, self._regexp):
104 for lnum, cstart, cend, line in matchlines(body, self._regexp):
101 s = linestate(line, lnum, cstart, cend)
105 s = linestate(line, lnum, cstart, cend)
102 m.append(s)
106 m.append(s)
107
108 def _readfile(self, ctx, fn):
109 rev = ctx.rev()
110 if rev is None:
111 fctx = ctx[fn]
112 try:
113 return fctx.data()
114 except IOError as e:
115 if e.errno != errno.ENOENT:
116 raise
117 else:
118 flog = self._getfile(fn)
119 fnode = ctx.filenode(fn)
120 try:
121 return flog.read(fnode)
122 except error.CensoredNodeError:
123 self._ui.warn(
124 _(
125 b'cannot search in censored file: '
126 b'%(filename)s:%(revnum)s\n'
127 )
128 % {b'filename': fn, b'revnum': pycompat.bytestr(rev)}
129 )
General Comments 0
You need to be logged in to leave comments. Login now