##// END OF EJS Templates
grep: move prep() to grepsearcher class
Yuya Nishihara -
r46292:c694b184 default
parent child Browse files
Show More
@@ -1,7743 +1,7695 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,
49 merge as mergemod,
48 merge as mergemod,
50 mergestate as mergestatemod,
49 mergestate as mergestatemod,
51 narrowspec,
50 narrowspec,
52 obsolete,
51 obsolete,
53 obsutil,
52 obsutil,
54 patch,
53 patch,
55 phases,
54 phases,
56 pycompat,
55 pycompat,
57 rcutil,
56 rcutil,
58 registrar,
57 registrar,
59 requirements,
58 requirements,
60 revsetlang,
59 revsetlang,
61 rewriteutil,
60 rewriteutil,
62 scmutil,
61 scmutil,
63 server,
62 server,
64 shelve as shelvemod,
63 shelve as shelvemod,
65 state as statemod,
64 state as statemod,
66 streamclone,
65 streamclone,
67 tags as tagsmod,
66 tags as tagsmod,
68 ui as uimod,
67 ui as uimod,
69 util,
68 util,
70 verify as verifymod,
69 verify as verifymod,
71 vfs as vfsmod,
70 vfs as vfsmod,
72 wireprotoserver,
71 wireprotoserver,
73 )
72 )
74 from .utils import (
73 from .utils import (
75 dateutil,
74 dateutil,
76 stringutil,
75 stringutil,
77 )
76 )
78
77
79 table = {}
78 table = {}
80 table.update(debugcommandsmod.command._table)
79 table.update(debugcommandsmod.command._table)
81
80
82 command = registrar.command(table)
81 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
84
83
85 # common command options
84 # common command options
86
85
87 globalopts = [
86 globalopts = [
88 (
87 (
89 b'R',
88 b'R',
90 b'repository',
89 b'repository',
91 b'',
90 b'',
92 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
92 _(b'REPO'),
94 ),
93 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
95 (
97 b'y',
96 b'y',
98 b'noninteractive',
97 b'noninteractive',
99 None,
98 None,
100 _(
99 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
101 ),
103 ),
102 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
105 (
107 b'',
106 b'',
108 b'color',
107 b'color',
109 b'',
108 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
110 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
112 _(b'TYPE'),
114 ),
113 ),
115 (
114 (
116 b'',
115 b'',
117 b'config',
116 b'config',
118 [],
117 [],
119 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
119 _(b'CONFIG'),
121 ),
120 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
124 (
123 (
125 b'',
124 b'',
126 b'encoding',
125 b'encoding',
127 encoding.encoding,
126 encoding.encoding,
128 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
129 _(b'ENCODE'),
128 _(b'ENCODE'),
130 ),
129 ),
131 (
130 (
132 b'',
131 b'',
133 b'encodingmode',
132 b'encodingmode',
134 encoding.encodingmode,
133 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
136 _(b'MODE'),
135 _(b'MODE'),
137 ),
136 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
143 (
145 b'',
144 b'',
146 b'pager',
145 b'pager',
147 b'auto',
146 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
148 _(b'TYPE'),
150 ),
149 ),
151 ]
150 ]
152
151
153 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
169
168
170 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
171
170
172
171
173 @command(
172 @command(
174 b'abort',
173 b'abort',
175 dryrunopts,
174 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
176 helpbasic=True,
178 )
177 )
179 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
181
180
182 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
184
183
185 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
186 """
185 """
187 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
188 if not abortstate:
190 raise error.Abort(_(b'no operation in progress'))
189 raise error.Abort(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
192 raise error.Abort(
191 raise error.Abort(
193 (
192 (
194 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
194 % (abortstate._opname)
196 ),
195 ),
197 hint=abortstate.hint(),
196 hint=abortstate.hint(),
198 )
197 )
199 if dryrun:
198 if dryrun:
200 ui.status(
199 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
201 )
203 return
202 return
204 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
205
204
206
205
207 @command(
206 @command(
208 b'add',
207 b'add',
209 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
211 helpbasic=True,
213 inferrepo=True,
212 inferrepo=True,
214 )
213 )
215 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
215 """add the specified files on the next commit
217
216
218 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
219 repository.
218 repository.
220
219
221 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
223
222
224 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
224 files matching ``.hgignore``).
226
225
227 .. container:: verbose
226 .. container:: verbose
228
227
229 Examples:
228 Examples:
230
229
231 - New (unknown) files are added
230 - New (unknown) files are added
232 automatically by :hg:`add`::
231 automatically by :hg:`add`::
233
232
234 $ ls
233 $ ls
235 foo.c
234 foo.c
236 $ hg status
235 $ hg status
237 ? foo.c
236 ? foo.c
238 $ hg add
237 $ hg add
239 adding foo.c
238 adding foo.c
240 $ hg status
239 $ hg status
241 A foo.c
240 A foo.c
242
241
243 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
244
243
245 $ ls
244 $ ls
246 bar.c foo.c
245 bar.c foo.c
247 $ hg status
246 $ hg status
248 ? bar.c
247 ? bar.c
249 ? foo.c
248 ? foo.c
250 $ hg add bar.c
249 $ hg add bar.c
251 $ hg status
250 $ hg status
252 A bar.c
251 A bar.c
253 ? foo.c
252 ? foo.c
254
253
255 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
256 """
255 """
257
256
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
260 return rejected and 1 or 0
262
261
263
262
264 @command(
263 @command(
265 b'addremove',
264 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
266 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
268 inferrepo=True,
270 )
269 )
271 def addremove(ui, repo, *pats, **opts):
270 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
271 """add all new files, delete all missing files
273
272
274 Add all new files and remove all missing files from the
273 Add all new files and remove all missing files from the
275 repository.
274 repository.
276
275
277 Unless names are given, new files are ignored if they match any of
276 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
277 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
278 effect at the next commit.
280
279
281 Use the -s/--similarity option to detect renamed files. This
280 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
281 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
282 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
283 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
284 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
285 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
286 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
287 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
288 identical files are detected.
290
289
291 .. container:: verbose
290 .. container:: verbose
292
291
293 Examples:
292 Examples:
294
293
295 - A number of files (bar.c and foo.c) are new,
294 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
295 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
296 from the repository::
298
297
299 $ ls
298 $ ls
300 bar.c foo.c
299 bar.c foo.c
301 $ hg status
300 $ hg status
302 ! foobar.c
301 ! foobar.c
303 ? bar.c
302 ? bar.c
304 ? foo.c
303 ? foo.c
305 $ hg addremove
304 $ hg addremove
306 adding bar.c
305 adding bar.c
307 adding foo.c
306 adding foo.c
308 removing foobar.c
307 removing foobar.c
309 $ hg status
308 $ hg status
310 A bar.c
309 A bar.c
311 A foo.c
310 A foo.c
312 R foobar.c
311 R foobar.c
313
312
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
314 Afterwards, it was edited slightly::
316
315
317 $ ls
316 $ ls
318 foo.c
317 foo.c
319 $ hg status
318 $ hg status
320 ! foobar.c
319 ! foobar.c
321 ? foo.c
320 ? foo.c
322 $ hg addremove --similarity 90
321 $ hg addremove --similarity 90
323 removing foobar.c
322 removing foobar.c
324 adding foo.c
323 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
324 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
325 $ hg status -C
327 A foo.c
326 A foo.c
328 foobar.c
327 foobar.c
329 R foobar.c
328 R foobar.c
330
329
331 Returns 0 if all files are successfully added.
330 Returns 0 if all files are successfully added.
332 """
331 """
333 opts = pycompat.byteskwargs(opts)
332 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
333 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
334 opts[b'similarity'] = b'100'
336 matcher = scmutil.match(repo[None], pats, opts)
335 matcher = scmutil.match(repo[None], pats, opts)
337 relative = scmutil.anypats(pats, opts)
336 relative = scmutil.anypats(pats, opts)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340
339
341
340
342 @command(
341 @command(
343 b'annotate|blame',
342 b'annotate|blame',
344 [
343 [
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (
345 (
347 b'',
346 b'',
348 b'follow',
347 b'follow',
349 None,
348 None,
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 ),
350 ),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'a', b'text', None, _(b'treat all files as text')),
352 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'f', b'file', None, _(b'list the filename')),
354 (b'f', b'file', None, _(b'list the filename')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
359 (
358 (
360 b'l',
359 b'l',
361 b'line-number',
360 b'line-number',
362 None,
361 None,
363 _(b'show line number at the first appearance'),
362 _(b'show line number at the first appearance'),
364 ),
363 ),
365 (
364 (
366 b'',
365 b'',
367 b'skip',
366 b'skip',
368 [],
367 [],
369 _(b'revset to not display (EXPERIMENTAL)'),
368 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'REV'),
369 _(b'REV'),
371 ),
370 ),
372 ]
371 ]
373 + diffwsopts
372 + diffwsopts
374 + walkopts
373 + walkopts
375 + formatteropts,
374 + formatteropts,
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpbasic=True,
377 helpbasic=True,
379 inferrepo=True,
378 inferrepo=True,
380 )
379 )
381 def annotate(ui, repo, *pats, **opts):
380 def annotate(ui, repo, *pats, **opts):
382 """show changeset information by line for each file
381 """show changeset information by line for each file
383
382
384 List changes in files, showing the revision id responsible for
383 List changes in files, showing the revision id responsible for
385 each line.
384 each line.
386
385
387 This command is useful for discovering when a change was made and
386 This command is useful for discovering when a change was made and
388 by whom.
387 by whom.
389
388
390 If you include --file, --user, or --date, the revision number is
389 If you include --file, --user, or --date, the revision number is
391 suppressed unless you also include --number.
390 suppressed unless you also include --number.
392
391
393 Without the -a/--text option, annotate will avoid processing files
392 Without the -a/--text option, annotate will avoid processing files
394 it detects as binary. With -a, annotate will annotate the file
393 it detects as binary. With -a, annotate will annotate the file
395 anyway, although the results will probably be neither useful
394 anyway, although the results will probably be neither useful
396 nor desirable.
395 nor desirable.
397
396
398 .. container:: verbose
397 .. container:: verbose
399
398
400 Template:
399 Template:
401
400
402 The following keywords are supported in addition to the common template
401 The following keywords are supported in addition to the common template
403 keywords and functions. See also :hg:`help templates`.
402 keywords and functions. See also :hg:`help templates`.
404
403
405 :lines: List of lines with annotation data.
404 :lines: List of lines with annotation data.
406 :path: String. Repository-absolute path of the specified file.
405 :path: String. Repository-absolute path of the specified file.
407
406
408 And each entry of ``{lines}`` provides the following sub-keywords in
407 And each entry of ``{lines}`` provides the following sub-keywords in
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410
409
411 :line: String. Line content.
410 :line: String. Line content.
412 :lineno: Integer. Line number at that revision.
411 :lineno: Integer. Line number at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
414
413
415 See :hg:`help templates.operators` for the list expansion syntax.
414 See :hg:`help templates.operators` for the list expansion syntax.
416
415
417 Returns 0 on success.
416 Returns 0 on success.
418 """
417 """
419 opts = pycompat.byteskwargs(opts)
418 opts = pycompat.byteskwargs(opts)
420 if not pats:
419 if not pats:
421 raise error.Abort(_(b'at least one filename or pattern is required'))
420 raise error.Abort(_(b'at least one filename or pattern is required'))
422
421
423 if opts.get(b'follow'):
422 if opts.get(b'follow'):
424 # --follow is deprecated and now just an alias for -f/--file
423 # --follow is deprecated and now just an alias for -f/--file
425 # to mimic the behavior of Mercurial before version 1.5
424 # to mimic the behavior of Mercurial before version 1.5
426 opts[b'file'] = True
425 opts[b'file'] = True
427
426
428 if (
427 if (
429 not opts.get(b'user')
428 not opts.get(b'user')
430 and not opts.get(b'changeset')
429 and not opts.get(b'changeset')
431 and not opts.get(b'date')
430 and not opts.get(b'date')
432 and not opts.get(b'file')
431 and not opts.get(b'file')
433 ):
432 ):
434 opts[b'number'] = True
433 opts[b'number'] = True
435
434
436 linenumber = opts.get(b'line_number') is not None
435 linenumber = opts.get(b'line_number') is not None
437 if (
436 if (
438 linenumber
437 linenumber
439 and (not opts.get(b'changeset'))
438 and (not opts.get(b'changeset'))
440 and (not opts.get(b'number'))
439 and (not opts.get(b'number'))
441 ):
440 ):
442 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
441 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
443
442
444 rev = opts.get(b'rev')
443 rev = opts.get(b'rev')
445 if rev:
444 if rev:
446 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
447 ctx = scmutil.revsingle(repo, rev)
446 ctx = scmutil.revsingle(repo, rev)
448
447
449 ui.pager(b'annotate')
448 ui.pager(b'annotate')
450 rootfm = ui.formatter(b'annotate', opts)
449 rootfm = ui.formatter(b'annotate', opts)
451 if ui.debugflag:
450 if ui.debugflag:
452 shorthex = pycompat.identity
451 shorthex = pycompat.identity
453 else:
452 else:
454
453
455 def shorthex(h):
454 def shorthex(h):
456 return h[:12]
455 return h[:12]
457
456
458 if ui.quiet:
457 if ui.quiet:
459 datefunc = dateutil.shortdate
458 datefunc = dateutil.shortdate
460 else:
459 else:
461 datefunc = dateutil.datestr
460 datefunc = dateutil.datestr
462 if ctx.rev() is None:
461 if ctx.rev() is None:
463 if opts.get(b'changeset'):
462 if opts.get(b'changeset'):
464 # omit "+" suffix which is appended to node hex
463 # omit "+" suffix which is appended to node hex
465 def formatrev(rev):
464 def formatrev(rev):
466 if rev == wdirrev:
465 if rev == wdirrev:
467 return b'%d' % ctx.p1().rev()
466 return b'%d' % ctx.p1().rev()
468 else:
467 else:
469 return b'%d' % rev
468 return b'%d' % rev
470
469
471 else:
470 else:
472
471
473 def formatrev(rev):
472 def formatrev(rev):
474 if rev == wdirrev:
473 if rev == wdirrev:
475 return b'%d+' % ctx.p1().rev()
474 return b'%d+' % ctx.p1().rev()
476 else:
475 else:
477 return b'%d ' % rev
476 return b'%d ' % rev
478
477
479 def formathex(h):
478 def formathex(h):
480 if h == wdirhex:
479 if h == wdirhex:
481 return b'%s+' % shorthex(hex(ctx.p1().node()))
480 return b'%s+' % shorthex(hex(ctx.p1().node()))
482 else:
481 else:
483 return b'%s ' % shorthex(h)
482 return b'%s ' % shorthex(h)
484
483
485 else:
484 else:
486 formatrev = b'%d'.__mod__
485 formatrev = b'%d'.__mod__
487 formathex = shorthex
486 formathex = shorthex
488
487
489 opmap = [
488 opmap = [
490 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
491 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
492 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
493 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
494 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
495 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
496 ]
495 ]
497 opnamemap = {
496 opnamemap = {
498 b'rev': b'number',
497 b'rev': b'number',
499 b'node': b'changeset',
498 b'node': b'changeset',
500 b'path': b'file',
499 b'path': b'file',
501 b'lineno': b'line_number',
500 b'lineno': b'line_number',
502 }
501 }
503
502
504 if rootfm.isplain():
503 if rootfm.isplain():
505
504
506 def makefunc(get, fmt):
505 def makefunc(get, fmt):
507 return lambda x: fmt(get(x))
506 return lambda x: fmt(get(x))
508
507
509 else:
508 else:
510
509
511 def makefunc(get, fmt):
510 def makefunc(get, fmt):
512 return get
511 return get
513
512
514 datahint = rootfm.datahint()
513 datahint = rootfm.datahint()
515 funcmap = [
514 funcmap = [
516 (makefunc(get, fmt), sep)
515 (makefunc(get, fmt), sep)
517 for fn, sep, get, fmt in opmap
516 for fn, sep, get, fmt in opmap
518 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
519 ]
518 ]
520 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
519 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
521 fields = b' '.join(
520 fields = b' '.join(
522 fn
521 fn
523 for fn, sep, get, fmt in opmap
522 for fn, sep, get, fmt in opmap
524 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
525 )
524 )
526
525
527 def bad(x, y):
526 def bad(x, y):
528 raise error.Abort(b"%s: %s" % (x, y))
527 raise error.Abort(b"%s: %s" % (x, y))
529
528
530 m = scmutil.match(ctx, pats, opts, badfn=bad)
529 m = scmutil.match(ctx, pats, opts, badfn=bad)
531
530
532 follow = not opts.get(b'no_follow')
531 follow = not opts.get(b'no_follow')
533 diffopts = patch.difffeatureopts(
532 diffopts = patch.difffeatureopts(
534 ui, opts, section=b'annotate', whitespace=True
533 ui, opts, section=b'annotate', whitespace=True
535 )
534 )
536 skiprevs = opts.get(b'skip')
535 skiprevs = opts.get(b'skip')
537 if skiprevs:
536 if skiprevs:
538 skiprevs = scmutil.revrange(repo, skiprevs)
537 skiprevs = scmutil.revrange(repo, skiprevs)
539
538
540 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
541 for abs in ctx.walk(m):
540 for abs in ctx.walk(m):
542 fctx = ctx[abs]
541 fctx = ctx[abs]
543 rootfm.startitem()
542 rootfm.startitem()
544 rootfm.data(path=abs)
543 rootfm.data(path=abs)
545 if not opts.get(b'text') and fctx.isbinary():
544 if not opts.get(b'text') and fctx.isbinary():
546 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
547 continue
546 continue
548
547
549 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
550 lines = fctx.annotate(
549 lines = fctx.annotate(
551 follow=follow, skiprevs=skiprevs, diffopts=diffopts
550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
552 )
551 )
553 if not lines:
552 if not lines:
554 fm.end()
553 fm.end()
555 continue
554 continue
556 formats = []
555 formats = []
557 pieces = []
556 pieces = []
558
557
559 for f, sep in funcmap:
558 for f, sep in funcmap:
560 l = [f(n) for n in lines]
559 l = [f(n) for n in lines]
561 if fm.isplain():
560 if fm.isplain():
562 sizes = [encoding.colwidth(x) for x in l]
561 sizes = [encoding.colwidth(x) for x in l]
563 ml = max(sizes)
562 ml = max(sizes)
564 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
563 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
565 else:
564 else:
566 formats.append([b'%s'] * len(l))
565 formats.append([b'%s'] * len(l))
567 pieces.append(l)
566 pieces.append(l)
568
567
569 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
570 fm.startitem()
569 fm.startitem()
571 fm.context(fctx=n.fctx)
570 fm.context(fctx=n.fctx)
572 fm.write(fields, b"".join(f), *p)
571 fm.write(fields, b"".join(f), *p)
573 if n.skip:
572 if n.skip:
574 fmt = b"* %s"
573 fmt = b"* %s"
575 else:
574 else:
576 fmt = b": %s"
575 fmt = b": %s"
577 fm.write(b'line', fmt, n.text)
576 fm.write(b'line', fmt, n.text)
578
577
579 if not lines[-1].text.endswith(b'\n'):
578 if not lines[-1].text.endswith(b'\n'):
580 fm.plain(b'\n')
579 fm.plain(b'\n')
581 fm.end()
580 fm.end()
582
581
583 rootfm.end()
582 rootfm.end()
584
583
585
584
586 @command(
585 @command(
587 b'archive',
586 b'archive',
588 [
587 [
589 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
588 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
590 (
589 (
591 b'p',
590 b'p',
592 b'prefix',
591 b'prefix',
593 b'',
592 b'',
594 _(b'directory prefix for files in archive'),
593 _(b'directory prefix for files in archive'),
595 _(b'PREFIX'),
594 _(b'PREFIX'),
596 ),
595 ),
597 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
596 (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')),
597 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
599 ]
598 ]
600 + subrepoopts
599 + subrepoopts
601 + walkopts,
600 + walkopts,
602 _(b'[OPTION]... DEST'),
601 _(b'[OPTION]... DEST'),
603 helpcategory=command.CATEGORY_IMPORT_EXPORT,
602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
604 )
603 )
605 def archive(ui, repo, dest, **opts):
604 def archive(ui, repo, dest, **opts):
606 '''create an unversioned archive of a repository revision
605 '''create an unversioned archive of a repository revision
607
606
608 By default, the revision used is the parent of the working
607 By default, the revision used is the parent of the working
609 directory; use -r/--rev to specify a different revision.
608 directory; use -r/--rev to specify a different revision.
610
609
611 The archive type is automatically detected based on file
610 The archive type is automatically detected based on file
612 extension (to override, use -t/--type).
611 extension (to override, use -t/--type).
613
612
614 .. container:: verbose
613 .. container:: verbose
615
614
616 Examples:
615 Examples:
617
616
618 - create a zip file containing the 1.0 release::
617 - create a zip file containing the 1.0 release::
619
618
620 hg archive -r 1.0 project-1.0.zip
619 hg archive -r 1.0 project-1.0.zip
621
620
622 - create a tarball excluding .hg files::
621 - create a tarball excluding .hg files::
623
622
624 hg archive project.tar.gz -X ".hg*"
623 hg archive project.tar.gz -X ".hg*"
625
624
626 Valid types are:
625 Valid types are:
627
626
628 :``files``: a directory full of files (default)
627 :``files``: a directory full of files (default)
629 :``tar``: tar archive, uncompressed
628 :``tar``: tar archive, uncompressed
630 :``tbz2``: tar archive, compressed using bzip2
629 :``tbz2``: tar archive, compressed using bzip2
631 :``tgz``: tar archive, compressed using gzip
630 :``tgz``: tar archive, compressed using gzip
632 :``txz``: tar archive, compressed using lzma (only in Python 3)
631 :``txz``: tar archive, compressed using lzma (only in Python 3)
633 :``uzip``: zip archive, uncompressed
632 :``uzip``: zip archive, uncompressed
634 :``zip``: zip archive, compressed using deflate
633 :``zip``: zip archive, compressed using deflate
635
634
636 The exact name of the destination archive or directory is given
635 The exact name of the destination archive or directory is given
637 using a format string; see :hg:`help export` for details.
636 using a format string; see :hg:`help export` for details.
638
637
639 Each member added to an archive file has a directory prefix
638 Each member added to an archive file has a directory prefix
640 prepended. Use -p/--prefix to specify a format string for the
639 prepended. Use -p/--prefix to specify a format string for the
641 prefix. The default is the basename of the archive, with suffixes
640 prefix. The default is the basename of the archive, with suffixes
642 removed.
641 removed.
643
642
644 Returns 0 on success.
643 Returns 0 on success.
645 '''
644 '''
646
645
647 opts = pycompat.byteskwargs(opts)
646 opts = pycompat.byteskwargs(opts)
648 rev = opts.get(b'rev')
647 rev = opts.get(b'rev')
649 if rev:
648 if rev:
650 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
651 ctx = scmutil.revsingle(repo, rev)
650 ctx = scmutil.revsingle(repo, rev)
652 if not ctx:
651 if not ctx:
653 raise error.Abort(_(b'no working directory: please specify a revision'))
652 raise error.Abort(_(b'no working directory: please specify a revision'))
654 node = ctx.node()
653 node = ctx.node()
655 dest = cmdutil.makefilename(ctx, dest)
654 dest = cmdutil.makefilename(ctx, dest)
656 if os.path.realpath(dest) == repo.root:
655 if os.path.realpath(dest) == repo.root:
657 raise error.Abort(_(b'repository root cannot be destination'))
656 raise error.Abort(_(b'repository root cannot be destination'))
658
657
659 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
658 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
660 prefix = opts.get(b'prefix')
659 prefix = opts.get(b'prefix')
661
660
662 if dest == b'-':
661 if dest == b'-':
663 if kind == b'files':
662 if kind == b'files':
664 raise error.Abort(_(b'cannot archive plain files to stdout'))
663 raise error.Abort(_(b'cannot archive plain files to stdout'))
665 dest = cmdutil.makefileobj(ctx, dest)
664 dest = cmdutil.makefileobj(ctx, dest)
666 if not prefix:
665 if not prefix:
667 prefix = os.path.basename(repo.root) + b'-%h'
666 prefix = os.path.basename(repo.root) + b'-%h'
668
667
669 prefix = cmdutil.makefilename(ctx, prefix)
668 prefix = cmdutil.makefilename(ctx, prefix)
670 match = scmutil.match(ctx, [], opts)
669 match = scmutil.match(ctx, [], opts)
671 archival.archive(
670 archival.archive(
672 repo,
671 repo,
673 dest,
672 dest,
674 node,
673 node,
675 kind,
674 kind,
676 not opts.get(b'no_decode'),
675 not opts.get(b'no_decode'),
677 match,
676 match,
678 prefix,
677 prefix,
679 subrepos=opts.get(b'subrepos'),
678 subrepos=opts.get(b'subrepos'),
680 )
679 )
681
680
682
681
683 @command(
682 @command(
684 b'backout',
683 b'backout',
685 [
684 [
686 (
685 (
687 b'',
686 b'',
688 b'merge',
687 b'merge',
689 None,
688 None,
690 _(b'merge with old dirstate parent after backout'),
689 _(b'merge with old dirstate parent after backout'),
691 ),
690 ),
692 (
691 (
693 b'',
692 b'',
694 b'commit',
693 b'commit',
695 None,
694 None,
696 _(b'commit if no conflicts were encountered (DEPRECATED)'),
695 _(b'commit if no conflicts were encountered (DEPRECATED)'),
697 ),
696 ),
698 (b'', b'no-commit', None, _(b'do not commit')),
697 (b'', b'no-commit', None, _(b'do not commit')),
699 (
698 (
700 b'',
699 b'',
701 b'parent',
700 b'parent',
702 b'',
701 b'',
703 _(b'parent to choose when backing out merge (DEPRECATED)'),
702 _(b'parent to choose when backing out merge (DEPRECATED)'),
704 _(b'REV'),
703 _(b'REV'),
705 ),
704 ),
706 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
705 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
707 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
706 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
708 ]
707 ]
709 + mergetoolopts
708 + mergetoolopts
710 + walkopts
709 + walkopts
711 + commitopts
710 + commitopts
712 + commitopts2,
711 + commitopts2,
713 _(b'[OPTION]... [-r] REV'),
712 _(b'[OPTION]... [-r] REV'),
714 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
713 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
715 )
714 )
716 def backout(ui, repo, node=None, rev=None, **opts):
715 def backout(ui, repo, node=None, rev=None, **opts):
717 '''reverse effect of earlier changeset
716 '''reverse effect of earlier changeset
718
717
719 Prepare a new changeset with the effect of REV undone in the
718 Prepare a new changeset with the effect of REV undone in the
720 current working directory. If no conflicts were encountered,
719 current working directory. If no conflicts were encountered,
721 it will be committed immediately.
720 it will be committed immediately.
722
721
723 If REV is the parent of the working directory, then this new changeset
722 If REV is the parent of the working directory, then this new changeset
724 is committed automatically (unless --no-commit is specified).
723 is committed automatically (unless --no-commit is specified).
725
724
726 .. note::
725 .. note::
727
726
728 :hg:`backout` cannot be used to fix either an unwanted or
727 :hg:`backout` cannot be used to fix either an unwanted or
729 incorrect merge.
728 incorrect merge.
730
729
731 .. container:: verbose
730 .. container:: verbose
732
731
733 Examples:
732 Examples:
734
733
735 - Reverse the effect of the parent of the working directory.
734 - Reverse the effect of the parent of the working directory.
736 This backout will be committed immediately::
735 This backout will be committed immediately::
737
736
738 hg backout -r .
737 hg backout -r .
739
738
740 - Reverse the effect of previous bad revision 23::
739 - Reverse the effect of previous bad revision 23::
741
740
742 hg backout -r 23
741 hg backout -r 23
743
742
744 - Reverse the effect of previous bad revision 23 and
743 - Reverse the effect of previous bad revision 23 and
745 leave changes uncommitted::
744 leave changes uncommitted::
746
745
747 hg backout -r 23 --no-commit
746 hg backout -r 23 --no-commit
748 hg commit -m "Backout revision 23"
747 hg commit -m "Backout revision 23"
749
748
750 By default, the pending changeset will have one parent,
749 By default, the pending changeset will have one parent,
751 maintaining a linear history. With --merge, the pending
750 maintaining a linear history. With --merge, the pending
752 changeset will instead have two parents: the old parent of the
751 changeset will instead have two parents: the old parent of the
753 working directory and a new child of REV that simply undoes REV.
752 working directory and a new child of REV that simply undoes REV.
754
753
755 Before version 1.7, the behavior without --merge was equivalent
754 Before version 1.7, the behavior without --merge was equivalent
756 to specifying --merge followed by :hg:`update --clean .` to
755 to specifying --merge followed by :hg:`update --clean .` to
757 cancel the merge and leave the child of REV as a head to be
756 cancel the merge and leave the child of REV as a head to be
758 merged separately.
757 merged separately.
759
758
760 See :hg:`help dates` for a list of formats valid for -d/--date.
759 See :hg:`help dates` for a list of formats valid for -d/--date.
761
760
762 See :hg:`help revert` for a way to restore files to the state
761 See :hg:`help revert` for a way to restore files to the state
763 of another revision.
762 of another revision.
764
763
765 Returns 0 on success, 1 if nothing to backout or there are unresolved
764 Returns 0 on success, 1 if nothing to backout or there are unresolved
766 files.
765 files.
767 '''
766 '''
768 with repo.wlock(), repo.lock():
767 with repo.wlock(), repo.lock():
769 return _dobackout(ui, repo, node, rev, **opts)
768 return _dobackout(ui, repo, node, rev, **opts)
770
769
771
770
772 def _dobackout(ui, repo, node=None, rev=None, **opts):
771 def _dobackout(ui, repo, node=None, rev=None, **opts):
773 opts = pycompat.byteskwargs(opts)
772 opts = pycompat.byteskwargs(opts)
774 if opts.get(b'commit') and opts.get(b'no_commit'):
773 if opts.get(b'commit') and opts.get(b'no_commit'):
775 raise error.Abort(_(b"cannot use --commit with --no-commit"))
774 raise error.Abort(_(b"cannot use --commit with --no-commit"))
776 if opts.get(b'merge') and opts.get(b'no_commit'):
775 if opts.get(b'merge') and opts.get(b'no_commit'):
777 raise error.Abort(_(b"cannot use --merge with --no-commit"))
776 raise error.Abort(_(b"cannot use --merge with --no-commit"))
778
777
779 if rev and node:
778 if rev and node:
780 raise error.Abort(_(b"please specify just one revision"))
779 raise error.Abort(_(b"please specify just one revision"))
781
780
782 if not rev:
781 if not rev:
783 rev = node
782 rev = node
784
783
785 if not rev:
784 if not rev:
786 raise error.Abort(_(b"please specify a revision to backout"))
785 raise error.Abort(_(b"please specify a revision to backout"))
787
786
788 date = opts.get(b'date')
787 date = opts.get(b'date')
789 if date:
788 if date:
790 opts[b'date'] = dateutil.parsedate(date)
789 opts[b'date'] = dateutil.parsedate(date)
791
790
792 cmdutil.checkunfinished(repo)
791 cmdutil.checkunfinished(repo)
793 cmdutil.bailifchanged(repo)
792 cmdutil.bailifchanged(repo)
794 ctx = scmutil.revsingle(repo, rev)
793 ctx = scmutil.revsingle(repo, rev)
795 node = ctx.node()
794 node = ctx.node()
796
795
797 op1, op2 = repo.dirstate.parents()
796 op1, op2 = repo.dirstate.parents()
798 if not repo.changelog.isancestor(node, op1):
797 if not repo.changelog.isancestor(node, op1):
799 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
798 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
800
799
801 p1, p2 = repo.changelog.parents(node)
800 p1, p2 = repo.changelog.parents(node)
802 if p1 == nullid:
801 if p1 == nullid:
803 raise error.Abort(_(b'cannot backout a change with no parents'))
802 raise error.Abort(_(b'cannot backout a change with no parents'))
804 if p2 != nullid:
803 if p2 != nullid:
805 if not opts.get(b'parent'):
804 if not opts.get(b'parent'):
806 raise error.Abort(_(b'cannot backout a merge changeset'))
805 raise error.Abort(_(b'cannot backout a merge changeset'))
807 p = repo.lookup(opts[b'parent'])
806 p = repo.lookup(opts[b'parent'])
808 if p not in (p1, p2):
807 if p not in (p1, p2):
809 raise error.Abort(
808 raise error.Abort(
810 _(b'%s is not a parent of %s') % (short(p), short(node))
809 _(b'%s is not a parent of %s') % (short(p), short(node))
811 )
810 )
812 parent = p
811 parent = p
813 else:
812 else:
814 if opts.get(b'parent'):
813 if opts.get(b'parent'):
815 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
814 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
816 parent = p1
815 parent = p1
817
816
818 # the backout should appear on the same branch
817 # the backout should appear on the same branch
819 branch = repo.dirstate.branch()
818 branch = repo.dirstate.branch()
820 bheads = repo.branchheads(branch)
819 bheads = repo.branchheads(branch)
821 rctx = scmutil.revsingle(repo, hex(parent))
820 rctx = scmutil.revsingle(repo, hex(parent))
822 if not opts.get(b'merge') and op1 != node:
821 if not opts.get(b'merge') and op1 != node:
823 with dirstateguard.dirstateguard(repo, b'backout'):
822 with dirstateguard.dirstateguard(repo, b'backout'):
824 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
823 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
825 with ui.configoverride(overrides, b'backout'):
824 with ui.configoverride(overrides, b'backout'):
826 stats = mergemod.back_out(ctx, parent=repo[parent])
825 stats = mergemod.back_out(ctx, parent=repo[parent])
827 repo.setparents(op1, op2)
826 repo.setparents(op1, op2)
828 hg._showstats(repo, stats)
827 hg._showstats(repo, stats)
829 if stats.unresolvedcount:
828 if stats.unresolvedcount:
830 repo.ui.status(
829 repo.ui.status(
831 _(b"use 'hg resolve' to retry unresolved file merges\n")
830 _(b"use 'hg resolve' to retry unresolved file merges\n")
832 )
831 )
833 return 1
832 return 1
834 else:
833 else:
835 hg.clean(repo, node, show_stats=False)
834 hg.clean(repo, node, show_stats=False)
836 repo.dirstate.setbranch(branch)
835 repo.dirstate.setbranch(branch)
837 cmdutil.revert(ui, repo, rctx)
836 cmdutil.revert(ui, repo, rctx)
838
837
839 if opts.get(b'no_commit'):
838 if opts.get(b'no_commit'):
840 msg = _(b"changeset %s backed out, don't forget to commit.\n")
839 msg = _(b"changeset %s backed out, don't forget to commit.\n")
841 ui.status(msg % short(node))
840 ui.status(msg % short(node))
842 return 0
841 return 0
843
842
844 def commitfunc(ui, repo, message, match, opts):
843 def commitfunc(ui, repo, message, match, opts):
845 editform = b'backout'
844 editform = b'backout'
846 e = cmdutil.getcommiteditor(
845 e = cmdutil.getcommiteditor(
847 editform=editform, **pycompat.strkwargs(opts)
846 editform=editform, **pycompat.strkwargs(opts)
848 )
847 )
849 if not message:
848 if not message:
850 # we don't translate commit messages
849 # we don't translate commit messages
851 message = b"Backed out changeset %s" % short(node)
850 message = b"Backed out changeset %s" % short(node)
852 e = cmdutil.getcommiteditor(edit=True, editform=editform)
851 e = cmdutil.getcommiteditor(edit=True, editform=editform)
853 return repo.commit(
852 return repo.commit(
854 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
853 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
855 )
854 )
856
855
857 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
856 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
858 if not newnode:
857 if not newnode:
859 ui.status(_(b"nothing changed\n"))
858 ui.status(_(b"nothing changed\n"))
860 return 1
859 return 1
861 cmdutil.commitstatus(repo, newnode, branch, bheads)
860 cmdutil.commitstatus(repo, newnode, branch, bheads)
862
861
863 def nice(node):
862 def nice(node):
864 return b'%d:%s' % (repo.changelog.rev(node), short(node))
863 return b'%d:%s' % (repo.changelog.rev(node), short(node))
865
864
866 ui.status(
865 ui.status(
867 _(b'changeset %s backs out changeset %s\n')
866 _(b'changeset %s backs out changeset %s\n')
868 % (nice(repo.changelog.tip()), nice(node))
867 % (nice(repo.changelog.tip()), nice(node))
869 )
868 )
870 if opts.get(b'merge') and op1 != node:
869 if opts.get(b'merge') and op1 != node:
871 hg.clean(repo, op1, show_stats=False)
870 hg.clean(repo, op1, show_stats=False)
872 ui.status(
871 ui.status(
873 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
872 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
874 )
873 )
875 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
874 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
876 with ui.configoverride(overrides, b'backout'):
875 with ui.configoverride(overrides, b'backout'):
877 return hg.merge(repo[b'tip'])
876 return hg.merge(repo[b'tip'])
878 return 0
877 return 0
879
878
880
879
881 @command(
880 @command(
882 b'bisect',
881 b'bisect',
883 [
882 [
884 (b'r', b'reset', False, _(b'reset bisect state')),
883 (b'r', b'reset', False, _(b'reset bisect state')),
885 (b'g', b'good', False, _(b'mark changeset good')),
884 (b'g', b'good', False, _(b'mark changeset good')),
886 (b'b', b'bad', False, _(b'mark changeset bad')),
885 (b'b', b'bad', False, _(b'mark changeset bad')),
887 (b's', b'skip', False, _(b'skip testing changeset')),
886 (b's', b'skip', False, _(b'skip testing changeset')),
888 (b'e', b'extend', False, _(b'extend the bisect range')),
887 (b'e', b'extend', False, _(b'extend the bisect range')),
889 (
888 (
890 b'c',
889 b'c',
891 b'command',
890 b'command',
892 b'',
891 b'',
893 _(b'use command to check changeset state'),
892 _(b'use command to check changeset state'),
894 _(b'CMD'),
893 _(b'CMD'),
895 ),
894 ),
896 (b'U', b'noupdate', False, _(b'do not update to target')),
895 (b'U', b'noupdate', False, _(b'do not update to target')),
897 ],
896 ],
898 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
897 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
899 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
898 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
900 )
899 )
901 def bisect(
900 def bisect(
902 ui,
901 ui,
903 repo,
902 repo,
904 rev=None,
903 rev=None,
905 extra=None,
904 extra=None,
906 command=None,
905 command=None,
907 reset=None,
906 reset=None,
908 good=None,
907 good=None,
909 bad=None,
908 bad=None,
910 skip=None,
909 skip=None,
911 extend=None,
910 extend=None,
912 noupdate=None,
911 noupdate=None,
913 ):
912 ):
914 """subdivision search of changesets
913 """subdivision search of changesets
915
914
916 This command helps to find changesets which introduce problems. To
915 This command helps to find changesets which introduce problems. To
917 use, mark the earliest changeset you know exhibits the problem as
916 use, mark the earliest changeset you know exhibits the problem as
918 bad, then mark the latest changeset which is free from the problem
917 bad, then mark the latest changeset which is free from the problem
919 as good. Bisect will update your working directory to a revision
918 as good. Bisect will update your working directory to a revision
920 for testing (unless the -U/--noupdate option is specified). Once
919 for testing (unless the -U/--noupdate option is specified). Once
921 you have performed tests, mark the working directory as good or
920 you have performed tests, mark the working directory as good or
922 bad, and bisect will either update to another candidate changeset
921 bad, and bisect will either update to another candidate changeset
923 or announce that it has found the bad revision.
922 or announce that it has found the bad revision.
924
923
925 As a shortcut, you can also use the revision argument to mark a
924 As a shortcut, you can also use the revision argument to mark a
926 revision as good or bad without checking it out first.
925 revision as good or bad without checking it out first.
927
926
928 If you supply a command, it will be used for automatic bisection.
927 If you supply a command, it will be used for automatic bisection.
929 The environment variable HG_NODE will contain the ID of the
928 The environment variable HG_NODE will contain the ID of the
930 changeset being tested. The exit status of the command will be
929 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
930 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
931 means to skip the revision, 127 (command not found) will abort the
933 bisection, and any other non-zero exit status means the revision
932 bisection, and any other non-zero exit status means the revision
934 is bad.
933 is bad.
935
934
936 .. container:: verbose
935 .. container:: verbose
937
936
938 Some examples:
937 Some examples:
939
938
940 - start a bisection with known bad revision 34, and good revision 12::
939 - start a bisection with known bad revision 34, and good revision 12::
941
940
942 hg bisect --bad 34
941 hg bisect --bad 34
943 hg bisect --good 12
942 hg bisect --good 12
944
943
945 - advance the current bisection by marking current revision as good or
944 - advance the current bisection by marking current revision as good or
946 bad::
945 bad::
947
946
948 hg bisect --good
947 hg bisect --good
949 hg bisect --bad
948 hg bisect --bad
950
949
951 - mark the current revision, or a known revision, to be skipped (e.g. if
950 - mark the current revision, or a known revision, to be skipped (e.g. if
952 that revision is not usable because of another issue)::
951 that revision is not usable because of another issue)::
953
952
954 hg bisect --skip
953 hg bisect --skip
955 hg bisect --skip 23
954 hg bisect --skip 23
956
955
957 - skip all revisions that do not touch directories ``foo`` or ``bar``::
956 - skip all revisions that do not touch directories ``foo`` or ``bar``::
958
957
959 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
958 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
960
959
961 - forget the current bisection::
960 - forget the current bisection::
962
961
963 hg bisect --reset
962 hg bisect --reset
964
963
965 - use 'make && make tests' to automatically find the first broken
964 - use 'make && make tests' to automatically find the first broken
966 revision::
965 revision::
967
966
968 hg bisect --reset
967 hg bisect --reset
969 hg bisect --bad 34
968 hg bisect --bad 34
970 hg bisect --good 12
969 hg bisect --good 12
971 hg bisect --command "make && make tests"
970 hg bisect --command "make && make tests"
972
971
973 - see all changesets whose states are already known in the current
972 - see all changesets whose states are already known in the current
974 bisection::
973 bisection::
975
974
976 hg log -r "bisect(pruned)"
975 hg log -r "bisect(pruned)"
977
976
978 - see the changeset currently being bisected (especially useful
977 - see the changeset currently being bisected (especially useful
979 if running with -U/--noupdate)::
978 if running with -U/--noupdate)::
980
979
981 hg log -r "bisect(current)"
980 hg log -r "bisect(current)"
982
981
983 - see all changesets that took part in the current bisection::
982 - see all changesets that took part in the current bisection::
984
983
985 hg log -r "bisect(range)"
984 hg log -r "bisect(range)"
986
985
987 - you can even get a nice graph::
986 - you can even get a nice graph::
988
987
989 hg log --graph -r "bisect(range)"
988 hg log --graph -r "bisect(range)"
990
989
991 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
990 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
992
991
993 Returns 0 on success.
992 Returns 0 on success.
994 """
993 """
995 # backward compatibility
994 # backward compatibility
996 if rev in b"good bad reset init".split():
995 if rev in b"good bad reset init".split():
997 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
996 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
998 cmd, rev, extra = rev, extra, None
997 cmd, rev, extra = rev, extra, None
999 if cmd == b"good":
998 if cmd == b"good":
1000 good = True
999 good = True
1001 elif cmd == b"bad":
1000 elif cmd == b"bad":
1002 bad = True
1001 bad = True
1003 else:
1002 else:
1004 reset = True
1003 reset = True
1005 elif extra:
1004 elif extra:
1006 raise error.Abort(_(b'incompatible arguments'))
1005 raise error.Abort(_(b'incompatible arguments'))
1007
1006
1008 incompatibles = {
1007 incompatibles = {
1009 b'--bad': bad,
1008 b'--bad': bad,
1010 b'--command': bool(command),
1009 b'--command': bool(command),
1011 b'--extend': extend,
1010 b'--extend': extend,
1012 b'--good': good,
1011 b'--good': good,
1013 b'--reset': reset,
1012 b'--reset': reset,
1014 b'--skip': skip,
1013 b'--skip': skip,
1015 }
1014 }
1016
1015
1017 enabled = [x for x in incompatibles if incompatibles[x]]
1016 enabled = [x for x in incompatibles if incompatibles[x]]
1018
1017
1019 if len(enabled) > 1:
1018 if len(enabled) > 1:
1020 raise error.Abort(
1019 raise error.Abort(
1021 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1020 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1022 )
1021 )
1023
1022
1024 if reset:
1023 if reset:
1025 hbisect.resetstate(repo)
1024 hbisect.resetstate(repo)
1026 return
1025 return
1027
1026
1028 state = hbisect.load_state(repo)
1027 state = hbisect.load_state(repo)
1029
1028
1030 # update state
1029 # update state
1031 if good or bad or skip:
1030 if good or bad or skip:
1032 if rev:
1031 if rev:
1033 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1032 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1034 else:
1033 else:
1035 nodes = [repo.lookup(b'.')]
1034 nodes = [repo.lookup(b'.')]
1036 if good:
1035 if good:
1037 state[b'good'] += nodes
1036 state[b'good'] += nodes
1038 elif bad:
1037 elif bad:
1039 state[b'bad'] += nodes
1038 state[b'bad'] += nodes
1040 elif skip:
1039 elif skip:
1041 state[b'skip'] += nodes
1040 state[b'skip'] += nodes
1042 hbisect.save_state(repo, state)
1041 hbisect.save_state(repo, state)
1043 if not (state[b'good'] and state[b'bad']):
1042 if not (state[b'good'] and state[b'bad']):
1044 return
1043 return
1045
1044
1046 def mayupdate(repo, node, show_stats=True):
1045 def mayupdate(repo, node, show_stats=True):
1047 """common used update sequence"""
1046 """common used update sequence"""
1048 if noupdate:
1047 if noupdate:
1049 return
1048 return
1050 cmdutil.checkunfinished(repo)
1049 cmdutil.checkunfinished(repo)
1051 cmdutil.bailifchanged(repo)
1050 cmdutil.bailifchanged(repo)
1052 return hg.clean(repo, node, show_stats=show_stats)
1051 return hg.clean(repo, node, show_stats=show_stats)
1053
1052
1054 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1053 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1055
1054
1056 if command:
1055 if command:
1057 changesets = 1
1056 changesets = 1
1058 if noupdate:
1057 if noupdate:
1059 try:
1058 try:
1060 node = state[b'current'][0]
1059 node = state[b'current'][0]
1061 except LookupError:
1060 except LookupError:
1062 raise error.Abort(
1061 raise error.Abort(
1063 _(
1062 _(
1064 b'current bisect revision is unknown - '
1063 b'current bisect revision is unknown - '
1065 b'start a new bisect to fix'
1064 b'start a new bisect to fix'
1066 )
1065 )
1067 )
1066 )
1068 else:
1067 else:
1069 node, p2 = repo.dirstate.parents()
1068 node, p2 = repo.dirstate.parents()
1070 if p2 != nullid:
1069 if p2 != nullid:
1071 raise error.Abort(_(b'current bisect revision is a merge'))
1070 raise error.Abort(_(b'current bisect revision is a merge'))
1072 if rev:
1071 if rev:
1073 node = repo[scmutil.revsingle(repo, rev, node)].node()
1072 node = repo[scmutil.revsingle(repo, rev, node)].node()
1074 with hbisect.restore_state(repo, state, node):
1073 with hbisect.restore_state(repo, state, node):
1075 while changesets:
1074 while changesets:
1076 # update state
1075 # update state
1077 state[b'current'] = [node]
1076 state[b'current'] = [node]
1078 hbisect.save_state(repo, state)
1077 hbisect.save_state(repo, state)
1079 status = ui.system(
1078 status = ui.system(
1080 command,
1079 command,
1081 environ={b'HG_NODE': hex(node)},
1080 environ={b'HG_NODE': hex(node)},
1082 blockedtag=b'bisect_check',
1081 blockedtag=b'bisect_check',
1083 )
1082 )
1084 if status == 125:
1083 if status == 125:
1085 transition = b"skip"
1084 transition = b"skip"
1086 elif status == 0:
1085 elif status == 0:
1087 transition = b"good"
1086 transition = b"good"
1088 # status < 0 means process was killed
1087 # status < 0 means process was killed
1089 elif status == 127:
1088 elif status == 127:
1090 raise error.Abort(_(b"failed to execute %s") % command)
1089 raise error.Abort(_(b"failed to execute %s") % command)
1091 elif status < 0:
1090 elif status < 0:
1092 raise error.Abort(_(b"%s killed") % command)
1091 raise error.Abort(_(b"%s killed") % command)
1093 else:
1092 else:
1094 transition = b"bad"
1093 transition = b"bad"
1095 state[transition].append(node)
1094 state[transition].append(node)
1096 ctx = repo[node]
1095 ctx = repo[node]
1097 ui.status(
1096 ui.status(
1098 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1097 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1099 )
1098 )
1100 hbisect.checkstate(state)
1099 hbisect.checkstate(state)
1101 # bisect
1100 # bisect
1102 nodes, changesets, bgood = hbisect.bisect(repo, state)
1101 nodes, changesets, bgood = hbisect.bisect(repo, state)
1103 # update to next check
1102 # update to next check
1104 node = nodes[0]
1103 node = nodes[0]
1105 mayupdate(repo, node, show_stats=False)
1104 mayupdate(repo, node, show_stats=False)
1106 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1105 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1107 return
1106 return
1108
1107
1109 hbisect.checkstate(state)
1108 hbisect.checkstate(state)
1110
1109
1111 # actually bisect
1110 # actually bisect
1112 nodes, changesets, good = hbisect.bisect(repo, state)
1111 nodes, changesets, good = hbisect.bisect(repo, state)
1113 if extend:
1112 if extend:
1114 if not changesets:
1113 if not changesets:
1115 extendnode = hbisect.extendrange(repo, state, nodes, good)
1114 extendnode = hbisect.extendrange(repo, state, nodes, good)
1116 if extendnode is not None:
1115 if extendnode is not None:
1117 ui.write(
1116 ui.write(
1118 _(b"Extending search to changeset %d:%s\n")
1117 _(b"Extending search to changeset %d:%s\n")
1119 % (extendnode.rev(), extendnode)
1118 % (extendnode.rev(), extendnode)
1120 )
1119 )
1121 state[b'current'] = [extendnode.node()]
1120 state[b'current'] = [extendnode.node()]
1122 hbisect.save_state(repo, state)
1121 hbisect.save_state(repo, state)
1123 return mayupdate(repo, extendnode.node())
1122 return mayupdate(repo, extendnode.node())
1124 raise error.Abort(_(b"nothing to extend"))
1123 raise error.Abort(_(b"nothing to extend"))
1125
1124
1126 if changesets == 0:
1125 if changesets == 0:
1127 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1126 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1128 else:
1127 else:
1129 assert len(nodes) == 1 # only a single node can be tested next
1128 assert len(nodes) == 1 # only a single node can be tested next
1130 node = nodes[0]
1129 node = nodes[0]
1131 # compute the approximate number of remaining tests
1130 # compute the approximate number of remaining tests
1132 tests, size = 0, 2
1131 tests, size = 0, 2
1133 while size <= changesets:
1132 while size <= changesets:
1134 tests, size = tests + 1, size * 2
1133 tests, size = tests + 1, size * 2
1135 rev = repo.changelog.rev(node)
1134 rev = repo.changelog.rev(node)
1136 ui.write(
1135 ui.write(
1137 _(
1136 _(
1138 b"Testing changeset %d:%s "
1137 b"Testing changeset %d:%s "
1139 b"(%d changesets remaining, ~%d tests)\n"
1138 b"(%d changesets remaining, ~%d tests)\n"
1140 )
1139 )
1141 % (rev, short(node), changesets, tests)
1140 % (rev, short(node), changesets, tests)
1142 )
1141 )
1143 state[b'current'] = [node]
1142 state[b'current'] = [node]
1144 hbisect.save_state(repo, state)
1143 hbisect.save_state(repo, state)
1145 return mayupdate(repo, node)
1144 return mayupdate(repo, node)
1146
1145
1147
1146
1148 @command(
1147 @command(
1149 b'bookmarks|bookmark',
1148 b'bookmarks|bookmark',
1150 [
1149 [
1151 (b'f', b'force', False, _(b'force')),
1150 (b'f', b'force', False, _(b'force')),
1152 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1151 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1153 (b'd', b'delete', False, _(b'delete a given bookmark')),
1152 (b'd', b'delete', False, _(b'delete a given bookmark')),
1154 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1153 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1155 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1154 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1156 (b'l', b'list', False, _(b'list existing bookmarks')),
1155 (b'l', b'list', False, _(b'list existing bookmarks')),
1157 ]
1156 ]
1158 + formatteropts,
1157 + formatteropts,
1159 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1158 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1160 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1159 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1161 )
1160 )
1162 def bookmark(ui, repo, *names, **opts):
1161 def bookmark(ui, repo, *names, **opts):
1163 '''create a new bookmark or list existing bookmarks
1162 '''create a new bookmark or list existing bookmarks
1164
1163
1165 Bookmarks are labels on changesets to help track lines of development.
1164 Bookmarks are labels on changesets to help track lines of development.
1166 Bookmarks are unversioned and can be moved, renamed and deleted.
1165 Bookmarks are unversioned and can be moved, renamed and deleted.
1167 Deleting or moving a bookmark has no effect on the associated changesets.
1166 Deleting or moving a bookmark has no effect on the associated changesets.
1168
1167
1169 Creating or updating to a bookmark causes it to be marked as 'active'.
1168 Creating or updating to a bookmark causes it to be marked as 'active'.
1170 The active bookmark is indicated with a '*'.
1169 The active bookmark is indicated with a '*'.
1171 When a commit is made, the active bookmark will advance to the new commit.
1170 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.
1171 A plain :hg:`update` will also advance an active bookmark, if possible.
1173 Updating away from a bookmark will cause it to be deactivated.
1172 Updating away from a bookmark will cause it to be deactivated.
1174
1173
1175 Bookmarks can be pushed and pulled between repositories (see
1174 Bookmarks can be pushed and pulled between repositories (see
1176 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1175 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1177 diverged, a new 'divergent bookmark' of the form 'name@path' will
1176 diverged, a new 'divergent bookmark' of the form 'name@path' will
1178 be created. Using :hg:`merge` will resolve the divergence.
1177 be created. Using :hg:`merge` will resolve the divergence.
1179
1178
1180 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1179 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1181 the active bookmark's name.
1180 the active bookmark's name.
1182
1181
1183 A bookmark named '@' has the special property that :hg:`clone` will
1182 A bookmark named '@' has the special property that :hg:`clone` will
1184 check it out by default if it exists.
1183 check it out by default if it exists.
1185
1184
1186 .. container:: verbose
1185 .. container:: verbose
1187
1186
1188 Template:
1187 Template:
1189
1188
1190 The following keywords are supported in addition to the common template
1189 The following keywords are supported in addition to the common template
1191 keywords and functions such as ``{bookmark}``. See also
1190 keywords and functions such as ``{bookmark}``. See also
1192 :hg:`help templates`.
1191 :hg:`help templates`.
1193
1192
1194 :active: Boolean. True if the bookmark is active.
1193 :active: Boolean. True if the bookmark is active.
1195
1194
1196 Examples:
1195 Examples:
1197
1196
1198 - create an active bookmark for a new line of development::
1197 - create an active bookmark for a new line of development::
1199
1198
1200 hg book new-feature
1199 hg book new-feature
1201
1200
1202 - create an inactive bookmark as a place marker::
1201 - create an inactive bookmark as a place marker::
1203
1202
1204 hg book -i reviewed
1203 hg book -i reviewed
1205
1204
1206 - create an inactive bookmark on another changeset::
1205 - create an inactive bookmark on another changeset::
1207
1206
1208 hg book -r .^ tested
1207 hg book -r .^ tested
1209
1208
1210 - rename bookmark turkey to dinner::
1209 - rename bookmark turkey to dinner::
1211
1210
1212 hg book -m turkey dinner
1211 hg book -m turkey dinner
1213
1212
1214 - move the '@' bookmark from another branch::
1213 - move the '@' bookmark from another branch::
1215
1214
1216 hg book -f @
1215 hg book -f @
1217
1216
1218 - print only the active bookmark name::
1217 - print only the active bookmark name::
1219
1218
1220 hg book -ql .
1219 hg book -ql .
1221 '''
1220 '''
1222 opts = pycompat.byteskwargs(opts)
1221 opts = pycompat.byteskwargs(opts)
1223 force = opts.get(b'force')
1222 force = opts.get(b'force')
1224 rev = opts.get(b'rev')
1223 rev = opts.get(b'rev')
1225 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1224 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1226
1225
1227 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1226 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1228 if action:
1227 if action:
1229 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1228 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1230 elif names or rev:
1229 elif names or rev:
1231 action = b'add'
1230 action = b'add'
1232 elif inactive:
1231 elif inactive:
1233 action = b'inactive' # meaning deactivate
1232 action = b'inactive' # meaning deactivate
1234 else:
1233 else:
1235 action = b'list'
1234 action = b'list'
1236
1235
1237 cmdutil.check_incompatible_arguments(
1236 cmdutil.check_incompatible_arguments(
1238 opts, b'inactive', [b'delete', b'list']
1237 opts, b'inactive', [b'delete', b'list']
1239 )
1238 )
1240 if not names and action in {b'add', b'delete'}:
1239 if not names and action in {b'add', b'delete'}:
1241 raise error.Abort(_(b"bookmark name required"))
1240 raise error.Abort(_(b"bookmark name required"))
1242
1241
1243 if action in {b'add', b'delete', b'rename', b'inactive'}:
1242 if action in {b'add', b'delete', b'rename', b'inactive'}:
1244 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1243 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1245 if action == b'delete':
1244 if action == b'delete':
1246 names = pycompat.maplist(repo._bookmarks.expandname, names)
1245 names = pycompat.maplist(repo._bookmarks.expandname, names)
1247 bookmarks.delete(repo, tr, names)
1246 bookmarks.delete(repo, tr, names)
1248 elif action == b'rename':
1247 elif action == b'rename':
1249 if not names:
1248 if not names:
1250 raise error.Abort(_(b"new bookmark name required"))
1249 raise error.Abort(_(b"new bookmark name required"))
1251 elif len(names) > 1:
1250 elif len(names) > 1:
1252 raise error.Abort(_(b"only one new bookmark name allowed"))
1251 raise error.Abort(_(b"only one new bookmark name allowed"))
1253 oldname = repo._bookmarks.expandname(opts[b'rename'])
1252 oldname = repo._bookmarks.expandname(opts[b'rename'])
1254 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1253 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1255 elif action == b'add':
1254 elif action == b'add':
1256 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1255 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1257 elif action == b'inactive':
1256 elif action == b'inactive':
1258 if len(repo._bookmarks) == 0:
1257 if len(repo._bookmarks) == 0:
1259 ui.status(_(b"no bookmarks set\n"))
1258 ui.status(_(b"no bookmarks set\n"))
1260 elif not repo._activebookmark:
1259 elif not repo._activebookmark:
1261 ui.status(_(b"no active bookmark\n"))
1260 ui.status(_(b"no active bookmark\n"))
1262 else:
1261 else:
1263 bookmarks.deactivate(repo)
1262 bookmarks.deactivate(repo)
1264 elif action == b'list':
1263 elif action == b'list':
1265 names = pycompat.maplist(repo._bookmarks.expandname, names)
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1266 with ui.formatter(b'bookmarks', opts) as fm:
1265 with ui.formatter(b'bookmarks', opts) as fm:
1267 bookmarks.printbookmarks(ui, repo, fm, names)
1266 bookmarks.printbookmarks(ui, repo, fm, names)
1268 else:
1267 else:
1269 raise error.ProgrammingError(b'invalid action: %s' % action)
1268 raise error.ProgrammingError(b'invalid action: %s' % action)
1270
1269
1271
1270
1272 @command(
1271 @command(
1273 b'branch',
1272 b'branch',
1274 [
1273 [
1275 (
1274 (
1276 b'f',
1275 b'f',
1277 b'force',
1276 b'force',
1278 None,
1277 None,
1279 _(b'set branch name even if it shadows an existing branch'),
1278 _(b'set branch name even if it shadows an existing branch'),
1280 ),
1279 ),
1281 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1280 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1282 (
1281 (
1283 b'r',
1282 b'r',
1284 b'rev',
1283 b'rev',
1285 [],
1284 [],
1286 _(b'change branches of the given revs (EXPERIMENTAL)'),
1285 _(b'change branches of the given revs (EXPERIMENTAL)'),
1287 ),
1286 ),
1288 ],
1287 ],
1289 _(b'[-fC] [NAME]'),
1288 _(b'[-fC] [NAME]'),
1290 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1289 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1291 )
1290 )
1292 def branch(ui, repo, label=None, **opts):
1291 def branch(ui, repo, label=None, **opts):
1293 """set or show the current branch name
1292 """set or show the current branch name
1294
1293
1295 .. note::
1294 .. note::
1296
1295
1297 Branch names are permanent and global. Use :hg:`bookmark` to create a
1296 Branch names are permanent and global. Use :hg:`bookmark` to create a
1298 light-weight bookmark instead. See :hg:`help glossary` for more
1297 light-weight bookmark instead. See :hg:`help glossary` for more
1299 information about named branches and bookmarks.
1298 information about named branches and bookmarks.
1300
1299
1301 With no argument, show the current branch name. With one argument,
1300 With no argument, show the current branch name. With one argument,
1302 set the working directory branch name (the branch will not exist
1301 set the working directory branch name (the branch will not exist
1303 in the repository until the next commit). Standard practice
1302 in the repository until the next commit). Standard practice
1304 recommends that primary development take place on the 'default'
1303 recommends that primary development take place on the 'default'
1305 branch.
1304 branch.
1306
1305
1307 Unless -f/--force is specified, branch will not let you set a
1306 Unless -f/--force is specified, branch will not let you set a
1308 branch name that already exists.
1307 branch name that already exists.
1309
1308
1310 Use -C/--clean to reset the working directory branch to that of
1309 Use -C/--clean to reset the working directory branch to that of
1311 the parent of the working directory, negating a previous branch
1310 the parent of the working directory, negating a previous branch
1312 change.
1311 change.
1313
1312
1314 Use the command :hg:`update` to switch to an existing branch. Use
1313 Use the command :hg:`update` to switch to an existing branch. Use
1315 :hg:`commit --close-branch` to mark this branch head as closed.
1314 :hg:`commit --close-branch` to mark this branch head as closed.
1316 When all heads of a branch are closed, the branch will be
1315 When all heads of a branch are closed, the branch will be
1317 considered closed.
1316 considered closed.
1318
1317
1319 Returns 0 on success.
1318 Returns 0 on success.
1320 """
1319 """
1321 opts = pycompat.byteskwargs(opts)
1320 opts = pycompat.byteskwargs(opts)
1322 revs = opts.get(b'rev')
1321 revs = opts.get(b'rev')
1323 if label:
1322 if label:
1324 label = label.strip()
1323 label = label.strip()
1325
1324
1326 if not opts.get(b'clean') and not label:
1325 if not opts.get(b'clean') and not label:
1327 if revs:
1326 if revs:
1328 raise error.Abort(_(b"no branch name specified for the revisions"))
1327 raise error.Abort(_(b"no branch name specified for the revisions"))
1329 ui.write(b"%s\n" % repo.dirstate.branch())
1328 ui.write(b"%s\n" % repo.dirstate.branch())
1330 return
1329 return
1331
1330
1332 with repo.wlock():
1331 with repo.wlock():
1333 if opts.get(b'clean'):
1332 if opts.get(b'clean'):
1334 label = repo[b'.'].branch()
1333 label = repo[b'.'].branch()
1335 repo.dirstate.setbranch(label)
1334 repo.dirstate.setbranch(label)
1336 ui.status(_(b'reset working directory to branch %s\n') % label)
1335 ui.status(_(b'reset working directory to branch %s\n') % label)
1337 elif label:
1336 elif label:
1338
1337
1339 scmutil.checknewlabel(repo, label, b'branch')
1338 scmutil.checknewlabel(repo, label, b'branch')
1340 if revs:
1339 if revs:
1341 return cmdutil.changebranch(ui, repo, revs, label, opts)
1340 return cmdutil.changebranch(ui, repo, revs, label, opts)
1342
1341
1343 if not opts.get(b'force') and label in repo.branchmap():
1342 if not opts.get(b'force') and label in repo.branchmap():
1344 if label not in [p.branch() for p in repo[None].parents()]:
1343 if label not in [p.branch() for p in repo[None].parents()]:
1345 raise error.Abort(
1344 raise error.Abort(
1346 _(b'a branch of the same name already exists'),
1345 _(b'a branch of the same name already exists'),
1347 # i18n: "it" refers to an existing branch
1346 # i18n: "it" refers to an existing branch
1348 hint=_(b"use 'hg update' to switch to it"),
1347 hint=_(b"use 'hg update' to switch to it"),
1349 )
1348 )
1350
1349
1351 repo.dirstate.setbranch(label)
1350 repo.dirstate.setbranch(label)
1352 ui.status(_(b'marked working directory as branch %s\n') % label)
1351 ui.status(_(b'marked working directory as branch %s\n') % label)
1353
1352
1354 # find any open named branches aside from default
1353 # find any open named branches aside from default
1355 for n, h, t, c in repo.branchmap().iterbranches():
1354 for n, h, t, c in repo.branchmap().iterbranches():
1356 if n != b"default" and not c:
1355 if n != b"default" and not c:
1357 return 0
1356 return 0
1358 ui.status(
1357 ui.status(
1359 _(
1358 _(
1360 b'(branches are permanent and global, '
1359 b'(branches are permanent and global, '
1361 b'did you want a bookmark?)\n'
1360 b'did you want a bookmark?)\n'
1362 )
1361 )
1363 )
1362 )
1364
1363
1365
1364
1366 @command(
1365 @command(
1367 b'branches',
1366 b'branches',
1368 [
1367 [
1369 (
1368 (
1370 b'a',
1369 b'a',
1371 b'active',
1370 b'active',
1372 False,
1371 False,
1373 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1372 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1374 ),
1373 ),
1375 (b'c', b'closed', False, _(b'show normal and closed branches')),
1374 (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')),
1375 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1377 ]
1376 ]
1378 + formatteropts,
1377 + formatteropts,
1379 _(b'[-c]'),
1378 _(b'[-c]'),
1380 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1379 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1381 intents={INTENT_READONLY},
1380 intents={INTENT_READONLY},
1382 )
1381 )
1383 def branches(ui, repo, active=False, closed=False, **opts):
1382 def branches(ui, repo, active=False, closed=False, **opts):
1384 """list repository named branches
1383 """list repository named branches
1385
1384
1386 List the repository's named branches, indicating which ones are
1385 List the repository's named branches, indicating which ones are
1387 inactive. If -c/--closed is specified, also list branches which have
1386 inactive. If -c/--closed is specified, also list branches which have
1388 been marked closed (see :hg:`commit --close-branch`).
1387 been marked closed (see :hg:`commit --close-branch`).
1389
1388
1390 Use the command :hg:`update` to switch to an existing branch.
1389 Use the command :hg:`update` to switch to an existing branch.
1391
1390
1392 .. container:: verbose
1391 .. container:: verbose
1393
1392
1394 Template:
1393 Template:
1395
1394
1396 The following keywords are supported in addition to the common template
1395 The following keywords are supported in addition to the common template
1397 keywords and functions such as ``{branch}``. See also
1396 keywords and functions such as ``{branch}``. See also
1398 :hg:`help templates`.
1397 :hg:`help templates`.
1399
1398
1400 :active: Boolean. True if the branch is active.
1399 :active: Boolean. True if the branch is active.
1401 :closed: Boolean. True if the branch is closed.
1400 :closed: Boolean. True if the branch is closed.
1402 :current: Boolean. True if it is the current branch.
1401 :current: Boolean. True if it is the current branch.
1403
1402
1404 Returns 0.
1403 Returns 0.
1405 """
1404 """
1406
1405
1407 opts = pycompat.byteskwargs(opts)
1406 opts = pycompat.byteskwargs(opts)
1408 revs = opts.get(b'rev')
1407 revs = opts.get(b'rev')
1409 selectedbranches = None
1408 selectedbranches = None
1410 if revs:
1409 if revs:
1411 revs = scmutil.revrange(repo, revs)
1410 revs = scmutil.revrange(repo, revs)
1412 getbi = repo.revbranchcache().branchinfo
1411 getbi = repo.revbranchcache().branchinfo
1413 selectedbranches = {getbi(r)[0] for r in revs}
1412 selectedbranches = {getbi(r)[0] for r in revs}
1414
1413
1415 ui.pager(b'branches')
1414 ui.pager(b'branches')
1416 fm = ui.formatter(b'branches', opts)
1415 fm = ui.formatter(b'branches', opts)
1417 hexfunc = fm.hexfunc
1416 hexfunc = fm.hexfunc
1418
1417
1419 allheads = set(repo.heads())
1418 allheads = set(repo.heads())
1420 branches = []
1419 branches = []
1421 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1420 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1422 if selectedbranches is not None and tag not in selectedbranches:
1421 if selectedbranches is not None and tag not in selectedbranches:
1423 continue
1422 continue
1424 isactive = False
1423 isactive = False
1425 if not isclosed:
1424 if not isclosed:
1426 openheads = set(repo.branchmap().iteropen(heads))
1425 openheads = set(repo.branchmap().iteropen(heads))
1427 isactive = bool(openheads & allheads)
1426 isactive = bool(openheads & allheads)
1428 branches.append((tag, repo[tip], isactive, not isclosed))
1427 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)
1428 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1430
1429
1431 for tag, ctx, isactive, isopen in branches:
1430 for tag, ctx, isactive, isopen in branches:
1432 if active and not isactive:
1431 if active and not isactive:
1433 continue
1432 continue
1434 if isactive:
1433 if isactive:
1435 label = b'branches.active'
1434 label = b'branches.active'
1436 notice = b''
1435 notice = b''
1437 elif not isopen:
1436 elif not isopen:
1438 if not closed:
1437 if not closed:
1439 continue
1438 continue
1440 label = b'branches.closed'
1439 label = b'branches.closed'
1441 notice = _(b' (closed)')
1440 notice = _(b' (closed)')
1442 else:
1441 else:
1443 label = b'branches.inactive'
1442 label = b'branches.inactive'
1444 notice = _(b' (inactive)')
1443 notice = _(b' (inactive)')
1445 current = tag == repo.dirstate.branch()
1444 current = tag == repo.dirstate.branch()
1446 if current:
1445 if current:
1447 label = b'branches.current'
1446 label = b'branches.current'
1448
1447
1449 fm.startitem()
1448 fm.startitem()
1450 fm.write(b'branch', b'%s', tag, label=label)
1449 fm.write(b'branch', b'%s', tag, label=label)
1451 rev = ctx.rev()
1450 rev = ctx.rev()
1452 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1451 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1453 fmt = b' ' * padsize + b' %d:%s'
1452 fmt = b' ' * padsize + b' %d:%s'
1454 fm.condwrite(
1453 fm.condwrite(
1455 not ui.quiet,
1454 not ui.quiet,
1456 b'rev node',
1455 b'rev node',
1457 fmt,
1456 fmt,
1458 rev,
1457 rev,
1459 hexfunc(ctx.node()),
1458 hexfunc(ctx.node()),
1460 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1459 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1461 )
1460 )
1462 fm.context(ctx=ctx)
1461 fm.context(ctx=ctx)
1463 fm.data(active=isactive, closed=not isopen, current=current)
1462 fm.data(active=isactive, closed=not isopen, current=current)
1464 if not ui.quiet:
1463 if not ui.quiet:
1465 fm.plain(notice)
1464 fm.plain(notice)
1466 fm.plain(b'\n')
1465 fm.plain(b'\n')
1467 fm.end()
1466 fm.end()
1468
1467
1469
1468
1470 @command(
1469 @command(
1471 b'bundle',
1470 b'bundle',
1472 [
1471 [
1473 (
1472 (
1474 b'f',
1473 b'f',
1475 b'force',
1474 b'force',
1476 None,
1475 None,
1477 _(b'run even when the destination is unrelated'),
1476 _(b'run even when the destination is unrelated'),
1478 ),
1477 ),
1479 (
1478 (
1480 b'r',
1479 b'r',
1481 b'rev',
1480 b'rev',
1482 [],
1481 [],
1483 _(b'a changeset intended to be added to the destination'),
1482 _(b'a changeset intended to be added to the destination'),
1484 _(b'REV'),
1483 _(b'REV'),
1485 ),
1484 ),
1486 (
1485 (
1487 b'b',
1486 b'b',
1488 b'branch',
1487 b'branch',
1489 [],
1488 [],
1490 _(b'a specific branch you would like to bundle'),
1489 _(b'a specific branch you would like to bundle'),
1491 _(b'BRANCH'),
1490 _(b'BRANCH'),
1492 ),
1491 ),
1493 (
1492 (
1494 b'',
1493 b'',
1495 b'base',
1494 b'base',
1496 [],
1495 [],
1497 _(b'a base changeset assumed to be available at the destination'),
1496 _(b'a base changeset assumed to be available at the destination'),
1498 _(b'REV'),
1497 _(b'REV'),
1499 ),
1498 ),
1500 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1499 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1501 (
1500 (
1502 b't',
1501 b't',
1503 b'type',
1502 b'type',
1504 b'bzip2',
1503 b'bzip2',
1505 _(b'bundle compression type to use'),
1504 _(b'bundle compression type to use'),
1506 _(b'TYPE'),
1505 _(b'TYPE'),
1507 ),
1506 ),
1508 ]
1507 ]
1509 + remoteopts,
1508 + remoteopts,
1510 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1509 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1511 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1510 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1512 )
1511 )
1513 def bundle(ui, repo, fname, dest=None, **opts):
1512 def bundle(ui, repo, fname, dest=None, **opts):
1514 """create a bundle file
1513 """create a bundle file
1515
1514
1516 Generate a bundle file containing data to be transferred to another
1515 Generate a bundle file containing data to be transferred to another
1517 repository.
1516 repository.
1518
1517
1519 To create a bundle containing all changesets, use -a/--all
1518 To create a bundle containing all changesets, use -a/--all
1520 (or --base null). Otherwise, hg assumes the destination will have
1519 (or --base null). Otherwise, hg assumes the destination will have
1521 all the nodes you specify with --base parameters. Otherwise, hg
1520 all the nodes you specify with --base parameters. Otherwise, hg
1522 will assume the repository has all the nodes in destination, or
1521 will assume the repository has all the nodes in destination, or
1523 default-push/default if no destination is specified, where destination
1522 default-push/default if no destination is specified, where destination
1524 is the repository you provide through DEST option.
1523 is the repository you provide through DEST option.
1525
1524
1526 You can change bundle format with the -t/--type option. See
1525 You can change bundle format with the -t/--type option. See
1527 :hg:`help bundlespec` for documentation on this format. By default,
1526 :hg:`help bundlespec` for documentation on this format. By default,
1528 the most appropriate format is used and compression defaults to
1527 the most appropriate format is used and compression defaults to
1529 bzip2.
1528 bzip2.
1530
1529
1531 The bundle file can then be transferred using conventional means
1530 The bundle file can then be transferred using conventional means
1532 and applied to another repository with the unbundle or pull
1531 and applied to another repository with the unbundle or pull
1533 command. This is useful when direct push and pull are not
1532 command. This is useful when direct push and pull are not
1534 available or when exporting an entire repository is undesirable.
1533 available or when exporting an entire repository is undesirable.
1535
1534
1536 Applying bundles preserves all changeset contents including
1535 Applying bundles preserves all changeset contents including
1537 permissions, copy/rename information, and revision history.
1536 permissions, copy/rename information, and revision history.
1538
1537
1539 Returns 0 on success, 1 if no changes found.
1538 Returns 0 on success, 1 if no changes found.
1540 """
1539 """
1541 opts = pycompat.byteskwargs(opts)
1540 opts = pycompat.byteskwargs(opts)
1542 revs = None
1541 revs = None
1543 if b'rev' in opts:
1542 if b'rev' in opts:
1544 revstrings = opts[b'rev']
1543 revstrings = opts[b'rev']
1545 revs = scmutil.revrange(repo, revstrings)
1544 revs = scmutil.revrange(repo, revstrings)
1546 if revstrings and not revs:
1545 if revstrings and not revs:
1547 raise error.Abort(_(b'no commits to bundle'))
1546 raise error.Abort(_(b'no commits to bundle'))
1548
1547
1549 bundletype = opts.get(b'type', b'bzip2').lower()
1548 bundletype = opts.get(b'type', b'bzip2').lower()
1550 try:
1549 try:
1551 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1550 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1552 except error.UnsupportedBundleSpecification as e:
1551 except error.UnsupportedBundleSpecification as e:
1553 raise error.Abort(
1552 raise error.Abort(
1554 pycompat.bytestr(e),
1553 pycompat.bytestr(e),
1555 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1556 )
1555 )
1557 cgversion = bundlespec.contentopts[b"cg.version"]
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1558
1557
1559 # Packed bundles are a pseudo bundle format for now.
1558 # Packed bundles are a pseudo bundle format for now.
1560 if cgversion == b's1':
1559 if cgversion == b's1':
1561 raise error.Abort(
1560 raise error.Abort(
1562 _(b'packed bundles cannot be produced by "hg bundle"'),
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1563 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1564 )
1563 )
1565
1564
1566 if opts.get(b'all'):
1565 if opts.get(b'all'):
1567 if dest:
1566 if dest:
1568 raise error.Abort(
1567 raise error.Abort(
1569 _(b"--all is incompatible with specifying a destination")
1568 _(b"--all is incompatible with specifying a destination")
1570 )
1569 )
1571 if opts.get(b'base'):
1570 if opts.get(b'base'):
1572 ui.warn(_(b"ignoring --base because --all was specified\n"))
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1573 base = [nullrev]
1572 base = [nullrev]
1574 else:
1573 else:
1575 base = scmutil.revrange(repo, opts.get(b'base'))
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1576 if cgversion not in changegroup.supportedoutgoingversions(repo):
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1577 raise error.Abort(
1576 raise error.Abort(
1578 _(b"repository does not support bundle version %s") % cgversion
1577 _(b"repository does not support bundle version %s") % cgversion
1579 )
1578 )
1580
1579
1581 if base:
1580 if base:
1582 if dest:
1581 if dest:
1583 raise error.Abort(
1582 raise error.Abort(
1584 _(b"--base is incompatible with specifying a destination")
1583 _(b"--base is incompatible with specifying a destination")
1585 )
1584 )
1586 common = [repo[rev].node() for rev in base]
1585 common = [repo[rev].node() for rev in base]
1587 heads = [repo[r].node() for r in revs] if revs else None
1586 heads = [repo[r].node() for r in revs] if revs else None
1588 outgoing = discovery.outgoing(repo, common, heads)
1587 outgoing = discovery.outgoing(repo, common, heads)
1589 else:
1588 else:
1590 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1589 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1591 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1592 other = hg.peer(repo, opts, dest)
1591 other = hg.peer(repo, opts, dest)
1593 revs = [repo[r].hex() for r in revs]
1592 revs = [repo[r].hex() for r in revs]
1594 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1595 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1596 outgoing = discovery.findcommonoutgoing(
1595 outgoing = discovery.findcommonoutgoing(
1597 repo,
1596 repo,
1598 other,
1597 other,
1599 onlyheads=heads,
1598 onlyheads=heads,
1600 force=opts.get(b'force'),
1599 force=opts.get(b'force'),
1601 portable=True,
1600 portable=True,
1602 )
1601 )
1603
1602
1604 if not outgoing.missing:
1603 if not outgoing.missing:
1605 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1606 return 1
1605 return 1
1607
1606
1608 if cgversion == b'01': # bundle1
1607 if cgversion == b'01': # bundle1
1609 bversion = b'HG10' + bundlespec.wirecompression
1608 bversion = b'HG10' + bundlespec.wirecompression
1610 bcompression = None
1609 bcompression = None
1611 elif cgversion in (b'02', b'03'):
1610 elif cgversion in (b'02', b'03'):
1612 bversion = b'HG20'
1611 bversion = b'HG20'
1613 bcompression = bundlespec.wirecompression
1612 bcompression = bundlespec.wirecompression
1614 else:
1613 else:
1615 raise error.ProgrammingError(
1614 raise error.ProgrammingError(
1616 b'bundle: unexpected changegroup version %s' % cgversion
1615 b'bundle: unexpected changegroup version %s' % cgversion
1617 )
1616 )
1618
1617
1619 # TODO compression options should be derived from bundlespec parsing.
1618 # TODO compression options should be derived from bundlespec parsing.
1620 # This is a temporary hack to allow adjusting bundle compression
1619 # This is a temporary hack to allow adjusting bundle compression
1621 # level without a) formalizing the bundlespec changes to declare it
1620 # level without a) formalizing the bundlespec changes to declare it
1622 # b) introducing a command flag.
1621 # b) introducing a command flag.
1623 compopts = {}
1622 compopts = {}
1624 complevel = ui.configint(
1623 complevel = ui.configint(
1625 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1626 )
1625 )
1627 if complevel is None:
1626 if complevel is None:
1628 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1629 if complevel is not None:
1628 if complevel is not None:
1630 compopts[b'level'] = complevel
1629 compopts[b'level'] = complevel
1631
1630
1632 # Allow overriding the bundling of obsmarker in phases through
1631 # Allow overriding the bundling of obsmarker in phases through
1633 # configuration while we don't have a bundle version that include them
1632 # configuration while we don't have a bundle version that include them
1634 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1635 bundlespec.contentopts[b'obsolescence'] = True
1634 bundlespec.contentopts[b'obsolescence'] = True
1636 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1637 bundlespec.contentopts[b'phases'] = True
1636 bundlespec.contentopts[b'phases'] = True
1638
1637
1639 bundle2.writenewbundle(
1638 bundle2.writenewbundle(
1640 ui,
1639 ui,
1641 repo,
1640 repo,
1642 b'bundle',
1641 b'bundle',
1643 fname,
1642 fname,
1644 bversion,
1643 bversion,
1645 outgoing,
1644 outgoing,
1646 bundlespec.contentopts,
1645 bundlespec.contentopts,
1647 compression=bcompression,
1646 compression=bcompression,
1648 compopts=compopts,
1647 compopts=compopts,
1649 )
1648 )
1650
1649
1651
1650
1652 @command(
1651 @command(
1653 b'cat',
1652 b'cat',
1654 [
1653 [
1655 (
1654 (
1656 b'o',
1655 b'o',
1657 b'output',
1656 b'output',
1658 b'',
1657 b'',
1659 _(b'print output to file with formatted name'),
1658 _(b'print output to file with formatted name'),
1660 _(b'FORMAT'),
1659 _(b'FORMAT'),
1661 ),
1660 ),
1662 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1661 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1663 (b'', b'decode', None, _(b'apply any matching decode filter')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1664 ]
1663 ]
1665 + walkopts
1664 + walkopts
1666 + formatteropts,
1665 + formatteropts,
1667 _(b'[OPTION]... FILE...'),
1666 _(b'[OPTION]... FILE...'),
1668 helpcategory=command.CATEGORY_FILE_CONTENTS,
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1669 inferrepo=True,
1668 inferrepo=True,
1670 intents={INTENT_READONLY},
1669 intents={INTENT_READONLY},
1671 )
1670 )
1672 def cat(ui, repo, file1, *pats, **opts):
1671 def cat(ui, repo, file1, *pats, **opts):
1673 """output the current or given revision of files
1672 """output the current or given revision of files
1674
1673
1675 Print the specified files as they were at the given revision. If
1674 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.
1675 no revision is given, the parent of the working directory is used.
1677
1676
1678 Output may be to a file, in which case the name of the file is
1677 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
1678 given using a template string. See :hg:`help templates`. In addition
1680 to the common template keywords, the following formatting rules are
1679 to the common template keywords, the following formatting rules are
1681 supported:
1680 supported:
1682
1681
1683 :``%%``: literal "%" character
1682 :``%%``: literal "%" character
1684 :``%s``: basename of file being printed
1683 :``%s``: basename of file being printed
1685 :``%d``: dirname of file being printed, or '.' if in repository root
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1686 :``%p``: root-relative path name of file being printed
1685 :``%p``: root-relative path name of file being printed
1687 :``%H``: changeset hash (40 hexadecimal digits)
1686 :``%H``: changeset hash (40 hexadecimal digits)
1688 :``%R``: changeset revision number
1687 :``%R``: changeset revision number
1689 :``%h``: short-form changeset hash (12 hexadecimal digits)
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1690 :``%r``: zero-padded changeset revision number
1689 :``%r``: zero-padded changeset revision number
1691 :``%b``: basename of the exporting repository
1690 :``%b``: basename of the exporting repository
1692 :``\\``: literal "\\" character
1691 :``\\``: literal "\\" character
1693
1692
1694 .. container:: verbose
1693 .. container:: verbose
1695
1694
1696 Template:
1695 Template:
1697
1696
1698 The following keywords are supported in addition to the common template
1697 The following keywords are supported in addition to the common template
1699 keywords and functions. See also :hg:`help templates`.
1698 keywords and functions. See also :hg:`help templates`.
1700
1699
1701 :data: String. File content.
1700 :data: String. File content.
1702 :path: String. Repository-absolute path of the file.
1701 :path: String. Repository-absolute path of the file.
1703
1702
1704 Returns 0 on success.
1703 Returns 0 on success.
1705 """
1704 """
1706 opts = pycompat.byteskwargs(opts)
1705 opts = pycompat.byteskwargs(opts)
1707 rev = opts.get(b'rev')
1706 rev = opts.get(b'rev')
1708 if rev:
1707 if rev:
1709 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1710 ctx = scmutil.revsingle(repo, rev)
1709 ctx = scmutil.revsingle(repo, rev)
1711 m = scmutil.match(ctx, (file1,) + pats, opts)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1712 fntemplate = opts.pop(b'output', b'')
1711 fntemplate = opts.pop(b'output', b'')
1713 if cmdutil.isstdiofilename(fntemplate):
1712 if cmdutil.isstdiofilename(fntemplate):
1714 fntemplate = b''
1713 fntemplate = b''
1715
1714
1716 if fntemplate:
1715 if fntemplate:
1717 fm = formatter.nullformatter(ui, b'cat', opts)
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1718 else:
1717 else:
1719 ui.pager(b'cat')
1718 ui.pager(b'cat')
1720 fm = ui.formatter(b'cat', opts)
1719 fm = ui.formatter(b'cat', opts)
1721 with fm:
1720 with fm:
1722 return cmdutil.cat(
1721 return cmdutil.cat(
1723 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1724 )
1723 )
1725
1724
1726
1725
1727 @command(
1726 @command(
1728 b'clone',
1727 b'clone',
1729 [
1728 [
1730 (
1729 (
1731 b'U',
1730 b'U',
1732 b'noupdate',
1731 b'noupdate',
1733 None,
1732 None,
1734 _(
1733 _(
1735 b'the clone will include an empty working '
1734 b'the clone will include an empty working '
1736 b'directory (only a repository)'
1735 b'directory (only a repository)'
1737 ),
1736 ),
1738 ),
1737 ),
1739 (
1738 (
1740 b'u',
1739 b'u',
1741 b'updaterev',
1740 b'updaterev',
1742 b'',
1741 b'',
1743 _(b'revision, tag, or branch to check out'),
1742 _(b'revision, tag, or branch to check out'),
1744 _(b'REV'),
1743 _(b'REV'),
1745 ),
1744 ),
1746 (
1745 (
1747 b'r',
1746 b'r',
1748 b'rev',
1747 b'rev',
1749 [],
1748 [],
1750 _(
1749 _(
1751 b'do not clone everything, but include this changeset'
1750 b'do not clone everything, but include this changeset'
1752 b' and its ancestors'
1751 b' and its ancestors'
1753 ),
1752 ),
1754 _(b'REV'),
1753 _(b'REV'),
1755 ),
1754 ),
1756 (
1755 (
1757 b'b',
1756 b'b',
1758 b'branch',
1757 b'branch',
1759 [],
1758 [],
1760 _(
1759 _(
1761 b'do not clone everything, but include this branch\'s'
1760 b'do not clone everything, but include this branch\'s'
1762 b' changesets and their ancestors'
1761 b' changesets and their ancestors'
1763 ),
1762 ),
1764 _(b'BRANCH'),
1763 _(b'BRANCH'),
1765 ),
1764 ),
1766 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1767 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1768 (b'', b'stream', None, _(b'clone with minimal data processing')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1769 ]
1768 ]
1770 + remoteopts,
1769 + remoteopts,
1771 _(b'[OPTION]... SOURCE [DEST]'),
1770 _(b'[OPTION]... SOURCE [DEST]'),
1772 helpcategory=command.CATEGORY_REPO_CREATION,
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1773 helpbasic=True,
1772 helpbasic=True,
1774 norepo=True,
1773 norepo=True,
1775 )
1774 )
1776 def clone(ui, source, dest=None, **opts):
1775 def clone(ui, source, dest=None, **opts):
1777 """make a copy of an existing repository
1776 """make a copy of an existing repository
1778
1777
1779 Create a copy of an existing repository in a new directory.
1778 Create a copy of an existing repository in a new directory.
1780
1779
1781 If no destination directory name is specified, it defaults to the
1780 If no destination directory name is specified, it defaults to the
1782 basename of the source.
1781 basename of the source.
1783
1782
1784 The location of the source is added to the new repository's
1783 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.
1784 ``.hg/hgrc`` file, as the default to be used for future pulls.
1786
1785
1787 Only local paths and ``ssh://`` URLs are supported as
1786 Only local paths and ``ssh://`` URLs are supported as
1788 destinations. For ``ssh://`` destinations, no working directory or
1787 destinations. For ``ssh://`` destinations, no working directory or
1789 ``.hg/hgrc`` will be created on the remote side.
1788 ``.hg/hgrc`` will be created on the remote side.
1790
1789
1791 If the source repository has a bookmark called '@' set, that
1790 If the source repository has a bookmark called '@' set, that
1792 revision will be checked out in the new repository by default.
1791 revision will be checked out in the new repository by default.
1793
1792
1794 To check out a particular version, use -u/--update, or
1793 To check out a particular version, use -u/--update, or
1795 -U/--noupdate to create a clone with no working directory.
1794 -U/--noupdate to create a clone with no working directory.
1796
1795
1797 To pull only a subset of changesets, specify one or more revisions
1796 To pull only a subset of changesets, specify one or more revisions
1798 identifiers with -r/--rev or branches with -b/--branch. The
1797 identifiers with -r/--rev or branches with -b/--branch. The
1799 resulting clone will contain only the specified changesets and
1798 resulting clone will contain only the specified changesets and
1800 their ancestors. These options (or 'clone src#rev dest') imply
1799 their ancestors. These options (or 'clone src#rev dest') imply
1801 --pull, even for local source repositories.
1800 --pull, even for local source repositories.
1802
1801
1803 In normal clone mode, the remote normalizes repository data into a common
1802 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
1803 exchange format and the receiving end translates this data into its local
1805 storage format. --stream activates a different clone mode that essentially
1804 storage format. --stream activates a different clone mode that essentially
1806 copies repository files from the remote with minimal data processing. This
1805 copies repository files from the remote with minimal data processing. This
1807 significantly reduces the CPU cost of a clone both remotely and locally.
1806 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
1807 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,
1808 result in substantially faster clones where I/O throughput is plentiful,
1810 especially for larger repositories. A side-effect of --stream clones is
1809 especially for larger repositories. A side-effect of --stream clones is
1811 that storage settings and requirements on the remote are applied locally:
1810 that storage settings and requirements on the remote are applied locally:
1812 a modern client may inherit legacy or inefficient storage used by the
1811 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
1812 remote or a legacy Mercurial client may not be able to clone from a
1814 modern Mercurial remote.
1813 modern Mercurial remote.
1815
1814
1816 .. note::
1815 .. note::
1817
1816
1818 Specifying a tag will include the tagged changeset but not the
1817 Specifying a tag will include the tagged changeset but not the
1819 changeset containing the tag.
1818 changeset containing the tag.
1820
1819
1821 .. container:: verbose
1820 .. container:: verbose
1822
1821
1823 For efficiency, hardlinks are used for cloning whenever the
1822 For efficiency, hardlinks are used for cloning whenever the
1824 source and destination are on the same filesystem (note this
1823 source and destination are on the same filesystem (note this
1825 applies only to the repository data, not to the working
1824 applies only to the repository data, not to the working
1826 directory). Some filesystems, such as AFS, implement hardlinking
1825 directory). Some filesystems, such as AFS, implement hardlinking
1827 incorrectly, but do not report errors. In these cases, use the
1826 incorrectly, but do not report errors. In these cases, use the
1828 --pull option to avoid hardlinking.
1827 --pull option to avoid hardlinking.
1829
1828
1830 Mercurial will update the working directory to the first applicable
1829 Mercurial will update the working directory to the first applicable
1831 revision from this list:
1830 revision from this list:
1832
1831
1833 a) null if -U or the source repository has no changesets
1832 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
1833 b) if -u . and the source repository is local, the first parent of
1835 the source repository's working directory
1834 the source repository's working directory
1836 c) the changeset specified with -u (if a branch name, this means the
1835 c) the changeset specified with -u (if a branch name, this means the
1837 latest head of that branch)
1836 latest head of that branch)
1838 d) the changeset specified with -r
1837 d) the changeset specified with -r
1839 e) the tipmost head specified with -b
1838 e) the tipmost head specified with -b
1840 f) the tipmost head specified with the url#branch source syntax
1839 f) the tipmost head specified with the url#branch source syntax
1841 g) the revision marked with the '@' bookmark, if present
1840 g) the revision marked with the '@' bookmark, if present
1842 h) the tipmost head of the default branch
1841 h) the tipmost head of the default branch
1843 i) tip
1842 i) tip
1844
1843
1845 When cloning from servers that support it, Mercurial may fetch
1844 When cloning from servers that support it, Mercurial may fetch
1846 pre-generated data from a server-advertised URL or inline from the
1845 pre-generated data from a server-advertised URL or inline from the
1847 same stream. When this is done, hooks operating on incoming changesets
1846 same stream. When this is done, hooks operating on incoming changesets
1848 and changegroups may fire more than once, once for each pre-generated
1847 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,
1848 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
1849 if an error occurs, the repository may be rolled back to a partial
1851 clone. This behavior may change in future releases.
1850 clone. This behavior may change in future releases.
1852 See :hg:`help -e clonebundles` for more.
1851 See :hg:`help -e clonebundles` for more.
1853
1852
1854 Examples:
1853 Examples:
1855
1854
1856 - clone a remote repository to a new directory named hg/::
1855 - clone a remote repository to a new directory named hg/::
1857
1856
1858 hg clone https://www.mercurial-scm.org/repo/hg/
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1859
1858
1860 - create a lightweight local clone::
1859 - create a lightweight local clone::
1861
1860
1862 hg clone project/ project-feature/
1861 hg clone project/ project-feature/
1863
1862
1864 - clone from an absolute path on an ssh server (note double-slash)::
1863 - clone from an absolute path on an ssh server (note double-slash)::
1865
1864
1866 hg clone ssh://user@server//home/projects/alpha/
1865 hg clone ssh://user@server//home/projects/alpha/
1867
1866
1868 - do a streaming clone while checking out a specified version::
1867 - do a streaming clone while checking out a specified version::
1869
1868
1870 hg clone --stream http://server/repo -u 1.5
1869 hg clone --stream http://server/repo -u 1.5
1871
1870
1872 - create a repository without changesets after a particular revision::
1871 - create a repository without changesets after a particular revision::
1873
1872
1874 hg clone -r 04e544 experimental/ good/
1873 hg clone -r 04e544 experimental/ good/
1875
1874
1876 - clone (and track) a particular named branch::
1875 - clone (and track) a particular named branch::
1877
1876
1878 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1879
1878
1880 See :hg:`help urls` for details on specifying URLs.
1879 See :hg:`help urls` for details on specifying URLs.
1881
1880
1882 Returns 0 on success.
1881 Returns 0 on success.
1883 """
1882 """
1884 opts = pycompat.byteskwargs(opts)
1883 opts = pycompat.byteskwargs(opts)
1885 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1886
1885
1887 # --include/--exclude can come from narrow or sparse.
1886 # --include/--exclude can come from narrow or sparse.
1888 includepats, excludepats = None, None
1887 includepats, excludepats = None, None
1889
1888
1890 # hg.clone() differentiates between None and an empty set. So make sure
1889 # hg.clone() differentiates between None and an empty set. So make sure
1891 # patterns are sets if narrow is requested without patterns.
1890 # patterns are sets if narrow is requested without patterns.
1892 if opts.get(b'narrow'):
1891 if opts.get(b'narrow'):
1893 includepats = set()
1892 includepats = set()
1894 excludepats = set()
1893 excludepats = set()
1895
1894
1896 if opts.get(b'include'):
1895 if opts.get(b'include'):
1897 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1898 if opts.get(b'exclude'):
1897 if opts.get(b'exclude'):
1899 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1900
1899
1901 r = hg.clone(
1900 r = hg.clone(
1902 ui,
1901 ui,
1903 opts,
1902 opts,
1904 source,
1903 source,
1905 dest,
1904 dest,
1906 pull=opts.get(b'pull'),
1905 pull=opts.get(b'pull'),
1907 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1908 revs=opts.get(b'rev'),
1907 revs=opts.get(b'rev'),
1909 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1910 branch=opts.get(b'branch'),
1909 branch=opts.get(b'branch'),
1911 shareopts=opts.get(b'shareopts'),
1910 shareopts=opts.get(b'shareopts'),
1912 storeincludepats=includepats,
1911 storeincludepats=includepats,
1913 storeexcludepats=excludepats,
1912 storeexcludepats=excludepats,
1914 depth=opts.get(b'depth') or None,
1913 depth=opts.get(b'depth') or None,
1915 )
1914 )
1916
1915
1917 return r is None
1916 return r is None
1918
1917
1919
1918
1920 @command(
1919 @command(
1921 b'commit|ci',
1920 b'commit|ci',
1922 [
1921 [
1923 (
1922 (
1924 b'A',
1923 b'A',
1925 b'addremove',
1924 b'addremove',
1926 None,
1925 None,
1927 _(b'mark new/missing files as added/removed before committing'),
1926 _(b'mark new/missing files as added/removed before committing'),
1928 ),
1927 ),
1929 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1928 (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')),
1929 (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')),
1930 (b's', b'secret', None, _(b'use the secret phase for committing')),
1932 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1933 (
1932 (
1934 b'',
1933 b'',
1935 b'force-close-branch',
1934 b'force-close-branch',
1936 None,
1935 None,
1937 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1938 ),
1937 ),
1939 (b'i', b'interactive', None, _(b'use interactive mode')),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1940 ]
1939 ]
1941 + walkopts
1940 + walkopts
1942 + commitopts
1941 + commitopts
1943 + commitopts2
1942 + commitopts2
1944 + subrepoopts,
1943 + subrepoopts,
1945 _(b'[OPTION]... [FILE]...'),
1944 _(b'[OPTION]... [FILE]...'),
1946 helpcategory=command.CATEGORY_COMMITTING,
1945 helpcategory=command.CATEGORY_COMMITTING,
1947 helpbasic=True,
1946 helpbasic=True,
1948 inferrepo=True,
1947 inferrepo=True,
1949 )
1948 )
1950 def commit(ui, repo, *pats, **opts):
1949 def commit(ui, repo, *pats, **opts):
1951 """commit the specified files or all outstanding changes
1950 """commit the specified files or all outstanding changes
1952
1951
1953 Commit changes to the given files into the repository. Unlike a
1952 Commit changes to the given files into the repository. Unlike a
1954 centralized SCM, this operation is a local operation. See
1953 centralized SCM, this operation is a local operation. See
1955 :hg:`push` for a way to actively distribute your changes.
1954 :hg:`push` for a way to actively distribute your changes.
1956
1955
1957 If a list of files is omitted, all changes reported by :hg:`status`
1956 If a list of files is omitted, all changes reported by :hg:`status`
1958 will be committed.
1957 will be committed.
1959
1958
1960 If you are committing the result of a merge, do not provide any
1959 If you are committing the result of a merge, do not provide any
1961 filenames or -I/-X filters.
1960 filenames or -I/-X filters.
1962
1961
1963 If no commit message is specified, Mercurial starts your
1962 If no commit message is specified, Mercurial starts your
1964 configured editor where you can enter a message. In case your
1963 configured editor where you can enter a message. In case your
1965 commit fails, you will find a backup of your message in
1964 commit fails, you will find a backup of your message in
1966 ``.hg/last-message.txt``.
1965 ``.hg/last-message.txt``.
1967
1966
1968 The --close-branch flag can be used to mark the current branch
1967 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
1968 head closed. When all heads of a branch are closed, the branch
1970 will be considered closed and no longer listed.
1969 will be considered closed and no longer listed.
1971
1970
1972 The --amend flag can be used to amend the parent of the
1971 The --amend flag can be used to amend the parent of the
1973 working directory with a new commit that contains the changes
1972 working directory with a new commit that contains the changes
1974 in the parent in addition to those currently reported by :hg:`status`,
1973 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
1974 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`
1975 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1977 on how to restore it).
1976 on how to restore it).
1978
1977
1979 Message, user and date are taken from the amended commit unless
1978 Message, user and date are taken from the amended commit unless
1980 specified. When a message isn't specified on the command line,
1979 specified. When a message isn't specified on the command line,
1981 the editor will open with the message of the amended commit.
1980 the editor will open with the message of the amended commit.
1982
1981
1983 It is not possible to amend public changesets (see :hg:`help phases`)
1982 It is not possible to amend public changesets (see :hg:`help phases`)
1984 or changesets that have children.
1983 or changesets that have children.
1985
1984
1986 See :hg:`help dates` for a list of formats valid for -d/--date.
1985 See :hg:`help dates` for a list of formats valid for -d/--date.
1987
1986
1988 Returns 0 on success, 1 if nothing changed.
1987 Returns 0 on success, 1 if nothing changed.
1989
1988
1990 .. container:: verbose
1989 .. container:: verbose
1991
1990
1992 Examples:
1991 Examples:
1993
1992
1994 - commit all files ending in .py::
1993 - commit all files ending in .py::
1995
1994
1996 hg commit --include "set:**.py"
1995 hg commit --include "set:**.py"
1997
1996
1998 - commit all non-binary files::
1997 - commit all non-binary files::
1999
1998
2000 hg commit --exclude "set:binary()"
1999 hg commit --exclude "set:binary()"
2001
2000
2002 - amend the current commit and set the date to now::
2001 - amend the current commit and set the date to now::
2003
2002
2004 hg commit --amend --date now
2003 hg commit --amend --date now
2005 """
2004 """
2006 with repo.wlock(), repo.lock():
2005 with repo.wlock(), repo.lock():
2007 return _docommit(ui, repo, *pats, **opts)
2006 return _docommit(ui, repo, *pats, **opts)
2008
2007
2009
2008
2010 def _docommit(ui, repo, *pats, **opts):
2009 def _docommit(ui, repo, *pats, **opts):
2011 if opts.get('interactive'):
2010 if opts.get('interactive'):
2012 opts.pop('interactive')
2011 opts.pop('interactive')
2013 ret = cmdutil.dorecord(
2012 ret = cmdutil.dorecord(
2014 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2015 )
2014 )
2016 # ret can be 0 (no changes to record) or the value returned by
2015 # ret can be 0 (no changes to record) or the value returned by
2017 # commit(), 1 if nothing changed or None on success.
2016 # commit(), 1 if nothing changed or None on success.
2018 return 1 if ret == 0 else ret
2017 return 1 if ret == 0 else ret
2019
2018
2020 opts = pycompat.byteskwargs(opts)
2019 opts = pycompat.byteskwargs(opts)
2021 if opts.get(b'subrepos'):
2020 if opts.get(b'subrepos'):
2022 if opts.get(b'amend'):
2021 if opts.get(b'amend'):
2023 raise error.Abort(_(b'cannot amend with --subrepos'))
2022 raise error.Abort(_(b'cannot amend with --subrepos'))
2024 # Let --subrepos on the command line override config setting.
2023 # Let --subrepos on the command line override config setting.
2025 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2024 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2026
2025
2027 cmdutil.checkunfinished(repo, commit=True)
2026 cmdutil.checkunfinished(repo, commit=True)
2028
2027
2029 branch = repo[None].branch()
2028 branch = repo[None].branch()
2030 bheads = repo.branchheads(branch)
2029 bheads = repo.branchheads(branch)
2031
2030
2032 extra = {}
2031 extra = {}
2033 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2032 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2034 extra[b'close'] = b'1'
2033 extra[b'close'] = b'1'
2035
2034
2036 if repo[b'.'].closesbranch():
2035 if repo[b'.'].closesbranch():
2037 raise error.Abort(
2036 raise error.Abort(
2038 _(b'current revision is already a branch closing head')
2037 _(b'current revision is already a branch closing head')
2039 )
2038 )
2040 elif not bheads:
2039 elif not bheads:
2041 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2040 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2042 elif (
2041 elif (
2043 branch == repo[b'.'].branch()
2042 branch == repo[b'.'].branch()
2044 and repo[b'.'].node() not in bheads
2043 and repo[b'.'].node() not in bheads
2045 and not opts.get(b'force_close_branch')
2044 and not opts.get(b'force_close_branch')
2046 ):
2045 ):
2047 hint = _(
2046 hint = _(
2048 b'use --force-close-branch to close branch from a non-head'
2047 b'use --force-close-branch to close branch from a non-head'
2049 b' changeset'
2048 b' changeset'
2050 )
2049 )
2051 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2050 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2052 elif opts.get(b'amend'):
2051 elif opts.get(b'amend'):
2053 if (
2052 if (
2054 repo[b'.'].p1().branch() != branch
2053 repo[b'.'].p1().branch() != branch
2055 and repo[b'.'].p2().branch() != branch
2054 and repo[b'.'].p2().branch() != branch
2056 ):
2055 ):
2057 raise error.Abort(_(b'can only close branch heads'))
2056 raise error.Abort(_(b'can only close branch heads'))
2058
2057
2059 if opts.get(b'amend'):
2058 if opts.get(b'amend'):
2060 if ui.configbool(b'ui', b'commitsubrepos'):
2059 if ui.configbool(b'ui', b'commitsubrepos'):
2061 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2060 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2062
2061
2063 old = repo[b'.']
2062 old = repo[b'.']
2064 rewriteutil.precheck(repo, [old.rev()], b'amend')
2063 rewriteutil.precheck(repo, [old.rev()], b'amend')
2065
2064
2066 # Currently histedit gets confused if an amend happens while histedit
2065 # Currently histedit gets confused if an amend happens while histedit
2067 # is in progress. Since we have a checkunfinished command, we are
2066 # is in progress. Since we have a checkunfinished command, we are
2068 # temporarily honoring it.
2067 # temporarily honoring it.
2069 #
2068 #
2070 # Note: eventually this guard will be removed. Please do not expect
2069 # Note: eventually this guard will be removed. Please do not expect
2071 # this behavior to remain.
2070 # this behavior to remain.
2072 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2071 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2073 cmdutil.checkunfinished(repo)
2072 cmdutil.checkunfinished(repo)
2074
2073
2075 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2074 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2076 if node == old.node():
2075 if node == old.node():
2077 ui.status(_(b"nothing changed\n"))
2076 ui.status(_(b"nothing changed\n"))
2078 return 1
2077 return 1
2079 else:
2078 else:
2080
2079
2081 def commitfunc(ui, repo, message, match, opts):
2080 def commitfunc(ui, repo, message, match, opts):
2082 overrides = {}
2081 overrides = {}
2083 if opts.get(b'secret'):
2082 if opts.get(b'secret'):
2084 overrides[(b'phases', b'new-commit')] = b'secret'
2083 overrides[(b'phases', b'new-commit')] = b'secret'
2085
2084
2086 baseui = repo.baseui
2085 baseui = repo.baseui
2087 with baseui.configoverride(overrides, b'commit'):
2086 with baseui.configoverride(overrides, b'commit'):
2088 with ui.configoverride(overrides, b'commit'):
2087 with ui.configoverride(overrides, b'commit'):
2089 editform = cmdutil.mergeeditform(
2088 editform = cmdutil.mergeeditform(
2090 repo[None], b'commit.normal'
2089 repo[None], b'commit.normal'
2091 )
2090 )
2092 editor = cmdutil.getcommiteditor(
2091 editor = cmdutil.getcommiteditor(
2093 editform=editform, **pycompat.strkwargs(opts)
2092 editform=editform, **pycompat.strkwargs(opts)
2094 )
2093 )
2095 return repo.commit(
2094 return repo.commit(
2096 message,
2095 message,
2097 opts.get(b'user'),
2096 opts.get(b'user'),
2098 opts.get(b'date'),
2097 opts.get(b'date'),
2099 match,
2098 match,
2100 editor=editor,
2099 editor=editor,
2101 extra=extra,
2100 extra=extra,
2102 )
2101 )
2103
2102
2104 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2103 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2105
2104
2106 if not node:
2105 if not node:
2107 stat = cmdutil.postcommitstatus(repo, pats, opts)
2106 stat = cmdutil.postcommitstatus(repo, pats, opts)
2108 if stat.deleted:
2107 if stat.deleted:
2109 ui.status(
2108 ui.status(
2110 _(
2109 _(
2111 b"nothing changed (%d missing files, see "
2110 b"nothing changed (%d missing files, see "
2112 b"'hg status')\n"
2111 b"'hg status')\n"
2113 )
2112 )
2114 % len(stat.deleted)
2113 % len(stat.deleted)
2115 )
2114 )
2116 else:
2115 else:
2117 ui.status(_(b"nothing changed\n"))
2116 ui.status(_(b"nothing changed\n"))
2118 return 1
2117 return 1
2119
2118
2120 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2119 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2121
2120
2122 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2121 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2123 status(
2122 status(
2124 ui,
2123 ui,
2125 repo,
2124 repo,
2126 modified=True,
2125 modified=True,
2127 added=True,
2126 added=True,
2128 removed=True,
2127 removed=True,
2129 deleted=True,
2128 deleted=True,
2130 unknown=True,
2129 unknown=True,
2131 subrepos=opts.get(b'subrepos'),
2130 subrepos=opts.get(b'subrepos'),
2132 )
2131 )
2133
2132
2134
2133
2135 @command(
2134 @command(
2136 b'config|showconfig|debugconfig',
2135 b'config|showconfig|debugconfig',
2137 [
2136 [
2138 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2137 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2139 (b'e', b'edit', None, _(b'edit user config')),
2138 (b'e', b'edit', None, _(b'edit user config')),
2140 (b'l', b'local', None, _(b'edit repository config')),
2139 (b'l', b'local', None, _(b'edit repository config')),
2141 (
2140 (
2142 b'',
2141 b'',
2143 b'shared',
2142 b'shared',
2144 None,
2143 None,
2145 _(b'edit shared source repository config (EXPERIMENTAL)'),
2144 _(b'edit shared source repository config (EXPERIMENTAL)'),
2146 ),
2145 ),
2147 (b'g', b'global', None, _(b'edit global config')),
2146 (b'g', b'global', None, _(b'edit global config')),
2148 ]
2147 ]
2149 + formatteropts,
2148 + formatteropts,
2150 _(b'[-u] [NAME]...'),
2149 _(b'[-u] [NAME]...'),
2151 helpcategory=command.CATEGORY_HELP,
2150 helpcategory=command.CATEGORY_HELP,
2152 optionalrepo=True,
2151 optionalrepo=True,
2153 intents={INTENT_READONLY},
2152 intents={INTENT_READONLY},
2154 )
2153 )
2155 def config(ui, repo, *values, **opts):
2154 def config(ui, repo, *values, **opts):
2156 """show combined config settings from all hgrc files
2155 """show combined config settings from all hgrc files
2157
2156
2158 With no arguments, print names and values of all config items.
2157 With no arguments, print names and values of all config items.
2159
2158
2160 With one argument of the form section.name, print just the value
2159 With one argument of the form section.name, print just the value
2161 of that config item.
2160 of that config item.
2162
2161
2163 With multiple arguments, print names and values of all config
2162 With multiple arguments, print names and values of all config
2164 items with matching section names or section.names.
2163 items with matching section names or section.names.
2165
2164
2166 With --edit, start an editor on the user-level config file. With
2165 With --edit, start an editor on the user-level config file. With
2167 --global, edit the system-wide config file. With --local, edit the
2166 --global, edit the system-wide config file. With --local, edit the
2168 repository-level config file.
2167 repository-level config file.
2169
2168
2170 With --debug, the source (filename and line number) is printed
2169 With --debug, the source (filename and line number) is printed
2171 for each config item.
2170 for each config item.
2172
2171
2173 See :hg:`help config` for more information about config files.
2172 See :hg:`help config` for more information about config files.
2174
2173
2175 .. container:: verbose
2174 .. container:: verbose
2176
2175
2177 Template:
2176 Template:
2178
2177
2179 The following keywords are supported. See also :hg:`help templates`.
2178 The following keywords are supported. See also :hg:`help templates`.
2180
2179
2181 :name: String. Config name.
2180 :name: String. Config name.
2182 :source: String. Filename and line number where the item is defined.
2181 :source: String. Filename and line number where the item is defined.
2183 :value: String. Config value.
2182 :value: String. Config value.
2184
2183
2185 The --shared flag can be used to edit the config file of shared source
2184 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
2185 repository. It only works when you have shared using the experimental
2187 share safe feature.
2186 share safe feature.
2188
2187
2189 Returns 0 on success, 1 if NAME does not exist.
2188 Returns 0 on success, 1 if NAME does not exist.
2190
2189
2191 """
2190 """
2192
2191
2193 opts = pycompat.byteskwargs(opts)
2192 opts = pycompat.byteskwargs(opts)
2194 editopts = (b'edit', b'local', b'global', b'shared')
2193 editopts = (b'edit', b'local', b'global', b'shared')
2195 if any(opts.get(o) for o in editopts):
2194 if any(opts.get(o) for o in editopts):
2196 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2195 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2197 if opts.get(b'local'):
2196 if opts.get(b'local'):
2198 if not repo:
2197 if not repo:
2199 raise error.Abort(_(b"can't use --local outside a repository"))
2198 raise error.Abort(_(b"can't use --local outside a repository"))
2200 paths = [repo.vfs.join(b'hgrc')]
2199 paths = [repo.vfs.join(b'hgrc')]
2201 elif opts.get(b'global'):
2200 elif opts.get(b'global'):
2202 paths = rcutil.systemrcpath()
2201 paths = rcutil.systemrcpath()
2203 elif opts.get(b'shared'):
2202 elif opts.get(b'shared'):
2204 if not repo.shared():
2203 if not repo.shared():
2205 raise error.Abort(
2204 raise error.Abort(
2206 _(b"repository is not shared; can't use --shared")
2205 _(b"repository is not shared; can't use --shared")
2207 )
2206 )
2208 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2207 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2209 raise error.Abort(
2208 raise error.Abort(
2210 _(
2209 _(
2211 b"share safe feature not unabled; "
2210 b"share safe feature not unabled; "
2212 b"unable to edit shared source repository config"
2211 b"unable to edit shared source repository config"
2213 )
2212 )
2214 )
2213 )
2215 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2214 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2216 else:
2215 else:
2217 paths = rcutil.userrcpath()
2216 paths = rcutil.userrcpath()
2218
2217
2219 for f in paths:
2218 for f in paths:
2220 if os.path.exists(f):
2219 if os.path.exists(f):
2221 break
2220 break
2222 else:
2221 else:
2223 if opts.get(b'global'):
2222 if opts.get(b'global'):
2224 samplehgrc = uimod.samplehgrcs[b'global']
2223 samplehgrc = uimod.samplehgrcs[b'global']
2225 elif opts.get(b'local'):
2224 elif opts.get(b'local'):
2226 samplehgrc = uimod.samplehgrcs[b'local']
2225 samplehgrc = uimod.samplehgrcs[b'local']
2227 else:
2226 else:
2228 samplehgrc = uimod.samplehgrcs[b'user']
2227 samplehgrc = uimod.samplehgrcs[b'user']
2229
2228
2230 f = paths[0]
2229 f = paths[0]
2231 fp = open(f, b"wb")
2230 fp = open(f, b"wb")
2232 fp.write(util.tonativeeol(samplehgrc))
2231 fp.write(util.tonativeeol(samplehgrc))
2233 fp.close()
2232 fp.close()
2234
2233
2235 editor = ui.geteditor()
2234 editor = ui.geteditor()
2236 ui.system(
2235 ui.system(
2237 b"%s \"%s\"" % (editor, f),
2236 b"%s \"%s\"" % (editor, f),
2238 onerr=error.Abort,
2237 onerr=error.Abort,
2239 errprefix=_(b"edit failed"),
2238 errprefix=_(b"edit failed"),
2240 blockedtag=b'config_edit',
2239 blockedtag=b'config_edit',
2241 )
2240 )
2242 return
2241 return
2243 ui.pager(b'config')
2242 ui.pager(b'config')
2244 fm = ui.formatter(b'config', opts)
2243 fm = ui.formatter(b'config', opts)
2245 for t, f in rcutil.rccomponents():
2244 for t, f in rcutil.rccomponents():
2246 if t == b'path':
2245 if t == b'path':
2247 ui.debug(b'read config from: %s\n' % f)
2246 ui.debug(b'read config from: %s\n' % f)
2248 elif t == b'resource':
2247 elif t == b'resource':
2249 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2248 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2250 elif t == b'items':
2249 elif t == b'items':
2251 # Don't print anything for 'items'.
2250 # Don't print anything for 'items'.
2252 pass
2251 pass
2253 else:
2252 else:
2254 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2253 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2255 untrusted = bool(opts.get(b'untrusted'))
2254 untrusted = bool(opts.get(b'untrusted'))
2256
2255
2257 selsections = selentries = []
2256 selsections = selentries = []
2258 if values:
2257 if values:
2259 selsections = [v for v in values if b'.' not in v]
2258 selsections = [v for v in values if b'.' not in v]
2260 selentries = [v for v in values if b'.' in v]
2259 selentries = [v for v in values if b'.' in v]
2261 uniquesel = len(selentries) == 1 and not selsections
2260 uniquesel = len(selentries) == 1 and not selsections
2262 selsections = set(selsections)
2261 selsections = set(selsections)
2263 selentries = set(selentries)
2262 selentries = set(selentries)
2264
2263
2265 matched = False
2264 matched = False
2266 for section, name, value in ui.walkconfig(untrusted=untrusted):
2265 for section, name, value in ui.walkconfig(untrusted=untrusted):
2267 source = ui.configsource(section, name, untrusted)
2266 source = ui.configsource(section, name, untrusted)
2268 value = pycompat.bytestr(value)
2267 value = pycompat.bytestr(value)
2269 defaultvalue = ui.configdefault(section, name)
2268 defaultvalue = ui.configdefault(section, name)
2270 if fm.isplain():
2269 if fm.isplain():
2271 source = source or b'none'
2270 source = source or b'none'
2272 value = value.replace(b'\n', b'\\n')
2271 value = value.replace(b'\n', b'\\n')
2273 entryname = section + b'.' + name
2272 entryname = section + b'.' + name
2274 if values and not (section in selsections or entryname in selentries):
2273 if values and not (section in selsections or entryname in selentries):
2275 continue
2274 continue
2276 fm.startitem()
2275 fm.startitem()
2277 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2276 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2278 if uniquesel:
2277 if uniquesel:
2279 fm.data(name=entryname)
2278 fm.data(name=entryname)
2280 fm.write(b'value', b'%s\n', value)
2279 fm.write(b'value', b'%s\n', value)
2281 else:
2280 else:
2282 fm.write(b'name value', b'%s=%s\n', entryname, value)
2281 fm.write(b'name value', b'%s=%s\n', entryname, value)
2283 if formatter.isprintable(defaultvalue):
2282 if formatter.isprintable(defaultvalue):
2284 fm.data(defaultvalue=defaultvalue)
2283 fm.data(defaultvalue=defaultvalue)
2285 elif isinstance(defaultvalue, list) and all(
2284 elif isinstance(defaultvalue, list) and all(
2286 formatter.isprintable(e) for e in defaultvalue
2285 formatter.isprintable(e) for e in defaultvalue
2287 ):
2286 ):
2288 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2287 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2289 # TODO: no idea how to process unsupported defaultvalue types
2288 # TODO: no idea how to process unsupported defaultvalue types
2290 matched = True
2289 matched = True
2291 fm.end()
2290 fm.end()
2292 if matched:
2291 if matched:
2293 return 0
2292 return 0
2294 return 1
2293 return 1
2295
2294
2296
2295
2297 @command(
2296 @command(
2298 b'continue',
2297 b'continue',
2299 dryrunopts,
2298 dryrunopts,
2300 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2299 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2301 helpbasic=True,
2300 helpbasic=True,
2302 )
2301 )
2303 def continuecmd(ui, repo, **opts):
2302 def continuecmd(ui, repo, **opts):
2304 """resumes an interrupted operation (EXPERIMENTAL)
2303 """resumes an interrupted operation (EXPERIMENTAL)
2305
2304
2306 Finishes a multistep operation like graft, histedit, rebase, merge,
2305 Finishes a multistep operation like graft, histedit, rebase, merge,
2307 and unshelve if they are in an interrupted state.
2306 and unshelve if they are in an interrupted state.
2308
2307
2309 use --dry-run/-n to dry run the command.
2308 use --dry-run/-n to dry run the command.
2310 """
2309 """
2311 dryrun = opts.get('dry_run')
2310 dryrun = opts.get('dry_run')
2312 contstate = cmdutil.getunfinishedstate(repo)
2311 contstate = cmdutil.getunfinishedstate(repo)
2313 if not contstate:
2312 if not contstate:
2314 raise error.Abort(_(b'no operation in progress'))
2313 raise error.Abort(_(b'no operation in progress'))
2315 if not contstate.continuefunc:
2314 if not contstate.continuefunc:
2316 raise error.Abort(
2315 raise error.Abort(
2317 (
2316 (
2318 _(b"%s in progress but does not support 'hg continue'")
2317 _(b"%s in progress but does not support 'hg continue'")
2319 % (contstate._opname)
2318 % (contstate._opname)
2320 ),
2319 ),
2321 hint=contstate.continuemsg(),
2320 hint=contstate.continuemsg(),
2322 )
2321 )
2323 if dryrun:
2322 if dryrun:
2324 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2323 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2325 return
2324 return
2326 return contstate.continuefunc(ui, repo)
2325 return contstate.continuefunc(ui, repo)
2327
2326
2328
2327
2329 @command(
2328 @command(
2330 b'copy|cp',
2329 b'copy|cp',
2331 [
2330 [
2332 (b'', b'forget', None, _(b'unmark a file as copied')),
2331 (b'', b'forget', None, _(b'unmark a file as copied')),
2333 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2332 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2334 (
2333 (
2335 b'',
2334 b'',
2336 b'at-rev',
2335 b'at-rev',
2337 b'',
2336 b'',
2338 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2337 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2339 _(b'REV'),
2338 _(b'REV'),
2340 ),
2339 ),
2341 (
2340 (
2342 b'f',
2341 b'f',
2343 b'force',
2342 b'force',
2344 None,
2343 None,
2345 _(b'forcibly copy over an existing managed file'),
2344 _(b'forcibly copy over an existing managed file'),
2346 ),
2345 ),
2347 ]
2346 ]
2348 + walkopts
2347 + walkopts
2349 + dryrunopts,
2348 + dryrunopts,
2350 _(b'[OPTION]... SOURCE... DEST'),
2349 _(b'[OPTION]... SOURCE... DEST'),
2351 helpcategory=command.CATEGORY_FILE_CONTENTS,
2350 helpcategory=command.CATEGORY_FILE_CONTENTS,
2352 )
2351 )
2353 def copy(ui, repo, *pats, **opts):
2352 def copy(ui, repo, *pats, **opts):
2354 """mark files as copied for the next commit
2353 """mark files as copied for the next commit
2355
2354
2356 Mark dest as having copies of source files. If dest is a
2355 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,
2356 directory, copies are put in that directory. If dest is a file,
2358 the source must be a single file.
2357 the source must be a single file.
2359
2358
2360 By default, this command copies the contents of files as they
2359 By default, this command copies the contents of files as they
2361 exist in the working directory. If invoked with -A/--after, the
2360 exist in the working directory. If invoked with -A/--after, the
2362 operation is recorded, but no copying is performed.
2361 operation is recorded, but no copying is performed.
2363
2362
2364 To undo marking a file as copied, use --forget. With that option,
2363 To undo marking a file as copied, use --forget. With that option,
2365 all given (positional) arguments are unmarked as copies. The destination
2364 all given (positional) arguments are unmarked as copies. The destination
2366 file(s) will be left in place (still tracked).
2365 file(s) will be left in place (still tracked).
2367
2366
2368 This command takes effect with the next commit by default.
2367 This command takes effect with the next commit by default.
2369
2368
2370 Returns 0 on success, 1 if errors are encountered.
2369 Returns 0 on success, 1 if errors are encountered.
2371 """
2370 """
2372 opts = pycompat.byteskwargs(opts)
2371 opts = pycompat.byteskwargs(opts)
2373 with repo.wlock():
2372 with repo.wlock():
2374 return cmdutil.copy(ui, repo, pats, opts)
2373 return cmdutil.copy(ui, repo, pats, opts)
2375
2374
2376
2375
2377 @command(
2376 @command(
2378 b'debugcommands',
2377 b'debugcommands',
2379 [],
2378 [],
2380 _(b'[COMMAND]'),
2379 _(b'[COMMAND]'),
2381 helpcategory=command.CATEGORY_HELP,
2380 helpcategory=command.CATEGORY_HELP,
2382 norepo=True,
2381 norepo=True,
2383 )
2382 )
2384 def debugcommands(ui, cmd=b'', *args):
2383 def debugcommands(ui, cmd=b'', *args):
2385 """list all available commands and options"""
2384 """list all available commands and options"""
2386 for cmd, vals in sorted(pycompat.iteritems(table)):
2385 for cmd, vals in sorted(pycompat.iteritems(table)):
2387 cmd = cmd.split(b'|')[0]
2386 cmd = cmd.split(b'|')[0]
2388 opts = b', '.join([i[1] for i in vals[1]])
2387 opts = b', '.join([i[1] for i in vals[1]])
2389 ui.write(b'%s: %s\n' % (cmd, opts))
2388 ui.write(b'%s: %s\n' % (cmd, opts))
2390
2389
2391
2390
2392 @command(
2391 @command(
2393 b'debugcomplete',
2392 b'debugcomplete',
2394 [(b'o', b'options', None, _(b'show the command options'))],
2393 [(b'o', b'options', None, _(b'show the command options'))],
2395 _(b'[-o] CMD'),
2394 _(b'[-o] CMD'),
2396 helpcategory=command.CATEGORY_HELP,
2395 helpcategory=command.CATEGORY_HELP,
2397 norepo=True,
2396 norepo=True,
2398 )
2397 )
2399 def debugcomplete(ui, cmd=b'', **opts):
2398 def debugcomplete(ui, cmd=b'', **opts):
2400 """returns the completion list associated with the given command"""
2399 """returns the completion list associated with the given command"""
2401
2400
2402 if opts.get('options'):
2401 if opts.get('options'):
2403 options = []
2402 options = []
2404 otables = [globalopts]
2403 otables = [globalopts]
2405 if cmd:
2404 if cmd:
2406 aliases, entry = cmdutil.findcmd(cmd, table, False)
2405 aliases, entry = cmdutil.findcmd(cmd, table, False)
2407 otables.append(entry[1])
2406 otables.append(entry[1])
2408 for t in otables:
2407 for t in otables:
2409 for o in t:
2408 for o in t:
2410 if b"(DEPRECATED)" in o[3]:
2409 if b"(DEPRECATED)" in o[3]:
2411 continue
2410 continue
2412 if o[0]:
2411 if o[0]:
2413 options.append(b'-%s' % o[0])
2412 options.append(b'-%s' % o[0])
2414 options.append(b'--%s' % o[1])
2413 options.append(b'--%s' % o[1])
2415 ui.write(b"%s\n" % b"\n".join(options))
2414 ui.write(b"%s\n" % b"\n".join(options))
2416 return
2415 return
2417
2416
2418 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2417 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2419 if ui.verbose:
2418 if ui.verbose:
2420 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2419 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2421 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2420 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2422
2421
2423
2422
2424 @command(
2423 @command(
2425 b'diff',
2424 b'diff',
2426 [
2425 [
2427 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2426 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2428 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2427 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2429 ]
2428 ]
2430 + diffopts
2429 + diffopts
2431 + diffopts2
2430 + diffopts2
2432 + walkopts
2431 + walkopts
2433 + subrepoopts,
2432 + subrepoopts,
2434 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2433 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2435 helpcategory=command.CATEGORY_FILE_CONTENTS,
2434 helpcategory=command.CATEGORY_FILE_CONTENTS,
2436 helpbasic=True,
2435 helpbasic=True,
2437 inferrepo=True,
2436 inferrepo=True,
2438 intents={INTENT_READONLY},
2437 intents={INTENT_READONLY},
2439 )
2438 )
2440 def diff(ui, repo, *pats, **opts):
2439 def diff(ui, repo, *pats, **opts):
2441 """diff repository (or selected files)
2440 """diff repository (or selected files)
2442
2441
2443 Show differences between revisions for the specified files.
2442 Show differences between revisions for the specified files.
2444
2443
2445 Differences between files are shown using the unified diff format.
2444 Differences between files are shown using the unified diff format.
2446
2445
2447 .. note::
2446 .. note::
2448
2447
2449 :hg:`diff` may generate unexpected results for merges, as it will
2448 :hg:`diff` may generate unexpected results for merges, as it will
2450 default to comparing against the working directory's first
2449 default to comparing against the working directory's first
2451 parent changeset if no revisions are specified.
2450 parent changeset if no revisions are specified.
2452
2451
2453 When two revision arguments are given, then changes are shown
2452 When two revision arguments are given, then changes are shown
2454 between those revisions. If only one revision is specified then
2453 between those revisions. If only one revision is specified then
2455 that revision is compared to the working directory, and, when no
2454 that revision is compared to the working directory, and, when no
2456 revisions are specified, the working directory files are compared
2455 revisions are specified, the working directory files are compared
2457 to its first parent.
2456 to its first parent.
2458
2457
2459 Alternatively you can specify -c/--change with a revision to see
2458 Alternatively you can specify -c/--change with a revision to see
2460 the changes in that changeset relative to its first parent.
2459 the changes in that changeset relative to its first parent.
2461
2460
2462 Without the -a/--text option, diff will avoid generating diffs of
2461 Without the -a/--text option, diff will avoid generating diffs of
2463 files it detects as binary. With -a, diff will generate a diff
2462 files it detects as binary. With -a, diff will generate a diff
2464 anyway, probably with undesirable results.
2463 anyway, probably with undesirable results.
2465
2464
2466 Use the -g/--git option to generate diffs in the git extended diff
2465 Use the -g/--git option to generate diffs in the git extended diff
2467 format. For more information, read :hg:`help diffs`.
2466 format. For more information, read :hg:`help diffs`.
2468
2467
2469 .. container:: verbose
2468 .. container:: verbose
2470
2469
2471 Examples:
2470 Examples:
2472
2471
2473 - compare a file in the current working directory to its parent::
2472 - compare a file in the current working directory to its parent::
2474
2473
2475 hg diff foo.c
2474 hg diff foo.c
2476
2475
2477 - compare two historical versions of a directory, with rename info::
2476 - compare two historical versions of a directory, with rename info::
2478
2477
2479 hg diff --git -r 1.0:1.2 lib/
2478 hg diff --git -r 1.0:1.2 lib/
2480
2479
2481 - get change stats relative to the last change on some date::
2480 - get change stats relative to the last change on some date::
2482
2481
2483 hg diff --stat -r "date('may 2')"
2482 hg diff --stat -r "date('may 2')"
2484
2483
2485 - diff all newly-added files that contain a keyword::
2484 - diff all newly-added files that contain a keyword::
2486
2485
2487 hg diff "set:added() and grep(GNU)"
2486 hg diff "set:added() and grep(GNU)"
2488
2487
2489 - compare a revision and its parents::
2488 - compare a revision and its parents::
2490
2489
2491 hg diff -c 9353 # compare against first parent
2490 hg diff -c 9353 # compare against first parent
2492 hg diff -r 9353^:9353 # same using revset syntax
2491 hg diff -r 9353^:9353 # same using revset syntax
2493 hg diff -r 9353^2:9353 # compare against the second parent
2492 hg diff -r 9353^2:9353 # compare against the second parent
2494
2493
2495 Returns 0 on success.
2494 Returns 0 on success.
2496 """
2495 """
2497
2496
2498 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2497 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2499 opts = pycompat.byteskwargs(opts)
2498 opts = pycompat.byteskwargs(opts)
2500 revs = opts.get(b'rev')
2499 revs = opts.get(b'rev')
2501 change = opts.get(b'change')
2500 change = opts.get(b'change')
2502 stat = opts.get(b'stat')
2501 stat = opts.get(b'stat')
2503 reverse = opts.get(b'reverse')
2502 reverse = opts.get(b'reverse')
2504
2503
2505 if change:
2504 if change:
2506 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2505 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2507 ctx2 = scmutil.revsingle(repo, change, None)
2506 ctx2 = scmutil.revsingle(repo, change, None)
2508 ctx1 = ctx2.p1()
2507 ctx1 = ctx2.p1()
2509 else:
2508 else:
2510 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2509 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2511 ctx1, ctx2 = scmutil.revpair(repo, revs)
2510 ctx1, ctx2 = scmutil.revpair(repo, revs)
2512
2511
2513 if reverse:
2512 if reverse:
2514 ctxleft = ctx2
2513 ctxleft = ctx2
2515 ctxright = ctx1
2514 ctxright = ctx1
2516 else:
2515 else:
2517 ctxleft = ctx1
2516 ctxleft = ctx1
2518 ctxright = ctx2
2517 ctxright = ctx2
2519
2518
2520 diffopts = patch.diffallopts(ui, opts)
2519 diffopts = patch.diffallopts(ui, opts)
2521 m = scmutil.match(ctx2, pats, opts)
2520 m = scmutil.match(ctx2, pats, opts)
2522 m = repo.narrowmatch(m)
2521 m = repo.narrowmatch(m)
2523 ui.pager(b'diff')
2522 ui.pager(b'diff')
2524 logcmdutil.diffordiffstat(
2523 logcmdutil.diffordiffstat(
2525 ui,
2524 ui,
2526 repo,
2525 repo,
2527 diffopts,
2526 diffopts,
2528 ctxleft,
2527 ctxleft,
2529 ctxright,
2528 ctxright,
2530 m,
2529 m,
2531 stat=stat,
2530 stat=stat,
2532 listsubrepos=opts.get(b'subrepos'),
2531 listsubrepos=opts.get(b'subrepos'),
2533 root=opts.get(b'root'),
2532 root=opts.get(b'root'),
2534 )
2533 )
2535
2534
2536
2535
2537 @command(
2536 @command(
2538 b'export',
2537 b'export',
2539 [
2538 [
2540 (
2539 (
2541 b'B',
2540 b'B',
2542 b'bookmark',
2541 b'bookmark',
2543 b'',
2542 b'',
2544 _(b'export changes only reachable by given bookmark'),
2543 _(b'export changes only reachable by given bookmark'),
2545 _(b'BOOKMARK'),
2544 _(b'BOOKMARK'),
2546 ),
2545 ),
2547 (
2546 (
2548 b'o',
2547 b'o',
2549 b'output',
2548 b'output',
2550 b'',
2549 b'',
2551 _(b'print output to file with formatted name'),
2550 _(b'print output to file with formatted name'),
2552 _(b'FORMAT'),
2551 _(b'FORMAT'),
2553 ),
2552 ),
2554 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2553 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2555 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2554 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2556 ]
2555 ]
2557 + diffopts
2556 + diffopts
2558 + formatteropts,
2557 + formatteropts,
2559 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2558 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2560 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2559 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2561 helpbasic=True,
2560 helpbasic=True,
2562 intents={INTENT_READONLY},
2561 intents={INTENT_READONLY},
2563 )
2562 )
2564 def export(ui, repo, *changesets, **opts):
2563 def export(ui, repo, *changesets, **opts):
2565 """dump the header and diffs for one or more changesets
2564 """dump the header and diffs for one or more changesets
2566
2565
2567 Print the changeset header and diffs for one or more revisions.
2566 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.
2567 If no revision is given, the parent of the working directory is used.
2569
2568
2570 The information shown in the changeset header is: author, date,
2569 The information shown in the changeset header is: author, date,
2571 branch name (if non-default), changeset hash, parent(s) and commit
2570 branch name (if non-default), changeset hash, parent(s) and commit
2572 comment.
2571 comment.
2573
2572
2574 .. note::
2573 .. note::
2575
2574
2576 :hg:`export` may generate unexpected diff output for merge
2575 :hg:`export` may generate unexpected diff output for merge
2577 changesets, as it will compare the merge changeset against its
2576 changesets, as it will compare the merge changeset against its
2578 first parent only.
2577 first parent only.
2579
2578
2580 Output may be to a file, in which case the name of the file is
2579 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
2580 given using a template string. See :hg:`help templates`. In addition
2582 to the common template keywords, the following formatting rules are
2581 to the common template keywords, the following formatting rules are
2583 supported:
2582 supported:
2584
2583
2585 :``%%``: literal "%" character
2584 :``%%``: literal "%" character
2586 :``%H``: changeset hash (40 hexadecimal digits)
2585 :``%H``: changeset hash (40 hexadecimal digits)
2587 :``%N``: number of patches being generated
2586 :``%N``: number of patches being generated
2588 :``%R``: changeset revision number
2587 :``%R``: changeset revision number
2589 :``%b``: basename of the exporting repository
2588 :``%b``: basename of the exporting repository
2590 :``%h``: short-form changeset hash (12 hexadecimal digits)
2589 :``%h``: short-form changeset hash (12 hexadecimal digits)
2591 :``%m``: first line of the commit message (only alphanumeric characters)
2590 :``%m``: first line of the commit message (only alphanumeric characters)
2592 :``%n``: zero-padded sequence number, starting at 1
2591 :``%n``: zero-padded sequence number, starting at 1
2593 :``%r``: zero-padded changeset revision number
2592 :``%r``: zero-padded changeset revision number
2594 :``\\``: literal "\\" character
2593 :``\\``: literal "\\" character
2595
2594
2596 Without the -a/--text option, export will avoid generating diffs
2595 Without the -a/--text option, export will avoid generating diffs
2597 of files it detects as binary. With -a, export will generate a
2596 of files it detects as binary. With -a, export will generate a
2598 diff anyway, probably with undesirable results.
2597 diff anyway, probably with undesirable results.
2599
2598
2600 With -B/--bookmark changesets reachable by the given bookmark are
2599 With -B/--bookmark changesets reachable by the given bookmark are
2601 selected.
2600 selected.
2602
2601
2603 Use the -g/--git option to generate diffs in the git extended diff
2602 Use the -g/--git option to generate diffs in the git extended diff
2604 format. See :hg:`help diffs` for more information.
2603 format. See :hg:`help diffs` for more information.
2605
2604
2606 With the --switch-parent option, the diff will be against the
2605 With the --switch-parent option, the diff will be against the
2607 second parent. It can be useful to review a merge.
2606 second parent. It can be useful to review a merge.
2608
2607
2609 .. container:: verbose
2608 .. container:: verbose
2610
2609
2611 Template:
2610 Template:
2612
2611
2613 The following keywords are supported in addition to the common template
2612 The following keywords are supported in addition to the common template
2614 keywords and functions. See also :hg:`help templates`.
2613 keywords and functions. See also :hg:`help templates`.
2615
2614
2616 :diff: String. Diff content.
2615 :diff: String. Diff content.
2617 :parents: List of strings. Parent nodes of the changeset.
2616 :parents: List of strings. Parent nodes of the changeset.
2618
2617
2619 Examples:
2618 Examples:
2620
2619
2621 - use export and import to transplant a bugfix to the current
2620 - use export and import to transplant a bugfix to the current
2622 branch::
2621 branch::
2623
2622
2624 hg export -r 9353 | hg import -
2623 hg export -r 9353 | hg import -
2625
2624
2626 - export all the changesets between two revisions to a file with
2625 - export all the changesets between two revisions to a file with
2627 rename information::
2626 rename information::
2628
2627
2629 hg export --git -r 123:150 > changes.txt
2628 hg export --git -r 123:150 > changes.txt
2630
2629
2631 - split outgoing changes into a series of patches with
2630 - split outgoing changes into a series of patches with
2632 descriptive names::
2631 descriptive names::
2633
2632
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2633 hg export -r "outgoing()" -o "%n-%m.patch"
2635
2634
2636 Returns 0 on success.
2635 Returns 0 on success.
2637 """
2636 """
2638 opts = pycompat.byteskwargs(opts)
2637 opts = pycompat.byteskwargs(opts)
2639 bookmark = opts.get(b'bookmark')
2638 bookmark = opts.get(b'bookmark')
2640 changesets += tuple(opts.get(b'rev', []))
2639 changesets += tuple(opts.get(b'rev', []))
2641
2640
2642 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2641 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2643
2642
2644 if bookmark:
2643 if bookmark:
2645 if bookmark not in repo._bookmarks:
2644 if bookmark not in repo._bookmarks:
2646 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2645 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2647
2646
2648 revs = scmutil.bookmarkrevs(repo, bookmark)
2647 revs = scmutil.bookmarkrevs(repo, bookmark)
2649 else:
2648 else:
2650 if not changesets:
2649 if not changesets:
2651 changesets = [b'.']
2650 changesets = [b'.']
2652
2651
2653 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2652 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2654 revs = scmutil.revrange(repo, changesets)
2653 revs = scmutil.revrange(repo, changesets)
2655
2654
2656 if not revs:
2655 if not revs:
2657 raise error.Abort(_(b"export requires at least one changeset"))
2656 raise error.Abort(_(b"export requires at least one changeset"))
2658 if len(revs) > 1:
2657 if len(revs) > 1:
2659 ui.note(_(b'exporting patches:\n'))
2658 ui.note(_(b'exporting patches:\n'))
2660 else:
2659 else:
2661 ui.note(_(b'exporting patch:\n'))
2660 ui.note(_(b'exporting patch:\n'))
2662
2661
2663 fntemplate = opts.get(b'output')
2662 fntemplate = opts.get(b'output')
2664 if cmdutil.isstdiofilename(fntemplate):
2663 if cmdutil.isstdiofilename(fntemplate):
2665 fntemplate = b''
2664 fntemplate = b''
2666
2665
2667 if fntemplate:
2666 if fntemplate:
2668 fm = formatter.nullformatter(ui, b'export', opts)
2667 fm = formatter.nullformatter(ui, b'export', opts)
2669 else:
2668 else:
2670 ui.pager(b'export')
2669 ui.pager(b'export')
2671 fm = ui.formatter(b'export', opts)
2670 fm = ui.formatter(b'export', opts)
2672 with fm:
2671 with fm:
2673 cmdutil.export(
2672 cmdutil.export(
2674 repo,
2673 repo,
2675 revs,
2674 revs,
2676 fm,
2675 fm,
2677 fntemplate=fntemplate,
2676 fntemplate=fntemplate,
2678 switch_parent=opts.get(b'switch_parent'),
2677 switch_parent=opts.get(b'switch_parent'),
2679 opts=patch.diffallopts(ui, opts),
2678 opts=patch.diffallopts(ui, opts),
2680 )
2679 )
2681
2680
2682
2681
2683 @command(
2682 @command(
2684 b'files',
2683 b'files',
2685 [
2684 [
2686 (
2685 (
2687 b'r',
2686 b'r',
2688 b'rev',
2687 b'rev',
2689 b'',
2688 b'',
2690 _(b'search the repository as it is in REV'),
2689 _(b'search the repository as it is in REV'),
2691 _(b'REV'),
2690 _(b'REV'),
2692 ),
2691 ),
2693 (
2692 (
2694 b'0',
2693 b'0',
2695 b'print0',
2694 b'print0',
2696 None,
2695 None,
2697 _(b'end filenames with NUL, for use with xargs'),
2696 _(b'end filenames with NUL, for use with xargs'),
2698 ),
2697 ),
2699 ]
2698 ]
2700 + walkopts
2699 + walkopts
2701 + formatteropts
2700 + formatteropts
2702 + subrepoopts,
2701 + subrepoopts,
2703 _(b'[OPTION]... [FILE]...'),
2702 _(b'[OPTION]... [FILE]...'),
2704 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2705 intents={INTENT_READONLY},
2704 intents={INTENT_READONLY},
2706 )
2705 )
2707 def files(ui, repo, *pats, **opts):
2706 def files(ui, repo, *pats, **opts):
2708 """list tracked files
2707 """list tracked files
2709
2708
2710 Print files under Mercurial control in the working directory or
2709 Print files under Mercurial control in the working directory or
2711 specified revision for given files (excluding removed files).
2710 specified revision for given files (excluding removed files).
2712 Files can be specified as filenames or filesets.
2711 Files can be specified as filenames or filesets.
2713
2712
2714 If no files are given to match, this command prints the names
2713 If no files are given to match, this command prints the names
2715 of all files under Mercurial control.
2714 of all files under Mercurial control.
2716
2715
2717 .. container:: verbose
2716 .. container:: verbose
2718
2717
2719 Template:
2718 Template:
2720
2719
2721 The following keywords are supported in addition to the common template
2720 The following keywords are supported in addition to the common template
2722 keywords and functions. See also :hg:`help templates`.
2721 keywords and functions. See also :hg:`help templates`.
2723
2722
2724 :flags: String. Character denoting file's symlink and executable bits.
2723 :flags: String. Character denoting file's symlink and executable bits.
2725 :path: String. Repository-absolute path of the file.
2724 :path: String. Repository-absolute path of the file.
2726 :size: Integer. Size of the file in bytes.
2725 :size: Integer. Size of the file in bytes.
2727
2726
2728 Examples:
2727 Examples:
2729
2728
2730 - list all files under the current directory::
2729 - list all files under the current directory::
2731
2730
2732 hg files .
2731 hg files .
2733
2732
2734 - shows sizes and flags for current revision::
2733 - shows sizes and flags for current revision::
2735
2734
2736 hg files -vr .
2735 hg files -vr .
2737
2736
2738 - list all files named README::
2737 - list all files named README::
2739
2738
2740 hg files -I "**/README"
2739 hg files -I "**/README"
2741
2740
2742 - list all binary files::
2741 - list all binary files::
2743
2742
2744 hg files "set:binary()"
2743 hg files "set:binary()"
2745
2744
2746 - find files containing a regular expression::
2745 - find files containing a regular expression::
2747
2746
2748 hg files "set:grep('bob')"
2747 hg files "set:grep('bob')"
2749
2748
2750 - search tracked file contents with xargs and grep::
2749 - search tracked file contents with xargs and grep::
2751
2750
2752 hg files -0 | xargs -0 grep foo
2751 hg files -0 | xargs -0 grep foo
2753
2752
2754 See :hg:`help patterns` and :hg:`help filesets` for more information
2753 See :hg:`help patterns` and :hg:`help filesets` for more information
2755 on specifying file patterns.
2754 on specifying file patterns.
2756
2755
2757 Returns 0 if a match is found, 1 otherwise.
2756 Returns 0 if a match is found, 1 otherwise.
2758
2757
2759 """
2758 """
2760
2759
2761 opts = pycompat.byteskwargs(opts)
2760 opts = pycompat.byteskwargs(opts)
2762 rev = opts.get(b'rev')
2761 rev = opts.get(b'rev')
2763 if rev:
2762 if rev:
2764 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2765 ctx = scmutil.revsingle(repo, rev, None)
2764 ctx = scmutil.revsingle(repo, rev, None)
2766
2765
2767 end = b'\n'
2766 end = b'\n'
2768 if opts.get(b'print0'):
2767 if opts.get(b'print0'):
2769 end = b'\0'
2768 end = b'\0'
2770 fmt = b'%s' + end
2769 fmt = b'%s' + end
2771
2770
2772 m = scmutil.match(ctx, pats, opts)
2771 m = scmutil.match(ctx, pats, opts)
2773 ui.pager(b'files')
2772 ui.pager(b'files')
2774 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2773 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2775 with ui.formatter(b'files', opts) as fm:
2774 with ui.formatter(b'files', opts) as fm:
2776 return cmdutil.files(
2775 return cmdutil.files(
2777 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2776 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2778 )
2777 )
2779
2778
2780
2779
2781 @command(
2780 @command(
2782 b'forget',
2781 b'forget',
2783 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2782 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2784 + walkopts
2783 + walkopts
2785 + dryrunopts,
2784 + dryrunopts,
2786 _(b'[OPTION]... FILE...'),
2785 _(b'[OPTION]... FILE...'),
2787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2788 helpbasic=True,
2787 helpbasic=True,
2789 inferrepo=True,
2788 inferrepo=True,
2790 )
2789 )
2791 def forget(ui, repo, *pats, **opts):
2790 def forget(ui, repo, *pats, **opts):
2792 """forget the specified files on the next commit
2791 """forget the specified files on the next commit
2793
2792
2794 Mark the specified files so they will no longer be tracked
2793 Mark the specified files so they will no longer be tracked
2795 after the next commit.
2794 after the next commit.
2796
2795
2797 This only removes files from the current branch, not from the
2796 This only removes files from the current branch, not from the
2798 entire project history, and it does not delete them from the
2797 entire project history, and it does not delete them from the
2799 working directory.
2798 working directory.
2800
2799
2801 To delete the file from the working directory, see :hg:`remove`.
2800 To delete the file from the working directory, see :hg:`remove`.
2802
2801
2803 To undo a forget before the next commit, see :hg:`add`.
2802 To undo a forget before the next commit, see :hg:`add`.
2804
2803
2805 .. container:: verbose
2804 .. container:: verbose
2806
2805
2807 Examples:
2806 Examples:
2808
2807
2809 - forget newly-added binary files::
2808 - forget newly-added binary files::
2810
2809
2811 hg forget "set:added() and binary()"
2810 hg forget "set:added() and binary()"
2812
2811
2813 - forget files that would be excluded by .hgignore::
2812 - forget files that would be excluded by .hgignore::
2814
2813
2815 hg forget "set:hgignore()"
2814 hg forget "set:hgignore()"
2816
2815
2817 Returns 0 on success.
2816 Returns 0 on success.
2818 """
2817 """
2819
2818
2820 opts = pycompat.byteskwargs(opts)
2819 opts = pycompat.byteskwargs(opts)
2821 if not pats:
2820 if not pats:
2822 raise error.Abort(_(b'no files specified'))
2821 raise error.Abort(_(b'no files specified'))
2823
2822
2824 m = scmutil.match(repo[None], pats, opts)
2823 m = scmutil.match(repo[None], pats, opts)
2825 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2824 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2826 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2825 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2827 rejected = cmdutil.forget(
2826 rejected = cmdutil.forget(
2828 ui,
2827 ui,
2829 repo,
2828 repo,
2830 m,
2829 m,
2831 prefix=b"",
2830 prefix=b"",
2832 uipathfn=uipathfn,
2831 uipathfn=uipathfn,
2833 explicitonly=False,
2832 explicitonly=False,
2834 dryrun=dryrun,
2833 dryrun=dryrun,
2835 interactive=interactive,
2834 interactive=interactive,
2836 )[0]
2835 )[0]
2837 return rejected and 1 or 0
2836 return rejected and 1 or 0
2838
2837
2839
2838
2840 @command(
2839 @command(
2841 b'graft',
2840 b'graft',
2842 [
2841 [
2843 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2842 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2844 (
2843 (
2845 b'',
2844 b'',
2846 b'base',
2845 b'base',
2847 b'',
2846 b'',
2848 _(b'base revision when doing the graft merge (ADVANCED)'),
2847 _(b'base revision when doing the graft merge (ADVANCED)'),
2849 _(b'REV'),
2848 _(b'REV'),
2850 ),
2849 ),
2851 (b'c', b'continue', False, _(b'resume interrupted graft')),
2850 (b'c', b'continue', False, _(b'resume interrupted graft')),
2852 (b'', b'stop', False, _(b'stop interrupted graft')),
2851 (b'', b'stop', False, _(b'stop interrupted graft')),
2853 (b'', b'abort', False, _(b'abort interrupted graft')),
2852 (b'', b'abort', False, _(b'abort interrupted graft')),
2854 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2853 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2855 (b'', b'log', None, _(b'append graft info to log message')),
2854 (b'', b'log', None, _(b'append graft info to log message')),
2856 (
2855 (
2857 b'',
2856 b'',
2858 b'no-commit',
2857 b'no-commit',
2859 None,
2858 None,
2860 _(b"don't commit, just apply the changes in working directory"),
2859 _(b"don't commit, just apply the changes in working directory"),
2861 ),
2860 ),
2862 (b'f', b'force', False, _(b'force graft')),
2861 (b'f', b'force', False, _(b'force graft')),
2863 (
2862 (
2864 b'D',
2863 b'D',
2865 b'currentdate',
2864 b'currentdate',
2866 False,
2865 False,
2867 _(b'record the current date as commit date'),
2866 _(b'record the current date as commit date'),
2868 ),
2867 ),
2869 (
2868 (
2870 b'U',
2869 b'U',
2871 b'currentuser',
2870 b'currentuser',
2872 False,
2871 False,
2873 _(b'record the current user as committer'),
2872 _(b'record the current user as committer'),
2874 ),
2873 ),
2875 ]
2874 ]
2876 + commitopts2
2875 + commitopts2
2877 + mergetoolopts
2876 + mergetoolopts
2878 + dryrunopts,
2877 + dryrunopts,
2879 _(b'[OPTION]... [-r REV]... REV...'),
2878 _(b'[OPTION]... [-r REV]... REV...'),
2880 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2879 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2881 )
2880 )
2882 def graft(ui, repo, *revs, **opts):
2881 def graft(ui, repo, *revs, **opts):
2883 '''copy changes from other branches onto the current branch
2882 '''copy changes from other branches onto the current branch
2884
2883
2885 This command uses Mercurial's merge logic to copy individual
2884 This command uses Mercurial's merge logic to copy individual
2886 changes from other branches without merging branches in the
2885 changes from other branches without merging branches in the
2887 history graph. This is sometimes known as 'backporting' or
2886 history graph. This is sometimes known as 'backporting' or
2888 'cherry-picking'. By default, graft will copy user, date, and
2887 'cherry-picking'. By default, graft will copy user, date, and
2889 description from the source changesets.
2888 description from the source changesets.
2890
2889
2891 Changesets that are ancestors of the current revision, that have
2890 Changesets that are ancestors of the current revision, that have
2892 already been grafted, or that are merges will be skipped.
2891 already been grafted, or that are merges will be skipped.
2893
2892
2894 If --log is specified, log messages will have a comment appended
2893 If --log is specified, log messages will have a comment appended
2895 of the form::
2894 of the form::
2896
2895
2897 (grafted from CHANGESETHASH)
2896 (grafted from CHANGESETHASH)
2898
2897
2899 If --force is specified, revisions will be grafted even if they
2898 If --force is specified, revisions will be grafted even if they
2900 are already ancestors of, or have been grafted to, the destination.
2899 are already ancestors of, or have been grafted to, the destination.
2901 This is useful when the revisions have since been backed out.
2900 This is useful when the revisions have since been backed out.
2902
2901
2903 If a graft merge results in conflicts, the graft process is
2902 If a graft merge results in conflicts, the graft process is
2904 interrupted so that the current merge can be manually resolved.
2903 interrupted so that the current merge can be manually resolved.
2905 Once all conflicts are addressed, the graft process can be
2904 Once all conflicts are addressed, the graft process can be
2906 continued with the -c/--continue option.
2905 continued with the -c/--continue option.
2907
2906
2908 The -c/--continue option reapplies all the earlier options.
2907 The -c/--continue option reapplies all the earlier options.
2909
2908
2910 .. container:: verbose
2909 .. container:: verbose
2911
2910
2912 The --base option exposes more of how graft internally uses merge with a
2911 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
2912 custom base revision. --base can be used to specify another ancestor than
2914 the first and only parent.
2913 the first and only parent.
2915
2914
2916 The command::
2915 The command::
2917
2916
2918 hg graft -r 345 --base 234
2917 hg graft -r 345 --base 234
2919
2918
2920 is thus pretty much the same as::
2919 is thus pretty much the same as::
2921
2920
2922 hg diff -r 234 -r 345 | hg import
2921 hg diff -r 234 -r 345 | hg import
2923
2922
2924 but using merge to resolve conflicts and track moved files.
2923 but using merge to resolve conflicts and track moved files.
2925
2924
2926 The result of a merge can thus be backported as a single commit by
2925 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
2926 specifying one of the merge parents as base, and thus effectively
2928 grafting the changes from the other side.
2927 grafting the changes from the other side.
2929
2928
2930 It is also possible to collapse multiple changesets and clean up history
2929 It is also possible to collapse multiple changesets and clean up history
2931 by specifying another ancestor as base, much like rebase --collapse
2930 by specifying another ancestor as base, much like rebase --collapse
2932 --keep.
2931 --keep.
2933
2932
2934 The commit message can be tweaked after the fact using commit --amend .
2933 The commit message can be tweaked after the fact using commit --amend .
2935
2934
2936 For using non-ancestors as the base to backout changes, see the backout
2935 For using non-ancestors as the base to backout changes, see the backout
2937 command and the hidden --parent option.
2936 command and the hidden --parent option.
2938
2937
2939 .. container:: verbose
2938 .. container:: verbose
2940
2939
2941 Examples:
2940 Examples:
2942
2941
2943 - copy a single change to the stable branch and edit its description::
2942 - copy a single change to the stable branch and edit its description::
2944
2943
2945 hg update stable
2944 hg update stable
2946 hg graft --edit 9393
2945 hg graft --edit 9393
2947
2946
2948 - graft a range of changesets with one exception, updating dates::
2947 - graft a range of changesets with one exception, updating dates::
2949
2948
2950 hg graft -D "2085::2093 and not 2091"
2949 hg graft -D "2085::2093 and not 2091"
2951
2950
2952 - continue a graft after resolving conflicts::
2951 - continue a graft after resolving conflicts::
2953
2952
2954 hg graft -c
2953 hg graft -c
2955
2954
2956 - show the source of a grafted changeset::
2955 - show the source of a grafted changeset::
2957
2956
2958 hg log --debug -r .
2957 hg log --debug -r .
2959
2958
2960 - show revisions sorted by date::
2959 - show revisions sorted by date::
2961
2960
2962 hg log -r "sort(all(), date)"
2961 hg log -r "sort(all(), date)"
2963
2962
2964 - backport the result of a merge as a single commit::
2963 - backport the result of a merge as a single commit::
2965
2964
2966 hg graft -r 123 --base 123^
2965 hg graft -r 123 --base 123^
2967
2966
2968 - land a feature branch as one changeset::
2967 - land a feature branch as one changeset::
2969
2968
2970 hg up -cr default
2969 hg up -cr default
2971 hg graft -r featureX --base "ancestor('featureX', 'default')"
2970 hg graft -r featureX --base "ancestor('featureX', 'default')"
2972
2971
2973 See :hg:`help revisions` for more about specifying revisions.
2972 See :hg:`help revisions` for more about specifying revisions.
2974
2973
2975 Returns 0 on successful completion, 1 if there are unresolved files.
2974 Returns 0 on successful completion, 1 if there are unresolved files.
2976 '''
2975 '''
2977 with repo.wlock():
2976 with repo.wlock():
2978 return _dograft(ui, repo, *revs, **opts)
2977 return _dograft(ui, repo, *revs, **opts)
2979
2978
2980
2979
2981 def _dograft(ui, repo, *revs, **opts):
2980 def _dograft(ui, repo, *revs, **opts):
2982 opts = pycompat.byteskwargs(opts)
2981 opts = pycompat.byteskwargs(opts)
2983 if revs and opts.get(b'rev'):
2982 if revs and opts.get(b'rev'):
2984 ui.warn(
2983 ui.warn(
2985 _(
2984 _(
2986 b'warning: inconsistent use of --rev might give unexpected '
2985 b'warning: inconsistent use of --rev might give unexpected '
2987 b'revision ordering!\n'
2986 b'revision ordering!\n'
2988 )
2987 )
2989 )
2988 )
2990
2989
2991 revs = list(revs)
2990 revs = list(revs)
2992 revs.extend(opts.get(b'rev'))
2991 revs.extend(opts.get(b'rev'))
2993 # a dict of data to be stored in state file
2992 # a dict of data to be stored in state file
2994 statedata = {}
2993 statedata = {}
2995 # list of new nodes created by ongoing graft
2994 # list of new nodes created by ongoing graft
2996 statedata[b'newnodes'] = []
2995 statedata[b'newnodes'] = []
2997
2996
2998 cmdutil.resolvecommitoptions(ui, opts)
2997 cmdutil.resolvecommitoptions(ui, opts)
2999
2998
3000 editor = cmdutil.getcommiteditor(
2999 editor = cmdutil.getcommiteditor(
3001 editform=b'graft', **pycompat.strkwargs(opts)
3000 editform=b'graft', **pycompat.strkwargs(opts)
3002 )
3001 )
3003
3002
3004 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3003 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3005
3004
3006 cont = False
3005 cont = False
3007 if opts.get(b'no_commit'):
3006 if opts.get(b'no_commit'):
3008 cmdutil.check_incompatible_arguments(
3007 cmdutil.check_incompatible_arguments(
3009 opts,
3008 opts,
3010 b'no_commit',
3009 b'no_commit',
3011 [b'edit', b'currentuser', b'currentdate', b'log'],
3010 [b'edit', b'currentuser', b'currentdate', b'log'],
3012 )
3011 )
3013
3012
3014 graftstate = statemod.cmdstate(repo, b'graftstate')
3013 graftstate = statemod.cmdstate(repo, b'graftstate')
3015
3014
3016 if opts.get(b'stop'):
3015 if opts.get(b'stop'):
3017 cmdutil.check_incompatible_arguments(
3016 cmdutil.check_incompatible_arguments(
3018 opts,
3017 opts,
3019 b'stop',
3018 b'stop',
3020 [
3019 [
3021 b'edit',
3020 b'edit',
3022 b'log',
3021 b'log',
3023 b'user',
3022 b'user',
3024 b'date',
3023 b'date',
3025 b'currentdate',
3024 b'currentdate',
3026 b'currentuser',
3025 b'currentuser',
3027 b'rev',
3026 b'rev',
3028 ],
3027 ],
3029 )
3028 )
3030 return _stopgraft(ui, repo, graftstate)
3029 return _stopgraft(ui, repo, graftstate)
3031 elif opts.get(b'abort'):
3030 elif opts.get(b'abort'):
3032 cmdutil.check_incompatible_arguments(
3031 cmdutil.check_incompatible_arguments(
3033 opts,
3032 opts,
3034 b'abort',
3033 b'abort',
3035 [
3034 [
3036 b'edit',
3035 b'edit',
3037 b'log',
3036 b'log',
3038 b'user',
3037 b'user',
3039 b'date',
3038 b'date',
3040 b'currentdate',
3039 b'currentdate',
3041 b'currentuser',
3040 b'currentuser',
3042 b'rev',
3041 b'rev',
3043 ],
3042 ],
3044 )
3043 )
3045 return cmdutil.abortgraft(ui, repo, graftstate)
3044 return cmdutil.abortgraft(ui, repo, graftstate)
3046 elif opts.get(b'continue'):
3045 elif opts.get(b'continue'):
3047 cont = True
3046 cont = True
3048 if revs:
3047 if revs:
3049 raise error.Abort(_(b"can't specify --continue and revisions"))
3048 raise error.Abort(_(b"can't specify --continue and revisions"))
3050 # read in unfinished revisions
3049 # read in unfinished revisions
3051 if graftstate.exists():
3050 if graftstate.exists():
3052 statedata = cmdutil.readgraftstate(repo, graftstate)
3051 statedata = cmdutil.readgraftstate(repo, graftstate)
3053 if statedata.get(b'date'):
3052 if statedata.get(b'date'):
3054 opts[b'date'] = statedata[b'date']
3053 opts[b'date'] = statedata[b'date']
3055 if statedata.get(b'user'):
3054 if statedata.get(b'user'):
3056 opts[b'user'] = statedata[b'user']
3055 opts[b'user'] = statedata[b'user']
3057 if statedata.get(b'log'):
3056 if statedata.get(b'log'):
3058 opts[b'log'] = True
3057 opts[b'log'] = True
3059 if statedata.get(b'no_commit'):
3058 if statedata.get(b'no_commit'):
3060 opts[b'no_commit'] = statedata.get(b'no_commit')
3059 opts[b'no_commit'] = statedata.get(b'no_commit')
3061 if statedata.get(b'base'):
3060 if statedata.get(b'base'):
3062 opts[b'base'] = statedata.get(b'base')
3061 opts[b'base'] = statedata.get(b'base')
3063 nodes = statedata[b'nodes']
3062 nodes = statedata[b'nodes']
3064 revs = [repo[node].rev() for node in nodes]
3063 revs = [repo[node].rev() for node in nodes]
3065 else:
3064 else:
3066 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3067 else:
3066 else:
3068 if not revs:
3067 if not revs:
3069 raise error.Abort(_(b'no revisions specified'))
3068 raise error.Abort(_(b'no revisions specified'))
3070 cmdutil.checkunfinished(repo)
3069 cmdutil.checkunfinished(repo)
3071 cmdutil.bailifchanged(repo)
3070 cmdutil.bailifchanged(repo)
3072 revs = scmutil.revrange(repo, revs)
3071 revs = scmutil.revrange(repo, revs)
3073
3072
3074 skipped = set()
3073 skipped = set()
3075 basectx = None
3074 basectx = None
3076 if opts.get(b'base'):
3075 if opts.get(b'base'):
3077 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3076 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3078 if basectx is None:
3077 if basectx is None:
3079 # check for merges
3078 # check for merges
3080 for rev in repo.revs(b'%ld and merge()', revs):
3079 for rev in repo.revs(b'%ld and merge()', revs):
3081 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3080 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3082 skipped.add(rev)
3081 skipped.add(rev)
3083 revs = [r for r in revs if r not in skipped]
3082 revs = [r for r in revs if r not in skipped]
3084 if not revs:
3083 if not revs:
3085 return -1
3084 return -1
3086 if basectx is not None and len(revs) != 1:
3085 if basectx is not None and len(revs) != 1:
3087 raise error.Abort(_(b'only one revision allowed with --base '))
3086 raise error.Abort(_(b'only one revision allowed with --base '))
3088
3087
3089 # Don't check in the --continue case, in effect retaining --force across
3088 # Don't check in the --continue case, in effect retaining --force across
3090 # --continues. That's because without --force, any revisions we decided to
3089 # --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
3090 # 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
3091 # 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
3092 # skipped would not have been filtered out, and if they hadn't been applied
3094 # already, they'd have been in the graftstate.
3093 # already, they'd have been in the graftstate.
3095 if not (cont or opts.get(b'force')) and basectx is None:
3094 if not (cont or opts.get(b'force')) and basectx is None:
3096 # check for ancestors of dest branch
3095 # check for ancestors of dest branch
3097 ancestors = repo.revs(b'%ld & (::.)', revs)
3096 ancestors = repo.revs(b'%ld & (::.)', revs)
3098 for rev in ancestors:
3097 for rev in ancestors:
3099 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3098 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3100
3099
3101 revs = [r for r in revs if r not in ancestors]
3100 revs = [r for r in revs if r not in ancestors]
3102
3101
3103 if not revs:
3102 if not revs:
3104 return -1
3103 return -1
3105
3104
3106 # analyze revs for earlier grafts
3105 # analyze revs for earlier grafts
3107 ids = {}
3106 ids = {}
3108 for ctx in repo.set(b"%ld", revs):
3107 for ctx in repo.set(b"%ld", revs):
3109 ids[ctx.hex()] = ctx.rev()
3108 ids[ctx.hex()] = ctx.rev()
3110 n = ctx.extra().get(b'source')
3109 n = ctx.extra().get(b'source')
3111 if n:
3110 if n:
3112 ids[n] = ctx.rev()
3111 ids[n] = ctx.rev()
3113
3112
3114 # check ancestors for earlier grafts
3113 # check ancestors for earlier grafts
3115 ui.debug(b'scanning for duplicate grafts\n')
3114 ui.debug(b'scanning for duplicate grafts\n')
3116
3115
3117 # The only changesets we can be sure doesn't contain grafts of any
3116 # 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:
3117 # 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):
3118 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3120 ctx = repo[rev]
3119 ctx = repo[rev]
3121 n = ctx.extra().get(b'source')
3120 n = ctx.extra().get(b'source')
3122 if n in ids:
3121 if n in ids:
3123 try:
3122 try:
3124 r = repo[n].rev()
3123 r = repo[n].rev()
3125 except error.RepoLookupError:
3124 except error.RepoLookupError:
3126 r = None
3125 r = None
3127 if r in revs:
3126 if r in revs:
3128 ui.warn(
3127 ui.warn(
3129 _(
3128 _(
3130 b'skipping revision %d:%s '
3129 b'skipping revision %d:%s '
3131 b'(already grafted to %d:%s)\n'
3130 b'(already grafted to %d:%s)\n'
3132 )
3131 )
3133 % (r, repo[r], rev, ctx)
3132 % (r, repo[r], rev, ctx)
3134 )
3133 )
3135 revs.remove(r)
3134 revs.remove(r)
3136 elif ids[n] in revs:
3135 elif ids[n] in revs:
3137 if r is None:
3136 if r is None:
3138 ui.warn(
3137 ui.warn(
3139 _(
3138 _(
3140 b'skipping already grafted revision %d:%s '
3139 b'skipping already grafted revision %d:%s '
3141 b'(%d:%s also has unknown origin %s)\n'
3140 b'(%d:%s also has unknown origin %s)\n'
3142 )
3141 )
3143 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3142 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3144 )
3143 )
3145 else:
3144 else:
3146 ui.warn(
3145 ui.warn(
3147 _(
3146 _(
3148 b'skipping already grafted revision %d:%s '
3147 b'skipping already grafted revision %d:%s '
3149 b'(%d:%s also has origin %d:%s)\n'
3148 b'(%d:%s also has origin %d:%s)\n'
3150 )
3149 )
3151 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3150 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3152 )
3151 )
3153 revs.remove(ids[n])
3152 revs.remove(ids[n])
3154 elif ctx.hex() in ids:
3153 elif ctx.hex() in ids:
3155 r = ids[ctx.hex()]
3154 r = ids[ctx.hex()]
3156 if r in revs:
3155 if r in revs:
3157 ui.warn(
3156 ui.warn(
3158 _(
3157 _(
3159 b'skipping already grafted revision %d:%s '
3158 b'skipping already grafted revision %d:%s '
3160 b'(was grafted from %d:%s)\n'
3159 b'(was grafted from %d:%s)\n'
3161 )
3160 )
3162 % (r, repo[r], rev, ctx)
3161 % (r, repo[r], rev, ctx)
3163 )
3162 )
3164 revs.remove(r)
3163 revs.remove(r)
3165 if not revs:
3164 if not revs:
3166 return -1
3165 return -1
3167
3166
3168 if opts.get(b'no_commit'):
3167 if opts.get(b'no_commit'):
3169 statedata[b'no_commit'] = True
3168 statedata[b'no_commit'] = True
3170 if opts.get(b'base'):
3169 if opts.get(b'base'):
3171 statedata[b'base'] = opts[b'base']
3170 statedata[b'base'] = opts[b'base']
3172 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3173 desc = b'%d:%s "%s"' % (
3172 desc = b'%d:%s "%s"' % (
3174 ctx.rev(),
3173 ctx.rev(),
3175 ctx,
3174 ctx,
3176 ctx.description().split(b'\n', 1)[0],
3175 ctx.description().split(b'\n', 1)[0],
3177 )
3176 )
3178 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3179 if names:
3178 if names:
3180 desc += b' (%s)' % b' '.join(names)
3179 desc += b' (%s)' % b' '.join(names)
3181 ui.status(_(b'grafting %s\n') % desc)
3180 ui.status(_(b'grafting %s\n') % desc)
3182 if opts.get(b'dry_run'):
3181 if opts.get(b'dry_run'):
3183 continue
3182 continue
3184
3183
3185 source = ctx.extra().get(b'source')
3184 source = ctx.extra().get(b'source')
3186 extra = {}
3185 extra = {}
3187 if source:
3186 if source:
3188 extra[b'source'] = source
3187 extra[b'source'] = source
3189 extra[b'intermediate-source'] = ctx.hex()
3188 extra[b'intermediate-source'] = ctx.hex()
3190 else:
3189 else:
3191 extra[b'source'] = ctx.hex()
3190 extra[b'source'] = ctx.hex()
3192 user = ctx.user()
3191 user = ctx.user()
3193 if opts.get(b'user'):
3192 if opts.get(b'user'):
3194 user = opts[b'user']
3193 user = opts[b'user']
3195 statedata[b'user'] = user
3194 statedata[b'user'] = user
3196 date = ctx.date()
3195 date = ctx.date()
3197 if opts.get(b'date'):
3196 if opts.get(b'date'):
3198 date = opts[b'date']
3197 date = opts[b'date']
3199 statedata[b'date'] = date
3198 statedata[b'date'] = date
3200 message = ctx.description()
3199 message = ctx.description()
3201 if opts.get(b'log'):
3200 if opts.get(b'log'):
3202 message += b'\n(grafted from %s)' % ctx.hex()
3201 message += b'\n(grafted from %s)' % ctx.hex()
3203 statedata[b'log'] = True
3202 statedata[b'log'] = True
3204
3203
3205 # we don't merge the first commit when continuing
3204 # we don't merge the first commit when continuing
3206 if not cont:
3205 if not cont:
3207 # perform the graft merge with p1(rev) as 'ancestor'
3206 # perform the graft merge with p1(rev) as 'ancestor'
3208 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3209 base = ctx.p1() if basectx is None else basectx
3208 base = ctx.p1() if basectx is None else basectx
3210 with ui.configoverride(overrides, b'graft'):
3209 with ui.configoverride(overrides, b'graft'):
3211 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3212 # report any conflicts
3211 # report any conflicts
3213 if stats.unresolvedcount > 0:
3212 if stats.unresolvedcount > 0:
3214 # write out state for --continue
3213 # write out state for --continue
3215 nodes = [repo[rev].hex() for rev in revs[pos:]]
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3216 statedata[b'nodes'] = nodes
3215 statedata[b'nodes'] = nodes
3217 stateversion = 1
3216 stateversion = 1
3218 graftstate.save(stateversion, statedata)
3217 graftstate.save(stateversion, statedata)
3219 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3218 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3220 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3219 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3221 return 1
3220 return 1
3222 else:
3221 else:
3223 cont = False
3222 cont = False
3224
3223
3225 # commit if --no-commit is false
3224 # commit if --no-commit is false
3226 if not opts.get(b'no_commit'):
3225 if not opts.get(b'no_commit'):
3227 node = repo.commit(
3226 node = repo.commit(
3228 text=message, user=user, date=date, extra=extra, editor=editor
3227 text=message, user=user, date=date, extra=extra, editor=editor
3229 )
3228 )
3230 if node is None:
3229 if node is None:
3231 ui.warn(
3230 ui.warn(
3232 _(b'note: graft of %d:%s created no changes to commit\n')
3231 _(b'note: graft of %d:%s created no changes to commit\n')
3233 % (ctx.rev(), ctx)
3232 % (ctx.rev(), ctx)
3234 )
3233 )
3235 # checking that newnodes exist because old state files won't have it
3234 # checking that newnodes exist because old state files won't have it
3236 elif statedata.get(b'newnodes') is not None:
3235 elif statedata.get(b'newnodes') is not None:
3237 statedata[b'newnodes'].append(node)
3236 statedata[b'newnodes'].append(node)
3238
3237
3239 # remove state when we complete successfully
3238 # remove state when we complete successfully
3240 if not opts.get(b'dry_run'):
3239 if not opts.get(b'dry_run'):
3241 graftstate.delete()
3240 graftstate.delete()
3242
3241
3243 return 0
3242 return 0
3244
3243
3245
3244
3246 def _stopgraft(ui, repo, graftstate):
3245 def _stopgraft(ui, repo, graftstate):
3247 """stop the interrupted graft"""
3246 """stop the interrupted graft"""
3248 if not graftstate.exists():
3247 if not graftstate.exists():
3249 raise error.Abort(_(b"no interrupted graft found"))
3248 raise error.Abort(_(b"no interrupted graft found"))
3250 pctx = repo[b'.']
3249 pctx = repo[b'.']
3251 mergemod.clean_update(pctx)
3250 mergemod.clean_update(pctx)
3252 graftstate.delete()
3251 graftstate.delete()
3253 ui.status(_(b"stopped the interrupted graft\n"))
3252 ui.status(_(b"stopped the interrupted graft\n"))
3254 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3253 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3255 return 0
3254 return 0
3256
3255
3257
3256
3258 statemod.addunfinished(
3257 statemod.addunfinished(
3259 b'graft',
3258 b'graft',
3260 fname=b'graftstate',
3259 fname=b'graftstate',
3261 clearable=True,
3260 clearable=True,
3262 stopflag=True,
3261 stopflag=True,
3263 continueflag=True,
3262 continueflag=True,
3264 abortfunc=cmdutil.hgabortgraft,
3263 abortfunc=cmdutil.hgabortgraft,
3265 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3264 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3266 )
3265 )
3267
3266
3268
3267
3269 @command(
3268 @command(
3270 b'grep',
3269 b'grep',
3271 [
3270 [
3272 (b'0', b'print0', None, _(b'end fields with NUL')),
3271 (b'0', b'print0', None, _(b'end fields with NUL')),
3273 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3272 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3274 (
3273 (
3275 b'',
3274 b'',
3276 b'diff',
3275 b'diff',
3277 None,
3276 None,
3278 _(
3277 _(
3279 b'search revision differences for when the pattern was added '
3278 b'search revision differences for when the pattern was added '
3280 b'or removed'
3279 b'or removed'
3281 ),
3280 ),
3282 ),
3281 ),
3283 (b'a', b'text', None, _(b'treat all files as text')),
3282 (b'a', b'text', None, _(b'treat all files as text')),
3284 (
3283 (
3285 b'f',
3284 b'f',
3286 b'follow',
3285 b'follow',
3287 None,
3286 None,
3288 _(
3287 _(
3289 b'follow changeset history,'
3288 b'follow changeset history,'
3290 b' or file history across copies and renames'
3289 b' or file history across copies and renames'
3291 ),
3290 ),
3292 ),
3291 ),
3293 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3292 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3294 (
3293 (
3295 b'l',
3294 b'l',
3296 b'files-with-matches',
3295 b'files-with-matches',
3297 None,
3296 None,
3298 _(b'print only filenames and revisions that match'),
3297 _(b'print only filenames and revisions that match'),
3299 ),
3298 ),
3300 (b'n', b'line-number', None, _(b'print matching line numbers')),
3299 (b'n', b'line-number', None, _(b'print matching line numbers')),
3301 (
3300 (
3302 b'r',
3301 b'r',
3303 b'rev',
3302 b'rev',
3304 [],
3303 [],
3305 _(b'search files changed within revision range'),
3304 _(b'search files changed within revision range'),
3306 _(b'REV'),
3305 _(b'REV'),
3307 ),
3306 ),
3308 (
3307 (
3309 b'',
3308 b'',
3310 b'all-files',
3309 b'all-files',
3311 None,
3310 None,
3312 _(
3311 _(
3313 b'include all files in the changeset while grepping (DEPRECATED)'
3312 b'include all files in the changeset while grepping (DEPRECATED)'
3314 ),
3313 ),
3315 ),
3314 ),
3316 (b'u', b'user', None, _(b'list the author (long with -v)')),
3315 (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)')),
3316 (b'd', b'date', None, _(b'list the date (short with -q)')),
3318 ]
3317 ]
3319 + formatteropts
3318 + formatteropts
3320 + walkopts,
3319 + walkopts,
3321 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3320 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3322 helpcategory=command.CATEGORY_FILE_CONTENTS,
3321 helpcategory=command.CATEGORY_FILE_CONTENTS,
3323 inferrepo=True,
3322 inferrepo=True,
3324 intents={INTENT_READONLY},
3323 intents={INTENT_READONLY},
3325 )
3324 )
3326 def grep(ui, repo, pattern, *pats, **opts):
3325 def grep(ui, repo, pattern, *pats, **opts):
3327 """search for a pattern in specified files
3326 """search for a pattern in specified files
3328
3327
3329 Search the working directory or revision history for a regular
3328 Search the working directory or revision history for a regular
3330 expression in the specified files for the entire repository.
3329 expression in the specified files for the entire repository.
3331
3330
3332 By default, grep searches the repository files in the working
3331 By default, grep searches the repository files in the working
3333 directory and prints the files where it finds a match. To specify
3332 directory and prints the files where it finds a match. To specify
3334 historical revisions instead of the working directory, use the
3333 historical revisions instead of the working directory, use the
3335 --rev flag.
3334 --rev flag.
3336
3335
3337 To search instead historical revision differences that contains a
3336 To search instead historical revision differences that contains a
3338 change in match status ("-" for a match that becomes a non-match,
3337 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.
3338 or "+" for a non-match that becomes a match), use the --diff flag.
3340
3339
3341 PATTERN can be any Python (roughly Perl-compatible) regular
3340 PATTERN can be any Python (roughly Perl-compatible) regular
3342 expression.
3341 expression.
3343
3342
3344 If no FILEs are specified and the --rev flag isn't supplied, all
3343 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
3344 files in the working directory are searched. When using the --rev
3346 flag and specifying FILEs, use the --follow argument to also
3345 flag and specifying FILEs, use the --follow argument to also
3347 follow the specified FILEs across renames and copies.
3346 follow the specified FILEs across renames and copies.
3348
3347
3349 .. container:: verbose
3348 .. container:: verbose
3350
3349
3351 Template:
3350 Template:
3352
3351
3353 The following keywords are supported in addition to the common template
3352 The following keywords are supported in addition to the common template
3354 keywords and functions. See also :hg:`help templates`.
3353 keywords and functions. See also :hg:`help templates`.
3355
3354
3356 :change: String. Character denoting insertion ``+`` or removal ``-``.
3355 :change: String. Character denoting insertion ``+`` or removal ``-``.
3357 Available if ``--diff`` is specified.
3356 Available if ``--diff`` is specified.
3358 :lineno: Integer. Line number of the match.
3357 :lineno: Integer. Line number of the match.
3359 :path: String. Repository-absolute path of the file.
3358 :path: String. Repository-absolute path of the file.
3360 :texts: List of text chunks.
3359 :texts: List of text chunks.
3361
3360
3362 And each entry of ``{texts}`` provides the following sub-keywords.
3361 And each entry of ``{texts}`` provides the following sub-keywords.
3363
3362
3364 :matched: Boolean. True if the chunk matches the specified pattern.
3363 :matched: Boolean. True if the chunk matches the specified pattern.
3365 :text: String. Chunk content.
3364 :text: String. Chunk content.
3366
3365
3367 See :hg:`help templates.operators` for the list expansion syntax.
3366 See :hg:`help templates.operators` for the list expansion syntax.
3368
3367
3369 Returns 0 if a match is found, 1 otherwise.
3368 Returns 0 if a match is found, 1 otherwise.
3370
3369
3371 """
3370 """
3372 opts = pycompat.byteskwargs(opts)
3371 opts = pycompat.byteskwargs(opts)
3373 diff = opts.get(b'all') or opts.get(b'diff')
3372 diff = opts.get(b'all') or opts.get(b'diff')
3373 follow = opts.get(b'follow')
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(
3402 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3403 )
3402
3404
3403 getfile = searcher._getfile
3405 getfile = searcher._getfile
3404 matches = searcher._matches
3406 matches = searcher._matches
3405 copies = searcher._copies
3407 copies = searcher._copies
3406
3408
3407 uipathfn = scmutil.getuipathfn(repo)
3409 uipathfn = scmutil.getuipathfn(repo)
3408
3410
3409 def display(fm, fn, ctx, pstates, states):
3411 def display(fm, fn, ctx, pstates, states):
3410 rev = scmutil.intrev(ctx)
3412 rev = scmutil.intrev(ctx)
3411 if fm.isplain():
3413 if fm.isplain():
3412 formatuser = ui.shortuser
3414 formatuser = ui.shortuser
3413 else:
3415 else:
3414 formatuser = pycompat.bytestr
3416 formatuser = pycompat.bytestr
3415 if ui.quiet:
3417 if ui.quiet:
3416 datefmt = b'%Y-%m-%d'
3418 datefmt = b'%Y-%m-%d'
3417 else:
3419 else:
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3420 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3419 found = False
3421 found = False
3420
3422
3421 @util.cachefunc
3423 @util.cachefunc
3422 def binary():
3424 def binary():
3423 flog = getfile(fn)
3425 flog = getfile(fn)
3424 try:
3426 try:
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3427 return stringutil.binary(flog.read(ctx.filenode(fn)))
3426 except error.WdirUnsupported:
3428 except error.WdirUnsupported:
3427 return ctx[fn].isbinary()
3429 return ctx[fn].isbinary()
3428
3430
3429 fieldnamemap = {b'linenumber': b'lineno'}
3431 fieldnamemap = {b'linenumber': b'lineno'}
3430 if diff:
3432 if diff:
3431 iter = grepmod.difflinestates(pstates, states)
3433 iter = grepmod.difflinestates(pstates, states)
3432 else:
3434 else:
3433 iter = [(b'', l) for l in states]
3435 iter = [(b'', l) for l in states]
3434 for change, l in iter:
3436 for change, l in iter:
3435 fm.startitem()
3437 fm.startitem()
3436 fm.context(ctx=ctx)
3438 fm.context(ctx=ctx)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3439 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3440 fm.plain(uipathfn(fn), label=b'grep.filename')
3439
3441
3440 cols = [
3442 cols = [
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3443 (b'rev', b'%d', rev, not plaingrep, b''),
3442 (
3444 (
3443 b'linenumber',
3445 b'linenumber',
3444 b'%d',
3446 b'%d',
3445 l.linenum,
3447 l.linenum,
3446 opts.get(b'line_number'),
3448 opts.get(b'line_number'),
3447 b'',
3449 b'',
3448 ),
3450 ),
3449 ]
3451 ]
3450 if diff:
3452 if diff:
3451 cols.append(
3453 cols.append(
3452 (
3454 (
3453 b'change',
3455 b'change',
3454 b'%s',
3456 b'%s',
3455 change,
3457 change,
3456 True,
3458 True,
3457 b'grep.inserted '
3459 b'grep.inserted '
3458 if change == b'+'
3460 if change == b'+'
3459 else b'grep.deleted ',
3461 else b'grep.deleted ',
3460 )
3462 )
3461 )
3463 )
3462 cols.extend(
3464 cols.extend(
3463 [
3465 [
3464 (
3466 (
3465 b'user',
3467 b'user',
3466 b'%s',
3468 b'%s',
3467 formatuser(ctx.user()),
3469 formatuser(ctx.user()),
3468 opts.get(b'user'),
3470 opts.get(b'user'),
3469 b'',
3471 b'',
3470 ),
3472 ),
3471 (
3473 (
3472 b'date',
3474 b'date',
3473 b'%s',
3475 b'%s',
3474 fm.formatdate(ctx.date(), datefmt),
3476 fm.formatdate(ctx.date(), datefmt),
3475 opts.get(b'date'),
3477 opts.get(b'date'),
3476 b'',
3478 b'',
3477 ),
3479 ),
3478 ]
3480 ]
3479 )
3481 )
3480 for name, fmt, data, cond, extra_label in cols:
3482 for name, fmt, data, cond, extra_label in cols:
3481 if cond:
3483 if cond:
3482 fm.plain(sep, label=b'grep.sep')
3484 fm.plain(sep, label=b'grep.sep')
3483 field = fieldnamemap.get(name, name)
3485 field = fieldnamemap.get(name, name)
3484 label = extra_label + (b'grep.%s' % name)
3486 label = extra_label + (b'grep.%s' % name)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3487 fm.condwrite(cond, field, fmt, data, label=label)
3486 if not opts.get(b'files_with_matches'):
3488 if not opts.get(b'files_with_matches'):
3487 fm.plain(sep, label=b'grep.sep')
3489 fm.plain(sep, label=b'grep.sep')
3488 if not opts.get(b'text') and binary():
3490 if not opts.get(b'text') and binary():
3489 fm.plain(_(b" Binary file matches"))
3491 fm.plain(_(b" Binary file matches"))
3490 else:
3492 else:
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3493 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3492 fm.plain(eol)
3494 fm.plain(eol)
3493 found = True
3495 found = True
3494 if opts.get(b'files_with_matches'):
3496 if opts.get(b'files_with_matches'):
3495 break
3497 break
3496 return found
3498 return found
3497
3499
3498 def displaymatches(fm, l):
3500 def displaymatches(fm, l):
3499 p = 0
3501 p = 0
3500 for s, e in l.findpos(regexp):
3502 for s, e in l.findpos(regexp):
3501 if p < s:
3503 if p < s:
3502 fm.startitem()
3504 fm.startitem()
3503 fm.write(b'text', b'%s', l.line[p:s])
3505 fm.write(b'text', b'%s', l.line[p:s])
3504 fm.data(matched=False)
3506 fm.data(matched=False)
3505 fm.startitem()
3507 fm.startitem()
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3508 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3507 fm.data(matched=True)
3509 fm.data(matched=True)
3508 p = e
3510 p = e
3509 if p < len(l.line):
3511 if p < len(l.line):
3510 fm.startitem()
3512 fm.startitem()
3511 fm.write(b'text', b'%s', l.line[p:])
3513 fm.write(b'text', b'%s', l.line[p:])
3512 fm.data(matched=False)
3514 fm.data(matched=False)
3513 fm.end()
3515 fm.end()
3514
3516
3515 skip = searcher._skip
3517 skip = searcher._skip
3516 revfiles = searcher._revfiles
3518 revfiles = searcher._revfiles
3517 found = False
3519 found = False
3518 follow = opts.get(b'follow')
3519
3520 getrenamed = searcher._getrenamed
3521
3522 def prep(ctx, fmatch):
3523 rev = ctx.rev()
3524 pctx = ctx.p1()
3525 matches.setdefault(rev, {})
3526 if diff:
3527 parent = pctx.rev()
3528 matches.setdefault(parent, {})
3529 files = revfiles.setdefault(rev, [])
3530 if rev is None:
3531 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3532 # pathauditor checks without this in mozilla-central
3533 contextmanager = repo.wvfs.audit.cached
3534 else:
3535 contextmanager = util.nullcontextmanager
3536 with contextmanager():
3537 # TODO: maybe better to warn missing files?
3538 if all_files:
3539 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
3540 filenames = ctx.matches(fmatch)
3541 else:
3542 filenames = (f for f in ctx.files() if fmatch(f))
3543 for fn in filenames:
3544 # fn might not exist in the revision (could be a file removed by
3545 # the revision). We could check `fn not in ctx` even when rev is
3546 # None, but it's less racy to protect againt that in readfile.
3547 if rev is not None and fn not in ctx:
3548 continue
3549
3550 copy = None
3551 if follow:
3552 copy = getrenamed(fn, rev)
3553 if copy:
3554 copies.setdefault(rev, {})[fn] = copy
3555 if fn in skip:
3556 skip.add(copy)
3557 if fn in skip:
3558 continue
3559 files.append(fn)
3560
3561 if fn not in matches[rev]:
3562 searcher._grepbody(fn, rev, searcher._readfile(ctx, fn))
3563
3564 if diff:
3565 pfn = copy or fn
3566 if pfn not in matches[parent] and pfn in pctx:
3567 searcher._grepbody(
3568 pfn, parent, searcher._readfile(pctx, pfn)
3569 )
3570
3520
3571 wopts = logcmdutil.walkopts(
3521 wopts = logcmdutil.walkopts(
3572 pats=pats,
3522 pats=pats,
3573 opts=opts,
3523 opts=opts,
3574 revspec=opts[b'rev'],
3524 revspec=opts[b'rev'],
3575 include_pats=opts[b'include'],
3525 include_pats=opts[b'include'],
3576 exclude_pats=opts[b'exclude'],
3526 exclude_pats=opts[b'exclude'],
3577 follow=follow,
3527 follow=follow,
3578 force_changelog_traversal=all_files,
3528 force_changelog_traversal=all_files,
3579 filter_revisions_by_pats=not all_files,
3529 filter_revisions_by_pats=not all_files,
3580 )
3530 )
3581 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3531 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3582
3532
3583 ui.pager(b'grep')
3533 ui.pager(b'grep')
3584 fm = ui.formatter(b'grep', opts)
3534 fm = ui.formatter(b'grep', opts)
3585 for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
3535 for ctx in cmdutil.walkchangerevs(
3536 repo, revs, makefilematcher, searcher._prep
3537 ):
3586 rev = ctx.rev()
3538 rev = ctx.rev()
3587 parent = ctx.p1().rev()
3539 parent = ctx.p1().rev()
3588 for fn in sorted(revfiles.get(rev, [])):
3540 for fn in sorted(revfiles.get(rev, [])):
3589 states = matches[rev][fn]
3541 states = matches[rev][fn]
3590 copy = copies.get(rev, {}).get(fn)
3542 copy = copies.get(rev, {}).get(fn)
3591 if fn in skip:
3543 if fn in skip:
3592 if copy:
3544 if copy:
3593 skip.add(copy)
3545 skip.add(copy)
3594 continue
3546 continue
3595 pstates = matches.get(parent, {}).get(copy or fn, [])
3547 pstates = matches.get(parent, {}).get(copy or fn, [])
3596 if pstates or states:
3548 if pstates or states:
3597 r = display(fm, fn, ctx, pstates, states)
3549 r = display(fm, fn, ctx, pstates, states)
3598 found = found or r
3550 found = found or r
3599 if r and not diff and not all_files:
3551 if r and not diff and not all_files:
3600 skip.add(fn)
3552 skip.add(fn)
3601 if copy:
3553 if copy:
3602 skip.add(copy)
3554 skip.add(copy)
3603 del revfiles[rev]
3555 del revfiles[rev]
3604 # We will keep the matches dict for the duration of the window
3556 # We will keep the matches dict for the duration of the window
3605 # clear the matches dict once the window is over
3557 # clear the matches dict once the window is over
3606 if not revfiles:
3558 if not revfiles:
3607 matches.clear()
3559 matches.clear()
3608 fm.end()
3560 fm.end()
3609
3561
3610 return not found
3562 return not found
3611
3563
3612
3564
3613 @command(
3565 @command(
3614 b'heads',
3566 b'heads',
3615 [
3567 [
3616 (
3568 (
3617 b'r',
3569 b'r',
3618 b'rev',
3570 b'rev',
3619 b'',
3571 b'',
3620 _(b'show only heads which are descendants of STARTREV'),
3572 _(b'show only heads which are descendants of STARTREV'),
3621 _(b'STARTREV'),
3573 _(b'STARTREV'),
3622 ),
3574 ),
3623 (b't', b'topo', False, _(b'show topological heads only')),
3575 (b't', b'topo', False, _(b'show topological heads only')),
3624 (
3576 (
3625 b'a',
3577 b'a',
3626 b'active',
3578 b'active',
3627 False,
3579 False,
3628 _(b'show active branchheads only (DEPRECATED)'),
3580 _(b'show active branchheads only (DEPRECATED)'),
3629 ),
3581 ),
3630 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3582 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3631 ]
3583 ]
3632 + templateopts,
3584 + templateopts,
3633 _(b'[-ct] [-r STARTREV] [REV]...'),
3585 _(b'[-ct] [-r STARTREV] [REV]...'),
3634 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3586 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3635 intents={INTENT_READONLY},
3587 intents={INTENT_READONLY},
3636 )
3588 )
3637 def heads(ui, repo, *branchrevs, **opts):
3589 def heads(ui, repo, *branchrevs, **opts):
3638 """show branch heads
3590 """show branch heads
3639
3591
3640 With no arguments, show all open branch heads in the repository.
3592 With no arguments, show all open branch heads in the repository.
3641 Branch heads are changesets that have no descendants on the
3593 Branch heads are changesets that have no descendants on the
3642 same branch. They are where development generally takes place and
3594 same branch. They are where development generally takes place and
3643 are the usual targets for update and merge operations.
3595 are the usual targets for update and merge operations.
3644
3596
3645 If one or more REVs are given, only open branch heads on the
3597 If one or more REVs are given, only open branch heads on the
3646 branches associated with the specified changesets are shown. This
3598 branches associated with the specified changesets are shown. This
3647 means that you can use :hg:`heads .` to see the heads on the
3599 means that you can use :hg:`heads .` to see the heads on the
3648 currently checked-out branch.
3600 currently checked-out branch.
3649
3601
3650 If -c/--closed is specified, also show branch heads marked closed
3602 If -c/--closed is specified, also show branch heads marked closed
3651 (see :hg:`commit --close-branch`).
3603 (see :hg:`commit --close-branch`).
3652
3604
3653 If STARTREV is specified, only those heads that are descendants of
3605 If STARTREV is specified, only those heads that are descendants of
3654 STARTREV will be displayed.
3606 STARTREV will be displayed.
3655
3607
3656 If -t/--topo is specified, named branch mechanics will be ignored and only
3608 If -t/--topo is specified, named branch mechanics will be ignored and only
3657 topological heads (changesets with no children) will be shown.
3609 topological heads (changesets with no children) will be shown.
3658
3610
3659 Returns 0 if matching heads are found, 1 if not.
3611 Returns 0 if matching heads are found, 1 if not.
3660 """
3612 """
3661
3613
3662 opts = pycompat.byteskwargs(opts)
3614 opts = pycompat.byteskwargs(opts)
3663 start = None
3615 start = None
3664 rev = opts.get(b'rev')
3616 rev = opts.get(b'rev')
3665 if rev:
3617 if rev:
3666 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3618 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3667 start = scmutil.revsingle(repo, rev, None).node()
3619 start = scmutil.revsingle(repo, rev, None).node()
3668
3620
3669 if opts.get(b'topo'):
3621 if opts.get(b'topo'):
3670 heads = [repo[h] for h in repo.heads(start)]
3622 heads = [repo[h] for h in repo.heads(start)]
3671 else:
3623 else:
3672 heads = []
3624 heads = []
3673 for branch in repo.branchmap():
3625 for branch in repo.branchmap():
3674 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3626 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3675 heads = [repo[h] for h in heads]
3627 heads = [repo[h] for h in heads]
3676
3628
3677 if branchrevs:
3629 if branchrevs:
3678 branches = {
3630 branches = {
3679 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3631 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3680 }
3632 }
3681 heads = [h for h in heads if h.branch() in branches]
3633 heads = [h for h in heads if h.branch() in branches]
3682
3634
3683 if opts.get(b'active') and branchrevs:
3635 if opts.get(b'active') and branchrevs:
3684 dagheads = repo.heads(start)
3636 dagheads = repo.heads(start)
3685 heads = [h for h in heads if h.node() in dagheads]
3637 heads = [h for h in heads if h.node() in dagheads]
3686
3638
3687 if branchrevs:
3639 if branchrevs:
3688 haveheads = {h.branch() for h in heads}
3640 haveheads = {h.branch() for h in heads}
3689 if branches - haveheads:
3641 if branches - haveheads:
3690 headless = b', '.join(b for b in branches - haveheads)
3642 headless = b', '.join(b for b in branches - haveheads)
3691 msg = _(b'no open branch heads found on branches %s')
3643 msg = _(b'no open branch heads found on branches %s')
3692 if opts.get(b'rev'):
3644 if opts.get(b'rev'):
3693 msg += _(b' (started at %s)') % opts[b'rev']
3645 msg += _(b' (started at %s)') % opts[b'rev']
3694 ui.warn((msg + b'\n') % headless)
3646 ui.warn((msg + b'\n') % headless)
3695
3647
3696 if not heads:
3648 if not heads:
3697 return 1
3649 return 1
3698
3650
3699 ui.pager(b'heads')
3651 ui.pager(b'heads')
3700 heads = sorted(heads, key=lambda x: -(x.rev()))
3652 heads = sorted(heads, key=lambda x: -(x.rev()))
3701 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3653 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3702 for ctx in heads:
3654 for ctx in heads:
3703 displayer.show(ctx)
3655 displayer.show(ctx)
3704 displayer.close()
3656 displayer.close()
3705
3657
3706
3658
3707 @command(
3659 @command(
3708 b'help',
3660 b'help',
3709 [
3661 [
3710 (b'e', b'extension', None, _(b'show only help for extensions')),
3662 (b'e', b'extension', None, _(b'show only help for extensions')),
3711 (b'c', b'command', None, _(b'show only help for commands')),
3663 (b'c', b'command', None, _(b'show only help for commands')),
3712 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3664 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3713 (
3665 (
3714 b's',
3666 b's',
3715 b'system',
3667 b'system',
3716 [],
3668 [],
3717 _(b'show help for specific platform(s)'),
3669 _(b'show help for specific platform(s)'),
3718 _(b'PLATFORM'),
3670 _(b'PLATFORM'),
3719 ),
3671 ),
3720 ],
3672 ],
3721 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3673 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3722 helpcategory=command.CATEGORY_HELP,
3674 helpcategory=command.CATEGORY_HELP,
3723 norepo=True,
3675 norepo=True,
3724 intents={INTENT_READONLY},
3676 intents={INTENT_READONLY},
3725 )
3677 )
3726 def help_(ui, name=None, **opts):
3678 def help_(ui, name=None, **opts):
3727 """show help for a given topic or a help overview
3679 """show help for a given topic or a help overview
3728
3680
3729 With no arguments, print a list of commands with short help messages.
3681 With no arguments, print a list of commands with short help messages.
3730
3682
3731 Given a topic, extension, or command name, print help for that
3683 Given a topic, extension, or command name, print help for that
3732 topic.
3684 topic.
3733
3685
3734 Returns 0 if successful.
3686 Returns 0 if successful.
3735 """
3687 """
3736
3688
3737 keep = opts.get('system') or []
3689 keep = opts.get('system') or []
3738 if len(keep) == 0:
3690 if len(keep) == 0:
3739 if pycompat.sysplatform.startswith(b'win'):
3691 if pycompat.sysplatform.startswith(b'win'):
3740 keep.append(b'windows')
3692 keep.append(b'windows')
3741 elif pycompat.sysplatform == b'OpenVMS':
3693 elif pycompat.sysplatform == b'OpenVMS':
3742 keep.append(b'vms')
3694 keep.append(b'vms')
3743 elif pycompat.sysplatform == b'plan9':
3695 elif pycompat.sysplatform == b'plan9':
3744 keep.append(b'plan9')
3696 keep.append(b'plan9')
3745 else:
3697 else:
3746 keep.append(b'unix')
3698 keep.append(b'unix')
3747 keep.append(pycompat.sysplatform.lower())
3699 keep.append(pycompat.sysplatform.lower())
3748 if ui.verbose:
3700 if ui.verbose:
3749 keep.append(b'verbose')
3701 keep.append(b'verbose')
3750
3702
3751 commands = sys.modules[__name__]
3703 commands = sys.modules[__name__]
3752 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3704 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3753 ui.pager(b'help')
3705 ui.pager(b'help')
3754 ui.write(formatted)
3706 ui.write(formatted)
3755
3707
3756
3708
3757 @command(
3709 @command(
3758 b'identify|id',
3710 b'identify|id',
3759 [
3711 [
3760 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3712 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3761 (b'n', b'num', None, _(b'show local revision number')),
3713 (b'n', b'num', None, _(b'show local revision number')),
3762 (b'i', b'id', None, _(b'show global revision id')),
3714 (b'i', b'id', None, _(b'show global revision id')),
3763 (b'b', b'branch', None, _(b'show branch')),
3715 (b'b', b'branch', None, _(b'show branch')),
3764 (b't', b'tags', None, _(b'show tags')),
3716 (b't', b'tags', None, _(b'show tags')),
3765 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3717 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3766 ]
3718 ]
3767 + remoteopts
3719 + remoteopts
3768 + formatteropts,
3720 + formatteropts,
3769 _(b'[-nibtB] [-r REV] [SOURCE]'),
3721 _(b'[-nibtB] [-r REV] [SOURCE]'),
3770 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3722 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3771 optionalrepo=True,
3723 optionalrepo=True,
3772 intents={INTENT_READONLY},
3724 intents={INTENT_READONLY},
3773 )
3725 )
3774 def identify(
3726 def identify(
3775 ui,
3727 ui,
3776 repo,
3728 repo,
3777 source=None,
3729 source=None,
3778 rev=None,
3730 rev=None,
3779 num=None,
3731 num=None,
3780 id=None,
3732 id=None,
3781 branch=None,
3733 branch=None,
3782 tags=None,
3734 tags=None,
3783 bookmarks=None,
3735 bookmarks=None,
3784 **opts
3736 **opts
3785 ):
3737 ):
3786 """identify the working directory or specified revision
3738 """identify the working directory or specified revision
3787
3739
3788 Print a summary identifying the repository state at REV using one or
3740 Print a summary identifying the repository state at REV using one or
3789 two parent hash identifiers, followed by a "+" if the working
3741 two parent hash identifiers, followed by a "+" if the working
3790 directory has uncommitted changes, the branch name (if not default),
3742 directory has uncommitted changes, the branch name (if not default),
3791 a list of tags, and a list of bookmarks.
3743 a list of tags, and a list of bookmarks.
3792
3744
3793 When REV is not given, print a summary of the current state of the
3745 When REV is not given, print a summary of the current state of the
3794 repository including the working directory. Specify -r. to get information
3746 repository including the working directory. Specify -r. to get information
3795 of the working directory parent without scanning uncommitted changes.
3747 of the working directory parent without scanning uncommitted changes.
3796
3748
3797 Specifying a path to a repository root or Mercurial bundle will
3749 Specifying a path to a repository root or Mercurial bundle will
3798 cause lookup to operate on that repository/bundle.
3750 cause lookup to operate on that repository/bundle.
3799
3751
3800 .. container:: verbose
3752 .. container:: verbose
3801
3753
3802 Template:
3754 Template:
3803
3755
3804 The following keywords are supported in addition to the common template
3756 The following keywords are supported in addition to the common template
3805 keywords and functions. See also :hg:`help templates`.
3757 keywords and functions. See also :hg:`help templates`.
3806
3758
3807 :dirty: String. Character ``+`` denoting if the working directory has
3759 :dirty: String. Character ``+`` denoting if the working directory has
3808 uncommitted changes.
3760 uncommitted changes.
3809 :id: String. One or two nodes, optionally followed by ``+``.
3761 :id: String. One or two nodes, optionally followed by ``+``.
3810 :parents: List of strings. Parent nodes of the changeset.
3762 :parents: List of strings. Parent nodes of the changeset.
3811
3763
3812 Examples:
3764 Examples:
3813
3765
3814 - generate a build identifier for the working directory::
3766 - generate a build identifier for the working directory::
3815
3767
3816 hg id --id > build-id.dat
3768 hg id --id > build-id.dat
3817
3769
3818 - find the revision corresponding to a tag::
3770 - find the revision corresponding to a tag::
3819
3771
3820 hg id -n -r 1.3
3772 hg id -n -r 1.3
3821
3773
3822 - check the most recent revision of a remote repository::
3774 - check the most recent revision of a remote repository::
3823
3775
3824 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3776 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3825
3777
3826 See :hg:`log` for generating more information about specific revisions,
3778 See :hg:`log` for generating more information about specific revisions,
3827 including full hash identifiers.
3779 including full hash identifiers.
3828
3780
3829 Returns 0 if successful.
3781 Returns 0 if successful.
3830 """
3782 """
3831
3783
3832 opts = pycompat.byteskwargs(opts)
3784 opts = pycompat.byteskwargs(opts)
3833 if not repo and not source:
3785 if not repo and not source:
3834 raise error.Abort(
3786 raise error.Abort(
3835 _(b"there is no Mercurial repository here (.hg not found)")
3787 _(b"there is no Mercurial repository here (.hg not found)")
3836 )
3788 )
3837
3789
3838 default = not (num or id or branch or tags or bookmarks)
3790 default = not (num or id or branch or tags or bookmarks)
3839 output = []
3791 output = []
3840 revs = []
3792 revs = []
3841
3793
3842 if source:
3794 if source:
3843 source, branches = hg.parseurl(ui.expandpath(source))
3795 source, branches = hg.parseurl(ui.expandpath(source))
3844 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3796 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3845 repo = peer.local()
3797 repo = peer.local()
3846 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3798 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3847
3799
3848 fm = ui.formatter(b'identify', opts)
3800 fm = ui.formatter(b'identify', opts)
3849 fm.startitem()
3801 fm.startitem()
3850
3802
3851 if not repo:
3803 if not repo:
3852 if num or branch or tags:
3804 if num or branch or tags:
3853 raise error.Abort(
3805 raise error.Abort(
3854 _(b"can't query remote revision number, branch, or tags")
3806 _(b"can't query remote revision number, branch, or tags")
3855 )
3807 )
3856 if not rev and revs:
3808 if not rev and revs:
3857 rev = revs[0]
3809 rev = revs[0]
3858 if not rev:
3810 if not rev:
3859 rev = b"tip"
3811 rev = b"tip"
3860
3812
3861 remoterev = peer.lookup(rev)
3813 remoterev = peer.lookup(rev)
3862 hexrev = fm.hexfunc(remoterev)
3814 hexrev = fm.hexfunc(remoterev)
3863 if default or id:
3815 if default or id:
3864 output = [hexrev]
3816 output = [hexrev]
3865 fm.data(id=hexrev)
3817 fm.data(id=hexrev)
3866
3818
3867 @util.cachefunc
3819 @util.cachefunc
3868 def getbms():
3820 def getbms():
3869 bms = []
3821 bms = []
3870
3822
3871 if b'bookmarks' in peer.listkeys(b'namespaces'):
3823 if b'bookmarks' in peer.listkeys(b'namespaces'):
3872 hexremoterev = hex(remoterev)
3824 hexremoterev = hex(remoterev)
3873 bms = [
3825 bms = [
3874 bm
3826 bm
3875 for bm, bmr in pycompat.iteritems(
3827 for bm, bmr in pycompat.iteritems(
3876 peer.listkeys(b'bookmarks')
3828 peer.listkeys(b'bookmarks')
3877 )
3829 )
3878 if bmr == hexremoterev
3830 if bmr == hexremoterev
3879 ]
3831 ]
3880
3832
3881 return sorted(bms)
3833 return sorted(bms)
3882
3834
3883 if fm.isplain():
3835 if fm.isplain():
3884 if bookmarks:
3836 if bookmarks:
3885 output.extend(getbms())
3837 output.extend(getbms())
3886 elif default and not ui.quiet:
3838 elif default and not ui.quiet:
3887 # multiple bookmarks for a single parent separated by '/'
3839 # multiple bookmarks for a single parent separated by '/'
3888 bm = b'/'.join(getbms())
3840 bm = b'/'.join(getbms())
3889 if bm:
3841 if bm:
3890 output.append(bm)
3842 output.append(bm)
3891 else:
3843 else:
3892 fm.data(node=hex(remoterev))
3844 fm.data(node=hex(remoterev))
3893 if bookmarks or b'bookmarks' in fm.datahint():
3845 if bookmarks or b'bookmarks' in fm.datahint():
3894 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3846 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3895 else:
3847 else:
3896 if rev:
3848 if rev:
3897 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3849 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3898 ctx = scmutil.revsingle(repo, rev, None)
3850 ctx = scmutil.revsingle(repo, rev, None)
3899
3851
3900 if ctx.rev() is None:
3852 if ctx.rev() is None:
3901 ctx = repo[None]
3853 ctx = repo[None]
3902 parents = ctx.parents()
3854 parents = ctx.parents()
3903 taglist = []
3855 taglist = []
3904 for p in parents:
3856 for p in parents:
3905 taglist.extend(p.tags())
3857 taglist.extend(p.tags())
3906
3858
3907 dirty = b""
3859 dirty = b""
3908 if ctx.dirty(missing=True, merge=False, branch=False):
3860 if ctx.dirty(missing=True, merge=False, branch=False):
3909 dirty = b'+'
3861 dirty = b'+'
3910 fm.data(dirty=dirty)
3862 fm.data(dirty=dirty)
3911
3863
3912 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3864 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3913 if default or id:
3865 if default or id:
3914 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3866 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3915 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3867 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3916
3868
3917 if num:
3869 if num:
3918 numoutput = [b"%d" % p.rev() for p in parents]
3870 numoutput = [b"%d" % p.rev() for p in parents]
3919 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3871 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3920
3872
3921 fm.data(
3873 fm.data(
3922 parents=fm.formatlist(
3874 parents=fm.formatlist(
3923 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3875 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3924 )
3876 )
3925 )
3877 )
3926 else:
3878 else:
3927 hexoutput = fm.hexfunc(ctx.node())
3879 hexoutput = fm.hexfunc(ctx.node())
3928 if default or id:
3880 if default or id:
3929 output = [hexoutput]
3881 output = [hexoutput]
3930 fm.data(id=hexoutput)
3882 fm.data(id=hexoutput)
3931
3883
3932 if num:
3884 if num:
3933 output.append(pycompat.bytestr(ctx.rev()))
3885 output.append(pycompat.bytestr(ctx.rev()))
3934 taglist = ctx.tags()
3886 taglist = ctx.tags()
3935
3887
3936 if default and not ui.quiet:
3888 if default and not ui.quiet:
3937 b = ctx.branch()
3889 b = ctx.branch()
3938 if b != b'default':
3890 if b != b'default':
3939 output.append(b"(%s)" % b)
3891 output.append(b"(%s)" % b)
3940
3892
3941 # multiple tags for a single parent separated by '/'
3893 # multiple tags for a single parent separated by '/'
3942 t = b'/'.join(taglist)
3894 t = b'/'.join(taglist)
3943 if t:
3895 if t:
3944 output.append(t)
3896 output.append(t)
3945
3897
3946 # multiple bookmarks for a single parent separated by '/'
3898 # multiple bookmarks for a single parent separated by '/'
3947 bm = b'/'.join(ctx.bookmarks())
3899 bm = b'/'.join(ctx.bookmarks())
3948 if bm:
3900 if bm:
3949 output.append(bm)
3901 output.append(bm)
3950 else:
3902 else:
3951 if branch:
3903 if branch:
3952 output.append(ctx.branch())
3904 output.append(ctx.branch())
3953
3905
3954 if tags:
3906 if tags:
3955 output.extend(taglist)
3907 output.extend(taglist)
3956
3908
3957 if bookmarks:
3909 if bookmarks:
3958 output.extend(ctx.bookmarks())
3910 output.extend(ctx.bookmarks())
3959
3911
3960 fm.data(node=ctx.hex())
3912 fm.data(node=ctx.hex())
3961 fm.data(branch=ctx.branch())
3913 fm.data(branch=ctx.branch())
3962 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3914 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3963 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3915 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3964 fm.context(ctx=ctx)
3916 fm.context(ctx=ctx)
3965
3917
3966 fm.plain(b"%s\n" % b' '.join(output))
3918 fm.plain(b"%s\n" % b' '.join(output))
3967 fm.end()
3919 fm.end()
3968
3920
3969
3921
3970 @command(
3922 @command(
3971 b'import|patch',
3923 b'import|patch',
3972 [
3924 [
3973 (
3925 (
3974 b'p',
3926 b'p',
3975 b'strip',
3927 b'strip',
3976 1,
3928 1,
3977 _(
3929 _(
3978 b'directory strip option for patch. This has the same '
3930 b'directory strip option for patch. This has the same '
3979 b'meaning as the corresponding patch option'
3931 b'meaning as the corresponding patch option'
3980 ),
3932 ),
3981 _(b'NUM'),
3933 _(b'NUM'),
3982 ),
3934 ),
3983 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3935 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3984 (b'', b'secret', None, _(b'use the secret phase for committing')),
3936 (b'', b'secret', None, _(b'use the secret phase for committing')),
3985 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3937 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3986 (
3938 (
3987 b'f',
3939 b'f',
3988 b'force',
3940 b'force',
3989 None,
3941 None,
3990 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3942 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3991 ),
3943 ),
3992 (
3944 (
3993 b'',
3945 b'',
3994 b'no-commit',
3946 b'no-commit',
3995 None,
3947 None,
3996 _(b"don't commit, just update the working directory"),
3948 _(b"don't commit, just update the working directory"),
3997 ),
3949 ),
3998 (
3950 (
3999 b'',
3951 b'',
4000 b'bypass',
3952 b'bypass',
4001 None,
3953 None,
4002 _(b"apply patch without touching the working directory"),
3954 _(b"apply patch without touching the working directory"),
4003 ),
3955 ),
4004 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3956 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4005 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3957 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4006 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3958 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4007 (
3959 (
4008 b'',
3960 b'',
4009 b'import-branch',
3961 b'import-branch',
4010 None,
3962 None,
4011 _(b'use any branch information in patch (implied by --exact)'),
3963 _(b'use any branch information in patch (implied by --exact)'),
4012 ),
3964 ),
4013 ]
3965 ]
4014 + commitopts
3966 + commitopts
4015 + commitopts2
3967 + commitopts2
4016 + similarityopts,
3968 + similarityopts,
4017 _(b'[OPTION]... PATCH...'),
3969 _(b'[OPTION]... PATCH...'),
4018 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3970 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4019 )
3971 )
4020 def import_(ui, repo, patch1=None, *patches, **opts):
3972 def import_(ui, repo, patch1=None, *patches, **opts):
4021 """import an ordered set of patches
3973 """import an ordered set of patches
4022
3974
4023 Import a list of patches and commit them individually (unless
3975 Import a list of patches and commit them individually (unless
4024 --no-commit is specified).
3976 --no-commit is specified).
4025
3977
4026 To read a patch from standard input (stdin), use "-" as the patch
3978 To read a patch from standard input (stdin), use "-" as the patch
4027 name. If a URL is specified, the patch will be downloaded from
3979 name. If a URL is specified, the patch will be downloaded from
4028 there.
3980 there.
4029
3981
4030 Import first applies changes to the working directory (unless
3982 Import first applies changes to the working directory (unless
4031 --bypass is specified), import will abort if there are outstanding
3983 --bypass is specified), import will abort if there are outstanding
4032 changes.
3984 changes.
4033
3985
4034 Use --bypass to apply and commit patches directly to the
3986 Use --bypass to apply and commit patches directly to the
4035 repository, without affecting the working directory. Without
3987 repository, without affecting the working directory. Without
4036 --exact, patches will be applied on top of the working directory
3988 --exact, patches will be applied on top of the working directory
4037 parent revision.
3989 parent revision.
4038
3990
4039 You can import a patch straight from a mail message. Even patches
3991 You can import a patch straight from a mail message. Even patches
4040 as attachments work (to use the body part, it must have type
3992 as attachments work (to use the body part, it must have type
4041 text/plain or text/x-patch). From and Subject headers of email
3993 text/plain or text/x-patch). From and Subject headers of email
4042 message are used as default committer and commit message. All
3994 message are used as default committer and commit message. All
4043 text/plain body parts before first diff are added to the commit
3995 text/plain body parts before first diff are added to the commit
4044 message.
3996 message.
4045
3997
4046 If the imported patch was generated by :hg:`export`, user and
3998 If the imported patch was generated by :hg:`export`, user and
4047 description from patch override values from message headers and
3999 description from patch override values from message headers and
4048 body. Values given on command line with -m/--message and -u/--user
4000 body. Values given on command line with -m/--message and -u/--user
4049 override these.
4001 override these.
4050
4002
4051 If --exact is specified, import will set the working directory to
4003 If --exact is specified, import will set the working directory to
4052 the parent of each patch before applying it, and will abort if the
4004 the parent of each patch before applying it, and will abort if the
4053 resulting changeset has a different ID than the one recorded in
4005 resulting changeset has a different ID than the one recorded in
4054 the patch. This will guard against various ways that portable
4006 the patch. This will guard against various ways that portable
4055 patch formats and mail systems might fail to transfer Mercurial
4007 patch formats and mail systems might fail to transfer Mercurial
4056 data or metadata. See :hg:`bundle` for lossless transmission.
4008 data or metadata. See :hg:`bundle` for lossless transmission.
4057
4009
4058 Use --partial to ensure a changeset will be created from the patch
4010 Use --partial to ensure a changeset will be created from the patch
4059 even if some hunks fail to apply. Hunks that fail to apply will be
4011 even if some hunks fail to apply. Hunks that fail to apply will be
4060 written to a <target-file>.rej file. Conflicts can then be resolved
4012 written to a <target-file>.rej file. Conflicts can then be resolved
4061 by hand before :hg:`commit --amend` is run to update the created
4013 by hand before :hg:`commit --amend` is run to update the created
4062 changeset. This flag exists to let people import patches that
4014 changeset. This flag exists to let people import patches that
4063 partially apply without losing the associated metadata (author,
4015 partially apply without losing the associated metadata (author,
4064 date, description, ...).
4016 date, description, ...).
4065
4017
4066 .. note::
4018 .. note::
4067
4019
4068 When no hunks apply cleanly, :hg:`import --partial` will create
4020 When no hunks apply cleanly, :hg:`import --partial` will create
4069 an empty changeset, importing only the patch metadata.
4021 an empty changeset, importing only the patch metadata.
4070
4022
4071 With -s/--similarity, hg will attempt to discover renames and
4023 With -s/--similarity, hg will attempt to discover renames and
4072 copies in the patch in the same way as :hg:`addremove`.
4024 copies in the patch in the same way as :hg:`addremove`.
4073
4025
4074 It is possible to use external patch programs to perform the patch
4026 It is possible to use external patch programs to perform the patch
4075 by setting the ``ui.patch`` configuration option. For the default
4027 by setting the ``ui.patch`` configuration option. For the default
4076 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4028 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4077 See :hg:`help config` for more information about configuration
4029 See :hg:`help config` for more information about configuration
4078 files and how to use these options.
4030 files and how to use these options.
4079
4031
4080 See :hg:`help dates` for a list of formats valid for -d/--date.
4032 See :hg:`help dates` for a list of formats valid for -d/--date.
4081
4033
4082 .. container:: verbose
4034 .. container:: verbose
4083
4035
4084 Examples:
4036 Examples:
4085
4037
4086 - import a traditional patch from a website and detect renames::
4038 - import a traditional patch from a website and detect renames::
4087
4039
4088 hg import -s 80 http://example.com/bugfix.patch
4040 hg import -s 80 http://example.com/bugfix.patch
4089
4041
4090 - import a changeset from an hgweb server::
4042 - import a changeset from an hgweb server::
4091
4043
4092 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4044 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4093
4045
4094 - import all the patches in an Unix-style mbox::
4046 - import all the patches in an Unix-style mbox::
4095
4047
4096 hg import incoming-patches.mbox
4048 hg import incoming-patches.mbox
4097
4049
4098 - import patches from stdin::
4050 - import patches from stdin::
4099
4051
4100 hg import -
4052 hg import -
4101
4053
4102 - attempt to exactly restore an exported changeset (not always
4054 - attempt to exactly restore an exported changeset (not always
4103 possible)::
4055 possible)::
4104
4056
4105 hg import --exact proposed-fix.patch
4057 hg import --exact proposed-fix.patch
4106
4058
4107 - use an external tool to apply a patch which is too fuzzy for
4059 - use an external tool to apply a patch which is too fuzzy for
4108 the default internal tool.
4060 the default internal tool.
4109
4061
4110 hg import --config ui.patch="patch --merge" fuzzy.patch
4062 hg import --config ui.patch="patch --merge" fuzzy.patch
4111
4063
4112 - change the default fuzzing from 2 to a less strict 7
4064 - change the default fuzzing from 2 to a less strict 7
4113
4065
4114 hg import --config ui.fuzz=7 fuzz.patch
4066 hg import --config ui.fuzz=7 fuzz.patch
4115
4067
4116 Returns 0 on success, 1 on partial success (see --partial).
4068 Returns 0 on success, 1 on partial success (see --partial).
4117 """
4069 """
4118
4070
4119 opts = pycompat.byteskwargs(opts)
4071 opts = pycompat.byteskwargs(opts)
4120 if not patch1:
4072 if not patch1:
4121 raise error.Abort(_(b'need at least one patch to import'))
4073 raise error.Abort(_(b'need at least one patch to import'))
4122
4074
4123 patches = (patch1,) + patches
4075 patches = (patch1,) + patches
4124
4076
4125 date = opts.get(b'date')
4077 date = opts.get(b'date')
4126 if date:
4078 if date:
4127 opts[b'date'] = dateutil.parsedate(date)
4079 opts[b'date'] = dateutil.parsedate(date)
4128
4080
4129 exact = opts.get(b'exact')
4081 exact = opts.get(b'exact')
4130 update = not opts.get(b'bypass')
4082 update = not opts.get(b'bypass')
4131 if not update and opts.get(b'no_commit'):
4083 if not update and opts.get(b'no_commit'):
4132 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4084 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4133 if opts.get(b'secret') and opts.get(b'no_commit'):
4085 if opts.get(b'secret') and opts.get(b'no_commit'):
4134 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4086 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4135 try:
4087 try:
4136 sim = float(opts.get(b'similarity') or 0)
4088 sim = float(opts.get(b'similarity') or 0)
4137 except ValueError:
4089 except ValueError:
4138 raise error.Abort(_(b'similarity must be a number'))
4090 raise error.Abort(_(b'similarity must be a number'))
4139 if sim < 0 or sim > 100:
4091 if sim < 0 or sim > 100:
4140 raise error.Abort(_(b'similarity must be between 0 and 100'))
4092 raise error.Abort(_(b'similarity must be between 0 and 100'))
4141 if sim and not update:
4093 if sim and not update:
4142 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4094 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4143 if exact:
4095 if exact:
4144 if opts.get(b'edit'):
4096 if opts.get(b'edit'):
4145 raise error.Abort(_(b'cannot use --exact with --edit'))
4097 raise error.Abort(_(b'cannot use --exact with --edit'))
4146 if opts.get(b'prefix'):
4098 if opts.get(b'prefix'):
4147 raise error.Abort(_(b'cannot use --exact with --prefix'))
4099 raise error.Abort(_(b'cannot use --exact with --prefix'))
4148
4100
4149 base = opts[b"base"]
4101 base = opts[b"base"]
4150 msgs = []
4102 msgs = []
4151 ret = 0
4103 ret = 0
4152
4104
4153 with repo.wlock():
4105 with repo.wlock():
4154 if update:
4106 if update:
4155 cmdutil.checkunfinished(repo)
4107 cmdutil.checkunfinished(repo)
4156 if exact or not opts.get(b'force'):
4108 if exact or not opts.get(b'force'):
4157 cmdutil.bailifchanged(repo)
4109 cmdutil.bailifchanged(repo)
4158
4110
4159 if not opts.get(b'no_commit'):
4111 if not opts.get(b'no_commit'):
4160 lock = repo.lock
4112 lock = repo.lock
4161 tr = lambda: repo.transaction(b'import')
4113 tr = lambda: repo.transaction(b'import')
4162 dsguard = util.nullcontextmanager
4114 dsguard = util.nullcontextmanager
4163 else:
4115 else:
4164 lock = util.nullcontextmanager
4116 lock = util.nullcontextmanager
4165 tr = util.nullcontextmanager
4117 tr = util.nullcontextmanager
4166 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4118 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4167 with lock(), tr(), dsguard():
4119 with lock(), tr(), dsguard():
4168 parents = repo[None].parents()
4120 parents = repo[None].parents()
4169 for patchurl in patches:
4121 for patchurl in patches:
4170 if patchurl == b'-':
4122 if patchurl == b'-':
4171 ui.status(_(b'applying patch from stdin\n'))
4123 ui.status(_(b'applying patch from stdin\n'))
4172 patchfile = ui.fin
4124 patchfile = ui.fin
4173 patchurl = b'stdin' # for error message
4125 patchurl = b'stdin' # for error message
4174 else:
4126 else:
4175 patchurl = os.path.join(base, patchurl)
4127 patchurl = os.path.join(base, patchurl)
4176 ui.status(_(b'applying %s\n') % patchurl)
4128 ui.status(_(b'applying %s\n') % patchurl)
4177 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4129 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4178
4130
4179 haspatch = False
4131 haspatch = False
4180 for hunk in patch.split(patchfile):
4132 for hunk in patch.split(patchfile):
4181 with patch.extract(ui, hunk) as patchdata:
4133 with patch.extract(ui, hunk) as patchdata:
4182 msg, node, rej = cmdutil.tryimportone(
4134 msg, node, rej = cmdutil.tryimportone(
4183 ui, repo, patchdata, parents, opts, msgs, hg.clean
4135 ui, repo, patchdata, parents, opts, msgs, hg.clean
4184 )
4136 )
4185 if msg:
4137 if msg:
4186 haspatch = True
4138 haspatch = True
4187 ui.note(msg + b'\n')
4139 ui.note(msg + b'\n')
4188 if update or exact:
4140 if update or exact:
4189 parents = repo[None].parents()
4141 parents = repo[None].parents()
4190 else:
4142 else:
4191 parents = [repo[node]]
4143 parents = [repo[node]]
4192 if rej:
4144 if rej:
4193 ui.write_err(_(b"patch applied partially\n"))
4145 ui.write_err(_(b"patch applied partially\n"))
4194 ui.write_err(
4146 ui.write_err(
4195 _(
4147 _(
4196 b"(fix the .rej files and run "
4148 b"(fix the .rej files and run "
4197 b"`hg commit --amend`)\n"
4149 b"`hg commit --amend`)\n"
4198 )
4150 )
4199 )
4151 )
4200 ret = 1
4152 ret = 1
4201 break
4153 break
4202
4154
4203 if not haspatch:
4155 if not haspatch:
4204 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4156 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4205
4157
4206 if msgs:
4158 if msgs:
4207 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4159 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4208 return ret
4160 return ret
4209
4161
4210
4162
4211 @command(
4163 @command(
4212 b'incoming|in',
4164 b'incoming|in',
4213 [
4165 [
4214 (
4166 (
4215 b'f',
4167 b'f',
4216 b'force',
4168 b'force',
4217 None,
4169 None,
4218 _(b'run even if remote repository is unrelated'),
4170 _(b'run even if remote repository is unrelated'),
4219 ),
4171 ),
4220 (b'n', b'newest-first', None, _(b'show newest record first')),
4172 (b'n', b'newest-first', None, _(b'show newest record first')),
4221 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4173 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4222 (
4174 (
4223 b'r',
4175 b'r',
4224 b'rev',
4176 b'rev',
4225 [],
4177 [],
4226 _(b'a remote changeset intended to be added'),
4178 _(b'a remote changeset intended to be added'),
4227 _(b'REV'),
4179 _(b'REV'),
4228 ),
4180 ),
4229 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4181 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4230 (
4182 (
4231 b'b',
4183 b'b',
4232 b'branch',
4184 b'branch',
4233 [],
4185 [],
4234 _(b'a specific branch you would like to pull'),
4186 _(b'a specific branch you would like to pull'),
4235 _(b'BRANCH'),
4187 _(b'BRANCH'),
4236 ),
4188 ),
4237 ]
4189 ]
4238 + logopts
4190 + logopts
4239 + remoteopts
4191 + remoteopts
4240 + subrepoopts,
4192 + subrepoopts,
4241 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4193 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4242 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4194 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4243 )
4195 )
4244 def incoming(ui, repo, source=b"default", **opts):
4196 def incoming(ui, repo, source=b"default", **opts):
4245 """show new changesets found in source
4197 """show new changesets found in source
4246
4198
4247 Show new changesets found in the specified path/URL or the default
4199 Show new changesets found in the specified path/URL or the default
4248 pull location. These are the changesets that would have been pulled
4200 pull location. These are the changesets that would have been pulled
4249 by :hg:`pull` at the time you issued this command.
4201 by :hg:`pull` at the time you issued this command.
4250
4202
4251 See pull for valid source format details.
4203 See pull for valid source format details.
4252
4204
4253 .. container:: verbose
4205 .. container:: verbose
4254
4206
4255 With -B/--bookmarks, the result of bookmark comparison between
4207 With -B/--bookmarks, the result of bookmark comparison between
4256 local and remote repositories is displayed. With -v/--verbose,
4208 local and remote repositories is displayed. With -v/--verbose,
4257 status is also displayed for each bookmark like below::
4209 status is also displayed for each bookmark like below::
4258
4210
4259 BM1 01234567890a added
4211 BM1 01234567890a added
4260 BM2 1234567890ab advanced
4212 BM2 1234567890ab advanced
4261 BM3 234567890abc diverged
4213 BM3 234567890abc diverged
4262 BM4 34567890abcd changed
4214 BM4 34567890abcd changed
4263
4215
4264 The action taken locally when pulling depends on the
4216 The action taken locally when pulling depends on the
4265 status of each bookmark:
4217 status of each bookmark:
4266
4218
4267 :``added``: pull will create it
4219 :``added``: pull will create it
4268 :``advanced``: pull will update it
4220 :``advanced``: pull will update it
4269 :``diverged``: pull will create a divergent bookmark
4221 :``diverged``: pull will create a divergent bookmark
4270 :``changed``: result depends on remote changesets
4222 :``changed``: result depends on remote changesets
4271
4223
4272 From the point of view of pulling behavior, bookmark
4224 From the point of view of pulling behavior, bookmark
4273 existing only in the remote repository are treated as ``added``,
4225 existing only in the remote repository are treated as ``added``,
4274 even if it is in fact locally deleted.
4226 even if it is in fact locally deleted.
4275
4227
4276 .. container:: verbose
4228 .. container:: verbose
4277
4229
4278 For remote repository, using --bundle avoids downloading the
4230 For remote repository, using --bundle avoids downloading the
4279 changesets twice if the incoming is followed by a pull.
4231 changesets twice if the incoming is followed by a pull.
4280
4232
4281 Examples:
4233 Examples:
4282
4234
4283 - show incoming changes with patches and full description::
4235 - show incoming changes with patches and full description::
4284
4236
4285 hg incoming -vp
4237 hg incoming -vp
4286
4238
4287 - show incoming changes excluding merges, store a bundle::
4239 - show incoming changes excluding merges, store a bundle::
4288
4240
4289 hg in -vpM --bundle incoming.hg
4241 hg in -vpM --bundle incoming.hg
4290 hg pull incoming.hg
4242 hg pull incoming.hg
4291
4243
4292 - briefly list changes inside a bundle::
4244 - briefly list changes inside a bundle::
4293
4245
4294 hg in changes.hg -T "{desc|firstline}\\n"
4246 hg in changes.hg -T "{desc|firstline}\\n"
4295
4247
4296 Returns 0 if there are incoming changes, 1 otherwise.
4248 Returns 0 if there are incoming changes, 1 otherwise.
4297 """
4249 """
4298 opts = pycompat.byteskwargs(opts)
4250 opts = pycompat.byteskwargs(opts)
4299 if opts.get(b'graph'):
4251 if opts.get(b'graph'):
4300 logcmdutil.checkunsupportedgraphflags([], opts)
4252 logcmdutil.checkunsupportedgraphflags([], opts)
4301
4253
4302 def display(other, chlist, displayer):
4254 def display(other, chlist, displayer):
4303 revdag = logcmdutil.graphrevs(other, chlist, opts)
4255 revdag = logcmdutil.graphrevs(other, chlist, opts)
4304 logcmdutil.displaygraph(
4256 logcmdutil.displaygraph(
4305 ui, repo, revdag, displayer, graphmod.asciiedges
4257 ui, repo, revdag, displayer, graphmod.asciiedges
4306 )
4258 )
4307
4259
4308 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4260 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4309 return 0
4261 return 0
4310
4262
4311 if opts.get(b'bundle') and opts.get(b'subrepos'):
4263 if opts.get(b'bundle') and opts.get(b'subrepos'):
4312 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4264 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4313
4265
4314 if opts.get(b'bookmarks'):
4266 if opts.get(b'bookmarks'):
4315 source, branches = hg.parseurl(
4267 source, branches = hg.parseurl(
4316 ui.expandpath(source), opts.get(b'branch')
4268 ui.expandpath(source), opts.get(b'branch')
4317 )
4269 )
4318 other = hg.peer(repo, opts, source)
4270 other = hg.peer(repo, opts, source)
4319 if b'bookmarks' not in other.listkeys(b'namespaces'):
4271 if b'bookmarks' not in other.listkeys(b'namespaces'):
4320 ui.warn(_(b"remote doesn't support bookmarks\n"))
4272 ui.warn(_(b"remote doesn't support bookmarks\n"))
4321 return 0
4273 return 0
4322 ui.pager(b'incoming')
4274 ui.pager(b'incoming')
4323 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4275 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4324 return bookmarks.incoming(ui, repo, other)
4276 return bookmarks.incoming(ui, repo, other)
4325
4277
4326 repo._subtoppath = ui.expandpath(source)
4278 repo._subtoppath = ui.expandpath(source)
4327 try:
4279 try:
4328 return hg.incoming(ui, repo, source, opts)
4280 return hg.incoming(ui, repo, source, opts)
4329 finally:
4281 finally:
4330 del repo._subtoppath
4282 del repo._subtoppath
4331
4283
4332
4284
4333 @command(
4285 @command(
4334 b'init',
4286 b'init',
4335 remoteopts,
4287 remoteopts,
4336 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4288 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4337 helpcategory=command.CATEGORY_REPO_CREATION,
4289 helpcategory=command.CATEGORY_REPO_CREATION,
4338 helpbasic=True,
4290 helpbasic=True,
4339 norepo=True,
4291 norepo=True,
4340 )
4292 )
4341 def init(ui, dest=b".", **opts):
4293 def init(ui, dest=b".", **opts):
4342 """create a new repository in the given directory
4294 """create a new repository in the given directory
4343
4295
4344 Initialize a new repository in the given directory. If the given
4296 Initialize a new repository in the given directory. If the given
4345 directory does not exist, it will be created.
4297 directory does not exist, it will be created.
4346
4298
4347 If no directory is given, the current directory is used.
4299 If no directory is given, the current directory is used.
4348
4300
4349 It is possible to specify an ``ssh://`` URL as the destination.
4301 It is possible to specify an ``ssh://`` URL as the destination.
4350 See :hg:`help urls` for more information.
4302 See :hg:`help urls` for more information.
4351
4303
4352 Returns 0 on success.
4304 Returns 0 on success.
4353 """
4305 """
4354 opts = pycompat.byteskwargs(opts)
4306 opts = pycompat.byteskwargs(opts)
4355 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4307 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4356
4308
4357
4309
4358 @command(
4310 @command(
4359 b'locate',
4311 b'locate',
4360 [
4312 [
4361 (
4313 (
4362 b'r',
4314 b'r',
4363 b'rev',
4315 b'rev',
4364 b'',
4316 b'',
4365 _(b'search the repository as it is in REV'),
4317 _(b'search the repository as it is in REV'),
4366 _(b'REV'),
4318 _(b'REV'),
4367 ),
4319 ),
4368 (
4320 (
4369 b'0',
4321 b'0',
4370 b'print0',
4322 b'print0',
4371 None,
4323 None,
4372 _(b'end filenames with NUL, for use with xargs'),
4324 _(b'end filenames with NUL, for use with xargs'),
4373 ),
4325 ),
4374 (
4326 (
4375 b'f',
4327 b'f',
4376 b'fullpath',
4328 b'fullpath',
4377 None,
4329 None,
4378 _(b'print complete paths from the filesystem root'),
4330 _(b'print complete paths from the filesystem root'),
4379 ),
4331 ),
4380 ]
4332 ]
4381 + walkopts,
4333 + walkopts,
4382 _(b'[OPTION]... [PATTERN]...'),
4334 _(b'[OPTION]... [PATTERN]...'),
4383 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4335 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4384 )
4336 )
4385 def locate(ui, repo, *pats, **opts):
4337 def locate(ui, repo, *pats, **opts):
4386 """locate files matching specific patterns (DEPRECATED)
4338 """locate files matching specific patterns (DEPRECATED)
4387
4339
4388 Print files under Mercurial control in the working directory whose
4340 Print files under Mercurial control in the working directory whose
4389 names match the given patterns.
4341 names match the given patterns.
4390
4342
4391 By default, this command searches all directories in the working
4343 By default, this command searches all directories in the working
4392 directory. To search just the current directory and its
4344 directory. To search just the current directory and its
4393 subdirectories, use "--include .".
4345 subdirectories, use "--include .".
4394
4346
4395 If no patterns are given to match, this command prints the names
4347 If no patterns are given to match, this command prints the names
4396 of all files under Mercurial control in the working directory.
4348 of all files under Mercurial control in the working directory.
4397
4349
4398 If you want to feed the output of this command into the "xargs"
4350 If you want to feed the output of this command into the "xargs"
4399 command, use the -0 option to both this command and "xargs". This
4351 command, use the -0 option to both this command and "xargs". This
4400 will avoid the problem of "xargs" treating single filenames that
4352 will avoid the problem of "xargs" treating single filenames that
4401 contain whitespace as multiple filenames.
4353 contain whitespace as multiple filenames.
4402
4354
4403 See :hg:`help files` for a more versatile command.
4355 See :hg:`help files` for a more versatile command.
4404
4356
4405 Returns 0 if a match is found, 1 otherwise.
4357 Returns 0 if a match is found, 1 otherwise.
4406 """
4358 """
4407 opts = pycompat.byteskwargs(opts)
4359 opts = pycompat.byteskwargs(opts)
4408 if opts.get(b'print0'):
4360 if opts.get(b'print0'):
4409 end = b'\0'
4361 end = b'\0'
4410 else:
4362 else:
4411 end = b'\n'
4363 end = b'\n'
4412 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4364 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4413
4365
4414 ret = 1
4366 ret = 1
4415 m = scmutil.match(
4367 m = scmutil.match(
4416 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4368 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4417 )
4369 )
4418
4370
4419 ui.pager(b'locate')
4371 ui.pager(b'locate')
4420 if ctx.rev() is None:
4372 if ctx.rev() is None:
4421 # When run on the working copy, "locate" includes removed files, so
4373 # When run on the working copy, "locate" includes removed files, so
4422 # we get the list of files from the dirstate.
4374 # we get the list of files from the dirstate.
4423 filesgen = sorted(repo.dirstate.matches(m))
4375 filesgen = sorted(repo.dirstate.matches(m))
4424 else:
4376 else:
4425 filesgen = ctx.matches(m)
4377 filesgen = ctx.matches(m)
4426 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4378 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4427 for abs in filesgen:
4379 for abs in filesgen:
4428 if opts.get(b'fullpath'):
4380 if opts.get(b'fullpath'):
4429 ui.write(repo.wjoin(abs), end)
4381 ui.write(repo.wjoin(abs), end)
4430 else:
4382 else:
4431 ui.write(uipathfn(abs), end)
4383 ui.write(uipathfn(abs), end)
4432 ret = 0
4384 ret = 0
4433
4385
4434 return ret
4386 return ret
4435
4387
4436
4388
4437 @command(
4389 @command(
4438 b'log|history',
4390 b'log|history',
4439 [
4391 [
4440 (
4392 (
4441 b'f',
4393 b'f',
4442 b'follow',
4394 b'follow',
4443 None,
4395 None,
4444 _(
4396 _(
4445 b'follow changeset history, or file history across copies and renames'
4397 b'follow changeset history, or file history across copies and renames'
4446 ),
4398 ),
4447 ),
4399 ),
4448 (
4400 (
4449 b'',
4401 b'',
4450 b'follow-first',
4402 b'follow-first',
4451 None,
4403 None,
4452 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4404 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4453 ),
4405 ),
4454 (
4406 (
4455 b'd',
4407 b'd',
4456 b'date',
4408 b'date',
4457 b'',
4409 b'',
4458 _(b'show revisions matching date spec'),
4410 _(b'show revisions matching date spec'),
4459 _(b'DATE'),
4411 _(b'DATE'),
4460 ),
4412 ),
4461 (b'C', b'copies', None, _(b'show copied files')),
4413 (b'C', b'copies', None, _(b'show copied files')),
4462 (
4414 (
4463 b'k',
4415 b'k',
4464 b'keyword',
4416 b'keyword',
4465 [],
4417 [],
4466 _(b'do case-insensitive search for a given text'),
4418 _(b'do case-insensitive search for a given text'),
4467 _(b'TEXT'),
4419 _(b'TEXT'),
4468 ),
4420 ),
4469 (
4421 (
4470 b'r',
4422 b'r',
4471 b'rev',
4423 b'rev',
4472 [],
4424 [],
4473 _(b'show the specified revision or revset'),
4425 _(b'show the specified revision or revset'),
4474 _(b'REV'),
4426 _(b'REV'),
4475 ),
4427 ),
4476 (
4428 (
4477 b'L',
4429 b'L',
4478 b'line-range',
4430 b'line-range',
4479 [],
4431 [],
4480 _(b'follow line range of specified file (EXPERIMENTAL)'),
4432 _(b'follow line range of specified file (EXPERIMENTAL)'),
4481 _(b'FILE,RANGE'),
4433 _(b'FILE,RANGE'),
4482 ),
4434 ),
4483 (
4435 (
4484 b'',
4436 b'',
4485 b'removed',
4437 b'removed',
4486 None,
4438 None,
4487 _(b'include revisions where files were removed'),
4439 _(b'include revisions where files were removed'),
4488 ),
4440 ),
4489 (
4441 (
4490 b'm',
4442 b'm',
4491 b'only-merges',
4443 b'only-merges',
4492 None,
4444 None,
4493 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4445 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4494 ),
4446 ),
4495 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4447 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4496 (
4448 (
4497 b'',
4449 b'',
4498 b'only-branch',
4450 b'only-branch',
4499 [],
4451 [],
4500 _(
4452 _(
4501 b'show only changesets within the given named branch (DEPRECATED)'
4453 b'show only changesets within the given named branch (DEPRECATED)'
4502 ),
4454 ),
4503 _(b'BRANCH'),
4455 _(b'BRANCH'),
4504 ),
4456 ),
4505 (
4457 (
4506 b'b',
4458 b'b',
4507 b'branch',
4459 b'branch',
4508 [],
4460 [],
4509 _(b'show changesets within the given named branch'),
4461 _(b'show changesets within the given named branch'),
4510 _(b'BRANCH'),
4462 _(b'BRANCH'),
4511 ),
4463 ),
4512 (
4464 (
4513 b'P',
4465 b'P',
4514 b'prune',
4466 b'prune',
4515 [],
4467 [],
4516 _(b'do not display revision or any of its ancestors'),
4468 _(b'do not display revision or any of its ancestors'),
4517 _(b'REV'),
4469 _(b'REV'),
4518 ),
4470 ),
4519 ]
4471 ]
4520 + logopts
4472 + logopts
4521 + walkopts,
4473 + walkopts,
4522 _(b'[OPTION]... [FILE]'),
4474 _(b'[OPTION]... [FILE]'),
4523 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4475 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4524 helpbasic=True,
4476 helpbasic=True,
4525 inferrepo=True,
4477 inferrepo=True,
4526 intents={INTENT_READONLY},
4478 intents={INTENT_READONLY},
4527 )
4479 )
4528 def log(ui, repo, *pats, **opts):
4480 def log(ui, repo, *pats, **opts):
4529 """show revision history of entire repository or files
4481 """show revision history of entire repository or files
4530
4482
4531 Print the revision history of the specified files or the entire
4483 Print the revision history of the specified files or the entire
4532 project.
4484 project.
4533
4485
4534 If no revision range is specified, the default is ``tip:0`` unless
4486 If no revision range is specified, the default is ``tip:0`` unless
4535 --follow is set, in which case the working directory parent is
4487 --follow is set, in which case the working directory parent is
4536 used as the starting revision.
4488 used as the starting revision.
4537
4489
4538 File history is shown without following rename or copy history of
4490 File history is shown without following rename or copy history of
4539 files. Use -f/--follow with a filename to follow history across
4491 files. Use -f/--follow with a filename to follow history across
4540 renames and copies. --follow without a filename will only show
4492 renames and copies. --follow without a filename will only show
4541 ancestors of the starting revision.
4493 ancestors of the starting revision.
4542
4494
4543 By default this command prints revision number and changeset id,
4495 By default this command prints revision number and changeset id,
4544 tags, non-trivial parents, user, date and time, and a summary for
4496 tags, non-trivial parents, user, date and time, and a summary for
4545 each commit. When the -v/--verbose switch is used, the list of
4497 each commit. When the -v/--verbose switch is used, the list of
4546 changed files and full commit message are shown.
4498 changed files and full commit message are shown.
4547
4499
4548 With --graph the revisions are shown as an ASCII art DAG with the most
4500 With --graph the revisions are shown as an ASCII art DAG with the most
4549 recent changeset at the top.
4501 recent changeset at the top.
4550 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4502 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4551 involved in an unresolved merge conflict, '_' closes a branch,
4503 involved in an unresolved merge conflict, '_' closes a branch,
4552 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4504 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4553 changeset from the lines below is a parent of the 'o' merge on the same
4505 changeset from the lines below is a parent of the 'o' merge on the same
4554 line.
4506 line.
4555 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4507 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4556 of a '|' indicates one or more revisions in a path are omitted.
4508 of a '|' indicates one or more revisions in a path are omitted.
4557
4509
4558 .. container:: verbose
4510 .. container:: verbose
4559
4511
4560 Use -L/--line-range FILE,M:N options to follow the history of lines
4512 Use -L/--line-range FILE,M:N options to follow the history of lines
4561 from M to N in FILE. With -p/--patch only diff hunks affecting
4513 from M to N in FILE. With -p/--patch only diff hunks affecting
4562 specified line range will be shown. This option requires --follow;
4514 specified line range will be shown. This option requires --follow;
4563 it can be specified multiple times. Currently, this option is not
4515 it can be specified multiple times. Currently, this option is not
4564 compatible with --graph. This option is experimental.
4516 compatible with --graph. This option is experimental.
4565
4517
4566 .. note::
4518 .. note::
4567
4519
4568 :hg:`log --patch` may generate unexpected diff output for merge
4520 :hg:`log --patch` may generate unexpected diff output for merge
4569 changesets, as it will only compare the merge changeset against
4521 changesets, as it will only compare the merge changeset against
4570 its first parent. Also, only files different from BOTH parents
4522 its first parent. Also, only files different from BOTH parents
4571 will appear in files:.
4523 will appear in files:.
4572
4524
4573 .. note::
4525 .. note::
4574
4526
4575 For performance reasons, :hg:`log FILE` may omit duplicate changes
4527 For performance reasons, :hg:`log FILE` may omit duplicate changes
4576 made on branches and will not show removals or mode changes. To
4528 made on branches and will not show removals or mode changes. To
4577 see all such changes, use the --removed switch.
4529 see all such changes, use the --removed switch.
4578
4530
4579 .. container:: verbose
4531 .. container:: verbose
4580
4532
4581 .. note::
4533 .. note::
4582
4534
4583 The history resulting from -L/--line-range options depends on diff
4535 The history resulting from -L/--line-range options depends on diff
4584 options; for instance if white-spaces are ignored, respective changes
4536 options; for instance if white-spaces are ignored, respective changes
4585 with only white-spaces in specified line range will not be listed.
4537 with only white-spaces in specified line range will not be listed.
4586
4538
4587 .. container:: verbose
4539 .. container:: verbose
4588
4540
4589 Some examples:
4541 Some examples:
4590
4542
4591 - changesets with full descriptions and file lists::
4543 - changesets with full descriptions and file lists::
4592
4544
4593 hg log -v
4545 hg log -v
4594
4546
4595 - changesets ancestral to the working directory::
4547 - changesets ancestral to the working directory::
4596
4548
4597 hg log -f
4549 hg log -f
4598
4550
4599 - last 10 commits on the current branch::
4551 - last 10 commits on the current branch::
4600
4552
4601 hg log -l 10 -b .
4553 hg log -l 10 -b .
4602
4554
4603 - changesets showing all modifications of a file, including removals::
4555 - changesets showing all modifications of a file, including removals::
4604
4556
4605 hg log --removed file.c
4557 hg log --removed file.c
4606
4558
4607 - all changesets that touch a directory, with diffs, excluding merges::
4559 - all changesets that touch a directory, with diffs, excluding merges::
4608
4560
4609 hg log -Mp lib/
4561 hg log -Mp lib/
4610
4562
4611 - all revision numbers that match a keyword::
4563 - all revision numbers that match a keyword::
4612
4564
4613 hg log -k bug --template "{rev}\\n"
4565 hg log -k bug --template "{rev}\\n"
4614
4566
4615 - the full hash identifier of the working directory parent::
4567 - the full hash identifier of the working directory parent::
4616
4568
4617 hg log -r . --template "{node}\\n"
4569 hg log -r . --template "{node}\\n"
4618
4570
4619 - list available log templates::
4571 - list available log templates::
4620
4572
4621 hg log -T list
4573 hg log -T list
4622
4574
4623 - check if a given changeset is included in a tagged release::
4575 - check if a given changeset is included in a tagged release::
4624
4576
4625 hg log -r "a21ccf and ancestor(1.9)"
4577 hg log -r "a21ccf and ancestor(1.9)"
4626
4578
4627 - find all changesets by some user in a date range::
4579 - find all changesets by some user in a date range::
4628
4580
4629 hg log -k alice -d "may 2008 to jul 2008"
4581 hg log -k alice -d "may 2008 to jul 2008"
4630
4582
4631 - summary of all changesets after the last tag::
4583 - summary of all changesets after the last tag::
4632
4584
4633 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4585 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4634
4586
4635 - changesets touching lines 13 to 23 for file.c::
4587 - changesets touching lines 13 to 23 for file.c::
4636
4588
4637 hg log -L file.c,13:23
4589 hg log -L file.c,13:23
4638
4590
4639 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4591 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4640 main.c with patch::
4592 main.c with patch::
4641
4593
4642 hg log -L file.c,13:23 -L main.c,2:6 -p
4594 hg log -L file.c,13:23 -L main.c,2:6 -p
4643
4595
4644 See :hg:`help dates` for a list of formats valid for -d/--date.
4596 See :hg:`help dates` for a list of formats valid for -d/--date.
4645
4597
4646 See :hg:`help revisions` for more about specifying and ordering
4598 See :hg:`help revisions` for more about specifying and ordering
4647 revisions.
4599 revisions.
4648
4600
4649 See :hg:`help templates` for more about pre-packaged styles and
4601 See :hg:`help templates` for more about pre-packaged styles and
4650 specifying custom templates. The default template used by the log
4602 specifying custom templates. The default template used by the log
4651 command can be customized via the ``ui.logtemplate`` configuration
4603 command can be customized via the ``ui.logtemplate`` configuration
4652 setting.
4604 setting.
4653
4605
4654 Returns 0 on success.
4606 Returns 0 on success.
4655
4607
4656 """
4608 """
4657 opts = pycompat.byteskwargs(opts)
4609 opts = pycompat.byteskwargs(opts)
4658 linerange = opts.get(b'line_range')
4610 linerange = opts.get(b'line_range')
4659
4611
4660 if linerange and not opts.get(b'follow'):
4612 if linerange and not opts.get(b'follow'):
4661 raise error.Abort(_(b'--line-range requires --follow'))
4613 raise error.Abort(_(b'--line-range requires --follow'))
4662
4614
4663 if linerange and pats:
4615 if linerange and pats:
4664 # TODO: take pats as patterns with no line-range filter
4616 # TODO: take pats as patterns with no line-range filter
4665 raise error.Abort(
4617 raise error.Abort(
4666 _(b'FILE arguments are not compatible with --line-range option')
4618 _(b'FILE arguments are not compatible with --line-range option')
4667 )
4619 )
4668
4620
4669 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4621 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4670 revs, differ = logcmdutil.getrevs(
4622 revs, differ = logcmdutil.getrevs(
4671 repo, logcmdutil.parseopts(ui, pats, opts)
4623 repo, logcmdutil.parseopts(ui, pats, opts)
4672 )
4624 )
4673 if linerange:
4625 if linerange:
4674 # TODO: should follow file history from logcmdutil._initialrevs(),
4626 # TODO: should follow file history from logcmdutil._initialrevs(),
4675 # then filter the result by logcmdutil._makerevset() and --limit
4627 # then filter the result by logcmdutil._makerevset() and --limit
4676 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4628 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4677
4629
4678 getcopies = None
4630 getcopies = None
4679 if opts.get(b'copies'):
4631 if opts.get(b'copies'):
4680 endrev = None
4632 endrev = None
4681 if revs:
4633 if revs:
4682 endrev = revs.max() + 1
4634 endrev = revs.max() + 1
4683 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4635 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4684
4636
4685 ui.pager(b'log')
4637 ui.pager(b'log')
4686 displayer = logcmdutil.changesetdisplayer(
4638 displayer = logcmdutil.changesetdisplayer(
4687 ui, repo, opts, differ, buffered=True
4639 ui, repo, opts, differ, buffered=True
4688 )
4640 )
4689 if opts.get(b'graph'):
4641 if opts.get(b'graph'):
4690 displayfn = logcmdutil.displaygraphrevs
4642 displayfn = logcmdutil.displaygraphrevs
4691 else:
4643 else:
4692 displayfn = logcmdutil.displayrevs
4644 displayfn = logcmdutil.displayrevs
4693 displayfn(ui, repo, revs, displayer, getcopies)
4645 displayfn(ui, repo, revs, displayer, getcopies)
4694
4646
4695
4647
4696 @command(
4648 @command(
4697 b'manifest',
4649 b'manifest',
4698 [
4650 [
4699 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4651 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4700 (b'', b'all', False, _(b"list files from all revisions")),
4652 (b'', b'all', False, _(b"list files from all revisions")),
4701 ]
4653 ]
4702 + formatteropts,
4654 + formatteropts,
4703 _(b'[-r REV]'),
4655 _(b'[-r REV]'),
4704 helpcategory=command.CATEGORY_MAINTENANCE,
4656 helpcategory=command.CATEGORY_MAINTENANCE,
4705 intents={INTENT_READONLY},
4657 intents={INTENT_READONLY},
4706 )
4658 )
4707 def manifest(ui, repo, node=None, rev=None, **opts):
4659 def manifest(ui, repo, node=None, rev=None, **opts):
4708 """output the current or given revision of the project manifest
4660 """output the current or given revision of the project manifest
4709
4661
4710 Print a list of version controlled files for the given revision.
4662 Print a list of version controlled files for the given revision.
4711 If no revision is given, the first parent of the working directory
4663 If no revision is given, the first parent of the working directory
4712 is used, or the null revision if no revision is checked out.
4664 is used, or the null revision if no revision is checked out.
4713
4665
4714 With -v, print file permissions, symlink and executable bits.
4666 With -v, print file permissions, symlink and executable bits.
4715 With --debug, print file revision hashes.
4667 With --debug, print file revision hashes.
4716
4668
4717 If option --all is specified, the list of all files from all revisions
4669 If option --all is specified, the list of all files from all revisions
4718 is printed. This includes deleted and renamed files.
4670 is printed. This includes deleted and renamed files.
4719
4671
4720 Returns 0 on success.
4672 Returns 0 on success.
4721 """
4673 """
4722 opts = pycompat.byteskwargs(opts)
4674 opts = pycompat.byteskwargs(opts)
4723 fm = ui.formatter(b'manifest', opts)
4675 fm = ui.formatter(b'manifest', opts)
4724
4676
4725 if opts.get(b'all'):
4677 if opts.get(b'all'):
4726 if rev or node:
4678 if rev or node:
4727 raise error.Abort(_(b"can't specify a revision with --all"))
4679 raise error.Abort(_(b"can't specify a revision with --all"))
4728
4680
4729 res = set()
4681 res = set()
4730 for rev in repo:
4682 for rev in repo:
4731 ctx = repo[rev]
4683 ctx = repo[rev]
4732 res |= set(ctx.files())
4684 res |= set(ctx.files())
4733
4685
4734 ui.pager(b'manifest')
4686 ui.pager(b'manifest')
4735 for f in sorted(res):
4687 for f in sorted(res):
4736 fm.startitem()
4688 fm.startitem()
4737 fm.write(b"path", b'%s\n', f)
4689 fm.write(b"path", b'%s\n', f)
4738 fm.end()
4690 fm.end()
4739 return
4691 return
4740
4692
4741 if rev and node:
4693 if rev and node:
4742 raise error.Abort(_(b"please specify just one revision"))
4694 raise error.Abort(_(b"please specify just one revision"))
4743
4695
4744 if not node:
4696 if not node:
4745 node = rev
4697 node = rev
4746
4698
4747 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4699 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4748 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4700 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4749 if node:
4701 if node:
4750 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4702 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4751 ctx = scmutil.revsingle(repo, node)
4703 ctx = scmutil.revsingle(repo, node)
4752 mf = ctx.manifest()
4704 mf = ctx.manifest()
4753 ui.pager(b'manifest')
4705 ui.pager(b'manifest')
4754 for f in ctx:
4706 for f in ctx:
4755 fm.startitem()
4707 fm.startitem()
4756 fm.context(ctx=ctx)
4708 fm.context(ctx=ctx)
4757 fl = ctx[f].flags()
4709 fl = ctx[f].flags()
4758 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4710 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4759 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4711 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4760 fm.write(b'path', b'%s\n', f)
4712 fm.write(b'path', b'%s\n', f)
4761 fm.end()
4713 fm.end()
4762
4714
4763
4715
4764 @command(
4716 @command(
4765 b'merge',
4717 b'merge',
4766 [
4718 [
4767 (
4719 (
4768 b'f',
4720 b'f',
4769 b'force',
4721 b'force',
4770 None,
4722 None,
4771 _(b'force a merge including outstanding changes (DEPRECATED)'),
4723 _(b'force a merge including outstanding changes (DEPRECATED)'),
4772 ),
4724 ),
4773 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4725 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4774 (
4726 (
4775 b'P',
4727 b'P',
4776 b'preview',
4728 b'preview',
4777 None,
4729 None,
4778 _(b'review revisions to merge (no merge is performed)'),
4730 _(b'review revisions to merge (no merge is performed)'),
4779 ),
4731 ),
4780 (b'', b'abort', None, _(b'abort the ongoing merge')),
4732 (b'', b'abort', None, _(b'abort the ongoing merge')),
4781 ]
4733 ]
4782 + mergetoolopts,
4734 + mergetoolopts,
4783 _(b'[-P] [[-r] REV]'),
4735 _(b'[-P] [[-r] REV]'),
4784 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4736 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4785 helpbasic=True,
4737 helpbasic=True,
4786 )
4738 )
4787 def merge(ui, repo, node=None, **opts):
4739 def merge(ui, repo, node=None, **opts):
4788 """merge another revision into working directory
4740 """merge another revision into working directory
4789
4741
4790 The current working directory is updated with all changes made in
4742 The current working directory is updated with all changes made in
4791 the requested revision since the last common predecessor revision.
4743 the requested revision since the last common predecessor revision.
4792
4744
4793 Files that changed between either parent are marked as changed for
4745 Files that changed between either parent are marked as changed for
4794 the next commit and a commit must be performed before any further
4746 the next commit and a commit must be performed before any further
4795 updates to the repository are allowed. The next commit will have
4747 updates to the repository are allowed. The next commit will have
4796 two parents.
4748 two parents.
4797
4749
4798 ``--tool`` can be used to specify the merge tool used for file
4750 ``--tool`` can be used to specify the merge tool used for file
4799 merges. It overrides the HGMERGE environment variable and your
4751 merges. It overrides the HGMERGE environment variable and your
4800 configuration files. See :hg:`help merge-tools` for options.
4752 configuration files. See :hg:`help merge-tools` for options.
4801
4753
4802 If no revision is specified, the working directory's parent is a
4754 If no revision is specified, the working directory's parent is a
4803 head revision, and the current branch contains exactly one other
4755 head revision, and the current branch contains exactly one other
4804 head, the other head is merged with by default. Otherwise, an
4756 head, the other head is merged with by default. Otherwise, an
4805 explicit revision with which to merge must be provided.
4757 explicit revision with which to merge must be provided.
4806
4758
4807 See :hg:`help resolve` for information on handling file conflicts.
4759 See :hg:`help resolve` for information on handling file conflicts.
4808
4760
4809 To undo an uncommitted merge, use :hg:`merge --abort` which
4761 To undo an uncommitted merge, use :hg:`merge --abort` which
4810 will check out a clean copy of the original merge parent, losing
4762 will check out a clean copy of the original merge parent, losing
4811 all changes.
4763 all changes.
4812
4764
4813 Returns 0 on success, 1 if there are unresolved files.
4765 Returns 0 on success, 1 if there are unresolved files.
4814 """
4766 """
4815
4767
4816 opts = pycompat.byteskwargs(opts)
4768 opts = pycompat.byteskwargs(opts)
4817 abort = opts.get(b'abort')
4769 abort = opts.get(b'abort')
4818 if abort and repo.dirstate.p2() == nullid:
4770 if abort and repo.dirstate.p2() == nullid:
4819 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4771 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4820 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4772 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4821 if abort:
4773 if abort:
4822 state = cmdutil.getunfinishedstate(repo)
4774 state = cmdutil.getunfinishedstate(repo)
4823 if state and state._opname != b'merge':
4775 if state and state._opname != b'merge':
4824 raise error.Abort(
4776 raise error.Abort(
4825 _(b'cannot abort merge with %s in progress') % (state._opname),
4777 _(b'cannot abort merge with %s in progress') % (state._opname),
4826 hint=state.hint(),
4778 hint=state.hint(),
4827 )
4779 )
4828 if node:
4780 if node:
4829 raise error.Abort(_(b"cannot specify a node with --abort"))
4781 raise error.Abort(_(b"cannot specify a node with --abort"))
4830 return hg.abortmerge(repo.ui, repo)
4782 return hg.abortmerge(repo.ui, repo)
4831
4783
4832 if opts.get(b'rev') and node:
4784 if opts.get(b'rev') and node:
4833 raise error.Abort(_(b"please specify just one revision"))
4785 raise error.Abort(_(b"please specify just one revision"))
4834 if not node:
4786 if not node:
4835 node = opts.get(b'rev')
4787 node = opts.get(b'rev')
4836
4788
4837 if node:
4789 if node:
4838 ctx = scmutil.revsingle(repo, node)
4790 ctx = scmutil.revsingle(repo, node)
4839 else:
4791 else:
4840 if ui.configbool(b'commands', b'merge.require-rev'):
4792 if ui.configbool(b'commands', b'merge.require-rev'):
4841 raise error.Abort(
4793 raise error.Abort(
4842 _(
4794 _(
4843 b'configuration requires specifying revision to merge '
4795 b'configuration requires specifying revision to merge '
4844 b'with'
4796 b'with'
4845 )
4797 )
4846 )
4798 )
4847 ctx = repo[destutil.destmerge(repo)]
4799 ctx = repo[destutil.destmerge(repo)]
4848
4800
4849 if ctx.node() is None:
4801 if ctx.node() is None:
4850 raise error.Abort(_(b'merging with the working copy has no effect'))
4802 raise error.Abort(_(b'merging with the working copy has no effect'))
4851
4803
4852 if opts.get(b'preview'):
4804 if opts.get(b'preview'):
4853 # find nodes that are ancestors of p2 but not of p1
4805 # find nodes that are ancestors of p2 but not of p1
4854 p1 = repo[b'.'].node()
4806 p1 = repo[b'.'].node()
4855 p2 = ctx.node()
4807 p2 = ctx.node()
4856 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4808 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4857
4809
4858 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4810 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4859 for node in nodes:
4811 for node in nodes:
4860 displayer.show(repo[node])
4812 displayer.show(repo[node])
4861 displayer.close()
4813 displayer.close()
4862 return 0
4814 return 0
4863
4815
4864 # ui.forcemerge is an internal variable, do not document
4816 # ui.forcemerge is an internal variable, do not document
4865 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4817 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4866 with ui.configoverride(overrides, b'merge'):
4818 with ui.configoverride(overrides, b'merge'):
4867 force = opts.get(b'force')
4819 force = opts.get(b'force')
4868 labels = [b'working copy', b'merge rev']
4820 labels = [b'working copy', b'merge rev']
4869 return hg.merge(ctx, force=force, labels=labels)
4821 return hg.merge(ctx, force=force, labels=labels)
4870
4822
4871
4823
4872 statemod.addunfinished(
4824 statemod.addunfinished(
4873 b'merge',
4825 b'merge',
4874 fname=None,
4826 fname=None,
4875 clearable=True,
4827 clearable=True,
4876 allowcommit=True,
4828 allowcommit=True,
4877 cmdmsg=_(b'outstanding uncommitted merge'),
4829 cmdmsg=_(b'outstanding uncommitted merge'),
4878 abortfunc=hg.abortmerge,
4830 abortfunc=hg.abortmerge,
4879 statushint=_(
4831 statushint=_(
4880 b'To continue: hg commit\nTo abort: hg merge --abort'
4832 b'To continue: hg commit\nTo abort: hg merge --abort'
4881 ),
4833 ),
4882 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4834 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4883 )
4835 )
4884
4836
4885
4837
4886 @command(
4838 @command(
4887 b'outgoing|out',
4839 b'outgoing|out',
4888 [
4840 [
4889 (
4841 (
4890 b'f',
4842 b'f',
4891 b'force',
4843 b'force',
4892 None,
4844 None,
4893 _(b'run even when the destination is unrelated'),
4845 _(b'run even when the destination is unrelated'),
4894 ),
4846 ),
4895 (
4847 (
4896 b'r',
4848 b'r',
4897 b'rev',
4849 b'rev',
4898 [],
4850 [],
4899 _(b'a changeset intended to be included in the destination'),
4851 _(b'a changeset intended to be included in the destination'),
4900 _(b'REV'),
4852 _(b'REV'),
4901 ),
4853 ),
4902 (b'n', b'newest-first', None, _(b'show newest record first')),
4854 (b'n', b'newest-first', None, _(b'show newest record first')),
4903 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4855 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4904 (
4856 (
4905 b'b',
4857 b'b',
4906 b'branch',
4858 b'branch',
4907 [],
4859 [],
4908 _(b'a specific branch you would like to push'),
4860 _(b'a specific branch you would like to push'),
4909 _(b'BRANCH'),
4861 _(b'BRANCH'),
4910 ),
4862 ),
4911 ]
4863 ]
4912 + logopts
4864 + logopts
4913 + remoteopts
4865 + remoteopts
4914 + subrepoopts,
4866 + subrepoopts,
4915 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4867 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4916 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4868 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4917 )
4869 )
4918 def outgoing(ui, repo, dest=None, **opts):
4870 def outgoing(ui, repo, dest=None, **opts):
4919 """show changesets not found in the destination
4871 """show changesets not found in the destination
4920
4872
4921 Show changesets not found in the specified destination repository
4873 Show changesets not found in the specified destination repository
4922 or the default push location. These are the changesets that would
4874 or the default push location. These are the changesets that would
4923 be pushed if a push was requested.
4875 be pushed if a push was requested.
4924
4876
4925 See pull for details of valid destination formats.
4877 See pull for details of valid destination formats.
4926
4878
4927 .. container:: verbose
4879 .. container:: verbose
4928
4880
4929 With -B/--bookmarks, the result of bookmark comparison between
4881 With -B/--bookmarks, the result of bookmark comparison between
4930 local and remote repositories is displayed. With -v/--verbose,
4882 local and remote repositories is displayed. With -v/--verbose,
4931 status is also displayed for each bookmark like below::
4883 status is also displayed for each bookmark like below::
4932
4884
4933 BM1 01234567890a added
4885 BM1 01234567890a added
4934 BM2 deleted
4886 BM2 deleted
4935 BM3 234567890abc advanced
4887 BM3 234567890abc advanced
4936 BM4 34567890abcd diverged
4888 BM4 34567890abcd diverged
4937 BM5 4567890abcde changed
4889 BM5 4567890abcde changed
4938
4890
4939 The action taken when pushing depends on the
4891 The action taken when pushing depends on the
4940 status of each bookmark:
4892 status of each bookmark:
4941
4893
4942 :``added``: push with ``-B`` will create it
4894 :``added``: push with ``-B`` will create it
4943 :``deleted``: push with ``-B`` will delete it
4895 :``deleted``: push with ``-B`` will delete it
4944 :``advanced``: push will update it
4896 :``advanced``: push will update it
4945 :``diverged``: push with ``-B`` will update it
4897 :``diverged``: push with ``-B`` will update it
4946 :``changed``: push with ``-B`` will update it
4898 :``changed``: push with ``-B`` will update it
4947
4899
4948 From the point of view of pushing behavior, bookmarks
4900 From the point of view of pushing behavior, bookmarks
4949 existing only in the remote repository are treated as
4901 existing only in the remote repository are treated as
4950 ``deleted``, even if it is in fact added remotely.
4902 ``deleted``, even if it is in fact added remotely.
4951
4903
4952 Returns 0 if there are outgoing changes, 1 otherwise.
4904 Returns 0 if there are outgoing changes, 1 otherwise.
4953 """
4905 """
4954 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4906 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4955 # style URLs, so don't overwrite dest.
4907 # style URLs, so don't overwrite dest.
4956 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4908 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4957 if not path:
4909 if not path:
4958 raise error.Abort(
4910 raise error.Abort(
4959 _(b'default repository not configured!'),
4911 _(b'default repository not configured!'),
4960 hint=_(b"see 'hg help config.paths'"),
4912 hint=_(b"see 'hg help config.paths'"),
4961 )
4913 )
4962
4914
4963 opts = pycompat.byteskwargs(opts)
4915 opts = pycompat.byteskwargs(opts)
4964 if opts.get(b'graph'):
4916 if opts.get(b'graph'):
4965 logcmdutil.checkunsupportedgraphflags([], opts)
4917 logcmdutil.checkunsupportedgraphflags([], opts)
4966 o, other = hg._outgoing(ui, repo, dest, opts)
4918 o, other = hg._outgoing(ui, repo, dest, opts)
4967 if not o:
4919 if not o:
4968 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4920 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4969 return
4921 return
4970
4922
4971 revdag = logcmdutil.graphrevs(repo, o, opts)
4923 revdag = logcmdutil.graphrevs(repo, o, opts)
4972 ui.pager(b'outgoing')
4924 ui.pager(b'outgoing')
4973 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4925 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4974 logcmdutil.displaygraph(
4926 logcmdutil.displaygraph(
4975 ui, repo, revdag, displayer, graphmod.asciiedges
4927 ui, repo, revdag, displayer, graphmod.asciiedges
4976 )
4928 )
4977 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4929 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4978 return 0
4930 return 0
4979
4931
4980 if opts.get(b'bookmarks'):
4932 if opts.get(b'bookmarks'):
4981 dest = path.pushloc or path.loc
4933 dest = path.pushloc or path.loc
4982 other = hg.peer(repo, opts, dest)
4934 other = hg.peer(repo, opts, dest)
4983 if b'bookmarks' not in other.listkeys(b'namespaces'):
4935 if b'bookmarks' not in other.listkeys(b'namespaces'):
4984 ui.warn(_(b"remote doesn't support bookmarks\n"))
4936 ui.warn(_(b"remote doesn't support bookmarks\n"))
4985 return 0
4937 return 0
4986 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4938 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4987 ui.pager(b'outgoing')
4939 ui.pager(b'outgoing')
4988 return bookmarks.outgoing(ui, repo, other)
4940 return bookmarks.outgoing(ui, repo, other)
4989
4941
4990 repo._subtoppath = path.pushloc or path.loc
4942 repo._subtoppath = path.pushloc or path.loc
4991 try:
4943 try:
4992 return hg.outgoing(ui, repo, dest, opts)
4944 return hg.outgoing(ui, repo, dest, opts)
4993 finally:
4945 finally:
4994 del repo._subtoppath
4946 del repo._subtoppath
4995
4947
4996
4948
4997 @command(
4949 @command(
4998 b'parents',
4950 b'parents',
4999 [
4951 [
5000 (
4952 (
5001 b'r',
4953 b'r',
5002 b'rev',
4954 b'rev',
5003 b'',
4955 b'',
5004 _(b'show parents of the specified revision'),
4956 _(b'show parents of the specified revision'),
5005 _(b'REV'),
4957 _(b'REV'),
5006 ),
4958 ),
5007 ]
4959 ]
5008 + templateopts,
4960 + templateopts,
5009 _(b'[-r REV] [FILE]'),
4961 _(b'[-r REV] [FILE]'),
5010 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4962 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5011 inferrepo=True,
4963 inferrepo=True,
5012 )
4964 )
5013 def parents(ui, repo, file_=None, **opts):
4965 def parents(ui, repo, file_=None, **opts):
5014 """show the parents of the working directory or revision (DEPRECATED)
4966 """show the parents of the working directory or revision (DEPRECATED)
5015
4967
5016 Print the working directory's parent revisions. If a revision is
4968 Print the working directory's parent revisions. If a revision is
5017 given via -r/--rev, the parent of that revision will be printed.
4969 given via -r/--rev, the parent of that revision will be printed.
5018 If a file argument is given, the revision in which the file was
4970 If a file argument is given, the revision in which the file was
5019 last changed (before the working directory revision or the
4971 last changed (before the working directory revision or the
5020 argument to --rev if given) is printed.
4972 argument to --rev if given) is printed.
5021
4973
5022 This command is equivalent to::
4974 This command is equivalent to::
5023
4975
5024 hg log -r "p1()+p2()" or
4976 hg log -r "p1()+p2()" or
5025 hg log -r "p1(REV)+p2(REV)" or
4977 hg log -r "p1(REV)+p2(REV)" or
5026 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4978 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5027 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4979 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5028
4980
5029 See :hg:`summary` and :hg:`help revsets` for related information.
4981 See :hg:`summary` and :hg:`help revsets` for related information.
5030
4982
5031 Returns 0 on success.
4983 Returns 0 on success.
5032 """
4984 """
5033
4985
5034 opts = pycompat.byteskwargs(opts)
4986 opts = pycompat.byteskwargs(opts)
5035 rev = opts.get(b'rev')
4987 rev = opts.get(b'rev')
5036 if rev:
4988 if rev:
5037 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4989 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5038 ctx = scmutil.revsingle(repo, rev, None)
4990 ctx = scmutil.revsingle(repo, rev, None)
5039
4991
5040 if file_:
4992 if file_:
5041 m = scmutil.match(ctx, (file_,), opts)
4993 m = scmutil.match(ctx, (file_,), opts)
5042 if m.anypats() or len(m.files()) != 1:
4994 if m.anypats() or len(m.files()) != 1:
5043 raise error.Abort(_(b'can only specify an explicit filename'))
4995 raise error.Abort(_(b'can only specify an explicit filename'))
5044 file_ = m.files()[0]
4996 file_ = m.files()[0]
5045 filenodes = []
4997 filenodes = []
5046 for cp in ctx.parents():
4998 for cp in ctx.parents():
5047 if not cp:
4999 if not cp:
5048 continue
5000 continue
5049 try:
5001 try:
5050 filenodes.append(cp.filenode(file_))
5002 filenodes.append(cp.filenode(file_))
5051 except error.LookupError:
5003 except error.LookupError:
5052 pass
5004 pass
5053 if not filenodes:
5005 if not filenodes:
5054 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5006 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5055 p = []
5007 p = []
5056 for fn in filenodes:
5008 for fn in filenodes:
5057 fctx = repo.filectx(file_, fileid=fn)
5009 fctx = repo.filectx(file_, fileid=fn)
5058 p.append(fctx.node())
5010 p.append(fctx.node())
5059 else:
5011 else:
5060 p = [cp.node() for cp in ctx.parents()]
5012 p = [cp.node() for cp in ctx.parents()]
5061
5013
5062 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5014 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5063 for n in p:
5015 for n in p:
5064 if n != nullid:
5016 if n != nullid:
5065 displayer.show(repo[n])
5017 displayer.show(repo[n])
5066 displayer.close()
5018 displayer.close()
5067
5019
5068
5020
5069 @command(
5021 @command(
5070 b'paths',
5022 b'paths',
5071 formatteropts,
5023 formatteropts,
5072 _(b'[NAME]'),
5024 _(b'[NAME]'),
5073 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5025 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5074 optionalrepo=True,
5026 optionalrepo=True,
5075 intents={INTENT_READONLY},
5027 intents={INTENT_READONLY},
5076 )
5028 )
5077 def paths(ui, repo, search=None, **opts):
5029 def paths(ui, repo, search=None, **opts):
5078 """show aliases for remote repositories
5030 """show aliases for remote repositories
5079
5031
5080 Show definition of symbolic path name NAME. If no name is given,
5032 Show definition of symbolic path name NAME. If no name is given,
5081 show definition of all available names.
5033 show definition of all available names.
5082
5034
5083 Option -q/--quiet suppresses all output when searching for NAME
5035 Option -q/--quiet suppresses all output when searching for NAME
5084 and shows only the path names when listing all definitions.
5036 and shows only the path names when listing all definitions.
5085
5037
5086 Path names are defined in the [paths] section of your
5038 Path names are defined in the [paths] section of your
5087 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5039 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5088 repository, ``.hg/hgrc`` is used, too.
5040 repository, ``.hg/hgrc`` is used, too.
5089
5041
5090 The path names ``default`` and ``default-push`` have a special
5042 The path names ``default`` and ``default-push`` have a special
5091 meaning. When performing a push or pull operation, they are used
5043 meaning. When performing a push or pull operation, they are used
5092 as fallbacks if no location is specified on the command-line.
5044 as fallbacks if no location is specified on the command-line.
5093 When ``default-push`` is set, it will be used for push and
5045 When ``default-push`` is set, it will be used for push and
5094 ``default`` will be used for pull; otherwise ``default`` is used
5046 ``default`` will be used for pull; otherwise ``default`` is used
5095 as the fallback for both. When cloning a repository, the clone
5047 as the fallback for both. When cloning a repository, the clone
5096 source is written as ``default`` in ``.hg/hgrc``.
5048 source is written as ``default`` in ``.hg/hgrc``.
5097
5049
5098 .. note::
5050 .. note::
5099
5051
5100 ``default`` and ``default-push`` apply to all inbound (e.g.
5052 ``default`` and ``default-push`` apply to all inbound (e.g.
5101 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5053 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5102 and :hg:`bundle`) operations.
5054 and :hg:`bundle`) operations.
5103
5055
5104 See :hg:`help urls` for more information.
5056 See :hg:`help urls` for more information.
5105
5057
5106 .. container:: verbose
5058 .. container:: verbose
5107
5059
5108 Template:
5060 Template:
5109
5061
5110 The following keywords are supported. See also :hg:`help templates`.
5062 The following keywords are supported. See also :hg:`help templates`.
5111
5063
5112 :name: String. Symbolic name of the path alias.
5064 :name: String. Symbolic name of the path alias.
5113 :pushurl: String. URL for push operations.
5065 :pushurl: String. URL for push operations.
5114 :url: String. URL or directory path for the other operations.
5066 :url: String. URL or directory path for the other operations.
5115
5067
5116 Returns 0 on success.
5068 Returns 0 on success.
5117 """
5069 """
5118
5070
5119 opts = pycompat.byteskwargs(opts)
5071 opts = pycompat.byteskwargs(opts)
5120 ui.pager(b'paths')
5072 ui.pager(b'paths')
5121 if search:
5073 if search:
5122 pathitems = [
5074 pathitems = [
5123 (name, path)
5075 (name, path)
5124 for name, path in pycompat.iteritems(ui.paths)
5076 for name, path in pycompat.iteritems(ui.paths)
5125 if name == search
5077 if name == search
5126 ]
5078 ]
5127 else:
5079 else:
5128 pathitems = sorted(pycompat.iteritems(ui.paths))
5080 pathitems = sorted(pycompat.iteritems(ui.paths))
5129
5081
5130 fm = ui.formatter(b'paths', opts)
5082 fm = ui.formatter(b'paths', opts)
5131 if fm.isplain():
5083 if fm.isplain():
5132 hidepassword = util.hidepassword
5084 hidepassword = util.hidepassword
5133 else:
5085 else:
5134 hidepassword = bytes
5086 hidepassword = bytes
5135 if ui.quiet:
5087 if ui.quiet:
5136 namefmt = b'%s\n'
5088 namefmt = b'%s\n'
5137 else:
5089 else:
5138 namefmt = b'%s = '
5090 namefmt = b'%s = '
5139 showsubopts = not search and not ui.quiet
5091 showsubopts = not search and not ui.quiet
5140
5092
5141 for name, path in pathitems:
5093 for name, path in pathitems:
5142 fm.startitem()
5094 fm.startitem()
5143 fm.condwrite(not search, b'name', namefmt, name)
5095 fm.condwrite(not search, b'name', namefmt, name)
5144 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5096 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5145 for subopt, value in sorted(path.suboptions.items()):
5097 for subopt, value in sorted(path.suboptions.items()):
5146 assert subopt not in (b'name', b'url')
5098 assert subopt not in (b'name', b'url')
5147 if showsubopts:
5099 if showsubopts:
5148 fm.plain(b'%s:%s = ' % (name, subopt))
5100 fm.plain(b'%s:%s = ' % (name, subopt))
5149 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5101 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5150
5102
5151 fm.end()
5103 fm.end()
5152
5104
5153 if search and not pathitems:
5105 if search and not pathitems:
5154 if not ui.quiet:
5106 if not ui.quiet:
5155 ui.warn(_(b"not found!\n"))
5107 ui.warn(_(b"not found!\n"))
5156 return 1
5108 return 1
5157 else:
5109 else:
5158 return 0
5110 return 0
5159
5111
5160
5112
5161 @command(
5113 @command(
5162 b'phase',
5114 b'phase',
5163 [
5115 [
5164 (b'p', b'public', False, _(b'set changeset phase to public')),
5116 (b'p', b'public', False, _(b'set changeset phase to public')),
5165 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5117 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5166 (b's', b'secret', False, _(b'set changeset phase to secret')),
5118 (b's', b'secret', False, _(b'set changeset phase to secret')),
5167 (b'f', b'force', False, _(b'allow to move boundary backward')),
5119 (b'f', b'force', False, _(b'allow to move boundary backward')),
5168 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5120 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5169 ],
5121 ],
5170 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5122 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5171 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5123 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5172 )
5124 )
5173 def phase(ui, repo, *revs, **opts):
5125 def phase(ui, repo, *revs, **opts):
5174 """set or show the current phase name
5126 """set or show the current phase name
5175
5127
5176 With no argument, show the phase name of the current revision(s).
5128 With no argument, show the phase name of the current revision(s).
5177
5129
5178 With one of -p/--public, -d/--draft or -s/--secret, change the
5130 With one of -p/--public, -d/--draft or -s/--secret, change the
5179 phase value of the specified revisions.
5131 phase value of the specified revisions.
5180
5132
5181 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5133 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5182 lower phase to a higher phase. Phases are ordered as follows::
5134 lower phase to a higher phase. Phases are ordered as follows::
5183
5135
5184 public < draft < secret
5136 public < draft < secret
5185
5137
5186 Returns 0 on success, 1 if some phases could not be changed.
5138 Returns 0 on success, 1 if some phases could not be changed.
5187
5139
5188 (For more information about the phases concept, see :hg:`help phases`.)
5140 (For more information about the phases concept, see :hg:`help phases`.)
5189 """
5141 """
5190 opts = pycompat.byteskwargs(opts)
5142 opts = pycompat.byteskwargs(opts)
5191 # search for a unique phase argument
5143 # search for a unique phase argument
5192 targetphase = None
5144 targetphase = None
5193 for idx, name in enumerate(phases.cmdphasenames):
5145 for idx, name in enumerate(phases.cmdphasenames):
5194 if opts[name]:
5146 if opts[name]:
5195 if targetphase is not None:
5147 if targetphase is not None:
5196 raise error.Abort(_(b'only one phase can be specified'))
5148 raise error.Abort(_(b'only one phase can be specified'))
5197 targetphase = idx
5149 targetphase = idx
5198
5150
5199 # look for specified revision
5151 # look for specified revision
5200 revs = list(revs)
5152 revs = list(revs)
5201 revs.extend(opts[b'rev'])
5153 revs.extend(opts[b'rev'])
5202 if not revs:
5154 if not revs:
5203 # display both parents as the second parent phase can influence
5155 # display both parents as the second parent phase can influence
5204 # the phase of a merge commit
5156 # the phase of a merge commit
5205 revs = [c.rev() for c in repo[None].parents()]
5157 revs = [c.rev() for c in repo[None].parents()]
5206
5158
5207 revs = scmutil.revrange(repo, revs)
5159 revs = scmutil.revrange(repo, revs)
5208
5160
5209 ret = 0
5161 ret = 0
5210 if targetphase is None:
5162 if targetphase is None:
5211 # display
5163 # display
5212 for r in revs:
5164 for r in revs:
5213 ctx = repo[r]
5165 ctx = repo[r]
5214 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5166 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5215 else:
5167 else:
5216 with repo.lock(), repo.transaction(b"phase") as tr:
5168 with repo.lock(), repo.transaction(b"phase") as tr:
5217 # set phase
5169 # set phase
5218 if not revs:
5170 if not revs:
5219 raise error.Abort(_(b'empty revision set'))
5171 raise error.Abort(_(b'empty revision set'))
5220 nodes = [repo[r].node() for r in revs]
5172 nodes = [repo[r].node() for r in revs]
5221 # moving revision from public to draft may hide them
5173 # moving revision from public to draft may hide them
5222 # We have to check result on an unfiltered repository
5174 # We have to check result on an unfiltered repository
5223 unfi = repo.unfiltered()
5175 unfi = repo.unfiltered()
5224 getphase = unfi._phasecache.phase
5176 getphase = unfi._phasecache.phase
5225 olddata = [getphase(unfi, r) for r in unfi]
5177 olddata = [getphase(unfi, r) for r in unfi]
5226 phases.advanceboundary(repo, tr, targetphase, nodes)
5178 phases.advanceboundary(repo, tr, targetphase, nodes)
5227 if opts[b'force']:
5179 if opts[b'force']:
5228 phases.retractboundary(repo, tr, targetphase, nodes)
5180 phases.retractboundary(repo, tr, targetphase, nodes)
5229 getphase = unfi._phasecache.phase
5181 getphase = unfi._phasecache.phase
5230 newdata = [getphase(unfi, r) for r in unfi]
5182 newdata = [getphase(unfi, r) for r in unfi]
5231 changes = sum(newdata[r] != olddata[r] for r in unfi)
5183 changes = sum(newdata[r] != olddata[r] for r in unfi)
5232 cl = unfi.changelog
5184 cl = unfi.changelog
5233 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5185 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5234 if rejected:
5186 if rejected:
5235 ui.warn(
5187 ui.warn(
5236 _(
5188 _(
5237 b'cannot move %i changesets to a higher '
5189 b'cannot move %i changesets to a higher '
5238 b'phase, use --force\n'
5190 b'phase, use --force\n'
5239 )
5191 )
5240 % len(rejected)
5192 % len(rejected)
5241 )
5193 )
5242 ret = 1
5194 ret = 1
5243 if changes:
5195 if changes:
5244 msg = _(b'phase changed for %i changesets\n') % changes
5196 msg = _(b'phase changed for %i changesets\n') % changes
5245 if ret:
5197 if ret:
5246 ui.status(msg)
5198 ui.status(msg)
5247 else:
5199 else:
5248 ui.note(msg)
5200 ui.note(msg)
5249 else:
5201 else:
5250 ui.warn(_(b'no phases changed\n'))
5202 ui.warn(_(b'no phases changed\n'))
5251 return ret
5203 return ret
5252
5204
5253
5205
5254 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5206 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5255 """Run after a changegroup has been added via pull/unbundle
5207 """Run after a changegroup has been added via pull/unbundle
5256
5208
5257 This takes arguments below:
5209 This takes arguments below:
5258
5210
5259 :modheads: change of heads by pull/unbundle
5211 :modheads: change of heads by pull/unbundle
5260 :optupdate: updating working directory is needed or not
5212 :optupdate: updating working directory is needed or not
5261 :checkout: update destination revision (or None to default destination)
5213 :checkout: update destination revision (or None to default destination)
5262 :brev: a name, which might be a bookmark to be activated after updating
5214 :brev: a name, which might be a bookmark to be activated after updating
5263 """
5215 """
5264 if modheads == 0:
5216 if modheads == 0:
5265 return
5217 return
5266 if optupdate:
5218 if optupdate:
5267 try:
5219 try:
5268 return hg.updatetotally(ui, repo, checkout, brev)
5220 return hg.updatetotally(ui, repo, checkout, brev)
5269 except error.UpdateAbort as inst:
5221 except error.UpdateAbort as inst:
5270 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5222 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5271 hint = inst.hint
5223 hint = inst.hint
5272 raise error.UpdateAbort(msg, hint=hint)
5224 raise error.UpdateAbort(msg, hint=hint)
5273 if modheads is not None and modheads > 1:
5225 if modheads is not None and modheads > 1:
5274 currentbranchheads = len(repo.branchheads())
5226 currentbranchheads = len(repo.branchheads())
5275 if currentbranchheads == modheads:
5227 if currentbranchheads == modheads:
5276 ui.status(
5228 ui.status(
5277 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5229 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5278 )
5230 )
5279 elif currentbranchheads > 1:
5231 elif currentbranchheads > 1:
5280 ui.status(
5232 ui.status(
5281 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5233 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5282 )
5234 )
5283 else:
5235 else:
5284 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5236 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5285 elif not ui.configbool(b'commands', b'update.requiredest'):
5237 elif not ui.configbool(b'commands', b'update.requiredest'):
5286 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5238 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5287
5239
5288
5240
5289 @command(
5241 @command(
5290 b'pull',
5242 b'pull',
5291 [
5243 [
5292 (
5244 (
5293 b'u',
5245 b'u',
5294 b'update',
5246 b'update',
5295 None,
5247 None,
5296 _(b'update to new branch head if new descendants were pulled'),
5248 _(b'update to new branch head if new descendants were pulled'),
5297 ),
5249 ),
5298 (
5250 (
5299 b'f',
5251 b'f',
5300 b'force',
5252 b'force',
5301 None,
5253 None,
5302 _(b'run even when remote repository is unrelated'),
5254 _(b'run even when remote repository is unrelated'),
5303 ),
5255 ),
5304 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5256 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5305 (
5257 (
5306 b'r',
5258 b'r',
5307 b'rev',
5259 b'rev',
5308 [],
5260 [],
5309 _(b'a remote changeset intended to be added'),
5261 _(b'a remote changeset intended to be added'),
5310 _(b'REV'),
5262 _(b'REV'),
5311 ),
5263 ),
5312 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5264 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5313 (
5265 (
5314 b'b',
5266 b'b',
5315 b'branch',
5267 b'branch',
5316 [],
5268 [],
5317 _(b'a specific branch you would like to pull'),
5269 _(b'a specific branch you would like to pull'),
5318 _(b'BRANCH'),
5270 _(b'BRANCH'),
5319 ),
5271 ),
5320 ]
5272 ]
5321 + remoteopts,
5273 + remoteopts,
5322 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5274 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5323 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5275 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5324 helpbasic=True,
5276 helpbasic=True,
5325 )
5277 )
5326 def pull(ui, repo, source=b"default", **opts):
5278 def pull(ui, repo, source=b"default", **opts):
5327 """pull changes from the specified source
5279 """pull changes from the specified source
5328
5280
5329 Pull changes from a remote repository to a local one.
5281 Pull changes from a remote repository to a local one.
5330
5282
5331 This finds all changes from the repository at the specified path
5283 This finds all changes from the repository at the specified path
5332 or URL and adds them to a local repository (the current one unless
5284 or URL and adds them to a local repository (the current one unless
5333 -R is specified). By default, this does not update the copy of the
5285 -R is specified). By default, this does not update the copy of the
5334 project in the working directory.
5286 project in the working directory.
5335
5287
5336 When cloning from servers that support it, Mercurial may fetch
5288 When cloning from servers that support it, Mercurial may fetch
5337 pre-generated data. When this is done, hooks operating on incoming
5289 pre-generated data. When this is done, hooks operating on incoming
5338 changesets and changegroups may fire more than once, once for each
5290 changesets and changegroups may fire more than once, once for each
5339 pre-generated bundle and as well as for any additional remaining
5291 pre-generated bundle and as well as for any additional remaining
5340 data. See :hg:`help -e clonebundles` for more.
5292 data. See :hg:`help -e clonebundles` for more.
5341
5293
5342 Use :hg:`incoming` if you want to see what would have been added
5294 Use :hg:`incoming` if you want to see what would have been added
5343 by a pull at the time you issued this command. If you then decide
5295 by a pull at the time you issued this command. If you then decide
5344 to add those changes to the repository, you should use :hg:`pull
5296 to add those changes to the repository, you should use :hg:`pull
5345 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5297 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5346
5298
5347 If SOURCE is omitted, the 'default' path will be used.
5299 If SOURCE is omitted, the 'default' path will be used.
5348 See :hg:`help urls` for more information.
5300 See :hg:`help urls` for more information.
5349
5301
5350 Specifying bookmark as ``.`` is equivalent to specifying the active
5302 Specifying bookmark as ``.`` is equivalent to specifying the active
5351 bookmark's name.
5303 bookmark's name.
5352
5304
5353 Returns 0 on success, 1 if an update had unresolved files.
5305 Returns 0 on success, 1 if an update had unresolved files.
5354 """
5306 """
5355
5307
5356 opts = pycompat.byteskwargs(opts)
5308 opts = pycompat.byteskwargs(opts)
5357 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5309 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5358 b'update'
5310 b'update'
5359 ):
5311 ):
5360 msg = _(b'update destination required by configuration')
5312 msg = _(b'update destination required by configuration')
5361 hint = _(b'use hg pull followed by hg update DEST')
5313 hint = _(b'use hg pull followed by hg update DEST')
5362 raise error.Abort(msg, hint=hint)
5314 raise error.Abort(msg, hint=hint)
5363
5315
5364 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5316 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5365 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5317 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5366 other = hg.peer(repo, opts, source)
5318 other = hg.peer(repo, opts, source)
5367 try:
5319 try:
5368 revs, checkout = hg.addbranchrevs(
5320 revs, checkout = hg.addbranchrevs(
5369 repo, other, branches, opts.get(b'rev')
5321 repo, other, branches, opts.get(b'rev')
5370 )
5322 )
5371
5323
5372 pullopargs = {}
5324 pullopargs = {}
5373
5325
5374 nodes = None
5326 nodes = None
5375 if opts.get(b'bookmark') or revs:
5327 if opts.get(b'bookmark') or revs:
5376 # The list of bookmark used here is the same used to actually update
5328 # The list of bookmark used here is the same used to actually update
5377 # the bookmark names, to avoid the race from issue 4689 and we do
5329 # the bookmark names, to avoid the race from issue 4689 and we do
5378 # all lookup and bookmark queries in one go so they see the same
5330 # all lookup and bookmark queries in one go so they see the same
5379 # version of the server state (issue 4700).
5331 # version of the server state (issue 4700).
5380 nodes = []
5332 nodes = []
5381 fnodes = []
5333 fnodes = []
5382 revs = revs or []
5334 revs = revs or []
5383 if revs and not other.capable(b'lookup'):
5335 if revs and not other.capable(b'lookup'):
5384 err = _(
5336 err = _(
5385 b"other repository doesn't support revision lookup, "
5337 b"other repository doesn't support revision lookup, "
5386 b"so a rev cannot be specified."
5338 b"so a rev cannot be specified."
5387 )
5339 )
5388 raise error.Abort(err)
5340 raise error.Abort(err)
5389 with other.commandexecutor() as e:
5341 with other.commandexecutor() as e:
5390 fremotebookmarks = e.callcommand(
5342 fremotebookmarks = e.callcommand(
5391 b'listkeys', {b'namespace': b'bookmarks'}
5343 b'listkeys', {b'namespace': b'bookmarks'}
5392 )
5344 )
5393 for r in revs:
5345 for r in revs:
5394 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5346 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5395 remotebookmarks = fremotebookmarks.result()
5347 remotebookmarks = fremotebookmarks.result()
5396 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5348 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5397 pullopargs[b'remotebookmarks'] = remotebookmarks
5349 pullopargs[b'remotebookmarks'] = remotebookmarks
5398 for b in opts.get(b'bookmark', []):
5350 for b in opts.get(b'bookmark', []):
5399 b = repo._bookmarks.expandname(b)
5351 b = repo._bookmarks.expandname(b)
5400 if b not in remotebookmarks:
5352 if b not in remotebookmarks:
5401 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5353 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5402 nodes.append(remotebookmarks[b])
5354 nodes.append(remotebookmarks[b])
5403 for i, rev in enumerate(revs):
5355 for i, rev in enumerate(revs):
5404 node = fnodes[i].result()
5356 node = fnodes[i].result()
5405 nodes.append(node)
5357 nodes.append(node)
5406 if rev == checkout:
5358 if rev == checkout:
5407 checkout = node
5359 checkout = node
5408
5360
5409 wlock = util.nullcontextmanager()
5361 wlock = util.nullcontextmanager()
5410 if opts.get(b'update'):
5362 if opts.get(b'update'):
5411 wlock = repo.wlock()
5363 wlock = repo.wlock()
5412 with wlock:
5364 with wlock:
5413 pullopargs.update(opts.get(b'opargs', {}))
5365 pullopargs.update(opts.get(b'opargs', {}))
5414 modheads = exchange.pull(
5366 modheads = exchange.pull(
5415 repo,
5367 repo,
5416 other,
5368 other,
5417 heads=nodes,
5369 heads=nodes,
5418 force=opts.get(b'force'),
5370 force=opts.get(b'force'),
5419 bookmarks=opts.get(b'bookmark', ()),
5371 bookmarks=opts.get(b'bookmark', ()),
5420 opargs=pullopargs,
5372 opargs=pullopargs,
5421 confirm=opts.get(b'confirm'),
5373 confirm=opts.get(b'confirm'),
5422 ).cgresult
5374 ).cgresult
5423
5375
5424 # brev is a name, which might be a bookmark to be activated at
5376 # brev is a name, which might be a bookmark to be activated at
5425 # the end of the update. In other words, it is an explicit
5377 # the end of the update. In other words, it is an explicit
5426 # destination of the update
5378 # destination of the update
5427 brev = None
5379 brev = None
5428
5380
5429 if checkout:
5381 if checkout:
5430 checkout = repo.unfiltered().changelog.rev(checkout)
5382 checkout = repo.unfiltered().changelog.rev(checkout)
5431
5383
5432 # order below depends on implementation of
5384 # order below depends on implementation of
5433 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5385 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5434 # because 'checkout' is determined without it.
5386 # because 'checkout' is determined without it.
5435 if opts.get(b'rev'):
5387 if opts.get(b'rev'):
5436 brev = opts[b'rev'][0]
5388 brev = opts[b'rev'][0]
5437 elif opts.get(b'branch'):
5389 elif opts.get(b'branch'):
5438 brev = opts[b'branch'][0]
5390 brev = opts[b'branch'][0]
5439 else:
5391 else:
5440 brev = branches[0]
5392 brev = branches[0]
5441 repo._subtoppath = source
5393 repo._subtoppath = source
5442 try:
5394 try:
5443 ret = postincoming(
5395 ret = postincoming(
5444 ui, repo, modheads, opts.get(b'update'), checkout, brev
5396 ui, repo, modheads, opts.get(b'update'), checkout, brev
5445 )
5397 )
5446 except error.FilteredRepoLookupError as exc:
5398 except error.FilteredRepoLookupError as exc:
5447 msg = _(b'cannot update to target: %s') % exc.args[0]
5399 msg = _(b'cannot update to target: %s') % exc.args[0]
5448 exc.args = (msg,) + exc.args[1:]
5400 exc.args = (msg,) + exc.args[1:]
5449 raise
5401 raise
5450 finally:
5402 finally:
5451 del repo._subtoppath
5403 del repo._subtoppath
5452
5404
5453 finally:
5405 finally:
5454 other.close()
5406 other.close()
5455 return ret
5407 return ret
5456
5408
5457
5409
5458 @command(
5410 @command(
5459 b'push',
5411 b'push',
5460 [
5412 [
5461 (b'f', b'force', None, _(b'force push')),
5413 (b'f', b'force', None, _(b'force push')),
5462 (
5414 (
5463 b'r',
5415 b'r',
5464 b'rev',
5416 b'rev',
5465 [],
5417 [],
5466 _(b'a changeset intended to be included in the destination'),
5418 _(b'a changeset intended to be included in the destination'),
5467 _(b'REV'),
5419 _(b'REV'),
5468 ),
5420 ),
5469 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5421 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5470 (
5422 (
5471 b'b',
5423 b'b',
5472 b'branch',
5424 b'branch',
5473 [],
5425 [],
5474 _(b'a specific branch you would like to push'),
5426 _(b'a specific branch you would like to push'),
5475 _(b'BRANCH'),
5427 _(b'BRANCH'),
5476 ),
5428 ),
5477 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5429 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5478 (
5430 (
5479 b'',
5431 b'',
5480 b'pushvars',
5432 b'pushvars',
5481 [],
5433 [],
5482 _(b'variables that can be sent to server (ADVANCED)'),
5434 _(b'variables that can be sent to server (ADVANCED)'),
5483 ),
5435 ),
5484 (
5436 (
5485 b'',
5437 b'',
5486 b'publish',
5438 b'publish',
5487 False,
5439 False,
5488 _(b'push the changeset as public (EXPERIMENTAL)'),
5440 _(b'push the changeset as public (EXPERIMENTAL)'),
5489 ),
5441 ),
5490 ]
5442 ]
5491 + remoteopts,
5443 + remoteopts,
5492 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5444 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5493 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5445 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5494 helpbasic=True,
5446 helpbasic=True,
5495 )
5447 )
5496 def push(ui, repo, dest=None, **opts):
5448 def push(ui, repo, dest=None, **opts):
5497 """push changes to the specified destination
5449 """push changes to the specified destination
5498
5450
5499 Push changesets from the local repository to the specified
5451 Push changesets from the local repository to the specified
5500 destination.
5452 destination.
5501
5453
5502 This operation is symmetrical to pull: it is identical to a pull
5454 This operation is symmetrical to pull: it is identical to a pull
5503 in the destination repository from the current one.
5455 in the destination repository from the current one.
5504
5456
5505 By default, push will not allow creation of new heads at the
5457 By default, push will not allow creation of new heads at the
5506 destination, since multiple heads would make it unclear which head
5458 destination, since multiple heads would make it unclear which head
5507 to use. In this situation, it is recommended to pull and merge
5459 to use. In this situation, it is recommended to pull and merge
5508 before pushing.
5460 before pushing.
5509
5461
5510 Use --new-branch if you want to allow push to create a new named
5462 Use --new-branch if you want to allow push to create a new named
5511 branch that is not present at the destination. This allows you to
5463 branch that is not present at the destination. This allows you to
5512 only create a new branch without forcing other changes.
5464 only create a new branch without forcing other changes.
5513
5465
5514 .. note::
5466 .. note::
5515
5467
5516 Extra care should be taken with the -f/--force option,
5468 Extra care should be taken with the -f/--force option,
5517 which will push all new heads on all branches, an action which will
5469 which will push all new heads on all branches, an action which will
5518 almost always cause confusion for collaborators.
5470 almost always cause confusion for collaborators.
5519
5471
5520 If -r/--rev is used, the specified revision and all its ancestors
5472 If -r/--rev is used, the specified revision and all its ancestors
5521 will be pushed to the remote repository.
5473 will be pushed to the remote repository.
5522
5474
5523 If -B/--bookmark is used, the specified bookmarked revision, its
5475 If -B/--bookmark is used, the specified bookmarked revision, its
5524 ancestors, and the bookmark will be pushed to the remote
5476 ancestors, and the bookmark will be pushed to the remote
5525 repository. Specifying ``.`` is equivalent to specifying the active
5477 repository. Specifying ``.`` is equivalent to specifying the active
5526 bookmark's name.
5478 bookmark's name.
5527
5479
5528 Please see :hg:`help urls` for important details about ``ssh://``
5480 Please see :hg:`help urls` for important details about ``ssh://``
5529 URLs. If DESTINATION is omitted, a default path will be used.
5481 URLs. If DESTINATION is omitted, a default path will be used.
5530
5482
5531 .. container:: verbose
5483 .. container:: verbose
5532
5484
5533 The --pushvars option sends strings to the server that become
5485 The --pushvars option sends strings to the server that become
5534 environment variables prepended with ``HG_USERVAR_``. For example,
5486 environment variables prepended with ``HG_USERVAR_``. For example,
5535 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5487 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5536 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5488 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5537
5489
5538 pushvars can provide for user-overridable hooks as well as set debug
5490 pushvars can provide for user-overridable hooks as well as set debug
5539 levels. One example is having a hook that blocks commits containing
5491 levels. One example is having a hook that blocks commits containing
5540 conflict markers, but enables the user to override the hook if the file
5492 conflict markers, but enables the user to override the hook if the file
5541 is using conflict markers for testing purposes or the file format has
5493 is using conflict markers for testing purposes or the file format has
5542 strings that look like conflict markers.
5494 strings that look like conflict markers.
5543
5495
5544 By default, servers will ignore `--pushvars`. To enable it add the
5496 By default, servers will ignore `--pushvars`. To enable it add the
5545 following to your configuration file::
5497 following to your configuration file::
5546
5498
5547 [push]
5499 [push]
5548 pushvars.server = true
5500 pushvars.server = true
5549
5501
5550 Returns 0 if push was successful, 1 if nothing to push.
5502 Returns 0 if push was successful, 1 if nothing to push.
5551 """
5503 """
5552
5504
5553 opts = pycompat.byteskwargs(opts)
5505 opts = pycompat.byteskwargs(opts)
5554 if opts.get(b'bookmark'):
5506 if opts.get(b'bookmark'):
5555 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5507 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5556 for b in opts[b'bookmark']:
5508 for b in opts[b'bookmark']:
5557 # translate -B options to -r so changesets get pushed
5509 # translate -B options to -r so changesets get pushed
5558 b = repo._bookmarks.expandname(b)
5510 b = repo._bookmarks.expandname(b)
5559 if b in repo._bookmarks:
5511 if b in repo._bookmarks:
5560 opts.setdefault(b'rev', []).append(b)
5512 opts.setdefault(b'rev', []).append(b)
5561 else:
5513 else:
5562 # if we try to push a deleted bookmark, translate it to null
5514 # if we try to push a deleted bookmark, translate it to null
5563 # this lets simultaneous -r, -b options continue working
5515 # this lets simultaneous -r, -b options continue working
5564 opts.setdefault(b'rev', []).append(b"null")
5516 opts.setdefault(b'rev', []).append(b"null")
5565
5517
5566 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5518 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5567 if not path:
5519 if not path:
5568 raise error.Abort(
5520 raise error.Abort(
5569 _(b'default repository not configured!'),
5521 _(b'default repository not configured!'),
5570 hint=_(b"see 'hg help config.paths'"),
5522 hint=_(b"see 'hg help config.paths'"),
5571 )
5523 )
5572 dest = path.pushloc or path.loc
5524 dest = path.pushloc or path.loc
5573 branches = (path.branch, opts.get(b'branch') or [])
5525 branches = (path.branch, opts.get(b'branch') or [])
5574 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5526 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5575 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5527 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5576 other = hg.peer(repo, opts, dest)
5528 other = hg.peer(repo, opts, dest)
5577
5529
5578 if revs:
5530 if revs:
5579 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5531 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5580 if not revs:
5532 if not revs:
5581 raise error.Abort(
5533 raise error.Abort(
5582 _(b"specified revisions evaluate to an empty set"),
5534 _(b"specified revisions evaluate to an empty set"),
5583 hint=_(b"use different revision arguments"),
5535 hint=_(b"use different revision arguments"),
5584 )
5536 )
5585 elif path.pushrev:
5537 elif path.pushrev:
5586 # It doesn't make any sense to specify ancestor revisions. So limit
5538 # It doesn't make any sense to specify ancestor revisions. So limit
5587 # to DAG heads to make discovery simpler.
5539 # to DAG heads to make discovery simpler.
5588 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5540 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5589 revs = scmutil.revrange(repo, [expr])
5541 revs = scmutil.revrange(repo, [expr])
5590 revs = [repo[rev].node() for rev in revs]
5542 revs = [repo[rev].node() for rev in revs]
5591 if not revs:
5543 if not revs:
5592 raise error.Abort(
5544 raise error.Abort(
5593 _(b'default push revset for path evaluates to an empty set')
5545 _(b'default push revset for path evaluates to an empty set')
5594 )
5546 )
5595 elif ui.configbool(b'commands', b'push.require-revs'):
5547 elif ui.configbool(b'commands', b'push.require-revs'):
5596 raise error.Abort(
5548 raise error.Abort(
5597 _(b'no revisions specified to push'),
5549 _(b'no revisions specified to push'),
5598 hint=_(b'did you mean "hg push -r ."?'),
5550 hint=_(b'did you mean "hg push -r ."?'),
5599 )
5551 )
5600
5552
5601 repo._subtoppath = dest
5553 repo._subtoppath = dest
5602 try:
5554 try:
5603 # push subrepos depth-first for coherent ordering
5555 # push subrepos depth-first for coherent ordering
5604 c = repo[b'.']
5556 c = repo[b'.']
5605 subs = c.substate # only repos that are committed
5557 subs = c.substate # only repos that are committed
5606 for s in sorted(subs):
5558 for s in sorted(subs):
5607 result = c.sub(s).push(opts)
5559 result = c.sub(s).push(opts)
5608 if result == 0:
5560 if result == 0:
5609 return not result
5561 return not result
5610 finally:
5562 finally:
5611 del repo._subtoppath
5563 del repo._subtoppath
5612
5564
5613 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5565 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5614 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5566 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5615
5567
5616 pushop = exchange.push(
5568 pushop = exchange.push(
5617 repo,
5569 repo,
5618 other,
5570 other,
5619 opts.get(b'force'),
5571 opts.get(b'force'),
5620 revs=revs,
5572 revs=revs,
5621 newbranch=opts.get(b'new_branch'),
5573 newbranch=opts.get(b'new_branch'),
5622 bookmarks=opts.get(b'bookmark', ()),
5574 bookmarks=opts.get(b'bookmark', ()),
5623 publish=opts.get(b'publish'),
5575 publish=opts.get(b'publish'),
5624 opargs=opargs,
5576 opargs=opargs,
5625 )
5577 )
5626
5578
5627 result = not pushop.cgresult
5579 result = not pushop.cgresult
5628
5580
5629 if pushop.bkresult is not None:
5581 if pushop.bkresult is not None:
5630 if pushop.bkresult == 2:
5582 if pushop.bkresult == 2:
5631 result = 2
5583 result = 2
5632 elif not result and pushop.bkresult:
5584 elif not result and pushop.bkresult:
5633 result = 2
5585 result = 2
5634
5586
5635 return result
5587 return result
5636
5588
5637
5589
5638 @command(
5590 @command(
5639 b'recover',
5591 b'recover',
5640 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5592 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5641 helpcategory=command.CATEGORY_MAINTENANCE,
5593 helpcategory=command.CATEGORY_MAINTENANCE,
5642 )
5594 )
5643 def recover(ui, repo, **opts):
5595 def recover(ui, repo, **opts):
5644 """roll back an interrupted transaction
5596 """roll back an interrupted transaction
5645
5597
5646 Recover from an interrupted commit or pull.
5598 Recover from an interrupted commit or pull.
5647
5599
5648 This command tries to fix the repository status after an
5600 This command tries to fix the repository status after an
5649 interrupted operation. It should only be necessary when Mercurial
5601 interrupted operation. It should only be necessary when Mercurial
5650 suggests it.
5602 suggests it.
5651
5603
5652 Returns 0 if successful, 1 if nothing to recover or verify fails.
5604 Returns 0 if successful, 1 if nothing to recover or verify fails.
5653 """
5605 """
5654 ret = repo.recover()
5606 ret = repo.recover()
5655 if ret:
5607 if ret:
5656 if opts['verify']:
5608 if opts['verify']:
5657 return hg.verify(repo)
5609 return hg.verify(repo)
5658 else:
5610 else:
5659 msg = _(
5611 msg = _(
5660 b"(verify step skipped, run `hg verify` to check your "
5612 b"(verify step skipped, run `hg verify` to check your "
5661 b"repository content)\n"
5613 b"repository content)\n"
5662 )
5614 )
5663 ui.warn(msg)
5615 ui.warn(msg)
5664 return 0
5616 return 0
5665 return 1
5617 return 1
5666
5618
5667
5619
5668 @command(
5620 @command(
5669 b'remove|rm',
5621 b'remove|rm',
5670 [
5622 [
5671 (b'A', b'after', None, _(b'record delete for missing files')),
5623 (b'A', b'after', None, _(b'record delete for missing files')),
5672 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5624 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5673 ]
5625 ]
5674 + subrepoopts
5626 + subrepoopts
5675 + walkopts
5627 + walkopts
5676 + dryrunopts,
5628 + dryrunopts,
5677 _(b'[OPTION]... FILE...'),
5629 _(b'[OPTION]... FILE...'),
5678 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5630 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5679 helpbasic=True,
5631 helpbasic=True,
5680 inferrepo=True,
5632 inferrepo=True,
5681 )
5633 )
5682 def remove(ui, repo, *pats, **opts):
5634 def remove(ui, repo, *pats, **opts):
5683 """remove the specified files on the next commit
5635 """remove the specified files on the next commit
5684
5636
5685 Schedule the indicated files for removal from the current branch.
5637 Schedule the indicated files for removal from the current branch.
5686
5638
5687 This command schedules the files to be removed at the next commit.
5639 This command schedules the files to be removed at the next commit.
5688 To undo a remove before that, see :hg:`revert`. To undo added
5640 To undo a remove before that, see :hg:`revert`. To undo added
5689 files, see :hg:`forget`.
5641 files, see :hg:`forget`.
5690
5642
5691 .. container:: verbose
5643 .. container:: verbose
5692
5644
5693 -A/--after can be used to remove only files that have already
5645 -A/--after can be used to remove only files that have already
5694 been deleted, -f/--force can be used to force deletion, and -Af
5646 been deleted, -f/--force can be used to force deletion, and -Af
5695 can be used to remove files from the next revision without
5647 can be used to remove files from the next revision without
5696 deleting them from the working directory.
5648 deleting them from the working directory.
5697
5649
5698 The following table details the behavior of remove for different
5650 The following table details the behavior of remove for different
5699 file states (columns) and option combinations (rows). The file
5651 file states (columns) and option combinations (rows). The file
5700 states are Added [A], Clean [C], Modified [M] and Missing [!]
5652 states are Added [A], Clean [C], Modified [M] and Missing [!]
5701 (as reported by :hg:`status`). The actions are Warn, Remove
5653 (as reported by :hg:`status`). The actions are Warn, Remove
5702 (from branch) and Delete (from disk):
5654 (from branch) and Delete (from disk):
5703
5655
5704 ========= == == == ==
5656 ========= == == == ==
5705 opt/state A C M !
5657 opt/state A C M !
5706 ========= == == == ==
5658 ========= == == == ==
5707 none W RD W R
5659 none W RD W R
5708 -f R RD RD R
5660 -f R RD RD R
5709 -A W W W R
5661 -A W W W R
5710 -Af R R R R
5662 -Af R R R R
5711 ========= == == == ==
5663 ========= == == == ==
5712
5664
5713 .. note::
5665 .. note::
5714
5666
5715 :hg:`remove` never deletes files in Added [A] state from the
5667 :hg:`remove` never deletes files in Added [A] state from the
5716 working directory, not even if ``--force`` is specified.
5668 working directory, not even if ``--force`` is specified.
5717
5669
5718 Returns 0 on success, 1 if any warnings encountered.
5670 Returns 0 on success, 1 if any warnings encountered.
5719 """
5671 """
5720
5672
5721 opts = pycompat.byteskwargs(opts)
5673 opts = pycompat.byteskwargs(opts)
5722 after, force = opts.get(b'after'), opts.get(b'force')
5674 after, force = opts.get(b'after'), opts.get(b'force')
5723 dryrun = opts.get(b'dry_run')
5675 dryrun = opts.get(b'dry_run')
5724 if not pats and not after:
5676 if not pats and not after:
5725 raise error.Abort(_(b'no files specified'))
5677 raise error.Abort(_(b'no files specified'))
5726
5678
5727 m = scmutil.match(repo[None], pats, opts)
5679 m = scmutil.match(repo[None], pats, opts)
5728 subrepos = opts.get(b'subrepos')
5680 subrepos = opts.get(b'subrepos')
5729 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5681 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5730 return cmdutil.remove(
5682 return cmdutil.remove(
5731 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5683 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5732 )
5684 )
5733
5685
5734
5686
5735 @command(
5687 @command(
5736 b'rename|move|mv',
5688 b'rename|move|mv',
5737 [
5689 [
5738 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5690 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5739 (
5691 (
5740 b'',
5692 b'',
5741 b'at-rev',
5693 b'at-rev',
5742 b'',
5694 b'',
5743 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5695 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5744 _(b'REV'),
5696 _(b'REV'),
5745 ),
5697 ),
5746 (
5698 (
5747 b'f',
5699 b'f',
5748 b'force',
5700 b'force',
5749 None,
5701 None,
5750 _(b'forcibly move over an existing managed file'),
5702 _(b'forcibly move over an existing managed file'),
5751 ),
5703 ),
5752 ]
5704 ]
5753 + walkopts
5705 + walkopts
5754 + dryrunopts,
5706 + dryrunopts,
5755 _(b'[OPTION]... SOURCE... DEST'),
5707 _(b'[OPTION]... SOURCE... DEST'),
5756 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5757 )
5709 )
5758 def rename(ui, repo, *pats, **opts):
5710 def rename(ui, repo, *pats, **opts):
5759 """rename files; equivalent of copy + remove
5711 """rename files; equivalent of copy + remove
5760
5712
5761 Mark dest as copies of sources; mark sources for deletion. If dest
5713 Mark dest as copies of sources; mark sources for deletion. If dest
5762 is a directory, copies are put in that directory. If dest is a
5714 is a directory, copies are put in that directory. If dest is a
5763 file, there can only be one source.
5715 file, there can only be one source.
5764
5716
5765 By default, this command copies the contents of files as they
5717 By default, this command copies the contents of files as they
5766 exist in the working directory. If invoked with -A/--after, the
5718 exist in the working directory. If invoked with -A/--after, the
5767 operation is recorded, but no copying is performed.
5719 operation is recorded, but no copying is performed.
5768
5720
5769 This command takes effect at the next commit. To undo a rename
5721 This command takes effect at the next commit. To undo a rename
5770 before that, see :hg:`revert`.
5722 before that, see :hg:`revert`.
5771
5723
5772 Returns 0 on success, 1 if errors are encountered.
5724 Returns 0 on success, 1 if errors are encountered.
5773 """
5725 """
5774 opts = pycompat.byteskwargs(opts)
5726 opts = pycompat.byteskwargs(opts)
5775 with repo.wlock():
5727 with repo.wlock():
5776 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5728 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5777
5729
5778
5730
5779 @command(
5731 @command(
5780 b'resolve',
5732 b'resolve',
5781 [
5733 [
5782 (b'a', b'all', None, _(b'select all unresolved files')),
5734 (b'a', b'all', None, _(b'select all unresolved files')),
5783 (b'l', b'list', None, _(b'list state of files needing merge')),
5735 (b'l', b'list', None, _(b'list state of files needing merge')),
5784 (b'm', b'mark', None, _(b'mark files as resolved')),
5736 (b'm', b'mark', None, _(b'mark files as resolved')),
5785 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5737 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5786 (b'n', b'no-status', None, _(b'hide status prefix')),
5738 (b'n', b'no-status', None, _(b'hide status prefix')),
5787 (b'', b're-merge', None, _(b're-merge files')),
5739 (b'', b're-merge', None, _(b're-merge files')),
5788 ]
5740 ]
5789 + mergetoolopts
5741 + mergetoolopts
5790 + walkopts
5742 + walkopts
5791 + formatteropts,
5743 + formatteropts,
5792 _(b'[OPTION]... [FILE]...'),
5744 _(b'[OPTION]... [FILE]...'),
5793 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5745 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5794 inferrepo=True,
5746 inferrepo=True,
5795 )
5747 )
5796 def resolve(ui, repo, *pats, **opts):
5748 def resolve(ui, repo, *pats, **opts):
5797 """redo merges or set/view the merge status of files
5749 """redo merges or set/view the merge status of files
5798
5750
5799 Merges with unresolved conflicts are often the result of
5751 Merges with unresolved conflicts are often the result of
5800 non-interactive merging using the ``internal:merge`` configuration
5752 non-interactive merging using the ``internal:merge`` configuration
5801 setting, or a command-line merge tool like ``diff3``. The resolve
5753 setting, or a command-line merge tool like ``diff3``. The resolve
5802 command is used to manage the files involved in a merge, after
5754 command is used to manage the files involved in a merge, after
5803 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5755 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5804 working directory must have two parents). See :hg:`help
5756 working directory must have two parents). See :hg:`help
5805 merge-tools` for information on configuring merge tools.
5757 merge-tools` for information on configuring merge tools.
5806
5758
5807 The resolve command can be used in the following ways:
5759 The resolve command can be used in the following ways:
5808
5760
5809 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5761 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5810 the specified files, discarding any previous merge attempts. Re-merging
5762 the specified files, discarding any previous merge attempts. Re-merging
5811 is not performed for files already marked as resolved. Use ``--all/-a``
5763 is not performed for files already marked as resolved. Use ``--all/-a``
5812 to select all unresolved files. ``--tool`` can be used to specify
5764 to select all unresolved files. ``--tool`` can be used to specify
5813 the merge tool used for the given files. It overrides the HGMERGE
5765 the merge tool used for the given files. It overrides the HGMERGE
5814 environment variable and your configuration files. Previous file
5766 environment variable and your configuration files. Previous file
5815 contents are saved with a ``.orig`` suffix.
5767 contents are saved with a ``.orig`` suffix.
5816
5768
5817 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5769 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5818 (e.g. after having manually fixed-up the files). The default is
5770 (e.g. after having manually fixed-up the files). The default is
5819 to mark all unresolved files.
5771 to mark all unresolved files.
5820
5772
5821 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5773 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5822 default is to mark all resolved files.
5774 default is to mark all resolved files.
5823
5775
5824 - :hg:`resolve -l`: list files which had or still have conflicts.
5776 - :hg:`resolve -l`: list files which had or still have conflicts.
5825 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5777 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5826 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5778 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5827 the list. See :hg:`help filesets` for details.
5779 the list. See :hg:`help filesets` for details.
5828
5780
5829 .. note::
5781 .. note::
5830
5782
5831 Mercurial will not let you commit files with unresolved merge
5783 Mercurial will not let you commit files with unresolved merge
5832 conflicts. You must use :hg:`resolve -m ...` before you can
5784 conflicts. You must use :hg:`resolve -m ...` before you can
5833 commit after a conflicting merge.
5785 commit after a conflicting merge.
5834
5786
5835 .. container:: verbose
5787 .. container:: verbose
5836
5788
5837 Template:
5789 Template:
5838
5790
5839 The following keywords are supported in addition to the common template
5791 The following keywords are supported in addition to the common template
5840 keywords and functions. See also :hg:`help templates`.
5792 keywords and functions. See also :hg:`help templates`.
5841
5793
5842 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5794 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5843 :path: String. Repository-absolute path of the file.
5795 :path: String. Repository-absolute path of the file.
5844
5796
5845 Returns 0 on success, 1 if any files fail a resolve attempt.
5797 Returns 0 on success, 1 if any files fail a resolve attempt.
5846 """
5798 """
5847
5799
5848 opts = pycompat.byteskwargs(opts)
5800 opts = pycompat.byteskwargs(opts)
5849 confirm = ui.configbool(b'commands', b'resolve.confirm')
5801 confirm = ui.configbool(b'commands', b'resolve.confirm')
5850 flaglist = b'all mark unmark list no_status re_merge'.split()
5802 flaglist = b'all mark unmark list no_status re_merge'.split()
5851 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5803 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5852
5804
5853 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5805 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5854 if actioncount > 1:
5806 if actioncount > 1:
5855 raise error.Abort(_(b"too many actions specified"))
5807 raise error.Abort(_(b"too many actions specified"))
5856 elif actioncount == 0 and ui.configbool(
5808 elif actioncount == 0 and ui.configbool(
5857 b'commands', b'resolve.explicit-re-merge'
5809 b'commands', b'resolve.explicit-re-merge'
5858 ):
5810 ):
5859 hint = _(b'use --mark, --unmark, --list or --re-merge')
5811 hint = _(b'use --mark, --unmark, --list or --re-merge')
5860 raise error.Abort(_(b'no action specified'), hint=hint)
5812 raise error.Abort(_(b'no action specified'), hint=hint)
5861 if pats and all:
5813 if pats and all:
5862 raise error.Abort(_(b"can't specify --all and patterns"))
5814 raise error.Abort(_(b"can't specify --all and patterns"))
5863 if not (all or pats or show or mark or unmark):
5815 if not (all or pats or show or mark or unmark):
5864 raise error.Abort(
5816 raise error.Abort(
5865 _(b'no files or directories specified'),
5817 _(b'no files or directories specified'),
5866 hint=b'use --all to re-merge all unresolved files',
5818 hint=b'use --all to re-merge all unresolved files',
5867 )
5819 )
5868
5820
5869 if confirm:
5821 if confirm:
5870 if all:
5822 if all:
5871 if ui.promptchoice(
5823 if ui.promptchoice(
5872 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5824 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5873 ):
5825 ):
5874 raise error.Abort(_(b'user quit'))
5826 raise error.Abort(_(b'user quit'))
5875 if mark and not pats:
5827 if mark and not pats:
5876 if ui.promptchoice(
5828 if ui.promptchoice(
5877 _(
5829 _(
5878 b'mark all unresolved files as resolved (yn)?'
5830 b'mark all unresolved files as resolved (yn)?'
5879 b'$$ &Yes $$ &No'
5831 b'$$ &Yes $$ &No'
5880 )
5832 )
5881 ):
5833 ):
5882 raise error.Abort(_(b'user quit'))
5834 raise error.Abort(_(b'user quit'))
5883 if unmark and not pats:
5835 if unmark and not pats:
5884 if ui.promptchoice(
5836 if ui.promptchoice(
5885 _(
5837 _(
5886 b'mark all resolved files as unresolved (yn)?'
5838 b'mark all resolved files as unresolved (yn)?'
5887 b'$$ &Yes $$ &No'
5839 b'$$ &Yes $$ &No'
5888 )
5840 )
5889 ):
5841 ):
5890 raise error.Abort(_(b'user quit'))
5842 raise error.Abort(_(b'user quit'))
5891
5843
5892 uipathfn = scmutil.getuipathfn(repo)
5844 uipathfn = scmutil.getuipathfn(repo)
5893
5845
5894 if show:
5846 if show:
5895 ui.pager(b'resolve')
5847 ui.pager(b'resolve')
5896 fm = ui.formatter(b'resolve', opts)
5848 fm = ui.formatter(b'resolve', opts)
5897 ms = mergestatemod.mergestate.read(repo)
5849 ms = mergestatemod.mergestate.read(repo)
5898 wctx = repo[None]
5850 wctx = repo[None]
5899 m = scmutil.match(wctx, pats, opts)
5851 m = scmutil.match(wctx, pats, opts)
5900
5852
5901 # Labels and keys based on merge state. Unresolved path conflicts show
5853 # Labels and keys based on merge state. Unresolved path conflicts show
5902 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5854 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5903 # resolved conflicts.
5855 # resolved conflicts.
5904 mergestateinfo = {
5856 mergestateinfo = {
5905 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5857 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5906 b'resolve.unresolved',
5858 b'resolve.unresolved',
5907 b'U',
5859 b'U',
5908 ),
5860 ),
5909 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5861 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5910 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5862 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5911 b'resolve.unresolved',
5863 b'resolve.unresolved',
5912 b'P',
5864 b'P',
5913 ),
5865 ),
5914 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5866 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5915 b'resolve.resolved',
5867 b'resolve.resolved',
5916 b'R',
5868 b'R',
5917 ),
5869 ),
5918 }
5870 }
5919
5871
5920 for f in ms:
5872 for f in ms:
5921 if not m(f):
5873 if not m(f):
5922 continue
5874 continue
5923
5875
5924 label, key = mergestateinfo[ms[f]]
5876 label, key = mergestateinfo[ms[f]]
5925 fm.startitem()
5877 fm.startitem()
5926 fm.context(ctx=wctx)
5878 fm.context(ctx=wctx)
5927 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5879 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5928 fm.data(path=f)
5880 fm.data(path=f)
5929 fm.plain(b'%s\n' % uipathfn(f), label=label)
5881 fm.plain(b'%s\n' % uipathfn(f), label=label)
5930 fm.end()
5882 fm.end()
5931 return 0
5883 return 0
5932
5884
5933 with repo.wlock():
5885 with repo.wlock():
5934 ms = mergestatemod.mergestate.read(repo)
5886 ms = mergestatemod.mergestate.read(repo)
5935
5887
5936 if not (ms.active() or repo.dirstate.p2() != nullid):
5888 if not (ms.active() or repo.dirstate.p2() != nullid):
5937 raise error.Abort(
5889 raise error.Abort(
5938 _(b'resolve command not applicable when not merging')
5890 _(b'resolve command not applicable when not merging')
5939 )
5891 )
5940
5892
5941 wctx = repo[None]
5893 wctx = repo[None]
5942 m = scmutil.match(wctx, pats, opts)
5894 m = scmutil.match(wctx, pats, opts)
5943 ret = 0
5895 ret = 0
5944 didwork = False
5896 didwork = False
5945
5897
5946 tocomplete = []
5898 tocomplete = []
5947 hasconflictmarkers = []
5899 hasconflictmarkers = []
5948 if mark:
5900 if mark:
5949 markcheck = ui.config(b'commands', b'resolve.mark-check')
5901 markcheck = ui.config(b'commands', b'resolve.mark-check')
5950 if markcheck not in [b'warn', b'abort']:
5902 if markcheck not in [b'warn', b'abort']:
5951 # Treat all invalid / unrecognized values as 'none'.
5903 # Treat all invalid / unrecognized values as 'none'.
5952 markcheck = False
5904 markcheck = False
5953 for f in ms:
5905 for f in ms:
5954 if not m(f):
5906 if not m(f):
5955 continue
5907 continue
5956
5908
5957 didwork = True
5909 didwork = True
5958
5910
5959 # path conflicts must be resolved manually
5911 # path conflicts must be resolved manually
5960 if ms[f] in (
5912 if ms[f] in (
5961 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5913 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5962 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5914 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5963 ):
5915 ):
5964 if mark:
5916 if mark:
5965 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5917 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5966 elif unmark:
5918 elif unmark:
5967 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5919 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5968 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5920 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5969 ui.warn(
5921 ui.warn(
5970 _(b'%s: path conflict must be resolved manually\n')
5922 _(b'%s: path conflict must be resolved manually\n')
5971 % uipathfn(f)
5923 % uipathfn(f)
5972 )
5924 )
5973 continue
5925 continue
5974
5926
5975 if mark:
5927 if mark:
5976 if markcheck:
5928 if markcheck:
5977 fdata = repo.wvfs.tryread(f)
5929 fdata = repo.wvfs.tryread(f)
5978 if (
5930 if (
5979 filemerge.hasconflictmarkers(fdata)
5931 filemerge.hasconflictmarkers(fdata)
5980 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5932 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5981 ):
5933 ):
5982 hasconflictmarkers.append(f)
5934 hasconflictmarkers.append(f)
5983 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5935 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5984 elif unmark:
5936 elif unmark:
5985 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5937 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5986 else:
5938 else:
5987 # backup pre-resolve (merge uses .orig for its own purposes)
5939 # backup pre-resolve (merge uses .orig for its own purposes)
5988 a = repo.wjoin(f)
5940 a = repo.wjoin(f)
5989 try:
5941 try:
5990 util.copyfile(a, a + b".resolve")
5942 util.copyfile(a, a + b".resolve")
5991 except (IOError, OSError) as inst:
5943 except (IOError, OSError) as inst:
5992 if inst.errno != errno.ENOENT:
5944 if inst.errno != errno.ENOENT:
5993 raise
5945 raise
5994
5946
5995 try:
5947 try:
5996 # preresolve file
5948 # preresolve file
5997 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5949 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5998 with ui.configoverride(overrides, b'resolve'):
5950 with ui.configoverride(overrides, b'resolve'):
5999 complete, r = ms.preresolve(f, wctx)
5951 complete, r = ms.preresolve(f, wctx)
6000 if not complete:
5952 if not complete:
6001 tocomplete.append(f)
5953 tocomplete.append(f)
6002 elif r:
5954 elif r:
6003 ret = 1
5955 ret = 1
6004 finally:
5956 finally:
6005 ms.commit()
5957 ms.commit()
6006
5958
6007 # replace filemerge's .orig file with our resolve file, but only
5959 # replace filemerge's .orig file with our resolve file, but only
6008 # for merges that are complete
5960 # for merges that are complete
6009 if complete:
5961 if complete:
6010 try:
5962 try:
6011 util.rename(
5963 util.rename(
6012 a + b".resolve", scmutil.backuppath(ui, repo, f)
5964 a + b".resolve", scmutil.backuppath(ui, repo, f)
6013 )
5965 )
6014 except OSError as inst:
5966 except OSError as inst:
6015 if inst.errno != errno.ENOENT:
5967 if inst.errno != errno.ENOENT:
6016 raise
5968 raise
6017
5969
6018 if hasconflictmarkers:
5970 if hasconflictmarkers:
6019 ui.warn(
5971 ui.warn(
6020 _(
5972 _(
6021 b'warning: the following files still have conflict '
5973 b'warning: the following files still have conflict '
6022 b'markers:\n'
5974 b'markers:\n'
6023 )
5975 )
6024 + b''.join(
5976 + b''.join(
6025 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5977 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6026 )
5978 )
6027 )
5979 )
6028 if markcheck == b'abort' and not all and not pats:
5980 if markcheck == b'abort' and not all and not pats:
6029 raise error.Abort(
5981 raise error.Abort(
6030 _(b'conflict markers detected'),
5982 _(b'conflict markers detected'),
6031 hint=_(b'use --all to mark anyway'),
5983 hint=_(b'use --all to mark anyway'),
6032 )
5984 )
6033
5985
6034 for f in tocomplete:
5986 for f in tocomplete:
6035 try:
5987 try:
6036 # resolve file
5988 # resolve file
6037 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5989 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6038 with ui.configoverride(overrides, b'resolve'):
5990 with ui.configoverride(overrides, b'resolve'):
6039 r = ms.resolve(f, wctx)
5991 r = ms.resolve(f, wctx)
6040 if r:
5992 if r:
6041 ret = 1
5993 ret = 1
6042 finally:
5994 finally:
6043 ms.commit()
5995 ms.commit()
6044
5996
6045 # replace filemerge's .orig file with our resolve file
5997 # replace filemerge's .orig file with our resolve file
6046 a = repo.wjoin(f)
5998 a = repo.wjoin(f)
6047 try:
5999 try:
6048 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6000 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6049 except OSError as inst:
6001 except OSError as inst:
6050 if inst.errno != errno.ENOENT:
6002 if inst.errno != errno.ENOENT:
6051 raise
6003 raise
6052
6004
6053 ms.commit()
6005 ms.commit()
6054 branchmerge = repo.dirstate.p2() != nullid
6006 branchmerge = repo.dirstate.p2() != nullid
6055 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6007 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6056
6008
6057 if not didwork and pats:
6009 if not didwork and pats:
6058 hint = None
6010 hint = None
6059 if not any([p for p in pats if p.find(b':') >= 0]):
6011 if not any([p for p in pats if p.find(b':') >= 0]):
6060 pats = [b'path:%s' % p for p in pats]
6012 pats = [b'path:%s' % p for p in pats]
6061 m = scmutil.match(wctx, pats, opts)
6013 m = scmutil.match(wctx, pats, opts)
6062 for f in ms:
6014 for f in ms:
6063 if not m(f):
6015 if not m(f):
6064 continue
6016 continue
6065
6017
6066 def flag(o):
6018 def flag(o):
6067 if o == b're_merge':
6019 if o == b're_merge':
6068 return b'--re-merge '
6020 return b'--re-merge '
6069 return b'-%s ' % o[0:1]
6021 return b'-%s ' % o[0:1]
6070
6022
6071 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6023 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6072 hint = _(b"(try: hg resolve %s%s)\n") % (
6024 hint = _(b"(try: hg resolve %s%s)\n") % (
6073 flags,
6025 flags,
6074 b' '.join(pats),
6026 b' '.join(pats),
6075 )
6027 )
6076 break
6028 break
6077 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6029 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6078 if hint:
6030 if hint:
6079 ui.warn(hint)
6031 ui.warn(hint)
6080
6032
6081 unresolvedf = list(ms.unresolved())
6033 unresolvedf = list(ms.unresolved())
6082 if not unresolvedf:
6034 if not unresolvedf:
6083 ui.status(_(b'(no more unresolved files)\n'))
6035 ui.status(_(b'(no more unresolved files)\n'))
6084 cmdutil.checkafterresolved(repo)
6036 cmdutil.checkafterresolved(repo)
6085
6037
6086 return ret
6038 return ret
6087
6039
6088
6040
6089 @command(
6041 @command(
6090 b'revert',
6042 b'revert',
6091 [
6043 [
6092 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6044 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6093 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6045 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6094 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6046 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6095 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6047 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6096 (b'i', b'interactive', None, _(b'interactively select the changes')),
6048 (b'i', b'interactive', None, _(b'interactively select the changes')),
6097 ]
6049 ]
6098 + walkopts
6050 + walkopts
6099 + dryrunopts,
6051 + dryrunopts,
6100 _(b'[OPTION]... [-r REV] [NAME]...'),
6052 _(b'[OPTION]... [-r REV] [NAME]...'),
6101 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6053 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6102 )
6054 )
6103 def revert(ui, repo, *pats, **opts):
6055 def revert(ui, repo, *pats, **opts):
6104 """restore files to their checkout state
6056 """restore files to their checkout state
6105
6057
6106 .. note::
6058 .. note::
6107
6059
6108 To check out earlier revisions, you should use :hg:`update REV`.
6060 To check out earlier revisions, you should use :hg:`update REV`.
6109 To cancel an uncommitted merge (and lose your changes),
6061 To cancel an uncommitted merge (and lose your changes),
6110 use :hg:`merge --abort`.
6062 use :hg:`merge --abort`.
6111
6063
6112 With no revision specified, revert the specified files or directories
6064 With no revision specified, revert the specified files or directories
6113 to the contents they had in the parent of the working directory.
6065 to the contents they had in the parent of the working directory.
6114 This restores the contents of files to an unmodified
6066 This restores the contents of files to an unmodified
6115 state and unschedules adds, removes, copies, and renames. If the
6067 state and unschedules adds, removes, copies, and renames. If the
6116 working directory has two parents, you must explicitly specify a
6068 working directory has two parents, you must explicitly specify a
6117 revision.
6069 revision.
6118
6070
6119 Using the -r/--rev or -d/--date options, revert the given files or
6071 Using the -r/--rev or -d/--date options, revert the given files or
6120 directories to their states as of a specific revision. Because
6072 directories to their states as of a specific revision. Because
6121 revert does not change the working directory parents, this will
6073 revert does not change the working directory parents, this will
6122 cause these files to appear modified. This can be helpful to "back
6074 cause these files to appear modified. This can be helpful to "back
6123 out" some or all of an earlier change. See :hg:`backout` for a
6075 out" some or all of an earlier change. See :hg:`backout` for a
6124 related method.
6076 related method.
6125
6077
6126 Modified files are saved with a .orig suffix before reverting.
6078 Modified files are saved with a .orig suffix before reverting.
6127 To disable these backups, use --no-backup. It is possible to store
6079 To disable these backups, use --no-backup. It is possible to store
6128 the backup files in a custom directory relative to the root of the
6080 the backup files in a custom directory relative to the root of the
6129 repository by setting the ``ui.origbackuppath`` configuration
6081 repository by setting the ``ui.origbackuppath`` configuration
6130 option.
6082 option.
6131
6083
6132 See :hg:`help dates` for a list of formats valid for -d/--date.
6084 See :hg:`help dates` for a list of formats valid for -d/--date.
6133
6085
6134 See :hg:`help backout` for a way to reverse the effect of an
6086 See :hg:`help backout` for a way to reverse the effect of an
6135 earlier changeset.
6087 earlier changeset.
6136
6088
6137 Returns 0 on success.
6089 Returns 0 on success.
6138 """
6090 """
6139
6091
6140 opts = pycompat.byteskwargs(opts)
6092 opts = pycompat.byteskwargs(opts)
6141 if opts.get(b"date"):
6093 if opts.get(b"date"):
6142 if opts.get(b"rev"):
6094 if opts.get(b"rev"):
6143 raise error.Abort(_(b"you can't specify a revision and a date"))
6095 raise error.Abort(_(b"you can't specify a revision and a date"))
6144 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6096 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6145
6097
6146 parent, p2 = repo.dirstate.parents()
6098 parent, p2 = repo.dirstate.parents()
6147 if not opts.get(b'rev') and p2 != nullid:
6099 if not opts.get(b'rev') and p2 != nullid:
6148 # revert after merge is a trap for new users (issue2915)
6100 # revert after merge is a trap for new users (issue2915)
6149 raise error.Abort(
6101 raise error.Abort(
6150 _(b'uncommitted merge with no revision specified'),
6102 _(b'uncommitted merge with no revision specified'),
6151 hint=_(b"use 'hg update' or see 'hg help revert'"),
6103 hint=_(b"use 'hg update' or see 'hg help revert'"),
6152 )
6104 )
6153
6105
6154 rev = opts.get(b'rev')
6106 rev = opts.get(b'rev')
6155 if rev:
6107 if rev:
6156 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6108 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6157 ctx = scmutil.revsingle(repo, rev)
6109 ctx = scmutil.revsingle(repo, rev)
6158
6110
6159 if not (
6111 if not (
6160 pats
6112 pats
6161 or opts.get(b'include')
6113 or opts.get(b'include')
6162 or opts.get(b'exclude')
6114 or opts.get(b'exclude')
6163 or opts.get(b'all')
6115 or opts.get(b'all')
6164 or opts.get(b'interactive')
6116 or opts.get(b'interactive')
6165 ):
6117 ):
6166 msg = _(b"no files or directories specified")
6118 msg = _(b"no files or directories specified")
6167 if p2 != nullid:
6119 if p2 != nullid:
6168 hint = _(
6120 hint = _(
6169 b"uncommitted merge, use --all to discard all changes,"
6121 b"uncommitted merge, use --all to discard all changes,"
6170 b" or 'hg update -C .' to abort the merge"
6122 b" or 'hg update -C .' to abort the merge"
6171 )
6123 )
6172 raise error.Abort(msg, hint=hint)
6124 raise error.Abort(msg, hint=hint)
6173 dirty = any(repo.status())
6125 dirty = any(repo.status())
6174 node = ctx.node()
6126 node = ctx.node()
6175 if node != parent:
6127 if node != parent:
6176 if dirty:
6128 if dirty:
6177 hint = (
6129 hint = (
6178 _(
6130 _(
6179 b"uncommitted changes, use --all to discard all"
6131 b"uncommitted changes, use --all to discard all"
6180 b" changes, or 'hg update %d' to update"
6132 b" changes, or 'hg update %d' to update"
6181 )
6133 )
6182 % ctx.rev()
6134 % ctx.rev()
6183 )
6135 )
6184 else:
6136 else:
6185 hint = (
6137 hint = (
6186 _(
6138 _(
6187 b"use --all to revert all files,"
6139 b"use --all to revert all files,"
6188 b" or 'hg update %d' to update"
6140 b" or 'hg update %d' to update"
6189 )
6141 )
6190 % ctx.rev()
6142 % ctx.rev()
6191 )
6143 )
6192 elif dirty:
6144 elif dirty:
6193 hint = _(b"uncommitted changes, use --all to discard all changes")
6145 hint = _(b"uncommitted changes, use --all to discard all changes")
6194 else:
6146 else:
6195 hint = _(b"use --all to revert all files")
6147 hint = _(b"use --all to revert all files")
6196 raise error.Abort(msg, hint=hint)
6148 raise error.Abort(msg, hint=hint)
6197
6149
6198 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6150 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6199
6151
6200
6152
6201 @command(
6153 @command(
6202 b'rollback',
6154 b'rollback',
6203 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6155 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6204 helpcategory=command.CATEGORY_MAINTENANCE,
6156 helpcategory=command.CATEGORY_MAINTENANCE,
6205 )
6157 )
6206 def rollback(ui, repo, **opts):
6158 def rollback(ui, repo, **opts):
6207 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6159 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6208
6160
6209 Please use :hg:`commit --amend` instead of rollback to correct
6161 Please use :hg:`commit --amend` instead of rollback to correct
6210 mistakes in the last commit.
6162 mistakes in the last commit.
6211
6163
6212 This command should be used with care. There is only one level of
6164 This command should be used with care. There is only one level of
6213 rollback, and there is no way to undo a rollback. It will also
6165 rollback, and there is no way to undo a rollback. It will also
6214 restore the dirstate at the time of the last transaction, losing
6166 restore the dirstate at the time of the last transaction, losing
6215 any dirstate changes since that time. This command does not alter
6167 any dirstate changes since that time. This command does not alter
6216 the working directory.
6168 the working directory.
6217
6169
6218 Transactions are used to encapsulate the effects of all commands
6170 Transactions are used to encapsulate the effects of all commands
6219 that create new changesets or propagate existing changesets into a
6171 that create new changesets or propagate existing changesets into a
6220 repository.
6172 repository.
6221
6173
6222 .. container:: verbose
6174 .. container:: verbose
6223
6175
6224 For example, the following commands are transactional, and their
6176 For example, the following commands are transactional, and their
6225 effects can be rolled back:
6177 effects can be rolled back:
6226
6178
6227 - commit
6179 - commit
6228 - import
6180 - import
6229 - pull
6181 - pull
6230 - push (with this repository as the destination)
6182 - push (with this repository as the destination)
6231 - unbundle
6183 - unbundle
6232
6184
6233 To avoid permanent data loss, rollback will refuse to rollback a
6185 To avoid permanent data loss, rollback will refuse to rollback a
6234 commit transaction if it isn't checked out. Use --force to
6186 commit transaction if it isn't checked out. Use --force to
6235 override this protection.
6187 override this protection.
6236
6188
6237 The rollback command can be entirely disabled by setting the
6189 The rollback command can be entirely disabled by setting the
6238 ``ui.rollback`` configuration setting to false. If you're here
6190 ``ui.rollback`` configuration setting to false. If you're here
6239 because you want to use rollback and it's disabled, you can
6191 because you want to use rollback and it's disabled, you can
6240 re-enable the command by setting ``ui.rollback`` to true.
6192 re-enable the command by setting ``ui.rollback`` to true.
6241
6193
6242 This command is not intended for use on public repositories. Once
6194 This command is not intended for use on public repositories. Once
6243 changes are visible for pull by other users, rolling a transaction
6195 changes are visible for pull by other users, rolling a transaction
6244 back locally is ineffective (someone else may already have pulled
6196 back locally is ineffective (someone else may already have pulled
6245 the changes). Furthermore, a race is possible with readers of the
6197 the changes). Furthermore, a race is possible with readers of the
6246 repository; for example an in-progress pull from the repository
6198 repository; for example an in-progress pull from the repository
6247 may fail if a rollback is performed.
6199 may fail if a rollback is performed.
6248
6200
6249 Returns 0 on success, 1 if no rollback data is available.
6201 Returns 0 on success, 1 if no rollback data is available.
6250 """
6202 """
6251 if not ui.configbool(b'ui', b'rollback'):
6203 if not ui.configbool(b'ui', b'rollback'):
6252 raise error.Abort(
6204 raise error.Abort(
6253 _(b'rollback is disabled because it is unsafe'),
6205 _(b'rollback is disabled because it is unsafe'),
6254 hint=b'see `hg help -v rollback` for information',
6206 hint=b'see `hg help -v rollback` for information',
6255 )
6207 )
6256 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6208 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6257
6209
6258
6210
6259 @command(
6211 @command(
6260 b'root',
6212 b'root',
6261 [] + formatteropts,
6213 [] + formatteropts,
6262 intents={INTENT_READONLY},
6214 intents={INTENT_READONLY},
6263 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6215 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6264 )
6216 )
6265 def root(ui, repo, **opts):
6217 def root(ui, repo, **opts):
6266 """print the root (top) of the current working directory
6218 """print the root (top) of the current working directory
6267
6219
6268 Print the root directory of the current repository.
6220 Print the root directory of the current repository.
6269
6221
6270 .. container:: verbose
6222 .. container:: verbose
6271
6223
6272 Template:
6224 Template:
6273
6225
6274 The following keywords are supported in addition to the common template
6226 The following keywords are supported in addition to the common template
6275 keywords and functions. See also :hg:`help templates`.
6227 keywords and functions. See also :hg:`help templates`.
6276
6228
6277 :hgpath: String. Path to the .hg directory.
6229 :hgpath: String. Path to the .hg directory.
6278 :storepath: String. Path to the directory holding versioned data.
6230 :storepath: String. Path to the directory holding versioned data.
6279
6231
6280 Returns 0 on success.
6232 Returns 0 on success.
6281 """
6233 """
6282 opts = pycompat.byteskwargs(opts)
6234 opts = pycompat.byteskwargs(opts)
6283 with ui.formatter(b'root', opts) as fm:
6235 with ui.formatter(b'root', opts) as fm:
6284 fm.startitem()
6236 fm.startitem()
6285 fm.write(b'reporoot', b'%s\n', repo.root)
6237 fm.write(b'reporoot', b'%s\n', repo.root)
6286 fm.data(hgpath=repo.path, storepath=repo.spath)
6238 fm.data(hgpath=repo.path, storepath=repo.spath)
6287
6239
6288
6240
6289 @command(
6241 @command(
6290 b'serve',
6242 b'serve',
6291 [
6243 [
6292 (
6244 (
6293 b'A',
6245 b'A',
6294 b'accesslog',
6246 b'accesslog',
6295 b'',
6247 b'',
6296 _(b'name of access log file to write to'),
6248 _(b'name of access log file to write to'),
6297 _(b'FILE'),
6249 _(b'FILE'),
6298 ),
6250 ),
6299 (b'd', b'daemon', None, _(b'run server in background')),
6251 (b'd', b'daemon', None, _(b'run server in background')),
6300 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6252 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6301 (
6253 (
6302 b'E',
6254 b'E',
6303 b'errorlog',
6255 b'errorlog',
6304 b'',
6256 b'',
6305 _(b'name of error log file to write to'),
6257 _(b'name of error log file to write to'),
6306 _(b'FILE'),
6258 _(b'FILE'),
6307 ),
6259 ),
6308 # use string type, then we can check if something was passed
6260 # use string type, then we can check if something was passed
6309 (
6261 (
6310 b'p',
6262 b'p',
6311 b'port',
6263 b'port',
6312 b'',
6264 b'',
6313 _(b'port to listen on (default: 8000)'),
6265 _(b'port to listen on (default: 8000)'),
6314 _(b'PORT'),
6266 _(b'PORT'),
6315 ),
6267 ),
6316 (
6268 (
6317 b'a',
6269 b'a',
6318 b'address',
6270 b'address',
6319 b'',
6271 b'',
6320 _(b'address to listen on (default: all interfaces)'),
6272 _(b'address to listen on (default: all interfaces)'),
6321 _(b'ADDR'),
6273 _(b'ADDR'),
6322 ),
6274 ),
6323 (
6275 (
6324 b'',
6276 b'',
6325 b'prefix',
6277 b'prefix',
6326 b'',
6278 b'',
6327 _(b'prefix path to serve from (default: server root)'),
6279 _(b'prefix path to serve from (default: server root)'),
6328 _(b'PREFIX'),
6280 _(b'PREFIX'),
6329 ),
6281 ),
6330 (
6282 (
6331 b'n',
6283 b'n',
6332 b'name',
6284 b'name',
6333 b'',
6285 b'',
6334 _(b'name to show in web pages (default: working directory)'),
6286 _(b'name to show in web pages (default: working directory)'),
6335 _(b'NAME'),
6287 _(b'NAME'),
6336 ),
6288 ),
6337 (
6289 (
6338 b'',
6290 b'',
6339 b'web-conf',
6291 b'web-conf',
6340 b'',
6292 b'',
6341 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6293 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6342 _(b'FILE'),
6294 _(b'FILE'),
6343 ),
6295 ),
6344 (
6296 (
6345 b'',
6297 b'',
6346 b'webdir-conf',
6298 b'webdir-conf',
6347 b'',
6299 b'',
6348 _(b'name of the hgweb config file (DEPRECATED)'),
6300 _(b'name of the hgweb config file (DEPRECATED)'),
6349 _(b'FILE'),
6301 _(b'FILE'),
6350 ),
6302 ),
6351 (
6303 (
6352 b'',
6304 b'',
6353 b'pid-file',
6305 b'pid-file',
6354 b'',
6306 b'',
6355 _(b'name of file to write process ID to'),
6307 _(b'name of file to write process ID to'),
6356 _(b'FILE'),
6308 _(b'FILE'),
6357 ),
6309 ),
6358 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6310 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6359 (
6311 (
6360 b'',
6312 b'',
6361 b'cmdserver',
6313 b'cmdserver',
6362 b'',
6314 b'',
6363 _(b'for remote clients (ADVANCED)'),
6315 _(b'for remote clients (ADVANCED)'),
6364 _(b'MODE'),
6316 _(b'MODE'),
6365 ),
6317 ),
6366 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6318 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6367 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6319 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6368 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6320 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6369 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6321 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6370 (b'', b'print-url', None, _(b'start and print only the URL')),
6322 (b'', b'print-url', None, _(b'start and print only the URL')),
6371 ]
6323 ]
6372 + subrepoopts,
6324 + subrepoopts,
6373 _(b'[OPTION]...'),
6325 _(b'[OPTION]...'),
6374 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6326 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6375 helpbasic=True,
6327 helpbasic=True,
6376 optionalrepo=True,
6328 optionalrepo=True,
6377 )
6329 )
6378 def serve(ui, repo, **opts):
6330 def serve(ui, repo, **opts):
6379 """start stand-alone webserver
6331 """start stand-alone webserver
6380
6332
6381 Start a local HTTP repository browser and pull server. You can use
6333 Start a local HTTP repository browser and pull server. You can use
6382 this for ad-hoc sharing and browsing of repositories. It is
6334 this for ad-hoc sharing and browsing of repositories. It is
6383 recommended to use a real web server to serve a repository for
6335 recommended to use a real web server to serve a repository for
6384 longer periods of time.
6336 longer periods of time.
6385
6337
6386 Please note that the server does not implement access control.
6338 Please note that the server does not implement access control.
6387 This means that, by default, anybody can read from the server and
6339 This means that, by default, anybody can read from the server and
6388 nobody can write to it by default. Set the ``web.allow-push``
6340 nobody can write to it by default. Set the ``web.allow-push``
6389 option to ``*`` to allow everybody to push to the server. You
6341 option to ``*`` to allow everybody to push to the server. You
6390 should use a real web server if you need to authenticate users.
6342 should use a real web server if you need to authenticate users.
6391
6343
6392 By default, the server logs accesses to stdout and errors to
6344 By default, the server logs accesses to stdout and errors to
6393 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6345 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6394 files.
6346 files.
6395
6347
6396 To have the server choose a free port number to listen on, specify
6348 To have the server choose a free port number to listen on, specify
6397 a port number of 0; in this case, the server will print the port
6349 a port number of 0; in this case, the server will print the port
6398 number it uses.
6350 number it uses.
6399
6351
6400 Returns 0 on success.
6352 Returns 0 on success.
6401 """
6353 """
6402
6354
6403 opts = pycompat.byteskwargs(opts)
6355 opts = pycompat.byteskwargs(opts)
6404 if opts[b"stdio"] and opts[b"cmdserver"]:
6356 if opts[b"stdio"] and opts[b"cmdserver"]:
6405 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6357 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6406 if opts[b"print_url"] and ui.verbose:
6358 if opts[b"print_url"] and ui.verbose:
6407 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6359 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6408
6360
6409 if opts[b"stdio"]:
6361 if opts[b"stdio"]:
6410 if repo is None:
6362 if repo is None:
6411 raise error.RepoError(
6363 raise error.RepoError(
6412 _(b"there is no Mercurial repository here (.hg not found)")
6364 _(b"there is no Mercurial repository here (.hg not found)")
6413 )
6365 )
6414 s = wireprotoserver.sshserver(ui, repo)
6366 s = wireprotoserver.sshserver(ui, repo)
6415 s.serve_forever()
6367 s.serve_forever()
6416
6368
6417 service = server.createservice(ui, repo, opts)
6369 service = server.createservice(ui, repo, opts)
6418 return server.runservice(opts, initfn=service.init, runfn=service.run)
6370 return server.runservice(opts, initfn=service.init, runfn=service.run)
6419
6371
6420
6372
6421 @command(
6373 @command(
6422 b'shelve',
6374 b'shelve',
6423 [
6375 [
6424 (
6376 (
6425 b'A',
6377 b'A',
6426 b'addremove',
6378 b'addremove',
6427 None,
6379 None,
6428 _(b'mark new/missing files as added/removed before shelving'),
6380 _(b'mark new/missing files as added/removed before shelving'),
6429 ),
6381 ),
6430 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6382 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6431 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6383 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6432 (
6384 (
6433 b'',
6385 b'',
6434 b'date',
6386 b'date',
6435 b'',
6387 b'',
6436 _(b'shelve with the specified commit date'),
6388 _(b'shelve with the specified commit date'),
6437 _(b'DATE'),
6389 _(b'DATE'),
6438 ),
6390 ),
6439 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6391 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6440 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6392 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6441 (
6393 (
6442 b'k',
6394 b'k',
6443 b'keep',
6395 b'keep',
6444 False,
6396 False,
6445 _(b'shelve, but keep changes in the working directory'),
6397 _(b'shelve, but keep changes in the working directory'),
6446 ),
6398 ),
6447 (b'l', b'list', None, _(b'list current shelves')),
6399 (b'l', b'list', None, _(b'list current shelves')),
6448 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6400 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6449 (
6401 (
6450 b'n',
6402 b'n',
6451 b'name',
6403 b'name',
6452 b'',
6404 b'',
6453 _(b'use the given name for the shelved commit'),
6405 _(b'use the given name for the shelved commit'),
6454 _(b'NAME'),
6406 _(b'NAME'),
6455 ),
6407 ),
6456 (
6408 (
6457 b'p',
6409 b'p',
6458 b'patch',
6410 b'patch',
6459 None,
6411 None,
6460 _(
6412 _(
6461 b'output patches for changes (provide the names of the shelved '
6413 b'output patches for changes (provide the names of the shelved '
6462 b'changes as positional arguments)'
6414 b'changes as positional arguments)'
6463 ),
6415 ),
6464 ),
6416 ),
6465 (b'i', b'interactive', None, _(b'interactive mode')),
6417 (b'i', b'interactive', None, _(b'interactive mode')),
6466 (
6418 (
6467 b'',
6419 b'',
6468 b'stat',
6420 b'stat',
6469 None,
6421 None,
6470 _(
6422 _(
6471 b'output diffstat-style summary of changes (provide the names of '
6423 b'output diffstat-style summary of changes (provide the names of '
6472 b'the shelved changes as positional arguments)'
6424 b'the shelved changes as positional arguments)'
6473 ),
6425 ),
6474 ),
6426 ),
6475 ]
6427 ]
6476 + cmdutil.walkopts,
6428 + cmdutil.walkopts,
6477 _(b'hg shelve [OPTION]... [FILE]...'),
6429 _(b'hg shelve [OPTION]... [FILE]...'),
6478 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6430 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6479 )
6431 )
6480 def shelve(ui, repo, *pats, **opts):
6432 def shelve(ui, repo, *pats, **opts):
6481 '''save and set aside changes from the working directory
6433 '''save and set aside changes from the working directory
6482
6434
6483 Shelving takes files that "hg status" reports as not clean, saves
6435 Shelving takes files that "hg status" reports as not clean, saves
6484 the modifications to a bundle (a shelved change), and reverts the
6436 the modifications to a bundle (a shelved change), and reverts the
6485 files so that their state in the working directory becomes clean.
6437 files so that their state in the working directory becomes clean.
6486
6438
6487 To restore these changes to the working directory, using "hg
6439 To restore these changes to the working directory, using "hg
6488 unshelve"; this will work even if you switch to a different
6440 unshelve"; this will work even if you switch to a different
6489 commit.
6441 commit.
6490
6442
6491 When no files are specified, "hg shelve" saves all not-clean
6443 When no files are specified, "hg shelve" saves all not-clean
6492 files. If specific files or directories are named, only changes to
6444 files. If specific files or directories are named, only changes to
6493 those files are shelved.
6445 those files are shelved.
6494
6446
6495 In bare shelve (when no files are specified, without interactive,
6447 In bare shelve (when no files are specified, without interactive,
6496 include and exclude option), shelving remembers information if the
6448 include and exclude option), shelving remembers information if the
6497 working directory was on newly created branch, in other words working
6449 working directory was on newly created branch, in other words working
6498 directory was on different branch than its first parent. In this
6450 directory was on different branch than its first parent. In this
6499 situation unshelving restores branch information to the working directory.
6451 situation unshelving restores branch information to the working directory.
6500
6452
6501 Each shelved change has a name that makes it easier to find later.
6453 Each shelved change has a name that makes it easier to find later.
6502 The name of a shelved change defaults to being based on the active
6454 The name of a shelved change defaults to being based on the active
6503 bookmark, or if there is no active bookmark, the current named
6455 bookmark, or if there is no active bookmark, the current named
6504 branch. To specify a different name, use ``--name``.
6456 branch. To specify a different name, use ``--name``.
6505
6457
6506 To see a list of existing shelved changes, use the ``--list``
6458 To see a list of existing shelved changes, use the ``--list``
6507 option. For each shelved change, this will print its name, age,
6459 option. For each shelved change, this will print its name, age,
6508 and description; use ``--patch`` or ``--stat`` for more details.
6460 and description; use ``--patch`` or ``--stat`` for more details.
6509
6461
6510 To delete specific shelved changes, use ``--delete``. To delete
6462 To delete specific shelved changes, use ``--delete``. To delete
6511 all shelved changes, use ``--cleanup``.
6463 all shelved changes, use ``--cleanup``.
6512 '''
6464 '''
6513 opts = pycompat.byteskwargs(opts)
6465 opts = pycompat.byteskwargs(opts)
6514 allowables = [
6466 allowables = [
6515 (b'addremove', {b'create'}), # 'create' is pseudo action
6467 (b'addremove', {b'create'}), # 'create' is pseudo action
6516 (b'unknown', {b'create'}),
6468 (b'unknown', {b'create'}),
6517 (b'cleanup', {b'cleanup'}),
6469 (b'cleanup', {b'cleanup'}),
6518 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6470 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6519 (b'delete', {b'delete'}),
6471 (b'delete', {b'delete'}),
6520 (b'edit', {b'create'}),
6472 (b'edit', {b'create'}),
6521 (b'keep', {b'create'}),
6473 (b'keep', {b'create'}),
6522 (b'list', {b'list'}),
6474 (b'list', {b'list'}),
6523 (b'message', {b'create'}),
6475 (b'message', {b'create'}),
6524 (b'name', {b'create'}),
6476 (b'name', {b'create'}),
6525 (b'patch', {b'patch', b'list'}),
6477 (b'patch', {b'patch', b'list'}),
6526 (b'stat', {b'stat', b'list'}),
6478 (b'stat', {b'stat', b'list'}),
6527 ]
6479 ]
6528
6480
6529 def checkopt(opt):
6481 def checkopt(opt):
6530 if opts.get(opt):
6482 if opts.get(opt):
6531 for i, allowable in allowables:
6483 for i, allowable in allowables:
6532 if opts[i] and opt not in allowable:
6484 if opts[i] and opt not in allowable:
6533 raise error.Abort(
6485 raise error.Abort(
6534 _(
6486 _(
6535 b"options '--%s' and '--%s' may not be "
6487 b"options '--%s' and '--%s' may not be "
6536 b"used together"
6488 b"used together"
6537 )
6489 )
6538 % (opt, i)
6490 % (opt, i)
6539 )
6491 )
6540 return True
6492 return True
6541
6493
6542 if checkopt(b'cleanup'):
6494 if checkopt(b'cleanup'):
6543 if pats:
6495 if pats:
6544 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6496 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6545 return shelvemod.cleanupcmd(ui, repo)
6497 return shelvemod.cleanupcmd(ui, repo)
6546 elif checkopt(b'delete'):
6498 elif checkopt(b'delete'):
6547 return shelvemod.deletecmd(ui, repo, pats)
6499 return shelvemod.deletecmd(ui, repo, pats)
6548 elif checkopt(b'list'):
6500 elif checkopt(b'list'):
6549 return shelvemod.listcmd(ui, repo, pats, opts)
6501 return shelvemod.listcmd(ui, repo, pats, opts)
6550 elif checkopt(b'patch') or checkopt(b'stat'):
6502 elif checkopt(b'patch') or checkopt(b'stat'):
6551 return shelvemod.patchcmds(ui, repo, pats, opts)
6503 return shelvemod.patchcmds(ui, repo, pats, opts)
6552 else:
6504 else:
6553 return shelvemod.createcmd(ui, repo, pats, opts)
6505 return shelvemod.createcmd(ui, repo, pats, opts)
6554
6506
6555
6507
6556 _NOTTERSE = b'nothing'
6508 _NOTTERSE = b'nothing'
6557
6509
6558
6510
6559 @command(
6511 @command(
6560 b'status|st',
6512 b'status|st',
6561 [
6513 [
6562 (b'A', b'all', None, _(b'show status of all files')),
6514 (b'A', b'all', None, _(b'show status of all files')),
6563 (b'm', b'modified', None, _(b'show only modified files')),
6515 (b'm', b'modified', None, _(b'show only modified files')),
6564 (b'a', b'added', None, _(b'show only added files')),
6516 (b'a', b'added', None, _(b'show only added files')),
6565 (b'r', b'removed', None, _(b'show only removed files')),
6517 (b'r', b'removed', None, _(b'show only removed files')),
6566 (b'd', b'deleted', None, _(b'show only missing files')),
6518 (b'd', b'deleted', None, _(b'show only missing files')),
6567 (b'c', b'clean', None, _(b'show only files without changes')),
6519 (b'c', b'clean', None, _(b'show only files without changes')),
6568 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6520 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6569 (b'i', b'ignored', None, _(b'show only ignored files')),
6521 (b'i', b'ignored', None, _(b'show only ignored files')),
6570 (b'n', b'no-status', None, _(b'hide status prefix')),
6522 (b'n', b'no-status', None, _(b'hide status prefix')),
6571 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6523 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6572 (
6524 (
6573 b'C',
6525 b'C',
6574 b'copies',
6526 b'copies',
6575 None,
6527 None,
6576 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6528 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6577 ),
6529 ),
6578 (
6530 (
6579 b'0',
6531 b'0',
6580 b'print0',
6532 b'print0',
6581 None,
6533 None,
6582 _(b'end filenames with NUL, for use with xargs'),
6534 _(b'end filenames with NUL, for use with xargs'),
6583 ),
6535 ),
6584 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6536 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6585 (
6537 (
6586 b'',
6538 b'',
6587 b'change',
6539 b'change',
6588 b'',
6540 b'',
6589 _(b'list the changed files of a revision'),
6541 _(b'list the changed files of a revision'),
6590 _(b'REV'),
6542 _(b'REV'),
6591 ),
6543 ),
6592 ]
6544 ]
6593 + walkopts
6545 + walkopts
6594 + subrepoopts
6546 + subrepoopts
6595 + formatteropts,
6547 + formatteropts,
6596 _(b'[OPTION]... [FILE]...'),
6548 _(b'[OPTION]... [FILE]...'),
6597 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6549 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6598 helpbasic=True,
6550 helpbasic=True,
6599 inferrepo=True,
6551 inferrepo=True,
6600 intents={INTENT_READONLY},
6552 intents={INTENT_READONLY},
6601 )
6553 )
6602 def status(ui, repo, *pats, **opts):
6554 def status(ui, repo, *pats, **opts):
6603 """show changed files in the working directory
6555 """show changed files in the working directory
6604
6556
6605 Show status of files in the repository. If names are given, only
6557 Show status of files in the repository. If names are given, only
6606 files that match are shown. Files that are clean or ignored or
6558 files that match are shown. Files that are clean or ignored or
6607 the source of a copy/move operation, are not listed unless
6559 the source of a copy/move operation, are not listed unless
6608 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6560 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6609 Unless options described with "show only ..." are given, the
6561 Unless options described with "show only ..." are given, the
6610 options -mardu are used.
6562 options -mardu are used.
6611
6563
6612 Option -q/--quiet hides untracked (unknown and ignored) files
6564 Option -q/--quiet hides untracked (unknown and ignored) files
6613 unless explicitly requested with -u/--unknown or -i/--ignored.
6565 unless explicitly requested with -u/--unknown or -i/--ignored.
6614
6566
6615 .. note::
6567 .. note::
6616
6568
6617 :hg:`status` may appear to disagree with diff if permissions have
6569 :hg:`status` may appear to disagree with diff if permissions have
6618 changed or a merge has occurred. The standard diff format does
6570 changed or a merge has occurred. The standard diff format does
6619 not report permission changes and diff only reports changes
6571 not report permission changes and diff only reports changes
6620 relative to one merge parent.
6572 relative to one merge parent.
6621
6573
6622 If one revision is given, it is used as the base revision.
6574 If one revision is given, it is used as the base revision.
6623 If two revisions are given, the differences between them are
6575 If two revisions are given, the differences between them are
6624 shown. The --change option can also be used as a shortcut to list
6576 shown. The --change option can also be used as a shortcut to list
6625 the changed files of a revision from its first parent.
6577 the changed files of a revision from its first parent.
6626
6578
6627 The codes used to show the status of files are::
6579 The codes used to show the status of files are::
6628
6580
6629 M = modified
6581 M = modified
6630 A = added
6582 A = added
6631 R = removed
6583 R = removed
6632 C = clean
6584 C = clean
6633 ! = missing (deleted by non-hg command, but still tracked)
6585 ! = missing (deleted by non-hg command, but still tracked)
6634 ? = not tracked
6586 ? = not tracked
6635 I = ignored
6587 I = ignored
6636 = origin of the previous file (with --copies)
6588 = origin of the previous file (with --copies)
6637
6589
6638 .. container:: verbose
6590 .. container:: verbose
6639
6591
6640 The -t/--terse option abbreviates the output by showing only the directory
6592 The -t/--terse option abbreviates the output by showing only the directory
6641 name if all the files in it share the same status. The option takes an
6593 name if all the files in it share the same status. The option takes an
6642 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6594 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6643 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6595 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6644 for 'ignored' and 'c' for clean.
6596 for 'ignored' and 'c' for clean.
6645
6597
6646 It abbreviates only those statuses which are passed. Note that clean and
6598 It abbreviates only those statuses which are passed. Note that clean and
6647 ignored files are not displayed with '--terse ic' unless the -c/--clean
6599 ignored files are not displayed with '--terse ic' unless the -c/--clean
6648 and -i/--ignored options are also used.
6600 and -i/--ignored options are also used.
6649
6601
6650 The -v/--verbose option shows information when the repository is in an
6602 The -v/--verbose option shows information when the repository is in an
6651 unfinished merge, shelve, rebase state etc. You can have this behavior
6603 unfinished merge, shelve, rebase state etc. You can have this behavior
6652 turned on by default by enabling the ``commands.status.verbose`` option.
6604 turned on by default by enabling the ``commands.status.verbose`` option.
6653
6605
6654 You can skip displaying some of these states by setting
6606 You can skip displaying some of these states by setting
6655 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6607 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6656 'histedit', 'merge', 'rebase', or 'unshelve'.
6608 'histedit', 'merge', 'rebase', or 'unshelve'.
6657
6609
6658 Template:
6610 Template:
6659
6611
6660 The following keywords are supported in addition to the common template
6612 The following keywords are supported in addition to the common template
6661 keywords and functions. See also :hg:`help templates`.
6613 keywords and functions. See also :hg:`help templates`.
6662
6614
6663 :path: String. Repository-absolute path of the file.
6615 :path: String. Repository-absolute path of the file.
6664 :source: String. Repository-absolute path of the file originated from.
6616 :source: String. Repository-absolute path of the file originated from.
6665 Available if ``--copies`` is specified.
6617 Available if ``--copies`` is specified.
6666 :status: String. Character denoting file's status.
6618 :status: String. Character denoting file's status.
6667
6619
6668 Examples:
6620 Examples:
6669
6621
6670 - show changes in the working directory relative to a
6622 - show changes in the working directory relative to a
6671 changeset::
6623 changeset::
6672
6624
6673 hg status --rev 9353
6625 hg status --rev 9353
6674
6626
6675 - show changes in the working directory relative to the
6627 - show changes in the working directory relative to the
6676 current directory (see :hg:`help patterns` for more information)::
6628 current directory (see :hg:`help patterns` for more information)::
6677
6629
6678 hg status re:
6630 hg status re:
6679
6631
6680 - show all changes including copies in an existing changeset::
6632 - show all changes including copies in an existing changeset::
6681
6633
6682 hg status --copies --change 9353
6634 hg status --copies --change 9353
6683
6635
6684 - get a NUL separated list of added files, suitable for xargs::
6636 - get a NUL separated list of added files, suitable for xargs::
6685
6637
6686 hg status -an0
6638 hg status -an0
6687
6639
6688 - show more information about the repository status, abbreviating
6640 - show more information about the repository status, abbreviating
6689 added, removed, modified, deleted, and untracked paths::
6641 added, removed, modified, deleted, and untracked paths::
6690
6642
6691 hg status -v -t mardu
6643 hg status -v -t mardu
6692
6644
6693 Returns 0 on success.
6645 Returns 0 on success.
6694
6646
6695 """
6647 """
6696
6648
6697 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6649 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6698 opts = pycompat.byteskwargs(opts)
6650 opts = pycompat.byteskwargs(opts)
6699 revs = opts.get(b'rev')
6651 revs = opts.get(b'rev')
6700 change = opts.get(b'change')
6652 change = opts.get(b'change')
6701 terse = opts.get(b'terse')
6653 terse = opts.get(b'terse')
6702 if terse is _NOTTERSE:
6654 if terse is _NOTTERSE:
6703 if revs:
6655 if revs:
6704 terse = b''
6656 terse = b''
6705 else:
6657 else:
6706 terse = ui.config(b'commands', b'status.terse')
6658 terse = ui.config(b'commands', b'status.terse')
6707
6659
6708 if revs and terse:
6660 if revs and terse:
6709 msg = _(b'cannot use --terse with --rev')
6661 msg = _(b'cannot use --terse with --rev')
6710 raise error.Abort(msg)
6662 raise error.Abort(msg)
6711 elif change:
6663 elif change:
6712 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6664 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6713 ctx2 = scmutil.revsingle(repo, change, None)
6665 ctx2 = scmutil.revsingle(repo, change, None)
6714 ctx1 = ctx2.p1()
6666 ctx1 = ctx2.p1()
6715 else:
6667 else:
6716 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6668 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6717 ctx1, ctx2 = scmutil.revpair(repo, revs)
6669 ctx1, ctx2 = scmutil.revpair(repo, revs)
6718
6670
6719 forcerelativevalue = None
6671 forcerelativevalue = None
6720 if ui.hasconfig(b'commands', b'status.relative'):
6672 if ui.hasconfig(b'commands', b'status.relative'):
6721 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6673 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6722 uipathfn = scmutil.getuipathfn(
6674 uipathfn = scmutil.getuipathfn(
6723 repo,
6675 repo,
6724 legacyrelativevalue=bool(pats),
6676 legacyrelativevalue=bool(pats),
6725 forcerelativevalue=forcerelativevalue,
6677 forcerelativevalue=forcerelativevalue,
6726 )
6678 )
6727
6679
6728 if opts.get(b'print0'):
6680 if opts.get(b'print0'):
6729 end = b'\0'
6681 end = b'\0'
6730 else:
6682 else:
6731 end = b'\n'
6683 end = b'\n'
6732 states = b'modified added removed deleted unknown ignored clean'.split()
6684 states = b'modified added removed deleted unknown ignored clean'.split()
6733 show = [k for k in states if opts.get(k)]
6685 show = [k for k in states if opts.get(k)]
6734 if opts.get(b'all'):
6686 if opts.get(b'all'):
6735 show += ui.quiet and (states[:4] + [b'clean']) or states
6687 show += ui.quiet and (states[:4] + [b'clean']) or states
6736
6688
6737 if not show:
6689 if not show:
6738 if ui.quiet:
6690 if ui.quiet:
6739 show = states[:4]
6691 show = states[:4]
6740 else:
6692 else:
6741 show = states[:5]
6693 show = states[:5]
6742
6694
6743 m = scmutil.match(ctx2, pats, opts)
6695 m = scmutil.match(ctx2, pats, opts)
6744 if terse:
6696 if terse:
6745 # we need to compute clean and unknown to terse
6697 # we need to compute clean and unknown to terse
6746 stat = repo.status(
6698 stat = repo.status(
6747 ctx1.node(),
6699 ctx1.node(),
6748 ctx2.node(),
6700 ctx2.node(),
6749 m,
6701 m,
6750 b'ignored' in show or b'i' in terse,
6702 b'ignored' in show or b'i' in terse,
6751 clean=True,
6703 clean=True,
6752 unknown=True,
6704 unknown=True,
6753 listsubrepos=opts.get(b'subrepos'),
6705 listsubrepos=opts.get(b'subrepos'),
6754 )
6706 )
6755
6707
6756 stat = cmdutil.tersedir(stat, terse)
6708 stat = cmdutil.tersedir(stat, terse)
6757 else:
6709 else:
6758 stat = repo.status(
6710 stat = repo.status(
6759 ctx1.node(),
6711 ctx1.node(),
6760 ctx2.node(),
6712 ctx2.node(),
6761 m,
6713 m,
6762 b'ignored' in show,
6714 b'ignored' in show,
6763 b'clean' in show,
6715 b'clean' in show,
6764 b'unknown' in show,
6716 b'unknown' in show,
6765 opts.get(b'subrepos'),
6717 opts.get(b'subrepos'),
6766 )
6718 )
6767
6719
6768 changestates = zip(
6720 changestates = zip(
6769 states,
6721 states,
6770 pycompat.iterbytestr(b'MAR!?IC'),
6722 pycompat.iterbytestr(b'MAR!?IC'),
6771 [getattr(stat, s.decode('utf8')) for s in states],
6723 [getattr(stat, s.decode('utf8')) for s in states],
6772 )
6724 )
6773
6725
6774 copy = {}
6726 copy = {}
6775 if (
6727 if (
6776 opts.get(b'all')
6728 opts.get(b'all')
6777 or opts.get(b'copies')
6729 or opts.get(b'copies')
6778 or ui.configbool(b'ui', b'statuscopies')
6730 or ui.configbool(b'ui', b'statuscopies')
6779 ) and not opts.get(b'no_status'):
6731 ) and not opts.get(b'no_status'):
6780 copy = copies.pathcopies(ctx1, ctx2, m)
6732 copy = copies.pathcopies(ctx1, ctx2, m)
6781
6733
6782 morestatus = None
6734 morestatus = None
6783 if (
6735 if (
6784 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6736 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6785 ) and not ui.plain():
6737 ) and not ui.plain():
6786 morestatus = cmdutil.readmorestatus(repo)
6738 morestatus = cmdutil.readmorestatus(repo)
6787
6739
6788 ui.pager(b'status')
6740 ui.pager(b'status')
6789 fm = ui.formatter(b'status', opts)
6741 fm = ui.formatter(b'status', opts)
6790 fmt = b'%s' + end
6742 fmt = b'%s' + end
6791 showchar = not opts.get(b'no_status')
6743 showchar = not opts.get(b'no_status')
6792
6744
6793 for state, char, files in changestates:
6745 for state, char, files in changestates:
6794 if state in show:
6746 if state in show:
6795 label = b'status.' + state
6747 label = b'status.' + state
6796 for f in files:
6748 for f in files:
6797 fm.startitem()
6749 fm.startitem()
6798 fm.context(ctx=ctx2)
6750 fm.context(ctx=ctx2)
6799 fm.data(itemtype=b'file', path=f)
6751 fm.data(itemtype=b'file', path=f)
6800 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6752 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6801 fm.plain(fmt % uipathfn(f), label=label)
6753 fm.plain(fmt % uipathfn(f), label=label)
6802 if f in copy:
6754 if f in copy:
6803 fm.data(source=copy[f])
6755 fm.data(source=copy[f])
6804 fm.plain(
6756 fm.plain(
6805 (b' %s' + end) % uipathfn(copy[f]),
6757 (b' %s' + end) % uipathfn(copy[f]),
6806 label=b'status.copied',
6758 label=b'status.copied',
6807 )
6759 )
6808 if morestatus:
6760 if morestatus:
6809 morestatus.formatfile(f, fm)
6761 morestatus.formatfile(f, fm)
6810
6762
6811 if morestatus:
6763 if morestatus:
6812 morestatus.formatfooter(fm)
6764 morestatus.formatfooter(fm)
6813 fm.end()
6765 fm.end()
6814
6766
6815
6767
6816 @command(
6768 @command(
6817 b'summary|sum',
6769 b'summary|sum',
6818 [(b'', b'remote', None, _(b'check for push and pull'))],
6770 [(b'', b'remote', None, _(b'check for push and pull'))],
6819 b'[--remote]',
6771 b'[--remote]',
6820 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6772 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6821 helpbasic=True,
6773 helpbasic=True,
6822 intents={INTENT_READONLY},
6774 intents={INTENT_READONLY},
6823 )
6775 )
6824 def summary(ui, repo, **opts):
6776 def summary(ui, repo, **opts):
6825 """summarize working directory state
6777 """summarize working directory state
6826
6778
6827 This generates a brief summary of the working directory state,
6779 This generates a brief summary of the working directory state,
6828 including parents, branch, commit status, phase and available updates.
6780 including parents, branch, commit status, phase and available updates.
6829
6781
6830 With the --remote option, this will check the default paths for
6782 With the --remote option, this will check the default paths for
6831 incoming and outgoing changes. This can be time-consuming.
6783 incoming and outgoing changes. This can be time-consuming.
6832
6784
6833 Returns 0 on success.
6785 Returns 0 on success.
6834 """
6786 """
6835
6787
6836 opts = pycompat.byteskwargs(opts)
6788 opts = pycompat.byteskwargs(opts)
6837 ui.pager(b'summary')
6789 ui.pager(b'summary')
6838 ctx = repo[None]
6790 ctx = repo[None]
6839 parents = ctx.parents()
6791 parents = ctx.parents()
6840 pnode = parents[0].node()
6792 pnode = parents[0].node()
6841 marks = []
6793 marks = []
6842
6794
6843 try:
6795 try:
6844 ms = mergestatemod.mergestate.read(repo)
6796 ms = mergestatemod.mergestate.read(repo)
6845 except error.UnsupportedMergeRecords as e:
6797 except error.UnsupportedMergeRecords as e:
6846 s = b' '.join(e.recordtypes)
6798 s = b' '.join(e.recordtypes)
6847 ui.warn(
6799 ui.warn(
6848 _(b'warning: merge state has unsupported record types: %s\n') % s
6800 _(b'warning: merge state has unsupported record types: %s\n') % s
6849 )
6801 )
6850 unresolved = []
6802 unresolved = []
6851 else:
6803 else:
6852 unresolved = list(ms.unresolved())
6804 unresolved = list(ms.unresolved())
6853
6805
6854 for p in parents:
6806 for p in parents:
6855 # label with log.changeset (instead of log.parent) since this
6807 # label with log.changeset (instead of log.parent) since this
6856 # shows a working directory parent *changeset*:
6808 # shows a working directory parent *changeset*:
6857 # i18n: column positioning for "hg summary"
6809 # i18n: column positioning for "hg summary"
6858 ui.write(
6810 ui.write(
6859 _(b'parent: %d:%s ') % (p.rev(), p),
6811 _(b'parent: %d:%s ') % (p.rev(), p),
6860 label=logcmdutil.changesetlabels(p),
6812 label=logcmdutil.changesetlabels(p),
6861 )
6813 )
6862 ui.write(b' '.join(p.tags()), label=b'log.tag')
6814 ui.write(b' '.join(p.tags()), label=b'log.tag')
6863 if p.bookmarks():
6815 if p.bookmarks():
6864 marks.extend(p.bookmarks())
6816 marks.extend(p.bookmarks())
6865 if p.rev() == -1:
6817 if p.rev() == -1:
6866 if not len(repo):
6818 if not len(repo):
6867 ui.write(_(b' (empty repository)'))
6819 ui.write(_(b' (empty repository)'))
6868 else:
6820 else:
6869 ui.write(_(b' (no revision checked out)'))
6821 ui.write(_(b' (no revision checked out)'))
6870 if p.obsolete():
6822 if p.obsolete():
6871 ui.write(_(b' (obsolete)'))
6823 ui.write(_(b' (obsolete)'))
6872 if p.isunstable():
6824 if p.isunstable():
6873 instabilities = (
6825 instabilities = (
6874 ui.label(instability, b'trouble.%s' % instability)
6826 ui.label(instability, b'trouble.%s' % instability)
6875 for instability in p.instabilities()
6827 for instability in p.instabilities()
6876 )
6828 )
6877 ui.write(b' (' + b', '.join(instabilities) + b')')
6829 ui.write(b' (' + b', '.join(instabilities) + b')')
6878 ui.write(b'\n')
6830 ui.write(b'\n')
6879 if p.description():
6831 if p.description():
6880 ui.status(
6832 ui.status(
6881 b' ' + p.description().splitlines()[0].strip() + b'\n',
6833 b' ' + p.description().splitlines()[0].strip() + b'\n',
6882 label=b'log.summary',
6834 label=b'log.summary',
6883 )
6835 )
6884
6836
6885 branch = ctx.branch()
6837 branch = ctx.branch()
6886 bheads = repo.branchheads(branch)
6838 bheads = repo.branchheads(branch)
6887 # i18n: column positioning for "hg summary"
6839 # i18n: column positioning for "hg summary"
6888 m = _(b'branch: %s\n') % branch
6840 m = _(b'branch: %s\n') % branch
6889 if branch != b'default':
6841 if branch != b'default':
6890 ui.write(m, label=b'log.branch')
6842 ui.write(m, label=b'log.branch')
6891 else:
6843 else:
6892 ui.status(m, label=b'log.branch')
6844 ui.status(m, label=b'log.branch')
6893
6845
6894 if marks:
6846 if marks:
6895 active = repo._activebookmark
6847 active = repo._activebookmark
6896 # i18n: column positioning for "hg summary"
6848 # i18n: column positioning for "hg summary"
6897 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6849 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6898 if active is not None:
6850 if active is not None:
6899 if active in marks:
6851 if active in marks:
6900 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6852 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6901 marks.remove(active)
6853 marks.remove(active)
6902 else:
6854 else:
6903 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6855 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6904 for m in marks:
6856 for m in marks:
6905 ui.write(b' ' + m, label=b'log.bookmark')
6857 ui.write(b' ' + m, label=b'log.bookmark')
6906 ui.write(b'\n', label=b'log.bookmark')
6858 ui.write(b'\n', label=b'log.bookmark')
6907
6859
6908 status = repo.status(unknown=True)
6860 status = repo.status(unknown=True)
6909
6861
6910 c = repo.dirstate.copies()
6862 c = repo.dirstate.copies()
6911 copied, renamed = [], []
6863 copied, renamed = [], []
6912 for d, s in pycompat.iteritems(c):
6864 for d, s in pycompat.iteritems(c):
6913 if s in status.removed:
6865 if s in status.removed:
6914 status.removed.remove(s)
6866 status.removed.remove(s)
6915 renamed.append(d)
6867 renamed.append(d)
6916 else:
6868 else:
6917 copied.append(d)
6869 copied.append(d)
6918 if d in status.added:
6870 if d in status.added:
6919 status.added.remove(d)
6871 status.added.remove(d)
6920
6872
6921 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6873 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6922
6874
6923 labels = [
6875 labels = [
6924 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6876 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6925 (ui.label(_(b'%d added'), b'status.added'), status.added),
6877 (ui.label(_(b'%d added'), b'status.added'), status.added),
6926 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6878 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6927 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6879 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6928 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6880 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6929 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6881 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6930 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6882 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6931 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6883 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6932 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6884 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6933 ]
6885 ]
6934 t = []
6886 t = []
6935 for l, s in labels:
6887 for l, s in labels:
6936 if s:
6888 if s:
6937 t.append(l % len(s))
6889 t.append(l % len(s))
6938
6890
6939 t = b', '.join(t)
6891 t = b', '.join(t)
6940 cleanworkdir = False
6892 cleanworkdir = False
6941
6893
6942 if repo.vfs.exists(b'graftstate'):
6894 if repo.vfs.exists(b'graftstate'):
6943 t += _(b' (graft in progress)')
6895 t += _(b' (graft in progress)')
6944 if repo.vfs.exists(b'updatestate'):
6896 if repo.vfs.exists(b'updatestate'):
6945 t += _(b' (interrupted update)')
6897 t += _(b' (interrupted update)')
6946 elif len(parents) > 1:
6898 elif len(parents) > 1:
6947 t += _(b' (merge)')
6899 t += _(b' (merge)')
6948 elif branch != parents[0].branch():
6900 elif branch != parents[0].branch():
6949 t += _(b' (new branch)')
6901 t += _(b' (new branch)')
6950 elif parents[0].closesbranch() and pnode in repo.branchheads(
6902 elif parents[0].closesbranch() and pnode in repo.branchheads(
6951 branch, closed=True
6903 branch, closed=True
6952 ):
6904 ):
6953 t += _(b' (head closed)')
6905 t += _(b' (head closed)')
6954 elif not (
6906 elif not (
6955 status.modified
6907 status.modified
6956 or status.added
6908 or status.added
6957 or status.removed
6909 or status.removed
6958 or renamed
6910 or renamed
6959 or copied
6911 or copied
6960 or subs
6912 or subs
6961 ):
6913 ):
6962 t += _(b' (clean)')
6914 t += _(b' (clean)')
6963 cleanworkdir = True
6915 cleanworkdir = True
6964 elif pnode not in bheads:
6916 elif pnode not in bheads:
6965 t += _(b' (new branch head)')
6917 t += _(b' (new branch head)')
6966
6918
6967 if parents:
6919 if parents:
6968 pendingphase = max(p.phase() for p in parents)
6920 pendingphase = max(p.phase() for p in parents)
6969 else:
6921 else:
6970 pendingphase = phases.public
6922 pendingphase = phases.public
6971
6923
6972 if pendingphase > phases.newcommitphase(ui):
6924 if pendingphase > phases.newcommitphase(ui):
6973 t += b' (%s)' % phases.phasenames[pendingphase]
6925 t += b' (%s)' % phases.phasenames[pendingphase]
6974
6926
6975 if cleanworkdir:
6927 if cleanworkdir:
6976 # i18n: column positioning for "hg summary"
6928 # i18n: column positioning for "hg summary"
6977 ui.status(_(b'commit: %s\n') % t.strip())
6929 ui.status(_(b'commit: %s\n') % t.strip())
6978 else:
6930 else:
6979 # i18n: column positioning for "hg summary"
6931 # i18n: column positioning for "hg summary"
6980 ui.write(_(b'commit: %s\n') % t.strip())
6932 ui.write(_(b'commit: %s\n') % t.strip())
6981
6933
6982 # all ancestors of branch heads - all ancestors of parent = new csets
6934 # all ancestors of branch heads - all ancestors of parent = new csets
6983 new = len(
6935 new = len(
6984 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6936 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6985 )
6937 )
6986
6938
6987 if new == 0:
6939 if new == 0:
6988 # i18n: column positioning for "hg summary"
6940 # i18n: column positioning for "hg summary"
6989 ui.status(_(b'update: (current)\n'))
6941 ui.status(_(b'update: (current)\n'))
6990 elif pnode not in bheads:
6942 elif pnode not in bheads:
6991 # i18n: column positioning for "hg summary"
6943 # i18n: column positioning for "hg summary"
6992 ui.write(_(b'update: %d new changesets (update)\n') % new)
6944 ui.write(_(b'update: %d new changesets (update)\n') % new)
6993 else:
6945 else:
6994 # i18n: column positioning for "hg summary"
6946 # i18n: column positioning for "hg summary"
6995 ui.write(
6947 ui.write(
6996 _(b'update: %d new changesets, %d branch heads (merge)\n')
6948 _(b'update: %d new changesets, %d branch heads (merge)\n')
6997 % (new, len(bheads))
6949 % (new, len(bheads))
6998 )
6950 )
6999
6951
7000 t = []
6952 t = []
7001 draft = len(repo.revs(b'draft()'))
6953 draft = len(repo.revs(b'draft()'))
7002 if draft:
6954 if draft:
7003 t.append(_(b'%d draft') % draft)
6955 t.append(_(b'%d draft') % draft)
7004 secret = len(repo.revs(b'secret()'))
6956 secret = len(repo.revs(b'secret()'))
7005 if secret:
6957 if secret:
7006 t.append(_(b'%d secret') % secret)
6958 t.append(_(b'%d secret') % secret)
7007
6959
7008 if draft or secret:
6960 if draft or secret:
7009 ui.status(_(b'phases: %s\n') % b', '.join(t))
6961 ui.status(_(b'phases: %s\n') % b', '.join(t))
7010
6962
7011 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6963 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7012 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6964 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7013 numtrouble = len(repo.revs(trouble + b"()"))
6965 numtrouble = len(repo.revs(trouble + b"()"))
7014 # We write all the possibilities to ease translation
6966 # We write all the possibilities to ease translation
7015 troublemsg = {
6967 troublemsg = {
7016 b"orphan": _(b"orphan: %d changesets"),
6968 b"orphan": _(b"orphan: %d changesets"),
7017 b"contentdivergent": _(b"content-divergent: %d changesets"),
6969 b"contentdivergent": _(b"content-divergent: %d changesets"),
7018 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6970 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7019 }
6971 }
7020 if numtrouble > 0:
6972 if numtrouble > 0:
7021 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6973 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7022
6974
7023 cmdutil.summaryhooks(ui, repo)
6975 cmdutil.summaryhooks(ui, repo)
7024
6976
7025 if opts.get(b'remote'):
6977 if opts.get(b'remote'):
7026 needsincoming, needsoutgoing = True, True
6978 needsincoming, needsoutgoing = True, True
7027 else:
6979 else:
7028 needsincoming, needsoutgoing = False, False
6980 needsincoming, needsoutgoing = False, False
7029 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6981 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7030 if i:
6982 if i:
7031 needsincoming = True
6983 needsincoming = True
7032 if o:
6984 if o:
7033 needsoutgoing = True
6985 needsoutgoing = True
7034 if not needsincoming and not needsoutgoing:
6986 if not needsincoming and not needsoutgoing:
7035 return
6987 return
7036
6988
7037 def getincoming():
6989 def getincoming():
7038 source, branches = hg.parseurl(ui.expandpath(b'default'))
6990 source, branches = hg.parseurl(ui.expandpath(b'default'))
7039 sbranch = branches[0]
6991 sbranch = branches[0]
7040 try:
6992 try:
7041 other = hg.peer(repo, {}, source)
6993 other = hg.peer(repo, {}, source)
7042 except error.RepoError:
6994 except error.RepoError:
7043 if opts.get(b'remote'):
6995 if opts.get(b'remote'):
7044 raise
6996 raise
7045 return source, sbranch, None, None, None
6997 return source, sbranch, None, None, None
7046 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6998 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7047 if revs:
6999 if revs:
7048 revs = [other.lookup(rev) for rev in revs]
7000 revs = [other.lookup(rev) for rev in revs]
7049 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7001 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7050 repo.ui.pushbuffer()
7002 repo.ui.pushbuffer()
7051 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7003 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7052 repo.ui.popbuffer()
7004 repo.ui.popbuffer()
7053 return source, sbranch, other, commoninc, commoninc[1]
7005 return source, sbranch, other, commoninc, commoninc[1]
7054
7006
7055 if needsincoming:
7007 if needsincoming:
7056 source, sbranch, sother, commoninc, incoming = getincoming()
7008 source, sbranch, sother, commoninc, incoming = getincoming()
7057 else:
7009 else:
7058 source = sbranch = sother = commoninc = incoming = None
7010 source = sbranch = sother = commoninc = incoming = None
7059
7011
7060 def getoutgoing():
7012 def getoutgoing():
7061 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7013 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7062 dbranch = branches[0]
7014 dbranch = branches[0]
7063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7015 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7064 if source != dest:
7016 if source != dest:
7065 try:
7017 try:
7066 dother = hg.peer(repo, {}, dest)
7018 dother = hg.peer(repo, {}, dest)
7067 except error.RepoError:
7019 except error.RepoError:
7068 if opts.get(b'remote'):
7020 if opts.get(b'remote'):
7069 raise
7021 raise
7070 return dest, dbranch, None, None
7022 return dest, dbranch, None, None
7071 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7023 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7072 elif sother is None:
7024 elif sother is None:
7073 # there is no explicit destination peer, but source one is invalid
7025 # there is no explicit destination peer, but source one is invalid
7074 return dest, dbranch, None, None
7026 return dest, dbranch, None, None
7075 else:
7027 else:
7076 dother = sother
7028 dother = sother
7077 if source != dest or (sbranch is not None and sbranch != dbranch):
7029 if source != dest or (sbranch is not None and sbranch != dbranch):
7078 common = None
7030 common = None
7079 else:
7031 else:
7080 common = commoninc
7032 common = commoninc
7081 if revs:
7033 if revs:
7082 revs = [repo.lookup(rev) for rev in revs]
7034 revs = [repo.lookup(rev) for rev in revs]
7083 repo.ui.pushbuffer()
7035 repo.ui.pushbuffer()
7084 outgoing = discovery.findcommonoutgoing(
7036 outgoing = discovery.findcommonoutgoing(
7085 repo, dother, onlyheads=revs, commoninc=common
7037 repo, dother, onlyheads=revs, commoninc=common
7086 )
7038 )
7087 repo.ui.popbuffer()
7039 repo.ui.popbuffer()
7088 return dest, dbranch, dother, outgoing
7040 return dest, dbranch, dother, outgoing
7089
7041
7090 if needsoutgoing:
7042 if needsoutgoing:
7091 dest, dbranch, dother, outgoing = getoutgoing()
7043 dest, dbranch, dother, outgoing = getoutgoing()
7092 else:
7044 else:
7093 dest = dbranch = dother = outgoing = None
7045 dest = dbranch = dother = outgoing = None
7094
7046
7095 if opts.get(b'remote'):
7047 if opts.get(b'remote'):
7096 t = []
7048 t = []
7097 if incoming:
7049 if incoming:
7098 t.append(_(b'1 or more incoming'))
7050 t.append(_(b'1 or more incoming'))
7099 o = outgoing.missing
7051 o = outgoing.missing
7100 if o:
7052 if o:
7101 t.append(_(b'%d outgoing') % len(o))
7053 t.append(_(b'%d outgoing') % len(o))
7102 other = dother or sother
7054 other = dother or sother
7103 if b'bookmarks' in other.listkeys(b'namespaces'):
7055 if b'bookmarks' in other.listkeys(b'namespaces'):
7104 counts = bookmarks.summary(repo, other)
7056 counts = bookmarks.summary(repo, other)
7105 if counts[0] > 0:
7057 if counts[0] > 0:
7106 t.append(_(b'%d incoming bookmarks') % counts[0])
7058 t.append(_(b'%d incoming bookmarks') % counts[0])
7107 if counts[1] > 0:
7059 if counts[1] > 0:
7108 t.append(_(b'%d outgoing bookmarks') % counts[1])
7060 t.append(_(b'%d outgoing bookmarks') % counts[1])
7109
7061
7110 if t:
7062 if t:
7111 # i18n: column positioning for "hg summary"
7063 # i18n: column positioning for "hg summary"
7112 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7064 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7113 else:
7065 else:
7114 # i18n: column positioning for "hg summary"
7066 # i18n: column positioning for "hg summary"
7115 ui.status(_(b'remote: (synced)\n'))
7067 ui.status(_(b'remote: (synced)\n'))
7116
7068
7117 cmdutil.summaryremotehooks(
7069 cmdutil.summaryremotehooks(
7118 ui,
7070 ui,
7119 repo,
7071 repo,
7120 opts,
7072 opts,
7121 (
7073 (
7122 (source, sbranch, sother, commoninc),
7074 (source, sbranch, sother, commoninc),
7123 (dest, dbranch, dother, outgoing),
7075 (dest, dbranch, dother, outgoing),
7124 ),
7076 ),
7125 )
7077 )
7126
7078
7127
7079
7128 @command(
7080 @command(
7129 b'tag',
7081 b'tag',
7130 [
7082 [
7131 (b'f', b'force', None, _(b'force tag')),
7083 (b'f', b'force', None, _(b'force tag')),
7132 (b'l', b'local', None, _(b'make the tag local')),
7084 (b'l', b'local', None, _(b'make the tag local')),
7133 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7085 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7134 (b'', b'remove', None, _(b'remove a tag')),
7086 (b'', b'remove', None, _(b'remove a tag')),
7135 # -l/--local is already there, commitopts cannot be used
7087 # -l/--local is already there, commitopts cannot be used
7136 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7088 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7137 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7089 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7138 ]
7090 ]
7139 + commitopts2,
7091 + commitopts2,
7140 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7092 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7141 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7093 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7142 )
7094 )
7143 def tag(ui, repo, name1, *names, **opts):
7095 def tag(ui, repo, name1, *names, **opts):
7144 """add one or more tags for the current or given revision
7096 """add one or more tags for the current or given revision
7145
7097
7146 Name a particular revision using <name>.
7098 Name a particular revision using <name>.
7147
7099
7148 Tags are used to name particular revisions of the repository and are
7100 Tags are used to name particular revisions of the repository and are
7149 very useful to compare different revisions, to go back to significant
7101 very useful to compare different revisions, to go back to significant
7150 earlier versions or to mark branch points as releases, etc. Changing
7102 earlier versions or to mark branch points as releases, etc. Changing
7151 an existing tag is normally disallowed; use -f/--force to override.
7103 an existing tag is normally disallowed; use -f/--force to override.
7152
7104
7153 If no revision is given, the parent of the working directory is
7105 If no revision is given, the parent of the working directory is
7154 used.
7106 used.
7155
7107
7156 To facilitate version control, distribution, and merging of tags,
7108 To facilitate version control, distribution, and merging of tags,
7157 they are stored as a file named ".hgtags" which is managed similarly
7109 they are stored as a file named ".hgtags" which is managed similarly
7158 to other project files and can be hand-edited if necessary. This
7110 to other project files and can be hand-edited if necessary. This
7159 also means that tagging creates a new commit. The file
7111 also means that tagging creates a new commit. The file
7160 ".hg/localtags" is used for local tags (not shared among
7112 ".hg/localtags" is used for local tags (not shared among
7161 repositories).
7113 repositories).
7162
7114
7163 Tag commits are usually made at the head of a branch. If the parent
7115 Tag commits are usually made at the head of a branch. If the parent
7164 of the working directory is not a branch head, :hg:`tag` aborts; use
7116 of the working directory is not a branch head, :hg:`tag` aborts; use
7165 -f/--force to force the tag commit to be based on a non-head
7117 -f/--force to force the tag commit to be based on a non-head
7166 changeset.
7118 changeset.
7167
7119
7168 See :hg:`help dates` for a list of formats valid for -d/--date.
7120 See :hg:`help dates` for a list of formats valid for -d/--date.
7169
7121
7170 Since tag names have priority over branch names during revision
7122 Since tag names have priority over branch names during revision
7171 lookup, using an existing branch name as a tag name is discouraged.
7123 lookup, using an existing branch name as a tag name is discouraged.
7172
7124
7173 Returns 0 on success.
7125 Returns 0 on success.
7174 """
7126 """
7175 opts = pycompat.byteskwargs(opts)
7127 opts = pycompat.byteskwargs(opts)
7176 with repo.wlock(), repo.lock():
7128 with repo.wlock(), repo.lock():
7177 rev_ = b"."
7129 rev_ = b"."
7178 names = [t.strip() for t in (name1,) + names]
7130 names = [t.strip() for t in (name1,) + names]
7179 if len(names) != len(set(names)):
7131 if len(names) != len(set(names)):
7180 raise error.Abort(_(b'tag names must be unique'))
7132 raise error.Abort(_(b'tag names must be unique'))
7181 for n in names:
7133 for n in names:
7182 scmutil.checknewlabel(repo, n, b'tag')
7134 scmutil.checknewlabel(repo, n, b'tag')
7183 if not n:
7135 if not n:
7184 raise error.Abort(
7136 raise error.Abort(
7185 _(b'tag names cannot consist entirely of whitespace')
7137 _(b'tag names cannot consist entirely of whitespace')
7186 )
7138 )
7187 if opts.get(b'rev') and opts.get(b'remove'):
7139 if opts.get(b'rev') and opts.get(b'remove'):
7188 raise error.Abort(_(b"--rev and --remove are incompatible"))
7140 raise error.Abort(_(b"--rev and --remove are incompatible"))
7189 if opts.get(b'rev'):
7141 if opts.get(b'rev'):
7190 rev_ = opts[b'rev']
7142 rev_ = opts[b'rev']
7191 message = opts.get(b'message')
7143 message = opts.get(b'message')
7192 if opts.get(b'remove'):
7144 if opts.get(b'remove'):
7193 if opts.get(b'local'):
7145 if opts.get(b'local'):
7194 expectedtype = b'local'
7146 expectedtype = b'local'
7195 else:
7147 else:
7196 expectedtype = b'global'
7148 expectedtype = b'global'
7197
7149
7198 for n in names:
7150 for n in names:
7199 if repo.tagtype(n) == b'global':
7151 if repo.tagtype(n) == b'global':
7200 alltags = tagsmod.findglobaltags(ui, repo)
7152 alltags = tagsmod.findglobaltags(ui, repo)
7201 if alltags[n][0] == nullid:
7153 if alltags[n][0] == nullid:
7202 raise error.Abort(_(b"tag '%s' is already removed") % n)
7154 raise error.Abort(_(b"tag '%s' is already removed") % n)
7203 if not repo.tagtype(n):
7155 if not repo.tagtype(n):
7204 raise error.Abort(_(b"tag '%s' does not exist") % n)
7156 raise error.Abort(_(b"tag '%s' does not exist") % n)
7205 if repo.tagtype(n) != expectedtype:
7157 if repo.tagtype(n) != expectedtype:
7206 if expectedtype == b'global':
7158 if expectedtype == b'global':
7207 raise error.Abort(
7159 raise error.Abort(
7208 _(b"tag '%s' is not a global tag") % n
7160 _(b"tag '%s' is not a global tag") % n
7209 )
7161 )
7210 else:
7162 else:
7211 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7163 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7212 rev_ = b'null'
7164 rev_ = b'null'
7213 if not message:
7165 if not message:
7214 # we don't translate commit messages
7166 # we don't translate commit messages
7215 message = b'Removed tag %s' % b', '.join(names)
7167 message = b'Removed tag %s' % b', '.join(names)
7216 elif not opts.get(b'force'):
7168 elif not opts.get(b'force'):
7217 for n in names:
7169 for n in names:
7218 if n in repo.tags():
7170 if n in repo.tags():
7219 raise error.Abort(
7171 raise error.Abort(
7220 _(b"tag '%s' already exists (use -f to force)") % n
7172 _(b"tag '%s' already exists (use -f to force)") % n
7221 )
7173 )
7222 if not opts.get(b'local'):
7174 if not opts.get(b'local'):
7223 p1, p2 = repo.dirstate.parents()
7175 p1, p2 = repo.dirstate.parents()
7224 if p2 != nullid:
7176 if p2 != nullid:
7225 raise error.Abort(_(b'uncommitted merge'))
7177 raise error.Abort(_(b'uncommitted merge'))
7226 bheads = repo.branchheads()
7178 bheads = repo.branchheads()
7227 if not opts.get(b'force') and bheads and p1 not in bheads:
7179 if not opts.get(b'force') and bheads and p1 not in bheads:
7228 raise error.Abort(
7180 raise error.Abort(
7229 _(
7181 _(
7230 b'working directory is not at a branch head '
7182 b'working directory is not at a branch head '
7231 b'(use -f to force)'
7183 b'(use -f to force)'
7232 )
7184 )
7233 )
7185 )
7234 node = scmutil.revsingle(repo, rev_).node()
7186 node = scmutil.revsingle(repo, rev_).node()
7235
7187
7236 if not message:
7188 if not message:
7237 # we don't translate commit messages
7189 # we don't translate commit messages
7238 message = b'Added tag %s for changeset %s' % (
7190 message = b'Added tag %s for changeset %s' % (
7239 b', '.join(names),
7191 b', '.join(names),
7240 short(node),
7192 short(node),
7241 )
7193 )
7242
7194
7243 date = opts.get(b'date')
7195 date = opts.get(b'date')
7244 if date:
7196 if date:
7245 date = dateutil.parsedate(date)
7197 date = dateutil.parsedate(date)
7246
7198
7247 if opts.get(b'remove'):
7199 if opts.get(b'remove'):
7248 editform = b'tag.remove'
7200 editform = b'tag.remove'
7249 else:
7201 else:
7250 editform = b'tag.add'
7202 editform = b'tag.add'
7251 editor = cmdutil.getcommiteditor(
7203 editor = cmdutil.getcommiteditor(
7252 editform=editform, **pycompat.strkwargs(opts)
7204 editform=editform, **pycompat.strkwargs(opts)
7253 )
7205 )
7254
7206
7255 # don't allow tagging the null rev
7207 # don't allow tagging the null rev
7256 if (
7208 if (
7257 not opts.get(b'remove')
7209 not opts.get(b'remove')
7258 and scmutil.revsingle(repo, rev_).rev() == nullrev
7210 and scmutil.revsingle(repo, rev_).rev() == nullrev
7259 ):
7211 ):
7260 raise error.Abort(_(b"cannot tag null revision"))
7212 raise error.Abort(_(b"cannot tag null revision"))
7261
7213
7262 tagsmod.tag(
7214 tagsmod.tag(
7263 repo,
7215 repo,
7264 names,
7216 names,
7265 node,
7217 node,
7266 message,
7218 message,
7267 opts.get(b'local'),
7219 opts.get(b'local'),
7268 opts.get(b'user'),
7220 opts.get(b'user'),
7269 date,
7221 date,
7270 editor=editor,
7222 editor=editor,
7271 )
7223 )
7272
7224
7273
7225
7274 @command(
7226 @command(
7275 b'tags',
7227 b'tags',
7276 formatteropts,
7228 formatteropts,
7277 b'',
7229 b'',
7278 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7230 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7279 intents={INTENT_READONLY},
7231 intents={INTENT_READONLY},
7280 )
7232 )
7281 def tags(ui, repo, **opts):
7233 def tags(ui, repo, **opts):
7282 """list repository tags
7234 """list repository tags
7283
7235
7284 This lists both regular and local tags. When the -v/--verbose
7236 This lists both regular and local tags. When the -v/--verbose
7285 switch is used, a third column "local" is printed for local tags.
7237 switch is used, a third column "local" is printed for local tags.
7286 When the -q/--quiet switch is used, only the tag name is printed.
7238 When the -q/--quiet switch is used, only the tag name is printed.
7287
7239
7288 .. container:: verbose
7240 .. container:: verbose
7289
7241
7290 Template:
7242 Template:
7291
7243
7292 The following keywords are supported in addition to the common template
7244 The following keywords are supported in addition to the common template
7293 keywords and functions such as ``{tag}``. See also
7245 keywords and functions such as ``{tag}``. See also
7294 :hg:`help templates`.
7246 :hg:`help templates`.
7295
7247
7296 :type: String. ``local`` for local tags.
7248 :type: String. ``local`` for local tags.
7297
7249
7298 Returns 0 on success.
7250 Returns 0 on success.
7299 """
7251 """
7300
7252
7301 opts = pycompat.byteskwargs(opts)
7253 opts = pycompat.byteskwargs(opts)
7302 ui.pager(b'tags')
7254 ui.pager(b'tags')
7303 fm = ui.formatter(b'tags', opts)
7255 fm = ui.formatter(b'tags', opts)
7304 hexfunc = fm.hexfunc
7256 hexfunc = fm.hexfunc
7305
7257
7306 for t, n in reversed(repo.tagslist()):
7258 for t, n in reversed(repo.tagslist()):
7307 hn = hexfunc(n)
7259 hn = hexfunc(n)
7308 label = b'tags.normal'
7260 label = b'tags.normal'
7309 tagtype = b''
7261 tagtype = b''
7310 if repo.tagtype(t) == b'local':
7262 if repo.tagtype(t) == b'local':
7311 label = b'tags.local'
7263 label = b'tags.local'
7312 tagtype = b'local'
7264 tagtype = b'local'
7313
7265
7314 fm.startitem()
7266 fm.startitem()
7315 fm.context(repo=repo)
7267 fm.context(repo=repo)
7316 fm.write(b'tag', b'%s', t, label=label)
7268 fm.write(b'tag', b'%s', t, label=label)
7317 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7269 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7318 fm.condwrite(
7270 fm.condwrite(
7319 not ui.quiet,
7271 not ui.quiet,
7320 b'rev node',
7272 b'rev node',
7321 fmt,
7273 fmt,
7322 repo.changelog.rev(n),
7274 repo.changelog.rev(n),
7323 hn,
7275 hn,
7324 label=label,
7276 label=label,
7325 )
7277 )
7326 fm.condwrite(
7278 fm.condwrite(
7327 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7279 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7328 )
7280 )
7329 fm.plain(b'\n')
7281 fm.plain(b'\n')
7330 fm.end()
7282 fm.end()
7331
7283
7332
7284
7333 @command(
7285 @command(
7334 b'tip',
7286 b'tip',
7335 [
7287 [
7336 (b'p', b'patch', None, _(b'show patch')),
7288 (b'p', b'patch', None, _(b'show patch')),
7337 (b'g', b'git', None, _(b'use git extended diff format')),
7289 (b'g', b'git', None, _(b'use git extended diff format')),
7338 ]
7290 ]
7339 + templateopts,
7291 + templateopts,
7340 _(b'[-p] [-g]'),
7292 _(b'[-p] [-g]'),
7341 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7293 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7342 )
7294 )
7343 def tip(ui, repo, **opts):
7295 def tip(ui, repo, **opts):
7344 """show the tip revision (DEPRECATED)
7296 """show the tip revision (DEPRECATED)
7345
7297
7346 The tip revision (usually just called the tip) is the changeset
7298 The tip revision (usually just called the tip) is the changeset
7347 most recently added to the repository (and therefore the most
7299 most recently added to the repository (and therefore the most
7348 recently changed head).
7300 recently changed head).
7349
7301
7350 If you have just made a commit, that commit will be the tip. If
7302 If you have just made a commit, that commit will be the tip. If
7351 you have just pulled changes from another repository, the tip of
7303 you have just pulled changes from another repository, the tip of
7352 that repository becomes the current tip. The "tip" tag is special
7304 that repository becomes the current tip. The "tip" tag is special
7353 and cannot be renamed or assigned to a different changeset.
7305 and cannot be renamed or assigned to a different changeset.
7354
7306
7355 This command is deprecated, please use :hg:`heads` instead.
7307 This command is deprecated, please use :hg:`heads` instead.
7356
7308
7357 Returns 0 on success.
7309 Returns 0 on success.
7358 """
7310 """
7359 opts = pycompat.byteskwargs(opts)
7311 opts = pycompat.byteskwargs(opts)
7360 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7312 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7361 displayer.show(repo[b'tip'])
7313 displayer.show(repo[b'tip'])
7362 displayer.close()
7314 displayer.close()
7363
7315
7364
7316
7365 @command(
7317 @command(
7366 b'unbundle',
7318 b'unbundle',
7367 [
7319 [
7368 (
7320 (
7369 b'u',
7321 b'u',
7370 b'update',
7322 b'update',
7371 None,
7323 None,
7372 _(b'update to new branch head if changesets were unbundled'),
7324 _(b'update to new branch head if changesets were unbundled'),
7373 )
7325 )
7374 ],
7326 ],
7375 _(b'[-u] FILE...'),
7327 _(b'[-u] FILE...'),
7376 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7328 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7377 )
7329 )
7378 def unbundle(ui, repo, fname1, *fnames, **opts):
7330 def unbundle(ui, repo, fname1, *fnames, **opts):
7379 """apply one or more bundle files
7331 """apply one or more bundle files
7380
7332
7381 Apply one or more bundle files generated by :hg:`bundle`.
7333 Apply one or more bundle files generated by :hg:`bundle`.
7382
7334
7383 Returns 0 on success, 1 if an update has unresolved files.
7335 Returns 0 on success, 1 if an update has unresolved files.
7384 """
7336 """
7385 fnames = (fname1,) + fnames
7337 fnames = (fname1,) + fnames
7386
7338
7387 with repo.lock():
7339 with repo.lock():
7388 for fname in fnames:
7340 for fname in fnames:
7389 f = hg.openpath(ui, fname)
7341 f = hg.openpath(ui, fname)
7390 gen = exchange.readbundle(ui, f, fname)
7342 gen = exchange.readbundle(ui, f, fname)
7391 if isinstance(gen, streamclone.streamcloneapplier):
7343 if isinstance(gen, streamclone.streamcloneapplier):
7392 raise error.Abort(
7344 raise error.Abort(
7393 _(
7345 _(
7394 b'packed bundles cannot be applied with '
7346 b'packed bundles cannot be applied with '
7395 b'"hg unbundle"'
7347 b'"hg unbundle"'
7396 ),
7348 ),
7397 hint=_(b'use "hg debugapplystreamclonebundle"'),
7349 hint=_(b'use "hg debugapplystreamclonebundle"'),
7398 )
7350 )
7399 url = b'bundle:' + fname
7351 url = b'bundle:' + fname
7400 try:
7352 try:
7401 txnname = b'unbundle'
7353 txnname = b'unbundle'
7402 if not isinstance(gen, bundle2.unbundle20):
7354 if not isinstance(gen, bundle2.unbundle20):
7403 txnname = b'unbundle\n%s' % util.hidepassword(url)
7355 txnname = b'unbundle\n%s' % util.hidepassword(url)
7404 with repo.transaction(txnname) as tr:
7356 with repo.transaction(txnname) as tr:
7405 op = bundle2.applybundle(
7357 op = bundle2.applybundle(
7406 repo, gen, tr, source=b'unbundle', url=url
7358 repo, gen, tr, source=b'unbundle', url=url
7407 )
7359 )
7408 except error.BundleUnknownFeatureError as exc:
7360 except error.BundleUnknownFeatureError as exc:
7409 raise error.Abort(
7361 raise error.Abort(
7410 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7362 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7411 hint=_(
7363 hint=_(
7412 b"see https://mercurial-scm.org/"
7364 b"see https://mercurial-scm.org/"
7413 b"wiki/BundleFeature for more "
7365 b"wiki/BundleFeature for more "
7414 b"information"
7366 b"information"
7415 ),
7367 ),
7416 )
7368 )
7417 modheads = bundle2.combinechangegroupresults(op)
7369 modheads = bundle2.combinechangegroupresults(op)
7418
7370
7419 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7371 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7420
7372
7421
7373
7422 @command(
7374 @command(
7423 b'unshelve',
7375 b'unshelve',
7424 [
7376 [
7425 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7377 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7426 (
7378 (
7427 b'c',
7379 b'c',
7428 b'continue',
7380 b'continue',
7429 None,
7381 None,
7430 _(b'continue an incomplete unshelve operation'),
7382 _(b'continue an incomplete unshelve operation'),
7431 ),
7383 ),
7432 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7384 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7433 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7385 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7434 (
7386 (
7435 b'n',
7387 b'n',
7436 b'name',
7388 b'name',
7437 b'',
7389 b'',
7438 _(b'restore shelved change with given name'),
7390 _(b'restore shelved change with given name'),
7439 _(b'NAME'),
7391 _(b'NAME'),
7440 ),
7392 ),
7441 (b't', b'tool', b'', _(b'specify merge tool')),
7393 (b't', b'tool', b'', _(b'specify merge tool')),
7442 (
7394 (
7443 b'',
7395 b'',
7444 b'date',
7396 b'date',
7445 b'',
7397 b'',
7446 _(b'set date for temporary commits (DEPRECATED)'),
7398 _(b'set date for temporary commits (DEPRECATED)'),
7447 _(b'DATE'),
7399 _(b'DATE'),
7448 ),
7400 ),
7449 ],
7401 ],
7450 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7402 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7451 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7403 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7452 )
7404 )
7453 def unshelve(ui, repo, *shelved, **opts):
7405 def unshelve(ui, repo, *shelved, **opts):
7454 """restore a shelved change to the working directory
7406 """restore a shelved change to the working directory
7455
7407
7456 This command accepts an optional name of a shelved change to
7408 This command accepts an optional name of a shelved change to
7457 restore. If none is given, the most recent shelved change is used.
7409 restore. If none is given, the most recent shelved change is used.
7458
7410
7459 If a shelved change is applied successfully, the bundle that
7411 If a shelved change is applied successfully, the bundle that
7460 contains the shelved changes is moved to a backup location
7412 contains the shelved changes is moved to a backup location
7461 (.hg/shelve-backup).
7413 (.hg/shelve-backup).
7462
7414
7463 Since you can restore a shelved change on top of an arbitrary
7415 Since you can restore a shelved change on top of an arbitrary
7464 commit, it is possible that unshelving will result in a conflict
7416 commit, it is possible that unshelving will result in a conflict
7465 between your changes and the commits you are unshelving onto. If
7417 between your changes and the commits you are unshelving onto. If
7466 this occurs, you must resolve the conflict, then use
7418 this occurs, you must resolve the conflict, then use
7467 ``--continue`` to complete the unshelve operation. (The bundle
7419 ``--continue`` to complete the unshelve operation. (The bundle
7468 will not be moved until you successfully complete the unshelve.)
7420 will not be moved until you successfully complete the unshelve.)
7469
7421
7470 (Alternatively, you can use ``--abort`` to abandon an unshelve
7422 (Alternatively, you can use ``--abort`` to abandon an unshelve
7471 that causes a conflict. This reverts the unshelved changes, and
7423 that causes a conflict. This reverts the unshelved changes, and
7472 leaves the bundle in place.)
7424 leaves the bundle in place.)
7473
7425
7474 If bare shelved change (without interactive, include and exclude
7426 If bare shelved change (without interactive, include and exclude
7475 option) was done on newly created branch it would restore branch
7427 option) was done on newly created branch it would restore branch
7476 information to the working directory.
7428 information to the working directory.
7477
7429
7478 After a successful unshelve, the shelved changes are stored in a
7430 After a successful unshelve, the shelved changes are stored in a
7479 backup directory. Only the N most recent backups are kept. N
7431 backup directory. Only the N most recent backups are kept. N
7480 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7432 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7481 configuration option.
7433 configuration option.
7482
7434
7483 .. container:: verbose
7435 .. container:: verbose
7484
7436
7485 Timestamp in seconds is used to decide order of backups. More
7437 Timestamp in seconds is used to decide order of backups. More
7486 than ``maxbackups`` backups are kept, if same timestamp
7438 than ``maxbackups`` backups are kept, if same timestamp
7487 prevents from deciding exact order of them, for safety.
7439 prevents from deciding exact order of them, for safety.
7488
7440
7489 Selected changes can be unshelved with ``--interactive`` flag.
7441 Selected changes can be unshelved with ``--interactive`` flag.
7490 The working directory is updated with the selected changes, and
7442 The working directory is updated with the selected changes, and
7491 only the unselected changes remain shelved.
7443 only the unselected changes remain shelved.
7492 Note: The whole shelve is applied to working directory first before
7444 Note: The whole shelve is applied to working directory first before
7493 running interactively. So, this will bring up all the conflicts between
7445 running interactively. So, this will bring up all the conflicts between
7494 working directory and the shelve, irrespective of which changes will be
7446 working directory and the shelve, irrespective of which changes will be
7495 unshelved.
7447 unshelved.
7496 """
7448 """
7497 with repo.wlock():
7449 with repo.wlock():
7498 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7450 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7499
7451
7500
7452
7501 statemod.addunfinished(
7453 statemod.addunfinished(
7502 b'unshelve',
7454 b'unshelve',
7503 fname=b'shelvedstate',
7455 fname=b'shelvedstate',
7504 continueflag=True,
7456 continueflag=True,
7505 abortfunc=shelvemod.hgabortunshelve,
7457 abortfunc=shelvemod.hgabortunshelve,
7506 continuefunc=shelvemod.hgcontinueunshelve,
7458 continuefunc=shelvemod.hgcontinueunshelve,
7507 cmdmsg=_(b'unshelve already in progress'),
7459 cmdmsg=_(b'unshelve already in progress'),
7508 )
7460 )
7509
7461
7510
7462
7511 @command(
7463 @command(
7512 b'update|up|checkout|co',
7464 b'update|up|checkout|co',
7513 [
7465 [
7514 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7466 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7515 (b'c', b'check', None, _(b'require clean working directory')),
7467 (b'c', b'check', None, _(b'require clean working directory')),
7516 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7468 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7517 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7469 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7518 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7470 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7519 ]
7471 ]
7520 + mergetoolopts,
7472 + mergetoolopts,
7521 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7473 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7522 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7474 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7523 helpbasic=True,
7475 helpbasic=True,
7524 )
7476 )
7525 def update(ui, repo, node=None, **opts):
7477 def update(ui, repo, node=None, **opts):
7526 """update working directory (or switch revisions)
7478 """update working directory (or switch revisions)
7527
7479
7528 Update the repository's working directory to the specified
7480 Update the repository's working directory to the specified
7529 changeset. If no changeset is specified, update to the tip of the
7481 changeset. If no changeset is specified, update to the tip of the
7530 current named branch and move the active bookmark (see :hg:`help
7482 current named branch and move the active bookmark (see :hg:`help
7531 bookmarks`).
7483 bookmarks`).
7532
7484
7533 Update sets the working directory's parent revision to the specified
7485 Update sets the working directory's parent revision to the specified
7534 changeset (see :hg:`help parents`).
7486 changeset (see :hg:`help parents`).
7535
7487
7536 If the changeset is not a descendant or ancestor of the working
7488 If the changeset is not a descendant or ancestor of the working
7537 directory's parent and there are uncommitted changes, the update is
7489 directory's parent and there are uncommitted changes, the update is
7538 aborted. With the -c/--check option, the working directory is checked
7490 aborted. With the -c/--check option, the working directory is checked
7539 for uncommitted changes; if none are found, the working directory is
7491 for uncommitted changes; if none are found, the working directory is
7540 updated to the specified changeset.
7492 updated to the specified changeset.
7541
7493
7542 .. container:: verbose
7494 .. container:: verbose
7543
7495
7544 The -C/--clean, -c/--check, and -m/--merge options control what
7496 The -C/--clean, -c/--check, and -m/--merge options control what
7545 happens if the working directory contains uncommitted changes.
7497 happens if the working directory contains uncommitted changes.
7546 At most of one of them can be specified.
7498 At most of one of them can be specified.
7547
7499
7548 1. If no option is specified, and if
7500 1. If no option is specified, and if
7549 the requested changeset is an ancestor or descendant of
7501 the requested changeset is an ancestor or descendant of
7550 the working directory's parent, the uncommitted changes
7502 the working directory's parent, the uncommitted changes
7551 are merged into the requested changeset and the merged
7503 are merged into the requested changeset and the merged
7552 result is left uncommitted. If the requested changeset is
7504 result is left uncommitted. If the requested changeset is
7553 not an ancestor or descendant (that is, it is on another
7505 not an ancestor or descendant (that is, it is on another
7554 branch), the update is aborted and the uncommitted changes
7506 branch), the update is aborted and the uncommitted changes
7555 are preserved.
7507 are preserved.
7556
7508
7557 2. With the -m/--merge option, the update is allowed even if the
7509 2. With the -m/--merge option, the update is allowed even if the
7558 requested changeset is not an ancestor or descendant of
7510 requested changeset is not an ancestor or descendant of
7559 the working directory's parent.
7511 the working directory's parent.
7560
7512
7561 3. With the -c/--check option, the update is aborted and the
7513 3. With the -c/--check option, the update is aborted and the
7562 uncommitted changes are preserved.
7514 uncommitted changes are preserved.
7563
7515
7564 4. With the -C/--clean option, uncommitted changes are discarded and
7516 4. With the -C/--clean option, uncommitted changes are discarded and
7565 the working directory is updated to the requested changeset.
7517 the working directory is updated to the requested changeset.
7566
7518
7567 To cancel an uncommitted merge (and lose your changes), use
7519 To cancel an uncommitted merge (and lose your changes), use
7568 :hg:`merge --abort`.
7520 :hg:`merge --abort`.
7569
7521
7570 Use null as the changeset to remove the working directory (like
7522 Use null as the changeset to remove the working directory (like
7571 :hg:`clone -U`).
7523 :hg:`clone -U`).
7572
7524
7573 If you want to revert just one file to an older revision, use
7525 If you want to revert just one file to an older revision, use
7574 :hg:`revert [-r REV] NAME`.
7526 :hg:`revert [-r REV] NAME`.
7575
7527
7576 See :hg:`help dates` for a list of formats valid for -d/--date.
7528 See :hg:`help dates` for a list of formats valid for -d/--date.
7577
7529
7578 Returns 0 on success, 1 if there are unresolved files.
7530 Returns 0 on success, 1 if there are unresolved files.
7579 """
7531 """
7580 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7532 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7581 rev = opts.get('rev')
7533 rev = opts.get('rev')
7582 date = opts.get('date')
7534 date = opts.get('date')
7583 clean = opts.get('clean')
7535 clean = opts.get('clean')
7584 check = opts.get('check')
7536 check = opts.get('check')
7585 merge = opts.get('merge')
7537 merge = opts.get('merge')
7586 if rev and node:
7538 if rev and node:
7587 raise error.Abort(_(b"please specify just one revision"))
7539 raise error.Abort(_(b"please specify just one revision"))
7588
7540
7589 if ui.configbool(b'commands', b'update.requiredest'):
7541 if ui.configbool(b'commands', b'update.requiredest'):
7590 if not node and not rev and not date:
7542 if not node and not rev and not date:
7591 raise error.Abort(
7543 raise error.Abort(
7592 _(b'you must specify a destination'),
7544 _(b'you must specify a destination'),
7593 hint=_(b'for example: hg update ".::"'),
7545 hint=_(b'for example: hg update ".::"'),
7594 )
7546 )
7595
7547
7596 if rev is None or rev == b'':
7548 if rev is None or rev == b'':
7597 rev = node
7549 rev = node
7598
7550
7599 if date and rev is not None:
7551 if date and rev is not None:
7600 raise error.Abort(_(b"you can't specify a revision and a date"))
7552 raise error.Abort(_(b"you can't specify a revision and a date"))
7601
7553
7602 updatecheck = None
7554 updatecheck = None
7603 if check:
7555 if check:
7604 updatecheck = b'abort'
7556 updatecheck = b'abort'
7605 elif merge:
7557 elif merge:
7606 updatecheck = b'none'
7558 updatecheck = b'none'
7607
7559
7608 with repo.wlock():
7560 with repo.wlock():
7609 cmdutil.clearunfinished(repo)
7561 cmdutil.clearunfinished(repo)
7610 if date:
7562 if date:
7611 rev = cmdutil.finddate(ui, repo, date)
7563 rev = cmdutil.finddate(ui, repo, date)
7612
7564
7613 # if we defined a bookmark, we have to remember the original name
7565 # if we defined a bookmark, we have to remember the original name
7614 brev = rev
7566 brev = rev
7615 if rev:
7567 if rev:
7616 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7568 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7617 ctx = scmutil.revsingle(repo, rev, default=None)
7569 ctx = scmutil.revsingle(repo, rev, default=None)
7618 rev = ctx.rev()
7570 rev = ctx.rev()
7619 hidden = ctx.hidden()
7571 hidden = ctx.hidden()
7620 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7572 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7621 with ui.configoverride(overrides, b'update'):
7573 with ui.configoverride(overrides, b'update'):
7622 ret = hg.updatetotally(
7574 ret = hg.updatetotally(
7623 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7575 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7624 )
7576 )
7625 if hidden:
7577 if hidden:
7626 ctxstr = ctx.hex()[:12]
7578 ctxstr = ctx.hex()[:12]
7627 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7579 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7628
7580
7629 if ctx.obsolete():
7581 if ctx.obsolete():
7630 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7582 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7631 ui.warn(b"(%s)\n" % obsfatemsg)
7583 ui.warn(b"(%s)\n" % obsfatemsg)
7632 return ret
7584 return ret
7633
7585
7634
7586
7635 @command(
7587 @command(
7636 b'verify',
7588 b'verify',
7637 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7589 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7638 helpcategory=command.CATEGORY_MAINTENANCE,
7590 helpcategory=command.CATEGORY_MAINTENANCE,
7639 )
7591 )
7640 def verify(ui, repo, **opts):
7592 def verify(ui, repo, **opts):
7641 """verify the integrity of the repository
7593 """verify the integrity of the repository
7642
7594
7643 Verify the integrity of the current repository.
7595 Verify the integrity of the current repository.
7644
7596
7645 This will perform an extensive check of the repository's
7597 This will perform an extensive check of the repository's
7646 integrity, validating the hashes and checksums of each entry in
7598 integrity, validating the hashes and checksums of each entry in
7647 the changelog, manifest, and tracked files, as well as the
7599 the changelog, manifest, and tracked files, as well as the
7648 integrity of their crosslinks and indices.
7600 integrity of their crosslinks and indices.
7649
7601
7650 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7602 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7651 for more information about recovery from corruption of the
7603 for more information about recovery from corruption of the
7652 repository.
7604 repository.
7653
7605
7654 Returns 0 on success, 1 if errors are encountered.
7606 Returns 0 on success, 1 if errors are encountered.
7655 """
7607 """
7656 opts = pycompat.byteskwargs(opts)
7608 opts = pycompat.byteskwargs(opts)
7657
7609
7658 level = None
7610 level = None
7659 if opts[b'full']:
7611 if opts[b'full']:
7660 level = verifymod.VERIFY_FULL
7612 level = verifymod.VERIFY_FULL
7661 return hg.verify(repo, level)
7613 return hg.verify(repo, level)
7662
7614
7663
7615
7664 @command(
7616 @command(
7665 b'version',
7617 b'version',
7666 [] + formatteropts,
7618 [] + formatteropts,
7667 helpcategory=command.CATEGORY_HELP,
7619 helpcategory=command.CATEGORY_HELP,
7668 norepo=True,
7620 norepo=True,
7669 intents={INTENT_READONLY},
7621 intents={INTENT_READONLY},
7670 )
7622 )
7671 def version_(ui, **opts):
7623 def version_(ui, **opts):
7672 """output version and copyright information
7624 """output version and copyright information
7673
7625
7674 .. container:: verbose
7626 .. container:: verbose
7675
7627
7676 Template:
7628 Template:
7677
7629
7678 The following keywords are supported. See also :hg:`help templates`.
7630 The following keywords are supported. See also :hg:`help templates`.
7679
7631
7680 :extensions: List of extensions.
7632 :extensions: List of extensions.
7681 :ver: String. Version number.
7633 :ver: String. Version number.
7682
7634
7683 And each entry of ``{extensions}`` provides the following sub-keywords
7635 And each entry of ``{extensions}`` provides the following sub-keywords
7684 in addition to ``{ver}``.
7636 in addition to ``{ver}``.
7685
7637
7686 :bundled: Boolean. True if included in the release.
7638 :bundled: Boolean. True if included in the release.
7687 :name: String. Extension name.
7639 :name: String. Extension name.
7688 """
7640 """
7689 opts = pycompat.byteskwargs(opts)
7641 opts = pycompat.byteskwargs(opts)
7690 if ui.verbose:
7642 if ui.verbose:
7691 ui.pager(b'version')
7643 ui.pager(b'version')
7692 fm = ui.formatter(b"version", opts)
7644 fm = ui.formatter(b"version", opts)
7693 fm.startitem()
7645 fm.startitem()
7694 fm.write(
7646 fm.write(
7695 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7647 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7696 )
7648 )
7697 license = _(
7649 license = _(
7698 b"(see https://mercurial-scm.org for more information)\n"
7650 b"(see https://mercurial-scm.org for more information)\n"
7699 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7651 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7700 b"This is free software; see the source for copying conditions. "
7652 b"This is free software; see the source for copying conditions. "
7701 b"There is NO\nwarranty; "
7653 b"There is NO\nwarranty; "
7702 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7654 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7703 )
7655 )
7704 if not ui.quiet:
7656 if not ui.quiet:
7705 fm.plain(license)
7657 fm.plain(license)
7706
7658
7707 if ui.verbose:
7659 if ui.verbose:
7708 fm.plain(_(b"\nEnabled extensions:\n\n"))
7660 fm.plain(_(b"\nEnabled extensions:\n\n"))
7709 # format names and versions into columns
7661 # format names and versions into columns
7710 names = []
7662 names = []
7711 vers = []
7663 vers = []
7712 isinternals = []
7664 isinternals = []
7713 for name, module in sorted(extensions.extensions()):
7665 for name, module in sorted(extensions.extensions()):
7714 names.append(name)
7666 names.append(name)
7715 vers.append(extensions.moduleversion(module) or None)
7667 vers.append(extensions.moduleversion(module) or None)
7716 isinternals.append(extensions.ismoduleinternal(module))
7668 isinternals.append(extensions.ismoduleinternal(module))
7717 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7669 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7718 if names:
7670 if names:
7719 namefmt = b" %%-%ds " % max(len(n) for n in names)
7671 namefmt = b" %%-%ds " % max(len(n) for n in names)
7720 places = [_(b"external"), _(b"internal")]
7672 places = [_(b"external"), _(b"internal")]
7721 for n, v, p in zip(names, vers, isinternals):
7673 for n, v, p in zip(names, vers, isinternals):
7722 fn.startitem()
7674 fn.startitem()
7723 fn.condwrite(ui.verbose, b"name", namefmt, n)
7675 fn.condwrite(ui.verbose, b"name", namefmt, n)
7724 if ui.verbose:
7676 if ui.verbose:
7725 fn.plain(b"%s " % places[p])
7677 fn.plain(b"%s " % places[p])
7726 fn.data(bundled=p)
7678 fn.data(bundled=p)
7727 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7679 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7728 if ui.verbose:
7680 if ui.verbose:
7729 fn.plain(b"\n")
7681 fn.plain(b"\n")
7730 fn.end()
7682 fn.end()
7731 fm.end()
7683 fm.end()
7732
7684
7733
7685
7734 def loadcmdtable(ui, name, cmdtable):
7686 def loadcmdtable(ui, name, cmdtable):
7735 """Load command functions from specified cmdtable
7687 """Load command functions from specified cmdtable
7736 """
7688 """
7737 overrides = [cmd for cmd in cmdtable if cmd in table]
7689 overrides = [cmd for cmd in cmdtable if cmd in table]
7738 if overrides:
7690 if overrides:
7739 ui.warn(
7691 ui.warn(
7740 _(b"extension '%s' overrides commands: %s\n")
7692 _(b"extension '%s' overrides commands: %s\n")
7741 % (name, b" ".join(overrides))
7693 % (name, b" ".join(overrides))
7742 )
7694 )
7743 table.update(cmdtable)
7695 table.update(cmdtable)
@@ -1,129 +1,188 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
11 import errno
12
12
13 from .i18n import _
13 from .i18n import _
14
14
15 from . import (
15 from . import (
16 error,
16 error,
17 match as matchmod,
17 pycompat,
18 pycompat,
18 scmutil,
19 scmutil,
19 util,
20 util,
20 )
21 )
21
22
22
23
23 def matchlines(body, regexp):
24 def matchlines(body, regexp):
24 begin = 0
25 begin = 0
25 linenum = 0
26 linenum = 0
26 while begin < len(body):
27 while begin < len(body):
27 match = regexp.search(body, begin)
28 match = regexp.search(body, begin)
28 if not match:
29 if not match:
29 break
30 break
30 mstart, mend = match.span()
31 mstart, mend = match.span()
31 linenum += body.count(b'\n', begin, mstart) + 1
32 linenum += body.count(b'\n', begin, mstart) + 1
32 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
33 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
33 begin = body.find(b'\n', mend) + 1 or len(body) + 1
34 begin = body.find(b'\n', mend) + 1 or len(body) + 1
34 lend = begin - 1
35 lend = begin - 1
35 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
36 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
36
37
37
38
38 class linestate(object):
39 class linestate(object):
39 def __init__(self, line, linenum, colstart, colend):
40 def __init__(self, line, linenum, colstart, colend):
40 self.line = line
41 self.line = line
41 self.linenum = linenum
42 self.linenum = linenum
42 self.colstart = colstart
43 self.colstart = colstart
43 self.colend = colend
44 self.colend = colend
44
45
45 def __hash__(self):
46 def __hash__(self):
46 return hash(self.line)
47 return hash(self.line)
47
48
48 def __eq__(self, other):
49 def __eq__(self, other):
49 return self.line == other.line
50 return self.line == other.line
50
51
51 def findpos(self, regexp):
52 def findpos(self, regexp):
52 """Iterate all (start, end) indices of matches"""
53 """Iterate all (start, end) indices of matches"""
53 yield self.colstart, self.colend
54 yield self.colstart, self.colend
54 p = self.colend
55 p = self.colend
55 while p < len(self.line):
56 while p < len(self.line):
56 m = regexp.search(self.line, p)
57 m = regexp.search(self.line, p)
57 if not m:
58 if not m:
58 break
59 break
59 if m.end() == p:
60 if m.end() == p:
60 p += 1
61 p += 1
61 else:
62 else:
62 yield m.span()
63 yield m.span()
63 p = m.end()
64 p = m.end()
64
65
65
66
66 def difflinestates(a, b):
67 def difflinestates(a, b):
67 sm = difflib.SequenceMatcher(None, a, b)
68 sm = difflib.SequenceMatcher(None, a, b)
68 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
69 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
69 if tag == 'insert':
70 if tag == 'insert':
70 for i in pycompat.xrange(blo, bhi):
71 for i in pycompat.xrange(blo, bhi):
71 yield (b'+', b[i])
72 yield (b'+', b[i])
72 elif tag == 'delete':
73 elif tag == 'delete':
73 for i in pycompat.xrange(alo, ahi):
74 for i in pycompat.xrange(alo, ahi):
74 yield (b'-', a[i])
75 yield (b'-', a[i])
75 elif tag == 'replace':
76 elif tag == 'replace':
76 for i in pycompat.xrange(alo, ahi):
77 for i in pycompat.xrange(alo, ahi):
77 yield (b'-', a[i])
78 yield (b'-', a[i])
78 for i in pycompat.xrange(blo, bhi):
79 for i in pycompat.xrange(blo, bhi):
79 yield (b'+', b[i])
80 yield (b'+', b[i])
80
81
81
82
82 class grepsearcher(object):
83 class grepsearcher(object):
83 """Search files and revisions for lines matching the given pattern"""
84 """Search files and revisions for lines matching the given pattern
84
85
85 def __init__(self, ui, repo, regexp):
86 Options:
87 - all_files to search unchanged files at that revision.
88 - diff to search files in the parent revision so diffs can be generated.
89 - follow to skip files across copies and renames.
90 """
91
92 def __init__(
93 self, ui, repo, regexp, all_files=False, diff=False, follow=False
94 ):
86 self._ui = ui
95 self._ui = ui
87 self._repo = repo
96 self._repo = repo
88 self._regexp = regexp
97 self._regexp = regexp
98 self._all_files = all_files
99 self._diff = diff
100 self._follow = follow
89
101
90 self._getfile = util.lrucachefunc(repo.file)
102 self._getfile = util.lrucachefunc(repo.file)
91 self._getrenamed = scmutil.getrenamedfn(repo)
103 self._getrenamed = scmutil.getrenamedfn(repo)
92
104
93 self._matches = {}
105 self._matches = {}
94 self._copies = {}
106 self._copies = {}
95 self._skip = set()
107 self._skip = set()
96 self._revfiles = {}
108 self._revfiles = {}
97
109
98 def _grepbody(self, fn, rev, body):
110 def _grepbody(self, fn, rev, body):
99 self._matches[rev].setdefault(fn, [])
111 self._matches[rev].setdefault(fn, [])
100 m = self._matches[rev][fn]
112 m = self._matches[rev][fn]
101 if body is None:
113 if body is None:
102 return
114 return
103
115
104 for lnum, cstart, cend, line in matchlines(body, self._regexp):
116 for lnum, cstart, cend, line in matchlines(body, self._regexp):
105 s = linestate(line, lnum, cstart, cend)
117 s = linestate(line, lnum, cstart, cend)
106 m.append(s)
118 m.append(s)
107
119
108 def _readfile(self, ctx, fn):
120 def _readfile(self, ctx, fn):
109 rev = ctx.rev()
121 rev = ctx.rev()
110 if rev is None:
122 if rev is None:
111 fctx = ctx[fn]
123 fctx = ctx[fn]
112 try:
124 try:
113 return fctx.data()
125 return fctx.data()
114 except IOError as e:
126 except IOError as e:
115 if e.errno != errno.ENOENT:
127 if e.errno != errno.ENOENT:
116 raise
128 raise
117 else:
129 else:
118 flog = self._getfile(fn)
130 flog = self._getfile(fn)
119 fnode = ctx.filenode(fn)
131 fnode = ctx.filenode(fn)
120 try:
132 try:
121 return flog.read(fnode)
133 return flog.read(fnode)
122 except error.CensoredNodeError:
134 except error.CensoredNodeError:
123 self._ui.warn(
135 self._ui.warn(
124 _(
136 _(
125 b'cannot search in censored file: '
137 b'cannot search in censored file: '
126 b'%(filename)s:%(revnum)s\n'
138 b'%(filename)s:%(revnum)s\n'
127 )
139 )
128 % {b'filename': fn, b'revnum': pycompat.bytestr(rev)}
140 % {b'filename': fn, b'revnum': pycompat.bytestr(rev)}
129 )
141 )
142
143 def _prep(self, ctx, fmatch):
144 rev = ctx.rev()
145 pctx = ctx.p1()
146 self._matches.setdefault(rev, {})
147 if self._diff:
148 parent = pctx.rev()
149 self._matches.setdefault(parent, {})
150 files = self._revfiles.setdefault(rev, [])
151 if rev is None:
152 # in `hg grep pattern`, 2/3 of the time is spent is spent in
153 # pathauditor checks without this in mozilla-central
154 contextmanager = self._repo.wvfs.audit.cached
155 else:
156 contextmanager = util.nullcontextmanager
157 with contextmanager():
158 # TODO: maybe better to warn missing files?
159 if self._all_files:
160 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
161 filenames = ctx.matches(fmatch)
162 else:
163 filenames = (f for f in ctx.files() if fmatch(f))
164 for fn in filenames:
165 # fn might not exist in the revision (could be a file removed by
166 # the revision). We could check `fn not in ctx` even when rev is
167 # None, but it's less racy to protect againt that in readfile.
168 if rev is not None and fn not in ctx:
169 continue
170
171 copy = None
172 if self._follow:
173 copy = self._getrenamed(fn, rev)
174 if copy:
175 self._copies.setdefault(rev, {})[fn] = copy
176 if fn in self._skip:
177 self._skip.add(copy)
178 if fn in self._skip:
179 continue
180 files.append(fn)
181
182 if fn not in self._matches[rev]:
183 self._grepbody(fn, rev, self._readfile(ctx, fn))
184
185 if self._diff:
186 pfn = copy or fn
187 if pfn not in self._matches[parent] and pfn in pctx:
188 self._grepbody(pfn, parent, self._readfile(pctx, pfn))
General Comments 0
You need to be logged in to leave comments. Login now