##// END OF EJS Templates
grep: extract main search loop as searcher method...
Yuya Nishihara -
r46313:f9d3ff23 default
parent child Browse files
Show More
@@ -1,7693 +1,7671 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 merge as mergemod,
48 merge as mergemod,
49 mergestate as mergestatemod,
49 mergestate as mergestatemod,
50 narrowspec,
50 narrowspec,
51 obsolete,
51 obsolete,
52 obsutil,
52 obsutil,
53 patch,
53 patch,
54 phases,
54 phases,
55 pycompat,
55 pycompat,
56 rcutil,
56 rcutil,
57 registrar,
57 registrar,
58 requirements,
58 requirements,
59 revsetlang,
59 revsetlang,
60 rewriteutil,
60 rewriteutil,
61 scmutil,
61 scmutil,
62 server,
62 server,
63 shelve as shelvemod,
63 shelve as shelvemod,
64 state as statemod,
64 state as statemod,
65 streamclone,
65 streamclone,
66 tags as tagsmod,
66 tags as tagsmod,
67 ui as uimod,
67 ui as uimod,
68 util,
68 util,
69 verify as verifymod,
69 verify as verifymod,
70 vfs as vfsmod,
70 vfs as vfsmod,
71 wireprotoserver,
71 wireprotoserver,
72 )
72 )
73 from .utils import (
73 from .utils import (
74 dateutil,
74 dateutil,
75 stringutil,
75 stringutil,
76 )
76 )
77
77
78 table = {}
78 table = {}
79 table.update(debugcommandsmod.command._table)
79 table.update(debugcommandsmod.command._table)
80
80
81 command = registrar.command(table)
81 command = registrar.command(table)
82 INTENT_READONLY = registrar.INTENT_READONLY
82 INTENT_READONLY = registrar.INTENT_READONLY
83
83
84 # common command options
84 # common command options
85
85
86 globalopts = [
86 globalopts = [
87 (
87 (
88 b'R',
88 b'R',
89 b'repository',
89 b'repository',
90 b'',
90 b'',
91 _(b'repository root directory or name of overlay bundle file'),
91 _(b'repository root directory or name of overlay bundle file'),
92 _(b'REPO'),
92 _(b'REPO'),
93 ),
93 ),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
94 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (
95 (
96 b'y',
96 b'y',
97 b'noninteractive',
97 b'noninteractive',
98 None,
98 None,
99 _(
99 _(
100 b'do not prompt, automatically pick the first choice for all prompts'
100 b'do not prompt, automatically pick the first choice for all prompts'
101 ),
101 ),
102 ),
102 ),
103 (b'q', b'quiet', None, _(b'suppress output')),
103 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
104 (b'v', b'verbose', None, _(b'enable additional output')),
105 (
105 (
106 b'',
106 b'',
107 b'color',
107 b'color',
108 b'',
108 b'',
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
109 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # and should not be translated
110 # and should not be translated
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
111 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b'TYPE'),
112 _(b'TYPE'),
113 ),
113 ),
114 (
114 (
115 b'',
115 b'',
116 b'config',
116 b'config',
117 [],
117 [],
118 _(b'set/override config option (use \'section.name=value\')'),
118 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'CONFIG'),
119 _(b'CONFIG'),
120 ),
120 ),
121 (b'', b'debug', None, _(b'enable debugging output')),
121 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debugger', None, _(b'start debugger')),
122 (b'', b'debugger', None, _(b'start debugger')),
123 (
123 (
124 b'',
124 b'',
125 b'encoding',
125 b'encoding',
126 encoding.encoding,
126 encoding.encoding,
127 _(b'set the charset encoding'),
127 _(b'set the charset encoding'),
128 _(b'ENCODE'),
128 _(b'ENCODE'),
129 ),
129 ),
130 (
130 (
131 b'',
131 b'',
132 b'encodingmode',
132 b'encodingmode',
133 encoding.encodingmode,
133 encoding.encodingmode,
134 _(b'set the charset encoding mode'),
134 _(b'set the charset encoding mode'),
135 _(b'MODE'),
135 _(b'MODE'),
136 ),
136 ),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
137 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'time', None, _(b'time how long the command takes')),
138 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'profile', None, _(b'print command execution profile')),
139 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'version', None, _(b'output version information and exit')),
140 (b'', b'version', None, _(b'output version information and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
141 (b'h', b'help', None, _(b'display help and exit')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
142 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (
143 (
144 b'',
144 b'',
145 b'pager',
145 b'pager',
146 b'auto',
146 b'auto',
147 _(b"when to paginate (boolean, always, auto, or never)"),
147 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b'TYPE'),
148 _(b'TYPE'),
149 ),
149 ),
150 ]
150 ]
151
151
152 dryrunopts = cmdutil.dryrunopts
152 dryrunopts = cmdutil.dryrunopts
153 remoteopts = cmdutil.remoteopts
153 remoteopts = cmdutil.remoteopts
154 walkopts = cmdutil.walkopts
154 walkopts = cmdutil.walkopts
155 commitopts = cmdutil.commitopts
155 commitopts = cmdutil.commitopts
156 commitopts2 = cmdutil.commitopts2
156 commitopts2 = cmdutil.commitopts2
157 commitopts3 = cmdutil.commitopts3
157 commitopts3 = cmdutil.commitopts3
158 formatteropts = cmdutil.formatteropts
158 formatteropts = cmdutil.formatteropts
159 templateopts = cmdutil.templateopts
159 templateopts = cmdutil.templateopts
160 logopts = cmdutil.logopts
160 logopts = cmdutil.logopts
161 diffopts = cmdutil.diffopts
161 diffopts = cmdutil.diffopts
162 diffwsopts = cmdutil.diffwsopts
162 diffwsopts = cmdutil.diffwsopts
163 diffopts2 = cmdutil.diffopts2
163 diffopts2 = cmdutil.diffopts2
164 mergetoolopts = cmdutil.mergetoolopts
164 mergetoolopts = cmdutil.mergetoolopts
165 similarityopts = cmdutil.similarityopts
165 similarityopts = cmdutil.similarityopts
166 subrepoopts = cmdutil.subrepoopts
166 subrepoopts = cmdutil.subrepoopts
167 debugrevlogopts = cmdutil.debugrevlogopts
167 debugrevlogopts = cmdutil.debugrevlogopts
168
168
169 # Commands start here, listed alphabetically
169 # Commands start here, listed alphabetically
170
170
171
171
172 @command(
172 @command(
173 b'abort',
173 b'abort',
174 dryrunopts,
174 dryrunopts,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
175 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpbasic=True,
176 helpbasic=True,
177 )
177 )
178 def abort(ui, repo, **opts):
178 def abort(ui, repo, **opts):
179 """abort an unfinished operation (EXPERIMENTAL)
179 """abort an unfinished operation (EXPERIMENTAL)
180
180
181 Aborts a multistep operation like graft, histedit, rebase, merge,
181 Aborts a multistep operation like graft, histedit, rebase, merge,
182 and unshelve if they are in an unfinished state.
182 and unshelve if they are in an unfinished state.
183
183
184 use --dry-run/-n to dry run the command.
184 use --dry-run/-n to dry run the command.
185 """
185 """
186 dryrun = opts.get('dry_run')
186 dryrun = opts.get('dry_run')
187 abortstate = cmdutil.getunfinishedstate(repo)
187 abortstate = cmdutil.getunfinishedstate(repo)
188 if not abortstate:
188 if not abortstate:
189 raise error.Abort(_(b'no operation in progress'))
189 raise error.Abort(_(b'no operation in progress'))
190 if not abortstate.abortfunc:
190 if not abortstate.abortfunc:
191 raise error.Abort(
191 raise error.Abort(
192 (
192 (
193 _(b"%s in progress but does not support 'hg abort'")
193 _(b"%s in progress but does not support 'hg abort'")
194 % (abortstate._opname)
194 % (abortstate._opname)
195 ),
195 ),
196 hint=abortstate.hint(),
196 hint=abortstate.hint(),
197 )
197 )
198 if dryrun:
198 if dryrun:
199 ui.status(
199 ui.status(
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
200 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 )
201 )
202 return
202 return
203 return abortstate.abortfunc(ui, repo)
203 return abortstate.abortfunc(ui, repo)
204
204
205
205
206 @command(
206 @command(
207 b'add',
207 b'add',
208 walkopts + subrepoopts + dryrunopts,
208 walkopts + subrepoopts + dryrunopts,
209 _(b'[OPTION]... [FILE]...'),
209 _(b'[OPTION]... [FILE]...'),
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpbasic=True,
211 helpbasic=True,
212 inferrepo=True,
212 inferrepo=True,
213 )
213 )
214 def add(ui, repo, *pats, **opts):
214 def add(ui, repo, *pats, **opts):
215 """add the specified files on the next commit
215 """add the specified files on the next commit
216
216
217 Schedule files to be version controlled and added to the
217 Schedule files to be version controlled and added to the
218 repository.
218 repository.
219
219
220 The files will be added to the repository at the next commit. To
220 The files will be added to the repository at the next commit. To
221 undo an add before that, see :hg:`forget`.
221 undo an add before that, see :hg:`forget`.
222
222
223 If no names are given, add all files to the repository (except
223 If no names are given, add all files to the repository (except
224 files matching ``.hgignore``).
224 files matching ``.hgignore``).
225
225
226 .. container:: verbose
226 .. container:: verbose
227
227
228 Examples:
228 Examples:
229
229
230 - New (unknown) files are added
230 - New (unknown) files are added
231 automatically by :hg:`add`::
231 automatically by :hg:`add`::
232
232
233 $ ls
233 $ ls
234 foo.c
234 foo.c
235 $ hg status
235 $ hg status
236 ? foo.c
236 ? foo.c
237 $ hg add
237 $ hg add
238 adding foo.c
238 adding foo.c
239 $ hg status
239 $ hg status
240 A foo.c
240 A foo.c
241
241
242 - Specific files to be added can be specified::
242 - Specific files to be added can be specified::
243
243
244 $ ls
244 $ ls
245 bar.c foo.c
245 bar.c foo.c
246 $ hg status
246 $ hg status
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg add bar.c
249 $ hg add bar.c
250 $ hg status
250 $ hg status
251 A bar.c
251 A bar.c
252 ? foo.c
252 ? foo.c
253
253
254 Returns 0 if all files are successfully added.
254 Returns 0 if all files are successfully added.
255 """
255 """
256
256
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
257 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
258 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
259 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 return rejected and 1 or 0
260 return rejected and 1 or 0
261
261
262
262
263 @command(
263 @command(
264 b'addremove',
264 b'addremove',
265 similarityopts + subrepoopts + walkopts + dryrunopts,
265 similarityopts + subrepoopts + walkopts + dryrunopts,
266 _(b'[OPTION]... [FILE]...'),
266 _(b'[OPTION]... [FILE]...'),
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
267 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 inferrepo=True,
268 inferrepo=True,
269 )
269 )
270 def addremove(ui, repo, *pats, **opts):
270 def addremove(ui, repo, *pats, **opts):
271 """add all new files, delete all missing files
271 """add all new files, delete all missing files
272
272
273 Add all new files and remove all missing files from the
273 Add all new files and remove all missing files from the
274 repository.
274 repository.
275
275
276 Unless names are given, new files are ignored if they match any of
276 Unless names are given, new files are ignored if they match any of
277 the patterns in ``.hgignore``. As with add, these changes take
277 the patterns in ``.hgignore``. As with add, these changes take
278 effect at the next commit.
278 effect at the next commit.
279
279
280 Use the -s/--similarity option to detect renamed files. This
280 Use the -s/--similarity option to detect renamed files. This
281 option takes a percentage between 0 (disabled) and 100 (files must
281 option takes a percentage between 0 (disabled) and 100 (files must
282 be identical) as its parameter. With a parameter greater than 0,
282 be identical) as its parameter. With a parameter greater than 0,
283 this compares every removed file with every added file and records
283 this compares every removed file with every added file and records
284 those similar enough as renames. Detecting renamed files this way
284 those similar enough as renames. Detecting renamed files this way
285 can be expensive. After using this option, :hg:`status -C` can be
285 can be expensive. After using this option, :hg:`status -C` can be
286 used to check which files were identified as moved or renamed. If
286 used to check which files were identified as moved or renamed. If
287 not specified, -s/--similarity defaults to 100 and only renames of
287 not specified, -s/--similarity defaults to 100 and only renames of
288 identical files are detected.
288 identical files are detected.
289
289
290 .. container:: verbose
290 .. container:: verbose
291
291
292 Examples:
292 Examples:
293
293
294 - A number of files (bar.c and foo.c) are new,
294 - A number of files (bar.c and foo.c) are new,
295 while foobar.c has been removed (without using :hg:`remove`)
295 while foobar.c has been removed (without using :hg:`remove`)
296 from the repository::
296 from the repository::
297
297
298 $ ls
298 $ ls
299 bar.c foo.c
299 bar.c foo.c
300 $ hg status
300 $ hg status
301 ! foobar.c
301 ! foobar.c
302 ? bar.c
302 ? bar.c
303 ? foo.c
303 ? foo.c
304 $ hg addremove
304 $ hg addremove
305 adding bar.c
305 adding bar.c
306 adding foo.c
306 adding foo.c
307 removing foobar.c
307 removing foobar.c
308 $ hg status
308 $ hg status
309 A bar.c
309 A bar.c
310 A foo.c
310 A foo.c
311 R foobar.c
311 R foobar.c
312
312
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
313 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 Afterwards, it was edited slightly::
314 Afterwards, it was edited slightly::
315
315
316 $ ls
316 $ ls
317 foo.c
317 foo.c
318 $ hg status
318 $ hg status
319 ! foobar.c
319 ! foobar.c
320 ? foo.c
320 ? foo.c
321 $ hg addremove --similarity 90
321 $ hg addremove --similarity 90
322 removing foobar.c
322 removing foobar.c
323 adding foo.c
323 adding foo.c
324 recording removal of foobar.c as rename to foo.c (94% similar)
324 recording removal of foobar.c as rename to foo.c (94% similar)
325 $ hg status -C
325 $ hg status -C
326 A foo.c
326 A foo.c
327 foobar.c
327 foobar.c
328 R foobar.c
328 R foobar.c
329
329
330 Returns 0 if all files are successfully added.
330 Returns 0 if all files are successfully added.
331 """
331 """
332 opts = pycompat.byteskwargs(opts)
332 opts = pycompat.byteskwargs(opts)
333 if not opts.get(b'similarity'):
333 if not opts.get(b'similarity'):
334 opts[b'similarity'] = b'100'
334 opts[b'similarity'] = b'100'
335 matcher = scmutil.match(repo[None], pats, opts)
335 matcher = scmutil.match(repo[None], pats, opts)
336 relative = scmutil.anypats(pats, opts)
336 relative = scmutil.anypats(pats, opts)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
337 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
338 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339
339
340
340
341 @command(
341 @command(
342 b'annotate|blame',
342 b'annotate|blame',
343 [
343 [
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
344 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (
345 (
346 b'',
346 b'',
347 b'follow',
347 b'follow',
348 None,
348 None,
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
349 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 ),
350 ),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
351 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'a', b'text', None, _(b'treat all files as text')),
352 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
353 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'f', b'file', None, _(b'list the filename')),
354 (b'f', b'file', None, _(b'list the filename')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
355 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
356 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
357 (b'c', b'changeset', None, _(b'list the changeset')),
358 (
358 (
359 b'l',
359 b'l',
360 b'line-number',
360 b'line-number',
361 None,
361 None,
362 _(b'show line number at the first appearance'),
362 _(b'show line number at the first appearance'),
363 ),
363 ),
364 (
364 (
365 b'',
365 b'',
366 b'skip',
366 b'skip',
367 [],
367 [],
368 _(b'revset to not display (EXPERIMENTAL)'),
368 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'REV'),
369 _(b'REV'),
370 ),
370 ),
371 ]
371 ]
372 + diffwsopts
372 + diffwsopts
373 + walkopts
373 + walkopts
374 + formatteropts,
374 + formatteropts,
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
375 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
376 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpbasic=True,
377 helpbasic=True,
378 inferrepo=True,
378 inferrepo=True,
379 )
379 )
380 def annotate(ui, repo, *pats, **opts):
380 def annotate(ui, repo, *pats, **opts):
381 """show changeset information by line for each file
381 """show changeset information by line for each file
382
382
383 List changes in files, showing the revision id responsible for
383 List changes in files, showing the revision id responsible for
384 each line.
384 each line.
385
385
386 This command is useful for discovering when a change was made and
386 This command is useful for discovering when a change was made and
387 by whom.
387 by whom.
388
388
389 If you include --file, --user, or --date, the revision number is
389 If you include --file, --user, or --date, the revision number is
390 suppressed unless you also include --number.
390 suppressed unless you also include --number.
391
391
392 Without the -a/--text option, annotate will avoid processing files
392 Without the -a/--text option, annotate will avoid processing files
393 it detects as binary. With -a, annotate will annotate the file
393 it detects as binary. With -a, annotate will annotate the file
394 anyway, although the results will probably be neither useful
394 anyway, although the results will probably be neither useful
395 nor desirable.
395 nor desirable.
396
396
397 .. container:: verbose
397 .. container:: verbose
398
398
399 Template:
399 Template:
400
400
401 The following keywords are supported in addition to the common template
401 The following keywords are supported in addition to the common template
402 keywords and functions. See also :hg:`help templates`.
402 keywords and functions. See also :hg:`help templates`.
403
403
404 :lines: List of lines with annotation data.
404 :lines: List of lines with annotation data.
405 :path: String. Repository-absolute path of the specified file.
405 :path: String. Repository-absolute path of the specified file.
406
406
407 And each entry of ``{lines}`` provides the following sub-keywords in
407 And each entry of ``{lines}`` provides the following sub-keywords in
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
408 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409
409
410 :line: String. Line content.
410 :line: String. Line content.
411 :lineno: Integer. Line number at that revision.
411 :lineno: Integer. Line number at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
412 :path: String. Repository-absolute path of the file at that revision.
413
413
414 See :hg:`help templates.operators` for the list expansion syntax.
414 See :hg:`help templates.operators` for the list expansion syntax.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 """
417 """
418 opts = pycompat.byteskwargs(opts)
418 opts = pycompat.byteskwargs(opts)
419 if not pats:
419 if not pats:
420 raise error.Abort(_(b'at least one filename or pattern is required'))
420 raise error.Abort(_(b'at least one filename or pattern is required'))
421
421
422 if opts.get(b'follow'):
422 if opts.get(b'follow'):
423 # --follow is deprecated and now just an alias for -f/--file
423 # --follow is deprecated and now just an alias for -f/--file
424 # to mimic the behavior of Mercurial before version 1.5
424 # to mimic the behavior of Mercurial before version 1.5
425 opts[b'file'] = True
425 opts[b'file'] = True
426
426
427 if (
427 if (
428 not opts.get(b'user')
428 not opts.get(b'user')
429 and not opts.get(b'changeset')
429 and not opts.get(b'changeset')
430 and not opts.get(b'date')
430 and not opts.get(b'date')
431 and not opts.get(b'file')
431 and not opts.get(b'file')
432 ):
432 ):
433 opts[b'number'] = True
433 opts[b'number'] = True
434
434
435 linenumber = opts.get(b'line_number') is not None
435 linenumber = opts.get(b'line_number') is not None
436 if (
436 if (
437 linenumber
437 linenumber
438 and (not opts.get(b'changeset'))
438 and (not opts.get(b'changeset'))
439 and (not opts.get(b'number'))
439 and (not opts.get(b'number'))
440 ):
440 ):
441 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'))
442
442
443 rev = opts.get(b'rev')
443 rev = opts.get(b'rev')
444 if rev:
444 if rev:
445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 ctx = scmutil.revsingle(repo, rev)
446 ctx = scmutil.revsingle(repo, rev)
447
447
448 ui.pager(b'annotate')
448 ui.pager(b'annotate')
449 rootfm = ui.formatter(b'annotate', opts)
449 rootfm = ui.formatter(b'annotate', opts)
450 if ui.debugflag:
450 if ui.debugflag:
451 shorthex = pycompat.identity
451 shorthex = pycompat.identity
452 else:
452 else:
453
453
454 def shorthex(h):
454 def shorthex(h):
455 return h[:12]
455 return h[:12]
456
456
457 if ui.quiet:
457 if ui.quiet:
458 datefunc = dateutil.shortdate
458 datefunc = dateutil.shortdate
459 else:
459 else:
460 datefunc = dateutil.datestr
460 datefunc = dateutil.datestr
461 if ctx.rev() is None:
461 if ctx.rev() is None:
462 if opts.get(b'changeset'):
462 if opts.get(b'changeset'):
463 # omit "+" suffix which is appended to node hex
463 # omit "+" suffix which is appended to node hex
464 def formatrev(rev):
464 def formatrev(rev):
465 if rev == wdirrev:
465 if rev == wdirrev:
466 return b'%d' % ctx.p1().rev()
466 return b'%d' % ctx.p1().rev()
467 else:
467 else:
468 return b'%d' % rev
468 return b'%d' % rev
469
469
470 else:
470 else:
471
471
472 def formatrev(rev):
472 def formatrev(rev):
473 if rev == wdirrev:
473 if rev == wdirrev:
474 return b'%d+' % ctx.p1().rev()
474 return b'%d+' % ctx.p1().rev()
475 else:
475 else:
476 return b'%d ' % rev
476 return b'%d ' % rev
477
477
478 def formathex(h):
478 def formathex(h):
479 if h == wdirhex:
479 if h == wdirhex:
480 return b'%s+' % shorthex(hex(ctx.p1().node()))
480 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 else:
481 else:
482 return b'%s ' % shorthex(h)
482 return b'%s ' % shorthex(h)
483
483
484 else:
484 else:
485 formatrev = b'%d'.__mod__
485 formatrev = b'%d'.__mod__
486 formathex = shorthex
486 formathex = shorthex
487
487
488 opmap = [
488 opmap = [
489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 ]
495 ]
496 opnamemap = {
496 opnamemap = {
497 b'rev': b'number',
497 b'rev': b'number',
498 b'node': b'changeset',
498 b'node': b'changeset',
499 b'path': b'file',
499 b'path': b'file',
500 b'lineno': b'line_number',
500 b'lineno': b'line_number',
501 }
501 }
502
502
503 if rootfm.isplain():
503 if rootfm.isplain():
504
504
505 def makefunc(get, fmt):
505 def makefunc(get, fmt):
506 return lambda x: fmt(get(x))
506 return lambda x: fmt(get(x))
507
507
508 else:
508 else:
509
509
510 def makefunc(get, fmt):
510 def makefunc(get, fmt):
511 return get
511 return get
512
512
513 datahint = rootfm.datahint()
513 datahint = rootfm.datahint()
514 funcmap = [
514 funcmap = [
515 (makefunc(get, fmt), sep)
515 (makefunc(get, fmt), sep)
516 for fn, sep, get, fmt in opmap
516 for fn, sep, get, fmt in opmap
517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 ]
518 ]
519 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
520 fields = b' '.join(
520 fields = b' '.join(
521 fn
521 fn
522 for fn, sep, get, fmt in opmap
522 for fn, sep, get, fmt in opmap
523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 )
524 )
525
525
526 def bad(x, y):
526 def bad(x, y):
527 raise error.Abort(b"%s: %s" % (x, y))
527 raise error.Abort(b"%s: %s" % (x, y))
528
528
529 m = scmutil.match(ctx, pats, opts, badfn=bad)
529 m = scmutil.match(ctx, pats, opts, badfn=bad)
530
530
531 follow = not opts.get(b'no_follow')
531 follow = not opts.get(b'no_follow')
532 diffopts = patch.difffeatureopts(
532 diffopts = patch.difffeatureopts(
533 ui, opts, section=b'annotate', whitespace=True
533 ui, opts, section=b'annotate', whitespace=True
534 )
534 )
535 skiprevs = opts.get(b'skip')
535 skiprevs = opts.get(b'skip')
536 if skiprevs:
536 if skiprevs:
537 skiprevs = scmutil.revrange(repo, skiprevs)
537 skiprevs = scmutil.revrange(repo, skiprevs)
538
538
539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 for abs in ctx.walk(m):
540 for abs in ctx.walk(m):
541 fctx = ctx[abs]
541 fctx = ctx[abs]
542 rootfm.startitem()
542 rootfm.startitem()
543 rootfm.data(path=abs)
543 rootfm.data(path=abs)
544 if not opts.get(b'text') and fctx.isbinary():
544 if not opts.get(b'text') and fctx.isbinary():
545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 continue
546 continue
547
547
548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 lines = fctx.annotate(
549 lines = fctx.annotate(
550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 )
551 )
552 if not lines:
552 if not lines:
553 fm.end()
553 fm.end()
554 continue
554 continue
555 formats = []
555 formats = []
556 pieces = []
556 pieces = []
557
557
558 for f, sep in funcmap:
558 for f, sep in funcmap:
559 l = [f(n) for n in lines]
559 l = [f(n) for n in lines]
560 if fm.isplain():
560 if fm.isplain():
561 sizes = [encoding.colwidth(x) for x in l]
561 sizes = [encoding.colwidth(x) for x in l]
562 ml = max(sizes)
562 ml = max(sizes)
563 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])
564 else:
564 else:
565 formats.append([b'%s'] * len(l))
565 formats.append([b'%s'] * len(l))
566 pieces.append(l)
566 pieces.append(l)
567
567
568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 fm.startitem()
569 fm.startitem()
570 fm.context(fctx=n.fctx)
570 fm.context(fctx=n.fctx)
571 fm.write(fields, b"".join(f), *p)
571 fm.write(fields, b"".join(f), *p)
572 if n.skip:
572 if n.skip:
573 fmt = b"* %s"
573 fmt = b"* %s"
574 else:
574 else:
575 fmt = b": %s"
575 fmt = b": %s"
576 fm.write(b'line', fmt, n.text)
576 fm.write(b'line', fmt, n.text)
577
577
578 if not lines[-1].text.endswith(b'\n'):
578 if not lines[-1].text.endswith(b'\n'):
579 fm.plain(b'\n')
579 fm.plain(b'\n')
580 fm.end()
580 fm.end()
581
581
582 rootfm.end()
582 rootfm.end()
583
583
584
584
585 @command(
585 @command(
586 b'archive',
586 b'archive',
587 [
587 [
588 (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')),
589 (
589 (
590 b'p',
590 b'p',
591 b'prefix',
591 b'prefix',
592 b'',
592 b'',
593 _(b'directory prefix for files in archive'),
593 _(b'directory prefix for files in archive'),
594 _(b'PREFIX'),
594 _(b'PREFIX'),
595 ),
595 ),
596 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
596 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 (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')),
598 ]
598 ]
599 + subrepoopts
599 + subrepoopts
600 + walkopts,
600 + walkopts,
601 _(b'[OPTION]... DEST'),
601 _(b'[OPTION]... DEST'),
602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 )
603 )
604 def archive(ui, repo, dest, **opts):
604 def archive(ui, repo, dest, **opts):
605 '''create an unversioned archive of a repository revision
605 '''create an unversioned archive of a repository revision
606
606
607 By default, the revision used is the parent of the working
607 By default, the revision used is the parent of the working
608 directory; use -r/--rev to specify a different revision.
608 directory; use -r/--rev to specify a different revision.
609
609
610 The archive type is automatically detected based on file
610 The archive type is automatically detected based on file
611 extension (to override, use -t/--type).
611 extension (to override, use -t/--type).
612
612
613 .. container:: verbose
613 .. container:: verbose
614
614
615 Examples:
615 Examples:
616
616
617 - create a zip file containing the 1.0 release::
617 - create a zip file containing the 1.0 release::
618
618
619 hg archive -r 1.0 project-1.0.zip
619 hg archive -r 1.0 project-1.0.zip
620
620
621 - create a tarball excluding .hg files::
621 - create a tarball excluding .hg files::
622
622
623 hg archive project.tar.gz -X ".hg*"
623 hg archive project.tar.gz -X ".hg*"
624
624
625 Valid types are:
625 Valid types are:
626
626
627 :``files``: a directory full of files (default)
627 :``files``: a directory full of files (default)
628 :``tar``: tar archive, uncompressed
628 :``tar``: tar archive, uncompressed
629 :``tbz2``: tar archive, compressed using bzip2
629 :``tbz2``: tar archive, compressed using bzip2
630 :``tgz``: tar archive, compressed using gzip
630 :``tgz``: tar archive, compressed using gzip
631 :``txz``: tar archive, compressed using lzma (only in Python 3)
631 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 :``uzip``: zip archive, uncompressed
632 :``uzip``: zip archive, uncompressed
633 :``zip``: zip archive, compressed using deflate
633 :``zip``: zip archive, compressed using deflate
634
634
635 The exact name of the destination archive or directory is given
635 The exact name of the destination archive or directory is given
636 using a format string; see :hg:`help export` for details.
636 using a format string; see :hg:`help export` for details.
637
637
638 Each member added to an archive file has a directory prefix
638 Each member added to an archive file has a directory prefix
639 prepended. Use -p/--prefix to specify a format string for the
639 prepended. Use -p/--prefix to specify a format string for the
640 prefix. The default is the basename of the archive, with suffixes
640 prefix. The default is the basename of the archive, with suffixes
641 removed.
641 removed.
642
642
643 Returns 0 on success.
643 Returns 0 on success.
644 '''
644 '''
645
645
646 opts = pycompat.byteskwargs(opts)
646 opts = pycompat.byteskwargs(opts)
647 rev = opts.get(b'rev')
647 rev = opts.get(b'rev')
648 if rev:
648 if rev:
649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 ctx = scmutil.revsingle(repo, rev)
650 ctx = scmutil.revsingle(repo, rev)
651 if not ctx:
651 if not ctx:
652 raise error.Abort(_(b'no working directory: please specify a revision'))
652 raise error.Abort(_(b'no working directory: please specify a revision'))
653 node = ctx.node()
653 node = ctx.node()
654 dest = cmdutil.makefilename(ctx, dest)
654 dest = cmdutil.makefilename(ctx, dest)
655 if os.path.realpath(dest) == repo.root:
655 if os.path.realpath(dest) == repo.root:
656 raise error.Abort(_(b'repository root cannot be destination'))
656 raise error.Abort(_(b'repository root cannot be destination'))
657
657
658 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'
659 prefix = opts.get(b'prefix')
659 prefix = opts.get(b'prefix')
660
660
661 if dest == b'-':
661 if dest == b'-':
662 if kind == b'files':
662 if kind == b'files':
663 raise error.Abort(_(b'cannot archive plain files to stdout'))
663 raise error.Abort(_(b'cannot archive plain files to stdout'))
664 dest = cmdutil.makefileobj(ctx, dest)
664 dest = cmdutil.makefileobj(ctx, dest)
665 if not prefix:
665 if not prefix:
666 prefix = os.path.basename(repo.root) + b'-%h'
666 prefix = os.path.basename(repo.root) + b'-%h'
667
667
668 prefix = cmdutil.makefilename(ctx, prefix)
668 prefix = cmdutil.makefilename(ctx, prefix)
669 match = scmutil.match(ctx, [], opts)
669 match = scmutil.match(ctx, [], opts)
670 archival.archive(
670 archival.archive(
671 repo,
671 repo,
672 dest,
672 dest,
673 node,
673 node,
674 kind,
674 kind,
675 not opts.get(b'no_decode'),
675 not opts.get(b'no_decode'),
676 match,
676 match,
677 prefix,
677 prefix,
678 subrepos=opts.get(b'subrepos'),
678 subrepos=opts.get(b'subrepos'),
679 )
679 )
680
680
681
681
682 @command(
682 @command(
683 b'backout',
683 b'backout',
684 [
684 [
685 (
685 (
686 b'',
686 b'',
687 b'merge',
687 b'merge',
688 None,
688 None,
689 _(b'merge with old dirstate parent after backout'),
689 _(b'merge with old dirstate parent after backout'),
690 ),
690 ),
691 (
691 (
692 b'',
692 b'',
693 b'commit',
693 b'commit',
694 None,
694 None,
695 _(b'commit if no conflicts were encountered (DEPRECATED)'),
695 _(b'commit if no conflicts were encountered (DEPRECATED)'),
696 ),
696 ),
697 (b'', b'no-commit', None, _(b'do not commit')),
697 (b'', b'no-commit', None, _(b'do not commit')),
698 (
698 (
699 b'',
699 b'',
700 b'parent',
700 b'parent',
701 b'',
701 b'',
702 _(b'parent to choose when backing out merge (DEPRECATED)'),
702 _(b'parent to choose when backing out merge (DEPRECATED)'),
703 _(b'REV'),
703 _(b'REV'),
704 ),
704 ),
705 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
705 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
706 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
706 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
707 ]
707 ]
708 + mergetoolopts
708 + mergetoolopts
709 + walkopts
709 + walkopts
710 + commitopts
710 + commitopts
711 + commitopts2,
711 + commitopts2,
712 _(b'[OPTION]... [-r] REV'),
712 _(b'[OPTION]... [-r] REV'),
713 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
713 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
714 )
714 )
715 def backout(ui, repo, node=None, rev=None, **opts):
715 def backout(ui, repo, node=None, rev=None, **opts):
716 '''reverse effect of earlier changeset
716 '''reverse effect of earlier changeset
717
717
718 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
719 current working directory. If no conflicts were encountered,
719 current working directory. If no conflicts were encountered,
720 it will be committed immediately.
720 it will be committed immediately.
721
721
722 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
723 is committed automatically (unless --no-commit is specified).
723 is committed automatically (unless --no-commit is specified).
724
724
725 .. note::
725 .. note::
726
726
727 :hg:`backout` cannot be used to fix either an unwanted or
727 :hg:`backout` cannot be used to fix either an unwanted or
728 incorrect merge.
728 incorrect merge.
729
729
730 .. container:: verbose
730 .. container:: verbose
731
731
732 Examples:
732 Examples:
733
733
734 - Reverse the effect of the parent of the working directory.
734 - Reverse the effect of the parent of the working directory.
735 This backout will be committed immediately::
735 This backout will be committed immediately::
736
736
737 hg backout -r .
737 hg backout -r .
738
738
739 - Reverse the effect of previous bad revision 23::
739 - Reverse the effect of previous bad revision 23::
740
740
741 hg backout -r 23
741 hg backout -r 23
742
742
743 - Reverse the effect of previous bad revision 23 and
743 - Reverse the effect of previous bad revision 23 and
744 leave changes uncommitted::
744 leave changes uncommitted::
745
745
746 hg backout -r 23 --no-commit
746 hg backout -r 23 --no-commit
747 hg commit -m "Backout revision 23"
747 hg commit -m "Backout revision 23"
748
748
749 By default, the pending changeset will have one parent,
749 By default, the pending changeset will have one parent,
750 maintaining a linear history. With --merge, the pending
750 maintaining a linear history. With --merge, the pending
751 changeset will instead have two parents: the old parent of the
751 changeset will instead have two parents: the old parent of the
752 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.
753
753
754 Before version 1.7, the behavior without --merge was equivalent
754 Before version 1.7, the behavior without --merge was equivalent
755 to specifying --merge followed by :hg:`update --clean .` to
755 to specifying --merge followed by :hg:`update --clean .` to
756 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
757 merged separately.
757 merged separately.
758
758
759 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.
760
760
761 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
762 of another revision.
762 of another revision.
763
763
764 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
765 files.
765 files.
766 '''
766 '''
767 with repo.wlock(), repo.lock():
767 with repo.wlock(), repo.lock():
768 return _dobackout(ui, repo, node, rev, **opts)
768 return _dobackout(ui, repo, node, rev, **opts)
769
769
770
770
771 def _dobackout(ui, repo, node=None, rev=None, **opts):
771 def _dobackout(ui, repo, node=None, rev=None, **opts):
772 opts = pycompat.byteskwargs(opts)
772 opts = pycompat.byteskwargs(opts)
773 if opts.get(b'commit') and opts.get(b'no_commit'):
773 if opts.get(b'commit') and opts.get(b'no_commit'):
774 raise error.Abort(_(b"cannot use --commit with --no-commit"))
774 raise error.Abort(_(b"cannot use --commit with --no-commit"))
775 if opts.get(b'merge') and opts.get(b'no_commit'):
775 if opts.get(b'merge') and opts.get(b'no_commit'):
776 raise error.Abort(_(b"cannot use --merge with --no-commit"))
776 raise error.Abort(_(b"cannot use --merge with --no-commit"))
777
777
778 if rev and node:
778 if rev and node:
779 raise error.Abort(_(b"please specify just one revision"))
779 raise error.Abort(_(b"please specify just one revision"))
780
780
781 if not rev:
781 if not rev:
782 rev = node
782 rev = node
783
783
784 if not rev:
784 if not rev:
785 raise error.Abort(_(b"please specify a revision to backout"))
785 raise error.Abort(_(b"please specify a revision to backout"))
786
786
787 date = opts.get(b'date')
787 date = opts.get(b'date')
788 if date:
788 if date:
789 opts[b'date'] = dateutil.parsedate(date)
789 opts[b'date'] = dateutil.parsedate(date)
790
790
791 cmdutil.checkunfinished(repo)
791 cmdutil.checkunfinished(repo)
792 cmdutil.bailifchanged(repo)
792 cmdutil.bailifchanged(repo)
793 ctx = scmutil.revsingle(repo, rev)
793 ctx = scmutil.revsingle(repo, rev)
794 node = ctx.node()
794 node = ctx.node()
795
795
796 op1, op2 = repo.dirstate.parents()
796 op1, op2 = repo.dirstate.parents()
797 if not repo.changelog.isancestor(node, op1):
797 if not repo.changelog.isancestor(node, op1):
798 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'))
799
799
800 p1, p2 = repo.changelog.parents(node)
800 p1, p2 = repo.changelog.parents(node)
801 if p1 == nullid:
801 if p1 == nullid:
802 raise error.Abort(_(b'cannot backout a change with no parents'))
802 raise error.Abort(_(b'cannot backout a change with no parents'))
803 if p2 != nullid:
803 if p2 != nullid:
804 if not opts.get(b'parent'):
804 if not opts.get(b'parent'):
805 raise error.Abort(_(b'cannot backout a merge changeset'))
805 raise error.Abort(_(b'cannot backout a merge changeset'))
806 p = repo.lookup(opts[b'parent'])
806 p = repo.lookup(opts[b'parent'])
807 if p not in (p1, p2):
807 if p not in (p1, p2):
808 raise error.Abort(
808 raise error.Abort(
809 _(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))
810 )
810 )
811 parent = p
811 parent = p
812 else:
812 else:
813 if opts.get(b'parent'):
813 if opts.get(b'parent'):
814 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
814 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
815 parent = p1
815 parent = p1
816
816
817 # the backout should appear on the same branch
817 # the backout should appear on the same branch
818 branch = repo.dirstate.branch()
818 branch = repo.dirstate.branch()
819 bheads = repo.branchheads(branch)
819 bheads = repo.branchheads(branch)
820 rctx = scmutil.revsingle(repo, hex(parent))
820 rctx = scmutil.revsingle(repo, hex(parent))
821 if not opts.get(b'merge') and op1 != node:
821 if not opts.get(b'merge') and op1 != node:
822 with dirstateguard.dirstateguard(repo, b'backout'):
822 with dirstateguard.dirstateguard(repo, b'backout'):
823 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
823 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
824 with ui.configoverride(overrides, b'backout'):
824 with ui.configoverride(overrides, b'backout'):
825 stats = mergemod.back_out(ctx, parent=repo[parent])
825 stats = mergemod.back_out(ctx, parent=repo[parent])
826 repo.setparents(op1, op2)
826 repo.setparents(op1, op2)
827 hg._showstats(repo, stats)
827 hg._showstats(repo, stats)
828 if stats.unresolvedcount:
828 if stats.unresolvedcount:
829 repo.ui.status(
829 repo.ui.status(
830 _(b"use 'hg resolve' to retry unresolved file merges\n")
830 _(b"use 'hg resolve' to retry unresolved file merges\n")
831 )
831 )
832 return 1
832 return 1
833 else:
833 else:
834 hg.clean(repo, node, show_stats=False)
834 hg.clean(repo, node, show_stats=False)
835 repo.dirstate.setbranch(branch)
835 repo.dirstate.setbranch(branch)
836 cmdutil.revert(ui, repo, rctx)
836 cmdutil.revert(ui, repo, rctx)
837
837
838 if opts.get(b'no_commit'):
838 if opts.get(b'no_commit'):
839 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")
840 ui.status(msg % short(node))
840 ui.status(msg % short(node))
841 return 0
841 return 0
842
842
843 def commitfunc(ui, repo, message, match, opts):
843 def commitfunc(ui, repo, message, match, opts):
844 editform = b'backout'
844 editform = b'backout'
845 e = cmdutil.getcommiteditor(
845 e = cmdutil.getcommiteditor(
846 editform=editform, **pycompat.strkwargs(opts)
846 editform=editform, **pycompat.strkwargs(opts)
847 )
847 )
848 if not message:
848 if not message:
849 # we don't translate commit messages
849 # we don't translate commit messages
850 message = b"Backed out changeset %s" % short(node)
850 message = b"Backed out changeset %s" % short(node)
851 e = cmdutil.getcommiteditor(edit=True, editform=editform)
851 e = cmdutil.getcommiteditor(edit=True, editform=editform)
852 return repo.commit(
852 return repo.commit(
853 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
854 )
854 )
855
855
856 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
856 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
857 if not newnode:
857 if not newnode:
858 ui.status(_(b"nothing changed\n"))
858 ui.status(_(b"nothing changed\n"))
859 return 1
859 return 1
860 cmdutil.commitstatus(repo, newnode, branch, bheads)
860 cmdutil.commitstatus(repo, newnode, branch, bheads)
861
861
862 def nice(node):
862 def nice(node):
863 return b'%d:%s' % (repo.changelog.rev(node), short(node))
863 return b'%d:%s' % (repo.changelog.rev(node), short(node))
864
864
865 ui.status(
865 ui.status(
866 _(b'changeset %s backs out changeset %s\n')
866 _(b'changeset %s backs out changeset %s\n')
867 % (nice(repo.changelog.tip()), nice(node))
867 % (nice(repo.changelog.tip()), nice(node))
868 )
868 )
869 if opts.get(b'merge') and op1 != node:
869 if opts.get(b'merge') and op1 != node:
870 hg.clean(repo, op1, show_stats=False)
870 hg.clean(repo, op1, show_stats=False)
871 ui.status(
871 ui.status(
872 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
872 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
873 )
873 )
874 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
874 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
875 with ui.configoverride(overrides, b'backout'):
875 with ui.configoverride(overrides, b'backout'):
876 return hg.merge(repo[b'tip'])
876 return hg.merge(repo[b'tip'])
877 return 0
877 return 0
878
878
879
879
880 @command(
880 @command(
881 b'bisect',
881 b'bisect',
882 [
882 [
883 (b'r', b'reset', False, _(b'reset bisect state')),
883 (b'r', b'reset', False, _(b'reset bisect state')),
884 (b'g', b'good', False, _(b'mark changeset good')),
884 (b'g', b'good', False, _(b'mark changeset good')),
885 (b'b', b'bad', False, _(b'mark changeset bad')),
885 (b'b', b'bad', False, _(b'mark changeset bad')),
886 (b's', b'skip', False, _(b'skip testing changeset')),
886 (b's', b'skip', False, _(b'skip testing changeset')),
887 (b'e', b'extend', False, _(b'extend the bisect range')),
887 (b'e', b'extend', False, _(b'extend the bisect range')),
888 (
888 (
889 b'c',
889 b'c',
890 b'command',
890 b'command',
891 b'',
891 b'',
892 _(b'use command to check changeset state'),
892 _(b'use command to check changeset state'),
893 _(b'CMD'),
893 _(b'CMD'),
894 ),
894 ),
895 (b'U', b'noupdate', False, _(b'do not update to target')),
895 (b'U', b'noupdate', False, _(b'do not update to target')),
896 ],
896 ],
897 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
897 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
898 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
898 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
899 )
899 )
900 def bisect(
900 def bisect(
901 ui,
901 ui,
902 repo,
902 repo,
903 rev=None,
903 rev=None,
904 extra=None,
904 extra=None,
905 command=None,
905 command=None,
906 reset=None,
906 reset=None,
907 good=None,
907 good=None,
908 bad=None,
908 bad=None,
909 skip=None,
909 skip=None,
910 extend=None,
910 extend=None,
911 noupdate=None,
911 noupdate=None,
912 ):
912 ):
913 """subdivision search of changesets
913 """subdivision search of changesets
914
914
915 This command helps to find changesets which introduce problems. To
915 This command helps to find changesets which introduce problems. To
916 use, mark the earliest changeset you know exhibits the problem as
916 use, mark the earliest changeset you know exhibits the problem as
917 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
918 as good. Bisect will update your working directory to a revision
918 as good. Bisect will update your working directory to a revision
919 for testing (unless the -U/--noupdate option is specified). Once
919 for testing (unless the -U/--noupdate option is specified). Once
920 you have performed tests, mark the working directory as good or
920 you have performed tests, mark the working directory as good or
921 bad, and bisect will either update to another candidate changeset
921 bad, and bisect will either update to another candidate changeset
922 or announce that it has found the bad revision.
922 or announce that it has found the bad revision.
923
923
924 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
925 revision as good or bad without checking it out first.
925 revision as good or bad without checking it out first.
926
926
927 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.
928 The environment variable HG_NODE will contain the ID of the
928 The environment variable HG_NODE will contain the ID of the
929 changeset being tested. The exit status of the command will be
929 changeset being tested. The exit status of the command will be
930 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
931 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
932 bisection, and any other non-zero exit status means the revision
932 bisection, and any other non-zero exit status means the revision
933 is bad.
933 is bad.
934
934
935 .. container:: verbose
935 .. container:: verbose
936
936
937 Some examples:
937 Some examples:
938
938
939 - 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::
940
940
941 hg bisect --bad 34
941 hg bisect --bad 34
942 hg bisect --good 12
942 hg bisect --good 12
943
943
944 - advance the current bisection by marking current revision as good or
944 - advance the current bisection by marking current revision as good or
945 bad::
945 bad::
946
946
947 hg bisect --good
947 hg bisect --good
948 hg bisect --bad
948 hg bisect --bad
949
949
950 - 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
951 that revision is not usable because of another issue)::
951 that revision is not usable because of another issue)::
952
952
953 hg bisect --skip
953 hg bisect --skip
954 hg bisect --skip 23
954 hg bisect --skip 23
955
955
956 - skip all revisions that do not touch directories ``foo`` or ``bar``::
956 - skip all revisions that do not touch directories ``foo`` or ``bar``::
957
957
958 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
958 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
959
959
960 - forget the current bisection::
960 - forget the current bisection::
961
961
962 hg bisect --reset
962 hg bisect --reset
963
963
964 - use 'make && make tests' to automatically find the first broken
964 - use 'make && make tests' to automatically find the first broken
965 revision::
965 revision::
966
966
967 hg bisect --reset
967 hg bisect --reset
968 hg bisect --bad 34
968 hg bisect --bad 34
969 hg bisect --good 12
969 hg bisect --good 12
970 hg bisect --command "make && make tests"
970 hg bisect --command "make && make tests"
971
971
972 - see all changesets whose states are already known in the current
972 - see all changesets whose states are already known in the current
973 bisection::
973 bisection::
974
974
975 hg log -r "bisect(pruned)"
975 hg log -r "bisect(pruned)"
976
976
977 - see the changeset currently being bisected (especially useful
977 - see the changeset currently being bisected (especially useful
978 if running with -U/--noupdate)::
978 if running with -U/--noupdate)::
979
979
980 hg log -r "bisect(current)"
980 hg log -r "bisect(current)"
981
981
982 - see all changesets that took part in the current bisection::
982 - see all changesets that took part in the current bisection::
983
983
984 hg log -r "bisect(range)"
984 hg log -r "bisect(range)"
985
985
986 - you can even get a nice graph::
986 - you can even get a nice graph::
987
987
988 hg log --graph -r "bisect(range)"
988 hg log --graph -r "bisect(range)"
989
989
990 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
990 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
991
991
992 Returns 0 on success.
992 Returns 0 on success.
993 """
993 """
994 # backward compatibility
994 # backward compatibility
995 if rev in b"good bad reset init".split():
995 if rev in b"good bad reset init".split():
996 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
996 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
997 cmd, rev, extra = rev, extra, None
997 cmd, rev, extra = rev, extra, None
998 if cmd == b"good":
998 if cmd == b"good":
999 good = True
999 good = True
1000 elif cmd == b"bad":
1000 elif cmd == b"bad":
1001 bad = True
1001 bad = True
1002 else:
1002 else:
1003 reset = True
1003 reset = True
1004 elif extra:
1004 elif extra:
1005 raise error.Abort(_(b'incompatible arguments'))
1005 raise error.Abort(_(b'incompatible arguments'))
1006
1006
1007 incompatibles = {
1007 incompatibles = {
1008 b'--bad': bad,
1008 b'--bad': bad,
1009 b'--command': bool(command),
1009 b'--command': bool(command),
1010 b'--extend': extend,
1010 b'--extend': extend,
1011 b'--good': good,
1011 b'--good': good,
1012 b'--reset': reset,
1012 b'--reset': reset,
1013 b'--skip': skip,
1013 b'--skip': skip,
1014 }
1014 }
1015
1015
1016 enabled = [x for x in incompatibles if incompatibles[x]]
1016 enabled = [x for x in incompatibles if incompatibles[x]]
1017
1017
1018 if len(enabled) > 1:
1018 if len(enabled) > 1:
1019 raise error.Abort(
1019 raise error.Abort(
1020 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1020 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1021 )
1021 )
1022
1022
1023 if reset:
1023 if reset:
1024 hbisect.resetstate(repo)
1024 hbisect.resetstate(repo)
1025 return
1025 return
1026
1026
1027 state = hbisect.load_state(repo)
1027 state = hbisect.load_state(repo)
1028
1028
1029 # update state
1029 # update state
1030 if good or bad or skip:
1030 if good or bad or skip:
1031 if rev:
1031 if rev:
1032 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1032 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1033 else:
1033 else:
1034 nodes = [repo.lookup(b'.')]
1034 nodes = [repo.lookup(b'.')]
1035 if good:
1035 if good:
1036 state[b'good'] += nodes
1036 state[b'good'] += nodes
1037 elif bad:
1037 elif bad:
1038 state[b'bad'] += nodes
1038 state[b'bad'] += nodes
1039 elif skip:
1039 elif skip:
1040 state[b'skip'] += nodes
1040 state[b'skip'] += nodes
1041 hbisect.save_state(repo, state)
1041 hbisect.save_state(repo, state)
1042 if not (state[b'good'] and state[b'bad']):
1042 if not (state[b'good'] and state[b'bad']):
1043 return
1043 return
1044
1044
1045 def mayupdate(repo, node, show_stats=True):
1045 def mayupdate(repo, node, show_stats=True):
1046 """common used update sequence"""
1046 """common used update sequence"""
1047 if noupdate:
1047 if noupdate:
1048 return
1048 return
1049 cmdutil.checkunfinished(repo)
1049 cmdutil.checkunfinished(repo)
1050 cmdutil.bailifchanged(repo)
1050 cmdutil.bailifchanged(repo)
1051 return hg.clean(repo, node, show_stats=show_stats)
1051 return hg.clean(repo, node, show_stats=show_stats)
1052
1052
1053 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1053 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1054
1054
1055 if command:
1055 if command:
1056 changesets = 1
1056 changesets = 1
1057 if noupdate:
1057 if noupdate:
1058 try:
1058 try:
1059 node = state[b'current'][0]
1059 node = state[b'current'][0]
1060 except LookupError:
1060 except LookupError:
1061 raise error.Abort(
1061 raise error.Abort(
1062 _(
1062 _(
1063 b'current bisect revision is unknown - '
1063 b'current bisect revision is unknown - '
1064 b'start a new bisect to fix'
1064 b'start a new bisect to fix'
1065 )
1065 )
1066 )
1066 )
1067 else:
1067 else:
1068 node, p2 = repo.dirstate.parents()
1068 node, p2 = repo.dirstate.parents()
1069 if p2 != nullid:
1069 if p2 != nullid:
1070 raise error.Abort(_(b'current bisect revision is a merge'))
1070 raise error.Abort(_(b'current bisect revision is a merge'))
1071 if rev:
1071 if rev:
1072 node = repo[scmutil.revsingle(repo, rev, node)].node()
1072 node = repo[scmutil.revsingle(repo, rev, node)].node()
1073 with hbisect.restore_state(repo, state, node):
1073 with hbisect.restore_state(repo, state, node):
1074 while changesets:
1074 while changesets:
1075 # update state
1075 # update state
1076 state[b'current'] = [node]
1076 state[b'current'] = [node]
1077 hbisect.save_state(repo, state)
1077 hbisect.save_state(repo, state)
1078 status = ui.system(
1078 status = ui.system(
1079 command,
1079 command,
1080 environ={b'HG_NODE': hex(node)},
1080 environ={b'HG_NODE': hex(node)},
1081 blockedtag=b'bisect_check',
1081 blockedtag=b'bisect_check',
1082 )
1082 )
1083 if status == 125:
1083 if status == 125:
1084 transition = b"skip"
1084 transition = b"skip"
1085 elif status == 0:
1085 elif status == 0:
1086 transition = b"good"
1086 transition = b"good"
1087 # status < 0 means process was killed
1087 # status < 0 means process was killed
1088 elif status == 127:
1088 elif status == 127:
1089 raise error.Abort(_(b"failed to execute %s") % command)
1089 raise error.Abort(_(b"failed to execute %s") % command)
1090 elif status < 0:
1090 elif status < 0:
1091 raise error.Abort(_(b"%s killed") % command)
1091 raise error.Abort(_(b"%s killed") % command)
1092 else:
1092 else:
1093 transition = b"bad"
1093 transition = b"bad"
1094 state[transition].append(node)
1094 state[transition].append(node)
1095 ctx = repo[node]
1095 ctx = repo[node]
1096 ui.status(
1096 ui.status(
1097 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1097 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1098 )
1098 )
1099 hbisect.checkstate(state)
1099 hbisect.checkstate(state)
1100 # bisect
1100 # bisect
1101 nodes, changesets, bgood = hbisect.bisect(repo, state)
1101 nodes, changesets, bgood = hbisect.bisect(repo, state)
1102 # update to next check
1102 # update to next check
1103 node = nodes[0]
1103 node = nodes[0]
1104 mayupdate(repo, node, show_stats=False)
1104 mayupdate(repo, node, show_stats=False)
1105 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1105 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1106 return
1106 return
1107
1107
1108 hbisect.checkstate(state)
1108 hbisect.checkstate(state)
1109
1109
1110 # actually bisect
1110 # actually bisect
1111 nodes, changesets, good = hbisect.bisect(repo, state)
1111 nodes, changesets, good = hbisect.bisect(repo, state)
1112 if extend:
1112 if extend:
1113 if not changesets:
1113 if not changesets:
1114 extendnode = hbisect.extendrange(repo, state, nodes, good)
1114 extendnode = hbisect.extendrange(repo, state, nodes, good)
1115 if extendnode is not None:
1115 if extendnode is not None:
1116 ui.write(
1116 ui.write(
1117 _(b"Extending search to changeset %d:%s\n")
1117 _(b"Extending search to changeset %d:%s\n")
1118 % (extendnode.rev(), extendnode)
1118 % (extendnode.rev(), extendnode)
1119 )
1119 )
1120 state[b'current'] = [extendnode.node()]
1120 state[b'current'] = [extendnode.node()]
1121 hbisect.save_state(repo, state)
1121 hbisect.save_state(repo, state)
1122 return mayupdate(repo, extendnode.node())
1122 return mayupdate(repo, extendnode.node())
1123 raise error.Abort(_(b"nothing to extend"))
1123 raise error.Abort(_(b"nothing to extend"))
1124
1124
1125 if changesets == 0:
1125 if changesets == 0:
1126 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1126 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1127 else:
1127 else:
1128 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
1129 node = nodes[0]
1129 node = nodes[0]
1130 # compute the approximate number of remaining tests
1130 # compute the approximate number of remaining tests
1131 tests, size = 0, 2
1131 tests, size = 0, 2
1132 while size <= changesets:
1132 while size <= changesets:
1133 tests, size = tests + 1, size * 2
1133 tests, size = tests + 1, size * 2
1134 rev = repo.changelog.rev(node)
1134 rev = repo.changelog.rev(node)
1135 ui.write(
1135 ui.write(
1136 _(
1136 _(
1137 b"Testing changeset %d:%s "
1137 b"Testing changeset %d:%s "
1138 b"(%d changesets remaining, ~%d tests)\n"
1138 b"(%d changesets remaining, ~%d tests)\n"
1139 )
1139 )
1140 % (rev, short(node), changesets, tests)
1140 % (rev, short(node), changesets, tests)
1141 )
1141 )
1142 state[b'current'] = [node]
1142 state[b'current'] = [node]
1143 hbisect.save_state(repo, state)
1143 hbisect.save_state(repo, state)
1144 return mayupdate(repo, node)
1144 return mayupdate(repo, node)
1145
1145
1146
1146
1147 @command(
1147 @command(
1148 b'bookmarks|bookmark',
1148 b'bookmarks|bookmark',
1149 [
1149 [
1150 (b'f', b'force', False, _(b'force')),
1150 (b'f', b'force', False, _(b'force')),
1151 (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')),
1152 (b'd', b'delete', False, _(b'delete a given bookmark')),
1152 (b'd', b'delete', False, _(b'delete a given bookmark')),
1153 (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')),
1154 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1154 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1155 (b'l', b'list', False, _(b'list existing bookmarks')),
1155 (b'l', b'list', False, _(b'list existing bookmarks')),
1156 ]
1156 ]
1157 + formatteropts,
1157 + formatteropts,
1158 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1158 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1159 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1159 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1160 )
1160 )
1161 def bookmark(ui, repo, *names, **opts):
1161 def bookmark(ui, repo, *names, **opts):
1162 '''create a new bookmark or list existing bookmarks
1162 '''create a new bookmark or list existing bookmarks
1163
1163
1164 Bookmarks are labels on changesets to help track lines of development.
1164 Bookmarks are labels on changesets to help track lines of development.
1165 Bookmarks are unversioned and can be moved, renamed and deleted.
1165 Bookmarks are unversioned and can be moved, renamed and deleted.
1166 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.
1167
1167
1168 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'.
1169 The active bookmark is indicated with a '*'.
1169 The active bookmark is indicated with a '*'.
1170 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.
1171 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.
1172 Updating away from a bookmark will cause it to be deactivated.
1172 Updating away from a bookmark will cause it to be deactivated.
1173
1173
1174 Bookmarks can be pushed and pulled between repositories (see
1174 Bookmarks can be pushed and pulled between repositories (see
1175 :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
1176 diverged, a new 'divergent bookmark' of the form 'name@path' will
1176 diverged, a new 'divergent bookmark' of the form 'name@path' will
1177 be created. Using :hg:`merge` will resolve the divergence.
1177 be created. Using :hg:`merge` will resolve the divergence.
1178
1178
1179 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
1180 the active bookmark's name.
1180 the active bookmark's name.
1181
1181
1182 A bookmark named '@' has the special property that :hg:`clone` will
1182 A bookmark named '@' has the special property that :hg:`clone` will
1183 check it out by default if it exists.
1183 check it out by default if it exists.
1184
1184
1185 .. container:: verbose
1185 .. container:: verbose
1186
1186
1187 Template:
1187 Template:
1188
1188
1189 The following keywords are supported in addition to the common template
1189 The following keywords are supported in addition to the common template
1190 keywords and functions such as ``{bookmark}``. See also
1190 keywords and functions such as ``{bookmark}``. See also
1191 :hg:`help templates`.
1191 :hg:`help templates`.
1192
1192
1193 :active: Boolean. True if the bookmark is active.
1193 :active: Boolean. True if the bookmark is active.
1194
1194
1195 Examples:
1195 Examples:
1196
1196
1197 - create an active bookmark for a new line of development::
1197 - create an active bookmark for a new line of development::
1198
1198
1199 hg book new-feature
1199 hg book new-feature
1200
1200
1201 - create an inactive bookmark as a place marker::
1201 - create an inactive bookmark as a place marker::
1202
1202
1203 hg book -i reviewed
1203 hg book -i reviewed
1204
1204
1205 - create an inactive bookmark on another changeset::
1205 - create an inactive bookmark on another changeset::
1206
1206
1207 hg book -r .^ tested
1207 hg book -r .^ tested
1208
1208
1209 - rename bookmark turkey to dinner::
1209 - rename bookmark turkey to dinner::
1210
1210
1211 hg book -m turkey dinner
1211 hg book -m turkey dinner
1212
1212
1213 - move the '@' bookmark from another branch::
1213 - move the '@' bookmark from another branch::
1214
1214
1215 hg book -f @
1215 hg book -f @
1216
1216
1217 - print only the active bookmark name::
1217 - print only the active bookmark name::
1218
1218
1219 hg book -ql .
1219 hg book -ql .
1220 '''
1220 '''
1221 opts = pycompat.byteskwargs(opts)
1221 opts = pycompat.byteskwargs(opts)
1222 force = opts.get(b'force')
1222 force = opts.get(b'force')
1223 rev = opts.get(b'rev')
1223 rev = opts.get(b'rev')
1224 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1224 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1225
1225
1226 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')
1227 if action:
1227 if action:
1228 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1228 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1229 elif names or rev:
1229 elif names or rev:
1230 action = b'add'
1230 action = b'add'
1231 elif inactive:
1231 elif inactive:
1232 action = b'inactive' # meaning deactivate
1232 action = b'inactive' # meaning deactivate
1233 else:
1233 else:
1234 action = b'list'
1234 action = b'list'
1235
1235
1236 cmdutil.check_incompatible_arguments(
1236 cmdutil.check_incompatible_arguments(
1237 opts, b'inactive', [b'delete', b'list']
1237 opts, b'inactive', [b'delete', b'list']
1238 )
1238 )
1239 if not names and action in {b'add', b'delete'}:
1239 if not names and action in {b'add', b'delete'}:
1240 raise error.Abort(_(b"bookmark name required"))
1240 raise error.Abort(_(b"bookmark name required"))
1241
1241
1242 if action in {b'add', b'delete', b'rename', b'inactive'}:
1242 if action in {b'add', b'delete', b'rename', b'inactive'}:
1243 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1243 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1244 if action == b'delete':
1244 if action == b'delete':
1245 names = pycompat.maplist(repo._bookmarks.expandname, names)
1245 names = pycompat.maplist(repo._bookmarks.expandname, names)
1246 bookmarks.delete(repo, tr, names)
1246 bookmarks.delete(repo, tr, names)
1247 elif action == b'rename':
1247 elif action == b'rename':
1248 if not names:
1248 if not names:
1249 raise error.Abort(_(b"new bookmark name required"))
1249 raise error.Abort(_(b"new bookmark name required"))
1250 elif len(names) > 1:
1250 elif len(names) > 1:
1251 raise error.Abort(_(b"only one new bookmark name allowed"))
1251 raise error.Abort(_(b"only one new bookmark name allowed"))
1252 oldname = repo._bookmarks.expandname(opts[b'rename'])
1252 oldname = repo._bookmarks.expandname(opts[b'rename'])
1253 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1253 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1254 elif action == b'add':
1254 elif action == b'add':
1255 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1255 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1256 elif action == b'inactive':
1256 elif action == b'inactive':
1257 if len(repo._bookmarks) == 0:
1257 if len(repo._bookmarks) == 0:
1258 ui.status(_(b"no bookmarks set\n"))
1258 ui.status(_(b"no bookmarks set\n"))
1259 elif not repo._activebookmark:
1259 elif not repo._activebookmark:
1260 ui.status(_(b"no active bookmark\n"))
1260 ui.status(_(b"no active bookmark\n"))
1261 else:
1261 else:
1262 bookmarks.deactivate(repo)
1262 bookmarks.deactivate(repo)
1263 elif action == b'list':
1263 elif action == b'list':
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 with ui.formatter(b'bookmarks', opts) as fm:
1265 with ui.formatter(b'bookmarks', opts) as fm:
1266 bookmarks.printbookmarks(ui, repo, fm, names)
1266 bookmarks.printbookmarks(ui, repo, fm, names)
1267 else:
1267 else:
1268 raise error.ProgrammingError(b'invalid action: %s' % action)
1268 raise error.ProgrammingError(b'invalid action: %s' % action)
1269
1269
1270
1270
1271 @command(
1271 @command(
1272 b'branch',
1272 b'branch',
1273 [
1273 [
1274 (
1274 (
1275 b'f',
1275 b'f',
1276 b'force',
1276 b'force',
1277 None,
1277 None,
1278 _(b'set branch name even if it shadows an existing branch'),
1278 _(b'set branch name even if it shadows an existing branch'),
1279 ),
1279 ),
1280 (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')),
1281 (
1281 (
1282 b'r',
1282 b'r',
1283 b'rev',
1283 b'rev',
1284 [],
1284 [],
1285 _(b'change branches of the given revs (EXPERIMENTAL)'),
1285 _(b'change branches of the given revs (EXPERIMENTAL)'),
1286 ),
1286 ),
1287 ],
1287 ],
1288 _(b'[-fC] [NAME]'),
1288 _(b'[-fC] [NAME]'),
1289 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1289 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1290 )
1290 )
1291 def branch(ui, repo, label=None, **opts):
1291 def branch(ui, repo, label=None, **opts):
1292 """set or show the current branch name
1292 """set or show the current branch name
1293
1293
1294 .. note::
1294 .. note::
1295
1295
1296 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
1297 light-weight bookmark instead. See :hg:`help glossary` for more
1297 light-weight bookmark instead. See :hg:`help glossary` for more
1298 information about named branches and bookmarks.
1298 information about named branches and bookmarks.
1299
1299
1300 With no argument, show the current branch name. With one argument,
1300 With no argument, show the current branch name. With one argument,
1301 set the working directory branch name (the branch will not exist
1301 set the working directory branch name (the branch will not exist
1302 in the repository until the next commit). Standard practice
1302 in the repository until the next commit). Standard practice
1303 recommends that primary development take place on the 'default'
1303 recommends that primary development take place on the 'default'
1304 branch.
1304 branch.
1305
1305
1306 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
1307 branch name that already exists.
1307 branch name that already exists.
1308
1308
1309 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
1310 the parent of the working directory, negating a previous branch
1310 the parent of the working directory, negating a previous branch
1311 change.
1311 change.
1312
1312
1313 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
1314 :hg:`commit --close-branch` to mark this branch head as closed.
1314 :hg:`commit --close-branch` to mark this branch head as closed.
1315 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
1316 considered closed.
1316 considered closed.
1317
1317
1318 Returns 0 on success.
1318 Returns 0 on success.
1319 """
1319 """
1320 opts = pycompat.byteskwargs(opts)
1320 opts = pycompat.byteskwargs(opts)
1321 revs = opts.get(b'rev')
1321 revs = opts.get(b'rev')
1322 if label:
1322 if label:
1323 label = label.strip()
1323 label = label.strip()
1324
1324
1325 if not opts.get(b'clean') and not label:
1325 if not opts.get(b'clean') and not label:
1326 if revs:
1326 if revs:
1327 raise error.Abort(_(b"no branch name specified for the revisions"))
1327 raise error.Abort(_(b"no branch name specified for the revisions"))
1328 ui.write(b"%s\n" % repo.dirstate.branch())
1328 ui.write(b"%s\n" % repo.dirstate.branch())
1329 return
1329 return
1330
1330
1331 with repo.wlock():
1331 with repo.wlock():
1332 if opts.get(b'clean'):
1332 if opts.get(b'clean'):
1333 label = repo[b'.'].branch()
1333 label = repo[b'.'].branch()
1334 repo.dirstate.setbranch(label)
1334 repo.dirstate.setbranch(label)
1335 ui.status(_(b'reset working directory to branch %s\n') % label)
1335 ui.status(_(b'reset working directory to branch %s\n') % label)
1336 elif label:
1336 elif label:
1337
1337
1338 scmutil.checknewlabel(repo, label, b'branch')
1338 scmutil.checknewlabel(repo, label, b'branch')
1339 if revs:
1339 if revs:
1340 return cmdutil.changebranch(ui, repo, revs, label, opts)
1340 return cmdutil.changebranch(ui, repo, revs, label, opts)
1341
1341
1342 if not opts.get(b'force') and label in repo.branchmap():
1342 if not opts.get(b'force') and label in repo.branchmap():
1343 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()]:
1344 raise error.Abort(
1344 raise error.Abort(
1345 _(b'a branch of the same name already exists'),
1345 _(b'a branch of the same name already exists'),
1346 # i18n: "it" refers to an existing branch
1346 # i18n: "it" refers to an existing branch
1347 hint=_(b"use 'hg update' to switch to it"),
1347 hint=_(b"use 'hg update' to switch to it"),
1348 )
1348 )
1349
1349
1350 repo.dirstate.setbranch(label)
1350 repo.dirstate.setbranch(label)
1351 ui.status(_(b'marked working directory as branch %s\n') % label)
1351 ui.status(_(b'marked working directory as branch %s\n') % label)
1352
1352
1353 # find any open named branches aside from default
1353 # find any open named branches aside from default
1354 for n, h, t, c in repo.branchmap().iterbranches():
1354 for n, h, t, c in repo.branchmap().iterbranches():
1355 if n != b"default" and not c:
1355 if n != b"default" and not c:
1356 return 0
1356 return 0
1357 ui.status(
1357 ui.status(
1358 _(
1358 _(
1359 b'(branches are permanent and global, '
1359 b'(branches are permanent and global, '
1360 b'did you want a bookmark?)\n'
1360 b'did you want a bookmark?)\n'
1361 )
1361 )
1362 )
1362 )
1363
1363
1364
1364
1365 @command(
1365 @command(
1366 b'branches',
1366 b'branches',
1367 [
1367 [
1368 (
1368 (
1369 b'a',
1369 b'a',
1370 b'active',
1370 b'active',
1371 False,
1371 False,
1372 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1372 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1373 ),
1373 ),
1374 (b'c', b'closed', False, _(b'show normal and closed branches')),
1374 (b'c', b'closed', False, _(b'show normal and closed branches')),
1375 (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')),
1376 ]
1376 ]
1377 + formatteropts,
1377 + formatteropts,
1378 _(b'[-c]'),
1378 _(b'[-c]'),
1379 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1379 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1380 intents={INTENT_READONLY},
1380 intents={INTENT_READONLY},
1381 )
1381 )
1382 def branches(ui, repo, active=False, closed=False, **opts):
1382 def branches(ui, repo, active=False, closed=False, **opts):
1383 """list repository named branches
1383 """list repository named branches
1384
1384
1385 List the repository's named branches, indicating which ones are
1385 List the repository's named branches, indicating which ones are
1386 inactive. If -c/--closed is specified, also list branches which have
1386 inactive. If -c/--closed is specified, also list branches which have
1387 been marked closed (see :hg:`commit --close-branch`).
1387 been marked closed (see :hg:`commit --close-branch`).
1388
1388
1389 Use the command :hg:`update` to switch to an existing branch.
1389 Use the command :hg:`update` to switch to an existing branch.
1390
1390
1391 .. container:: verbose
1391 .. container:: verbose
1392
1392
1393 Template:
1393 Template:
1394
1394
1395 The following keywords are supported in addition to the common template
1395 The following keywords are supported in addition to the common template
1396 keywords and functions such as ``{branch}``. See also
1396 keywords and functions such as ``{branch}``. See also
1397 :hg:`help templates`.
1397 :hg:`help templates`.
1398
1398
1399 :active: Boolean. True if the branch is active.
1399 :active: Boolean. True if the branch is active.
1400 :closed: Boolean. True if the branch is closed.
1400 :closed: Boolean. True if the branch is closed.
1401 :current: Boolean. True if it is the current branch.
1401 :current: Boolean. True if it is the current branch.
1402
1402
1403 Returns 0.
1403 Returns 0.
1404 """
1404 """
1405
1405
1406 opts = pycompat.byteskwargs(opts)
1406 opts = pycompat.byteskwargs(opts)
1407 revs = opts.get(b'rev')
1407 revs = opts.get(b'rev')
1408 selectedbranches = None
1408 selectedbranches = None
1409 if revs:
1409 if revs:
1410 revs = scmutil.revrange(repo, revs)
1410 revs = scmutil.revrange(repo, revs)
1411 getbi = repo.revbranchcache().branchinfo
1411 getbi = repo.revbranchcache().branchinfo
1412 selectedbranches = {getbi(r)[0] for r in revs}
1412 selectedbranches = {getbi(r)[0] for r in revs}
1413
1413
1414 ui.pager(b'branches')
1414 ui.pager(b'branches')
1415 fm = ui.formatter(b'branches', opts)
1415 fm = ui.formatter(b'branches', opts)
1416 hexfunc = fm.hexfunc
1416 hexfunc = fm.hexfunc
1417
1417
1418 allheads = set(repo.heads())
1418 allheads = set(repo.heads())
1419 branches = []
1419 branches = []
1420 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1420 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1421 if selectedbranches is not None and tag not in selectedbranches:
1421 if selectedbranches is not None and tag not in selectedbranches:
1422 continue
1422 continue
1423 isactive = False
1423 isactive = False
1424 if not isclosed:
1424 if not isclosed:
1425 openheads = set(repo.branchmap().iteropen(heads))
1425 openheads = set(repo.branchmap().iteropen(heads))
1426 isactive = bool(openheads & allheads)
1426 isactive = bool(openheads & allheads)
1427 branches.append((tag, repo[tip], isactive, not isclosed))
1427 branches.append((tag, repo[tip], isactive, not isclosed))
1428 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)
1429
1429
1430 for tag, ctx, isactive, isopen in branches:
1430 for tag, ctx, isactive, isopen in branches:
1431 if active and not isactive:
1431 if active and not isactive:
1432 continue
1432 continue
1433 if isactive:
1433 if isactive:
1434 label = b'branches.active'
1434 label = b'branches.active'
1435 notice = b''
1435 notice = b''
1436 elif not isopen:
1436 elif not isopen:
1437 if not closed:
1437 if not closed:
1438 continue
1438 continue
1439 label = b'branches.closed'
1439 label = b'branches.closed'
1440 notice = _(b' (closed)')
1440 notice = _(b' (closed)')
1441 else:
1441 else:
1442 label = b'branches.inactive'
1442 label = b'branches.inactive'
1443 notice = _(b' (inactive)')
1443 notice = _(b' (inactive)')
1444 current = tag == repo.dirstate.branch()
1444 current = tag == repo.dirstate.branch()
1445 if current:
1445 if current:
1446 label = b'branches.current'
1446 label = b'branches.current'
1447
1447
1448 fm.startitem()
1448 fm.startitem()
1449 fm.write(b'branch', b'%s', tag, label=label)
1449 fm.write(b'branch', b'%s', tag, label=label)
1450 rev = ctx.rev()
1450 rev = ctx.rev()
1451 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1451 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1452 fmt = b' ' * padsize + b' %d:%s'
1452 fmt = b' ' * padsize + b' %d:%s'
1453 fm.condwrite(
1453 fm.condwrite(
1454 not ui.quiet,
1454 not ui.quiet,
1455 b'rev node',
1455 b'rev node',
1456 fmt,
1456 fmt,
1457 rev,
1457 rev,
1458 hexfunc(ctx.node()),
1458 hexfunc(ctx.node()),
1459 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1459 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1460 )
1460 )
1461 fm.context(ctx=ctx)
1461 fm.context(ctx=ctx)
1462 fm.data(active=isactive, closed=not isopen, current=current)
1462 fm.data(active=isactive, closed=not isopen, current=current)
1463 if not ui.quiet:
1463 if not ui.quiet:
1464 fm.plain(notice)
1464 fm.plain(notice)
1465 fm.plain(b'\n')
1465 fm.plain(b'\n')
1466 fm.end()
1466 fm.end()
1467
1467
1468
1468
1469 @command(
1469 @command(
1470 b'bundle',
1470 b'bundle',
1471 [
1471 [
1472 (
1472 (
1473 b'f',
1473 b'f',
1474 b'force',
1474 b'force',
1475 None,
1475 None,
1476 _(b'run even when the destination is unrelated'),
1476 _(b'run even when the destination is unrelated'),
1477 ),
1477 ),
1478 (
1478 (
1479 b'r',
1479 b'r',
1480 b'rev',
1480 b'rev',
1481 [],
1481 [],
1482 _(b'a changeset intended to be added to the destination'),
1482 _(b'a changeset intended to be added to the destination'),
1483 _(b'REV'),
1483 _(b'REV'),
1484 ),
1484 ),
1485 (
1485 (
1486 b'b',
1486 b'b',
1487 b'branch',
1487 b'branch',
1488 [],
1488 [],
1489 _(b'a specific branch you would like to bundle'),
1489 _(b'a specific branch you would like to bundle'),
1490 _(b'BRANCH'),
1490 _(b'BRANCH'),
1491 ),
1491 ),
1492 (
1492 (
1493 b'',
1493 b'',
1494 b'base',
1494 b'base',
1495 [],
1495 [],
1496 _(b'a base changeset assumed to be available at the destination'),
1496 _(b'a base changeset assumed to be available at the destination'),
1497 _(b'REV'),
1497 _(b'REV'),
1498 ),
1498 ),
1499 (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')),
1500 (
1500 (
1501 b't',
1501 b't',
1502 b'type',
1502 b'type',
1503 b'bzip2',
1503 b'bzip2',
1504 _(b'bundle compression type to use'),
1504 _(b'bundle compression type to use'),
1505 _(b'TYPE'),
1505 _(b'TYPE'),
1506 ),
1506 ),
1507 ]
1507 ]
1508 + remoteopts,
1508 + remoteopts,
1509 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1509 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1510 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1510 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1511 )
1511 )
1512 def bundle(ui, repo, fname, dest=None, **opts):
1512 def bundle(ui, repo, fname, dest=None, **opts):
1513 """create a bundle file
1513 """create a bundle file
1514
1514
1515 Generate a bundle file containing data to be transferred to another
1515 Generate a bundle file containing data to be transferred to another
1516 repository.
1516 repository.
1517
1517
1518 To create a bundle containing all changesets, use -a/--all
1518 To create a bundle containing all changesets, use -a/--all
1519 (or --base null). Otherwise, hg assumes the destination will have
1519 (or --base null). Otherwise, hg assumes the destination will have
1520 all the nodes you specify with --base parameters. Otherwise, hg
1520 all the nodes you specify with --base parameters. Otherwise, hg
1521 will assume the repository has all the nodes in destination, or
1521 will assume the repository has all the nodes in destination, or
1522 default-push/default if no destination is specified, where destination
1522 default-push/default if no destination is specified, where destination
1523 is the repository you provide through DEST option.
1523 is the repository you provide through DEST option.
1524
1524
1525 You can change bundle format with the -t/--type option. See
1525 You can change bundle format with the -t/--type option. See
1526 :hg:`help bundlespec` for documentation on this format. By default,
1526 :hg:`help bundlespec` for documentation on this format. By default,
1527 the most appropriate format is used and compression defaults to
1527 the most appropriate format is used and compression defaults to
1528 bzip2.
1528 bzip2.
1529
1529
1530 The bundle file can then be transferred using conventional means
1530 The bundle file can then be transferred using conventional means
1531 and applied to another repository with the unbundle or pull
1531 and applied to another repository with the unbundle or pull
1532 command. This is useful when direct push and pull are not
1532 command. This is useful when direct push and pull are not
1533 available or when exporting an entire repository is undesirable.
1533 available or when exporting an entire repository is undesirable.
1534
1534
1535 Applying bundles preserves all changeset contents including
1535 Applying bundles preserves all changeset contents including
1536 permissions, copy/rename information, and revision history.
1536 permissions, copy/rename information, and revision history.
1537
1537
1538 Returns 0 on success, 1 if no changes found.
1538 Returns 0 on success, 1 if no changes found.
1539 """
1539 """
1540 opts = pycompat.byteskwargs(opts)
1540 opts = pycompat.byteskwargs(opts)
1541 revs = None
1541 revs = None
1542 if b'rev' in opts:
1542 if b'rev' in opts:
1543 revstrings = opts[b'rev']
1543 revstrings = opts[b'rev']
1544 revs = scmutil.revrange(repo, revstrings)
1544 revs = scmutil.revrange(repo, revstrings)
1545 if revstrings and not revs:
1545 if revstrings and not revs:
1546 raise error.Abort(_(b'no commits to bundle'))
1546 raise error.Abort(_(b'no commits to bundle'))
1547
1547
1548 bundletype = opts.get(b'type', b'bzip2').lower()
1548 bundletype = opts.get(b'type', b'bzip2').lower()
1549 try:
1549 try:
1550 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1550 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1551 except error.UnsupportedBundleSpecification as e:
1551 except error.UnsupportedBundleSpecification as e:
1552 raise error.Abort(
1552 raise error.Abort(
1553 pycompat.bytestr(e),
1553 pycompat.bytestr(e),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1555 )
1555 )
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1557
1557
1558 # Packed bundles are a pseudo bundle format for now.
1558 # Packed bundles are a pseudo bundle format for now.
1559 if cgversion == b's1':
1559 if cgversion == b's1':
1560 raise error.Abort(
1560 raise error.Abort(
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1563 )
1563 )
1564
1564
1565 if opts.get(b'all'):
1565 if opts.get(b'all'):
1566 if dest:
1566 if dest:
1567 raise error.Abort(
1567 raise error.Abort(
1568 _(b"--all is incompatible with specifying a destination")
1568 _(b"--all is incompatible with specifying a destination")
1569 )
1569 )
1570 if opts.get(b'base'):
1570 if opts.get(b'base'):
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1572 base = [nullrev]
1572 base = [nullrev]
1573 else:
1573 else:
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1576 raise error.Abort(
1576 raise error.Abort(
1577 _(b"repository does not support bundle version %s") % cgversion
1577 _(b"repository does not support bundle version %s") % cgversion
1578 )
1578 )
1579
1579
1580 if base:
1580 if base:
1581 if dest:
1581 if dest:
1582 raise error.Abort(
1582 raise error.Abort(
1583 _(b"--base is incompatible with specifying a destination")
1583 _(b"--base is incompatible with specifying a destination")
1584 )
1584 )
1585 common = [repo[rev].node() for rev in base]
1585 common = [repo[rev].node() for rev in base]
1586 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
1587 outgoing = discovery.outgoing(repo, common, heads)
1587 outgoing = discovery.outgoing(repo, common, heads)
1588 else:
1588 else:
1589 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')
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1591 other = hg.peer(repo, opts, dest)
1591 other = hg.peer(repo, opts, dest)
1592 revs = [repo[r].hex() for r in revs]
1592 revs = [repo[r].hex() for r in revs]
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1595 outgoing = discovery.findcommonoutgoing(
1595 outgoing = discovery.findcommonoutgoing(
1596 repo,
1596 repo,
1597 other,
1597 other,
1598 onlyheads=heads,
1598 onlyheads=heads,
1599 force=opts.get(b'force'),
1599 force=opts.get(b'force'),
1600 portable=True,
1600 portable=True,
1601 )
1601 )
1602
1602
1603 if not outgoing.missing:
1603 if not outgoing.missing:
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1605 return 1
1605 return 1
1606
1606
1607 if cgversion == b'01': # bundle1
1607 if cgversion == b'01': # bundle1
1608 bversion = b'HG10' + bundlespec.wirecompression
1608 bversion = b'HG10' + bundlespec.wirecompression
1609 bcompression = None
1609 bcompression = None
1610 elif cgversion in (b'02', b'03'):
1610 elif cgversion in (b'02', b'03'):
1611 bversion = b'HG20'
1611 bversion = b'HG20'
1612 bcompression = bundlespec.wirecompression
1612 bcompression = bundlespec.wirecompression
1613 else:
1613 else:
1614 raise error.ProgrammingError(
1614 raise error.ProgrammingError(
1615 b'bundle: unexpected changegroup version %s' % cgversion
1615 b'bundle: unexpected changegroup version %s' % cgversion
1616 )
1616 )
1617
1617
1618 # TODO compression options should be derived from bundlespec parsing.
1618 # TODO compression options should be derived from bundlespec parsing.
1619 # This is a temporary hack to allow adjusting bundle compression
1619 # This is a temporary hack to allow adjusting bundle compression
1620 # level without a) formalizing the bundlespec changes to declare it
1620 # level without a) formalizing the bundlespec changes to declare it
1621 # b) introducing a command flag.
1621 # b) introducing a command flag.
1622 compopts = {}
1622 compopts = {}
1623 complevel = ui.configint(
1623 complevel = ui.configint(
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1625 )
1625 )
1626 if complevel is None:
1626 if complevel is None:
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1628 if complevel is not None:
1628 if complevel is not None:
1629 compopts[b'level'] = complevel
1629 compopts[b'level'] = complevel
1630
1630
1631 # Allow overriding the bundling of obsmarker in phases through
1631 # Allow overriding the bundling of obsmarker in phases through
1632 # 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
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1634 bundlespec.contentopts[b'obsolescence'] = True
1634 bundlespec.contentopts[b'obsolescence'] = True
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1636 bundlespec.contentopts[b'phases'] = True
1636 bundlespec.contentopts[b'phases'] = True
1637
1637
1638 bundle2.writenewbundle(
1638 bundle2.writenewbundle(
1639 ui,
1639 ui,
1640 repo,
1640 repo,
1641 b'bundle',
1641 b'bundle',
1642 fname,
1642 fname,
1643 bversion,
1643 bversion,
1644 outgoing,
1644 outgoing,
1645 bundlespec.contentopts,
1645 bundlespec.contentopts,
1646 compression=bcompression,
1646 compression=bcompression,
1647 compopts=compopts,
1647 compopts=compopts,
1648 )
1648 )
1649
1649
1650
1650
1651 @command(
1651 @command(
1652 b'cat',
1652 b'cat',
1653 [
1653 [
1654 (
1654 (
1655 b'o',
1655 b'o',
1656 b'output',
1656 b'output',
1657 b'',
1657 b'',
1658 _(b'print output to file with formatted name'),
1658 _(b'print output to file with formatted name'),
1659 _(b'FORMAT'),
1659 _(b'FORMAT'),
1660 ),
1660 ),
1661 (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')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1663 ]
1663 ]
1664 + walkopts
1664 + walkopts
1665 + formatteropts,
1665 + formatteropts,
1666 _(b'[OPTION]... FILE...'),
1666 _(b'[OPTION]... FILE...'),
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1668 inferrepo=True,
1668 inferrepo=True,
1669 intents={INTENT_READONLY},
1669 intents={INTENT_READONLY},
1670 )
1670 )
1671 def cat(ui, repo, file1, *pats, **opts):
1671 def cat(ui, repo, file1, *pats, **opts):
1672 """output the current or given revision of files
1672 """output the current or given revision of files
1673
1673
1674 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
1675 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.
1676
1676
1677 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
1678 given using a template string. See :hg:`help templates`. In addition
1678 given using a template string. See :hg:`help templates`. In addition
1679 to the common template keywords, the following formatting rules are
1679 to the common template keywords, the following formatting rules are
1680 supported:
1680 supported:
1681
1681
1682 :``%%``: literal "%" character
1682 :``%%``: literal "%" character
1683 :``%s``: basename of file being printed
1683 :``%s``: basename of file being printed
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1685 :``%p``: root-relative path name of file being printed
1685 :``%p``: root-relative path name of file being printed
1686 :``%H``: changeset hash (40 hexadecimal digits)
1686 :``%H``: changeset hash (40 hexadecimal digits)
1687 :``%R``: changeset revision number
1687 :``%R``: changeset revision number
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1689 :``%r``: zero-padded changeset revision number
1689 :``%r``: zero-padded changeset revision number
1690 :``%b``: basename of the exporting repository
1690 :``%b``: basename of the exporting repository
1691 :``\\``: literal "\\" character
1691 :``\\``: literal "\\" character
1692
1692
1693 .. container:: verbose
1693 .. container:: verbose
1694
1694
1695 Template:
1695 Template:
1696
1696
1697 The following keywords are supported in addition to the common template
1697 The following keywords are supported in addition to the common template
1698 keywords and functions. See also :hg:`help templates`.
1698 keywords and functions. See also :hg:`help templates`.
1699
1699
1700 :data: String. File content.
1700 :data: String. File content.
1701 :path: String. Repository-absolute path of the file.
1701 :path: String. Repository-absolute path of the file.
1702
1702
1703 Returns 0 on success.
1703 Returns 0 on success.
1704 """
1704 """
1705 opts = pycompat.byteskwargs(opts)
1705 opts = pycompat.byteskwargs(opts)
1706 rev = opts.get(b'rev')
1706 rev = opts.get(b'rev')
1707 if rev:
1707 if rev:
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1709 ctx = scmutil.revsingle(repo, rev)
1709 ctx = scmutil.revsingle(repo, rev)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1711 fntemplate = opts.pop(b'output', b'')
1711 fntemplate = opts.pop(b'output', b'')
1712 if cmdutil.isstdiofilename(fntemplate):
1712 if cmdutil.isstdiofilename(fntemplate):
1713 fntemplate = b''
1713 fntemplate = b''
1714
1714
1715 if fntemplate:
1715 if fntemplate:
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1717 else:
1717 else:
1718 ui.pager(b'cat')
1718 ui.pager(b'cat')
1719 fm = ui.formatter(b'cat', opts)
1719 fm = ui.formatter(b'cat', opts)
1720 with fm:
1720 with fm:
1721 return cmdutil.cat(
1721 return cmdutil.cat(
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1723 )
1723 )
1724
1724
1725
1725
1726 @command(
1726 @command(
1727 b'clone',
1727 b'clone',
1728 [
1728 [
1729 (
1729 (
1730 b'U',
1730 b'U',
1731 b'noupdate',
1731 b'noupdate',
1732 None,
1732 None,
1733 _(
1733 _(
1734 b'the clone will include an empty working '
1734 b'the clone will include an empty working '
1735 b'directory (only a repository)'
1735 b'directory (only a repository)'
1736 ),
1736 ),
1737 ),
1737 ),
1738 (
1738 (
1739 b'u',
1739 b'u',
1740 b'updaterev',
1740 b'updaterev',
1741 b'',
1741 b'',
1742 _(b'revision, tag, or branch to check out'),
1742 _(b'revision, tag, or branch to check out'),
1743 _(b'REV'),
1743 _(b'REV'),
1744 ),
1744 ),
1745 (
1745 (
1746 b'r',
1746 b'r',
1747 b'rev',
1747 b'rev',
1748 [],
1748 [],
1749 _(
1749 _(
1750 b'do not clone everything, but include this changeset'
1750 b'do not clone everything, but include this changeset'
1751 b' and its ancestors'
1751 b' and its ancestors'
1752 ),
1752 ),
1753 _(b'REV'),
1753 _(b'REV'),
1754 ),
1754 ),
1755 (
1755 (
1756 b'b',
1756 b'b',
1757 b'branch',
1757 b'branch',
1758 [],
1758 [],
1759 _(
1759 _(
1760 b'do not clone everything, but include this branch\'s'
1760 b'do not clone everything, but include this branch\'s'
1761 b' changesets and their ancestors'
1761 b' changesets and their ancestors'
1762 ),
1762 ),
1763 _(b'BRANCH'),
1763 _(b'BRANCH'),
1764 ),
1764 ),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1768 ]
1768 ]
1769 + remoteopts,
1769 + remoteopts,
1770 _(b'[OPTION]... SOURCE [DEST]'),
1770 _(b'[OPTION]... SOURCE [DEST]'),
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1772 helpbasic=True,
1772 helpbasic=True,
1773 norepo=True,
1773 norepo=True,
1774 )
1774 )
1775 def clone(ui, source, dest=None, **opts):
1775 def clone(ui, source, dest=None, **opts):
1776 """make a copy of an existing repository
1776 """make a copy of an existing repository
1777
1777
1778 Create a copy of an existing repository in a new directory.
1778 Create a copy of an existing repository in a new directory.
1779
1779
1780 If no destination directory name is specified, it defaults to the
1780 If no destination directory name is specified, it defaults to the
1781 basename of the source.
1781 basename of the source.
1782
1782
1783 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
1784 ``.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.
1785
1785
1786 Only local paths and ``ssh://`` URLs are supported as
1786 Only local paths and ``ssh://`` URLs are supported as
1787 destinations. For ``ssh://`` destinations, no working directory or
1787 destinations. For ``ssh://`` destinations, no working directory or
1788 ``.hg/hgrc`` will be created on the remote side.
1788 ``.hg/hgrc`` will be created on the remote side.
1789
1789
1790 If the source repository has a bookmark called '@' set, that
1790 If the source repository has a bookmark called '@' set, that
1791 revision will be checked out in the new repository by default.
1791 revision will be checked out in the new repository by default.
1792
1792
1793 To check out a particular version, use -u/--update, or
1793 To check out a particular version, use -u/--update, or
1794 -U/--noupdate to create a clone with no working directory.
1794 -U/--noupdate to create a clone with no working directory.
1795
1795
1796 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
1797 identifiers with -r/--rev or branches with -b/--branch. The
1797 identifiers with -r/--rev or branches with -b/--branch. The
1798 resulting clone will contain only the specified changesets and
1798 resulting clone will contain only the specified changesets and
1799 their ancestors. These options (or 'clone src#rev dest') imply
1799 their ancestors. These options (or 'clone src#rev dest') imply
1800 --pull, even for local source repositories.
1800 --pull, even for local source repositories.
1801
1801
1802 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
1803 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
1804 storage format. --stream activates a different clone mode that essentially
1804 storage format. --stream activates a different clone mode that essentially
1805 copies repository files from the remote with minimal data processing. This
1805 copies repository files from the remote with minimal data processing. This
1806 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.
1807 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
1808 result in substantially faster clones where I/O throughput is plentiful,
1808 result in substantially faster clones where I/O throughput is plentiful,
1809 especially for larger repositories. A side-effect of --stream clones is
1809 especially for larger repositories. A side-effect of --stream clones is
1810 that storage settings and requirements on the remote are applied locally:
1810 that storage settings and requirements on the remote are applied locally:
1811 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
1812 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
1813 modern Mercurial remote.
1813 modern Mercurial remote.
1814
1814
1815 .. note::
1815 .. note::
1816
1816
1817 Specifying a tag will include the tagged changeset but not the
1817 Specifying a tag will include the tagged changeset but not the
1818 changeset containing the tag.
1818 changeset containing the tag.
1819
1819
1820 .. container:: verbose
1820 .. container:: verbose
1821
1821
1822 For efficiency, hardlinks are used for cloning whenever the
1822 For efficiency, hardlinks are used for cloning whenever the
1823 source and destination are on the same filesystem (note this
1823 source and destination are on the same filesystem (note this
1824 applies only to the repository data, not to the working
1824 applies only to the repository data, not to the working
1825 directory). Some filesystems, such as AFS, implement hardlinking
1825 directory). Some filesystems, such as AFS, implement hardlinking
1826 incorrectly, but do not report errors. In these cases, use the
1826 incorrectly, but do not report errors. In these cases, use the
1827 --pull option to avoid hardlinking.
1827 --pull option to avoid hardlinking.
1828
1828
1829 Mercurial will update the working directory to the first applicable
1829 Mercurial will update the working directory to the first applicable
1830 revision from this list:
1830 revision from this list:
1831
1831
1832 a) null if -U or the source repository has no changesets
1832 a) null if -U or the source repository has no changesets
1833 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
1834 the source repository's working directory
1834 the source repository's working directory
1835 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
1836 latest head of that branch)
1836 latest head of that branch)
1837 d) the changeset specified with -r
1837 d) the changeset specified with -r
1838 e) the tipmost head specified with -b
1838 e) the tipmost head specified with -b
1839 f) the tipmost head specified with the url#branch source syntax
1839 f) the tipmost head specified with the url#branch source syntax
1840 g) the revision marked with the '@' bookmark, if present
1840 g) the revision marked with the '@' bookmark, if present
1841 h) the tipmost head of the default branch
1841 h) the tipmost head of the default branch
1842 i) tip
1842 i) tip
1843
1843
1844 When cloning from servers that support it, Mercurial may fetch
1844 When cloning from servers that support it, Mercurial may fetch
1845 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
1846 same stream. When this is done, hooks operating on incoming changesets
1846 same stream. When this is done, hooks operating on incoming changesets
1847 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
1848 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,
1849 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
1850 clone. This behavior may change in future releases.
1850 clone. This behavior may change in future releases.
1851 See :hg:`help -e clonebundles` for more.
1851 See :hg:`help -e clonebundles` for more.
1852
1852
1853 Examples:
1853 Examples:
1854
1854
1855 - clone a remote repository to a new directory named hg/::
1855 - clone a remote repository to a new directory named hg/::
1856
1856
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1858
1858
1859 - create a lightweight local clone::
1859 - create a lightweight local clone::
1860
1860
1861 hg clone project/ project-feature/
1861 hg clone project/ project-feature/
1862
1862
1863 - 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)::
1864
1864
1865 hg clone ssh://user@server//home/projects/alpha/
1865 hg clone ssh://user@server//home/projects/alpha/
1866
1866
1867 - do a streaming clone while checking out a specified version::
1867 - do a streaming clone while checking out a specified version::
1868
1868
1869 hg clone --stream http://server/repo -u 1.5
1869 hg clone --stream http://server/repo -u 1.5
1870
1870
1871 - create a repository without changesets after a particular revision::
1871 - create a repository without changesets after a particular revision::
1872
1872
1873 hg clone -r 04e544 experimental/ good/
1873 hg clone -r 04e544 experimental/ good/
1874
1874
1875 - clone (and track) a particular named branch::
1875 - clone (and track) a particular named branch::
1876
1876
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1878
1878
1879 See :hg:`help urls` for details on specifying URLs.
1879 See :hg:`help urls` for details on specifying URLs.
1880
1880
1881 Returns 0 on success.
1881 Returns 0 on success.
1882 """
1882 """
1883 opts = pycompat.byteskwargs(opts)
1883 opts = pycompat.byteskwargs(opts)
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1885
1885
1886 # --include/--exclude can come from narrow or sparse.
1886 # --include/--exclude can come from narrow or sparse.
1887 includepats, excludepats = None, None
1887 includepats, excludepats = None, None
1888
1888
1889 # 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
1890 # patterns are sets if narrow is requested without patterns.
1890 # patterns are sets if narrow is requested without patterns.
1891 if opts.get(b'narrow'):
1891 if opts.get(b'narrow'):
1892 includepats = set()
1892 includepats = set()
1893 excludepats = set()
1893 excludepats = set()
1894
1894
1895 if opts.get(b'include'):
1895 if opts.get(b'include'):
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1897 if opts.get(b'exclude'):
1897 if opts.get(b'exclude'):
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1899
1899
1900 r = hg.clone(
1900 r = hg.clone(
1901 ui,
1901 ui,
1902 opts,
1902 opts,
1903 source,
1903 source,
1904 dest,
1904 dest,
1905 pull=opts.get(b'pull'),
1905 pull=opts.get(b'pull'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1907 revs=opts.get(b'rev'),
1907 revs=opts.get(b'rev'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1909 branch=opts.get(b'branch'),
1909 branch=opts.get(b'branch'),
1910 shareopts=opts.get(b'shareopts'),
1910 shareopts=opts.get(b'shareopts'),
1911 storeincludepats=includepats,
1911 storeincludepats=includepats,
1912 storeexcludepats=excludepats,
1912 storeexcludepats=excludepats,
1913 depth=opts.get(b'depth') or None,
1913 depth=opts.get(b'depth') or None,
1914 )
1914 )
1915
1915
1916 return r is None
1916 return r is None
1917
1917
1918
1918
1919 @command(
1919 @command(
1920 b'commit|ci',
1920 b'commit|ci',
1921 [
1921 [
1922 (
1922 (
1923 b'A',
1923 b'A',
1924 b'addremove',
1924 b'addremove',
1925 None,
1925 None,
1926 _(b'mark new/missing files as added/removed before committing'),
1926 _(b'mark new/missing files as added/removed before committing'),
1927 ),
1927 ),
1928 (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')),
1929 (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')),
1930 (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')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1932 (
1932 (
1933 b'',
1933 b'',
1934 b'force-close-branch',
1934 b'force-close-branch',
1935 None,
1935 None,
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1937 ),
1937 ),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1939 ]
1939 ]
1940 + walkopts
1940 + walkopts
1941 + commitopts
1941 + commitopts
1942 + commitopts2
1942 + commitopts2
1943 + subrepoopts,
1943 + subrepoopts,
1944 _(b'[OPTION]... [FILE]...'),
1944 _(b'[OPTION]... [FILE]...'),
1945 helpcategory=command.CATEGORY_COMMITTING,
1945 helpcategory=command.CATEGORY_COMMITTING,
1946 helpbasic=True,
1946 helpbasic=True,
1947 inferrepo=True,
1947 inferrepo=True,
1948 )
1948 )
1949 def commit(ui, repo, *pats, **opts):
1949 def commit(ui, repo, *pats, **opts):
1950 """commit the specified files or all outstanding changes
1950 """commit the specified files or all outstanding changes
1951
1951
1952 Commit changes to the given files into the repository. Unlike a
1952 Commit changes to the given files into the repository. Unlike a
1953 centralized SCM, this operation is a local operation. See
1953 centralized SCM, this operation is a local operation. See
1954 :hg:`push` for a way to actively distribute your changes.
1954 :hg:`push` for a way to actively distribute your changes.
1955
1955
1956 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`
1957 will be committed.
1957 will be committed.
1958
1958
1959 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
1960 filenames or -I/-X filters.
1960 filenames or -I/-X filters.
1961
1961
1962 If no commit message is specified, Mercurial starts your
1962 If no commit message is specified, Mercurial starts your
1963 configured editor where you can enter a message. In case your
1963 configured editor where you can enter a message. In case your
1964 commit fails, you will find a backup of your message in
1964 commit fails, you will find a backup of your message in
1965 ``.hg/last-message.txt``.
1965 ``.hg/last-message.txt``.
1966
1966
1967 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
1968 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
1969 will be considered closed and no longer listed.
1969 will be considered closed and no longer listed.
1970
1970
1971 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
1972 working directory with a new commit that contains the changes
1972 working directory with a new commit that contains the changes
1973 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`,
1974 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
1975 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1975 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1976 on how to restore it).
1976 on how to restore it).
1977
1977
1978 Message, user and date are taken from the amended commit unless
1978 Message, user and date are taken from the amended commit unless
1979 specified. When a message isn't specified on the command line,
1979 specified. When a message isn't specified on the command line,
1980 the editor will open with the message of the amended commit.
1980 the editor will open with the message of the amended commit.
1981
1981
1982 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`)
1983 or changesets that have children.
1983 or changesets that have children.
1984
1984
1985 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.
1986
1986
1987 Returns 0 on success, 1 if nothing changed.
1987 Returns 0 on success, 1 if nothing changed.
1988
1988
1989 .. container:: verbose
1989 .. container:: verbose
1990
1990
1991 Examples:
1991 Examples:
1992
1992
1993 - commit all files ending in .py::
1993 - commit all files ending in .py::
1994
1994
1995 hg commit --include "set:**.py"
1995 hg commit --include "set:**.py"
1996
1996
1997 - commit all non-binary files::
1997 - commit all non-binary files::
1998
1998
1999 hg commit --exclude "set:binary()"
1999 hg commit --exclude "set:binary()"
2000
2000
2001 - amend the current commit and set the date to now::
2001 - amend the current commit and set the date to now::
2002
2002
2003 hg commit --amend --date now
2003 hg commit --amend --date now
2004 """
2004 """
2005 with repo.wlock(), repo.lock():
2005 with repo.wlock(), repo.lock():
2006 return _docommit(ui, repo, *pats, **opts)
2006 return _docommit(ui, repo, *pats, **opts)
2007
2007
2008
2008
2009 def _docommit(ui, repo, *pats, **opts):
2009 def _docommit(ui, repo, *pats, **opts):
2010 if opts.get('interactive'):
2010 if opts.get('interactive'):
2011 opts.pop('interactive')
2011 opts.pop('interactive')
2012 ret = cmdutil.dorecord(
2012 ret = cmdutil.dorecord(
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2014 )
2014 )
2015 # 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
2016 # commit(), 1 if nothing changed or None on success.
2016 # commit(), 1 if nothing changed or None on success.
2017 return 1 if ret == 0 else ret
2017 return 1 if ret == 0 else ret
2018
2018
2019 opts = pycompat.byteskwargs(opts)
2019 opts = pycompat.byteskwargs(opts)
2020 if opts.get(b'subrepos'):
2020 if opts.get(b'subrepos'):
2021 if opts.get(b'amend'):
2021 if opts.get(b'amend'):
2022 raise error.Abort(_(b'cannot amend with --subrepos'))
2022 raise error.Abort(_(b'cannot amend with --subrepos'))
2023 # Let --subrepos on the command line override config setting.
2023 # Let --subrepos on the command line override config setting.
2024 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2024 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2025
2025
2026 cmdutil.checkunfinished(repo, commit=True)
2026 cmdutil.checkunfinished(repo, commit=True)
2027
2027
2028 branch = repo[None].branch()
2028 branch = repo[None].branch()
2029 bheads = repo.branchheads(branch)
2029 bheads = repo.branchheads(branch)
2030
2030
2031 extra = {}
2031 extra = {}
2032 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'):
2033 extra[b'close'] = b'1'
2033 extra[b'close'] = b'1'
2034
2034
2035 if repo[b'.'].closesbranch():
2035 if repo[b'.'].closesbranch():
2036 raise error.Abort(
2036 raise error.Abort(
2037 _(b'current revision is already a branch closing head')
2037 _(b'current revision is already a branch closing head')
2038 )
2038 )
2039 elif not bheads:
2039 elif not bheads:
2040 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)
2041 elif (
2041 elif (
2042 branch == repo[b'.'].branch()
2042 branch == repo[b'.'].branch()
2043 and repo[b'.'].node() not in bheads
2043 and repo[b'.'].node() not in bheads
2044 and not opts.get(b'force_close_branch')
2044 and not opts.get(b'force_close_branch')
2045 ):
2045 ):
2046 hint = _(
2046 hint = _(
2047 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'
2048 b' changeset'
2048 b' changeset'
2049 )
2049 )
2050 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2050 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2051 elif opts.get(b'amend'):
2051 elif opts.get(b'amend'):
2052 if (
2052 if (
2053 repo[b'.'].p1().branch() != branch
2053 repo[b'.'].p1().branch() != branch
2054 and repo[b'.'].p2().branch() != branch
2054 and repo[b'.'].p2().branch() != branch
2055 ):
2055 ):
2056 raise error.Abort(_(b'can only close branch heads'))
2056 raise error.Abort(_(b'can only close branch heads'))
2057
2057
2058 if opts.get(b'amend'):
2058 if opts.get(b'amend'):
2059 if ui.configbool(b'ui', b'commitsubrepos'):
2059 if ui.configbool(b'ui', b'commitsubrepos'):
2060 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2060 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2061
2061
2062 old = repo[b'.']
2062 old = repo[b'.']
2063 rewriteutil.precheck(repo, [old.rev()], b'amend')
2063 rewriteutil.precheck(repo, [old.rev()], b'amend')
2064
2064
2065 # Currently histedit gets confused if an amend happens while histedit
2065 # Currently histedit gets confused if an amend happens while histedit
2066 # is in progress. Since we have a checkunfinished command, we are
2066 # is in progress. Since we have a checkunfinished command, we are
2067 # temporarily honoring it.
2067 # temporarily honoring it.
2068 #
2068 #
2069 # Note: eventually this guard will be removed. Please do not expect
2069 # Note: eventually this guard will be removed. Please do not expect
2070 # this behavior to remain.
2070 # this behavior to remain.
2071 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2071 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2072 cmdutil.checkunfinished(repo)
2072 cmdutil.checkunfinished(repo)
2073
2073
2074 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2074 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2075 if node == old.node():
2075 if node == old.node():
2076 ui.status(_(b"nothing changed\n"))
2076 ui.status(_(b"nothing changed\n"))
2077 return 1
2077 return 1
2078 else:
2078 else:
2079
2079
2080 def commitfunc(ui, repo, message, match, opts):
2080 def commitfunc(ui, repo, message, match, opts):
2081 overrides = {}
2081 overrides = {}
2082 if opts.get(b'secret'):
2082 if opts.get(b'secret'):
2083 overrides[(b'phases', b'new-commit')] = b'secret'
2083 overrides[(b'phases', b'new-commit')] = b'secret'
2084
2084
2085 baseui = repo.baseui
2085 baseui = repo.baseui
2086 with baseui.configoverride(overrides, b'commit'):
2086 with baseui.configoverride(overrides, b'commit'):
2087 with ui.configoverride(overrides, b'commit'):
2087 with ui.configoverride(overrides, b'commit'):
2088 editform = cmdutil.mergeeditform(
2088 editform = cmdutil.mergeeditform(
2089 repo[None], b'commit.normal'
2089 repo[None], b'commit.normal'
2090 )
2090 )
2091 editor = cmdutil.getcommiteditor(
2091 editor = cmdutil.getcommiteditor(
2092 editform=editform, **pycompat.strkwargs(opts)
2092 editform=editform, **pycompat.strkwargs(opts)
2093 )
2093 )
2094 return repo.commit(
2094 return repo.commit(
2095 message,
2095 message,
2096 opts.get(b'user'),
2096 opts.get(b'user'),
2097 opts.get(b'date'),
2097 opts.get(b'date'),
2098 match,
2098 match,
2099 editor=editor,
2099 editor=editor,
2100 extra=extra,
2100 extra=extra,
2101 )
2101 )
2102
2102
2103 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2103 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2104
2104
2105 if not node:
2105 if not node:
2106 stat = cmdutil.postcommitstatus(repo, pats, opts)
2106 stat = cmdutil.postcommitstatus(repo, pats, opts)
2107 if stat.deleted:
2107 if stat.deleted:
2108 ui.status(
2108 ui.status(
2109 _(
2109 _(
2110 b"nothing changed (%d missing files, see "
2110 b"nothing changed (%d missing files, see "
2111 b"'hg status')\n"
2111 b"'hg status')\n"
2112 )
2112 )
2113 % len(stat.deleted)
2113 % len(stat.deleted)
2114 )
2114 )
2115 else:
2115 else:
2116 ui.status(_(b"nothing changed\n"))
2116 ui.status(_(b"nothing changed\n"))
2117 return 1
2117 return 1
2118
2118
2119 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2119 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2120
2120
2121 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'):
2122 status(
2122 status(
2123 ui,
2123 ui,
2124 repo,
2124 repo,
2125 modified=True,
2125 modified=True,
2126 added=True,
2126 added=True,
2127 removed=True,
2127 removed=True,
2128 deleted=True,
2128 deleted=True,
2129 unknown=True,
2129 unknown=True,
2130 subrepos=opts.get(b'subrepos'),
2130 subrepos=opts.get(b'subrepos'),
2131 )
2131 )
2132
2132
2133
2133
2134 @command(
2134 @command(
2135 b'config|showconfig|debugconfig',
2135 b'config|showconfig|debugconfig',
2136 [
2136 [
2137 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2137 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2138 (b'e', b'edit', None, _(b'edit user config')),
2138 (b'e', b'edit', None, _(b'edit user config')),
2139 (b'l', b'local', None, _(b'edit repository config')),
2139 (b'l', b'local', None, _(b'edit repository config')),
2140 (
2140 (
2141 b'',
2141 b'',
2142 b'shared',
2142 b'shared',
2143 None,
2143 None,
2144 _(b'edit shared source repository config (EXPERIMENTAL)'),
2144 _(b'edit shared source repository config (EXPERIMENTAL)'),
2145 ),
2145 ),
2146 (b'g', b'global', None, _(b'edit global config')),
2146 (b'g', b'global', None, _(b'edit global config')),
2147 ]
2147 ]
2148 + formatteropts,
2148 + formatteropts,
2149 _(b'[-u] [NAME]...'),
2149 _(b'[-u] [NAME]...'),
2150 helpcategory=command.CATEGORY_HELP,
2150 helpcategory=command.CATEGORY_HELP,
2151 optionalrepo=True,
2151 optionalrepo=True,
2152 intents={INTENT_READONLY},
2152 intents={INTENT_READONLY},
2153 )
2153 )
2154 def config(ui, repo, *values, **opts):
2154 def config(ui, repo, *values, **opts):
2155 """show combined config settings from all hgrc files
2155 """show combined config settings from all hgrc files
2156
2156
2157 With no arguments, print names and values of all config items.
2157 With no arguments, print names and values of all config items.
2158
2158
2159 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
2160 of that config item.
2160 of that config item.
2161
2161
2162 With multiple arguments, print names and values of all config
2162 With multiple arguments, print names and values of all config
2163 items with matching section names or section.names.
2163 items with matching section names or section.names.
2164
2164
2165 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
2166 --global, edit the system-wide config file. With --local, edit the
2166 --global, edit the system-wide config file. With --local, edit the
2167 repository-level config file.
2167 repository-level config file.
2168
2168
2169 With --debug, the source (filename and line number) is printed
2169 With --debug, the source (filename and line number) is printed
2170 for each config item.
2170 for each config item.
2171
2171
2172 See :hg:`help config` for more information about config files.
2172 See :hg:`help config` for more information about config files.
2173
2173
2174 .. container:: verbose
2174 .. container:: verbose
2175
2175
2176 Template:
2176 Template:
2177
2177
2178 The following keywords are supported. See also :hg:`help templates`.
2178 The following keywords are supported. See also :hg:`help templates`.
2179
2179
2180 :name: String. Config name.
2180 :name: String. Config name.
2181 :source: String. Filename and line number where the item is defined.
2181 :source: String. Filename and line number where the item is defined.
2182 :value: String. Config value.
2182 :value: String. Config value.
2183
2183
2184 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
2185 repository. It only works when you have shared using the experimental
2185 repository. It only works when you have shared using the experimental
2186 share safe feature.
2186 share safe feature.
2187
2187
2188 Returns 0 on success, 1 if NAME does not exist.
2188 Returns 0 on success, 1 if NAME does not exist.
2189
2189
2190 """
2190 """
2191
2191
2192 opts = pycompat.byteskwargs(opts)
2192 opts = pycompat.byteskwargs(opts)
2193 editopts = (b'edit', b'local', b'global', b'shared')
2193 editopts = (b'edit', b'local', b'global', b'shared')
2194 if any(opts.get(o) for o in editopts):
2194 if any(opts.get(o) for o in editopts):
2195 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2195 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2196 if opts.get(b'local'):
2196 if opts.get(b'local'):
2197 if not repo:
2197 if not repo:
2198 raise error.Abort(_(b"can't use --local outside a repository"))
2198 raise error.Abort(_(b"can't use --local outside a repository"))
2199 paths = [repo.vfs.join(b'hgrc')]
2199 paths = [repo.vfs.join(b'hgrc')]
2200 elif opts.get(b'global'):
2200 elif opts.get(b'global'):
2201 paths = rcutil.systemrcpath()
2201 paths = rcutil.systemrcpath()
2202 elif opts.get(b'shared'):
2202 elif opts.get(b'shared'):
2203 if not repo.shared():
2203 if not repo.shared():
2204 raise error.Abort(
2204 raise error.Abort(
2205 _(b"repository is not shared; can't use --shared")
2205 _(b"repository is not shared; can't use --shared")
2206 )
2206 )
2207 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2207 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2208 raise error.Abort(
2208 raise error.Abort(
2209 _(
2209 _(
2210 b"share safe feature not unabled; "
2210 b"share safe feature not unabled; "
2211 b"unable to edit shared source repository config"
2211 b"unable to edit shared source repository config"
2212 )
2212 )
2213 )
2213 )
2214 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2214 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2215 else:
2215 else:
2216 paths = rcutil.userrcpath()
2216 paths = rcutil.userrcpath()
2217
2217
2218 for f in paths:
2218 for f in paths:
2219 if os.path.exists(f):
2219 if os.path.exists(f):
2220 break
2220 break
2221 else:
2221 else:
2222 if opts.get(b'global'):
2222 if opts.get(b'global'):
2223 samplehgrc = uimod.samplehgrcs[b'global']
2223 samplehgrc = uimod.samplehgrcs[b'global']
2224 elif opts.get(b'local'):
2224 elif opts.get(b'local'):
2225 samplehgrc = uimod.samplehgrcs[b'local']
2225 samplehgrc = uimod.samplehgrcs[b'local']
2226 else:
2226 else:
2227 samplehgrc = uimod.samplehgrcs[b'user']
2227 samplehgrc = uimod.samplehgrcs[b'user']
2228
2228
2229 f = paths[0]
2229 f = paths[0]
2230 fp = open(f, b"wb")
2230 fp = open(f, b"wb")
2231 fp.write(util.tonativeeol(samplehgrc))
2231 fp.write(util.tonativeeol(samplehgrc))
2232 fp.close()
2232 fp.close()
2233
2233
2234 editor = ui.geteditor()
2234 editor = ui.geteditor()
2235 ui.system(
2235 ui.system(
2236 b"%s \"%s\"" % (editor, f),
2236 b"%s \"%s\"" % (editor, f),
2237 onerr=error.Abort,
2237 onerr=error.Abort,
2238 errprefix=_(b"edit failed"),
2238 errprefix=_(b"edit failed"),
2239 blockedtag=b'config_edit',
2239 blockedtag=b'config_edit',
2240 )
2240 )
2241 return
2241 return
2242 ui.pager(b'config')
2242 ui.pager(b'config')
2243 fm = ui.formatter(b'config', opts)
2243 fm = ui.formatter(b'config', opts)
2244 for t, f in rcutil.rccomponents():
2244 for t, f in rcutil.rccomponents():
2245 if t == b'path':
2245 if t == b'path':
2246 ui.debug(b'read config from: %s\n' % f)
2246 ui.debug(b'read config from: %s\n' % f)
2247 elif t == b'resource':
2247 elif t == b'resource':
2248 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]))
2249 elif t == b'items':
2249 elif t == b'items':
2250 # Don't print anything for 'items'.
2250 # Don't print anything for 'items'.
2251 pass
2251 pass
2252 else:
2252 else:
2253 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2253 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2254 untrusted = bool(opts.get(b'untrusted'))
2254 untrusted = bool(opts.get(b'untrusted'))
2255
2255
2256 selsections = selentries = []
2256 selsections = selentries = []
2257 if values:
2257 if values:
2258 selsections = [v for v in values if b'.' not in v]
2258 selsections = [v for v in values if b'.' not in v]
2259 selentries = [v for v in values if b'.' in v]
2259 selentries = [v for v in values if b'.' in v]
2260 uniquesel = len(selentries) == 1 and not selsections
2260 uniquesel = len(selentries) == 1 and not selsections
2261 selsections = set(selsections)
2261 selsections = set(selsections)
2262 selentries = set(selentries)
2262 selentries = set(selentries)
2263
2263
2264 matched = False
2264 matched = False
2265 for section, name, value in ui.walkconfig(untrusted=untrusted):
2265 for section, name, value in ui.walkconfig(untrusted=untrusted):
2266 source = ui.configsource(section, name, untrusted)
2266 source = ui.configsource(section, name, untrusted)
2267 value = pycompat.bytestr(value)
2267 value = pycompat.bytestr(value)
2268 defaultvalue = ui.configdefault(section, name)
2268 defaultvalue = ui.configdefault(section, name)
2269 if fm.isplain():
2269 if fm.isplain():
2270 source = source or b'none'
2270 source = source or b'none'
2271 value = value.replace(b'\n', b'\\n')
2271 value = value.replace(b'\n', b'\\n')
2272 entryname = section + b'.' + name
2272 entryname = section + b'.' + name
2273 if values and not (section in selsections or entryname in selentries):
2273 if values and not (section in selsections or entryname in selentries):
2274 continue
2274 continue
2275 fm.startitem()
2275 fm.startitem()
2276 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2276 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2277 if uniquesel:
2277 if uniquesel:
2278 fm.data(name=entryname)
2278 fm.data(name=entryname)
2279 fm.write(b'value', b'%s\n', value)
2279 fm.write(b'value', b'%s\n', value)
2280 else:
2280 else:
2281 fm.write(b'name value', b'%s=%s\n', entryname, value)
2281 fm.write(b'name value', b'%s=%s\n', entryname, value)
2282 if formatter.isprintable(defaultvalue):
2282 if formatter.isprintable(defaultvalue):
2283 fm.data(defaultvalue=defaultvalue)
2283 fm.data(defaultvalue=defaultvalue)
2284 elif isinstance(defaultvalue, list) and all(
2284 elif isinstance(defaultvalue, list) and all(
2285 formatter.isprintable(e) for e in defaultvalue
2285 formatter.isprintable(e) for e in defaultvalue
2286 ):
2286 ):
2287 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2287 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2288 # TODO: no idea how to process unsupported defaultvalue types
2288 # TODO: no idea how to process unsupported defaultvalue types
2289 matched = True
2289 matched = True
2290 fm.end()
2290 fm.end()
2291 if matched:
2291 if matched:
2292 return 0
2292 return 0
2293 return 1
2293 return 1
2294
2294
2295
2295
2296 @command(
2296 @command(
2297 b'continue',
2297 b'continue',
2298 dryrunopts,
2298 dryrunopts,
2299 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2299 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2300 helpbasic=True,
2300 helpbasic=True,
2301 )
2301 )
2302 def continuecmd(ui, repo, **opts):
2302 def continuecmd(ui, repo, **opts):
2303 """resumes an interrupted operation (EXPERIMENTAL)
2303 """resumes an interrupted operation (EXPERIMENTAL)
2304
2304
2305 Finishes a multistep operation like graft, histedit, rebase, merge,
2305 Finishes a multistep operation like graft, histedit, rebase, merge,
2306 and unshelve if they are in an interrupted state.
2306 and unshelve if they are in an interrupted state.
2307
2307
2308 use --dry-run/-n to dry run the command.
2308 use --dry-run/-n to dry run the command.
2309 """
2309 """
2310 dryrun = opts.get('dry_run')
2310 dryrun = opts.get('dry_run')
2311 contstate = cmdutil.getunfinishedstate(repo)
2311 contstate = cmdutil.getunfinishedstate(repo)
2312 if not contstate:
2312 if not contstate:
2313 raise error.Abort(_(b'no operation in progress'))
2313 raise error.Abort(_(b'no operation in progress'))
2314 if not contstate.continuefunc:
2314 if not contstate.continuefunc:
2315 raise error.Abort(
2315 raise error.Abort(
2316 (
2316 (
2317 _(b"%s in progress but does not support 'hg continue'")
2317 _(b"%s in progress but does not support 'hg continue'")
2318 % (contstate._opname)
2318 % (contstate._opname)
2319 ),
2319 ),
2320 hint=contstate.continuemsg(),
2320 hint=contstate.continuemsg(),
2321 )
2321 )
2322 if dryrun:
2322 if dryrun:
2323 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))
2324 return
2324 return
2325 return contstate.continuefunc(ui, repo)
2325 return contstate.continuefunc(ui, repo)
2326
2326
2327
2327
2328 @command(
2328 @command(
2329 b'copy|cp',
2329 b'copy|cp',
2330 [
2330 [
2331 (b'', b'forget', None, _(b'unmark a file as copied')),
2331 (b'', b'forget', None, _(b'unmark a file as copied')),
2332 (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')),
2333 (
2333 (
2334 b'',
2334 b'',
2335 b'at-rev',
2335 b'at-rev',
2336 b'',
2336 b'',
2337 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2337 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2338 _(b'REV'),
2338 _(b'REV'),
2339 ),
2339 ),
2340 (
2340 (
2341 b'f',
2341 b'f',
2342 b'force',
2342 b'force',
2343 None,
2343 None,
2344 _(b'forcibly copy over an existing managed file'),
2344 _(b'forcibly copy over an existing managed file'),
2345 ),
2345 ),
2346 ]
2346 ]
2347 + walkopts
2347 + walkopts
2348 + dryrunopts,
2348 + dryrunopts,
2349 _(b'[OPTION]... SOURCE... DEST'),
2349 _(b'[OPTION]... SOURCE... DEST'),
2350 helpcategory=command.CATEGORY_FILE_CONTENTS,
2350 helpcategory=command.CATEGORY_FILE_CONTENTS,
2351 )
2351 )
2352 def copy(ui, repo, *pats, **opts):
2352 def copy(ui, repo, *pats, **opts):
2353 """mark files as copied for the next commit
2353 """mark files as copied for the next commit
2354
2354
2355 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
2356 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,
2357 the source must be a single file.
2357 the source must be a single file.
2358
2358
2359 By default, this command copies the contents of files as they
2359 By default, this command copies the contents of files as they
2360 exist in the working directory. If invoked with -A/--after, the
2360 exist in the working directory. If invoked with -A/--after, the
2361 operation is recorded, but no copying is performed.
2361 operation is recorded, but no copying is performed.
2362
2362
2363 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,
2364 all given (positional) arguments are unmarked as copies. The destination
2364 all given (positional) arguments are unmarked as copies. The destination
2365 file(s) will be left in place (still tracked).
2365 file(s) will be left in place (still tracked).
2366
2366
2367 This command takes effect with the next commit by default.
2367 This command takes effect with the next commit by default.
2368
2368
2369 Returns 0 on success, 1 if errors are encountered.
2369 Returns 0 on success, 1 if errors are encountered.
2370 """
2370 """
2371 opts = pycompat.byteskwargs(opts)
2371 opts = pycompat.byteskwargs(opts)
2372 with repo.wlock():
2372 with repo.wlock():
2373 return cmdutil.copy(ui, repo, pats, opts)
2373 return cmdutil.copy(ui, repo, pats, opts)
2374
2374
2375
2375
2376 @command(
2376 @command(
2377 b'debugcommands',
2377 b'debugcommands',
2378 [],
2378 [],
2379 _(b'[COMMAND]'),
2379 _(b'[COMMAND]'),
2380 helpcategory=command.CATEGORY_HELP,
2380 helpcategory=command.CATEGORY_HELP,
2381 norepo=True,
2381 norepo=True,
2382 )
2382 )
2383 def debugcommands(ui, cmd=b'', *args):
2383 def debugcommands(ui, cmd=b'', *args):
2384 """list all available commands and options"""
2384 """list all available commands and options"""
2385 for cmd, vals in sorted(pycompat.iteritems(table)):
2385 for cmd, vals in sorted(pycompat.iteritems(table)):
2386 cmd = cmd.split(b'|')[0]
2386 cmd = cmd.split(b'|')[0]
2387 opts = b', '.join([i[1] for i in vals[1]])
2387 opts = b', '.join([i[1] for i in vals[1]])
2388 ui.write(b'%s: %s\n' % (cmd, opts))
2388 ui.write(b'%s: %s\n' % (cmd, opts))
2389
2389
2390
2390
2391 @command(
2391 @command(
2392 b'debugcomplete',
2392 b'debugcomplete',
2393 [(b'o', b'options', None, _(b'show the command options'))],
2393 [(b'o', b'options', None, _(b'show the command options'))],
2394 _(b'[-o] CMD'),
2394 _(b'[-o] CMD'),
2395 helpcategory=command.CATEGORY_HELP,
2395 helpcategory=command.CATEGORY_HELP,
2396 norepo=True,
2396 norepo=True,
2397 )
2397 )
2398 def debugcomplete(ui, cmd=b'', **opts):
2398 def debugcomplete(ui, cmd=b'', **opts):
2399 """returns the completion list associated with the given command"""
2399 """returns the completion list associated with the given command"""
2400
2400
2401 if opts.get('options'):
2401 if opts.get('options'):
2402 options = []
2402 options = []
2403 otables = [globalopts]
2403 otables = [globalopts]
2404 if cmd:
2404 if cmd:
2405 aliases, entry = cmdutil.findcmd(cmd, table, False)
2405 aliases, entry = cmdutil.findcmd(cmd, table, False)
2406 otables.append(entry[1])
2406 otables.append(entry[1])
2407 for t in otables:
2407 for t in otables:
2408 for o in t:
2408 for o in t:
2409 if b"(DEPRECATED)" in o[3]:
2409 if b"(DEPRECATED)" in o[3]:
2410 continue
2410 continue
2411 if o[0]:
2411 if o[0]:
2412 options.append(b'-%s' % o[0])
2412 options.append(b'-%s' % o[0])
2413 options.append(b'--%s' % o[1])
2413 options.append(b'--%s' % o[1])
2414 ui.write(b"%s\n" % b"\n".join(options))
2414 ui.write(b"%s\n" % b"\n".join(options))
2415 return
2415 return
2416
2416
2417 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2417 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2418 if ui.verbose:
2418 if ui.verbose:
2419 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2419 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2420 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2420 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2421
2421
2422
2422
2423 @command(
2423 @command(
2424 b'diff',
2424 b'diff',
2425 [
2425 [
2426 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2426 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2427 (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')),
2428 ]
2428 ]
2429 + diffopts
2429 + diffopts
2430 + diffopts2
2430 + diffopts2
2431 + walkopts
2431 + walkopts
2432 + subrepoopts,
2432 + subrepoopts,
2433 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2433 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2434 helpcategory=command.CATEGORY_FILE_CONTENTS,
2434 helpcategory=command.CATEGORY_FILE_CONTENTS,
2435 helpbasic=True,
2435 helpbasic=True,
2436 inferrepo=True,
2436 inferrepo=True,
2437 intents={INTENT_READONLY},
2437 intents={INTENT_READONLY},
2438 )
2438 )
2439 def diff(ui, repo, *pats, **opts):
2439 def diff(ui, repo, *pats, **opts):
2440 """diff repository (or selected files)
2440 """diff repository (or selected files)
2441
2441
2442 Show differences between revisions for the specified files.
2442 Show differences between revisions for the specified files.
2443
2443
2444 Differences between files are shown using the unified diff format.
2444 Differences between files are shown using the unified diff format.
2445
2445
2446 .. note::
2446 .. note::
2447
2447
2448 :hg:`diff` may generate unexpected results for merges, as it will
2448 :hg:`diff` may generate unexpected results for merges, as it will
2449 default to comparing against the working directory's first
2449 default to comparing against the working directory's first
2450 parent changeset if no revisions are specified.
2450 parent changeset if no revisions are specified.
2451
2451
2452 When two revision arguments are given, then changes are shown
2452 When two revision arguments are given, then changes are shown
2453 between those revisions. If only one revision is specified then
2453 between those revisions. If only one revision is specified then
2454 that revision is compared to the working directory, and, when no
2454 that revision is compared to the working directory, and, when no
2455 revisions are specified, the working directory files are compared
2455 revisions are specified, the working directory files are compared
2456 to its first parent.
2456 to its first parent.
2457
2457
2458 Alternatively you can specify -c/--change with a revision to see
2458 Alternatively you can specify -c/--change with a revision to see
2459 the changes in that changeset relative to its first parent.
2459 the changes in that changeset relative to its first parent.
2460
2460
2461 Without the -a/--text option, diff will avoid generating diffs of
2461 Without the -a/--text option, diff will avoid generating diffs of
2462 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
2463 anyway, probably with undesirable results.
2463 anyway, probably with undesirable results.
2464
2464
2465 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
2466 format. For more information, read :hg:`help diffs`.
2466 format. For more information, read :hg:`help diffs`.
2467
2467
2468 .. container:: verbose
2468 .. container:: verbose
2469
2469
2470 Examples:
2470 Examples:
2471
2471
2472 - compare a file in the current working directory to its parent::
2472 - compare a file in the current working directory to its parent::
2473
2473
2474 hg diff foo.c
2474 hg diff foo.c
2475
2475
2476 - compare two historical versions of a directory, with rename info::
2476 - compare two historical versions of a directory, with rename info::
2477
2477
2478 hg diff --git -r 1.0:1.2 lib/
2478 hg diff --git -r 1.0:1.2 lib/
2479
2479
2480 - get change stats relative to the last change on some date::
2480 - get change stats relative to the last change on some date::
2481
2481
2482 hg diff --stat -r "date('may 2')"
2482 hg diff --stat -r "date('may 2')"
2483
2483
2484 - diff all newly-added files that contain a keyword::
2484 - diff all newly-added files that contain a keyword::
2485
2485
2486 hg diff "set:added() and grep(GNU)"
2486 hg diff "set:added() and grep(GNU)"
2487
2487
2488 - compare a revision and its parents::
2488 - compare a revision and its parents::
2489
2489
2490 hg diff -c 9353 # compare against first parent
2490 hg diff -c 9353 # compare against first parent
2491 hg diff -r 9353^:9353 # same using revset syntax
2491 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^2:9353 # compare against the second parent
2492 hg diff -r 9353^2:9353 # compare against the second parent
2493
2493
2494 Returns 0 on success.
2494 Returns 0 on success.
2495 """
2495 """
2496
2496
2497 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2497 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2498 opts = pycompat.byteskwargs(opts)
2498 opts = pycompat.byteskwargs(opts)
2499 revs = opts.get(b'rev')
2499 revs = opts.get(b'rev')
2500 change = opts.get(b'change')
2500 change = opts.get(b'change')
2501 stat = opts.get(b'stat')
2501 stat = opts.get(b'stat')
2502 reverse = opts.get(b'reverse')
2502 reverse = opts.get(b'reverse')
2503
2503
2504 if change:
2504 if change:
2505 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2505 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2506 ctx2 = scmutil.revsingle(repo, change, None)
2506 ctx2 = scmutil.revsingle(repo, change, None)
2507 ctx1 = ctx2.p1()
2507 ctx1 = ctx2.p1()
2508 else:
2508 else:
2509 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2509 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2510 ctx1, ctx2 = scmutil.revpair(repo, revs)
2510 ctx1, ctx2 = scmutil.revpair(repo, revs)
2511
2511
2512 if reverse:
2512 if reverse:
2513 ctxleft = ctx2
2513 ctxleft = ctx2
2514 ctxright = ctx1
2514 ctxright = ctx1
2515 else:
2515 else:
2516 ctxleft = ctx1
2516 ctxleft = ctx1
2517 ctxright = ctx2
2517 ctxright = ctx2
2518
2518
2519 diffopts = patch.diffallopts(ui, opts)
2519 diffopts = patch.diffallopts(ui, opts)
2520 m = scmutil.match(ctx2, pats, opts)
2520 m = scmutil.match(ctx2, pats, opts)
2521 m = repo.narrowmatch(m)
2521 m = repo.narrowmatch(m)
2522 ui.pager(b'diff')
2522 ui.pager(b'diff')
2523 logcmdutil.diffordiffstat(
2523 logcmdutil.diffordiffstat(
2524 ui,
2524 ui,
2525 repo,
2525 repo,
2526 diffopts,
2526 diffopts,
2527 ctxleft,
2527 ctxleft,
2528 ctxright,
2528 ctxright,
2529 m,
2529 m,
2530 stat=stat,
2530 stat=stat,
2531 listsubrepos=opts.get(b'subrepos'),
2531 listsubrepos=opts.get(b'subrepos'),
2532 root=opts.get(b'root'),
2532 root=opts.get(b'root'),
2533 )
2533 )
2534
2534
2535
2535
2536 @command(
2536 @command(
2537 b'export',
2537 b'export',
2538 [
2538 [
2539 (
2539 (
2540 b'B',
2540 b'B',
2541 b'bookmark',
2541 b'bookmark',
2542 b'',
2542 b'',
2543 _(b'export changes only reachable by given bookmark'),
2543 _(b'export changes only reachable by given bookmark'),
2544 _(b'BOOKMARK'),
2544 _(b'BOOKMARK'),
2545 ),
2545 ),
2546 (
2546 (
2547 b'o',
2547 b'o',
2548 b'output',
2548 b'output',
2549 b'',
2549 b'',
2550 _(b'print output to file with formatted name'),
2550 _(b'print output to file with formatted name'),
2551 _(b'FORMAT'),
2551 _(b'FORMAT'),
2552 ),
2552 ),
2553 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2553 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2554 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2554 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2555 ]
2555 ]
2556 + diffopts
2556 + diffopts
2557 + formatteropts,
2557 + formatteropts,
2558 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2558 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2559 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2559 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2560 helpbasic=True,
2560 helpbasic=True,
2561 intents={INTENT_READONLY},
2561 intents={INTENT_READONLY},
2562 )
2562 )
2563 def export(ui, repo, *changesets, **opts):
2563 def export(ui, repo, *changesets, **opts):
2564 """dump the header and diffs for one or more changesets
2564 """dump the header and diffs for one or more changesets
2565
2565
2566 Print the changeset header and diffs for one or more revisions.
2566 Print the changeset header and diffs for one or more revisions.
2567 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.
2568
2568
2569 The information shown in the changeset header is: author, date,
2569 The information shown in the changeset header is: author, date,
2570 branch name (if non-default), changeset hash, parent(s) and commit
2570 branch name (if non-default), changeset hash, parent(s) and commit
2571 comment.
2571 comment.
2572
2572
2573 .. note::
2573 .. note::
2574
2574
2575 :hg:`export` may generate unexpected diff output for merge
2575 :hg:`export` may generate unexpected diff output for merge
2576 changesets, as it will compare the merge changeset against its
2576 changesets, as it will compare the merge changeset against its
2577 first parent only.
2577 first parent only.
2578
2578
2579 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
2580 given using a template string. See :hg:`help templates`. In addition
2580 given using a template string. See :hg:`help templates`. In addition
2581 to the common template keywords, the following formatting rules are
2581 to the common template keywords, the following formatting rules are
2582 supported:
2582 supported:
2583
2583
2584 :``%%``: literal "%" character
2584 :``%%``: literal "%" character
2585 :``%H``: changeset hash (40 hexadecimal digits)
2585 :``%H``: changeset hash (40 hexadecimal digits)
2586 :``%N``: number of patches being generated
2586 :``%N``: number of patches being generated
2587 :``%R``: changeset revision number
2587 :``%R``: changeset revision number
2588 :``%b``: basename of the exporting repository
2588 :``%b``: basename of the exporting repository
2589 :``%h``: short-form changeset hash (12 hexadecimal digits)
2589 :``%h``: short-form changeset hash (12 hexadecimal digits)
2590 :``%m``: first line of the commit message (only alphanumeric characters)
2590 :``%m``: first line of the commit message (only alphanumeric characters)
2591 :``%n``: zero-padded sequence number, starting at 1
2591 :``%n``: zero-padded sequence number, starting at 1
2592 :``%r``: zero-padded changeset revision number
2592 :``%r``: zero-padded changeset revision number
2593 :``\\``: literal "\\" character
2593 :``\\``: literal "\\" character
2594
2594
2595 Without the -a/--text option, export will avoid generating diffs
2595 Without the -a/--text option, export will avoid generating diffs
2596 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
2597 diff anyway, probably with undesirable results.
2597 diff anyway, probably with undesirable results.
2598
2598
2599 With -B/--bookmark changesets reachable by the given bookmark are
2599 With -B/--bookmark changesets reachable by the given bookmark are
2600 selected.
2600 selected.
2601
2601
2602 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
2603 format. See :hg:`help diffs` for more information.
2603 format. See :hg:`help diffs` for more information.
2604
2604
2605 With the --switch-parent option, the diff will be against the
2605 With the --switch-parent option, the diff will be against the
2606 second parent. It can be useful to review a merge.
2606 second parent. It can be useful to review a merge.
2607
2607
2608 .. container:: verbose
2608 .. container:: verbose
2609
2609
2610 Template:
2610 Template:
2611
2611
2612 The following keywords are supported in addition to the common template
2612 The following keywords are supported in addition to the common template
2613 keywords and functions. See also :hg:`help templates`.
2613 keywords and functions. See also :hg:`help templates`.
2614
2614
2615 :diff: String. Diff content.
2615 :diff: String. Diff content.
2616 :parents: List of strings. Parent nodes of the changeset.
2616 :parents: List of strings. Parent nodes of the changeset.
2617
2617
2618 Examples:
2618 Examples:
2619
2619
2620 - use export and import to transplant a bugfix to the current
2620 - use export and import to transplant a bugfix to the current
2621 branch::
2621 branch::
2622
2622
2623 hg export -r 9353 | hg import -
2623 hg export -r 9353 | hg import -
2624
2624
2625 - export all the changesets between two revisions to a file with
2625 - export all the changesets between two revisions to a file with
2626 rename information::
2626 rename information::
2627
2627
2628 hg export --git -r 123:150 > changes.txt
2628 hg export --git -r 123:150 > changes.txt
2629
2629
2630 - split outgoing changes into a series of patches with
2630 - split outgoing changes into a series of patches with
2631 descriptive names::
2631 descriptive names::
2632
2632
2633 hg export -r "outgoing()" -o "%n-%m.patch"
2633 hg export -r "outgoing()" -o "%n-%m.patch"
2634
2634
2635 Returns 0 on success.
2635 Returns 0 on success.
2636 """
2636 """
2637 opts = pycompat.byteskwargs(opts)
2637 opts = pycompat.byteskwargs(opts)
2638 bookmark = opts.get(b'bookmark')
2638 bookmark = opts.get(b'bookmark')
2639 changesets += tuple(opts.get(b'rev', []))
2639 changesets += tuple(opts.get(b'rev', []))
2640
2640
2641 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2641 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2642
2642
2643 if bookmark:
2643 if bookmark:
2644 if bookmark not in repo._bookmarks:
2644 if bookmark not in repo._bookmarks:
2645 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2645 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2646
2646
2647 revs = scmutil.bookmarkrevs(repo, bookmark)
2647 revs = scmutil.bookmarkrevs(repo, bookmark)
2648 else:
2648 else:
2649 if not changesets:
2649 if not changesets:
2650 changesets = [b'.']
2650 changesets = [b'.']
2651
2651
2652 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2652 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2653 revs = scmutil.revrange(repo, changesets)
2653 revs = scmutil.revrange(repo, changesets)
2654
2654
2655 if not revs:
2655 if not revs:
2656 raise error.Abort(_(b"export requires at least one changeset"))
2656 raise error.Abort(_(b"export requires at least one changeset"))
2657 if len(revs) > 1:
2657 if len(revs) > 1:
2658 ui.note(_(b'exporting patches:\n'))
2658 ui.note(_(b'exporting patches:\n'))
2659 else:
2659 else:
2660 ui.note(_(b'exporting patch:\n'))
2660 ui.note(_(b'exporting patch:\n'))
2661
2661
2662 fntemplate = opts.get(b'output')
2662 fntemplate = opts.get(b'output')
2663 if cmdutil.isstdiofilename(fntemplate):
2663 if cmdutil.isstdiofilename(fntemplate):
2664 fntemplate = b''
2664 fntemplate = b''
2665
2665
2666 if fntemplate:
2666 if fntemplate:
2667 fm = formatter.nullformatter(ui, b'export', opts)
2667 fm = formatter.nullformatter(ui, b'export', opts)
2668 else:
2668 else:
2669 ui.pager(b'export')
2669 ui.pager(b'export')
2670 fm = ui.formatter(b'export', opts)
2670 fm = ui.formatter(b'export', opts)
2671 with fm:
2671 with fm:
2672 cmdutil.export(
2672 cmdutil.export(
2673 repo,
2673 repo,
2674 revs,
2674 revs,
2675 fm,
2675 fm,
2676 fntemplate=fntemplate,
2676 fntemplate=fntemplate,
2677 switch_parent=opts.get(b'switch_parent'),
2677 switch_parent=opts.get(b'switch_parent'),
2678 opts=patch.diffallopts(ui, opts),
2678 opts=patch.diffallopts(ui, opts),
2679 )
2679 )
2680
2680
2681
2681
2682 @command(
2682 @command(
2683 b'files',
2683 b'files',
2684 [
2684 [
2685 (
2685 (
2686 b'r',
2686 b'r',
2687 b'rev',
2687 b'rev',
2688 b'',
2688 b'',
2689 _(b'search the repository as it is in REV'),
2689 _(b'search the repository as it is in REV'),
2690 _(b'REV'),
2690 _(b'REV'),
2691 ),
2691 ),
2692 (
2692 (
2693 b'0',
2693 b'0',
2694 b'print0',
2694 b'print0',
2695 None,
2695 None,
2696 _(b'end filenames with NUL, for use with xargs'),
2696 _(b'end filenames with NUL, for use with xargs'),
2697 ),
2697 ),
2698 ]
2698 ]
2699 + walkopts
2699 + walkopts
2700 + formatteropts
2700 + formatteropts
2701 + subrepoopts,
2701 + subrepoopts,
2702 _(b'[OPTION]... [FILE]...'),
2702 _(b'[OPTION]... [FILE]...'),
2703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2704 intents={INTENT_READONLY},
2704 intents={INTENT_READONLY},
2705 )
2705 )
2706 def files(ui, repo, *pats, **opts):
2706 def files(ui, repo, *pats, **opts):
2707 """list tracked files
2707 """list tracked files
2708
2708
2709 Print files under Mercurial control in the working directory or
2709 Print files under Mercurial control in the working directory or
2710 specified revision for given files (excluding removed files).
2710 specified revision for given files (excluding removed files).
2711 Files can be specified as filenames or filesets.
2711 Files can be specified as filenames or filesets.
2712
2712
2713 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
2714 of all files under Mercurial control.
2714 of all files under Mercurial control.
2715
2715
2716 .. container:: verbose
2716 .. container:: verbose
2717
2717
2718 Template:
2718 Template:
2719
2719
2720 The following keywords are supported in addition to the common template
2720 The following keywords are supported in addition to the common template
2721 keywords and functions. See also :hg:`help templates`.
2721 keywords and functions. See also :hg:`help templates`.
2722
2722
2723 :flags: String. Character denoting file's symlink and executable bits.
2723 :flags: String. Character denoting file's symlink and executable bits.
2724 :path: String. Repository-absolute path of the file.
2724 :path: String. Repository-absolute path of the file.
2725 :size: Integer. Size of the file in bytes.
2725 :size: Integer. Size of the file in bytes.
2726
2726
2727 Examples:
2727 Examples:
2728
2728
2729 - list all files under the current directory::
2729 - list all files under the current directory::
2730
2730
2731 hg files .
2731 hg files .
2732
2732
2733 - shows sizes and flags for current revision::
2733 - shows sizes and flags for current revision::
2734
2734
2735 hg files -vr .
2735 hg files -vr .
2736
2736
2737 - list all files named README::
2737 - list all files named README::
2738
2738
2739 hg files -I "**/README"
2739 hg files -I "**/README"
2740
2740
2741 - list all binary files::
2741 - list all binary files::
2742
2742
2743 hg files "set:binary()"
2743 hg files "set:binary()"
2744
2744
2745 - find files containing a regular expression::
2745 - find files containing a regular expression::
2746
2746
2747 hg files "set:grep('bob')"
2747 hg files "set:grep('bob')"
2748
2748
2749 - search tracked file contents with xargs and grep::
2749 - search tracked file contents with xargs and grep::
2750
2750
2751 hg files -0 | xargs -0 grep foo
2751 hg files -0 | xargs -0 grep foo
2752
2752
2753 See :hg:`help patterns` and :hg:`help filesets` for more information
2753 See :hg:`help patterns` and :hg:`help filesets` for more information
2754 on specifying file patterns.
2754 on specifying file patterns.
2755
2755
2756 Returns 0 if a match is found, 1 otherwise.
2756 Returns 0 if a match is found, 1 otherwise.
2757
2757
2758 """
2758 """
2759
2759
2760 opts = pycompat.byteskwargs(opts)
2760 opts = pycompat.byteskwargs(opts)
2761 rev = opts.get(b'rev')
2761 rev = opts.get(b'rev')
2762 if rev:
2762 if rev:
2763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2764 ctx = scmutil.revsingle(repo, rev, None)
2764 ctx = scmutil.revsingle(repo, rev, None)
2765
2765
2766 end = b'\n'
2766 end = b'\n'
2767 if opts.get(b'print0'):
2767 if opts.get(b'print0'):
2768 end = b'\0'
2768 end = b'\0'
2769 fmt = b'%s' + end
2769 fmt = b'%s' + end
2770
2770
2771 m = scmutil.match(ctx, pats, opts)
2771 m = scmutil.match(ctx, pats, opts)
2772 ui.pager(b'files')
2772 ui.pager(b'files')
2773 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2773 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2774 with ui.formatter(b'files', opts) as fm:
2774 with ui.formatter(b'files', opts) as fm:
2775 return cmdutil.files(
2775 return cmdutil.files(
2776 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2776 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2777 )
2777 )
2778
2778
2779
2779
2780 @command(
2780 @command(
2781 b'forget',
2781 b'forget',
2782 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2782 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2783 + walkopts
2783 + walkopts
2784 + dryrunopts,
2784 + dryrunopts,
2785 _(b'[OPTION]... FILE...'),
2785 _(b'[OPTION]... FILE...'),
2786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2787 helpbasic=True,
2787 helpbasic=True,
2788 inferrepo=True,
2788 inferrepo=True,
2789 )
2789 )
2790 def forget(ui, repo, *pats, **opts):
2790 def forget(ui, repo, *pats, **opts):
2791 """forget the specified files on the next commit
2791 """forget the specified files on the next commit
2792
2792
2793 Mark the specified files so they will no longer be tracked
2793 Mark the specified files so they will no longer be tracked
2794 after the next commit.
2794 after the next commit.
2795
2795
2796 This only removes files from the current branch, not from the
2796 This only removes files from the current branch, not from the
2797 entire project history, and it does not delete them from the
2797 entire project history, and it does not delete them from the
2798 working directory.
2798 working directory.
2799
2799
2800 To delete the file from the working directory, see :hg:`remove`.
2800 To delete the file from the working directory, see :hg:`remove`.
2801
2801
2802 To undo a forget before the next commit, see :hg:`add`.
2802 To undo a forget before the next commit, see :hg:`add`.
2803
2803
2804 .. container:: verbose
2804 .. container:: verbose
2805
2805
2806 Examples:
2806 Examples:
2807
2807
2808 - forget newly-added binary files::
2808 - forget newly-added binary files::
2809
2809
2810 hg forget "set:added() and binary()"
2810 hg forget "set:added() and binary()"
2811
2811
2812 - forget files that would be excluded by .hgignore::
2812 - forget files that would be excluded by .hgignore::
2813
2813
2814 hg forget "set:hgignore()"
2814 hg forget "set:hgignore()"
2815
2815
2816 Returns 0 on success.
2816 Returns 0 on success.
2817 """
2817 """
2818
2818
2819 opts = pycompat.byteskwargs(opts)
2819 opts = pycompat.byteskwargs(opts)
2820 if not pats:
2820 if not pats:
2821 raise error.Abort(_(b'no files specified'))
2821 raise error.Abort(_(b'no files specified'))
2822
2822
2823 m = scmutil.match(repo[None], pats, opts)
2823 m = scmutil.match(repo[None], pats, opts)
2824 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2824 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2825 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2825 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2826 rejected = cmdutil.forget(
2826 rejected = cmdutil.forget(
2827 ui,
2827 ui,
2828 repo,
2828 repo,
2829 m,
2829 m,
2830 prefix=b"",
2830 prefix=b"",
2831 uipathfn=uipathfn,
2831 uipathfn=uipathfn,
2832 explicitonly=False,
2832 explicitonly=False,
2833 dryrun=dryrun,
2833 dryrun=dryrun,
2834 interactive=interactive,
2834 interactive=interactive,
2835 )[0]
2835 )[0]
2836 return rejected and 1 or 0
2836 return rejected and 1 or 0
2837
2837
2838
2838
2839 @command(
2839 @command(
2840 b'graft',
2840 b'graft',
2841 [
2841 [
2842 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2842 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2843 (
2843 (
2844 b'',
2844 b'',
2845 b'base',
2845 b'base',
2846 b'',
2846 b'',
2847 _(b'base revision when doing the graft merge (ADVANCED)'),
2847 _(b'base revision when doing the graft merge (ADVANCED)'),
2848 _(b'REV'),
2848 _(b'REV'),
2849 ),
2849 ),
2850 (b'c', b'continue', False, _(b'resume interrupted graft')),
2850 (b'c', b'continue', False, _(b'resume interrupted graft')),
2851 (b'', b'stop', False, _(b'stop interrupted graft')),
2851 (b'', b'stop', False, _(b'stop interrupted graft')),
2852 (b'', b'abort', False, _(b'abort interrupted graft')),
2852 (b'', b'abort', False, _(b'abort interrupted graft')),
2853 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2853 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2854 (b'', b'log', None, _(b'append graft info to log message')),
2854 (b'', b'log', None, _(b'append graft info to log message')),
2855 (
2855 (
2856 b'',
2856 b'',
2857 b'no-commit',
2857 b'no-commit',
2858 None,
2858 None,
2859 _(b"don't commit, just apply the changes in working directory"),
2859 _(b"don't commit, just apply the changes in working directory"),
2860 ),
2860 ),
2861 (b'f', b'force', False, _(b'force graft')),
2861 (b'f', b'force', False, _(b'force graft')),
2862 (
2862 (
2863 b'D',
2863 b'D',
2864 b'currentdate',
2864 b'currentdate',
2865 False,
2865 False,
2866 _(b'record the current date as commit date'),
2866 _(b'record the current date as commit date'),
2867 ),
2867 ),
2868 (
2868 (
2869 b'U',
2869 b'U',
2870 b'currentuser',
2870 b'currentuser',
2871 False,
2871 False,
2872 _(b'record the current user as committer'),
2872 _(b'record the current user as committer'),
2873 ),
2873 ),
2874 ]
2874 ]
2875 + commitopts2
2875 + commitopts2
2876 + mergetoolopts
2876 + mergetoolopts
2877 + dryrunopts,
2877 + dryrunopts,
2878 _(b'[OPTION]... [-r REV]... REV...'),
2878 _(b'[OPTION]... [-r REV]... REV...'),
2879 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2879 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2880 )
2880 )
2881 def graft(ui, repo, *revs, **opts):
2881 def graft(ui, repo, *revs, **opts):
2882 '''copy changes from other branches onto the current branch
2882 '''copy changes from other branches onto the current branch
2883
2883
2884 This command uses Mercurial's merge logic to copy individual
2884 This command uses Mercurial's merge logic to copy individual
2885 changes from other branches without merging branches in the
2885 changes from other branches without merging branches in the
2886 history graph. This is sometimes known as 'backporting' or
2886 history graph. This is sometimes known as 'backporting' or
2887 'cherry-picking'. By default, graft will copy user, date, and
2887 'cherry-picking'. By default, graft will copy user, date, and
2888 description from the source changesets.
2888 description from the source changesets.
2889
2889
2890 Changesets that are ancestors of the current revision, that have
2890 Changesets that are ancestors of the current revision, that have
2891 already been grafted, or that are merges will be skipped.
2891 already been grafted, or that are merges will be skipped.
2892
2892
2893 If --log is specified, log messages will have a comment appended
2893 If --log is specified, log messages will have a comment appended
2894 of the form::
2894 of the form::
2895
2895
2896 (grafted from CHANGESETHASH)
2896 (grafted from CHANGESETHASH)
2897
2897
2898 If --force is specified, revisions will be grafted even if they
2898 If --force is specified, revisions will be grafted even if they
2899 are already ancestors of, or have been grafted to, the destination.
2899 are already ancestors of, or have been grafted to, the destination.
2900 This is useful when the revisions have since been backed out.
2900 This is useful when the revisions have since been backed out.
2901
2901
2902 If a graft merge results in conflicts, the graft process is
2902 If a graft merge results in conflicts, the graft process is
2903 interrupted so that the current merge can be manually resolved.
2903 interrupted so that the current merge can be manually resolved.
2904 Once all conflicts are addressed, the graft process can be
2904 Once all conflicts are addressed, the graft process can be
2905 continued with the -c/--continue option.
2905 continued with the -c/--continue option.
2906
2906
2907 The -c/--continue option reapplies all the earlier options.
2907 The -c/--continue option reapplies all the earlier options.
2908
2908
2909 .. container:: verbose
2909 .. container:: verbose
2910
2910
2911 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
2912 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
2913 the first and only parent.
2913 the first and only parent.
2914
2914
2915 The command::
2915 The command::
2916
2916
2917 hg graft -r 345 --base 234
2917 hg graft -r 345 --base 234
2918
2918
2919 is thus pretty much the same as::
2919 is thus pretty much the same as::
2920
2920
2921 hg diff -r 234 -r 345 | hg import
2921 hg diff -r 234 -r 345 | hg import
2922
2922
2923 but using merge to resolve conflicts and track moved files.
2923 but using merge to resolve conflicts and track moved files.
2924
2924
2925 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
2926 specifying one of the merge parents as base, and thus effectively
2926 specifying one of the merge parents as base, and thus effectively
2927 grafting the changes from the other side.
2927 grafting the changes from the other side.
2928
2928
2929 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
2930 by specifying another ancestor as base, much like rebase --collapse
2930 by specifying another ancestor as base, much like rebase --collapse
2931 --keep.
2931 --keep.
2932
2932
2933 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 .
2934
2934
2935 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
2936 command and the hidden --parent option.
2936 command and the hidden --parent option.
2937
2937
2938 .. container:: verbose
2938 .. container:: verbose
2939
2939
2940 Examples:
2940 Examples:
2941
2941
2942 - 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::
2943
2943
2944 hg update stable
2944 hg update stable
2945 hg graft --edit 9393
2945 hg graft --edit 9393
2946
2946
2947 - graft a range of changesets with one exception, updating dates::
2947 - graft a range of changesets with one exception, updating dates::
2948
2948
2949 hg graft -D "2085::2093 and not 2091"
2949 hg graft -D "2085::2093 and not 2091"
2950
2950
2951 - continue a graft after resolving conflicts::
2951 - continue a graft after resolving conflicts::
2952
2952
2953 hg graft -c
2953 hg graft -c
2954
2954
2955 - show the source of a grafted changeset::
2955 - show the source of a grafted changeset::
2956
2956
2957 hg log --debug -r .
2957 hg log --debug -r .
2958
2958
2959 - show revisions sorted by date::
2959 - show revisions sorted by date::
2960
2960
2961 hg log -r "sort(all(), date)"
2961 hg log -r "sort(all(), date)"
2962
2962
2963 - backport the result of a merge as a single commit::
2963 - backport the result of a merge as a single commit::
2964
2964
2965 hg graft -r 123 --base 123^
2965 hg graft -r 123 --base 123^
2966
2966
2967 - land a feature branch as one changeset::
2967 - land a feature branch as one changeset::
2968
2968
2969 hg up -cr default
2969 hg up -cr default
2970 hg graft -r featureX --base "ancestor('featureX', 'default')"
2970 hg graft -r featureX --base "ancestor('featureX', 'default')"
2971
2971
2972 See :hg:`help revisions` for more about specifying revisions.
2972 See :hg:`help revisions` for more about specifying revisions.
2973
2973
2974 Returns 0 on successful completion, 1 if there are unresolved files.
2974 Returns 0 on successful completion, 1 if there are unresolved files.
2975 '''
2975 '''
2976 with repo.wlock():
2976 with repo.wlock():
2977 return _dograft(ui, repo, *revs, **opts)
2977 return _dograft(ui, repo, *revs, **opts)
2978
2978
2979
2979
2980 def _dograft(ui, repo, *revs, **opts):
2980 def _dograft(ui, repo, *revs, **opts):
2981 opts = pycompat.byteskwargs(opts)
2981 opts = pycompat.byteskwargs(opts)
2982 if revs and opts.get(b'rev'):
2982 if revs and opts.get(b'rev'):
2983 ui.warn(
2983 ui.warn(
2984 _(
2984 _(
2985 b'warning: inconsistent use of --rev might give unexpected '
2985 b'warning: inconsistent use of --rev might give unexpected '
2986 b'revision ordering!\n'
2986 b'revision ordering!\n'
2987 )
2987 )
2988 )
2988 )
2989
2989
2990 revs = list(revs)
2990 revs = list(revs)
2991 revs.extend(opts.get(b'rev'))
2991 revs.extend(opts.get(b'rev'))
2992 # a dict of data to be stored in state file
2992 # a dict of data to be stored in state file
2993 statedata = {}
2993 statedata = {}
2994 # list of new nodes created by ongoing graft
2994 # list of new nodes created by ongoing graft
2995 statedata[b'newnodes'] = []
2995 statedata[b'newnodes'] = []
2996
2996
2997 cmdutil.resolvecommitoptions(ui, opts)
2997 cmdutil.resolvecommitoptions(ui, opts)
2998
2998
2999 editor = cmdutil.getcommiteditor(
2999 editor = cmdutil.getcommiteditor(
3000 editform=b'graft', **pycompat.strkwargs(opts)
3000 editform=b'graft', **pycompat.strkwargs(opts)
3001 )
3001 )
3002
3002
3003 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')
3004
3004
3005 cont = False
3005 cont = False
3006 if opts.get(b'no_commit'):
3006 if opts.get(b'no_commit'):
3007 cmdutil.check_incompatible_arguments(
3007 cmdutil.check_incompatible_arguments(
3008 opts,
3008 opts,
3009 b'no_commit',
3009 b'no_commit',
3010 [b'edit', b'currentuser', b'currentdate', b'log'],
3010 [b'edit', b'currentuser', b'currentdate', b'log'],
3011 )
3011 )
3012
3012
3013 graftstate = statemod.cmdstate(repo, b'graftstate')
3013 graftstate = statemod.cmdstate(repo, b'graftstate')
3014
3014
3015 if opts.get(b'stop'):
3015 if opts.get(b'stop'):
3016 cmdutil.check_incompatible_arguments(
3016 cmdutil.check_incompatible_arguments(
3017 opts,
3017 opts,
3018 b'stop',
3018 b'stop',
3019 [
3019 [
3020 b'edit',
3020 b'edit',
3021 b'log',
3021 b'log',
3022 b'user',
3022 b'user',
3023 b'date',
3023 b'date',
3024 b'currentdate',
3024 b'currentdate',
3025 b'currentuser',
3025 b'currentuser',
3026 b'rev',
3026 b'rev',
3027 ],
3027 ],
3028 )
3028 )
3029 return _stopgraft(ui, repo, graftstate)
3029 return _stopgraft(ui, repo, graftstate)
3030 elif opts.get(b'abort'):
3030 elif opts.get(b'abort'):
3031 cmdutil.check_incompatible_arguments(
3031 cmdutil.check_incompatible_arguments(
3032 opts,
3032 opts,
3033 b'abort',
3033 b'abort',
3034 [
3034 [
3035 b'edit',
3035 b'edit',
3036 b'log',
3036 b'log',
3037 b'user',
3037 b'user',
3038 b'date',
3038 b'date',
3039 b'currentdate',
3039 b'currentdate',
3040 b'currentuser',
3040 b'currentuser',
3041 b'rev',
3041 b'rev',
3042 ],
3042 ],
3043 )
3043 )
3044 return cmdutil.abortgraft(ui, repo, graftstate)
3044 return cmdutil.abortgraft(ui, repo, graftstate)
3045 elif opts.get(b'continue'):
3045 elif opts.get(b'continue'):
3046 cont = True
3046 cont = True
3047 if revs:
3047 if revs:
3048 raise error.Abort(_(b"can't specify --continue and revisions"))
3048 raise error.Abort(_(b"can't specify --continue and revisions"))
3049 # read in unfinished revisions
3049 # read in unfinished revisions
3050 if graftstate.exists():
3050 if graftstate.exists():
3051 statedata = cmdutil.readgraftstate(repo, graftstate)
3051 statedata = cmdutil.readgraftstate(repo, graftstate)
3052 if statedata.get(b'date'):
3052 if statedata.get(b'date'):
3053 opts[b'date'] = statedata[b'date']
3053 opts[b'date'] = statedata[b'date']
3054 if statedata.get(b'user'):
3054 if statedata.get(b'user'):
3055 opts[b'user'] = statedata[b'user']
3055 opts[b'user'] = statedata[b'user']
3056 if statedata.get(b'log'):
3056 if statedata.get(b'log'):
3057 opts[b'log'] = True
3057 opts[b'log'] = True
3058 if statedata.get(b'no_commit'):
3058 if statedata.get(b'no_commit'):
3059 opts[b'no_commit'] = statedata.get(b'no_commit')
3059 opts[b'no_commit'] = statedata.get(b'no_commit')
3060 if statedata.get(b'base'):
3060 if statedata.get(b'base'):
3061 opts[b'base'] = statedata.get(b'base')
3061 opts[b'base'] = statedata.get(b'base')
3062 nodes = statedata[b'nodes']
3062 nodes = statedata[b'nodes']
3063 revs = [repo[node].rev() for node in nodes]
3063 revs = [repo[node].rev() for node in nodes]
3064 else:
3064 else:
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3066 else:
3066 else:
3067 if not revs:
3067 if not revs:
3068 raise error.Abort(_(b'no revisions specified'))
3068 raise error.Abort(_(b'no revisions specified'))
3069 cmdutil.checkunfinished(repo)
3069 cmdutil.checkunfinished(repo)
3070 cmdutil.bailifchanged(repo)
3070 cmdutil.bailifchanged(repo)
3071 revs = scmutil.revrange(repo, revs)
3071 revs = scmutil.revrange(repo, revs)
3072
3072
3073 skipped = set()
3073 skipped = set()
3074 basectx = None
3074 basectx = None
3075 if opts.get(b'base'):
3075 if opts.get(b'base'):
3076 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3076 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3077 if basectx is None:
3077 if basectx is None:
3078 # check for merges
3078 # check for merges
3079 for rev in repo.revs(b'%ld and merge()', revs):
3079 for rev in repo.revs(b'%ld and merge()', revs):
3080 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3080 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3081 skipped.add(rev)
3081 skipped.add(rev)
3082 revs = [r for r in revs if r not in skipped]
3082 revs = [r for r in revs if r not in skipped]
3083 if not revs:
3083 if not revs:
3084 return -1
3084 return -1
3085 if basectx is not None and len(revs) != 1:
3085 if basectx is not None and len(revs) != 1:
3086 raise error.Abort(_(b'only one revision allowed with --base '))
3086 raise error.Abort(_(b'only one revision allowed with --base '))
3087
3087
3088 # 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
3089 # --continues. That's because without --force, any revisions we decided to
3089 # --continues. That's because without --force, any revisions we decided to
3090 # 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
3091 # 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
3092 # 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
3093 # already, they'd have been in the graftstate.
3093 # already, they'd have been in the graftstate.
3094 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:
3095 # check for ancestors of dest branch
3095 # check for ancestors of dest branch
3096 ancestors = repo.revs(b'%ld & (::.)', revs)
3096 ancestors = repo.revs(b'%ld & (::.)', revs)
3097 for rev in ancestors:
3097 for rev in ancestors:
3098 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]))
3099
3099
3100 revs = [r for r in revs if r not in ancestors]
3100 revs = [r for r in revs if r not in ancestors]
3101
3101
3102 if not revs:
3102 if not revs:
3103 return -1
3103 return -1
3104
3104
3105 # analyze revs for earlier grafts
3105 # analyze revs for earlier grafts
3106 ids = {}
3106 ids = {}
3107 for ctx in repo.set(b"%ld", revs):
3107 for ctx in repo.set(b"%ld", revs):
3108 ids[ctx.hex()] = ctx.rev()
3108 ids[ctx.hex()] = ctx.rev()
3109 n = ctx.extra().get(b'source')
3109 n = ctx.extra().get(b'source')
3110 if n:
3110 if n:
3111 ids[n] = ctx.rev()
3111 ids[n] = ctx.rev()
3112
3112
3113 # check ancestors for earlier grafts
3113 # check ancestors for earlier grafts
3114 ui.debug(b'scanning for duplicate grafts\n')
3114 ui.debug(b'scanning for duplicate grafts\n')
3115
3115
3116 # 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
3117 # revs, are the ones that are common ancestors of *all* revs:
3117 # revs, are the ones that are common ancestors of *all* revs:
3118 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):
3119 ctx = repo[rev]
3119 ctx = repo[rev]
3120 n = ctx.extra().get(b'source')
3120 n = ctx.extra().get(b'source')
3121 if n in ids:
3121 if n in ids:
3122 try:
3122 try:
3123 r = repo[n].rev()
3123 r = repo[n].rev()
3124 except error.RepoLookupError:
3124 except error.RepoLookupError:
3125 r = None
3125 r = None
3126 if r in revs:
3126 if r in revs:
3127 ui.warn(
3127 ui.warn(
3128 _(
3128 _(
3129 b'skipping revision %d:%s '
3129 b'skipping revision %d:%s '
3130 b'(already grafted to %d:%s)\n'
3130 b'(already grafted to %d:%s)\n'
3131 )
3131 )
3132 % (r, repo[r], rev, ctx)
3132 % (r, repo[r], rev, ctx)
3133 )
3133 )
3134 revs.remove(r)
3134 revs.remove(r)
3135 elif ids[n] in revs:
3135 elif ids[n] in revs:
3136 if r is None:
3136 if r is None:
3137 ui.warn(
3137 ui.warn(
3138 _(
3138 _(
3139 b'skipping already grafted revision %d:%s '
3139 b'skipping already grafted revision %d:%s '
3140 b'(%d:%s also has unknown origin %s)\n'
3140 b'(%d:%s also has unknown origin %s)\n'
3141 )
3141 )
3142 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3142 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3143 )
3143 )
3144 else:
3144 else:
3145 ui.warn(
3145 ui.warn(
3146 _(
3146 _(
3147 b'skipping already grafted revision %d:%s '
3147 b'skipping already grafted revision %d:%s '
3148 b'(%d:%s also has origin %d:%s)\n'
3148 b'(%d:%s also has origin %d:%s)\n'
3149 )
3149 )
3150 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3150 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3151 )
3151 )
3152 revs.remove(ids[n])
3152 revs.remove(ids[n])
3153 elif ctx.hex() in ids:
3153 elif ctx.hex() in ids:
3154 r = ids[ctx.hex()]
3154 r = ids[ctx.hex()]
3155 if r in revs:
3155 if r in revs:
3156 ui.warn(
3156 ui.warn(
3157 _(
3157 _(
3158 b'skipping already grafted revision %d:%s '
3158 b'skipping already grafted revision %d:%s '
3159 b'(was grafted from %d:%s)\n'
3159 b'(was grafted from %d:%s)\n'
3160 )
3160 )
3161 % (r, repo[r], rev, ctx)
3161 % (r, repo[r], rev, ctx)
3162 )
3162 )
3163 revs.remove(r)
3163 revs.remove(r)
3164 if not revs:
3164 if not revs:
3165 return -1
3165 return -1
3166
3166
3167 if opts.get(b'no_commit'):
3167 if opts.get(b'no_commit'):
3168 statedata[b'no_commit'] = True
3168 statedata[b'no_commit'] = True
3169 if opts.get(b'base'):
3169 if opts.get(b'base'):
3170 statedata[b'base'] = opts[b'base']
3170 statedata[b'base'] = opts[b'base']
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3172 desc = b'%d:%s "%s"' % (
3172 desc = b'%d:%s "%s"' % (
3173 ctx.rev(),
3173 ctx.rev(),
3174 ctx,
3174 ctx,
3175 ctx.description().split(b'\n', 1)[0],
3175 ctx.description().split(b'\n', 1)[0],
3176 )
3176 )
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3178 if names:
3178 if names:
3179 desc += b' (%s)' % b' '.join(names)
3179 desc += b' (%s)' % b' '.join(names)
3180 ui.status(_(b'grafting %s\n') % desc)
3180 ui.status(_(b'grafting %s\n') % desc)
3181 if opts.get(b'dry_run'):
3181 if opts.get(b'dry_run'):
3182 continue
3182 continue
3183
3183
3184 source = ctx.extra().get(b'source')
3184 source = ctx.extra().get(b'source')
3185 extra = {}
3185 extra = {}
3186 if source:
3186 if source:
3187 extra[b'source'] = source
3187 extra[b'source'] = source
3188 extra[b'intermediate-source'] = ctx.hex()
3188 extra[b'intermediate-source'] = ctx.hex()
3189 else:
3189 else:
3190 extra[b'source'] = ctx.hex()
3190 extra[b'source'] = ctx.hex()
3191 user = ctx.user()
3191 user = ctx.user()
3192 if opts.get(b'user'):
3192 if opts.get(b'user'):
3193 user = opts[b'user']
3193 user = opts[b'user']
3194 statedata[b'user'] = user
3194 statedata[b'user'] = user
3195 date = ctx.date()
3195 date = ctx.date()
3196 if opts.get(b'date'):
3196 if opts.get(b'date'):
3197 date = opts[b'date']
3197 date = opts[b'date']
3198 statedata[b'date'] = date
3198 statedata[b'date'] = date
3199 message = ctx.description()
3199 message = ctx.description()
3200 if opts.get(b'log'):
3200 if opts.get(b'log'):
3201 message += b'\n(grafted from %s)' % ctx.hex()
3201 message += b'\n(grafted from %s)' % ctx.hex()
3202 statedata[b'log'] = True
3202 statedata[b'log'] = True
3203
3203
3204 # we don't merge the first commit when continuing
3204 # we don't merge the first commit when continuing
3205 if not cont:
3205 if not cont:
3206 # perform the graft merge with p1(rev) as 'ancestor'
3206 # perform the graft merge with p1(rev) as 'ancestor'
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3208 base = ctx.p1() if basectx is None else basectx
3208 base = ctx.p1() if basectx is None else basectx
3209 with ui.configoverride(overrides, b'graft'):
3209 with ui.configoverride(overrides, b'graft'):
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3211 # report any conflicts
3211 # report any conflicts
3212 if stats.unresolvedcount > 0:
3212 if stats.unresolvedcount > 0:
3213 # write out state for --continue
3213 # write out state for --continue
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3215 statedata[b'nodes'] = nodes
3215 statedata[b'nodes'] = nodes
3216 stateversion = 1
3216 stateversion = 1
3217 graftstate.save(stateversion, statedata)
3217 graftstate.save(stateversion, statedata)
3218 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3218 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3219 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3219 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3220 return 1
3220 return 1
3221 else:
3221 else:
3222 cont = False
3222 cont = False
3223
3223
3224 # commit if --no-commit is false
3224 # commit if --no-commit is false
3225 if not opts.get(b'no_commit'):
3225 if not opts.get(b'no_commit'):
3226 node = repo.commit(
3226 node = repo.commit(
3227 text=message, user=user, date=date, extra=extra, editor=editor
3227 text=message, user=user, date=date, extra=extra, editor=editor
3228 )
3228 )
3229 if node is None:
3229 if node is None:
3230 ui.warn(
3230 ui.warn(
3231 _(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')
3232 % (ctx.rev(), ctx)
3232 % (ctx.rev(), ctx)
3233 )
3233 )
3234 # 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
3235 elif statedata.get(b'newnodes') is not None:
3235 elif statedata.get(b'newnodes') is not None:
3236 statedata[b'newnodes'].append(node)
3236 statedata[b'newnodes'].append(node)
3237
3237
3238 # remove state when we complete successfully
3238 # remove state when we complete successfully
3239 if not opts.get(b'dry_run'):
3239 if not opts.get(b'dry_run'):
3240 graftstate.delete()
3240 graftstate.delete()
3241
3241
3242 return 0
3242 return 0
3243
3243
3244
3244
3245 def _stopgraft(ui, repo, graftstate):
3245 def _stopgraft(ui, repo, graftstate):
3246 """stop the interrupted graft"""
3246 """stop the interrupted graft"""
3247 if not graftstate.exists():
3247 if not graftstate.exists():
3248 raise error.Abort(_(b"no interrupted graft found"))
3248 raise error.Abort(_(b"no interrupted graft found"))
3249 pctx = repo[b'.']
3249 pctx = repo[b'.']
3250 mergemod.clean_update(pctx)
3250 mergemod.clean_update(pctx)
3251 graftstate.delete()
3251 graftstate.delete()
3252 ui.status(_(b"stopped the interrupted graft\n"))
3252 ui.status(_(b"stopped the interrupted graft\n"))
3253 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])
3254 return 0
3254 return 0
3255
3255
3256
3256
3257 statemod.addunfinished(
3257 statemod.addunfinished(
3258 b'graft',
3258 b'graft',
3259 fname=b'graftstate',
3259 fname=b'graftstate',
3260 clearable=True,
3260 clearable=True,
3261 stopflag=True,
3261 stopflag=True,
3262 continueflag=True,
3262 continueflag=True,
3263 abortfunc=cmdutil.hgabortgraft,
3263 abortfunc=cmdutil.hgabortgraft,
3264 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"),
3265 )
3265 )
3266
3266
3267
3267
3268 @command(
3268 @command(
3269 b'grep',
3269 b'grep',
3270 [
3270 [
3271 (b'0', b'print0', None, _(b'end fields with NUL')),
3271 (b'0', b'print0', None, _(b'end fields with NUL')),
3272 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3272 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3273 (
3273 (
3274 b'',
3274 b'',
3275 b'diff',
3275 b'diff',
3276 None,
3276 None,
3277 _(
3277 _(
3278 b'search revision differences for when the pattern was added '
3278 b'search revision differences for when the pattern was added '
3279 b'or removed'
3279 b'or removed'
3280 ),
3280 ),
3281 ),
3281 ),
3282 (b'a', b'text', None, _(b'treat all files as text')),
3282 (b'a', b'text', None, _(b'treat all files as text')),
3283 (
3283 (
3284 b'f',
3284 b'f',
3285 b'follow',
3285 b'follow',
3286 None,
3286 None,
3287 _(
3287 _(
3288 b'follow changeset history,'
3288 b'follow changeset history,'
3289 b' or file history across copies and renames'
3289 b' or file history across copies and renames'
3290 ),
3290 ),
3291 ),
3291 ),
3292 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3292 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3293 (
3293 (
3294 b'l',
3294 b'l',
3295 b'files-with-matches',
3295 b'files-with-matches',
3296 None,
3296 None,
3297 _(b'print only filenames and revisions that match'),
3297 _(b'print only filenames and revisions that match'),
3298 ),
3298 ),
3299 (b'n', b'line-number', None, _(b'print matching line numbers')),
3299 (b'n', b'line-number', None, _(b'print matching line numbers')),
3300 (
3300 (
3301 b'r',
3301 b'r',
3302 b'rev',
3302 b'rev',
3303 [],
3303 [],
3304 _(b'search files changed within revision range'),
3304 _(b'search files changed within revision range'),
3305 _(b'REV'),
3305 _(b'REV'),
3306 ),
3306 ),
3307 (
3307 (
3308 b'',
3308 b'',
3309 b'all-files',
3309 b'all-files',
3310 None,
3310 None,
3311 _(
3311 _(
3312 b'include all files in the changeset while grepping (DEPRECATED)'
3312 b'include all files in the changeset while grepping (DEPRECATED)'
3313 ),
3313 ),
3314 ),
3314 ),
3315 (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)')),
3316 (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)')),
3317 ]
3317 ]
3318 + formatteropts
3318 + formatteropts
3319 + walkopts,
3319 + walkopts,
3320 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3320 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3321 helpcategory=command.CATEGORY_FILE_CONTENTS,
3321 helpcategory=command.CATEGORY_FILE_CONTENTS,
3322 inferrepo=True,
3322 inferrepo=True,
3323 intents={INTENT_READONLY},
3323 intents={INTENT_READONLY},
3324 )
3324 )
3325 def grep(ui, repo, pattern, *pats, **opts):
3325 def grep(ui, repo, pattern, *pats, **opts):
3326 """search for a pattern in specified files
3326 """search for a pattern in specified files
3327
3327
3328 Search the working directory or revision history for a regular
3328 Search the working directory or revision history for a regular
3329 expression in the specified files for the entire repository.
3329 expression in the specified files for the entire repository.
3330
3330
3331 By default, grep searches the repository files in the working
3331 By default, grep searches the repository files in the working
3332 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
3333 historical revisions instead of the working directory, use the
3333 historical revisions instead of the working directory, use the
3334 --rev flag.
3334 --rev flag.
3335
3335
3336 To search instead historical revision differences that contains a
3336 To search instead historical revision differences that contains a
3337 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,
3338 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.
3339
3339
3340 PATTERN can be any Python (roughly Perl-compatible) regular
3340 PATTERN can be any Python (roughly Perl-compatible) regular
3341 expression.
3341 expression.
3342
3342
3343 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
3344 files in the working directory are searched. When using the --rev
3344 files in the working directory are searched. When using the --rev
3345 flag and specifying FILEs, use the --follow argument to also
3345 flag and specifying FILEs, use the --follow argument to also
3346 follow the specified FILEs across renames and copies.
3346 follow the specified FILEs across renames and copies.
3347
3347
3348 .. container:: verbose
3348 .. container:: verbose
3349
3349
3350 Template:
3350 Template:
3351
3351
3352 The following keywords are supported in addition to the common template
3352 The following keywords are supported in addition to the common template
3353 keywords and functions. See also :hg:`help templates`.
3353 keywords and functions. See also :hg:`help templates`.
3354
3354
3355 :change: String. Character denoting insertion ``+`` or removal ``-``.
3355 :change: String. Character denoting insertion ``+`` or removal ``-``.
3356 Available if ``--diff`` is specified.
3356 Available if ``--diff`` is specified.
3357 :lineno: Integer. Line number of the match.
3357 :lineno: Integer. Line number of the match.
3358 :path: String. Repository-absolute path of the file.
3358 :path: String. Repository-absolute path of the file.
3359 :texts: List of text chunks.
3359 :texts: List of text chunks.
3360
3360
3361 And each entry of ``{texts}`` provides the following sub-keywords.
3361 And each entry of ``{texts}`` provides the following sub-keywords.
3362
3362
3363 :matched: Boolean. True if the chunk matches the specified pattern.
3363 :matched: Boolean. True if the chunk matches the specified pattern.
3364 :text: String. Chunk content.
3364 :text: String. Chunk content.
3365
3365
3366 See :hg:`help templates.operators` for the list expansion syntax.
3366 See :hg:`help templates.operators` for the list expansion syntax.
3367
3367
3368 Returns 0 if a match is found, 1 otherwise.
3368 Returns 0 if a match is found, 1 otherwise.
3369
3369
3370 """
3370 """
3371 opts = pycompat.byteskwargs(opts)
3371 opts = pycompat.byteskwargs(opts)
3372 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')
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(
3401 searcher = grepmod.grepsearcher(
3402 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3402 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3403 )
3403 )
3404
3404
3405 getfile = searcher._getfile
3405 getfile = searcher._getfile
3406 matches = searcher._matches
3407 copies = searcher._copies
3408
3406
3409 uipathfn = scmutil.getuipathfn(repo)
3407 uipathfn = scmutil.getuipathfn(repo)
3410
3408
3411 def display(fm, fn, ctx, pstates, states):
3409 def display(fm, fn, ctx, pstates, states):
3412 rev = scmutil.intrev(ctx)
3410 rev = scmutil.intrev(ctx)
3413 if fm.isplain():
3411 if fm.isplain():
3414 formatuser = ui.shortuser
3412 formatuser = ui.shortuser
3415 else:
3413 else:
3416 formatuser = pycompat.bytestr
3414 formatuser = pycompat.bytestr
3417 if ui.quiet:
3415 if ui.quiet:
3418 datefmt = b'%Y-%m-%d'
3416 datefmt = b'%Y-%m-%d'
3419 else:
3417 else:
3420 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3421 found = False
3419 found = False
3422
3420
3423 @util.cachefunc
3421 @util.cachefunc
3424 def binary():
3422 def binary():
3425 flog = getfile(fn)
3423 flog = getfile(fn)
3426 try:
3424 try:
3427 return stringutil.binary(flog.read(ctx.filenode(fn)))
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3428 except error.WdirUnsupported:
3426 except error.WdirUnsupported:
3429 return ctx[fn].isbinary()
3427 return ctx[fn].isbinary()
3430
3428
3431 fieldnamemap = {b'linenumber': b'lineno'}
3429 fieldnamemap = {b'linenumber': b'lineno'}
3432 if diff:
3430 if diff:
3433 iter = grepmod.difflinestates(pstates, states)
3431 iter = grepmod.difflinestates(pstates, states)
3434 else:
3432 else:
3435 iter = [(b'', l) for l in states]
3433 iter = [(b'', l) for l in states]
3436 for change, l in iter:
3434 for change, l in iter:
3437 fm.startitem()
3435 fm.startitem()
3438 fm.context(ctx=ctx)
3436 fm.context(ctx=ctx)
3439 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3440 fm.plain(uipathfn(fn), label=b'grep.filename')
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3441
3439
3442 cols = [
3440 cols = [
3443 (b'rev', b'%d', rev, not plaingrep, b''),
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3444 (
3442 (
3445 b'linenumber',
3443 b'linenumber',
3446 b'%d',
3444 b'%d',
3447 l.linenum,
3445 l.linenum,
3448 opts.get(b'line_number'),
3446 opts.get(b'line_number'),
3449 b'',
3447 b'',
3450 ),
3448 ),
3451 ]
3449 ]
3452 if diff:
3450 if diff:
3453 cols.append(
3451 cols.append(
3454 (
3452 (
3455 b'change',
3453 b'change',
3456 b'%s',
3454 b'%s',
3457 change,
3455 change,
3458 True,
3456 True,
3459 b'grep.inserted '
3457 b'grep.inserted '
3460 if change == b'+'
3458 if change == b'+'
3461 else b'grep.deleted ',
3459 else b'grep.deleted ',
3462 )
3460 )
3463 )
3461 )
3464 cols.extend(
3462 cols.extend(
3465 [
3463 [
3466 (
3464 (
3467 b'user',
3465 b'user',
3468 b'%s',
3466 b'%s',
3469 formatuser(ctx.user()),
3467 formatuser(ctx.user()),
3470 opts.get(b'user'),
3468 opts.get(b'user'),
3471 b'',
3469 b'',
3472 ),
3470 ),
3473 (
3471 (
3474 b'date',
3472 b'date',
3475 b'%s',
3473 b'%s',
3476 fm.formatdate(ctx.date(), datefmt),
3474 fm.formatdate(ctx.date(), datefmt),
3477 opts.get(b'date'),
3475 opts.get(b'date'),
3478 b'',
3476 b'',
3479 ),
3477 ),
3480 ]
3478 ]
3481 )
3479 )
3482 for name, fmt, data, cond, extra_label in cols:
3480 for name, fmt, data, cond, extra_label in cols:
3483 if cond:
3481 if cond:
3484 fm.plain(sep, label=b'grep.sep')
3482 fm.plain(sep, label=b'grep.sep')
3485 field = fieldnamemap.get(name, name)
3483 field = fieldnamemap.get(name, name)
3486 label = extra_label + (b'grep.%s' % name)
3484 label = extra_label + (b'grep.%s' % name)
3487 fm.condwrite(cond, field, fmt, data, label=label)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3488 if not opts.get(b'files_with_matches'):
3486 if not opts.get(b'files_with_matches'):
3489 fm.plain(sep, label=b'grep.sep')
3487 fm.plain(sep, label=b'grep.sep')
3490 if not opts.get(b'text') and binary():
3488 if not opts.get(b'text') and binary():
3491 fm.plain(_(b" Binary file matches"))
3489 fm.plain(_(b" Binary file matches"))
3492 else:
3490 else:
3493 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3494 fm.plain(eol)
3492 fm.plain(eol)
3495 found = True
3493 found = True
3496 if opts.get(b'files_with_matches'):
3494 if opts.get(b'files_with_matches'):
3497 break
3495 break
3498 return found
3496 return found
3499
3497
3500 def displaymatches(fm, l):
3498 def displaymatches(fm, l):
3501 p = 0
3499 p = 0
3502 for s, e in l.findpos(regexp):
3500 for s, e in l.findpos(regexp):
3503 if p < s:
3501 if p < s:
3504 fm.startitem()
3502 fm.startitem()
3505 fm.write(b'text', b'%s', l.line[p:s])
3503 fm.write(b'text', b'%s', l.line[p:s])
3506 fm.data(matched=False)
3504 fm.data(matched=False)
3507 fm.startitem()
3505 fm.startitem()
3508 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3509 fm.data(matched=True)
3507 fm.data(matched=True)
3510 p = e
3508 p = e
3511 if p < len(l.line):
3509 if p < len(l.line):
3512 fm.startitem()
3510 fm.startitem()
3513 fm.write(b'text', b'%s', l.line[p:])
3511 fm.write(b'text', b'%s', l.line[p:])
3514 fm.data(matched=False)
3512 fm.data(matched=False)
3515 fm.end()
3513 fm.end()
3516
3514
3517 skip = searcher._skip
3518 revfiles = searcher._revfiles
3519 found = False
3515 found = False
3520
3516
3521 wopts = logcmdutil.walkopts(
3517 wopts = logcmdutil.walkopts(
3522 pats=pats,
3518 pats=pats,
3523 opts=opts,
3519 opts=opts,
3524 revspec=opts[b'rev'],
3520 revspec=opts[b'rev'],
3525 include_pats=opts[b'include'],
3521 include_pats=opts[b'include'],
3526 exclude_pats=opts[b'exclude'],
3522 exclude_pats=opts[b'exclude'],
3527 follow=follow,
3523 follow=follow,
3528 force_changelog_traversal=all_files,
3524 force_changelog_traversal=all_files,
3529 filter_revisions_by_pats=not all_files,
3525 filter_revisions_by_pats=not all_files,
3530 )
3526 )
3531 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3527 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3532
3528
3533 ui.pager(b'grep')
3529 ui.pager(b'grep')
3534 fm = ui.formatter(b'grep', opts)
3530 fm = ui.formatter(b'grep', opts)
3535 for ctx in scmutil.walkchangerevs(
3531 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3536 repo, revs, makefilematcher, searcher._prep
3532 r = display(fm, fn, ctx, pstates, states)
3537 ):
3533 found = found or r
3538 rev = ctx.rev()
3534 if r and not diff and not all_files:
3539 parent = ctx.p1().rev()
3535 searcher.skipfile(fn, ctx.rev())
3540 for fn in sorted(revfiles.get(rev, [])):
3541 states = matches[rev][fn]
3542 copy = copies.get(rev, {}).get(fn)
3543 if fn in skip:
3544 if copy:
3545 skip.add(copy)
3546 continue
3547 pstates = matches.get(parent, {}).get(copy or fn, [])
3548 if pstates or states:
3549 r = display(fm, fn, ctx, pstates, states)
3550 found = found or r
3551 if r and not diff and not all_files:
3552 searcher.skipfile(fn, rev)
3553 del revfiles[rev]
3554 # We will keep the matches dict for the duration of the window
3555 # clear the matches dict once the window is over
3556 if not revfiles:
3557 matches.clear()
3558 fm.end()
3536 fm.end()
3559
3537
3560 return not found
3538 return not found
3561
3539
3562
3540
3563 @command(
3541 @command(
3564 b'heads',
3542 b'heads',
3565 [
3543 [
3566 (
3544 (
3567 b'r',
3545 b'r',
3568 b'rev',
3546 b'rev',
3569 b'',
3547 b'',
3570 _(b'show only heads which are descendants of STARTREV'),
3548 _(b'show only heads which are descendants of STARTREV'),
3571 _(b'STARTREV'),
3549 _(b'STARTREV'),
3572 ),
3550 ),
3573 (b't', b'topo', False, _(b'show topological heads only')),
3551 (b't', b'topo', False, _(b'show topological heads only')),
3574 (
3552 (
3575 b'a',
3553 b'a',
3576 b'active',
3554 b'active',
3577 False,
3555 False,
3578 _(b'show active branchheads only (DEPRECATED)'),
3556 _(b'show active branchheads only (DEPRECATED)'),
3579 ),
3557 ),
3580 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3558 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3581 ]
3559 ]
3582 + templateopts,
3560 + templateopts,
3583 _(b'[-ct] [-r STARTREV] [REV]...'),
3561 _(b'[-ct] [-r STARTREV] [REV]...'),
3584 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3562 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3585 intents={INTENT_READONLY},
3563 intents={INTENT_READONLY},
3586 )
3564 )
3587 def heads(ui, repo, *branchrevs, **opts):
3565 def heads(ui, repo, *branchrevs, **opts):
3588 """show branch heads
3566 """show branch heads
3589
3567
3590 With no arguments, show all open branch heads in the repository.
3568 With no arguments, show all open branch heads in the repository.
3591 Branch heads are changesets that have no descendants on the
3569 Branch heads are changesets that have no descendants on the
3592 same branch. They are where development generally takes place and
3570 same branch. They are where development generally takes place and
3593 are the usual targets for update and merge operations.
3571 are the usual targets for update and merge operations.
3594
3572
3595 If one or more REVs are given, only open branch heads on the
3573 If one or more REVs are given, only open branch heads on the
3596 branches associated with the specified changesets are shown. This
3574 branches associated with the specified changesets are shown. This
3597 means that you can use :hg:`heads .` to see the heads on the
3575 means that you can use :hg:`heads .` to see the heads on the
3598 currently checked-out branch.
3576 currently checked-out branch.
3599
3577
3600 If -c/--closed is specified, also show branch heads marked closed
3578 If -c/--closed is specified, also show branch heads marked closed
3601 (see :hg:`commit --close-branch`).
3579 (see :hg:`commit --close-branch`).
3602
3580
3603 If STARTREV is specified, only those heads that are descendants of
3581 If STARTREV is specified, only those heads that are descendants of
3604 STARTREV will be displayed.
3582 STARTREV will be displayed.
3605
3583
3606 If -t/--topo is specified, named branch mechanics will be ignored and only
3584 If -t/--topo is specified, named branch mechanics will be ignored and only
3607 topological heads (changesets with no children) will be shown.
3585 topological heads (changesets with no children) will be shown.
3608
3586
3609 Returns 0 if matching heads are found, 1 if not.
3587 Returns 0 if matching heads are found, 1 if not.
3610 """
3588 """
3611
3589
3612 opts = pycompat.byteskwargs(opts)
3590 opts = pycompat.byteskwargs(opts)
3613 start = None
3591 start = None
3614 rev = opts.get(b'rev')
3592 rev = opts.get(b'rev')
3615 if rev:
3593 if rev:
3616 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3594 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3617 start = scmutil.revsingle(repo, rev, None).node()
3595 start = scmutil.revsingle(repo, rev, None).node()
3618
3596
3619 if opts.get(b'topo'):
3597 if opts.get(b'topo'):
3620 heads = [repo[h] for h in repo.heads(start)]
3598 heads = [repo[h] for h in repo.heads(start)]
3621 else:
3599 else:
3622 heads = []
3600 heads = []
3623 for branch in repo.branchmap():
3601 for branch in repo.branchmap():
3624 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3602 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3625 heads = [repo[h] for h in heads]
3603 heads = [repo[h] for h in heads]
3626
3604
3627 if branchrevs:
3605 if branchrevs:
3628 branches = {
3606 branches = {
3629 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3607 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3630 }
3608 }
3631 heads = [h for h in heads if h.branch() in branches]
3609 heads = [h for h in heads if h.branch() in branches]
3632
3610
3633 if opts.get(b'active') and branchrevs:
3611 if opts.get(b'active') and branchrevs:
3634 dagheads = repo.heads(start)
3612 dagheads = repo.heads(start)
3635 heads = [h for h in heads if h.node() in dagheads]
3613 heads = [h for h in heads if h.node() in dagheads]
3636
3614
3637 if branchrevs:
3615 if branchrevs:
3638 haveheads = {h.branch() for h in heads}
3616 haveheads = {h.branch() for h in heads}
3639 if branches - haveheads:
3617 if branches - haveheads:
3640 headless = b', '.join(b for b in branches - haveheads)
3618 headless = b', '.join(b for b in branches - haveheads)
3641 msg = _(b'no open branch heads found on branches %s')
3619 msg = _(b'no open branch heads found on branches %s')
3642 if opts.get(b'rev'):
3620 if opts.get(b'rev'):
3643 msg += _(b' (started at %s)') % opts[b'rev']
3621 msg += _(b' (started at %s)') % opts[b'rev']
3644 ui.warn((msg + b'\n') % headless)
3622 ui.warn((msg + b'\n') % headless)
3645
3623
3646 if not heads:
3624 if not heads:
3647 return 1
3625 return 1
3648
3626
3649 ui.pager(b'heads')
3627 ui.pager(b'heads')
3650 heads = sorted(heads, key=lambda x: -(x.rev()))
3628 heads = sorted(heads, key=lambda x: -(x.rev()))
3651 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3629 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3652 for ctx in heads:
3630 for ctx in heads:
3653 displayer.show(ctx)
3631 displayer.show(ctx)
3654 displayer.close()
3632 displayer.close()
3655
3633
3656
3634
3657 @command(
3635 @command(
3658 b'help',
3636 b'help',
3659 [
3637 [
3660 (b'e', b'extension', None, _(b'show only help for extensions')),
3638 (b'e', b'extension', None, _(b'show only help for extensions')),
3661 (b'c', b'command', None, _(b'show only help for commands')),
3639 (b'c', b'command', None, _(b'show only help for commands')),
3662 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3640 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3663 (
3641 (
3664 b's',
3642 b's',
3665 b'system',
3643 b'system',
3666 [],
3644 [],
3667 _(b'show help for specific platform(s)'),
3645 _(b'show help for specific platform(s)'),
3668 _(b'PLATFORM'),
3646 _(b'PLATFORM'),
3669 ),
3647 ),
3670 ],
3648 ],
3671 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3649 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3672 helpcategory=command.CATEGORY_HELP,
3650 helpcategory=command.CATEGORY_HELP,
3673 norepo=True,
3651 norepo=True,
3674 intents={INTENT_READONLY},
3652 intents={INTENT_READONLY},
3675 )
3653 )
3676 def help_(ui, name=None, **opts):
3654 def help_(ui, name=None, **opts):
3677 """show help for a given topic or a help overview
3655 """show help for a given topic or a help overview
3678
3656
3679 With no arguments, print a list of commands with short help messages.
3657 With no arguments, print a list of commands with short help messages.
3680
3658
3681 Given a topic, extension, or command name, print help for that
3659 Given a topic, extension, or command name, print help for that
3682 topic.
3660 topic.
3683
3661
3684 Returns 0 if successful.
3662 Returns 0 if successful.
3685 """
3663 """
3686
3664
3687 keep = opts.get('system') or []
3665 keep = opts.get('system') or []
3688 if len(keep) == 0:
3666 if len(keep) == 0:
3689 if pycompat.sysplatform.startswith(b'win'):
3667 if pycompat.sysplatform.startswith(b'win'):
3690 keep.append(b'windows')
3668 keep.append(b'windows')
3691 elif pycompat.sysplatform == b'OpenVMS':
3669 elif pycompat.sysplatform == b'OpenVMS':
3692 keep.append(b'vms')
3670 keep.append(b'vms')
3693 elif pycompat.sysplatform == b'plan9':
3671 elif pycompat.sysplatform == b'plan9':
3694 keep.append(b'plan9')
3672 keep.append(b'plan9')
3695 else:
3673 else:
3696 keep.append(b'unix')
3674 keep.append(b'unix')
3697 keep.append(pycompat.sysplatform.lower())
3675 keep.append(pycompat.sysplatform.lower())
3698 if ui.verbose:
3676 if ui.verbose:
3699 keep.append(b'verbose')
3677 keep.append(b'verbose')
3700
3678
3701 commands = sys.modules[__name__]
3679 commands = sys.modules[__name__]
3702 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3680 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3703 ui.pager(b'help')
3681 ui.pager(b'help')
3704 ui.write(formatted)
3682 ui.write(formatted)
3705
3683
3706
3684
3707 @command(
3685 @command(
3708 b'identify|id',
3686 b'identify|id',
3709 [
3687 [
3710 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3688 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3711 (b'n', b'num', None, _(b'show local revision number')),
3689 (b'n', b'num', None, _(b'show local revision number')),
3712 (b'i', b'id', None, _(b'show global revision id')),
3690 (b'i', b'id', None, _(b'show global revision id')),
3713 (b'b', b'branch', None, _(b'show branch')),
3691 (b'b', b'branch', None, _(b'show branch')),
3714 (b't', b'tags', None, _(b'show tags')),
3692 (b't', b'tags', None, _(b'show tags')),
3715 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3693 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3716 ]
3694 ]
3717 + remoteopts
3695 + remoteopts
3718 + formatteropts,
3696 + formatteropts,
3719 _(b'[-nibtB] [-r REV] [SOURCE]'),
3697 _(b'[-nibtB] [-r REV] [SOURCE]'),
3720 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3698 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3721 optionalrepo=True,
3699 optionalrepo=True,
3722 intents={INTENT_READONLY},
3700 intents={INTENT_READONLY},
3723 )
3701 )
3724 def identify(
3702 def identify(
3725 ui,
3703 ui,
3726 repo,
3704 repo,
3727 source=None,
3705 source=None,
3728 rev=None,
3706 rev=None,
3729 num=None,
3707 num=None,
3730 id=None,
3708 id=None,
3731 branch=None,
3709 branch=None,
3732 tags=None,
3710 tags=None,
3733 bookmarks=None,
3711 bookmarks=None,
3734 **opts
3712 **opts
3735 ):
3713 ):
3736 """identify the working directory or specified revision
3714 """identify the working directory or specified revision
3737
3715
3738 Print a summary identifying the repository state at REV using one or
3716 Print a summary identifying the repository state at REV using one or
3739 two parent hash identifiers, followed by a "+" if the working
3717 two parent hash identifiers, followed by a "+" if the working
3740 directory has uncommitted changes, the branch name (if not default),
3718 directory has uncommitted changes, the branch name (if not default),
3741 a list of tags, and a list of bookmarks.
3719 a list of tags, and a list of bookmarks.
3742
3720
3743 When REV is not given, print a summary of the current state of the
3721 When REV is not given, print a summary of the current state of the
3744 repository including the working directory. Specify -r. to get information
3722 repository including the working directory. Specify -r. to get information
3745 of the working directory parent without scanning uncommitted changes.
3723 of the working directory parent without scanning uncommitted changes.
3746
3724
3747 Specifying a path to a repository root or Mercurial bundle will
3725 Specifying a path to a repository root or Mercurial bundle will
3748 cause lookup to operate on that repository/bundle.
3726 cause lookup to operate on that repository/bundle.
3749
3727
3750 .. container:: verbose
3728 .. container:: verbose
3751
3729
3752 Template:
3730 Template:
3753
3731
3754 The following keywords are supported in addition to the common template
3732 The following keywords are supported in addition to the common template
3755 keywords and functions. See also :hg:`help templates`.
3733 keywords and functions. See also :hg:`help templates`.
3756
3734
3757 :dirty: String. Character ``+`` denoting if the working directory has
3735 :dirty: String. Character ``+`` denoting if the working directory has
3758 uncommitted changes.
3736 uncommitted changes.
3759 :id: String. One or two nodes, optionally followed by ``+``.
3737 :id: String. One or two nodes, optionally followed by ``+``.
3760 :parents: List of strings. Parent nodes of the changeset.
3738 :parents: List of strings. Parent nodes of the changeset.
3761
3739
3762 Examples:
3740 Examples:
3763
3741
3764 - generate a build identifier for the working directory::
3742 - generate a build identifier for the working directory::
3765
3743
3766 hg id --id > build-id.dat
3744 hg id --id > build-id.dat
3767
3745
3768 - find the revision corresponding to a tag::
3746 - find the revision corresponding to a tag::
3769
3747
3770 hg id -n -r 1.3
3748 hg id -n -r 1.3
3771
3749
3772 - check the most recent revision of a remote repository::
3750 - check the most recent revision of a remote repository::
3773
3751
3774 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3752 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3775
3753
3776 See :hg:`log` for generating more information about specific revisions,
3754 See :hg:`log` for generating more information about specific revisions,
3777 including full hash identifiers.
3755 including full hash identifiers.
3778
3756
3779 Returns 0 if successful.
3757 Returns 0 if successful.
3780 """
3758 """
3781
3759
3782 opts = pycompat.byteskwargs(opts)
3760 opts = pycompat.byteskwargs(opts)
3783 if not repo and not source:
3761 if not repo and not source:
3784 raise error.Abort(
3762 raise error.Abort(
3785 _(b"there is no Mercurial repository here (.hg not found)")
3763 _(b"there is no Mercurial repository here (.hg not found)")
3786 )
3764 )
3787
3765
3788 default = not (num or id or branch or tags or bookmarks)
3766 default = not (num or id or branch or tags or bookmarks)
3789 output = []
3767 output = []
3790 revs = []
3768 revs = []
3791
3769
3792 if source:
3770 if source:
3793 source, branches = hg.parseurl(ui.expandpath(source))
3771 source, branches = hg.parseurl(ui.expandpath(source))
3794 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3772 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3795 repo = peer.local()
3773 repo = peer.local()
3796 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3774 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3797
3775
3798 fm = ui.formatter(b'identify', opts)
3776 fm = ui.formatter(b'identify', opts)
3799 fm.startitem()
3777 fm.startitem()
3800
3778
3801 if not repo:
3779 if not repo:
3802 if num or branch or tags:
3780 if num or branch or tags:
3803 raise error.Abort(
3781 raise error.Abort(
3804 _(b"can't query remote revision number, branch, or tags")
3782 _(b"can't query remote revision number, branch, or tags")
3805 )
3783 )
3806 if not rev and revs:
3784 if not rev and revs:
3807 rev = revs[0]
3785 rev = revs[0]
3808 if not rev:
3786 if not rev:
3809 rev = b"tip"
3787 rev = b"tip"
3810
3788
3811 remoterev = peer.lookup(rev)
3789 remoterev = peer.lookup(rev)
3812 hexrev = fm.hexfunc(remoterev)
3790 hexrev = fm.hexfunc(remoterev)
3813 if default or id:
3791 if default or id:
3814 output = [hexrev]
3792 output = [hexrev]
3815 fm.data(id=hexrev)
3793 fm.data(id=hexrev)
3816
3794
3817 @util.cachefunc
3795 @util.cachefunc
3818 def getbms():
3796 def getbms():
3819 bms = []
3797 bms = []
3820
3798
3821 if b'bookmarks' in peer.listkeys(b'namespaces'):
3799 if b'bookmarks' in peer.listkeys(b'namespaces'):
3822 hexremoterev = hex(remoterev)
3800 hexremoterev = hex(remoterev)
3823 bms = [
3801 bms = [
3824 bm
3802 bm
3825 for bm, bmr in pycompat.iteritems(
3803 for bm, bmr in pycompat.iteritems(
3826 peer.listkeys(b'bookmarks')
3804 peer.listkeys(b'bookmarks')
3827 )
3805 )
3828 if bmr == hexremoterev
3806 if bmr == hexremoterev
3829 ]
3807 ]
3830
3808
3831 return sorted(bms)
3809 return sorted(bms)
3832
3810
3833 if fm.isplain():
3811 if fm.isplain():
3834 if bookmarks:
3812 if bookmarks:
3835 output.extend(getbms())
3813 output.extend(getbms())
3836 elif default and not ui.quiet:
3814 elif default and not ui.quiet:
3837 # multiple bookmarks for a single parent separated by '/'
3815 # multiple bookmarks for a single parent separated by '/'
3838 bm = b'/'.join(getbms())
3816 bm = b'/'.join(getbms())
3839 if bm:
3817 if bm:
3840 output.append(bm)
3818 output.append(bm)
3841 else:
3819 else:
3842 fm.data(node=hex(remoterev))
3820 fm.data(node=hex(remoterev))
3843 if bookmarks or b'bookmarks' in fm.datahint():
3821 if bookmarks or b'bookmarks' in fm.datahint():
3844 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3822 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3845 else:
3823 else:
3846 if rev:
3824 if rev:
3847 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3825 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3848 ctx = scmutil.revsingle(repo, rev, None)
3826 ctx = scmutil.revsingle(repo, rev, None)
3849
3827
3850 if ctx.rev() is None:
3828 if ctx.rev() is None:
3851 ctx = repo[None]
3829 ctx = repo[None]
3852 parents = ctx.parents()
3830 parents = ctx.parents()
3853 taglist = []
3831 taglist = []
3854 for p in parents:
3832 for p in parents:
3855 taglist.extend(p.tags())
3833 taglist.extend(p.tags())
3856
3834
3857 dirty = b""
3835 dirty = b""
3858 if ctx.dirty(missing=True, merge=False, branch=False):
3836 if ctx.dirty(missing=True, merge=False, branch=False):
3859 dirty = b'+'
3837 dirty = b'+'
3860 fm.data(dirty=dirty)
3838 fm.data(dirty=dirty)
3861
3839
3862 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3840 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3863 if default or id:
3841 if default or id:
3864 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3842 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3865 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3843 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3866
3844
3867 if num:
3845 if num:
3868 numoutput = [b"%d" % p.rev() for p in parents]
3846 numoutput = [b"%d" % p.rev() for p in parents]
3869 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3847 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3870
3848
3871 fm.data(
3849 fm.data(
3872 parents=fm.formatlist(
3850 parents=fm.formatlist(
3873 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3851 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3874 )
3852 )
3875 )
3853 )
3876 else:
3854 else:
3877 hexoutput = fm.hexfunc(ctx.node())
3855 hexoutput = fm.hexfunc(ctx.node())
3878 if default or id:
3856 if default or id:
3879 output = [hexoutput]
3857 output = [hexoutput]
3880 fm.data(id=hexoutput)
3858 fm.data(id=hexoutput)
3881
3859
3882 if num:
3860 if num:
3883 output.append(pycompat.bytestr(ctx.rev()))
3861 output.append(pycompat.bytestr(ctx.rev()))
3884 taglist = ctx.tags()
3862 taglist = ctx.tags()
3885
3863
3886 if default and not ui.quiet:
3864 if default and not ui.quiet:
3887 b = ctx.branch()
3865 b = ctx.branch()
3888 if b != b'default':
3866 if b != b'default':
3889 output.append(b"(%s)" % b)
3867 output.append(b"(%s)" % b)
3890
3868
3891 # multiple tags for a single parent separated by '/'
3869 # multiple tags for a single parent separated by '/'
3892 t = b'/'.join(taglist)
3870 t = b'/'.join(taglist)
3893 if t:
3871 if t:
3894 output.append(t)
3872 output.append(t)
3895
3873
3896 # multiple bookmarks for a single parent separated by '/'
3874 # multiple bookmarks for a single parent separated by '/'
3897 bm = b'/'.join(ctx.bookmarks())
3875 bm = b'/'.join(ctx.bookmarks())
3898 if bm:
3876 if bm:
3899 output.append(bm)
3877 output.append(bm)
3900 else:
3878 else:
3901 if branch:
3879 if branch:
3902 output.append(ctx.branch())
3880 output.append(ctx.branch())
3903
3881
3904 if tags:
3882 if tags:
3905 output.extend(taglist)
3883 output.extend(taglist)
3906
3884
3907 if bookmarks:
3885 if bookmarks:
3908 output.extend(ctx.bookmarks())
3886 output.extend(ctx.bookmarks())
3909
3887
3910 fm.data(node=ctx.hex())
3888 fm.data(node=ctx.hex())
3911 fm.data(branch=ctx.branch())
3889 fm.data(branch=ctx.branch())
3912 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3890 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3913 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3891 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3914 fm.context(ctx=ctx)
3892 fm.context(ctx=ctx)
3915
3893
3916 fm.plain(b"%s\n" % b' '.join(output))
3894 fm.plain(b"%s\n" % b' '.join(output))
3917 fm.end()
3895 fm.end()
3918
3896
3919
3897
3920 @command(
3898 @command(
3921 b'import|patch',
3899 b'import|patch',
3922 [
3900 [
3923 (
3901 (
3924 b'p',
3902 b'p',
3925 b'strip',
3903 b'strip',
3926 1,
3904 1,
3927 _(
3905 _(
3928 b'directory strip option for patch. This has the same '
3906 b'directory strip option for patch. This has the same '
3929 b'meaning as the corresponding patch option'
3907 b'meaning as the corresponding patch option'
3930 ),
3908 ),
3931 _(b'NUM'),
3909 _(b'NUM'),
3932 ),
3910 ),
3933 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3911 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3934 (b'', b'secret', None, _(b'use the secret phase for committing')),
3912 (b'', b'secret', None, _(b'use the secret phase for committing')),
3935 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3913 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3936 (
3914 (
3937 b'f',
3915 b'f',
3938 b'force',
3916 b'force',
3939 None,
3917 None,
3940 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3918 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3941 ),
3919 ),
3942 (
3920 (
3943 b'',
3921 b'',
3944 b'no-commit',
3922 b'no-commit',
3945 None,
3923 None,
3946 _(b"don't commit, just update the working directory"),
3924 _(b"don't commit, just update the working directory"),
3947 ),
3925 ),
3948 (
3926 (
3949 b'',
3927 b'',
3950 b'bypass',
3928 b'bypass',
3951 None,
3929 None,
3952 _(b"apply patch without touching the working directory"),
3930 _(b"apply patch without touching the working directory"),
3953 ),
3931 ),
3954 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3932 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3955 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3933 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3956 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3934 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3957 (
3935 (
3958 b'',
3936 b'',
3959 b'import-branch',
3937 b'import-branch',
3960 None,
3938 None,
3961 _(b'use any branch information in patch (implied by --exact)'),
3939 _(b'use any branch information in patch (implied by --exact)'),
3962 ),
3940 ),
3963 ]
3941 ]
3964 + commitopts
3942 + commitopts
3965 + commitopts2
3943 + commitopts2
3966 + similarityopts,
3944 + similarityopts,
3967 _(b'[OPTION]... PATCH...'),
3945 _(b'[OPTION]... PATCH...'),
3968 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3946 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3969 )
3947 )
3970 def import_(ui, repo, patch1=None, *patches, **opts):
3948 def import_(ui, repo, patch1=None, *patches, **opts):
3971 """import an ordered set of patches
3949 """import an ordered set of patches
3972
3950
3973 Import a list of patches and commit them individually (unless
3951 Import a list of patches and commit them individually (unless
3974 --no-commit is specified).
3952 --no-commit is specified).
3975
3953
3976 To read a patch from standard input (stdin), use "-" as the patch
3954 To read a patch from standard input (stdin), use "-" as the patch
3977 name. If a URL is specified, the patch will be downloaded from
3955 name. If a URL is specified, the patch will be downloaded from
3978 there.
3956 there.
3979
3957
3980 Import first applies changes to the working directory (unless
3958 Import first applies changes to the working directory (unless
3981 --bypass is specified), import will abort if there are outstanding
3959 --bypass is specified), import will abort if there are outstanding
3982 changes.
3960 changes.
3983
3961
3984 Use --bypass to apply and commit patches directly to the
3962 Use --bypass to apply and commit patches directly to the
3985 repository, without affecting the working directory. Without
3963 repository, without affecting the working directory. Without
3986 --exact, patches will be applied on top of the working directory
3964 --exact, patches will be applied on top of the working directory
3987 parent revision.
3965 parent revision.
3988
3966
3989 You can import a patch straight from a mail message. Even patches
3967 You can import a patch straight from a mail message. Even patches
3990 as attachments work (to use the body part, it must have type
3968 as attachments work (to use the body part, it must have type
3991 text/plain or text/x-patch). From and Subject headers of email
3969 text/plain or text/x-patch). From and Subject headers of email
3992 message are used as default committer and commit message. All
3970 message are used as default committer and commit message. All
3993 text/plain body parts before first diff are added to the commit
3971 text/plain body parts before first diff are added to the commit
3994 message.
3972 message.
3995
3973
3996 If the imported patch was generated by :hg:`export`, user and
3974 If the imported patch was generated by :hg:`export`, user and
3997 description from patch override values from message headers and
3975 description from patch override values from message headers and
3998 body. Values given on command line with -m/--message and -u/--user
3976 body. Values given on command line with -m/--message and -u/--user
3999 override these.
3977 override these.
4000
3978
4001 If --exact is specified, import will set the working directory to
3979 If --exact is specified, import will set the working directory to
4002 the parent of each patch before applying it, and will abort if the
3980 the parent of each patch before applying it, and will abort if the
4003 resulting changeset has a different ID than the one recorded in
3981 resulting changeset has a different ID than the one recorded in
4004 the patch. This will guard against various ways that portable
3982 the patch. This will guard against various ways that portable
4005 patch formats and mail systems might fail to transfer Mercurial
3983 patch formats and mail systems might fail to transfer Mercurial
4006 data or metadata. See :hg:`bundle` for lossless transmission.
3984 data or metadata. See :hg:`bundle` for lossless transmission.
4007
3985
4008 Use --partial to ensure a changeset will be created from the patch
3986 Use --partial to ensure a changeset will be created from the patch
4009 even if some hunks fail to apply. Hunks that fail to apply will be
3987 even if some hunks fail to apply. Hunks that fail to apply will be
4010 written to a <target-file>.rej file. Conflicts can then be resolved
3988 written to a <target-file>.rej file. Conflicts can then be resolved
4011 by hand before :hg:`commit --amend` is run to update the created
3989 by hand before :hg:`commit --amend` is run to update the created
4012 changeset. This flag exists to let people import patches that
3990 changeset. This flag exists to let people import patches that
4013 partially apply without losing the associated metadata (author,
3991 partially apply without losing the associated metadata (author,
4014 date, description, ...).
3992 date, description, ...).
4015
3993
4016 .. note::
3994 .. note::
4017
3995
4018 When no hunks apply cleanly, :hg:`import --partial` will create
3996 When no hunks apply cleanly, :hg:`import --partial` will create
4019 an empty changeset, importing only the patch metadata.
3997 an empty changeset, importing only the patch metadata.
4020
3998
4021 With -s/--similarity, hg will attempt to discover renames and
3999 With -s/--similarity, hg will attempt to discover renames and
4022 copies in the patch in the same way as :hg:`addremove`.
4000 copies in the patch in the same way as :hg:`addremove`.
4023
4001
4024 It is possible to use external patch programs to perform the patch
4002 It is possible to use external patch programs to perform the patch
4025 by setting the ``ui.patch`` configuration option. For the default
4003 by setting the ``ui.patch`` configuration option. For the default
4026 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4004 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4027 See :hg:`help config` for more information about configuration
4005 See :hg:`help config` for more information about configuration
4028 files and how to use these options.
4006 files and how to use these options.
4029
4007
4030 See :hg:`help dates` for a list of formats valid for -d/--date.
4008 See :hg:`help dates` for a list of formats valid for -d/--date.
4031
4009
4032 .. container:: verbose
4010 .. container:: verbose
4033
4011
4034 Examples:
4012 Examples:
4035
4013
4036 - import a traditional patch from a website and detect renames::
4014 - import a traditional patch from a website and detect renames::
4037
4015
4038 hg import -s 80 http://example.com/bugfix.patch
4016 hg import -s 80 http://example.com/bugfix.patch
4039
4017
4040 - import a changeset from an hgweb server::
4018 - import a changeset from an hgweb server::
4041
4019
4042 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4020 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4043
4021
4044 - import all the patches in an Unix-style mbox::
4022 - import all the patches in an Unix-style mbox::
4045
4023
4046 hg import incoming-patches.mbox
4024 hg import incoming-patches.mbox
4047
4025
4048 - import patches from stdin::
4026 - import patches from stdin::
4049
4027
4050 hg import -
4028 hg import -
4051
4029
4052 - attempt to exactly restore an exported changeset (not always
4030 - attempt to exactly restore an exported changeset (not always
4053 possible)::
4031 possible)::
4054
4032
4055 hg import --exact proposed-fix.patch
4033 hg import --exact proposed-fix.patch
4056
4034
4057 - use an external tool to apply a patch which is too fuzzy for
4035 - use an external tool to apply a patch which is too fuzzy for
4058 the default internal tool.
4036 the default internal tool.
4059
4037
4060 hg import --config ui.patch="patch --merge" fuzzy.patch
4038 hg import --config ui.patch="patch --merge" fuzzy.patch
4061
4039
4062 - change the default fuzzing from 2 to a less strict 7
4040 - change the default fuzzing from 2 to a less strict 7
4063
4041
4064 hg import --config ui.fuzz=7 fuzz.patch
4042 hg import --config ui.fuzz=7 fuzz.patch
4065
4043
4066 Returns 0 on success, 1 on partial success (see --partial).
4044 Returns 0 on success, 1 on partial success (see --partial).
4067 """
4045 """
4068
4046
4069 opts = pycompat.byteskwargs(opts)
4047 opts = pycompat.byteskwargs(opts)
4070 if not patch1:
4048 if not patch1:
4071 raise error.Abort(_(b'need at least one patch to import'))
4049 raise error.Abort(_(b'need at least one patch to import'))
4072
4050
4073 patches = (patch1,) + patches
4051 patches = (patch1,) + patches
4074
4052
4075 date = opts.get(b'date')
4053 date = opts.get(b'date')
4076 if date:
4054 if date:
4077 opts[b'date'] = dateutil.parsedate(date)
4055 opts[b'date'] = dateutil.parsedate(date)
4078
4056
4079 exact = opts.get(b'exact')
4057 exact = opts.get(b'exact')
4080 update = not opts.get(b'bypass')
4058 update = not opts.get(b'bypass')
4081 if not update and opts.get(b'no_commit'):
4059 if not update and opts.get(b'no_commit'):
4082 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4060 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4083 if opts.get(b'secret') and opts.get(b'no_commit'):
4061 if opts.get(b'secret') and opts.get(b'no_commit'):
4084 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4062 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4085 try:
4063 try:
4086 sim = float(opts.get(b'similarity') or 0)
4064 sim = float(opts.get(b'similarity') or 0)
4087 except ValueError:
4065 except ValueError:
4088 raise error.Abort(_(b'similarity must be a number'))
4066 raise error.Abort(_(b'similarity must be a number'))
4089 if sim < 0 or sim > 100:
4067 if sim < 0 or sim > 100:
4090 raise error.Abort(_(b'similarity must be between 0 and 100'))
4068 raise error.Abort(_(b'similarity must be between 0 and 100'))
4091 if sim and not update:
4069 if sim and not update:
4092 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4070 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4093 if exact:
4071 if exact:
4094 if opts.get(b'edit'):
4072 if opts.get(b'edit'):
4095 raise error.Abort(_(b'cannot use --exact with --edit'))
4073 raise error.Abort(_(b'cannot use --exact with --edit'))
4096 if opts.get(b'prefix'):
4074 if opts.get(b'prefix'):
4097 raise error.Abort(_(b'cannot use --exact with --prefix'))
4075 raise error.Abort(_(b'cannot use --exact with --prefix'))
4098
4076
4099 base = opts[b"base"]
4077 base = opts[b"base"]
4100 msgs = []
4078 msgs = []
4101 ret = 0
4079 ret = 0
4102
4080
4103 with repo.wlock():
4081 with repo.wlock():
4104 if update:
4082 if update:
4105 cmdutil.checkunfinished(repo)
4083 cmdutil.checkunfinished(repo)
4106 if exact or not opts.get(b'force'):
4084 if exact or not opts.get(b'force'):
4107 cmdutil.bailifchanged(repo)
4085 cmdutil.bailifchanged(repo)
4108
4086
4109 if not opts.get(b'no_commit'):
4087 if not opts.get(b'no_commit'):
4110 lock = repo.lock
4088 lock = repo.lock
4111 tr = lambda: repo.transaction(b'import')
4089 tr = lambda: repo.transaction(b'import')
4112 dsguard = util.nullcontextmanager
4090 dsguard = util.nullcontextmanager
4113 else:
4091 else:
4114 lock = util.nullcontextmanager
4092 lock = util.nullcontextmanager
4115 tr = util.nullcontextmanager
4093 tr = util.nullcontextmanager
4116 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4094 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4117 with lock(), tr(), dsguard():
4095 with lock(), tr(), dsguard():
4118 parents = repo[None].parents()
4096 parents = repo[None].parents()
4119 for patchurl in patches:
4097 for patchurl in patches:
4120 if patchurl == b'-':
4098 if patchurl == b'-':
4121 ui.status(_(b'applying patch from stdin\n'))
4099 ui.status(_(b'applying patch from stdin\n'))
4122 patchfile = ui.fin
4100 patchfile = ui.fin
4123 patchurl = b'stdin' # for error message
4101 patchurl = b'stdin' # for error message
4124 else:
4102 else:
4125 patchurl = os.path.join(base, patchurl)
4103 patchurl = os.path.join(base, patchurl)
4126 ui.status(_(b'applying %s\n') % patchurl)
4104 ui.status(_(b'applying %s\n') % patchurl)
4127 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4105 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4128
4106
4129 haspatch = False
4107 haspatch = False
4130 for hunk in patch.split(patchfile):
4108 for hunk in patch.split(patchfile):
4131 with patch.extract(ui, hunk) as patchdata:
4109 with patch.extract(ui, hunk) as patchdata:
4132 msg, node, rej = cmdutil.tryimportone(
4110 msg, node, rej = cmdutil.tryimportone(
4133 ui, repo, patchdata, parents, opts, msgs, hg.clean
4111 ui, repo, patchdata, parents, opts, msgs, hg.clean
4134 )
4112 )
4135 if msg:
4113 if msg:
4136 haspatch = True
4114 haspatch = True
4137 ui.note(msg + b'\n')
4115 ui.note(msg + b'\n')
4138 if update or exact:
4116 if update or exact:
4139 parents = repo[None].parents()
4117 parents = repo[None].parents()
4140 else:
4118 else:
4141 parents = [repo[node]]
4119 parents = [repo[node]]
4142 if rej:
4120 if rej:
4143 ui.write_err(_(b"patch applied partially\n"))
4121 ui.write_err(_(b"patch applied partially\n"))
4144 ui.write_err(
4122 ui.write_err(
4145 _(
4123 _(
4146 b"(fix the .rej files and run "
4124 b"(fix the .rej files and run "
4147 b"`hg commit --amend`)\n"
4125 b"`hg commit --amend`)\n"
4148 )
4126 )
4149 )
4127 )
4150 ret = 1
4128 ret = 1
4151 break
4129 break
4152
4130
4153 if not haspatch:
4131 if not haspatch:
4154 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4132 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4155
4133
4156 if msgs:
4134 if msgs:
4157 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4135 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4158 return ret
4136 return ret
4159
4137
4160
4138
4161 @command(
4139 @command(
4162 b'incoming|in',
4140 b'incoming|in',
4163 [
4141 [
4164 (
4142 (
4165 b'f',
4143 b'f',
4166 b'force',
4144 b'force',
4167 None,
4145 None,
4168 _(b'run even if remote repository is unrelated'),
4146 _(b'run even if remote repository is unrelated'),
4169 ),
4147 ),
4170 (b'n', b'newest-first', None, _(b'show newest record first')),
4148 (b'n', b'newest-first', None, _(b'show newest record first')),
4171 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4149 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4172 (
4150 (
4173 b'r',
4151 b'r',
4174 b'rev',
4152 b'rev',
4175 [],
4153 [],
4176 _(b'a remote changeset intended to be added'),
4154 _(b'a remote changeset intended to be added'),
4177 _(b'REV'),
4155 _(b'REV'),
4178 ),
4156 ),
4179 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4157 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4180 (
4158 (
4181 b'b',
4159 b'b',
4182 b'branch',
4160 b'branch',
4183 [],
4161 [],
4184 _(b'a specific branch you would like to pull'),
4162 _(b'a specific branch you would like to pull'),
4185 _(b'BRANCH'),
4163 _(b'BRANCH'),
4186 ),
4164 ),
4187 ]
4165 ]
4188 + logopts
4166 + logopts
4189 + remoteopts
4167 + remoteopts
4190 + subrepoopts,
4168 + subrepoopts,
4191 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4169 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4192 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4170 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4193 )
4171 )
4194 def incoming(ui, repo, source=b"default", **opts):
4172 def incoming(ui, repo, source=b"default", **opts):
4195 """show new changesets found in source
4173 """show new changesets found in source
4196
4174
4197 Show new changesets found in the specified path/URL or the default
4175 Show new changesets found in the specified path/URL or the default
4198 pull location. These are the changesets that would have been pulled
4176 pull location. These are the changesets that would have been pulled
4199 by :hg:`pull` at the time you issued this command.
4177 by :hg:`pull` at the time you issued this command.
4200
4178
4201 See pull for valid source format details.
4179 See pull for valid source format details.
4202
4180
4203 .. container:: verbose
4181 .. container:: verbose
4204
4182
4205 With -B/--bookmarks, the result of bookmark comparison between
4183 With -B/--bookmarks, the result of bookmark comparison between
4206 local and remote repositories is displayed. With -v/--verbose,
4184 local and remote repositories is displayed. With -v/--verbose,
4207 status is also displayed for each bookmark like below::
4185 status is also displayed for each bookmark like below::
4208
4186
4209 BM1 01234567890a added
4187 BM1 01234567890a added
4210 BM2 1234567890ab advanced
4188 BM2 1234567890ab advanced
4211 BM3 234567890abc diverged
4189 BM3 234567890abc diverged
4212 BM4 34567890abcd changed
4190 BM4 34567890abcd changed
4213
4191
4214 The action taken locally when pulling depends on the
4192 The action taken locally when pulling depends on the
4215 status of each bookmark:
4193 status of each bookmark:
4216
4194
4217 :``added``: pull will create it
4195 :``added``: pull will create it
4218 :``advanced``: pull will update it
4196 :``advanced``: pull will update it
4219 :``diverged``: pull will create a divergent bookmark
4197 :``diverged``: pull will create a divergent bookmark
4220 :``changed``: result depends on remote changesets
4198 :``changed``: result depends on remote changesets
4221
4199
4222 From the point of view of pulling behavior, bookmark
4200 From the point of view of pulling behavior, bookmark
4223 existing only in the remote repository are treated as ``added``,
4201 existing only in the remote repository are treated as ``added``,
4224 even if it is in fact locally deleted.
4202 even if it is in fact locally deleted.
4225
4203
4226 .. container:: verbose
4204 .. container:: verbose
4227
4205
4228 For remote repository, using --bundle avoids downloading the
4206 For remote repository, using --bundle avoids downloading the
4229 changesets twice if the incoming is followed by a pull.
4207 changesets twice if the incoming is followed by a pull.
4230
4208
4231 Examples:
4209 Examples:
4232
4210
4233 - show incoming changes with patches and full description::
4211 - show incoming changes with patches and full description::
4234
4212
4235 hg incoming -vp
4213 hg incoming -vp
4236
4214
4237 - show incoming changes excluding merges, store a bundle::
4215 - show incoming changes excluding merges, store a bundle::
4238
4216
4239 hg in -vpM --bundle incoming.hg
4217 hg in -vpM --bundle incoming.hg
4240 hg pull incoming.hg
4218 hg pull incoming.hg
4241
4219
4242 - briefly list changes inside a bundle::
4220 - briefly list changes inside a bundle::
4243
4221
4244 hg in changes.hg -T "{desc|firstline}\\n"
4222 hg in changes.hg -T "{desc|firstline}\\n"
4245
4223
4246 Returns 0 if there are incoming changes, 1 otherwise.
4224 Returns 0 if there are incoming changes, 1 otherwise.
4247 """
4225 """
4248 opts = pycompat.byteskwargs(opts)
4226 opts = pycompat.byteskwargs(opts)
4249 if opts.get(b'graph'):
4227 if opts.get(b'graph'):
4250 logcmdutil.checkunsupportedgraphflags([], opts)
4228 logcmdutil.checkunsupportedgraphflags([], opts)
4251
4229
4252 def display(other, chlist, displayer):
4230 def display(other, chlist, displayer):
4253 revdag = logcmdutil.graphrevs(other, chlist, opts)
4231 revdag = logcmdutil.graphrevs(other, chlist, opts)
4254 logcmdutil.displaygraph(
4232 logcmdutil.displaygraph(
4255 ui, repo, revdag, displayer, graphmod.asciiedges
4233 ui, repo, revdag, displayer, graphmod.asciiedges
4256 )
4234 )
4257
4235
4258 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4236 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4259 return 0
4237 return 0
4260
4238
4261 if opts.get(b'bundle') and opts.get(b'subrepos'):
4239 if opts.get(b'bundle') and opts.get(b'subrepos'):
4262 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4240 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4263
4241
4264 if opts.get(b'bookmarks'):
4242 if opts.get(b'bookmarks'):
4265 source, branches = hg.parseurl(
4243 source, branches = hg.parseurl(
4266 ui.expandpath(source), opts.get(b'branch')
4244 ui.expandpath(source), opts.get(b'branch')
4267 )
4245 )
4268 other = hg.peer(repo, opts, source)
4246 other = hg.peer(repo, opts, source)
4269 if b'bookmarks' not in other.listkeys(b'namespaces'):
4247 if b'bookmarks' not in other.listkeys(b'namespaces'):
4270 ui.warn(_(b"remote doesn't support bookmarks\n"))
4248 ui.warn(_(b"remote doesn't support bookmarks\n"))
4271 return 0
4249 return 0
4272 ui.pager(b'incoming')
4250 ui.pager(b'incoming')
4273 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4251 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4274 return bookmarks.incoming(ui, repo, other)
4252 return bookmarks.incoming(ui, repo, other)
4275
4253
4276 repo._subtoppath = ui.expandpath(source)
4254 repo._subtoppath = ui.expandpath(source)
4277 try:
4255 try:
4278 return hg.incoming(ui, repo, source, opts)
4256 return hg.incoming(ui, repo, source, opts)
4279 finally:
4257 finally:
4280 del repo._subtoppath
4258 del repo._subtoppath
4281
4259
4282
4260
4283 @command(
4261 @command(
4284 b'init',
4262 b'init',
4285 remoteopts,
4263 remoteopts,
4286 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4264 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4287 helpcategory=command.CATEGORY_REPO_CREATION,
4265 helpcategory=command.CATEGORY_REPO_CREATION,
4288 helpbasic=True,
4266 helpbasic=True,
4289 norepo=True,
4267 norepo=True,
4290 )
4268 )
4291 def init(ui, dest=b".", **opts):
4269 def init(ui, dest=b".", **opts):
4292 """create a new repository in the given directory
4270 """create a new repository in the given directory
4293
4271
4294 Initialize a new repository in the given directory. If the given
4272 Initialize a new repository in the given directory. If the given
4295 directory does not exist, it will be created.
4273 directory does not exist, it will be created.
4296
4274
4297 If no directory is given, the current directory is used.
4275 If no directory is given, the current directory is used.
4298
4276
4299 It is possible to specify an ``ssh://`` URL as the destination.
4277 It is possible to specify an ``ssh://`` URL as the destination.
4300 See :hg:`help urls` for more information.
4278 See :hg:`help urls` for more information.
4301
4279
4302 Returns 0 on success.
4280 Returns 0 on success.
4303 """
4281 """
4304 opts = pycompat.byteskwargs(opts)
4282 opts = pycompat.byteskwargs(opts)
4305 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4306
4284
4307
4285
4308 @command(
4286 @command(
4309 b'locate',
4287 b'locate',
4310 [
4288 [
4311 (
4289 (
4312 b'r',
4290 b'r',
4313 b'rev',
4291 b'rev',
4314 b'',
4292 b'',
4315 _(b'search the repository as it is in REV'),
4293 _(b'search the repository as it is in REV'),
4316 _(b'REV'),
4294 _(b'REV'),
4317 ),
4295 ),
4318 (
4296 (
4319 b'0',
4297 b'0',
4320 b'print0',
4298 b'print0',
4321 None,
4299 None,
4322 _(b'end filenames with NUL, for use with xargs'),
4300 _(b'end filenames with NUL, for use with xargs'),
4323 ),
4301 ),
4324 (
4302 (
4325 b'f',
4303 b'f',
4326 b'fullpath',
4304 b'fullpath',
4327 None,
4305 None,
4328 _(b'print complete paths from the filesystem root'),
4306 _(b'print complete paths from the filesystem root'),
4329 ),
4307 ),
4330 ]
4308 ]
4331 + walkopts,
4309 + walkopts,
4332 _(b'[OPTION]... [PATTERN]...'),
4310 _(b'[OPTION]... [PATTERN]...'),
4333 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4311 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4334 )
4312 )
4335 def locate(ui, repo, *pats, **opts):
4313 def locate(ui, repo, *pats, **opts):
4336 """locate files matching specific patterns (DEPRECATED)
4314 """locate files matching specific patterns (DEPRECATED)
4337
4315
4338 Print files under Mercurial control in the working directory whose
4316 Print files under Mercurial control in the working directory whose
4339 names match the given patterns.
4317 names match the given patterns.
4340
4318
4341 By default, this command searches all directories in the working
4319 By default, this command searches all directories in the working
4342 directory. To search just the current directory and its
4320 directory. To search just the current directory and its
4343 subdirectories, use "--include .".
4321 subdirectories, use "--include .".
4344
4322
4345 If no patterns are given to match, this command prints the names
4323 If no patterns are given to match, this command prints the names
4346 of all files under Mercurial control in the working directory.
4324 of all files under Mercurial control in the working directory.
4347
4325
4348 If you want to feed the output of this command into the "xargs"
4326 If you want to feed the output of this command into the "xargs"
4349 command, use the -0 option to both this command and "xargs". This
4327 command, use the -0 option to both this command and "xargs". This
4350 will avoid the problem of "xargs" treating single filenames that
4328 will avoid the problem of "xargs" treating single filenames that
4351 contain whitespace as multiple filenames.
4329 contain whitespace as multiple filenames.
4352
4330
4353 See :hg:`help files` for a more versatile command.
4331 See :hg:`help files` for a more versatile command.
4354
4332
4355 Returns 0 if a match is found, 1 otherwise.
4333 Returns 0 if a match is found, 1 otherwise.
4356 """
4334 """
4357 opts = pycompat.byteskwargs(opts)
4335 opts = pycompat.byteskwargs(opts)
4358 if opts.get(b'print0'):
4336 if opts.get(b'print0'):
4359 end = b'\0'
4337 end = b'\0'
4360 else:
4338 else:
4361 end = b'\n'
4339 end = b'\n'
4362 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4340 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4363
4341
4364 ret = 1
4342 ret = 1
4365 m = scmutil.match(
4343 m = scmutil.match(
4366 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4344 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4367 )
4345 )
4368
4346
4369 ui.pager(b'locate')
4347 ui.pager(b'locate')
4370 if ctx.rev() is None:
4348 if ctx.rev() is None:
4371 # When run on the working copy, "locate" includes removed files, so
4349 # When run on the working copy, "locate" includes removed files, so
4372 # we get the list of files from the dirstate.
4350 # we get the list of files from the dirstate.
4373 filesgen = sorted(repo.dirstate.matches(m))
4351 filesgen = sorted(repo.dirstate.matches(m))
4374 else:
4352 else:
4375 filesgen = ctx.matches(m)
4353 filesgen = ctx.matches(m)
4376 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4354 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4377 for abs in filesgen:
4355 for abs in filesgen:
4378 if opts.get(b'fullpath'):
4356 if opts.get(b'fullpath'):
4379 ui.write(repo.wjoin(abs), end)
4357 ui.write(repo.wjoin(abs), end)
4380 else:
4358 else:
4381 ui.write(uipathfn(abs), end)
4359 ui.write(uipathfn(abs), end)
4382 ret = 0
4360 ret = 0
4383
4361
4384 return ret
4362 return ret
4385
4363
4386
4364
4387 @command(
4365 @command(
4388 b'log|history',
4366 b'log|history',
4389 [
4367 [
4390 (
4368 (
4391 b'f',
4369 b'f',
4392 b'follow',
4370 b'follow',
4393 None,
4371 None,
4394 _(
4372 _(
4395 b'follow changeset history, or file history across copies and renames'
4373 b'follow changeset history, or file history across copies and renames'
4396 ),
4374 ),
4397 ),
4375 ),
4398 (
4376 (
4399 b'',
4377 b'',
4400 b'follow-first',
4378 b'follow-first',
4401 None,
4379 None,
4402 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4380 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4403 ),
4381 ),
4404 (
4382 (
4405 b'd',
4383 b'd',
4406 b'date',
4384 b'date',
4407 b'',
4385 b'',
4408 _(b'show revisions matching date spec'),
4386 _(b'show revisions matching date spec'),
4409 _(b'DATE'),
4387 _(b'DATE'),
4410 ),
4388 ),
4411 (b'C', b'copies', None, _(b'show copied files')),
4389 (b'C', b'copies', None, _(b'show copied files')),
4412 (
4390 (
4413 b'k',
4391 b'k',
4414 b'keyword',
4392 b'keyword',
4415 [],
4393 [],
4416 _(b'do case-insensitive search for a given text'),
4394 _(b'do case-insensitive search for a given text'),
4417 _(b'TEXT'),
4395 _(b'TEXT'),
4418 ),
4396 ),
4419 (
4397 (
4420 b'r',
4398 b'r',
4421 b'rev',
4399 b'rev',
4422 [],
4400 [],
4423 _(b'show the specified revision or revset'),
4401 _(b'show the specified revision or revset'),
4424 _(b'REV'),
4402 _(b'REV'),
4425 ),
4403 ),
4426 (
4404 (
4427 b'L',
4405 b'L',
4428 b'line-range',
4406 b'line-range',
4429 [],
4407 [],
4430 _(b'follow line range of specified file (EXPERIMENTAL)'),
4408 _(b'follow line range of specified file (EXPERIMENTAL)'),
4431 _(b'FILE,RANGE'),
4409 _(b'FILE,RANGE'),
4432 ),
4410 ),
4433 (
4411 (
4434 b'',
4412 b'',
4435 b'removed',
4413 b'removed',
4436 None,
4414 None,
4437 _(b'include revisions where files were removed'),
4415 _(b'include revisions where files were removed'),
4438 ),
4416 ),
4439 (
4417 (
4440 b'm',
4418 b'm',
4441 b'only-merges',
4419 b'only-merges',
4442 None,
4420 None,
4443 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4421 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4444 ),
4422 ),
4445 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4423 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4446 (
4424 (
4447 b'',
4425 b'',
4448 b'only-branch',
4426 b'only-branch',
4449 [],
4427 [],
4450 _(
4428 _(
4451 b'show only changesets within the given named branch (DEPRECATED)'
4429 b'show only changesets within the given named branch (DEPRECATED)'
4452 ),
4430 ),
4453 _(b'BRANCH'),
4431 _(b'BRANCH'),
4454 ),
4432 ),
4455 (
4433 (
4456 b'b',
4434 b'b',
4457 b'branch',
4435 b'branch',
4458 [],
4436 [],
4459 _(b'show changesets within the given named branch'),
4437 _(b'show changesets within the given named branch'),
4460 _(b'BRANCH'),
4438 _(b'BRANCH'),
4461 ),
4439 ),
4462 (
4440 (
4463 b'P',
4441 b'P',
4464 b'prune',
4442 b'prune',
4465 [],
4443 [],
4466 _(b'do not display revision or any of its ancestors'),
4444 _(b'do not display revision or any of its ancestors'),
4467 _(b'REV'),
4445 _(b'REV'),
4468 ),
4446 ),
4469 ]
4447 ]
4470 + logopts
4448 + logopts
4471 + walkopts,
4449 + walkopts,
4472 _(b'[OPTION]... [FILE]'),
4450 _(b'[OPTION]... [FILE]'),
4473 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4451 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4474 helpbasic=True,
4452 helpbasic=True,
4475 inferrepo=True,
4453 inferrepo=True,
4476 intents={INTENT_READONLY},
4454 intents={INTENT_READONLY},
4477 )
4455 )
4478 def log(ui, repo, *pats, **opts):
4456 def log(ui, repo, *pats, **opts):
4479 """show revision history of entire repository or files
4457 """show revision history of entire repository or files
4480
4458
4481 Print the revision history of the specified files or the entire
4459 Print the revision history of the specified files or the entire
4482 project.
4460 project.
4483
4461
4484 If no revision range is specified, the default is ``tip:0`` unless
4462 If no revision range is specified, the default is ``tip:0`` unless
4485 --follow is set, in which case the working directory parent is
4463 --follow is set, in which case the working directory parent is
4486 used as the starting revision.
4464 used as the starting revision.
4487
4465
4488 File history is shown without following rename or copy history of
4466 File history is shown without following rename or copy history of
4489 files. Use -f/--follow with a filename to follow history across
4467 files. Use -f/--follow with a filename to follow history across
4490 renames and copies. --follow without a filename will only show
4468 renames and copies. --follow without a filename will only show
4491 ancestors of the starting revision.
4469 ancestors of the starting revision.
4492
4470
4493 By default this command prints revision number and changeset id,
4471 By default this command prints revision number and changeset id,
4494 tags, non-trivial parents, user, date and time, and a summary for
4472 tags, non-trivial parents, user, date and time, and a summary for
4495 each commit. When the -v/--verbose switch is used, the list of
4473 each commit. When the -v/--verbose switch is used, the list of
4496 changed files and full commit message are shown.
4474 changed files and full commit message are shown.
4497
4475
4498 With --graph the revisions are shown as an ASCII art DAG with the most
4476 With --graph the revisions are shown as an ASCII art DAG with the most
4499 recent changeset at the top.
4477 recent changeset at the top.
4500 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4478 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4501 involved in an unresolved merge conflict, '_' closes a branch,
4479 involved in an unresolved merge conflict, '_' closes a branch,
4502 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4480 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4503 changeset from the lines below is a parent of the 'o' merge on the same
4481 changeset from the lines below is a parent of the 'o' merge on the same
4504 line.
4482 line.
4505 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4483 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4506 of a '|' indicates one or more revisions in a path are omitted.
4484 of a '|' indicates one or more revisions in a path are omitted.
4507
4485
4508 .. container:: verbose
4486 .. container:: verbose
4509
4487
4510 Use -L/--line-range FILE,M:N options to follow the history of lines
4488 Use -L/--line-range FILE,M:N options to follow the history of lines
4511 from M to N in FILE. With -p/--patch only diff hunks affecting
4489 from M to N in FILE. With -p/--patch only diff hunks affecting
4512 specified line range will be shown. This option requires --follow;
4490 specified line range will be shown. This option requires --follow;
4513 it can be specified multiple times. Currently, this option is not
4491 it can be specified multiple times. Currently, this option is not
4514 compatible with --graph. This option is experimental.
4492 compatible with --graph. This option is experimental.
4515
4493
4516 .. note::
4494 .. note::
4517
4495
4518 :hg:`log --patch` may generate unexpected diff output for merge
4496 :hg:`log --patch` may generate unexpected diff output for merge
4519 changesets, as it will only compare the merge changeset against
4497 changesets, as it will only compare the merge changeset against
4520 its first parent. Also, only files different from BOTH parents
4498 its first parent. Also, only files different from BOTH parents
4521 will appear in files:.
4499 will appear in files:.
4522
4500
4523 .. note::
4501 .. note::
4524
4502
4525 For performance reasons, :hg:`log FILE` may omit duplicate changes
4503 For performance reasons, :hg:`log FILE` may omit duplicate changes
4526 made on branches and will not show removals or mode changes. To
4504 made on branches and will not show removals or mode changes. To
4527 see all such changes, use the --removed switch.
4505 see all such changes, use the --removed switch.
4528
4506
4529 .. container:: verbose
4507 .. container:: verbose
4530
4508
4531 .. note::
4509 .. note::
4532
4510
4533 The history resulting from -L/--line-range options depends on diff
4511 The history resulting from -L/--line-range options depends on diff
4534 options; for instance if white-spaces are ignored, respective changes
4512 options; for instance if white-spaces are ignored, respective changes
4535 with only white-spaces in specified line range will not be listed.
4513 with only white-spaces in specified line range will not be listed.
4536
4514
4537 .. container:: verbose
4515 .. container:: verbose
4538
4516
4539 Some examples:
4517 Some examples:
4540
4518
4541 - changesets with full descriptions and file lists::
4519 - changesets with full descriptions and file lists::
4542
4520
4543 hg log -v
4521 hg log -v
4544
4522
4545 - changesets ancestral to the working directory::
4523 - changesets ancestral to the working directory::
4546
4524
4547 hg log -f
4525 hg log -f
4548
4526
4549 - last 10 commits on the current branch::
4527 - last 10 commits on the current branch::
4550
4528
4551 hg log -l 10 -b .
4529 hg log -l 10 -b .
4552
4530
4553 - changesets showing all modifications of a file, including removals::
4531 - changesets showing all modifications of a file, including removals::
4554
4532
4555 hg log --removed file.c
4533 hg log --removed file.c
4556
4534
4557 - all changesets that touch a directory, with diffs, excluding merges::
4535 - all changesets that touch a directory, with diffs, excluding merges::
4558
4536
4559 hg log -Mp lib/
4537 hg log -Mp lib/
4560
4538
4561 - all revision numbers that match a keyword::
4539 - all revision numbers that match a keyword::
4562
4540
4563 hg log -k bug --template "{rev}\\n"
4541 hg log -k bug --template "{rev}\\n"
4564
4542
4565 - the full hash identifier of the working directory parent::
4543 - the full hash identifier of the working directory parent::
4566
4544
4567 hg log -r . --template "{node}\\n"
4545 hg log -r . --template "{node}\\n"
4568
4546
4569 - list available log templates::
4547 - list available log templates::
4570
4548
4571 hg log -T list
4549 hg log -T list
4572
4550
4573 - check if a given changeset is included in a tagged release::
4551 - check if a given changeset is included in a tagged release::
4574
4552
4575 hg log -r "a21ccf and ancestor(1.9)"
4553 hg log -r "a21ccf and ancestor(1.9)"
4576
4554
4577 - find all changesets by some user in a date range::
4555 - find all changesets by some user in a date range::
4578
4556
4579 hg log -k alice -d "may 2008 to jul 2008"
4557 hg log -k alice -d "may 2008 to jul 2008"
4580
4558
4581 - summary of all changesets after the last tag::
4559 - summary of all changesets after the last tag::
4582
4560
4583 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4561 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4584
4562
4585 - changesets touching lines 13 to 23 for file.c::
4563 - changesets touching lines 13 to 23 for file.c::
4586
4564
4587 hg log -L file.c,13:23
4565 hg log -L file.c,13:23
4588
4566
4589 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4567 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4590 main.c with patch::
4568 main.c with patch::
4591
4569
4592 hg log -L file.c,13:23 -L main.c,2:6 -p
4570 hg log -L file.c,13:23 -L main.c,2:6 -p
4593
4571
4594 See :hg:`help dates` for a list of formats valid for -d/--date.
4572 See :hg:`help dates` for a list of formats valid for -d/--date.
4595
4573
4596 See :hg:`help revisions` for more about specifying and ordering
4574 See :hg:`help revisions` for more about specifying and ordering
4597 revisions.
4575 revisions.
4598
4576
4599 See :hg:`help templates` for more about pre-packaged styles and
4577 See :hg:`help templates` for more about pre-packaged styles and
4600 specifying custom templates. The default template used by the log
4578 specifying custom templates. The default template used by the log
4601 command can be customized via the ``ui.logtemplate`` configuration
4579 command can be customized via the ``ui.logtemplate`` configuration
4602 setting.
4580 setting.
4603
4581
4604 Returns 0 on success.
4582 Returns 0 on success.
4605
4583
4606 """
4584 """
4607 opts = pycompat.byteskwargs(opts)
4585 opts = pycompat.byteskwargs(opts)
4608 linerange = opts.get(b'line_range')
4586 linerange = opts.get(b'line_range')
4609
4587
4610 if linerange and not opts.get(b'follow'):
4588 if linerange and not opts.get(b'follow'):
4611 raise error.Abort(_(b'--line-range requires --follow'))
4589 raise error.Abort(_(b'--line-range requires --follow'))
4612
4590
4613 if linerange and pats:
4591 if linerange and pats:
4614 # TODO: take pats as patterns with no line-range filter
4592 # TODO: take pats as patterns with no line-range filter
4615 raise error.Abort(
4593 raise error.Abort(
4616 _(b'FILE arguments are not compatible with --line-range option')
4594 _(b'FILE arguments are not compatible with --line-range option')
4617 )
4595 )
4618
4596
4619 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4597 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4620 revs, differ = logcmdutil.getrevs(
4598 revs, differ = logcmdutil.getrevs(
4621 repo, logcmdutil.parseopts(ui, pats, opts)
4599 repo, logcmdutil.parseopts(ui, pats, opts)
4622 )
4600 )
4623 if linerange:
4601 if linerange:
4624 # TODO: should follow file history from logcmdutil._initialrevs(),
4602 # TODO: should follow file history from logcmdutil._initialrevs(),
4625 # then filter the result by logcmdutil._makerevset() and --limit
4603 # then filter the result by logcmdutil._makerevset() and --limit
4626 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4604 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4627
4605
4628 getcopies = None
4606 getcopies = None
4629 if opts.get(b'copies'):
4607 if opts.get(b'copies'):
4630 endrev = None
4608 endrev = None
4631 if revs:
4609 if revs:
4632 endrev = revs.max() + 1
4610 endrev = revs.max() + 1
4633 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4611 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4634
4612
4635 ui.pager(b'log')
4613 ui.pager(b'log')
4636 displayer = logcmdutil.changesetdisplayer(
4614 displayer = logcmdutil.changesetdisplayer(
4637 ui, repo, opts, differ, buffered=True
4615 ui, repo, opts, differ, buffered=True
4638 )
4616 )
4639 if opts.get(b'graph'):
4617 if opts.get(b'graph'):
4640 displayfn = logcmdutil.displaygraphrevs
4618 displayfn = logcmdutil.displaygraphrevs
4641 else:
4619 else:
4642 displayfn = logcmdutil.displayrevs
4620 displayfn = logcmdutil.displayrevs
4643 displayfn(ui, repo, revs, displayer, getcopies)
4621 displayfn(ui, repo, revs, displayer, getcopies)
4644
4622
4645
4623
4646 @command(
4624 @command(
4647 b'manifest',
4625 b'manifest',
4648 [
4626 [
4649 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4627 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4650 (b'', b'all', False, _(b"list files from all revisions")),
4628 (b'', b'all', False, _(b"list files from all revisions")),
4651 ]
4629 ]
4652 + formatteropts,
4630 + formatteropts,
4653 _(b'[-r REV]'),
4631 _(b'[-r REV]'),
4654 helpcategory=command.CATEGORY_MAINTENANCE,
4632 helpcategory=command.CATEGORY_MAINTENANCE,
4655 intents={INTENT_READONLY},
4633 intents={INTENT_READONLY},
4656 )
4634 )
4657 def manifest(ui, repo, node=None, rev=None, **opts):
4635 def manifest(ui, repo, node=None, rev=None, **opts):
4658 """output the current or given revision of the project manifest
4636 """output the current or given revision of the project manifest
4659
4637
4660 Print a list of version controlled files for the given revision.
4638 Print a list of version controlled files for the given revision.
4661 If no revision is given, the first parent of the working directory
4639 If no revision is given, the first parent of the working directory
4662 is used, or the null revision if no revision is checked out.
4640 is used, or the null revision if no revision is checked out.
4663
4641
4664 With -v, print file permissions, symlink and executable bits.
4642 With -v, print file permissions, symlink and executable bits.
4665 With --debug, print file revision hashes.
4643 With --debug, print file revision hashes.
4666
4644
4667 If option --all is specified, the list of all files from all revisions
4645 If option --all is specified, the list of all files from all revisions
4668 is printed. This includes deleted and renamed files.
4646 is printed. This includes deleted and renamed files.
4669
4647
4670 Returns 0 on success.
4648 Returns 0 on success.
4671 """
4649 """
4672 opts = pycompat.byteskwargs(opts)
4650 opts = pycompat.byteskwargs(opts)
4673 fm = ui.formatter(b'manifest', opts)
4651 fm = ui.formatter(b'manifest', opts)
4674
4652
4675 if opts.get(b'all'):
4653 if opts.get(b'all'):
4676 if rev or node:
4654 if rev or node:
4677 raise error.Abort(_(b"can't specify a revision with --all"))
4655 raise error.Abort(_(b"can't specify a revision with --all"))
4678
4656
4679 res = set()
4657 res = set()
4680 for rev in repo:
4658 for rev in repo:
4681 ctx = repo[rev]
4659 ctx = repo[rev]
4682 res |= set(ctx.files())
4660 res |= set(ctx.files())
4683
4661
4684 ui.pager(b'manifest')
4662 ui.pager(b'manifest')
4685 for f in sorted(res):
4663 for f in sorted(res):
4686 fm.startitem()
4664 fm.startitem()
4687 fm.write(b"path", b'%s\n', f)
4665 fm.write(b"path", b'%s\n', f)
4688 fm.end()
4666 fm.end()
4689 return
4667 return
4690
4668
4691 if rev and node:
4669 if rev and node:
4692 raise error.Abort(_(b"please specify just one revision"))
4670 raise error.Abort(_(b"please specify just one revision"))
4693
4671
4694 if not node:
4672 if not node:
4695 node = rev
4673 node = rev
4696
4674
4697 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4675 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4698 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4676 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4699 if node:
4677 if node:
4700 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4678 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4701 ctx = scmutil.revsingle(repo, node)
4679 ctx = scmutil.revsingle(repo, node)
4702 mf = ctx.manifest()
4680 mf = ctx.manifest()
4703 ui.pager(b'manifest')
4681 ui.pager(b'manifest')
4704 for f in ctx:
4682 for f in ctx:
4705 fm.startitem()
4683 fm.startitem()
4706 fm.context(ctx=ctx)
4684 fm.context(ctx=ctx)
4707 fl = ctx[f].flags()
4685 fl = ctx[f].flags()
4708 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4686 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4709 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4687 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4710 fm.write(b'path', b'%s\n', f)
4688 fm.write(b'path', b'%s\n', f)
4711 fm.end()
4689 fm.end()
4712
4690
4713
4691
4714 @command(
4692 @command(
4715 b'merge',
4693 b'merge',
4716 [
4694 [
4717 (
4695 (
4718 b'f',
4696 b'f',
4719 b'force',
4697 b'force',
4720 None,
4698 None,
4721 _(b'force a merge including outstanding changes (DEPRECATED)'),
4699 _(b'force a merge including outstanding changes (DEPRECATED)'),
4722 ),
4700 ),
4723 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4701 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4724 (
4702 (
4725 b'P',
4703 b'P',
4726 b'preview',
4704 b'preview',
4727 None,
4705 None,
4728 _(b'review revisions to merge (no merge is performed)'),
4706 _(b'review revisions to merge (no merge is performed)'),
4729 ),
4707 ),
4730 (b'', b'abort', None, _(b'abort the ongoing merge')),
4708 (b'', b'abort', None, _(b'abort the ongoing merge')),
4731 ]
4709 ]
4732 + mergetoolopts,
4710 + mergetoolopts,
4733 _(b'[-P] [[-r] REV]'),
4711 _(b'[-P] [[-r] REV]'),
4734 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4712 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4735 helpbasic=True,
4713 helpbasic=True,
4736 )
4714 )
4737 def merge(ui, repo, node=None, **opts):
4715 def merge(ui, repo, node=None, **opts):
4738 """merge another revision into working directory
4716 """merge another revision into working directory
4739
4717
4740 The current working directory is updated with all changes made in
4718 The current working directory is updated with all changes made in
4741 the requested revision since the last common predecessor revision.
4719 the requested revision since the last common predecessor revision.
4742
4720
4743 Files that changed between either parent are marked as changed for
4721 Files that changed between either parent are marked as changed for
4744 the next commit and a commit must be performed before any further
4722 the next commit and a commit must be performed before any further
4745 updates to the repository are allowed. The next commit will have
4723 updates to the repository are allowed. The next commit will have
4746 two parents.
4724 two parents.
4747
4725
4748 ``--tool`` can be used to specify the merge tool used for file
4726 ``--tool`` can be used to specify the merge tool used for file
4749 merges. It overrides the HGMERGE environment variable and your
4727 merges. It overrides the HGMERGE environment variable and your
4750 configuration files. See :hg:`help merge-tools` for options.
4728 configuration files. See :hg:`help merge-tools` for options.
4751
4729
4752 If no revision is specified, the working directory's parent is a
4730 If no revision is specified, the working directory's parent is a
4753 head revision, and the current branch contains exactly one other
4731 head revision, and the current branch contains exactly one other
4754 head, the other head is merged with by default. Otherwise, an
4732 head, the other head is merged with by default. Otherwise, an
4755 explicit revision with which to merge must be provided.
4733 explicit revision with which to merge must be provided.
4756
4734
4757 See :hg:`help resolve` for information on handling file conflicts.
4735 See :hg:`help resolve` for information on handling file conflicts.
4758
4736
4759 To undo an uncommitted merge, use :hg:`merge --abort` which
4737 To undo an uncommitted merge, use :hg:`merge --abort` which
4760 will check out a clean copy of the original merge parent, losing
4738 will check out a clean copy of the original merge parent, losing
4761 all changes.
4739 all changes.
4762
4740
4763 Returns 0 on success, 1 if there are unresolved files.
4741 Returns 0 on success, 1 if there are unresolved files.
4764 """
4742 """
4765
4743
4766 opts = pycompat.byteskwargs(opts)
4744 opts = pycompat.byteskwargs(opts)
4767 abort = opts.get(b'abort')
4745 abort = opts.get(b'abort')
4768 if abort and repo.dirstate.p2() == nullid:
4746 if abort and repo.dirstate.p2() == nullid:
4769 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4747 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4770 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4748 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4771 if abort:
4749 if abort:
4772 state = cmdutil.getunfinishedstate(repo)
4750 state = cmdutil.getunfinishedstate(repo)
4773 if state and state._opname != b'merge':
4751 if state and state._opname != b'merge':
4774 raise error.Abort(
4752 raise error.Abort(
4775 _(b'cannot abort merge with %s in progress') % (state._opname),
4753 _(b'cannot abort merge with %s in progress') % (state._opname),
4776 hint=state.hint(),
4754 hint=state.hint(),
4777 )
4755 )
4778 if node:
4756 if node:
4779 raise error.Abort(_(b"cannot specify a node with --abort"))
4757 raise error.Abort(_(b"cannot specify a node with --abort"))
4780 return hg.abortmerge(repo.ui, repo)
4758 return hg.abortmerge(repo.ui, repo)
4781
4759
4782 if opts.get(b'rev') and node:
4760 if opts.get(b'rev') and node:
4783 raise error.Abort(_(b"please specify just one revision"))
4761 raise error.Abort(_(b"please specify just one revision"))
4784 if not node:
4762 if not node:
4785 node = opts.get(b'rev')
4763 node = opts.get(b'rev')
4786
4764
4787 if node:
4765 if node:
4788 ctx = scmutil.revsingle(repo, node)
4766 ctx = scmutil.revsingle(repo, node)
4789 else:
4767 else:
4790 if ui.configbool(b'commands', b'merge.require-rev'):
4768 if ui.configbool(b'commands', b'merge.require-rev'):
4791 raise error.Abort(
4769 raise error.Abort(
4792 _(
4770 _(
4793 b'configuration requires specifying revision to merge '
4771 b'configuration requires specifying revision to merge '
4794 b'with'
4772 b'with'
4795 )
4773 )
4796 )
4774 )
4797 ctx = repo[destutil.destmerge(repo)]
4775 ctx = repo[destutil.destmerge(repo)]
4798
4776
4799 if ctx.node() is None:
4777 if ctx.node() is None:
4800 raise error.Abort(_(b'merging with the working copy has no effect'))
4778 raise error.Abort(_(b'merging with the working copy has no effect'))
4801
4779
4802 if opts.get(b'preview'):
4780 if opts.get(b'preview'):
4803 # find nodes that are ancestors of p2 but not of p1
4781 # find nodes that are ancestors of p2 but not of p1
4804 p1 = repo[b'.'].node()
4782 p1 = repo[b'.'].node()
4805 p2 = ctx.node()
4783 p2 = ctx.node()
4806 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4784 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4807
4785
4808 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4786 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4809 for node in nodes:
4787 for node in nodes:
4810 displayer.show(repo[node])
4788 displayer.show(repo[node])
4811 displayer.close()
4789 displayer.close()
4812 return 0
4790 return 0
4813
4791
4814 # ui.forcemerge is an internal variable, do not document
4792 # ui.forcemerge is an internal variable, do not document
4815 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4793 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4816 with ui.configoverride(overrides, b'merge'):
4794 with ui.configoverride(overrides, b'merge'):
4817 force = opts.get(b'force')
4795 force = opts.get(b'force')
4818 labels = [b'working copy', b'merge rev']
4796 labels = [b'working copy', b'merge rev']
4819 return hg.merge(ctx, force=force, labels=labels)
4797 return hg.merge(ctx, force=force, labels=labels)
4820
4798
4821
4799
4822 statemod.addunfinished(
4800 statemod.addunfinished(
4823 b'merge',
4801 b'merge',
4824 fname=None,
4802 fname=None,
4825 clearable=True,
4803 clearable=True,
4826 allowcommit=True,
4804 allowcommit=True,
4827 cmdmsg=_(b'outstanding uncommitted merge'),
4805 cmdmsg=_(b'outstanding uncommitted merge'),
4828 abortfunc=hg.abortmerge,
4806 abortfunc=hg.abortmerge,
4829 statushint=_(
4807 statushint=_(
4830 b'To continue: hg commit\nTo abort: hg merge --abort'
4808 b'To continue: hg commit\nTo abort: hg merge --abort'
4831 ),
4809 ),
4832 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4810 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4833 )
4811 )
4834
4812
4835
4813
4836 @command(
4814 @command(
4837 b'outgoing|out',
4815 b'outgoing|out',
4838 [
4816 [
4839 (
4817 (
4840 b'f',
4818 b'f',
4841 b'force',
4819 b'force',
4842 None,
4820 None,
4843 _(b'run even when the destination is unrelated'),
4821 _(b'run even when the destination is unrelated'),
4844 ),
4822 ),
4845 (
4823 (
4846 b'r',
4824 b'r',
4847 b'rev',
4825 b'rev',
4848 [],
4826 [],
4849 _(b'a changeset intended to be included in the destination'),
4827 _(b'a changeset intended to be included in the destination'),
4850 _(b'REV'),
4828 _(b'REV'),
4851 ),
4829 ),
4852 (b'n', b'newest-first', None, _(b'show newest record first')),
4830 (b'n', b'newest-first', None, _(b'show newest record first')),
4853 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4831 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4854 (
4832 (
4855 b'b',
4833 b'b',
4856 b'branch',
4834 b'branch',
4857 [],
4835 [],
4858 _(b'a specific branch you would like to push'),
4836 _(b'a specific branch you would like to push'),
4859 _(b'BRANCH'),
4837 _(b'BRANCH'),
4860 ),
4838 ),
4861 ]
4839 ]
4862 + logopts
4840 + logopts
4863 + remoteopts
4841 + remoteopts
4864 + subrepoopts,
4842 + subrepoopts,
4865 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4843 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4866 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4844 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4867 )
4845 )
4868 def outgoing(ui, repo, dest=None, **opts):
4846 def outgoing(ui, repo, dest=None, **opts):
4869 """show changesets not found in the destination
4847 """show changesets not found in the destination
4870
4848
4871 Show changesets not found in the specified destination repository
4849 Show changesets not found in the specified destination repository
4872 or the default push location. These are the changesets that would
4850 or the default push location. These are the changesets that would
4873 be pushed if a push was requested.
4851 be pushed if a push was requested.
4874
4852
4875 See pull for details of valid destination formats.
4853 See pull for details of valid destination formats.
4876
4854
4877 .. container:: verbose
4855 .. container:: verbose
4878
4856
4879 With -B/--bookmarks, the result of bookmark comparison between
4857 With -B/--bookmarks, the result of bookmark comparison between
4880 local and remote repositories is displayed. With -v/--verbose,
4858 local and remote repositories is displayed. With -v/--verbose,
4881 status is also displayed for each bookmark like below::
4859 status is also displayed for each bookmark like below::
4882
4860
4883 BM1 01234567890a added
4861 BM1 01234567890a added
4884 BM2 deleted
4862 BM2 deleted
4885 BM3 234567890abc advanced
4863 BM3 234567890abc advanced
4886 BM4 34567890abcd diverged
4864 BM4 34567890abcd diverged
4887 BM5 4567890abcde changed
4865 BM5 4567890abcde changed
4888
4866
4889 The action taken when pushing depends on the
4867 The action taken when pushing depends on the
4890 status of each bookmark:
4868 status of each bookmark:
4891
4869
4892 :``added``: push with ``-B`` will create it
4870 :``added``: push with ``-B`` will create it
4893 :``deleted``: push with ``-B`` will delete it
4871 :``deleted``: push with ``-B`` will delete it
4894 :``advanced``: push will update it
4872 :``advanced``: push will update it
4895 :``diverged``: push with ``-B`` will update it
4873 :``diverged``: push with ``-B`` will update it
4896 :``changed``: push with ``-B`` will update it
4874 :``changed``: push with ``-B`` will update it
4897
4875
4898 From the point of view of pushing behavior, bookmarks
4876 From the point of view of pushing behavior, bookmarks
4899 existing only in the remote repository are treated as
4877 existing only in the remote repository are treated as
4900 ``deleted``, even if it is in fact added remotely.
4878 ``deleted``, even if it is in fact added remotely.
4901
4879
4902 Returns 0 if there are outgoing changes, 1 otherwise.
4880 Returns 0 if there are outgoing changes, 1 otherwise.
4903 """
4881 """
4904 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4882 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4905 # style URLs, so don't overwrite dest.
4883 # style URLs, so don't overwrite dest.
4906 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4884 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4907 if not path:
4885 if not path:
4908 raise error.Abort(
4886 raise error.Abort(
4909 _(b'default repository not configured!'),
4887 _(b'default repository not configured!'),
4910 hint=_(b"see 'hg help config.paths'"),
4888 hint=_(b"see 'hg help config.paths'"),
4911 )
4889 )
4912
4890
4913 opts = pycompat.byteskwargs(opts)
4891 opts = pycompat.byteskwargs(opts)
4914 if opts.get(b'graph'):
4892 if opts.get(b'graph'):
4915 logcmdutil.checkunsupportedgraphflags([], opts)
4893 logcmdutil.checkunsupportedgraphflags([], opts)
4916 o, other = hg._outgoing(ui, repo, dest, opts)
4894 o, other = hg._outgoing(ui, repo, dest, opts)
4917 if not o:
4895 if not o:
4918 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4896 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4919 return
4897 return
4920
4898
4921 revdag = logcmdutil.graphrevs(repo, o, opts)
4899 revdag = logcmdutil.graphrevs(repo, o, opts)
4922 ui.pager(b'outgoing')
4900 ui.pager(b'outgoing')
4923 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4901 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4924 logcmdutil.displaygraph(
4902 logcmdutil.displaygraph(
4925 ui, repo, revdag, displayer, graphmod.asciiedges
4903 ui, repo, revdag, displayer, graphmod.asciiedges
4926 )
4904 )
4927 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4905 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4928 return 0
4906 return 0
4929
4907
4930 if opts.get(b'bookmarks'):
4908 if opts.get(b'bookmarks'):
4931 dest = path.pushloc or path.loc
4909 dest = path.pushloc or path.loc
4932 other = hg.peer(repo, opts, dest)
4910 other = hg.peer(repo, opts, dest)
4933 if b'bookmarks' not in other.listkeys(b'namespaces'):
4911 if b'bookmarks' not in other.listkeys(b'namespaces'):
4934 ui.warn(_(b"remote doesn't support bookmarks\n"))
4912 ui.warn(_(b"remote doesn't support bookmarks\n"))
4935 return 0
4913 return 0
4936 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4914 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4937 ui.pager(b'outgoing')
4915 ui.pager(b'outgoing')
4938 return bookmarks.outgoing(ui, repo, other)
4916 return bookmarks.outgoing(ui, repo, other)
4939
4917
4940 repo._subtoppath = path.pushloc or path.loc
4918 repo._subtoppath = path.pushloc or path.loc
4941 try:
4919 try:
4942 return hg.outgoing(ui, repo, dest, opts)
4920 return hg.outgoing(ui, repo, dest, opts)
4943 finally:
4921 finally:
4944 del repo._subtoppath
4922 del repo._subtoppath
4945
4923
4946
4924
4947 @command(
4925 @command(
4948 b'parents',
4926 b'parents',
4949 [
4927 [
4950 (
4928 (
4951 b'r',
4929 b'r',
4952 b'rev',
4930 b'rev',
4953 b'',
4931 b'',
4954 _(b'show parents of the specified revision'),
4932 _(b'show parents of the specified revision'),
4955 _(b'REV'),
4933 _(b'REV'),
4956 ),
4934 ),
4957 ]
4935 ]
4958 + templateopts,
4936 + templateopts,
4959 _(b'[-r REV] [FILE]'),
4937 _(b'[-r REV] [FILE]'),
4960 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4938 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4961 inferrepo=True,
4939 inferrepo=True,
4962 )
4940 )
4963 def parents(ui, repo, file_=None, **opts):
4941 def parents(ui, repo, file_=None, **opts):
4964 """show the parents of the working directory or revision (DEPRECATED)
4942 """show the parents of the working directory or revision (DEPRECATED)
4965
4943
4966 Print the working directory's parent revisions. If a revision is
4944 Print the working directory's parent revisions. If a revision is
4967 given via -r/--rev, the parent of that revision will be printed.
4945 given via -r/--rev, the parent of that revision will be printed.
4968 If a file argument is given, the revision in which the file was
4946 If a file argument is given, the revision in which the file was
4969 last changed (before the working directory revision or the
4947 last changed (before the working directory revision or the
4970 argument to --rev if given) is printed.
4948 argument to --rev if given) is printed.
4971
4949
4972 This command is equivalent to::
4950 This command is equivalent to::
4973
4951
4974 hg log -r "p1()+p2()" or
4952 hg log -r "p1()+p2()" or
4975 hg log -r "p1(REV)+p2(REV)" or
4953 hg log -r "p1(REV)+p2(REV)" or
4976 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4954 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4977 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4955 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4978
4956
4979 See :hg:`summary` and :hg:`help revsets` for related information.
4957 See :hg:`summary` and :hg:`help revsets` for related information.
4980
4958
4981 Returns 0 on success.
4959 Returns 0 on success.
4982 """
4960 """
4983
4961
4984 opts = pycompat.byteskwargs(opts)
4962 opts = pycompat.byteskwargs(opts)
4985 rev = opts.get(b'rev')
4963 rev = opts.get(b'rev')
4986 if rev:
4964 if rev:
4987 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4965 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4988 ctx = scmutil.revsingle(repo, rev, None)
4966 ctx = scmutil.revsingle(repo, rev, None)
4989
4967
4990 if file_:
4968 if file_:
4991 m = scmutil.match(ctx, (file_,), opts)
4969 m = scmutil.match(ctx, (file_,), opts)
4992 if m.anypats() or len(m.files()) != 1:
4970 if m.anypats() or len(m.files()) != 1:
4993 raise error.Abort(_(b'can only specify an explicit filename'))
4971 raise error.Abort(_(b'can only specify an explicit filename'))
4994 file_ = m.files()[0]
4972 file_ = m.files()[0]
4995 filenodes = []
4973 filenodes = []
4996 for cp in ctx.parents():
4974 for cp in ctx.parents():
4997 if not cp:
4975 if not cp:
4998 continue
4976 continue
4999 try:
4977 try:
5000 filenodes.append(cp.filenode(file_))
4978 filenodes.append(cp.filenode(file_))
5001 except error.LookupError:
4979 except error.LookupError:
5002 pass
4980 pass
5003 if not filenodes:
4981 if not filenodes:
5004 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
4982 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5005 p = []
4983 p = []
5006 for fn in filenodes:
4984 for fn in filenodes:
5007 fctx = repo.filectx(file_, fileid=fn)
4985 fctx = repo.filectx(file_, fileid=fn)
5008 p.append(fctx.node())
4986 p.append(fctx.node())
5009 else:
4987 else:
5010 p = [cp.node() for cp in ctx.parents()]
4988 p = [cp.node() for cp in ctx.parents()]
5011
4989
5012 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4990 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5013 for n in p:
4991 for n in p:
5014 if n != nullid:
4992 if n != nullid:
5015 displayer.show(repo[n])
4993 displayer.show(repo[n])
5016 displayer.close()
4994 displayer.close()
5017
4995
5018
4996
5019 @command(
4997 @command(
5020 b'paths',
4998 b'paths',
5021 formatteropts,
4999 formatteropts,
5022 _(b'[NAME]'),
5000 _(b'[NAME]'),
5023 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5001 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5024 optionalrepo=True,
5002 optionalrepo=True,
5025 intents={INTENT_READONLY},
5003 intents={INTENT_READONLY},
5026 )
5004 )
5027 def paths(ui, repo, search=None, **opts):
5005 def paths(ui, repo, search=None, **opts):
5028 """show aliases for remote repositories
5006 """show aliases for remote repositories
5029
5007
5030 Show definition of symbolic path name NAME. If no name is given,
5008 Show definition of symbolic path name NAME. If no name is given,
5031 show definition of all available names.
5009 show definition of all available names.
5032
5010
5033 Option -q/--quiet suppresses all output when searching for NAME
5011 Option -q/--quiet suppresses all output when searching for NAME
5034 and shows only the path names when listing all definitions.
5012 and shows only the path names when listing all definitions.
5035
5013
5036 Path names are defined in the [paths] section of your
5014 Path names are defined in the [paths] section of your
5037 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5015 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5038 repository, ``.hg/hgrc`` is used, too.
5016 repository, ``.hg/hgrc`` is used, too.
5039
5017
5040 The path names ``default`` and ``default-push`` have a special
5018 The path names ``default`` and ``default-push`` have a special
5041 meaning. When performing a push or pull operation, they are used
5019 meaning. When performing a push or pull operation, they are used
5042 as fallbacks if no location is specified on the command-line.
5020 as fallbacks if no location is specified on the command-line.
5043 When ``default-push`` is set, it will be used for push and
5021 When ``default-push`` is set, it will be used for push and
5044 ``default`` will be used for pull; otherwise ``default`` is used
5022 ``default`` will be used for pull; otherwise ``default`` is used
5045 as the fallback for both. When cloning a repository, the clone
5023 as the fallback for both. When cloning a repository, the clone
5046 source is written as ``default`` in ``.hg/hgrc``.
5024 source is written as ``default`` in ``.hg/hgrc``.
5047
5025
5048 .. note::
5026 .. note::
5049
5027
5050 ``default`` and ``default-push`` apply to all inbound (e.g.
5028 ``default`` and ``default-push`` apply to all inbound (e.g.
5051 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5029 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5052 and :hg:`bundle`) operations.
5030 and :hg:`bundle`) operations.
5053
5031
5054 See :hg:`help urls` for more information.
5032 See :hg:`help urls` for more information.
5055
5033
5056 .. container:: verbose
5034 .. container:: verbose
5057
5035
5058 Template:
5036 Template:
5059
5037
5060 The following keywords are supported. See also :hg:`help templates`.
5038 The following keywords are supported. See also :hg:`help templates`.
5061
5039
5062 :name: String. Symbolic name of the path alias.
5040 :name: String. Symbolic name of the path alias.
5063 :pushurl: String. URL for push operations.
5041 :pushurl: String. URL for push operations.
5064 :url: String. URL or directory path for the other operations.
5042 :url: String. URL or directory path for the other operations.
5065
5043
5066 Returns 0 on success.
5044 Returns 0 on success.
5067 """
5045 """
5068
5046
5069 opts = pycompat.byteskwargs(opts)
5047 opts = pycompat.byteskwargs(opts)
5070 ui.pager(b'paths')
5048 ui.pager(b'paths')
5071 if search:
5049 if search:
5072 pathitems = [
5050 pathitems = [
5073 (name, path)
5051 (name, path)
5074 for name, path in pycompat.iteritems(ui.paths)
5052 for name, path in pycompat.iteritems(ui.paths)
5075 if name == search
5053 if name == search
5076 ]
5054 ]
5077 else:
5055 else:
5078 pathitems = sorted(pycompat.iteritems(ui.paths))
5056 pathitems = sorted(pycompat.iteritems(ui.paths))
5079
5057
5080 fm = ui.formatter(b'paths', opts)
5058 fm = ui.formatter(b'paths', opts)
5081 if fm.isplain():
5059 if fm.isplain():
5082 hidepassword = util.hidepassword
5060 hidepassword = util.hidepassword
5083 else:
5061 else:
5084 hidepassword = bytes
5062 hidepassword = bytes
5085 if ui.quiet:
5063 if ui.quiet:
5086 namefmt = b'%s\n'
5064 namefmt = b'%s\n'
5087 else:
5065 else:
5088 namefmt = b'%s = '
5066 namefmt = b'%s = '
5089 showsubopts = not search and not ui.quiet
5067 showsubopts = not search and not ui.quiet
5090
5068
5091 for name, path in pathitems:
5069 for name, path in pathitems:
5092 fm.startitem()
5070 fm.startitem()
5093 fm.condwrite(not search, b'name', namefmt, name)
5071 fm.condwrite(not search, b'name', namefmt, name)
5094 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5072 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5095 for subopt, value in sorted(path.suboptions.items()):
5073 for subopt, value in sorted(path.suboptions.items()):
5096 assert subopt not in (b'name', b'url')
5074 assert subopt not in (b'name', b'url')
5097 if showsubopts:
5075 if showsubopts:
5098 fm.plain(b'%s:%s = ' % (name, subopt))
5076 fm.plain(b'%s:%s = ' % (name, subopt))
5099 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5077 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5100
5078
5101 fm.end()
5079 fm.end()
5102
5080
5103 if search and not pathitems:
5081 if search and not pathitems:
5104 if not ui.quiet:
5082 if not ui.quiet:
5105 ui.warn(_(b"not found!\n"))
5083 ui.warn(_(b"not found!\n"))
5106 return 1
5084 return 1
5107 else:
5085 else:
5108 return 0
5086 return 0
5109
5087
5110
5088
5111 @command(
5089 @command(
5112 b'phase',
5090 b'phase',
5113 [
5091 [
5114 (b'p', b'public', False, _(b'set changeset phase to public')),
5092 (b'p', b'public', False, _(b'set changeset phase to public')),
5115 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5093 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5116 (b's', b'secret', False, _(b'set changeset phase to secret')),
5094 (b's', b'secret', False, _(b'set changeset phase to secret')),
5117 (b'f', b'force', False, _(b'allow to move boundary backward')),
5095 (b'f', b'force', False, _(b'allow to move boundary backward')),
5118 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5096 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5119 ],
5097 ],
5120 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5098 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5121 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5099 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5122 )
5100 )
5123 def phase(ui, repo, *revs, **opts):
5101 def phase(ui, repo, *revs, **opts):
5124 """set or show the current phase name
5102 """set or show the current phase name
5125
5103
5126 With no argument, show the phase name of the current revision(s).
5104 With no argument, show the phase name of the current revision(s).
5127
5105
5128 With one of -p/--public, -d/--draft or -s/--secret, change the
5106 With one of -p/--public, -d/--draft or -s/--secret, change the
5129 phase value of the specified revisions.
5107 phase value of the specified revisions.
5130
5108
5131 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5109 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5132 lower phase to a higher phase. Phases are ordered as follows::
5110 lower phase to a higher phase. Phases are ordered as follows::
5133
5111
5134 public < draft < secret
5112 public < draft < secret
5135
5113
5136 Returns 0 on success, 1 if some phases could not be changed.
5114 Returns 0 on success, 1 if some phases could not be changed.
5137
5115
5138 (For more information about the phases concept, see :hg:`help phases`.)
5116 (For more information about the phases concept, see :hg:`help phases`.)
5139 """
5117 """
5140 opts = pycompat.byteskwargs(opts)
5118 opts = pycompat.byteskwargs(opts)
5141 # search for a unique phase argument
5119 # search for a unique phase argument
5142 targetphase = None
5120 targetphase = None
5143 for idx, name in enumerate(phases.cmdphasenames):
5121 for idx, name in enumerate(phases.cmdphasenames):
5144 if opts[name]:
5122 if opts[name]:
5145 if targetphase is not None:
5123 if targetphase is not None:
5146 raise error.Abort(_(b'only one phase can be specified'))
5124 raise error.Abort(_(b'only one phase can be specified'))
5147 targetphase = idx
5125 targetphase = idx
5148
5126
5149 # look for specified revision
5127 # look for specified revision
5150 revs = list(revs)
5128 revs = list(revs)
5151 revs.extend(opts[b'rev'])
5129 revs.extend(opts[b'rev'])
5152 if not revs:
5130 if not revs:
5153 # display both parents as the second parent phase can influence
5131 # display both parents as the second parent phase can influence
5154 # the phase of a merge commit
5132 # the phase of a merge commit
5155 revs = [c.rev() for c in repo[None].parents()]
5133 revs = [c.rev() for c in repo[None].parents()]
5156
5134
5157 revs = scmutil.revrange(repo, revs)
5135 revs = scmutil.revrange(repo, revs)
5158
5136
5159 ret = 0
5137 ret = 0
5160 if targetphase is None:
5138 if targetphase is None:
5161 # display
5139 # display
5162 for r in revs:
5140 for r in revs:
5163 ctx = repo[r]
5141 ctx = repo[r]
5164 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5142 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5165 else:
5143 else:
5166 with repo.lock(), repo.transaction(b"phase") as tr:
5144 with repo.lock(), repo.transaction(b"phase") as tr:
5167 # set phase
5145 # set phase
5168 if not revs:
5146 if not revs:
5169 raise error.Abort(_(b'empty revision set'))
5147 raise error.Abort(_(b'empty revision set'))
5170 nodes = [repo[r].node() for r in revs]
5148 nodes = [repo[r].node() for r in revs]
5171 # moving revision from public to draft may hide them
5149 # moving revision from public to draft may hide them
5172 # We have to check result on an unfiltered repository
5150 # We have to check result on an unfiltered repository
5173 unfi = repo.unfiltered()
5151 unfi = repo.unfiltered()
5174 getphase = unfi._phasecache.phase
5152 getphase = unfi._phasecache.phase
5175 olddata = [getphase(unfi, r) for r in unfi]
5153 olddata = [getphase(unfi, r) for r in unfi]
5176 phases.advanceboundary(repo, tr, targetphase, nodes)
5154 phases.advanceboundary(repo, tr, targetphase, nodes)
5177 if opts[b'force']:
5155 if opts[b'force']:
5178 phases.retractboundary(repo, tr, targetphase, nodes)
5156 phases.retractboundary(repo, tr, targetphase, nodes)
5179 getphase = unfi._phasecache.phase
5157 getphase = unfi._phasecache.phase
5180 newdata = [getphase(unfi, r) for r in unfi]
5158 newdata = [getphase(unfi, r) for r in unfi]
5181 changes = sum(newdata[r] != olddata[r] for r in unfi)
5159 changes = sum(newdata[r] != olddata[r] for r in unfi)
5182 cl = unfi.changelog
5160 cl = unfi.changelog
5183 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5161 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5184 if rejected:
5162 if rejected:
5185 ui.warn(
5163 ui.warn(
5186 _(
5164 _(
5187 b'cannot move %i changesets to a higher '
5165 b'cannot move %i changesets to a higher '
5188 b'phase, use --force\n'
5166 b'phase, use --force\n'
5189 )
5167 )
5190 % len(rejected)
5168 % len(rejected)
5191 )
5169 )
5192 ret = 1
5170 ret = 1
5193 if changes:
5171 if changes:
5194 msg = _(b'phase changed for %i changesets\n') % changes
5172 msg = _(b'phase changed for %i changesets\n') % changes
5195 if ret:
5173 if ret:
5196 ui.status(msg)
5174 ui.status(msg)
5197 else:
5175 else:
5198 ui.note(msg)
5176 ui.note(msg)
5199 else:
5177 else:
5200 ui.warn(_(b'no phases changed\n'))
5178 ui.warn(_(b'no phases changed\n'))
5201 return ret
5179 return ret
5202
5180
5203
5181
5204 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5182 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5205 """Run after a changegroup has been added via pull/unbundle
5183 """Run after a changegroup has been added via pull/unbundle
5206
5184
5207 This takes arguments below:
5185 This takes arguments below:
5208
5186
5209 :modheads: change of heads by pull/unbundle
5187 :modheads: change of heads by pull/unbundle
5210 :optupdate: updating working directory is needed or not
5188 :optupdate: updating working directory is needed or not
5211 :checkout: update destination revision (or None to default destination)
5189 :checkout: update destination revision (or None to default destination)
5212 :brev: a name, which might be a bookmark to be activated after updating
5190 :brev: a name, which might be a bookmark to be activated after updating
5213 """
5191 """
5214 if modheads == 0:
5192 if modheads == 0:
5215 return
5193 return
5216 if optupdate:
5194 if optupdate:
5217 try:
5195 try:
5218 return hg.updatetotally(ui, repo, checkout, brev)
5196 return hg.updatetotally(ui, repo, checkout, brev)
5219 except error.UpdateAbort as inst:
5197 except error.UpdateAbort as inst:
5220 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5198 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5221 hint = inst.hint
5199 hint = inst.hint
5222 raise error.UpdateAbort(msg, hint=hint)
5200 raise error.UpdateAbort(msg, hint=hint)
5223 if modheads is not None and modheads > 1:
5201 if modheads is not None and modheads > 1:
5224 currentbranchheads = len(repo.branchheads())
5202 currentbranchheads = len(repo.branchheads())
5225 if currentbranchheads == modheads:
5203 if currentbranchheads == modheads:
5226 ui.status(
5204 ui.status(
5227 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5205 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5228 )
5206 )
5229 elif currentbranchheads > 1:
5207 elif currentbranchheads > 1:
5230 ui.status(
5208 ui.status(
5231 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5209 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5232 )
5210 )
5233 else:
5211 else:
5234 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5212 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5235 elif not ui.configbool(b'commands', b'update.requiredest'):
5213 elif not ui.configbool(b'commands', b'update.requiredest'):
5236 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5214 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5237
5215
5238
5216
5239 @command(
5217 @command(
5240 b'pull',
5218 b'pull',
5241 [
5219 [
5242 (
5220 (
5243 b'u',
5221 b'u',
5244 b'update',
5222 b'update',
5245 None,
5223 None,
5246 _(b'update to new branch head if new descendants were pulled'),
5224 _(b'update to new branch head if new descendants were pulled'),
5247 ),
5225 ),
5248 (
5226 (
5249 b'f',
5227 b'f',
5250 b'force',
5228 b'force',
5251 None,
5229 None,
5252 _(b'run even when remote repository is unrelated'),
5230 _(b'run even when remote repository is unrelated'),
5253 ),
5231 ),
5254 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5232 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5255 (
5233 (
5256 b'r',
5234 b'r',
5257 b'rev',
5235 b'rev',
5258 [],
5236 [],
5259 _(b'a remote changeset intended to be added'),
5237 _(b'a remote changeset intended to be added'),
5260 _(b'REV'),
5238 _(b'REV'),
5261 ),
5239 ),
5262 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5240 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5263 (
5241 (
5264 b'b',
5242 b'b',
5265 b'branch',
5243 b'branch',
5266 [],
5244 [],
5267 _(b'a specific branch you would like to pull'),
5245 _(b'a specific branch you would like to pull'),
5268 _(b'BRANCH'),
5246 _(b'BRANCH'),
5269 ),
5247 ),
5270 ]
5248 ]
5271 + remoteopts,
5249 + remoteopts,
5272 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5250 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5273 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5251 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5274 helpbasic=True,
5252 helpbasic=True,
5275 )
5253 )
5276 def pull(ui, repo, source=b"default", **opts):
5254 def pull(ui, repo, source=b"default", **opts):
5277 """pull changes from the specified source
5255 """pull changes from the specified source
5278
5256
5279 Pull changes from a remote repository to a local one.
5257 Pull changes from a remote repository to a local one.
5280
5258
5281 This finds all changes from the repository at the specified path
5259 This finds all changes from the repository at the specified path
5282 or URL and adds them to a local repository (the current one unless
5260 or URL and adds them to a local repository (the current one unless
5283 -R is specified). By default, this does not update the copy of the
5261 -R is specified). By default, this does not update the copy of the
5284 project in the working directory.
5262 project in the working directory.
5285
5263
5286 When cloning from servers that support it, Mercurial may fetch
5264 When cloning from servers that support it, Mercurial may fetch
5287 pre-generated data. When this is done, hooks operating on incoming
5265 pre-generated data. When this is done, hooks operating on incoming
5288 changesets and changegroups may fire more than once, once for each
5266 changesets and changegroups may fire more than once, once for each
5289 pre-generated bundle and as well as for any additional remaining
5267 pre-generated bundle and as well as for any additional remaining
5290 data. See :hg:`help -e clonebundles` for more.
5268 data. See :hg:`help -e clonebundles` for more.
5291
5269
5292 Use :hg:`incoming` if you want to see what would have been added
5270 Use :hg:`incoming` if you want to see what would have been added
5293 by a pull at the time you issued this command. If you then decide
5271 by a pull at the time you issued this command. If you then decide
5294 to add those changes to the repository, you should use :hg:`pull
5272 to add those changes to the repository, you should use :hg:`pull
5295 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5273 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5296
5274
5297 If SOURCE is omitted, the 'default' path will be used.
5275 If SOURCE is omitted, the 'default' path will be used.
5298 See :hg:`help urls` for more information.
5276 See :hg:`help urls` for more information.
5299
5277
5300 Specifying bookmark as ``.`` is equivalent to specifying the active
5278 Specifying bookmark as ``.`` is equivalent to specifying the active
5301 bookmark's name.
5279 bookmark's name.
5302
5280
5303 Returns 0 on success, 1 if an update had unresolved files.
5281 Returns 0 on success, 1 if an update had unresolved files.
5304 """
5282 """
5305
5283
5306 opts = pycompat.byteskwargs(opts)
5284 opts = pycompat.byteskwargs(opts)
5307 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5285 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5308 b'update'
5286 b'update'
5309 ):
5287 ):
5310 msg = _(b'update destination required by configuration')
5288 msg = _(b'update destination required by configuration')
5311 hint = _(b'use hg pull followed by hg update DEST')
5289 hint = _(b'use hg pull followed by hg update DEST')
5312 raise error.Abort(msg, hint=hint)
5290 raise error.Abort(msg, hint=hint)
5313
5291
5314 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5292 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5315 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5293 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5316 other = hg.peer(repo, opts, source)
5294 other = hg.peer(repo, opts, source)
5317 try:
5295 try:
5318 revs, checkout = hg.addbranchrevs(
5296 revs, checkout = hg.addbranchrevs(
5319 repo, other, branches, opts.get(b'rev')
5297 repo, other, branches, opts.get(b'rev')
5320 )
5298 )
5321
5299
5322 pullopargs = {}
5300 pullopargs = {}
5323
5301
5324 nodes = None
5302 nodes = None
5325 if opts.get(b'bookmark') or revs:
5303 if opts.get(b'bookmark') or revs:
5326 # The list of bookmark used here is the same used to actually update
5304 # The list of bookmark used here is the same used to actually update
5327 # the bookmark names, to avoid the race from issue 4689 and we do
5305 # the bookmark names, to avoid the race from issue 4689 and we do
5328 # all lookup and bookmark queries in one go so they see the same
5306 # all lookup and bookmark queries in one go so they see the same
5329 # version of the server state (issue 4700).
5307 # version of the server state (issue 4700).
5330 nodes = []
5308 nodes = []
5331 fnodes = []
5309 fnodes = []
5332 revs = revs or []
5310 revs = revs or []
5333 if revs and not other.capable(b'lookup'):
5311 if revs and not other.capable(b'lookup'):
5334 err = _(
5312 err = _(
5335 b"other repository doesn't support revision lookup, "
5313 b"other repository doesn't support revision lookup, "
5336 b"so a rev cannot be specified."
5314 b"so a rev cannot be specified."
5337 )
5315 )
5338 raise error.Abort(err)
5316 raise error.Abort(err)
5339 with other.commandexecutor() as e:
5317 with other.commandexecutor() as e:
5340 fremotebookmarks = e.callcommand(
5318 fremotebookmarks = e.callcommand(
5341 b'listkeys', {b'namespace': b'bookmarks'}
5319 b'listkeys', {b'namespace': b'bookmarks'}
5342 )
5320 )
5343 for r in revs:
5321 for r in revs:
5344 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5322 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5345 remotebookmarks = fremotebookmarks.result()
5323 remotebookmarks = fremotebookmarks.result()
5346 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5324 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5347 pullopargs[b'remotebookmarks'] = remotebookmarks
5325 pullopargs[b'remotebookmarks'] = remotebookmarks
5348 for b in opts.get(b'bookmark', []):
5326 for b in opts.get(b'bookmark', []):
5349 b = repo._bookmarks.expandname(b)
5327 b = repo._bookmarks.expandname(b)
5350 if b not in remotebookmarks:
5328 if b not in remotebookmarks:
5351 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5329 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5352 nodes.append(remotebookmarks[b])
5330 nodes.append(remotebookmarks[b])
5353 for i, rev in enumerate(revs):
5331 for i, rev in enumerate(revs):
5354 node = fnodes[i].result()
5332 node = fnodes[i].result()
5355 nodes.append(node)
5333 nodes.append(node)
5356 if rev == checkout:
5334 if rev == checkout:
5357 checkout = node
5335 checkout = node
5358
5336
5359 wlock = util.nullcontextmanager()
5337 wlock = util.nullcontextmanager()
5360 if opts.get(b'update'):
5338 if opts.get(b'update'):
5361 wlock = repo.wlock()
5339 wlock = repo.wlock()
5362 with wlock:
5340 with wlock:
5363 pullopargs.update(opts.get(b'opargs', {}))
5341 pullopargs.update(opts.get(b'opargs', {}))
5364 modheads = exchange.pull(
5342 modheads = exchange.pull(
5365 repo,
5343 repo,
5366 other,
5344 other,
5367 heads=nodes,
5345 heads=nodes,
5368 force=opts.get(b'force'),
5346 force=opts.get(b'force'),
5369 bookmarks=opts.get(b'bookmark', ()),
5347 bookmarks=opts.get(b'bookmark', ()),
5370 opargs=pullopargs,
5348 opargs=pullopargs,
5371 confirm=opts.get(b'confirm'),
5349 confirm=opts.get(b'confirm'),
5372 ).cgresult
5350 ).cgresult
5373
5351
5374 # brev is a name, which might be a bookmark to be activated at
5352 # brev is a name, which might be a bookmark to be activated at
5375 # the end of the update. In other words, it is an explicit
5353 # the end of the update. In other words, it is an explicit
5376 # destination of the update
5354 # destination of the update
5377 brev = None
5355 brev = None
5378
5356
5379 if checkout:
5357 if checkout:
5380 checkout = repo.unfiltered().changelog.rev(checkout)
5358 checkout = repo.unfiltered().changelog.rev(checkout)
5381
5359
5382 # order below depends on implementation of
5360 # order below depends on implementation of
5383 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5361 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5384 # because 'checkout' is determined without it.
5362 # because 'checkout' is determined without it.
5385 if opts.get(b'rev'):
5363 if opts.get(b'rev'):
5386 brev = opts[b'rev'][0]
5364 brev = opts[b'rev'][0]
5387 elif opts.get(b'branch'):
5365 elif opts.get(b'branch'):
5388 brev = opts[b'branch'][0]
5366 brev = opts[b'branch'][0]
5389 else:
5367 else:
5390 brev = branches[0]
5368 brev = branches[0]
5391 repo._subtoppath = source
5369 repo._subtoppath = source
5392 try:
5370 try:
5393 ret = postincoming(
5371 ret = postincoming(
5394 ui, repo, modheads, opts.get(b'update'), checkout, brev
5372 ui, repo, modheads, opts.get(b'update'), checkout, brev
5395 )
5373 )
5396 except error.FilteredRepoLookupError as exc:
5374 except error.FilteredRepoLookupError as exc:
5397 msg = _(b'cannot update to target: %s') % exc.args[0]
5375 msg = _(b'cannot update to target: %s') % exc.args[0]
5398 exc.args = (msg,) + exc.args[1:]
5376 exc.args = (msg,) + exc.args[1:]
5399 raise
5377 raise
5400 finally:
5378 finally:
5401 del repo._subtoppath
5379 del repo._subtoppath
5402
5380
5403 finally:
5381 finally:
5404 other.close()
5382 other.close()
5405 return ret
5383 return ret
5406
5384
5407
5385
5408 @command(
5386 @command(
5409 b'push',
5387 b'push',
5410 [
5388 [
5411 (b'f', b'force', None, _(b'force push')),
5389 (b'f', b'force', None, _(b'force push')),
5412 (
5390 (
5413 b'r',
5391 b'r',
5414 b'rev',
5392 b'rev',
5415 [],
5393 [],
5416 _(b'a changeset intended to be included in the destination'),
5394 _(b'a changeset intended to be included in the destination'),
5417 _(b'REV'),
5395 _(b'REV'),
5418 ),
5396 ),
5419 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5397 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5420 (
5398 (
5421 b'b',
5399 b'b',
5422 b'branch',
5400 b'branch',
5423 [],
5401 [],
5424 _(b'a specific branch you would like to push'),
5402 _(b'a specific branch you would like to push'),
5425 _(b'BRANCH'),
5403 _(b'BRANCH'),
5426 ),
5404 ),
5427 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5405 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5428 (
5406 (
5429 b'',
5407 b'',
5430 b'pushvars',
5408 b'pushvars',
5431 [],
5409 [],
5432 _(b'variables that can be sent to server (ADVANCED)'),
5410 _(b'variables that can be sent to server (ADVANCED)'),
5433 ),
5411 ),
5434 (
5412 (
5435 b'',
5413 b'',
5436 b'publish',
5414 b'publish',
5437 False,
5415 False,
5438 _(b'push the changeset as public (EXPERIMENTAL)'),
5416 _(b'push the changeset as public (EXPERIMENTAL)'),
5439 ),
5417 ),
5440 ]
5418 ]
5441 + remoteopts,
5419 + remoteopts,
5442 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5420 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5443 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5421 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5444 helpbasic=True,
5422 helpbasic=True,
5445 )
5423 )
5446 def push(ui, repo, dest=None, **opts):
5424 def push(ui, repo, dest=None, **opts):
5447 """push changes to the specified destination
5425 """push changes to the specified destination
5448
5426
5449 Push changesets from the local repository to the specified
5427 Push changesets from the local repository to the specified
5450 destination.
5428 destination.
5451
5429
5452 This operation is symmetrical to pull: it is identical to a pull
5430 This operation is symmetrical to pull: it is identical to a pull
5453 in the destination repository from the current one.
5431 in the destination repository from the current one.
5454
5432
5455 By default, push will not allow creation of new heads at the
5433 By default, push will not allow creation of new heads at the
5456 destination, since multiple heads would make it unclear which head
5434 destination, since multiple heads would make it unclear which head
5457 to use. In this situation, it is recommended to pull and merge
5435 to use. In this situation, it is recommended to pull and merge
5458 before pushing.
5436 before pushing.
5459
5437
5460 Use --new-branch if you want to allow push to create a new named
5438 Use --new-branch if you want to allow push to create a new named
5461 branch that is not present at the destination. This allows you to
5439 branch that is not present at the destination. This allows you to
5462 only create a new branch without forcing other changes.
5440 only create a new branch without forcing other changes.
5463
5441
5464 .. note::
5442 .. note::
5465
5443
5466 Extra care should be taken with the -f/--force option,
5444 Extra care should be taken with the -f/--force option,
5467 which will push all new heads on all branches, an action which will
5445 which will push all new heads on all branches, an action which will
5468 almost always cause confusion for collaborators.
5446 almost always cause confusion for collaborators.
5469
5447
5470 If -r/--rev is used, the specified revision and all its ancestors
5448 If -r/--rev is used, the specified revision and all its ancestors
5471 will be pushed to the remote repository.
5449 will be pushed to the remote repository.
5472
5450
5473 If -B/--bookmark is used, the specified bookmarked revision, its
5451 If -B/--bookmark is used, the specified bookmarked revision, its
5474 ancestors, and the bookmark will be pushed to the remote
5452 ancestors, and the bookmark will be pushed to the remote
5475 repository. Specifying ``.`` is equivalent to specifying the active
5453 repository. Specifying ``.`` is equivalent to specifying the active
5476 bookmark's name.
5454 bookmark's name.
5477
5455
5478 Please see :hg:`help urls` for important details about ``ssh://``
5456 Please see :hg:`help urls` for important details about ``ssh://``
5479 URLs. If DESTINATION is omitted, a default path will be used.
5457 URLs. If DESTINATION is omitted, a default path will be used.
5480
5458
5481 .. container:: verbose
5459 .. container:: verbose
5482
5460
5483 The --pushvars option sends strings to the server that become
5461 The --pushvars option sends strings to the server that become
5484 environment variables prepended with ``HG_USERVAR_``. For example,
5462 environment variables prepended with ``HG_USERVAR_``. For example,
5485 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5463 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5486 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5464 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5487
5465
5488 pushvars can provide for user-overridable hooks as well as set debug
5466 pushvars can provide for user-overridable hooks as well as set debug
5489 levels. One example is having a hook that blocks commits containing
5467 levels. One example is having a hook that blocks commits containing
5490 conflict markers, but enables the user to override the hook if the file
5468 conflict markers, but enables the user to override the hook if the file
5491 is using conflict markers for testing purposes or the file format has
5469 is using conflict markers for testing purposes or the file format has
5492 strings that look like conflict markers.
5470 strings that look like conflict markers.
5493
5471
5494 By default, servers will ignore `--pushvars`. To enable it add the
5472 By default, servers will ignore `--pushvars`. To enable it add the
5495 following to your configuration file::
5473 following to your configuration file::
5496
5474
5497 [push]
5475 [push]
5498 pushvars.server = true
5476 pushvars.server = true
5499
5477
5500 Returns 0 if push was successful, 1 if nothing to push.
5478 Returns 0 if push was successful, 1 if nothing to push.
5501 """
5479 """
5502
5480
5503 opts = pycompat.byteskwargs(opts)
5481 opts = pycompat.byteskwargs(opts)
5504 if opts.get(b'bookmark'):
5482 if opts.get(b'bookmark'):
5505 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5483 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5506 for b in opts[b'bookmark']:
5484 for b in opts[b'bookmark']:
5507 # translate -B options to -r so changesets get pushed
5485 # translate -B options to -r so changesets get pushed
5508 b = repo._bookmarks.expandname(b)
5486 b = repo._bookmarks.expandname(b)
5509 if b in repo._bookmarks:
5487 if b in repo._bookmarks:
5510 opts.setdefault(b'rev', []).append(b)
5488 opts.setdefault(b'rev', []).append(b)
5511 else:
5489 else:
5512 # if we try to push a deleted bookmark, translate it to null
5490 # if we try to push a deleted bookmark, translate it to null
5513 # this lets simultaneous -r, -b options continue working
5491 # this lets simultaneous -r, -b options continue working
5514 opts.setdefault(b'rev', []).append(b"null")
5492 opts.setdefault(b'rev', []).append(b"null")
5515
5493
5516 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5494 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5517 if not path:
5495 if not path:
5518 raise error.Abort(
5496 raise error.Abort(
5519 _(b'default repository not configured!'),
5497 _(b'default repository not configured!'),
5520 hint=_(b"see 'hg help config.paths'"),
5498 hint=_(b"see 'hg help config.paths'"),
5521 )
5499 )
5522 dest = path.pushloc or path.loc
5500 dest = path.pushloc or path.loc
5523 branches = (path.branch, opts.get(b'branch') or [])
5501 branches = (path.branch, opts.get(b'branch') or [])
5524 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5502 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5525 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5503 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5526 other = hg.peer(repo, opts, dest)
5504 other = hg.peer(repo, opts, dest)
5527
5505
5528 if revs:
5506 if revs:
5529 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5507 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5530 if not revs:
5508 if not revs:
5531 raise error.Abort(
5509 raise error.Abort(
5532 _(b"specified revisions evaluate to an empty set"),
5510 _(b"specified revisions evaluate to an empty set"),
5533 hint=_(b"use different revision arguments"),
5511 hint=_(b"use different revision arguments"),
5534 )
5512 )
5535 elif path.pushrev:
5513 elif path.pushrev:
5536 # It doesn't make any sense to specify ancestor revisions. So limit
5514 # It doesn't make any sense to specify ancestor revisions. So limit
5537 # to DAG heads to make discovery simpler.
5515 # to DAG heads to make discovery simpler.
5538 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5516 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5539 revs = scmutil.revrange(repo, [expr])
5517 revs = scmutil.revrange(repo, [expr])
5540 revs = [repo[rev].node() for rev in revs]
5518 revs = [repo[rev].node() for rev in revs]
5541 if not revs:
5519 if not revs:
5542 raise error.Abort(
5520 raise error.Abort(
5543 _(b'default push revset for path evaluates to an empty set')
5521 _(b'default push revset for path evaluates to an empty set')
5544 )
5522 )
5545 elif ui.configbool(b'commands', b'push.require-revs'):
5523 elif ui.configbool(b'commands', b'push.require-revs'):
5546 raise error.Abort(
5524 raise error.Abort(
5547 _(b'no revisions specified to push'),
5525 _(b'no revisions specified to push'),
5548 hint=_(b'did you mean "hg push -r ."?'),
5526 hint=_(b'did you mean "hg push -r ."?'),
5549 )
5527 )
5550
5528
5551 repo._subtoppath = dest
5529 repo._subtoppath = dest
5552 try:
5530 try:
5553 # push subrepos depth-first for coherent ordering
5531 # push subrepos depth-first for coherent ordering
5554 c = repo[b'.']
5532 c = repo[b'.']
5555 subs = c.substate # only repos that are committed
5533 subs = c.substate # only repos that are committed
5556 for s in sorted(subs):
5534 for s in sorted(subs):
5557 result = c.sub(s).push(opts)
5535 result = c.sub(s).push(opts)
5558 if result == 0:
5536 if result == 0:
5559 return not result
5537 return not result
5560 finally:
5538 finally:
5561 del repo._subtoppath
5539 del repo._subtoppath
5562
5540
5563 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5541 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5564 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5542 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5565
5543
5566 pushop = exchange.push(
5544 pushop = exchange.push(
5567 repo,
5545 repo,
5568 other,
5546 other,
5569 opts.get(b'force'),
5547 opts.get(b'force'),
5570 revs=revs,
5548 revs=revs,
5571 newbranch=opts.get(b'new_branch'),
5549 newbranch=opts.get(b'new_branch'),
5572 bookmarks=opts.get(b'bookmark', ()),
5550 bookmarks=opts.get(b'bookmark', ()),
5573 publish=opts.get(b'publish'),
5551 publish=opts.get(b'publish'),
5574 opargs=opargs,
5552 opargs=opargs,
5575 )
5553 )
5576
5554
5577 result = not pushop.cgresult
5555 result = not pushop.cgresult
5578
5556
5579 if pushop.bkresult is not None:
5557 if pushop.bkresult is not None:
5580 if pushop.bkresult == 2:
5558 if pushop.bkresult == 2:
5581 result = 2
5559 result = 2
5582 elif not result and pushop.bkresult:
5560 elif not result and pushop.bkresult:
5583 result = 2
5561 result = 2
5584
5562
5585 return result
5563 return result
5586
5564
5587
5565
5588 @command(
5566 @command(
5589 b'recover',
5567 b'recover',
5590 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5568 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5591 helpcategory=command.CATEGORY_MAINTENANCE,
5569 helpcategory=command.CATEGORY_MAINTENANCE,
5592 )
5570 )
5593 def recover(ui, repo, **opts):
5571 def recover(ui, repo, **opts):
5594 """roll back an interrupted transaction
5572 """roll back an interrupted transaction
5595
5573
5596 Recover from an interrupted commit or pull.
5574 Recover from an interrupted commit or pull.
5597
5575
5598 This command tries to fix the repository status after an
5576 This command tries to fix the repository status after an
5599 interrupted operation. It should only be necessary when Mercurial
5577 interrupted operation. It should only be necessary when Mercurial
5600 suggests it.
5578 suggests it.
5601
5579
5602 Returns 0 if successful, 1 if nothing to recover or verify fails.
5580 Returns 0 if successful, 1 if nothing to recover or verify fails.
5603 """
5581 """
5604 ret = repo.recover()
5582 ret = repo.recover()
5605 if ret:
5583 if ret:
5606 if opts['verify']:
5584 if opts['verify']:
5607 return hg.verify(repo)
5585 return hg.verify(repo)
5608 else:
5586 else:
5609 msg = _(
5587 msg = _(
5610 b"(verify step skipped, run `hg verify` to check your "
5588 b"(verify step skipped, run `hg verify` to check your "
5611 b"repository content)\n"
5589 b"repository content)\n"
5612 )
5590 )
5613 ui.warn(msg)
5591 ui.warn(msg)
5614 return 0
5592 return 0
5615 return 1
5593 return 1
5616
5594
5617
5595
5618 @command(
5596 @command(
5619 b'remove|rm',
5597 b'remove|rm',
5620 [
5598 [
5621 (b'A', b'after', None, _(b'record delete for missing files')),
5599 (b'A', b'after', None, _(b'record delete for missing files')),
5622 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5600 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5623 ]
5601 ]
5624 + subrepoopts
5602 + subrepoopts
5625 + walkopts
5603 + walkopts
5626 + dryrunopts,
5604 + dryrunopts,
5627 _(b'[OPTION]... FILE...'),
5605 _(b'[OPTION]... FILE...'),
5628 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5606 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5629 helpbasic=True,
5607 helpbasic=True,
5630 inferrepo=True,
5608 inferrepo=True,
5631 )
5609 )
5632 def remove(ui, repo, *pats, **opts):
5610 def remove(ui, repo, *pats, **opts):
5633 """remove the specified files on the next commit
5611 """remove the specified files on the next commit
5634
5612
5635 Schedule the indicated files for removal from the current branch.
5613 Schedule the indicated files for removal from the current branch.
5636
5614
5637 This command schedules the files to be removed at the next commit.
5615 This command schedules the files to be removed at the next commit.
5638 To undo a remove before that, see :hg:`revert`. To undo added
5616 To undo a remove before that, see :hg:`revert`. To undo added
5639 files, see :hg:`forget`.
5617 files, see :hg:`forget`.
5640
5618
5641 .. container:: verbose
5619 .. container:: verbose
5642
5620
5643 -A/--after can be used to remove only files that have already
5621 -A/--after can be used to remove only files that have already
5644 been deleted, -f/--force can be used to force deletion, and -Af
5622 been deleted, -f/--force can be used to force deletion, and -Af
5645 can be used to remove files from the next revision without
5623 can be used to remove files from the next revision without
5646 deleting them from the working directory.
5624 deleting them from the working directory.
5647
5625
5648 The following table details the behavior of remove for different
5626 The following table details the behavior of remove for different
5649 file states (columns) and option combinations (rows). The file
5627 file states (columns) and option combinations (rows). The file
5650 states are Added [A], Clean [C], Modified [M] and Missing [!]
5628 states are Added [A], Clean [C], Modified [M] and Missing [!]
5651 (as reported by :hg:`status`). The actions are Warn, Remove
5629 (as reported by :hg:`status`). The actions are Warn, Remove
5652 (from branch) and Delete (from disk):
5630 (from branch) and Delete (from disk):
5653
5631
5654 ========= == == == ==
5632 ========= == == == ==
5655 opt/state A C M !
5633 opt/state A C M !
5656 ========= == == == ==
5634 ========= == == == ==
5657 none W RD W R
5635 none W RD W R
5658 -f R RD RD R
5636 -f R RD RD R
5659 -A W W W R
5637 -A W W W R
5660 -Af R R R R
5638 -Af R R R R
5661 ========= == == == ==
5639 ========= == == == ==
5662
5640
5663 .. note::
5641 .. note::
5664
5642
5665 :hg:`remove` never deletes files in Added [A] state from the
5643 :hg:`remove` never deletes files in Added [A] state from the
5666 working directory, not even if ``--force`` is specified.
5644 working directory, not even if ``--force`` is specified.
5667
5645
5668 Returns 0 on success, 1 if any warnings encountered.
5646 Returns 0 on success, 1 if any warnings encountered.
5669 """
5647 """
5670
5648
5671 opts = pycompat.byteskwargs(opts)
5649 opts = pycompat.byteskwargs(opts)
5672 after, force = opts.get(b'after'), opts.get(b'force')
5650 after, force = opts.get(b'after'), opts.get(b'force')
5673 dryrun = opts.get(b'dry_run')
5651 dryrun = opts.get(b'dry_run')
5674 if not pats and not after:
5652 if not pats and not after:
5675 raise error.Abort(_(b'no files specified'))
5653 raise error.Abort(_(b'no files specified'))
5676
5654
5677 m = scmutil.match(repo[None], pats, opts)
5655 m = scmutil.match(repo[None], pats, opts)
5678 subrepos = opts.get(b'subrepos')
5656 subrepos = opts.get(b'subrepos')
5679 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5657 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5680 return cmdutil.remove(
5658 return cmdutil.remove(
5681 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5659 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5682 )
5660 )
5683
5661
5684
5662
5685 @command(
5663 @command(
5686 b'rename|move|mv',
5664 b'rename|move|mv',
5687 [
5665 [
5688 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5666 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5689 (
5667 (
5690 b'',
5668 b'',
5691 b'at-rev',
5669 b'at-rev',
5692 b'',
5670 b'',
5693 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5671 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5694 _(b'REV'),
5672 _(b'REV'),
5695 ),
5673 ),
5696 (
5674 (
5697 b'f',
5675 b'f',
5698 b'force',
5676 b'force',
5699 None,
5677 None,
5700 _(b'forcibly move over an existing managed file'),
5678 _(b'forcibly move over an existing managed file'),
5701 ),
5679 ),
5702 ]
5680 ]
5703 + walkopts
5681 + walkopts
5704 + dryrunopts,
5682 + dryrunopts,
5705 _(b'[OPTION]... SOURCE... DEST'),
5683 _(b'[OPTION]... SOURCE... DEST'),
5706 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5684 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5707 )
5685 )
5708 def rename(ui, repo, *pats, **opts):
5686 def rename(ui, repo, *pats, **opts):
5709 """rename files; equivalent of copy + remove
5687 """rename files; equivalent of copy + remove
5710
5688
5711 Mark dest as copies of sources; mark sources for deletion. If dest
5689 Mark dest as copies of sources; mark sources for deletion. If dest
5712 is a directory, copies are put in that directory. If dest is a
5690 is a directory, copies are put in that directory. If dest is a
5713 file, there can only be one source.
5691 file, there can only be one source.
5714
5692
5715 By default, this command copies the contents of files as they
5693 By default, this command copies the contents of files as they
5716 exist in the working directory. If invoked with -A/--after, the
5694 exist in the working directory. If invoked with -A/--after, the
5717 operation is recorded, but no copying is performed.
5695 operation is recorded, but no copying is performed.
5718
5696
5719 This command takes effect at the next commit. To undo a rename
5697 This command takes effect at the next commit. To undo a rename
5720 before that, see :hg:`revert`.
5698 before that, see :hg:`revert`.
5721
5699
5722 Returns 0 on success, 1 if errors are encountered.
5700 Returns 0 on success, 1 if errors are encountered.
5723 """
5701 """
5724 opts = pycompat.byteskwargs(opts)
5702 opts = pycompat.byteskwargs(opts)
5725 with repo.wlock():
5703 with repo.wlock():
5726 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5704 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5727
5705
5728
5706
5729 @command(
5707 @command(
5730 b'resolve',
5708 b'resolve',
5731 [
5709 [
5732 (b'a', b'all', None, _(b'select all unresolved files')),
5710 (b'a', b'all', None, _(b'select all unresolved files')),
5733 (b'l', b'list', None, _(b'list state of files needing merge')),
5711 (b'l', b'list', None, _(b'list state of files needing merge')),
5734 (b'm', b'mark', None, _(b'mark files as resolved')),
5712 (b'm', b'mark', None, _(b'mark files as resolved')),
5735 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5713 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5736 (b'n', b'no-status', None, _(b'hide status prefix')),
5714 (b'n', b'no-status', None, _(b'hide status prefix')),
5737 (b'', b're-merge', None, _(b're-merge files')),
5715 (b'', b're-merge', None, _(b're-merge files')),
5738 ]
5716 ]
5739 + mergetoolopts
5717 + mergetoolopts
5740 + walkopts
5718 + walkopts
5741 + formatteropts,
5719 + formatteropts,
5742 _(b'[OPTION]... [FILE]...'),
5720 _(b'[OPTION]... [FILE]...'),
5743 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5721 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5744 inferrepo=True,
5722 inferrepo=True,
5745 )
5723 )
5746 def resolve(ui, repo, *pats, **opts):
5724 def resolve(ui, repo, *pats, **opts):
5747 """redo merges or set/view the merge status of files
5725 """redo merges or set/view the merge status of files
5748
5726
5749 Merges with unresolved conflicts are often the result of
5727 Merges with unresolved conflicts are often the result of
5750 non-interactive merging using the ``internal:merge`` configuration
5728 non-interactive merging using the ``internal:merge`` configuration
5751 setting, or a command-line merge tool like ``diff3``. The resolve
5729 setting, or a command-line merge tool like ``diff3``. The resolve
5752 command is used to manage the files involved in a merge, after
5730 command is used to manage the files involved in a merge, after
5753 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5731 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5754 working directory must have two parents). See :hg:`help
5732 working directory must have two parents). See :hg:`help
5755 merge-tools` for information on configuring merge tools.
5733 merge-tools` for information on configuring merge tools.
5756
5734
5757 The resolve command can be used in the following ways:
5735 The resolve command can be used in the following ways:
5758
5736
5759 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5737 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5760 the specified files, discarding any previous merge attempts. Re-merging
5738 the specified files, discarding any previous merge attempts. Re-merging
5761 is not performed for files already marked as resolved. Use ``--all/-a``
5739 is not performed for files already marked as resolved. Use ``--all/-a``
5762 to select all unresolved files. ``--tool`` can be used to specify
5740 to select all unresolved files. ``--tool`` can be used to specify
5763 the merge tool used for the given files. It overrides the HGMERGE
5741 the merge tool used for the given files. It overrides the HGMERGE
5764 environment variable and your configuration files. Previous file
5742 environment variable and your configuration files. Previous file
5765 contents are saved with a ``.orig`` suffix.
5743 contents are saved with a ``.orig`` suffix.
5766
5744
5767 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5745 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5768 (e.g. after having manually fixed-up the files). The default is
5746 (e.g. after having manually fixed-up the files). The default is
5769 to mark all unresolved files.
5747 to mark all unresolved files.
5770
5748
5771 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5749 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5772 default is to mark all resolved files.
5750 default is to mark all resolved files.
5773
5751
5774 - :hg:`resolve -l`: list files which had or still have conflicts.
5752 - :hg:`resolve -l`: list files which had or still have conflicts.
5775 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5753 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5776 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5754 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5777 the list. See :hg:`help filesets` for details.
5755 the list. See :hg:`help filesets` for details.
5778
5756
5779 .. note::
5757 .. note::
5780
5758
5781 Mercurial will not let you commit files with unresolved merge
5759 Mercurial will not let you commit files with unresolved merge
5782 conflicts. You must use :hg:`resolve -m ...` before you can
5760 conflicts. You must use :hg:`resolve -m ...` before you can
5783 commit after a conflicting merge.
5761 commit after a conflicting merge.
5784
5762
5785 .. container:: verbose
5763 .. container:: verbose
5786
5764
5787 Template:
5765 Template:
5788
5766
5789 The following keywords are supported in addition to the common template
5767 The following keywords are supported in addition to the common template
5790 keywords and functions. See also :hg:`help templates`.
5768 keywords and functions. See also :hg:`help templates`.
5791
5769
5792 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5770 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5793 :path: String. Repository-absolute path of the file.
5771 :path: String. Repository-absolute path of the file.
5794
5772
5795 Returns 0 on success, 1 if any files fail a resolve attempt.
5773 Returns 0 on success, 1 if any files fail a resolve attempt.
5796 """
5774 """
5797
5775
5798 opts = pycompat.byteskwargs(opts)
5776 opts = pycompat.byteskwargs(opts)
5799 confirm = ui.configbool(b'commands', b'resolve.confirm')
5777 confirm = ui.configbool(b'commands', b'resolve.confirm')
5800 flaglist = b'all mark unmark list no_status re_merge'.split()
5778 flaglist = b'all mark unmark list no_status re_merge'.split()
5801 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5779 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5802
5780
5803 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5781 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5804 if actioncount > 1:
5782 if actioncount > 1:
5805 raise error.Abort(_(b"too many actions specified"))
5783 raise error.Abort(_(b"too many actions specified"))
5806 elif actioncount == 0 and ui.configbool(
5784 elif actioncount == 0 and ui.configbool(
5807 b'commands', b'resolve.explicit-re-merge'
5785 b'commands', b'resolve.explicit-re-merge'
5808 ):
5786 ):
5809 hint = _(b'use --mark, --unmark, --list or --re-merge')
5787 hint = _(b'use --mark, --unmark, --list or --re-merge')
5810 raise error.Abort(_(b'no action specified'), hint=hint)
5788 raise error.Abort(_(b'no action specified'), hint=hint)
5811 if pats and all:
5789 if pats and all:
5812 raise error.Abort(_(b"can't specify --all and patterns"))
5790 raise error.Abort(_(b"can't specify --all and patterns"))
5813 if not (all or pats or show or mark or unmark):
5791 if not (all or pats or show or mark or unmark):
5814 raise error.Abort(
5792 raise error.Abort(
5815 _(b'no files or directories specified'),
5793 _(b'no files or directories specified'),
5816 hint=b'use --all to re-merge all unresolved files',
5794 hint=b'use --all to re-merge all unresolved files',
5817 )
5795 )
5818
5796
5819 if confirm:
5797 if confirm:
5820 if all:
5798 if all:
5821 if ui.promptchoice(
5799 if ui.promptchoice(
5822 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5800 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5823 ):
5801 ):
5824 raise error.Abort(_(b'user quit'))
5802 raise error.Abort(_(b'user quit'))
5825 if mark and not pats:
5803 if mark and not pats:
5826 if ui.promptchoice(
5804 if ui.promptchoice(
5827 _(
5805 _(
5828 b'mark all unresolved files as resolved (yn)?'
5806 b'mark all unresolved files as resolved (yn)?'
5829 b'$$ &Yes $$ &No'
5807 b'$$ &Yes $$ &No'
5830 )
5808 )
5831 ):
5809 ):
5832 raise error.Abort(_(b'user quit'))
5810 raise error.Abort(_(b'user quit'))
5833 if unmark and not pats:
5811 if unmark and not pats:
5834 if ui.promptchoice(
5812 if ui.promptchoice(
5835 _(
5813 _(
5836 b'mark all resolved files as unresolved (yn)?'
5814 b'mark all resolved files as unresolved (yn)?'
5837 b'$$ &Yes $$ &No'
5815 b'$$ &Yes $$ &No'
5838 )
5816 )
5839 ):
5817 ):
5840 raise error.Abort(_(b'user quit'))
5818 raise error.Abort(_(b'user quit'))
5841
5819
5842 uipathfn = scmutil.getuipathfn(repo)
5820 uipathfn = scmutil.getuipathfn(repo)
5843
5821
5844 if show:
5822 if show:
5845 ui.pager(b'resolve')
5823 ui.pager(b'resolve')
5846 fm = ui.formatter(b'resolve', opts)
5824 fm = ui.formatter(b'resolve', opts)
5847 ms = mergestatemod.mergestate.read(repo)
5825 ms = mergestatemod.mergestate.read(repo)
5848 wctx = repo[None]
5826 wctx = repo[None]
5849 m = scmutil.match(wctx, pats, opts)
5827 m = scmutil.match(wctx, pats, opts)
5850
5828
5851 # Labels and keys based on merge state. Unresolved path conflicts show
5829 # Labels and keys based on merge state. Unresolved path conflicts show
5852 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5830 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5853 # resolved conflicts.
5831 # resolved conflicts.
5854 mergestateinfo = {
5832 mergestateinfo = {
5855 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5833 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5856 b'resolve.unresolved',
5834 b'resolve.unresolved',
5857 b'U',
5835 b'U',
5858 ),
5836 ),
5859 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5837 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5860 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5838 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5861 b'resolve.unresolved',
5839 b'resolve.unresolved',
5862 b'P',
5840 b'P',
5863 ),
5841 ),
5864 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5842 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5865 b'resolve.resolved',
5843 b'resolve.resolved',
5866 b'R',
5844 b'R',
5867 ),
5845 ),
5868 }
5846 }
5869
5847
5870 for f in ms:
5848 for f in ms:
5871 if not m(f):
5849 if not m(f):
5872 continue
5850 continue
5873
5851
5874 label, key = mergestateinfo[ms[f]]
5852 label, key = mergestateinfo[ms[f]]
5875 fm.startitem()
5853 fm.startitem()
5876 fm.context(ctx=wctx)
5854 fm.context(ctx=wctx)
5877 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5855 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5878 fm.data(path=f)
5856 fm.data(path=f)
5879 fm.plain(b'%s\n' % uipathfn(f), label=label)
5857 fm.plain(b'%s\n' % uipathfn(f), label=label)
5880 fm.end()
5858 fm.end()
5881 return 0
5859 return 0
5882
5860
5883 with repo.wlock():
5861 with repo.wlock():
5884 ms = mergestatemod.mergestate.read(repo)
5862 ms = mergestatemod.mergestate.read(repo)
5885
5863
5886 if not (ms.active() or repo.dirstate.p2() != nullid):
5864 if not (ms.active() or repo.dirstate.p2() != nullid):
5887 raise error.Abort(
5865 raise error.Abort(
5888 _(b'resolve command not applicable when not merging')
5866 _(b'resolve command not applicable when not merging')
5889 )
5867 )
5890
5868
5891 wctx = repo[None]
5869 wctx = repo[None]
5892 m = scmutil.match(wctx, pats, opts)
5870 m = scmutil.match(wctx, pats, opts)
5893 ret = 0
5871 ret = 0
5894 didwork = False
5872 didwork = False
5895
5873
5896 tocomplete = []
5874 tocomplete = []
5897 hasconflictmarkers = []
5875 hasconflictmarkers = []
5898 if mark:
5876 if mark:
5899 markcheck = ui.config(b'commands', b'resolve.mark-check')
5877 markcheck = ui.config(b'commands', b'resolve.mark-check')
5900 if markcheck not in [b'warn', b'abort']:
5878 if markcheck not in [b'warn', b'abort']:
5901 # Treat all invalid / unrecognized values as 'none'.
5879 # Treat all invalid / unrecognized values as 'none'.
5902 markcheck = False
5880 markcheck = False
5903 for f in ms:
5881 for f in ms:
5904 if not m(f):
5882 if not m(f):
5905 continue
5883 continue
5906
5884
5907 didwork = True
5885 didwork = True
5908
5886
5909 # path conflicts must be resolved manually
5887 # path conflicts must be resolved manually
5910 if ms[f] in (
5888 if ms[f] in (
5911 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5889 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5912 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5890 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5913 ):
5891 ):
5914 if mark:
5892 if mark:
5915 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5893 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5916 elif unmark:
5894 elif unmark:
5917 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5895 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5918 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5896 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5919 ui.warn(
5897 ui.warn(
5920 _(b'%s: path conflict must be resolved manually\n')
5898 _(b'%s: path conflict must be resolved manually\n')
5921 % uipathfn(f)
5899 % uipathfn(f)
5922 )
5900 )
5923 continue
5901 continue
5924
5902
5925 if mark:
5903 if mark:
5926 if markcheck:
5904 if markcheck:
5927 fdata = repo.wvfs.tryread(f)
5905 fdata = repo.wvfs.tryread(f)
5928 if (
5906 if (
5929 filemerge.hasconflictmarkers(fdata)
5907 filemerge.hasconflictmarkers(fdata)
5930 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5908 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5931 ):
5909 ):
5932 hasconflictmarkers.append(f)
5910 hasconflictmarkers.append(f)
5933 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5911 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5934 elif unmark:
5912 elif unmark:
5935 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5913 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5936 else:
5914 else:
5937 # backup pre-resolve (merge uses .orig for its own purposes)
5915 # backup pre-resolve (merge uses .orig for its own purposes)
5938 a = repo.wjoin(f)
5916 a = repo.wjoin(f)
5939 try:
5917 try:
5940 util.copyfile(a, a + b".resolve")
5918 util.copyfile(a, a + b".resolve")
5941 except (IOError, OSError) as inst:
5919 except (IOError, OSError) as inst:
5942 if inst.errno != errno.ENOENT:
5920 if inst.errno != errno.ENOENT:
5943 raise
5921 raise
5944
5922
5945 try:
5923 try:
5946 # preresolve file
5924 # preresolve file
5947 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5925 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5948 with ui.configoverride(overrides, b'resolve'):
5926 with ui.configoverride(overrides, b'resolve'):
5949 complete, r = ms.preresolve(f, wctx)
5927 complete, r = ms.preresolve(f, wctx)
5950 if not complete:
5928 if not complete:
5951 tocomplete.append(f)
5929 tocomplete.append(f)
5952 elif r:
5930 elif r:
5953 ret = 1
5931 ret = 1
5954 finally:
5932 finally:
5955 ms.commit()
5933 ms.commit()
5956
5934
5957 # replace filemerge's .orig file with our resolve file, but only
5935 # replace filemerge's .orig file with our resolve file, but only
5958 # for merges that are complete
5936 # for merges that are complete
5959 if complete:
5937 if complete:
5960 try:
5938 try:
5961 util.rename(
5939 util.rename(
5962 a + b".resolve", scmutil.backuppath(ui, repo, f)
5940 a + b".resolve", scmutil.backuppath(ui, repo, f)
5963 )
5941 )
5964 except OSError as inst:
5942 except OSError as inst:
5965 if inst.errno != errno.ENOENT:
5943 if inst.errno != errno.ENOENT:
5966 raise
5944 raise
5967
5945
5968 if hasconflictmarkers:
5946 if hasconflictmarkers:
5969 ui.warn(
5947 ui.warn(
5970 _(
5948 _(
5971 b'warning: the following files still have conflict '
5949 b'warning: the following files still have conflict '
5972 b'markers:\n'
5950 b'markers:\n'
5973 )
5951 )
5974 + b''.join(
5952 + b''.join(
5975 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5953 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5976 )
5954 )
5977 )
5955 )
5978 if markcheck == b'abort' and not all and not pats:
5956 if markcheck == b'abort' and not all and not pats:
5979 raise error.Abort(
5957 raise error.Abort(
5980 _(b'conflict markers detected'),
5958 _(b'conflict markers detected'),
5981 hint=_(b'use --all to mark anyway'),
5959 hint=_(b'use --all to mark anyway'),
5982 )
5960 )
5983
5961
5984 for f in tocomplete:
5962 for f in tocomplete:
5985 try:
5963 try:
5986 # resolve file
5964 # resolve file
5987 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5965 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5988 with ui.configoverride(overrides, b'resolve'):
5966 with ui.configoverride(overrides, b'resolve'):
5989 r = ms.resolve(f, wctx)
5967 r = ms.resolve(f, wctx)
5990 if r:
5968 if r:
5991 ret = 1
5969 ret = 1
5992 finally:
5970 finally:
5993 ms.commit()
5971 ms.commit()
5994
5972
5995 # replace filemerge's .orig file with our resolve file
5973 # replace filemerge's .orig file with our resolve file
5996 a = repo.wjoin(f)
5974 a = repo.wjoin(f)
5997 try:
5975 try:
5998 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5976 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5999 except OSError as inst:
5977 except OSError as inst:
6000 if inst.errno != errno.ENOENT:
5978 if inst.errno != errno.ENOENT:
6001 raise
5979 raise
6002
5980
6003 ms.commit()
5981 ms.commit()
6004 branchmerge = repo.dirstate.p2() != nullid
5982 branchmerge = repo.dirstate.p2() != nullid
6005 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5983 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6006
5984
6007 if not didwork and pats:
5985 if not didwork and pats:
6008 hint = None
5986 hint = None
6009 if not any([p for p in pats if p.find(b':') >= 0]):
5987 if not any([p for p in pats if p.find(b':') >= 0]):
6010 pats = [b'path:%s' % p for p in pats]
5988 pats = [b'path:%s' % p for p in pats]
6011 m = scmutil.match(wctx, pats, opts)
5989 m = scmutil.match(wctx, pats, opts)
6012 for f in ms:
5990 for f in ms:
6013 if not m(f):
5991 if not m(f):
6014 continue
5992 continue
6015
5993
6016 def flag(o):
5994 def flag(o):
6017 if o == b're_merge':
5995 if o == b're_merge':
6018 return b'--re-merge '
5996 return b'--re-merge '
6019 return b'-%s ' % o[0:1]
5997 return b'-%s ' % o[0:1]
6020
5998
6021 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5999 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6022 hint = _(b"(try: hg resolve %s%s)\n") % (
6000 hint = _(b"(try: hg resolve %s%s)\n") % (
6023 flags,
6001 flags,
6024 b' '.join(pats),
6002 b' '.join(pats),
6025 )
6003 )
6026 break
6004 break
6027 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6005 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6028 if hint:
6006 if hint:
6029 ui.warn(hint)
6007 ui.warn(hint)
6030
6008
6031 unresolvedf = list(ms.unresolved())
6009 unresolvedf = list(ms.unresolved())
6032 if not unresolvedf:
6010 if not unresolvedf:
6033 ui.status(_(b'(no more unresolved files)\n'))
6011 ui.status(_(b'(no more unresolved files)\n'))
6034 cmdutil.checkafterresolved(repo)
6012 cmdutil.checkafterresolved(repo)
6035
6013
6036 return ret
6014 return ret
6037
6015
6038
6016
6039 @command(
6017 @command(
6040 b'revert',
6018 b'revert',
6041 [
6019 [
6042 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6020 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6043 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6021 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6044 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6022 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6045 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6023 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6046 (b'i', b'interactive', None, _(b'interactively select the changes')),
6024 (b'i', b'interactive', None, _(b'interactively select the changes')),
6047 ]
6025 ]
6048 + walkopts
6026 + walkopts
6049 + dryrunopts,
6027 + dryrunopts,
6050 _(b'[OPTION]... [-r REV] [NAME]...'),
6028 _(b'[OPTION]... [-r REV] [NAME]...'),
6051 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6029 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6052 )
6030 )
6053 def revert(ui, repo, *pats, **opts):
6031 def revert(ui, repo, *pats, **opts):
6054 """restore files to their checkout state
6032 """restore files to their checkout state
6055
6033
6056 .. note::
6034 .. note::
6057
6035
6058 To check out earlier revisions, you should use :hg:`update REV`.
6036 To check out earlier revisions, you should use :hg:`update REV`.
6059 To cancel an uncommitted merge (and lose your changes),
6037 To cancel an uncommitted merge (and lose your changes),
6060 use :hg:`merge --abort`.
6038 use :hg:`merge --abort`.
6061
6039
6062 With no revision specified, revert the specified files or directories
6040 With no revision specified, revert the specified files or directories
6063 to the contents they had in the parent of the working directory.
6041 to the contents they had in the parent of the working directory.
6064 This restores the contents of files to an unmodified
6042 This restores the contents of files to an unmodified
6065 state and unschedules adds, removes, copies, and renames. If the
6043 state and unschedules adds, removes, copies, and renames. If the
6066 working directory has two parents, you must explicitly specify a
6044 working directory has two parents, you must explicitly specify a
6067 revision.
6045 revision.
6068
6046
6069 Using the -r/--rev or -d/--date options, revert the given files or
6047 Using the -r/--rev or -d/--date options, revert the given files or
6070 directories to their states as of a specific revision. Because
6048 directories to their states as of a specific revision. Because
6071 revert does not change the working directory parents, this will
6049 revert does not change the working directory parents, this will
6072 cause these files to appear modified. This can be helpful to "back
6050 cause these files to appear modified. This can be helpful to "back
6073 out" some or all of an earlier change. See :hg:`backout` for a
6051 out" some or all of an earlier change. See :hg:`backout` for a
6074 related method.
6052 related method.
6075
6053
6076 Modified files are saved with a .orig suffix before reverting.
6054 Modified files are saved with a .orig suffix before reverting.
6077 To disable these backups, use --no-backup. It is possible to store
6055 To disable these backups, use --no-backup. It is possible to store
6078 the backup files in a custom directory relative to the root of the
6056 the backup files in a custom directory relative to the root of the
6079 repository by setting the ``ui.origbackuppath`` configuration
6057 repository by setting the ``ui.origbackuppath`` configuration
6080 option.
6058 option.
6081
6059
6082 See :hg:`help dates` for a list of formats valid for -d/--date.
6060 See :hg:`help dates` for a list of formats valid for -d/--date.
6083
6061
6084 See :hg:`help backout` for a way to reverse the effect of an
6062 See :hg:`help backout` for a way to reverse the effect of an
6085 earlier changeset.
6063 earlier changeset.
6086
6064
6087 Returns 0 on success.
6065 Returns 0 on success.
6088 """
6066 """
6089
6067
6090 opts = pycompat.byteskwargs(opts)
6068 opts = pycompat.byteskwargs(opts)
6091 if opts.get(b"date"):
6069 if opts.get(b"date"):
6092 if opts.get(b"rev"):
6070 if opts.get(b"rev"):
6093 raise error.Abort(_(b"you can't specify a revision and a date"))
6071 raise error.Abort(_(b"you can't specify a revision and a date"))
6094 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6072 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6095
6073
6096 parent, p2 = repo.dirstate.parents()
6074 parent, p2 = repo.dirstate.parents()
6097 if not opts.get(b'rev') and p2 != nullid:
6075 if not opts.get(b'rev') and p2 != nullid:
6098 # revert after merge is a trap for new users (issue2915)
6076 # revert after merge is a trap for new users (issue2915)
6099 raise error.Abort(
6077 raise error.Abort(
6100 _(b'uncommitted merge with no revision specified'),
6078 _(b'uncommitted merge with no revision specified'),
6101 hint=_(b"use 'hg update' or see 'hg help revert'"),
6079 hint=_(b"use 'hg update' or see 'hg help revert'"),
6102 )
6080 )
6103
6081
6104 rev = opts.get(b'rev')
6082 rev = opts.get(b'rev')
6105 if rev:
6083 if rev:
6106 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6084 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6107 ctx = scmutil.revsingle(repo, rev)
6085 ctx = scmutil.revsingle(repo, rev)
6108
6086
6109 if not (
6087 if not (
6110 pats
6088 pats
6111 or opts.get(b'include')
6089 or opts.get(b'include')
6112 or opts.get(b'exclude')
6090 or opts.get(b'exclude')
6113 or opts.get(b'all')
6091 or opts.get(b'all')
6114 or opts.get(b'interactive')
6092 or opts.get(b'interactive')
6115 ):
6093 ):
6116 msg = _(b"no files or directories specified")
6094 msg = _(b"no files or directories specified")
6117 if p2 != nullid:
6095 if p2 != nullid:
6118 hint = _(
6096 hint = _(
6119 b"uncommitted merge, use --all to discard all changes,"
6097 b"uncommitted merge, use --all to discard all changes,"
6120 b" or 'hg update -C .' to abort the merge"
6098 b" or 'hg update -C .' to abort the merge"
6121 )
6099 )
6122 raise error.Abort(msg, hint=hint)
6100 raise error.Abort(msg, hint=hint)
6123 dirty = any(repo.status())
6101 dirty = any(repo.status())
6124 node = ctx.node()
6102 node = ctx.node()
6125 if node != parent:
6103 if node != parent:
6126 if dirty:
6104 if dirty:
6127 hint = (
6105 hint = (
6128 _(
6106 _(
6129 b"uncommitted changes, use --all to discard all"
6107 b"uncommitted changes, use --all to discard all"
6130 b" changes, or 'hg update %d' to update"
6108 b" changes, or 'hg update %d' to update"
6131 )
6109 )
6132 % ctx.rev()
6110 % ctx.rev()
6133 )
6111 )
6134 else:
6112 else:
6135 hint = (
6113 hint = (
6136 _(
6114 _(
6137 b"use --all to revert all files,"
6115 b"use --all to revert all files,"
6138 b" or 'hg update %d' to update"
6116 b" or 'hg update %d' to update"
6139 )
6117 )
6140 % ctx.rev()
6118 % ctx.rev()
6141 )
6119 )
6142 elif dirty:
6120 elif dirty:
6143 hint = _(b"uncommitted changes, use --all to discard all changes")
6121 hint = _(b"uncommitted changes, use --all to discard all changes")
6144 else:
6122 else:
6145 hint = _(b"use --all to revert all files")
6123 hint = _(b"use --all to revert all files")
6146 raise error.Abort(msg, hint=hint)
6124 raise error.Abort(msg, hint=hint)
6147
6125
6148 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6126 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6149
6127
6150
6128
6151 @command(
6129 @command(
6152 b'rollback',
6130 b'rollback',
6153 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6131 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6154 helpcategory=command.CATEGORY_MAINTENANCE,
6132 helpcategory=command.CATEGORY_MAINTENANCE,
6155 )
6133 )
6156 def rollback(ui, repo, **opts):
6134 def rollback(ui, repo, **opts):
6157 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6135 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6158
6136
6159 Please use :hg:`commit --amend` instead of rollback to correct
6137 Please use :hg:`commit --amend` instead of rollback to correct
6160 mistakes in the last commit.
6138 mistakes in the last commit.
6161
6139
6162 This command should be used with care. There is only one level of
6140 This command should be used with care. There is only one level of
6163 rollback, and there is no way to undo a rollback. It will also
6141 rollback, and there is no way to undo a rollback. It will also
6164 restore the dirstate at the time of the last transaction, losing
6142 restore the dirstate at the time of the last transaction, losing
6165 any dirstate changes since that time. This command does not alter
6143 any dirstate changes since that time. This command does not alter
6166 the working directory.
6144 the working directory.
6167
6145
6168 Transactions are used to encapsulate the effects of all commands
6146 Transactions are used to encapsulate the effects of all commands
6169 that create new changesets or propagate existing changesets into a
6147 that create new changesets or propagate existing changesets into a
6170 repository.
6148 repository.
6171
6149
6172 .. container:: verbose
6150 .. container:: verbose
6173
6151
6174 For example, the following commands are transactional, and their
6152 For example, the following commands are transactional, and their
6175 effects can be rolled back:
6153 effects can be rolled back:
6176
6154
6177 - commit
6155 - commit
6178 - import
6156 - import
6179 - pull
6157 - pull
6180 - push (with this repository as the destination)
6158 - push (with this repository as the destination)
6181 - unbundle
6159 - unbundle
6182
6160
6183 To avoid permanent data loss, rollback will refuse to rollback a
6161 To avoid permanent data loss, rollback will refuse to rollback a
6184 commit transaction if it isn't checked out. Use --force to
6162 commit transaction if it isn't checked out. Use --force to
6185 override this protection.
6163 override this protection.
6186
6164
6187 The rollback command can be entirely disabled by setting the
6165 The rollback command can be entirely disabled by setting the
6188 ``ui.rollback`` configuration setting to false. If you're here
6166 ``ui.rollback`` configuration setting to false. If you're here
6189 because you want to use rollback and it's disabled, you can
6167 because you want to use rollback and it's disabled, you can
6190 re-enable the command by setting ``ui.rollback`` to true.
6168 re-enable the command by setting ``ui.rollback`` to true.
6191
6169
6192 This command is not intended for use on public repositories. Once
6170 This command is not intended for use on public repositories. Once
6193 changes are visible for pull by other users, rolling a transaction
6171 changes are visible for pull by other users, rolling a transaction
6194 back locally is ineffective (someone else may already have pulled
6172 back locally is ineffective (someone else may already have pulled
6195 the changes). Furthermore, a race is possible with readers of the
6173 the changes). Furthermore, a race is possible with readers of the
6196 repository; for example an in-progress pull from the repository
6174 repository; for example an in-progress pull from the repository
6197 may fail if a rollback is performed.
6175 may fail if a rollback is performed.
6198
6176
6199 Returns 0 on success, 1 if no rollback data is available.
6177 Returns 0 on success, 1 if no rollback data is available.
6200 """
6178 """
6201 if not ui.configbool(b'ui', b'rollback'):
6179 if not ui.configbool(b'ui', b'rollback'):
6202 raise error.Abort(
6180 raise error.Abort(
6203 _(b'rollback is disabled because it is unsafe'),
6181 _(b'rollback is disabled because it is unsafe'),
6204 hint=b'see `hg help -v rollback` for information',
6182 hint=b'see `hg help -v rollback` for information',
6205 )
6183 )
6206 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6184 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6207
6185
6208
6186
6209 @command(
6187 @command(
6210 b'root',
6188 b'root',
6211 [] + formatteropts,
6189 [] + formatteropts,
6212 intents={INTENT_READONLY},
6190 intents={INTENT_READONLY},
6213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6191 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6214 )
6192 )
6215 def root(ui, repo, **opts):
6193 def root(ui, repo, **opts):
6216 """print the root (top) of the current working directory
6194 """print the root (top) of the current working directory
6217
6195
6218 Print the root directory of the current repository.
6196 Print the root directory of the current repository.
6219
6197
6220 .. container:: verbose
6198 .. container:: verbose
6221
6199
6222 Template:
6200 Template:
6223
6201
6224 The following keywords are supported in addition to the common template
6202 The following keywords are supported in addition to the common template
6225 keywords and functions. See also :hg:`help templates`.
6203 keywords and functions. See also :hg:`help templates`.
6226
6204
6227 :hgpath: String. Path to the .hg directory.
6205 :hgpath: String. Path to the .hg directory.
6228 :storepath: String. Path to the directory holding versioned data.
6206 :storepath: String. Path to the directory holding versioned data.
6229
6207
6230 Returns 0 on success.
6208 Returns 0 on success.
6231 """
6209 """
6232 opts = pycompat.byteskwargs(opts)
6210 opts = pycompat.byteskwargs(opts)
6233 with ui.formatter(b'root', opts) as fm:
6211 with ui.formatter(b'root', opts) as fm:
6234 fm.startitem()
6212 fm.startitem()
6235 fm.write(b'reporoot', b'%s\n', repo.root)
6213 fm.write(b'reporoot', b'%s\n', repo.root)
6236 fm.data(hgpath=repo.path, storepath=repo.spath)
6214 fm.data(hgpath=repo.path, storepath=repo.spath)
6237
6215
6238
6216
6239 @command(
6217 @command(
6240 b'serve',
6218 b'serve',
6241 [
6219 [
6242 (
6220 (
6243 b'A',
6221 b'A',
6244 b'accesslog',
6222 b'accesslog',
6245 b'',
6223 b'',
6246 _(b'name of access log file to write to'),
6224 _(b'name of access log file to write to'),
6247 _(b'FILE'),
6225 _(b'FILE'),
6248 ),
6226 ),
6249 (b'd', b'daemon', None, _(b'run server in background')),
6227 (b'd', b'daemon', None, _(b'run server in background')),
6250 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6228 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6251 (
6229 (
6252 b'E',
6230 b'E',
6253 b'errorlog',
6231 b'errorlog',
6254 b'',
6232 b'',
6255 _(b'name of error log file to write to'),
6233 _(b'name of error log file to write to'),
6256 _(b'FILE'),
6234 _(b'FILE'),
6257 ),
6235 ),
6258 # use string type, then we can check if something was passed
6236 # use string type, then we can check if something was passed
6259 (
6237 (
6260 b'p',
6238 b'p',
6261 b'port',
6239 b'port',
6262 b'',
6240 b'',
6263 _(b'port to listen on (default: 8000)'),
6241 _(b'port to listen on (default: 8000)'),
6264 _(b'PORT'),
6242 _(b'PORT'),
6265 ),
6243 ),
6266 (
6244 (
6267 b'a',
6245 b'a',
6268 b'address',
6246 b'address',
6269 b'',
6247 b'',
6270 _(b'address to listen on (default: all interfaces)'),
6248 _(b'address to listen on (default: all interfaces)'),
6271 _(b'ADDR'),
6249 _(b'ADDR'),
6272 ),
6250 ),
6273 (
6251 (
6274 b'',
6252 b'',
6275 b'prefix',
6253 b'prefix',
6276 b'',
6254 b'',
6277 _(b'prefix path to serve from (default: server root)'),
6255 _(b'prefix path to serve from (default: server root)'),
6278 _(b'PREFIX'),
6256 _(b'PREFIX'),
6279 ),
6257 ),
6280 (
6258 (
6281 b'n',
6259 b'n',
6282 b'name',
6260 b'name',
6283 b'',
6261 b'',
6284 _(b'name to show in web pages (default: working directory)'),
6262 _(b'name to show in web pages (default: working directory)'),
6285 _(b'NAME'),
6263 _(b'NAME'),
6286 ),
6264 ),
6287 (
6265 (
6288 b'',
6266 b'',
6289 b'web-conf',
6267 b'web-conf',
6290 b'',
6268 b'',
6291 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6269 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6292 _(b'FILE'),
6270 _(b'FILE'),
6293 ),
6271 ),
6294 (
6272 (
6295 b'',
6273 b'',
6296 b'webdir-conf',
6274 b'webdir-conf',
6297 b'',
6275 b'',
6298 _(b'name of the hgweb config file (DEPRECATED)'),
6276 _(b'name of the hgweb config file (DEPRECATED)'),
6299 _(b'FILE'),
6277 _(b'FILE'),
6300 ),
6278 ),
6301 (
6279 (
6302 b'',
6280 b'',
6303 b'pid-file',
6281 b'pid-file',
6304 b'',
6282 b'',
6305 _(b'name of file to write process ID to'),
6283 _(b'name of file to write process ID to'),
6306 _(b'FILE'),
6284 _(b'FILE'),
6307 ),
6285 ),
6308 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6286 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6309 (
6287 (
6310 b'',
6288 b'',
6311 b'cmdserver',
6289 b'cmdserver',
6312 b'',
6290 b'',
6313 _(b'for remote clients (ADVANCED)'),
6291 _(b'for remote clients (ADVANCED)'),
6314 _(b'MODE'),
6292 _(b'MODE'),
6315 ),
6293 ),
6316 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6294 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6317 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6295 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6318 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6296 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6319 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6297 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6320 (b'', b'print-url', None, _(b'start and print only the URL')),
6298 (b'', b'print-url', None, _(b'start and print only the URL')),
6321 ]
6299 ]
6322 + subrepoopts,
6300 + subrepoopts,
6323 _(b'[OPTION]...'),
6301 _(b'[OPTION]...'),
6324 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6302 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6325 helpbasic=True,
6303 helpbasic=True,
6326 optionalrepo=True,
6304 optionalrepo=True,
6327 )
6305 )
6328 def serve(ui, repo, **opts):
6306 def serve(ui, repo, **opts):
6329 """start stand-alone webserver
6307 """start stand-alone webserver
6330
6308
6331 Start a local HTTP repository browser and pull server. You can use
6309 Start a local HTTP repository browser and pull server. You can use
6332 this for ad-hoc sharing and browsing of repositories. It is
6310 this for ad-hoc sharing and browsing of repositories. It is
6333 recommended to use a real web server to serve a repository for
6311 recommended to use a real web server to serve a repository for
6334 longer periods of time.
6312 longer periods of time.
6335
6313
6336 Please note that the server does not implement access control.
6314 Please note that the server does not implement access control.
6337 This means that, by default, anybody can read from the server and
6315 This means that, by default, anybody can read from the server and
6338 nobody can write to it by default. Set the ``web.allow-push``
6316 nobody can write to it by default. Set the ``web.allow-push``
6339 option to ``*`` to allow everybody to push to the server. You
6317 option to ``*`` to allow everybody to push to the server. You
6340 should use a real web server if you need to authenticate users.
6318 should use a real web server if you need to authenticate users.
6341
6319
6342 By default, the server logs accesses to stdout and errors to
6320 By default, the server logs accesses to stdout and errors to
6343 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6321 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6344 files.
6322 files.
6345
6323
6346 To have the server choose a free port number to listen on, specify
6324 To have the server choose a free port number to listen on, specify
6347 a port number of 0; in this case, the server will print the port
6325 a port number of 0; in this case, the server will print the port
6348 number it uses.
6326 number it uses.
6349
6327
6350 Returns 0 on success.
6328 Returns 0 on success.
6351 """
6329 """
6352
6330
6353 opts = pycompat.byteskwargs(opts)
6331 opts = pycompat.byteskwargs(opts)
6354 if opts[b"stdio"] and opts[b"cmdserver"]:
6332 if opts[b"stdio"] and opts[b"cmdserver"]:
6355 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6333 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6356 if opts[b"print_url"] and ui.verbose:
6334 if opts[b"print_url"] and ui.verbose:
6357 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6335 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6358
6336
6359 if opts[b"stdio"]:
6337 if opts[b"stdio"]:
6360 if repo is None:
6338 if repo is None:
6361 raise error.RepoError(
6339 raise error.RepoError(
6362 _(b"there is no Mercurial repository here (.hg not found)")
6340 _(b"there is no Mercurial repository here (.hg not found)")
6363 )
6341 )
6364 s = wireprotoserver.sshserver(ui, repo)
6342 s = wireprotoserver.sshserver(ui, repo)
6365 s.serve_forever()
6343 s.serve_forever()
6366
6344
6367 service = server.createservice(ui, repo, opts)
6345 service = server.createservice(ui, repo, opts)
6368 return server.runservice(opts, initfn=service.init, runfn=service.run)
6346 return server.runservice(opts, initfn=service.init, runfn=service.run)
6369
6347
6370
6348
6371 @command(
6349 @command(
6372 b'shelve',
6350 b'shelve',
6373 [
6351 [
6374 (
6352 (
6375 b'A',
6353 b'A',
6376 b'addremove',
6354 b'addremove',
6377 None,
6355 None,
6378 _(b'mark new/missing files as added/removed before shelving'),
6356 _(b'mark new/missing files as added/removed before shelving'),
6379 ),
6357 ),
6380 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6358 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6381 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6359 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6382 (
6360 (
6383 b'',
6361 b'',
6384 b'date',
6362 b'date',
6385 b'',
6363 b'',
6386 _(b'shelve with the specified commit date'),
6364 _(b'shelve with the specified commit date'),
6387 _(b'DATE'),
6365 _(b'DATE'),
6388 ),
6366 ),
6389 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6367 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6390 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6368 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6391 (
6369 (
6392 b'k',
6370 b'k',
6393 b'keep',
6371 b'keep',
6394 False,
6372 False,
6395 _(b'shelve, but keep changes in the working directory'),
6373 _(b'shelve, but keep changes in the working directory'),
6396 ),
6374 ),
6397 (b'l', b'list', None, _(b'list current shelves')),
6375 (b'l', b'list', None, _(b'list current shelves')),
6398 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6376 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6399 (
6377 (
6400 b'n',
6378 b'n',
6401 b'name',
6379 b'name',
6402 b'',
6380 b'',
6403 _(b'use the given name for the shelved commit'),
6381 _(b'use the given name for the shelved commit'),
6404 _(b'NAME'),
6382 _(b'NAME'),
6405 ),
6383 ),
6406 (
6384 (
6407 b'p',
6385 b'p',
6408 b'patch',
6386 b'patch',
6409 None,
6387 None,
6410 _(
6388 _(
6411 b'output patches for changes (provide the names of the shelved '
6389 b'output patches for changes (provide the names of the shelved '
6412 b'changes as positional arguments)'
6390 b'changes as positional arguments)'
6413 ),
6391 ),
6414 ),
6392 ),
6415 (b'i', b'interactive', None, _(b'interactive mode')),
6393 (b'i', b'interactive', None, _(b'interactive mode')),
6416 (
6394 (
6417 b'',
6395 b'',
6418 b'stat',
6396 b'stat',
6419 None,
6397 None,
6420 _(
6398 _(
6421 b'output diffstat-style summary of changes (provide the names of '
6399 b'output diffstat-style summary of changes (provide the names of '
6422 b'the shelved changes as positional arguments)'
6400 b'the shelved changes as positional arguments)'
6423 ),
6401 ),
6424 ),
6402 ),
6425 ]
6403 ]
6426 + cmdutil.walkopts,
6404 + cmdutil.walkopts,
6427 _(b'hg shelve [OPTION]... [FILE]...'),
6405 _(b'hg shelve [OPTION]... [FILE]...'),
6428 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6406 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6429 )
6407 )
6430 def shelve(ui, repo, *pats, **opts):
6408 def shelve(ui, repo, *pats, **opts):
6431 '''save and set aside changes from the working directory
6409 '''save and set aside changes from the working directory
6432
6410
6433 Shelving takes files that "hg status" reports as not clean, saves
6411 Shelving takes files that "hg status" reports as not clean, saves
6434 the modifications to a bundle (a shelved change), and reverts the
6412 the modifications to a bundle (a shelved change), and reverts the
6435 files so that their state in the working directory becomes clean.
6413 files so that their state in the working directory becomes clean.
6436
6414
6437 To restore these changes to the working directory, using "hg
6415 To restore these changes to the working directory, using "hg
6438 unshelve"; this will work even if you switch to a different
6416 unshelve"; this will work even if you switch to a different
6439 commit.
6417 commit.
6440
6418
6441 When no files are specified, "hg shelve" saves all not-clean
6419 When no files are specified, "hg shelve" saves all not-clean
6442 files. If specific files or directories are named, only changes to
6420 files. If specific files or directories are named, only changes to
6443 those files are shelved.
6421 those files are shelved.
6444
6422
6445 In bare shelve (when no files are specified, without interactive,
6423 In bare shelve (when no files are specified, without interactive,
6446 include and exclude option), shelving remembers information if the
6424 include and exclude option), shelving remembers information if the
6447 working directory was on newly created branch, in other words working
6425 working directory was on newly created branch, in other words working
6448 directory was on different branch than its first parent. In this
6426 directory was on different branch than its first parent. In this
6449 situation unshelving restores branch information to the working directory.
6427 situation unshelving restores branch information to the working directory.
6450
6428
6451 Each shelved change has a name that makes it easier to find later.
6429 Each shelved change has a name that makes it easier to find later.
6452 The name of a shelved change defaults to being based on the active
6430 The name of a shelved change defaults to being based on the active
6453 bookmark, or if there is no active bookmark, the current named
6431 bookmark, or if there is no active bookmark, the current named
6454 branch. To specify a different name, use ``--name``.
6432 branch. To specify a different name, use ``--name``.
6455
6433
6456 To see a list of existing shelved changes, use the ``--list``
6434 To see a list of existing shelved changes, use the ``--list``
6457 option. For each shelved change, this will print its name, age,
6435 option. For each shelved change, this will print its name, age,
6458 and description; use ``--patch`` or ``--stat`` for more details.
6436 and description; use ``--patch`` or ``--stat`` for more details.
6459
6437
6460 To delete specific shelved changes, use ``--delete``. To delete
6438 To delete specific shelved changes, use ``--delete``. To delete
6461 all shelved changes, use ``--cleanup``.
6439 all shelved changes, use ``--cleanup``.
6462 '''
6440 '''
6463 opts = pycompat.byteskwargs(opts)
6441 opts = pycompat.byteskwargs(opts)
6464 allowables = [
6442 allowables = [
6465 (b'addremove', {b'create'}), # 'create' is pseudo action
6443 (b'addremove', {b'create'}), # 'create' is pseudo action
6466 (b'unknown', {b'create'}),
6444 (b'unknown', {b'create'}),
6467 (b'cleanup', {b'cleanup'}),
6445 (b'cleanup', {b'cleanup'}),
6468 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6446 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6469 (b'delete', {b'delete'}),
6447 (b'delete', {b'delete'}),
6470 (b'edit', {b'create'}),
6448 (b'edit', {b'create'}),
6471 (b'keep', {b'create'}),
6449 (b'keep', {b'create'}),
6472 (b'list', {b'list'}),
6450 (b'list', {b'list'}),
6473 (b'message', {b'create'}),
6451 (b'message', {b'create'}),
6474 (b'name', {b'create'}),
6452 (b'name', {b'create'}),
6475 (b'patch', {b'patch', b'list'}),
6453 (b'patch', {b'patch', b'list'}),
6476 (b'stat', {b'stat', b'list'}),
6454 (b'stat', {b'stat', b'list'}),
6477 ]
6455 ]
6478
6456
6479 def checkopt(opt):
6457 def checkopt(opt):
6480 if opts.get(opt):
6458 if opts.get(opt):
6481 for i, allowable in allowables:
6459 for i, allowable in allowables:
6482 if opts[i] and opt not in allowable:
6460 if opts[i] and opt not in allowable:
6483 raise error.Abort(
6461 raise error.Abort(
6484 _(
6462 _(
6485 b"options '--%s' and '--%s' may not be "
6463 b"options '--%s' and '--%s' may not be "
6486 b"used together"
6464 b"used together"
6487 )
6465 )
6488 % (opt, i)
6466 % (opt, i)
6489 )
6467 )
6490 return True
6468 return True
6491
6469
6492 if checkopt(b'cleanup'):
6470 if checkopt(b'cleanup'):
6493 if pats:
6471 if pats:
6494 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6472 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6495 return shelvemod.cleanupcmd(ui, repo)
6473 return shelvemod.cleanupcmd(ui, repo)
6496 elif checkopt(b'delete'):
6474 elif checkopt(b'delete'):
6497 return shelvemod.deletecmd(ui, repo, pats)
6475 return shelvemod.deletecmd(ui, repo, pats)
6498 elif checkopt(b'list'):
6476 elif checkopt(b'list'):
6499 return shelvemod.listcmd(ui, repo, pats, opts)
6477 return shelvemod.listcmd(ui, repo, pats, opts)
6500 elif checkopt(b'patch') or checkopt(b'stat'):
6478 elif checkopt(b'patch') or checkopt(b'stat'):
6501 return shelvemod.patchcmds(ui, repo, pats, opts)
6479 return shelvemod.patchcmds(ui, repo, pats, opts)
6502 else:
6480 else:
6503 return shelvemod.createcmd(ui, repo, pats, opts)
6481 return shelvemod.createcmd(ui, repo, pats, opts)
6504
6482
6505
6483
6506 _NOTTERSE = b'nothing'
6484 _NOTTERSE = b'nothing'
6507
6485
6508
6486
6509 @command(
6487 @command(
6510 b'status|st',
6488 b'status|st',
6511 [
6489 [
6512 (b'A', b'all', None, _(b'show status of all files')),
6490 (b'A', b'all', None, _(b'show status of all files')),
6513 (b'm', b'modified', None, _(b'show only modified files')),
6491 (b'm', b'modified', None, _(b'show only modified files')),
6514 (b'a', b'added', None, _(b'show only added files')),
6492 (b'a', b'added', None, _(b'show only added files')),
6515 (b'r', b'removed', None, _(b'show only removed files')),
6493 (b'r', b'removed', None, _(b'show only removed files')),
6516 (b'd', b'deleted', None, _(b'show only missing files')),
6494 (b'd', b'deleted', None, _(b'show only missing files')),
6517 (b'c', b'clean', None, _(b'show only files without changes')),
6495 (b'c', b'clean', None, _(b'show only files without changes')),
6518 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6496 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6519 (b'i', b'ignored', None, _(b'show only ignored files')),
6497 (b'i', b'ignored', None, _(b'show only ignored files')),
6520 (b'n', b'no-status', None, _(b'hide status prefix')),
6498 (b'n', b'no-status', None, _(b'hide status prefix')),
6521 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6499 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6522 (
6500 (
6523 b'C',
6501 b'C',
6524 b'copies',
6502 b'copies',
6525 None,
6503 None,
6526 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6504 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6527 ),
6505 ),
6528 (
6506 (
6529 b'0',
6507 b'0',
6530 b'print0',
6508 b'print0',
6531 None,
6509 None,
6532 _(b'end filenames with NUL, for use with xargs'),
6510 _(b'end filenames with NUL, for use with xargs'),
6533 ),
6511 ),
6534 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6512 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6535 (
6513 (
6536 b'',
6514 b'',
6537 b'change',
6515 b'change',
6538 b'',
6516 b'',
6539 _(b'list the changed files of a revision'),
6517 _(b'list the changed files of a revision'),
6540 _(b'REV'),
6518 _(b'REV'),
6541 ),
6519 ),
6542 ]
6520 ]
6543 + walkopts
6521 + walkopts
6544 + subrepoopts
6522 + subrepoopts
6545 + formatteropts,
6523 + formatteropts,
6546 _(b'[OPTION]... [FILE]...'),
6524 _(b'[OPTION]... [FILE]...'),
6547 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6525 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6548 helpbasic=True,
6526 helpbasic=True,
6549 inferrepo=True,
6527 inferrepo=True,
6550 intents={INTENT_READONLY},
6528 intents={INTENT_READONLY},
6551 )
6529 )
6552 def status(ui, repo, *pats, **opts):
6530 def status(ui, repo, *pats, **opts):
6553 """show changed files in the working directory
6531 """show changed files in the working directory
6554
6532
6555 Show status of files in the repository. If names are given, only
6533 Show status of files in the repository. If names are given, only
6556 files that match are shown. Files that are clean or ignored or
6534 files that match are shown. Files that are clean or ignored or
6557 the source of a copy/move operation, are not listed unless
6535 the source of a copy/move operation, are not listed unless
6558 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6536 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6559 Unless options described with "show only ..." are given, the
6537 Unless options described with "show only ..." are given, the
6560 options -mardu are used.
6538 options -mardu are used.
6561
6539
6562 Option -q/--quiet hides untracked (unknown and ignored) files
6540 Option -q/--quiet hides untracked (unknown and ignored) files
6563 unless explicitly requested with -u/--unknown or -i/--ignored.
6541 unless explicitly requested with -u/--unknown or -i/--ignored.
6564
6542
6565 .. note::
6543 .. note::
6566
6544
6567 :hg:`status` may appear to disagree with diff if permissions have
6545 :hg:`status` may appear to disagree with diff if permissions have
6568 changed or a merge has occurred. The standard diff format does
6546 changed or a merge has occurred. The standard diff format does
6569 not report permission changes and diff only reports changes
6547 not report permission changes and diff only reports changes
6570 relative to one merge parent.
6548 relative to one merge parent.
6571
6549
6572 If one revision is given, it is used as the base revision.
6550 If one revision is given, it is used as the base revision.
6573 If two revisions are given, the differences between them are
6551 If two revisions are given, the differences between them are
6574 shown. The --change option can also be used as a shortcut to list
6552 shown. The --change option can also be used as a shortcut to list
6575 the changed files of a revision from its first parent.
6553 the changed files of a revision from its first parent.
6576
6554
6577 The codes used to show the status of files are::
6555 The codes used to show the status of files are::
6578
6556
6579 M = modified
6557 M = modified
6580 A = added
6558 A = added
6581 R = removed
6559 R = removed
6582 C = clean
6560 C = clean
6583 ! = missing (deleted by non-hg command, but still tracked)
6561 ! = missing (deleted by non-hg command, but still tracked)
6584 ? = not tracked
6562 ? = not tracked
6585 I = ignored
6563 I = ignored
6586 = origin of the previous file (with --copies)
6564 = origin of the previous file (with --copies)
6587
6565
6588 .. container:: verbose
6566 .. container:: verbose
6589
6567
6590 The -t/--terse option abbreviates the output by showing only the directory
6568 The -t/--terse option abbreviates the output by showing only the directory
6591 name if all the files in it share the same status. The option takes an
6569 name if all the files in it share the same status. The option takes an
6592 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6570 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6593 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6571 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6594 for 'ignored' and 'c' for clean.
6572 for 'ignored' and 'c' for clean.
6595
6573
6596 It abbreviates only those statuses which are passed. Note that clean and
6574 It abbreviates only those statuses which are passed. Note that clean and
6597 ignored files are not displayed with '--terse ic' unless the -c/--clean
6575 ignored files are not displayed with '--terse ic' unless the -c/--clean
6598 and -i/--ignored options are also used.
6576 and -i/--ignored options are also used.
6599
6577
6600 The -v/--verbose option shows information when the repository is in an
6578 The -v/--verbose option shows information when the repository is in an
6601 unfinished merge, shelve, rebase state etc. You can have this behavior
6579 unfinished merge, shelve, rebase state etc. You can have this behavior
6602 turned on by default by enabling the ``commands.status.verbose`` option.
6580 turned on by default by enabling the ``commands.status.verbose`` option.
6603
6581
6604 You can skip displaying some of these states by setting
6582 You can skip displaying some of these states by setting
6605 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6583 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6606 'histedit', 'merge', 'rebase', or 'unshelve'.
6584 'histedit', 'merge', 'rebase', or 'unshelve'.
6607
6585
6608 Template:
6586 Template:
6609
6587
6610 The following keywords are supported in addition to the common template
6588 The following keywords are supported in addition to the common template
6611 keywords and functions. See also :hg:`help templates`.
6589 keywords and functions. See also :hg:`help templates`.
6612
6590
6613 :path: String. Repository-absolute path of the file.
6591 :path: String. Repository-absolute path of the file.
6614 :source: String. Repository-absolute path of the file originated from.
6592 :source: String. Repository-absolute path of the file originated from.
6615 Available if ``--copies`` is specified.
6593 Available if ``--copies`` is specified.
6616 :status: String. Character denoting file's status.
6594 :status: String. Character denoting file's status.
6617
6595
6618 Examples:
6596 Examples:
6619
6597
6620 - show changes in the working directory relative to a
6598 - show changes in the working directory relative to a
6621 changeset::
6599 changeset::
6622
6600
6623 hg status --rev 9353
6601 hg status --rev 9353
6624
6602
6625 - show changes in the working directory relative to the
6603 - show changes in the working directory relative to the
6626 current directory (see :hg:`help patterns` for more information)::
6604 current directory (see :hg:`help patterns` for more information)::
6627
6605
6628 hg status re:
6606 hg status re:
6629
6607
6630 - show all changes including copies in an existing changeset::
6608 - show all changes including copies in an existing changeset::
6631
6609
6632 hg status --copies --change 9353
6610 hg status --copies --change 9353
6633
6611
6634 - get a NUL separated list of added files, suitable for xargs::
6612 - get a NUL separated list of added files, suitable for xargs::
6635
6613
6636 hg status -an0
6614 hg status -an0
6637
6615
6638 - show more information about the repository status, abbreviating
6616 - show more information about the repository status, abbreviating
6639 added, removed, modified, deleted, and untracked paths::
6617 added, removed, modified, deleted, and untracked paths::
6640
6618
6641 hg status -v -t mardu
6619 hg status -v -t mardu
6642
6620
6643 Returns 0 on success.
6621 Returns 0 on success.
6644
6622
6645 """
6623 """
6646
6624
6647 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6625 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6648 opts = pycompat.byteskwargs(opts)
6626 opts = pycompat.byteskwargs(opts)
6649 revs = opts.get(b'rev')
6627 revs = opts.get(b'rev')
6650 change = opts.get(b'change')
6628 change = opts.get(b'change')
6651 terse = opts.get(b'terse')
6629 terse = opts.get(b'terse')
6652 if terse is _NOTTERSE:
6630 if terse is _NOTTERSE:
6653 if revs:
6631 if revs:
6654 terse = b''
6632 terse = b''
6655 else:
6633 else:
6656 terse = ui.config(b'commands', b'status.terse')
6634 terse = ui.config(b'commands', b'status.terse')
6657
6635
6658 if revs and terse:
6636 if revs and terse:
6659 msg = _(b'cannot use --terse with --rev')
6637 msg = _(b'cannot use --terse with --rev')
6660 raise error.Abort(msg)
6638 raise error.Abort(msg)
6661 elif change:
6639 elif change:
6662 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6640 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6663 ctx2 = scmutil.revsingle(repo, change, None)
6641 ctx2 = scmutil.revsingle(repo, change, None)
6664 ctx1 = ctx2.p1()
6642 ctx1 = ctx2.p1()
6665 else:
6643 else:
6666 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6644 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6667 ctx1, ctx2 = scmutil.revpair(repo, revs)
6645 ctx1, ctx2 = scmutil.revpair(repo, revs)
6668
6646
6669 forcerelativevalue = None
6647 forcerelativevalue = None
6670 if ui.hasconfig(b'commands', b'status.relative'):
6648 if ui.hasconfig(b'commands', b'status.relative'):
6671 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6649 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6672 uipathfn = scmutil.getuipathfn(
6650 uipathfn = scmutil.getuipathfn(
6673 repo,
6651 repo,
6674 legacyrelativevalue=bool(pats),
6652 legacyrelativevalue=bool(pats),
6675 forcerelativevalue=forcerelativevalue,
6653 forcerelativevalue=forcerelativevalue,
6676 )
6654 )
6677
6655
6678 if opts.get(b'print0'):
6656 if opts.get(b'print0'):
6679 end = b'\0'
6657 end = b'\0'
6680 else:
6658 else:
6681 end = b'\n'
6659 end = b'\n'
6682 states = b'modified added removed deleted unknown ignored clean'.split()
6660 states = b'modified added removed deleted unknown ignored clean'.split()
6683 show = [k for k in states if opts.get(k)]
6661 show = [k for k in states if opts.get(k)]
6684 if opts.get(b'all'):
6662 if opts.get(b'all'):
6685 show += ui.quiet and (states[:4] + [b'clean']) or states
6663 show += ui.quiet and (states[:4] + [b'clean']) or states
6686
6664
6687 if not show:
6665 if not show:
6688 if ui.quiet:
6666 if ui.quiet:
6689 show = states[:4]
6667 show = states[:4]
6690 else:
6668 else:
6691 show = states[:5]
6669 show = states[:5]
6692
6670
6693 m = scmutil.match(ctx2, pats, opts)
6671 m = scmutil.match(ctx2, pats, opts)
6694 if terse:
6672 if terse:
6695 # we need to compute clean and unknown to terse
6673 # we need to compute clean and unknown to terse
6696 stat = repo.status(
6674 stat = repo.status(
6697 ctx1.node(),
6675 ctx1.node(),
6698 ctx2.node(),
6676 ctx2.node(),
6699 m,
6677 m,
6700 b'ignored' in show or b'i' in terse,
6678 b'ignored' in show or b'i' in terse,
6701 clean=True,
6679 clean=True,
6702 unknown=True,
6680 unknown=True,
6703 listsubrepos=opts.get(b'subrepos'),
6681 listsubrepos=opts.get(b'subrepos'),
6704 )
6682 )
6705
6683
6706 stat = cmdutil.tersedir(stat, terse)
6684 stat = cmdutil.tersedir(stat, terse)
6707 else:
6685 else:
6708 stat = repo.status(
6686 stat = repo.status(
6709 ctx1.node(),
6687 ctx1.node(),
6710 ctx2.node(),
6688 ctx2.node(),
6711 m,
6689 m,
6712 b'ignored' in show,
6690 b'ignored' in show,
6713 b'clean' in show,
6691 b'clean' in show,
6714 b'unknown' in show,
6692 b'unknown' in show,
6715 opts.get(b'subrepos'),
6693 opts.get(b'subrepos'),
6716 )
6694 )
6717
6695
6718 changestates = zip(
6696 changestates = zip(
6719 states,
6697 states,
6720 pycompat.iterbytestr(b'MAR!?IC'),
6698 pycompat.iterbytestr(b'MAR!?IC'),
6721 [getattr(stat, s.decode('utf8')) for s in states],
6699 [getattr(stat, s.decode('utf8')) for s in states],
6722 )
6700 )
6723
6701
6724 copy = {}
6702 copy = {}
6725 if (
6703 if (
6726 opts.get(b'all')
6704 opts.get(b'all')
6727 or opts.get(b'copies')
6705 or opts.get(b'copies')
6728 or ui.configbool(b'ui', b'statuscopies')
6706 or ui.configbool(b'ui', b'statuscopies')
6729 ) and not opts.get(b'no_status'):
6707 ) and not opts.get(b'no_status'):
6730 copy = copies.pathcopies(ctx1, ctx2, m)
6708 copy = copies.pathcopies(ctx1, ctx2, m)
6731
6709
6732 morestatus = None
6710 morestatus = None
6733 if (
6711 if (
6734 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6712 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6735 ) and not ui.plain():
6713 ) and not ui.plain():
6736 morestatus = cmdutil.readmorestatus(repo)
6714 morestatus = cmdutil.readmorestatus(repo)
6737
6715
6738 ui.pager(b'status')
6716 ui.pager(b'status')
6739 fm = ui.formatter(b'status', opts)
6717 fm = ui.formatter(b'status', opts)
6740 fmt = b'%s' + end
6718 fmt = b'%s' + end
6741 showchar = not opts.get(b'no_status')
6719 showchar = not opts.get(b'no_status')
6742
6720
6743 for state, char, files in changestates:
6721 for state, char, files in changestates:
6744 if state in show:
6722 if state in show:
6745 label = b'status.' + state
6723 label = b'status.' + state
6746 for f in files:
6724 for f in files:
6747 fm.startitem()
6725 fm.startitem()
6748 fm.context(ctx=ctx2)
6726 fm.context(ctx=ctx2)
6749 fm.data(itemtype=b'file', path=f)
6727 fm.data(itemtype=b'file', path=f)
6750 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6728 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6751 fm.plain(fmt % uipathfn(f), label=label)
6729 fm.plain(fmt % uipathfn(f), label=label)
6752 if f in copy:
6730 if f in copy:
6753 fm.data(source=copy[f])
6731 fm.data(source=copy[f])
6754 fm.plain(
6732 fm.plain(
6755 (b' %s' + end) % uipathfn(copy[f]),
6733 (b' %s' + end) % uipathfn(copy[f]),
6756 label=b'status.copied',
6734 label=b'status.copied',
6757 )
6735 )
6758 if morestatus:
6736 if morestatus:
6759 morestatus.formatfile(f, fm)
6737 morestatus.formatfile(f, fm)
6760
6738
6761 if morestatus:
6739 if morestatus:
6762 morestatus.formatfooter(fm)
6740 morestatus.formatfooter(fm)
6763 fm.end()
6741 fm.end()
6764
6742
6765
6743
6766 @command(
6744 @command(
6767 b'summary|sum',
6745 b'summary|sum',
6768 [(b'', b'remote', None, _(b'check for push and pull'))],
6746 [(b'', b'remote', None, _(b'check for push and pull'))],
6769 b'[--remote]',
6747 b'[--remote]',
6770 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6748 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6771 helpbasic=True,
6749 helpbasic=True,
6772 intents={INTENT_READONLY},
6750 intents={INTENT_READONLY},
6773 )
6751 )
6774 def summary(ui, repo, **opts):
6752 def summary(ui, repo, **opts):
6775 """summarize working directory state
6753 """summarize working directory state
6776
6754
6777 This generates a brief summary of the working directory state,
6755 This generates a brief summary of the working directory state,
6778 including parents, branch, commit status, phase and available updates.
6756 including parents, branch, commit status, phase and available updates.
6779
6757
6780 With the --remote option, this will check the default paths for
6758 With the --remote option, this will check the default paths for
6781 incoming and outgoing changes. This can be time-consuming.
6759 incoming and outgoing changes. This can be time-consuming.
6782
6760
6783 Returns 0 on success.
6761 Returns 0 on success.
6784 """
6762 """
6785
6763
6786 opts = pycompat.byteskwargs(opts)
6764 opts = pycompat.byteskwargs(opts)
6787 ui.pager(b'summary')
6765 ui.pager(b'summary')
6788 ctx = repo[None]
6766 ctx = repo[None]
6789 parents = ctx.parents()
6767 parents = ctx.parents()
6790 pnode = parents[0].node()
6768 pnode = parents[0].node()
6791 marks = []
6769 marks = []
6792
6770
6793 try:
6771 try:
6794 ms = mergestatemod.mergestate.read(repo)
6772 ms = mergestatemod.mergestate.read(repo)
6795 except error.UnsupportedMergeRecords as e:
6773 except error.UnsupportedMergeRecords as e:
6796 s = b' '.join(e.recordtypes)
6774 s = b' '.join(e.recordtypes)
6797 ui.warn(
6775 ui.warn(
6798 _(b'warning: merge state has unsupported record types: %s\n') % s
6776 _(b'warning: merge state has unsupported record types: %s\n') % s
6799 )
6777 )
6800 unresolved = []
6778 unresolved = []
6801 else:
6779 else:
6802 unresolved = list(ms.unresolved())
6780 unresolved = list(ms.unresolved())
6803
6781
6804 for p in parents:
6782 for p in parents:
6805 # label with log.changeset (instead of log.parent) since this
6783 # label with log.changeset (instead of log.parent) since this
6806 # shows a working directory parent *changeset*:
6784 # shows a working directory parent *changeset*:
6807 # i18n: column positioning for "hg summary"
6785 # i18n: column positioning for "hg summary"
6808 ui.write(
6786 ui.write(
6809 _(b'parent: %d:%s ') % (p.rev(), p),
6787 _(b'parent: %d:%s ') % (p.rev(), p),
6810 label=logcmdutil.changesetlabels(p),
6788 label=logcmdutil.changesetlabels(p),
6811 )
6789 )
6812 ui.write(b' '.join(p.tags()), label=b'log.tag')
6790 ui.write(b' '.join(p.tags()), label=b'log.tag')
6813 if p.bookmarks():
6791 if p.bookmarks():
6814 marks.extend(p.bookmarks())
6792 marks.extend(p.bookmarks())
6815 if p.rev() == -1:
6793 if p.rev() == -1:
6816 if not len(repo):
6794 if not len(repo):
6817 ui.write(_(b' (empty repository)'))
6795 ui.write(_(b' (empty repository)'))
6818 else:
6796 else:
6819 ui.write(_(b' (no revision checked out)'))
6797 ui.write(_(b' (no revision checked out)'))
6820 if p.obsolete():
6798 if p.obsolete():
6821 ui.write(_(b' (obsolete)'))
6799 ui.write(_(b' (obsolete)'))
6822 if p.isunstable():
6800 if p.isunstable():
6823 instabilities = (
6801 instabilities = (
6824 ui.label(instability, b'trouble.%s' % instability)
6802 ui.label(instability, b'trouble.%s' % instability)
6825 for instability in p.instabilities()
6803 for instability in p.instabilities()
6826 )
6804 )
6827 ui.write(b' (' + b', '.join(instabilities) + b')')
6805 ui.write(b' (' + b', '.join(instabilities) + b')')
6828 ui.write(b'\n')
6806 ui.write(b'\n')
6829 if p.description():
6807 if p.description():
6830 ui.status(
6808 ui.status(
6831 b' ' + p.description().splitlines()[0].strip() + b'\n',
6809 b' ' + p.description().splitlines()[0].strip() + b'\n',
6832 label=b'log.summary',
6810 label=b'log.summary',
6833 )
6811 )
6834
6812
6835 branch = ctx.branch()
6813 branch = ctx.branch()
6836 bheads = repo.branchheads(branch)
6814 bheads = repo.branchheads(branch)
6837 # i18n: column positioning for "hg summary"
6815 # i18n: column positioning for "hg summary"
6838 m = _(b'branch: %s\n') % branch
6816 m = _(b'branch: %s\n') % branch
6839 if branch != b'default':
6817 if branch != b'default':
6840 ui.write(m, label=b'log.branch')
6818 ui.write(m, label=b'log.branch')
6841 else:
6819 else:
6842 ui.status(m, label=b'log.branch')
6820 ui.status(m, label=b'log.branch')
6843
6821
6844 if marks:
6822 if marks:
6845 active = repo._activebookmark
6823 active = repo._activebookmark
6846 # i18n: column positioning for "hg summary"
6824 # i18n: column positioning for "hg summary"
6847 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6825 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6848 if active is not None:
6826 if active is not None:
6849 if active in marks:
6827 if active in marks:
6850 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6828 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6851 marks.remove(active)
6829 marks.remove(active)
6852 else:
6830 else:
6853 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6831 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6854 for m in marks:
6832 for m in marks:
6855 ui.write(b' ' + m, label=b'log.bookmark')
6833 ui.write(b' ' + m, label=b'log.bookmark')
6856 ui.write(b'\n', label=b'log.bookmark')
6834 ui.write(b'\n', label=b'log.bookmark')
6857
6835
6858 status = repo.status(unknown=True)
6836 status = repo.status(unknown=True)
6859
6837
6860 c = repo.dirstate.copies()
6838 c = repo.dirstate.copies()
6861 copied, renamed = [], []
6839 copied, renamed = [], []
6862 for d, s in pycompat.iteritems(c):
6840 for d, s in pycompat.iteritems(c):
6863 if s in status.removed:
6841 if s in status.removed:
6864 status.removed.remove(s)
6842 status.removed.remove(s)
6865 renamed.append(d)
6843 renamed.append(d)
6866 else:
6844 else:
6867 copied.append(d)
6845 copied.append(d)
6868 if d in status.added:
6846 if d in status.added:
6869 status.added.remove(d)
6847 status.added.remove(d)
6870
6848
6871 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6849 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6872
6850
6873 labels = [
6851 labels = [
6874 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6852 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6875 (ui.label(_(b'%d added'), b'status.added'), status.added),
6853 (ui.label(_(b'%d added'), b'status.added'), status.added),
6876 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6854 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6877 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6855 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6878 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6856 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6879 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6857 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6880 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6858 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6881 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6859 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6882 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6860 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6883 ]
6861 ]
6884 t = []
6862 t = []
6885 for l, s in labels:
6863 for l, s in labels:
6886 if s:
6864 if s:
6887 t.append(l % len(s))
6865 t.append(l % len(s))
6888
6866
6889 t = b', '.join(t)
6867 t = b', '.join(t)
6890 cleanworkdir = False
6868 cleanworkdir = False
6891
6869
6892 if repo.vfs.exists(b'graftstate'):
6870 if repo.vfs.exists(b'graftstate'):
6893 t += _(b' (graft in progress)')
6871 t += _(b' (graft in progress)')
6894 if repo.vfs.exists(b'updatestate'):
6872 if repo.vfs.exists(b'updatestate'):
6895 t += _(b' (interrupted update)')
6873 t += _(b' (interrupted update)')
6896 elif len(parents) > 1:
6874 elif len(parents) > 1:
6897 t += _(b' (merge)')
6875 t += _(b' (merge)')
6898 elif branch != parents[0].branch():
6876 elif branch != parents[0].branch():
6899 t += _(b' (new branch)')
6877 t += _(b' (new branch)')
6900 elif parents[0].closesbranch() and pnode in repo.branchheads(
6878 elif parents[0].closesbranch() and pnode in repo.branchheads(
6901 branch, closed=True
6879 branch, closed=True
6902 ):
6880 ):
6903 t += _(b' (head closed)')
6881 t += _(b' (head closed)')
6904 elif not (
6882 elif not (
6905 status.modified
6883 status.modified
6906 or status.added
6884 or status.added
6907 or status.removed
6885 or status.removed
6908 or renamed
6886 or renamed
6909 or copied
6887 or copied
6910 or subs
6888 or subs
6911 ):
6889 ):
6912 t += _(b' (clean)')
6890 t += _(b' (clean)')
6913 cleanworkdir = True
6891 cleanworkdir = True
6914 elif pnode not in bheads:
6892 elif pnode not in bheads:
6915 t += _(b' (new branch head)')
6893 t += _(b' (new branch head)')
6916
6894
6917 if parents:
6895 if parents:
6918 pendingphase = max(p.phase() for p in parents)
6896 pendingphase = max(p.phase() for p in parents)
6919 else:
6897 else:
6920 pendingphase = phases.public
6898 pendingphase = phases.public
6921
6899
6922 if pendingphase > phases.newcommitphase(ui):
6900 if pendingphase > phases.newcommitphase(ui):
6923 t += b' (%s)' % phases.phasenames[pendingphase]
6901 t += b' (%s)' % phases.phasenames[pendingphase]
6924
6902
6925 if cleanworkdir:
6903 if cleanworkdir:
6926 # i18n: column positioning for "hg summary"
6904 # i18n: column positioning for "hg summary"
6927 ui.status(_(b'commit: %s\n') % t.strip())
6905 ui.status(_(b'commit: %s\n') % t.strip())
6928 else:
6906 else:
6929 # i18n: column positioning for "hg summary"
6907 # i18n: column positioning for "hg summary"
6930 ui.write(_(b'commit: %s\n') % t.strip())
6908 ui.write(_(b'commit: %s\n') % t.strip())
6931
6909
6932 # all ancestors of branch heads - all ancestors of parent = new csets
6910 # all ancestors of branch heads - all ancestors of parent = new csets
6933 new = len(
6911 new = len(
6934 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6912 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6935 )
6913 )
6936
6914
6937 if new == 0:
6915 if new == 0:
6938 # i18n: column positioning for "hg summary"
6916 # i18n: column positioning for "hg summary"
6939 ui.status(_(b'update: (current)\n'))
6917 ui.status(_(b'update: (current)\n'))
6940 elif pnode not in bheads:
6918 elif pnode not in bheads:
6941 # i18n: column positioning for "hg summary"
6919 # i18n: column positioning for "hg summary"
6942 ui.write(_(b'update: %d new changesets (update)\n') % new)
6920 ui.write(_(b'update: %d new changesets (update)\n') % new)
6943 else:
6921 else:
6944 # i18n: column positioning for "hg summary"
6922 # i18n: column positioning for "hg summary"
6945 ui.write(
6923 ui.write(
6946 _(b'update: %d new changesets, %d branch heads (merge)\n')
6924 _(b'update: %d new changesets, %d branch heads (merge)\n')
6947 % (new, len(bheads))
6925 % (new, len(bheads))
6948 )
6926 )
6949
6927
6950 t = []
6928 t = []
6951 draft = len(repo.revs(b'draft()'))
6929 draft = len(repo.revs(b'draft()'))
6952 if draft:
6930 if draft:
6953 t.append(_(b'%d draft') % draft)
6931 t.append(_(b'%d draft') % draft)
6954 secret = len(repo.revs(b'secret()'))
6932 secret = len(repo.revs(b'secret()'))
6955 if secret:
6933 if secret:
6956 t.append(_(b'%d secret') % secret)
6934 t.append(_(b'%d secret') % secret)
6957
6935
6958 if draft or secret:
6936 if draft or secret:
6959 ui.status(_(b'phases: %s\n') % b', '.join(t))
6937 ui.status(_(b'phases: %s\n') % b', '.join(t))
6960
6938
6961 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6939 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6962 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6940 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6963 numtrouble = len(repo.revs(trouble + b"()"))
6941 numtrouble = len(repo.revs(trouble + b"()"))
6964 # We write all the possibilities to ease translation
6942 # We write all the possibilities to ease translation
6965 troublemsg = {
6943 troublemsg = {
6966 b"orphan": _(b"orphan: %d changesets"),
6944 b"orphan": _(b"orphan: %d changesets"),
6967 b"contentdivergent": _(b"content-divergent: %d changesets"),
6945 b"contentdivergent": _(b"content-divergent: %d changesets"),
6968 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6946 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6969 }
6947 }
6970 if numtrouble > 0:
6948 if numtrouble > 0:
6971 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6949 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6972
6950
6973 cmdutil.summaryhooks(ui, repo)
6951 cmdutil.summaryhooks(ui, repo)
6974
6952
6975 if opts.get(b'remote'):
6953 if opts.get(b'remote'):
6976 needsincoming, needsoutgoing = True, True
6954 needsincoming, needsoutgoing = True, True
6977 else:
6955 else:
6978 needsincoming, needsoutgoing = False, False
6956 needsincoming, needsoutgoing = False, False
6979 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6957 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6980 if i:
6958 if i:
6981 needsincoming = True
6959 needsincoming = True
6982 if o:
6960 if o:
6983 needsoutgoing = True
6961 needsoutgoing = True
6984 if not needsincoming and not needsoutgoing:
6962 if not needsincoming and not needsoutgoing:
6985 return
6963 return
6986
6964
6987 def getincoming():
6965 def getincoming():
6988 source, branches = hg.parseurl(ui.expandpath(b'default'))
6966 source, branches = hg.parseurl(ui.expandpath(b'default'))
6989 sbranch = branches[0]
6967 sbranch = branches[0]
6990 try:
6968 try:
6991 other = hg.peer(repo, {}, source)
6969 other = hg.peer(repo, {}, source)
6992 except error.RepoError:
6970 except error.RepoError:
6993 if opts.get(b'remote'):
6971 if opts.get(b'remote'):
6994 raise
6972 raise
6995 return source, sbranch, None, None, None
6973 return source, sbranch, None, None, None
6996 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6974 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6997 if revs:
6975 if revs:
6998 revs = [other.lookup(rev) for rev in revs]
6976 revs = [other.lookup(rev) for rev in revs]
6999 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
6977 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7000 repo.ui.pushbuffer()
6978 repo.ui.pushbuffer()
7001 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6979 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7002 repo.ui.popbuffer()
6980 repo.ui.popbuffer()
7003 return source, sbranch, other, commoninc, commoninc[1]
6981 return source, sbranch, other, commoninc, commoninc[1]
7004
6982
7005 if needsincoming:
6983 if needsincoming:
7006 source, sbranch, sother, commoninc, incoming = getincoming()
6984 source, sbranch, sother, commoninc, incoming = getincoming()
7007 else:
6985 else:
7008 source = sbranch = sother = commoninc = incoming = None
6986 source = sbranch = sother = commoninc = incoming = None
7009
6987
7010 def getoutgoing():
6988 def getoutgoing():
7011 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
6989 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7012 dbranch = branches[0]
6990 dbranch = branches[0]
7013 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6991 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7014 if source != dest:
6992 if source != dest:
7015 try:
6993 try:
7016 dother = hg.peer(repo, {}, dest)
6994 dother = hg.peer(repo, {}, dest)
7017 except error.RepoError:
6995 except error.RepoError:
7018 if opts.get(b'remote'):
6996 if opts.get(b'remote'):
7019 raise
6997 raise
7020 return dest, dbranch, None, None
6998 return dest, dbranch, None, None
7021 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
6999 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7022 elif sother is None:
7000 elif sother is None:
7023 # there is no explicit destination peer, but source one is invalid
7001 # there is no explicit destination peer, but source one is invalid
7024 return dest, dbranch, None, None
7002 return dest, dbranch, None, None
7025 else:
7003 else:
7026 dother = sother
7004 dother = sother
7027 if source != dest or (sbranch is not None and sbranch != dbranch):
7005 if source != dest or (sbranch is not None and sbranch != dbranch):
7028 common = None
7006 common = None
7029 else:
7007 else:
7030 common = commoninc
7008 common = commoninc
7031 if revs:
7009 if revs:
7032 revs = [repo.lookup(rev) for rev in revs]
7010 revs = [repo.lookup(rev) for rev in revs]
7033 repo.ui.pushbuffer()
7011 repo.ui.pushbuffer()
7034 outgoing = discovery.findcommonoutgoing(
7012 outgoing = discovery.findcommonoutgoing(
7035 repo, dother, onlyheads=revs, commoninc=common
7013 repo, dother, onlyheads=revs, commoninc=common
7036 )
7014 )
7037 repo.ui.popbuffer()
7015 repo.ui.popbuffer()
7038 return dest, dbranch, dother, outgoing
7016 return dest, dbranch, dother, outgoing
7039
7017
7040 if needsoutgoing:
7018 if needsoutgoing:
7041 dest, dbranch, dother, outgoing = getoutgoing()
7019 dest, dbranch, dother, outgoing = getoutgoing()
7042 else:
7020 else:
7043 dest = dbranch = dother = outgoing = None
7021 dest = dbranch = dother = outgoing = None
7044
7022
7045 if opts.get(b'remote'):
7023 if opts.get(b'remote'):
7046 t = []
7024 t = []
7047 if incoming:
7025 if incoming:
7048 t.append(_(b'1 or more incoming'))
7026 t.append(_(b'1 or more incoming'))
7049 o = outgoing.missing
7027 o = outgoing.missing
7050 if o:
7028 if o:
7051 t.append(_(b'%d outgoing') % len(o))
7029 t.append(_(b'%d outgoing') % len(o))
7052 other = dother or sother
7030 other = dother or sother
7053 if b'bookmarks' in other.listkeys(b'namespaces'):
7031 if b'bookmarks' in other.listkeys(b'namespaces'):
7054 counts = bookmarks.summary(repo, other)
7032 counts = bookmarks.summary(repo, other)
7055 if counts[0] > 0:
7033 if counts[0] > 0:
7056 t.append(_(b'%d incoming bookmarks') % counts[0])
7034 t.append(_(b'%d incoming bookmarks') % counts[0])
7057 if counts[1] > 0:
7035 if counts[1] > 0:
7058 t.append(_(b'%d outgoing bookmarks') % counts[1])
7036 t.append(_(b'%d outgoing bookmarks') % counts[1])
7059
7037
7060 if t:
7038 if t:
7061 # i18n: column positioning for "hg summary"
7039 # i18n: column positioning for "hg summary"
7062 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7040 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7063 else:
7041 else:
7064 # i18n: column positioning for "hg summary"
7042 # i18n: column positioning for "hg summary"
7065 ui.status(_(b'remote: (synced)\n'))
7043 ui.status(_(b'remote: (synced)\n'))
7066
7044
7067 cmdutil.summaryremotehooks(
7045 cmdutil.summaryremotehooks(
7068 ui,
7046 ui,
7069 repo,
7047 repo,
7070 opts,
7048 opts,
7071 (
7049 (
7072 (source, sbranch, sother, commoninc),
7050 (source, sbranch, sother, commoninc),
7073 (dest, dbranch, dother, outgoing),
7051 (dest, dbranch, dother, outgoing),
7074 ),
7052 ),
7075 )
7053 )
7076
7054
7077
7055
7078 @command(
7056 @command(
7079 b'tag',
7057 b'tag',
7080 [
7058 [
7081 (b'f', b'force', None, _(b'force tag')),
7059 (b'f', b'force', None, _(b'force tag')),
7082 (b'l', b'local', None, _(b'make the tag local')),
7060 (b'l', b'local', None, _(b'make the tag local')),
7083 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7061 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7084 (b'', b'remove', None, _(b'remove a tag')),
7062 (b'', b'remove', None, _(b'remove a tag')),
7085 # -l/--local is already there, commitopts cannot be used
7063 # -l/--local is already there, commitopts cannot be used
7086 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7064 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7087 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7065 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7088 ]
7066 ]
7089 + commitopts2,
7067 + commitopts2,
7090 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7068 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7091 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7069 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7092 )
7070 )
7093 def tag(ui, repo, name1, *names, **opts):
7071 def tag(ui, repo, name1, *names, **opts):
7094 """add one or more tags for the current or given revision
7072 """add one or more tags for the current or given revision
7095
7073
7096 Name a particular revision using <name>.
7074 Name a particular revision using <name>.
7097
7075
7098 Tags are used to name particular revisions of the repository and are
7076 Tags are used to name particular revisions of the repository and are
7099 very useful to compare different revisions, to go back to significant
7077 very useful to compare different revisions, to go back to significant
7100 earlier versions or to mark branch points as releases, etc. Changing
7078 earlier versions or to mark branch points as releases, etc. Changing
7101 an existing tag is normally disallowed; use -f/--force to override.
7079 an existing tag is normally disallowed; use -f/--force to override.
7102
7080
7103 If no revision is given, the parent of the working directory is
7081 If no revision is given, the parent of the working directory is
7104 used.
7082 used.
7105
7083
7106 To facilitate version control, distribution, and merging of tags,
7084 To facilitate version control, distribution, and merging of tags,
7107 they are stored as a file named ".hgtags" which is managed similarly
7085 they are stored as a file named ".hgtags" which is managed similarly
7108 to other project files and can be hand-edited if necessary. This
7086 to other project files and can be hand-edited if necessary. This
7109 also means that tagging creates a new commit. The file
7087 also means that tagging creates a new commit. The file
7110 ".hg/localtags" is used for local tags (not shared among
7088 ".hg/localtags" is used for local tags (not shared among
7111 repositories).
7089 repositories).
7112
7090
7113 Tag commits are usually made at the head of a branch. If the parent
7091 Tag commits are usually made at the head of a branch. If the parent
7114 of the working directory is not a branch head, :hg:`tag` aborts; use
7092 of the working directory is not a branch head, :hg:`tag` aborts; use
7115 -f/--force to force the tag commit to be based on a non-head
7093 -f/--force to force the tag commit to be based on a non-head
7116 changeset.
7094 changeset.
7117
7095
7118 See :hg:`help dates` for a list of formats valid for -d/--date.
7096 See :hg:`help dates` for a list of formats valid for -d/--date.
7119
7097
7120 Since tag names have priority over branch names during revision
7098 Since tag names have priority over branch names during revision
7121 lookup, using an existing branch name as a tag name is discouraged.
7099 lookup, using an existing branch name as a tag name is discouraged.
7122
7100
7123 Returns 0 on success.
7101 Returns 0 on success.
7124 """
7102 """
7125 opts = pycompat.byteskwargs(opts)
7103 opts = pycompat.byteskwargs(opts)
7126 with repo.wlock(), repo.lock():
7104 with repo.wlock(), repo.lock():
7127 rev_ = b"."
7105 rev_ = b"."
7128 names = [t.strip() for t in (name1,) + names]
7106 names = [t.strip() for t in (name1,) + names]
7129 if len(names) != len(set(names)):
7107 if len(names) != len(set(names)):
7130 raise error.Abort(_(b'tag names must be unique'))
7108 raise error.Abort(_(b'tag names must be unique'))
7131 for n in names:
7109 for n in names:
7132 scmutil.checknewlabel(repo, n, b'tag')
7110 scmutil.checknewlabel(repo, n, b'tag')
7133 if not n:
7111 if not n:
7134 raise error.Abort(
7112 raise error.Abort(
7135 _(b'tag names cannot consist entirely of whitespace')
7113 _(b'tag names cannot consist entirely of whitespace')
7136 )
7114 )
7137 if opts.get(b'rev') and opts.get(b'remove'):
7115 if opts.get(b'rev') and opts.get(b'remove'):
7138 raise error.Abort(_(b"--rev and --remove are incompatible"))
7116 raise error.Abort(_(b"--rev and --remove are incompatible"))
7139 if opts.get(b'rev'):
7117 if opts.get(b'rev'):
7140 rev_ = opts[b'rev']
7118 rev_ = opts[b'rev']
7141 message = opts.get(b'message')
7119 message = opts.get(b'message')
7142 if opts.get(b'remove'):
7120 if opts.get(b'remove'):
7143 if opts.get(b'local'):
7121 if opts.get(b'local'):
7144 expectedtype = b'local'
7122 expectedtype = b'local'
7145 else:
7123 else:
7146 expectedtype = b'global'
7124 expectedtype = b'global'
7147
7125
7148 for n in names:
7126 for n in names:
7149 if repo.tagtype(n) == b'global':
7127 if repo.tagtype(n) == b'global':
7150 alltags = tagsmod.findglobaltags(ui, repo)
7128 alltags = tagsmod.findglobaltags(ui, repo)
7151 if alltags[n][0] == nullid:
7129 if alltags[n][0] == nullid:
7152 raise error.Abort(_(b"tag '%s' is already removed") % n)
7130 raise error.Abort(_(b"tag '%s' is already removed") % n)
7153 if not repo.tagtype(n):
7131 if not repo.tagtype(n):
7154 raise error.Abort(_(b"tag '%s' does not exist") % n)
7132 raise error.Abort(_(b"tag '%s' does not exist") % n)
7155 if repo.tagtype(n) != expectedtype:
7133 if repo.tagtype(n) != expectedtype:
7156 if expectedtype == b'global':
7134 if expectedtype == b'global':
7157 raise error.Abort(
7135 raise error.Abort(
7158 _(b"tag '%s' is not a global tag") % n
7136 _(b"tag '%s' is not a global tag") % n
7159 )
7137 )
7160 else:
7138 else:
7161 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7139 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7162 rev_ = b'null'
7140 rev_ = b'null'
7163 if not message:
7141 if not message:
7164 # we don't translate commit messages
7142 # we don't translate commit messages
7165 message = b'Removed tag %s' % b', '.join(names)
7143 message = b'Removed tag %s' % b', '.join(names)
7166 elif not opts.get(b'force'):
7144 elif not opts.get(b'force'):
7167 for n in names:
7145 for n in names:
7168 if n in repo.tags():
7146 if n in repo.tags():
7169 raise error.Abort(
7147 raise error.Abort(
7170 _(b"tag '%s' already exists (use -f to force)") % n
7148 _(b"tag '%s' already exists (use -f to force)") % n
7171 )
7149 )
7172 if not opts.get(b'local'):
7150 if not opts.get(b'local'):
7173 p1, p2 = repo.dirstate.parents()
7151 p1, p2 = repo.dirstate.parents()
7174 if p2 != nullid:
7152 if p2 != nullid:
7175 raise error.Abort(_(b'uncommitted merge'))
7153 raise error.Abort(_(b'uncommitted merge'))
7176 bheads = repo.branchheads()
7154 bheads = repo.branchheads()
7177 if not opts.get(b'force') and bheads and p1 not in bheads:
7155 if not opts.get(b'force') and bheads and p1 not in bheads:
7178 raise error.Abort(
7156 raise error.Abort(
7179 _(
7157 _(
7180 b'working directory is not at a branch head '
7158 b'working directory is not at a branch head '
7181 b'(use -f to force)'
7159 b'(use -f to force)'
7182 )
7160 )
7183 )
7161 )
7184 node = scmutil.revsingle(repo, rev_).node()
7162 node = scmutil.revsingle(repo, rev_).node()
7185
7163
7186 if not message:
7164 if not message:
7187 # we don't translate commit messages
7165 # we don't translate commit messages
7188 message = b'Added tag %s for changeset %s' % (
7166 message = b'Added tag %s for changeset %s' % (
7189 b', '.join(names),
7167 b', '.join(names),
7190 short(node),
7168 short(node),
7191 )
7169 )
7192
7170
7193 date = opts.get(b'date')
7171 date = opts.get(b'date')
7194 if date:
7172 if date:
7195 date = dateutil.parsedate(date)
7173 date = dateutil.parsedate(date)
7196
7174
7197 if opts.get(b'remove'):
7175 if opts.get(b'remove'):
7198 editform = b'tag.remove'
7176 editform = b'tag.remove'
7199 else:
7177 else:
7200 editform = b'tag.add'
7178 editform = b'tag.add'
7201 editor = cmdutil.getcommiteditor(
7179 editor = cmdutil.getcommiteditor(
7202 editform=editform, **pycompat.strkwargs(opts)
7180 editform=editform, **pycompat.strkwargs(opts)
7203 )
7181 )
7204
7182
7205 # don't allow tagging the null rev
7183 # don't allow tagging the null rev
7206 if (
7184 if (
7207 not opts.get(b'remove')
7185 not opts.get(b'remove')
7208 and scmutil.revsingle(repo, rev_).rev() == nullrev
7186 and scmutil.revsingle(repo, rev_).rev() == nullrev
7209 ):
7187 ):
7210 raise error.Abort(_(b"cannot tag null revision"))
7188 raise error.Abort(_(b"cannot tag null revision"))
7211
7189
7212 tagsmod.tag(
7190 tagsmod.tag(
7213 repo,
7191 repo,
7214 names,
7192 names,
7215 node,
7193 node,
7216 message,
7194 message,
7217 opts.get(b'local'),
7195 opts.get(b'local'),
7218 opts.get(b'user'),
7196 opts.get(b'user'),
7219 date,
7197 date,
7220 editor=editor,
7198 editor=editor,
7221 )
7199 )
7222
7200
7223
7201
7224 @command(
7202 @command(
7225 b'tags',
7203 b'tags',
7226 formatteropts,
7204 formatteropts,
7227 b'',
7205 b'',
7228 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7206 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7229 intents={INTENT_READONLY},
7207 intents={INTENT_READONLY},
7230 )
7208 )
7231 def tags(ui, repo, **opts):
7209 def tags(ui, repo, **opts):
7232 """list repository tags
7210 """list repository tags
7233
7211
7234 This lists both regular and local tags. When the -v/--verbose
7212 This lists both regular and local tags. When the -v/--verbose
7235 switch is used, a third column "local" is printed for local tags.
7213 switch is used, a third column "local" is printed for local tags.
7236 When the -q/--quiet switch is used, only the tag name is printed.
7214 When the -q/--quiet switch is used, only the tag name is printed.
7237
7215
7238 .. container:: verbose
7216 .. container:: verbose
7239
7217
7240 Template:
7218 Template:
7241
7219
7242 The following keywords are supported in addition to the common template
7220 The following keywords are supported in addition to the common template
7243 keywords and functions such as ``{tag}``. See also
7221 keywords and functions such as ``{tag}``. See also
7244 :hg:`help templates`.
7222 :hg:`help templates`.
7245
7223
7246 :type: String. ``local`` for local tags.
7224 :type: String. ``local`` for local tags.
7247
7225
7248 Returns 0 on success.
7226 Returns 0 on success.
7249 """
7227 """
7250
7228
7251 opts = pycompat.byteskwargs(opts)
7229 opts = pycompat.byteskwargs(opts)
7252 ui.pager(b'tags')
7230 ui.pager(b'tags')
7253 fm = ui.formatter(b'tags', opts)
7231 fm = ui.formatter(b'tags', opts)
7254 hexfunc = fm.hexfunc
7232 hexfunc = fm.hexfunc
7255
7233
7256 for t, n in reversed(repo.tagslist()):
7234 for t, n in reversed(repo.tagslist()):
7257 hn = hexfunc(n)
7235 hn = hexfunc(n)
7258 label = b'tags.normal'
7236 label = b'tags.normal'
7259 tagtype = b''
7237 tagtype = b''
7260 if repo.tagtype(t) == b'local':
7238 if repo.tagtype(t) == b'local':
7261 label = b'tags.local'
7239 label = b'tags.local'
7262 tagtype = b'local'
7240 tagtype = b'local'
7263
7241
7264 fm.startitem()
7242 fm.startitem()
7265 fm.context(repo=repo)
7243 fm.context(repo=repo)
7266 fm.write(b'tag', b'%s', t, label=label)
7244 fm.write(b'tag', b'%s', t, label=label)
7267 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7245 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7268 fm.condwrite(
7246 fm.condwrite(
7269 not ui.quiet,
7247 not ui.quiet,
7270 b'rev node',
7248 b'rev node',
7271 fmt,
7249 fmt,
7272 repo.changelog.rev(n),
7250 repo.changelog.rev(n),
7273 hn,
7251 hn,
7274 label=label,
7252 label=label,
7275 )
7253 )
7276 fm.condwrite(
7254 fm.condwrite(
7277 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7255 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7278 )
7256 )
7279 fm.plain(b'\n')
7257 fm.plain(b'\n')
7280 fm.end()
7258 fm.end()
7281
7259
7282
7260
7283 @command(
7261 @command(
7284 b'tip',
7262 b'tip',
7285 [
7263 [
7286 (b'p', b'patch', None, _(b'show patch')),
7264 (b'p', b'patch', None, _(b'show patch')),
7287 (b'g', b'git', None, _(b'use git extended diff format')),
7265 (b'g', b'git', None, _(b'use git extended diff format')),
7288 ]
7266 ]
7289 + templateopts,
7267 + templateopts,
7290 _(b'[-p] [-g]'),
7268 _(b'[-p] [-g]'),
7291 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7269 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7292 )
7270 )
7293 def tip(ui, repo, **opts):
7271 def tip(ui, repo, **opts):
7294 """show the tip revision (DEPRECATED)
7272 """show the tip revision (DEPRECATED)
7295
7273
7296 The tip revision (usually just called the tip) is the changeset
7274 The tip revision (usually just called the tip) is the changeset
7297 most recently added to the repository (and therefore the most
7275 most recently added to the repository (and therefore the most
7298 recently changed head).
7276 recently changed head).
7299
7277
7300 If you have just made a commit, that commit will be the tip. If
7278 If you have just made a commit, that commit will be the tip. If
7301 you have just pulled changes from another repository, the tip of
7279 you have just pulled changes from another repository, the tip of
7302 that repository becomes the current tip. The "tip" tag is special
7280 that repository becomes the current tip. The "tip" tag is special
7303 and cannot be renamed or assigned to a different changeset.
7281 and cannot be renamed or assigned to a different changeset.
7304
7282
7305 This command is deprecated, please use :hg:`heads` instead.
7283 This command is deprecated, please use :hg:`heads` instead.
7306
7284
7307 Returns 0 on success.
7285 Returns 0 on success.
7308 """
7286 """
7309 opts = pycompat.byteskwargs(opts)
7287 opts = pycompat.byteskwargs(opts)
7310 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7288 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7311 displayer.show(repo[b'tip'])
7289 displayer.show(repo[b'tip'])
7312 displayer.close()
7290 displayer.close()
7313
7291
7314
7292
7315 @command(
7293 @command(
7316 b'unbundle',
7294 b'unbundle',
7317 [
7295 [
7318 (
7296 (
7319 b'u',
7297 b'u',
7320 b'update',
7298 b'update',
7321 None,
7299 None,
7322 _(b'update to new branch head if changesets were unbundled'),
7300 _(b'update to new branch head if changesets were unbundled'),
7323 )
7301 )
7324 ],
7302 ],
7325 _(b'[-u] FILE...'),
7303 _(b'[-u] FILE...'),
7326 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7304 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7327 )
7305 )
7328 def unbundle(ui, repo, fname1, *fnames, **opts):
7306 def unbundle(ui, repo, fname1, *fnames, **opts):
7329 """apply one or more bundle files
7307 """apply one or more bundle files
7330
7308
7331 Apply one or more bundle files generated by :hg:`bundle`.
7309 Apply one or more bundle files generated by :hg:`bundle`.
7332
7310
7333 Returns 0 on success, 1 if an update has unresolved files.
7311 Returns 0 on success, 1 if an update has unresolved files.
7334 """
7312 """
7335 fnames = (fname1,) + fnames
7313 fnames = (fname1,) + fnames
7336
7314
7337 with repo.lock():
7315 with repo.lock():
7338 for fname in fnames:
7316 for fname in fnames:
7339 f = hg.openpath(ui, fname)
7317 f = hg.openpath(ui, fname)
7340 gen = exchange.readbundle(ui, f, fname)
7318 gen = exchange.readbundle(ui, f, fname)
7341 if isinstance(gen, streamclone.streamcloneapplier):
7319 if isinstance(gen, streamclone.streamcloneapplier):
7342 raise error.Abort(
7320 raise error.Abort(
7343 _(
7321 _(
7344 b'packed bundles cannot be applied with '
7322 b'packed bundles cannot be applied with '
7345 b'"hg unbundle"'
7323 b'"hg unbundle"'
7346 ),
7324 ),
7347 hint=_(b'use "hg debugapplystreamclonebundle"'),
7325 hint=_(b'use "hg debugapplystreamclonebundle"'),
7348 )
7326 )
7349 url = b'bundle:' + fname
7327 url = b'bundle:' + fname
7350 try:
7328 try:
7351 txnname = b'unbundle'
7329 txnname = b'unbundle'
7352 if not isinstance(gen, bundle2.unbundle20):
7330 if not isinstance(gen, bundle2.unbundle20):
7353 txnname = b'unbundle\n%s' % util.hidepassword(url)
7331 txnname = b'unbundle\n%s' % util.hidepassword(url)
7354 with repo.transaction(txnname) as tr:
7332 with repo.transaction(txnname) as tr:
7355 op = bundle2.applybundle(
7333 op = bundle2.applybundle(
7356 repo, gen, tr, source=b'unbundle', url=url
7334 repo, gen, tr, source=b'unbundle', url=url
7357 )
7335 )
7358 except error.BundleUnknownFeatureError as exc:
7336 except error.BundleUnknownFeatureError as exc:
7359 raise error.Abort(
7337 raise error.Abort(
7360 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7338 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7361 hint=_(
7339 hint=_(
7362 b"see https://mercurial-scm.org/"
7340 b"see https://mercurial-scm.org/"
7363 b"wiki/BundleFeature for more "
7341 b"wiki/BundleFeature for more "
7364 b"information"
7342 b"information"
7365 ),
7343 ),
7366 )
7344 )
7367 modheads = bundle2.combinechangegroupresults(op)
7345 modheads = bundle2.combinechangegroupresults(op)
7368
7346
7369 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7347 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7370
7348
7371
7349
7372 @command(
7350 @command(
7373 b'unshelve',
7351 b'unshelve',
7374 [
7352 [
7375 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7353 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7376 (
7354 (
7377 b'c',
7355 b'c',
7378 b'continue',
7356 b'continue',
7379 None,
7357 None,
7380 _(b'continue an incomplete unshelve operation'),
7358 _(b'continue an incomplete unshelve operation'),
7381 ),
7359 ),
7382 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7360 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7383 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7361 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7384 (
7362 (
7385 b'n',
7363 b'n',
7386 b'name',
7364 b'name',
7387 b'',
7365 b'',
7388 _(b'restore shelved change with given name'),
7366 _(b'restore shelved change with given name'),
7389 _(b'NAME'),
7367 _(b'NAME'),
7390 ),
7368 ),
7391 (b't', b'tool', b'', _(b'specify merge tool')),
7369 (b't', b'tool', b'', _(b'specify merge tool')),
7392 (
7370 (
7393 b'',
7371 b'',
7394 b'date',
7372 b'date',
7395 b'',
7373 b'',
7396 _(b'set date for temporary commits (DEPRECATED)'),
7374 _(b'set date for temporary commits (DEPRECATED)'),
7397 _(b'DATE'),
7375 _(b'DATE'),
7398 ),
7376 ),
7399 ],
7377 ],
7400 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7378 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7401 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7379 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7402 )
7380 )
7403 def unshelve(ui, repo, *shelved, **opts):
7381 def unshelve(ui, repo, *shelved, **opts):
7404 """restore a shelved change to the working directory
7382 """restore a shelved change to the working directory
7405
7383
7406 This command accepts an optional name of a shelved change to
7384 This command accepts an optional name of a shelved change to
7407 restore. If none is given, the most recent shelved change is used.
7385 restore. If none is given, the most recent shelved change is used.
7408
7386
7409 If a shelved change is applied successfully, the bundle that
7387 If a shelved change is applied successfully, the bundle that
7410 contains the shelved changes is moved to a backup location
7388 contains the shelved changes is moved to a backup location
7411 (.hg/shelve-backup).
7389 (.hg/shelve-backup).
7412
7390
7413 Since you can restore a shelved change on top of an arbitrary
7391 Since you can restore a shelved change on top of an arbitrary
7414 commit, it is possible that unshelving will result in a conflict
7392 commit, it is possible that unshelving will result in a conflict
7415 between your changes and the commits you are unshelving onto. If
7393 between your changes and the commits you are unshelving onto. If
7416 this occurs, you must resolve the conflict, then use
7394 this occurs, you must resolve the conflict, then use
7417 ``--continue`` to complete the unshelve operation. (The bundle
7395 ``--continue`` to complete the unshelve operation. (The bundle
7418 will not be moved until you successfully complete the unshelve.)
7396 will not be moved until you successfully complete the unshelve.)
7419
7397
7420 (Alternatively, you can use ``--abort`` to abandon an unshelve
7398 (Alternatively, you can use ``--abort`` to abandon an unshelve
7421 that causes a conflict. This reverts the unshelved changes, and
7399 that causes a conflict. This reverts the unshelved changes, and
7422 leaves the bundle in place.)
7400 leaves the bundle in place.)
7423
7401
7424 If bare shelved change (without interactive, include and exclude
7402 If bare shelved change (without interactive, include and exclude
7425 option) was done on newly created branch it would restore branch
7403 option) was done on newly created branch it would restore branch
7426 information to the working directory.
7404 information to the working directory.
7427
7405
7428 After a successful unshelve, the shelved changes are stored in a
7406 After a successful unshelve, the shelved changes are stored in a
7429 backup directory. Only the N most recent backups are kept. N
7407 backup directory. Only the N most recent backups are kept. N
7430 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7408 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7431 configuration option.
7409 configuration option.
7432
7410
7433 .. container:: verbose
7411 .. container:: verbose
7434
7412
7435 Timestamp in seconds is used to decide order of backups. More
7413 Timestamp in seconds is used to decide order of backups. More
7436 than ``maxbackups`` backups are kept, if same timestamp
7414 than ``maxbackups`` backups are kept, if same timestamp
7437 prevents from deciding exact order of them, for safety.
7415 prevents from deciding exact order of them, for safety.
7438
7416
7439 Selected changes can be unshelved with ``--interactive`` flag.
7417 Selected changes can be unshelved with ``--interactive`` flag.
7440 The working directory is updated with the selected changes, and
7418 The working directory is updated with the selected changes, and
7441 only the unselected changes remain shelved.
7419 only the unselected changes remain shelved.
7442 Note: The whole shelve is applied to working directory first before
7420 Note: The whole shelve is applied to working directory first before
7443 running interactively. So, this will bring up all the conflicts between
7421 running interactively. So, this will bring up all the conflicts between
7444 working directory and the shelve, irrespective of which changes will be
7422 working directory and the shelve, irrespective of which changes will be
7445 unshelved.
7423 unshelved.
7446 """
7424 """
7447 with repo.wlock():
7425 with repo.wlock():
7448 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7426 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7449
7427
7450
7428
7451 statemod.addunfinished(
7429 statemod.addunfinished(
7452 b'unshelve',
7430 b'unshelve',
7453 fname=b'shelvedstate',
7431 fname=b'shelvedstate',
7454 continueflag=True,
7432 continueflag=True,
7455 abortfunc=shelvemod.hgabortunshelve,
7433 abortfunc=shelvemod.hgabortunshelve,
7456 continuefunc=shelvemod.hgcontinueunshelve,
7434 continuefunc=shelvemod.hgcontinueunshelve,
7457 cmdmsg=_(b'unshelve already in progress'),
7435 cmdmsg=_(b'unshelve already in progress'),
7458 )
7436 )
7459
7437
7460
7438
7461 @command(
7439 @command(
7462 b'update|up|checkout|co',
7440 b'update|up|checkout|co',
7463 [
7441 [
7464 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7442 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7465 (b'c', b'check', None, _(b'require clean working directory')),
7443 (b'c', b'check', None, _(b'require clean working directory')),
7466 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7444 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7467 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7445 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7468 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7446 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7469 ]
7447 ]
7470 + mergetoolopts,
7448 + mergetoolopts,
7471 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7449 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7472 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7450 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7473 helpbasic=True,
7451 helpbasic=True,
7474 )
7452 )
7475 def update(ui, repo, node=None, **opts):
7453 def update(ui, repo, node=None, **opts):
7476 """update working directory (or switch revisions)
7454 """update working directory (or switch revisions)
7477
7455
7478 Update the repository's working directory to the specified
7456 Update the repository's working directory to the specified
7479 changeset. If no changeset is specified, update to the tip of the
7457 changeset. If no changeset is specified, update to the tip of the
7480 current named branch and move the active bookmark (see :hg:`help
7458 current named branch and move the active bookmark (see :hg:`help
7481 bookmarks`).
7459 bookmarks`).
7482
7460
7483 Update sets the working directory's parent revision to the specified
7461 Update sets the working directory's parent revision to the specified
7484 changeset (see :hg:`help parents`).
7462 changeset (see :hg:`help parents`).
7485
7463
7486 If the changeset is not a descendant or ancestor of the working
7464 If the changeset is not a descendant or ancestor of the working
7487 directory's parent and there are uncommitted changes, the update is
7465 directory's parent and there are uncommitted changes, the update is
7488 aborted. With the -c/--check option, the working directory is checked
7466 aborted. With the -c/--check option, the working directory is checked
7489 for uncommitted changes; if none are found, the working directory is
7467 for uncommitted changes; if none are found, the working directory is
7490 updated to the specified changeset.
7468 updated to the specified changeset.
7491
7469
7492 .. container:: verbose
7470 .. container:: verbose
7493
7471
7494 The -C/--clean, -c/--check, and -m/--merge options control what
7472 The -C/--clean, -c/--check, and -m/--merge options control what
7495 happens if the working directory contains uncommitted changes.
7473 happens if the working directory contains uncommitted changes.
7496 At most of one of them can be specified.
7474 At most of one of them can be specified.
7497
7475
7498 1. If no option is specified, and if
7476 1. If no option is specified, and if
7499 the requested changeset is an ancestor or descendant of
7477 the requested changeset is an ancestor or descendant of
7500 the working directory's parent, the uncommitted changes
7478 the working directory's parent, the uncommitted changes
7501 are merged into the requested changeset and the merged
7479 are merged into the requested changeset and the merged
7502 result is left uncommitted. If the requested changeset is
7480 result is left uncommitted. If the requested changeset is
7503 not an ancestor or descendant (that is, it is on another
7481 not an ancestor or descendant (that is, it is on another
7504 branch), the update is aborted and the uncommitted changes
7482 branch), the update is aborted and the uncommitted changes
7505 are preserved.
7483 are preserved.
7506
7484
7507 2. With the -m/--merge option, the update is allowed even if the
7485 2. With the -m/--merge option, the update is allowed even if the
7508 requested changeset is not an ancestor or descendant of
7486 requested changeset is not an ancestor or descendant of
7509 the working directory's parent.
7487 the working directory's parent.
7510
7488
7511 3. With the -c/--check option, the update is aborted and the
7489 3. With the -c/--check option, the update is aborted and the
7512 uncommitted changes are preserved.
7490 uncommitted changes are preserved.
7513
7491
7514 4. With the -C/--clean option, uncommitted changes are discarded and
7492 4. With the -C/--clean option, uncommitted changes are discarded and
7515 the working directory is updated to the requested changeset.
7493 the working directory is updated to the requested changeset.
7516
7494
7517 To cancel an uncommitted merge (and lose your changes), use
7495 To cancel an uncommitted merge (and lose your changes), use
7518 :hg:`merge --abort`.
7496 :hg:`merge --abort`.
7519
7497
7520 Use null as the changeset to remove the working directory (like
7498 Use null as the changeset to remove the working directory (like
7521 :hg:`clone -U`).
7499 :hg:`clone -U`).
7522
7500
7523 If you want to revert just one file to an older revision, use
7501 If you want to revert just one file to an older revision, use
7524 :hg:`revert [-r REV] NAME`.
7502 :hg:`revert [-r REV] NAME`.
7525
7503
7526 See :hg:`help dates` for a list of formats valid for -d/--date.
7504 See :hg:`help dates` for a list of formats valid for -d/--date.
7527
7505
7528 Returns 0 on success, 1 if there are unresolved files.
7506 Returns 0 on success, 1 if there are unresolved files.
7529 """
7507 """
7530 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7508 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7531 rev = opts.get('rev')
7509 rev = opts.get('rev')
7532 date = opts.get('date')
7510 date = opts.get('date')
7533 clean = opts.get('clean')
7511 clean = opts.get('clean')
7534 check = opts.get('check')
7512 check = opts.get('check')
7535 merge = opts.get('merge')
7513 merge = opts.get('merge')
7536 if rev and node:
7514 if rev and node:
7537 raise error.Abort(_(b"please specify just one revision"))
7515 raise error.Abort(_(b"please specify just one revision"))
7538
7516
7539 if ui.configbool(b'commands', b'update.requiredest'):
7517 if ui.configbool(b'commands', b'update.requiredest'):
7540 if not node and not rev and not date:
7518 if not node and not rev and not date:
7541 raise error.Abort(
7519 raise error.Abort(
7542 _(b'you must specify a destination'),
7520 _(b'you must specify a destination'),
7543 hint=_(b'for example: hg update ".::"'),
7521 hint=_(b'for example: hg update ".::"'),
7544 )
7522 )
7545
7523
7546 if rev is None or rev == b'':
7524 if rev is None or rev == b'':
7547 rev = node
7525 rev = node
7548
7526
7549 if date and rev is not None:
7527 if date and rev is not None:
7550 raise error.Abort(_(b"you can't specify a revision and a date"))
7528 raise error.Abort(_(b"you can't specify a revision and a date"))
7551
7529
7552 updatecheck = None
7530 updatecheck = None
7553 if check:
7531 if check:
7554 updatecheck = b'abort'
7532 updatecheck = b'abort'
7555 elif merge:
7533 elif merge:
7556 updatecheck = b'none'
7534 updatecheck = b'none'
7557
7535
7558 with repo.wlock():
7536 with repo.wlock():
7559 cmdutil.clearunfinished(repo)
7537 cmdutil.clearunfinished(repo)
7560 if date:
7538 if date:
7561 rev = cmdutil.finddate(ui, repo, date)
7539 rev = cmdutil.finddate(ui, repo, date)
7562
7540
7563 # if we defined a bookmark, we have to remember the original name
7541 # if we defined a bookmark, we have to remember the original name
7564 brev = rev
7542 brev = rev
7565 if rev:
7543 if rev:
7566 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7544 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7567 ctx = scmutil.revsingle(repo, rev, default=None)
7545 ctx = scmutil.revsingle(repo, rev, default=None)
7568 rev = ctx.rev()
7546 rev = ctx.rev()
7569 hidden = ctx.hidden()
7547 hidden = ctx.hidden()
7570 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7548 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7571 with ui.configoverride(overrides, b'update'):
7549 with ui.configoverride(overrides, b'update'):
7572 ret = hg.updatetotally(
7550 ret = hg.updatetotally(
7573 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7551 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7574 )
7552 )
7575 if hidden:
7553 if hidden:
7576 ctxstr = ctx.hex()[:12]
7554 ctxstr = ctx.hex()[:12]
7577 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7555 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7578
7556
7579 if ctx.obsolete():
7557 if ctx.obsolete():
7580 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7558 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7581 ui.warn(b"(%s)\n" % obsfatemsg)
7559 ui.warn(b"(%s)\n" % obsfatemsg)
7582 return ret
7560 return ret
7583
7561
7584
7562
7585 @command(
7563 @command(
7586 b'verify',
7564 b'verify',
7587 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7565 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7588 helpcategory=command.CATEGORY_MAINTENANCE,
7566 helpcategory=command.CATEGORY_MAINTENANCE,
7589 )
7567 )
7590 def verify(ui, repo, **opts):
7568 def verify(ui, repo, **opts):
7591 """verify the integrity of the repository
7569 """verify the integrity of the repository
7592
7570
7593 Verify the integrity of the current repository.
7571 Verify the integrity of the current repository.
7594
7572
7595 This will perform an extensive check of the repository's
7573 This will perform an extensive check of the repository's
7596 integrity, validating the hashes and checksums of each entry in
7574 integrity, validating the hashes and checksums of each entry in
7597 the changelog, manifest, and tracked files, as well as the
7575 the changelog, manifest, and tracked files, as well as the
7598 integrity of their crosslinks and indices.
7576 integrity of their crosslinks and indices.
7599
7577
7600 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7578 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7601 for more information about recovery from corruption of the
7579 for more information about recovery from corruption of the
7602 repository.
7580 repository.
7603
7581
7604 Returns 0 on success, 1 if errors are encountered.
7582 Returns 0 on success, 1 if errors are encountered.
7605 """
7583 """
7606 opts = pycompat.byteskwargs(opts)
7584 opts = pycompat.byteskwargs(opts)
7607
7585
7608 level = None
7586 level = None
7609 if opts[b'full']:
7587 if opts[b'full']:
7610 level = verifymod.VERIFY_FULL
7588 level = verifymod.VERIFY_FULL
7611 return hg.verify(repo, level)
7589 return hg.verify(repo, level)
7612
7590
7613
7591
7614 @command(
7592 @command(
7615 b'version',
7593 b'version',
7616 [] + formatteropts,
7594 [] + formatteropts,
7617 helpcategory=command.CATEGORY_HELP,
7595 helpcategory=command.CATEGORY_HELP,
7618 norepo=True,
7596 norepo=True,
7619 intents={INTENT_READONLY},
7597 intents={INTENT_READONLY},
7620 )
7598 )
7621 def version_(ui, **opts):
7599 def version_(ui, **opts):
7622 """output version and copyright information
7600 """output version and copyright information
7623
7601
7624 .. container:: verbose
7602 .. container:: verbose
7625
7603
7626 Template:
7604 Template:
7627
7605
7628 The following keywords are supported. See also :hg:`help templates`.
7606 The following keywords are supported. See also :hg:`help templates`.
7629
7607
7630 :extensions: List of extensions.
7608 :extensions: List of extensions.
7631 :ver: String. Version number.
7609 :ver: String. Version number.
7632
7610
7633 And each entry of ``{extensions}`` provides the following sub-keywords
7611 And each entry of ``{extensions}`` provides the following sub-keywords
7634 in addition to ``{ver}``.
7612 in addition to ``{ver}``.
7635
7613
7636 :bundled: Boolean. True if included in the release.
7614 :bundled: Boolean. True if included in the release.
7637 :name: String. Extension name.
7615 :name: String. Extension name.
7638 """
7616 """
7639 opts = pycompat.byteskwargs(opts)
7617 opts = pycompat.byteskwargs(opts)
7640 if ui.verbose:
7618 if ui.verbose:
7641 ui.pager(b'version')
7619 ui.pager(b'version')
7642 fm = ui.formatter(b"version", opts)
7620 fm = ui.formatter(b"version", opts)
7643 fm.startitem()
7621 fm.startitem()
7644 fm.write(
7622 fm.write(
7645 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7623 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7646 )
7624 )
7647 license = _(
7625 license = _(
7648 b"(see https://mercurial-scm.org for more information)\n"
7626 b"(see https://mercurial-scm.org for more information)\n"
7649 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7627 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7650 b"This is free software; see the source for copying conditions. "
7628 b"This is free software; see the source for copying conditions. "
7651 b"There is NO\nwarranty; "
7629 b"There is NO\nwarranty; "
7652 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7630 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7653 )
7631 )
7654 if not ui.quiet:
7632 if not ui.quiet:
7655 fm.plain(license)
7633 fm.plain(license)
7656
7634
7657 if ui.verbose:
7635 if ui.verbose:
7658 fm.plain(_(b"\nEnabled extensions:\n\n"))
7636 fm.plain(_(b"\nEnabled extensions:\n\n"))
7659 # format names and versions into columns
7637 # format names and versions into columns
7660 names = []
7638 names = []
7661 vers = []
7639 vers = []
7662 isinternals = []
7640 isinternals = []
7663 for name, module in sorted(extensions.extensions()):
7641 for name, module in sorted(extensions.extensions()):
7664 names.append(name)
7642 names.append(name)
7665 vers.append(extensions.moduleversion(module) or None)
7643 vers.append(extensions.moduleversion(module) or None)
7666 isinternals.append(extensions.ismoduleinternal(module))
7644 isinternals.append(extensions.ismoduleinternal(module))
7667 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7645 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7668 if names:
7646 if names:
7669 namefmt = b" %%-%ds " % max(len(n) for n in names)
7647 namefmt = b" %%-%ds " % max(len(n) for n in names)
7670 places = [_(b"external"), _(b"internal")]
7648 places = [_(b"external"), _(b"internal")]
7671 for n, v, p in zip(names, vers, isinternals):
7649 for n, v, p in zip(names, vers, isinternals):
7672 fn.startitem()
7650 fn.startitem()
7673 fn.condwrite(ui.verbose, b"name", namefmt, n)
7651 fn.condwrite(ui.verbose, b"name", namefmt, n)
7674 if ui.verbose:
7652 if ui.verbose:
7675 fn.plain(b"%s " % places[p])
7653 fn.plain(b"%s " % places[p])
7676 fn.data(bundled=p)
7654 fn.data(bundled=p)
7677 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7655 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7678 if ui.verbose:
7656 if ui.verbose:
7679 fn.plain(b"\n")
7657 fn.plain(b"\n")
7680 fn.end()
7658 fn.end()
7681 fm.end()
7659 fm.end()
7682
7660
7683
7661
7684 def loadcmdtable(ui, name, cmdtable):
7662 def loadcmdtable(ui, name, cmdtable):
7685 """Load command functions from specified cmdtable
7663 """Load command functions from specified cmdtable
7686 """
7664 """
7687 overrides = [cmd for cmd in cmdtable if cmd in table]
7665 overrides = [cmd for cmd in cmdtable if cmd in table]
7688 if overrides:
7666 if overrides:
7689 ui.warn(
7667 ui.warn(
7690 _(b"extension '%s' overrides commands: %s\n")
7668 _(b"extension '%s' overrides commands: %s\n")
7691 % (name, b" ".join(overrides))
7669 % (name, b" ".join(overrides))
7692 )
7670 )
7693 table.update(cmdtable)
7671 table.update(cmdtable)
@@ -1,196 +1,224 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 match as matchmod,
18 pycompat,
18 pycompat,
19 scmutil,
19 scmutil,
20 util,
20 util,
21 )
21 )
22
22
23
23
24 def matchlines(body, regexp):
24 def matchlines(body, regexp):
25 begin = 0
25 begin = 0
26 linenum = 0
26 linenum = 0
27 while begin < len(body):
27 while begin < len(body):
28 match = regexp.search(body, begin)
28 match = regexp.search(body, begin)
29 if not match:
29 if not match:
30 break
30 break
31 mstart, mend = match.span()
31 mstart, mend = match.span()
32 linenum += body.count(b'\n', begin, mstart) + 1
32 linenum += body.count(b'\n', begin, mstart) + 1
33 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
33 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
34 begin = body.find(b'\n', mend) + 1 or len(body) + 1
34 begin = body.find(b'\n', mend) + 1 or len(body) + 1
35 lend = begin - 1
35 lend = begin - 1
36 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
36 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
37
37
38
38
39 class linestate(object):
39 class linestate(object):
40 def __init__(self, line, linenum, colstart, colend):
40 def __init__(self, line, linenum, colstart, colend):
41 self.line = line
41 self.line = line
42 self.linenum = linenum
42 self.linenum = linenum
43 self.colstart = colstart
43 self.colstart = colstart
44 self.colend = colend
44 self.colend = colend
45
45
46 def __hash__(self):
46 def __hash__(self):
47 return hash(self.line)
47 return hash(self.line)
48
48
49 def __eq__(self, other):
49 def __eq__(self, other):
50 return self.line == other.line
50 return self.line == other.line
51
51
52 def findpos(self, regexp):
52 def findpos(self, regexp):
53 """Iterate all (start, end) indices of matches"""
53 """Iterate all (start, end) indices of matches"""
54 yield self.colstart, self.colend
54 yield self.colstart, self.colend
55 p = self.colend
55 p = self.colend
56 while p < len(self.line):
56 while p < len(self.line):
57 m = regexp.search(self.line, p)
57 m = regexp.search(self.line, p)
58 if not m:
58 if not m:
59 break
59 break
60 if m.end() == p:
60 if m.end() == p:
61 p += 1
61 p += 1
62 else:
62 else:
63 yield m.span()
63 yield m.span()
64 p = m.end()
64 p = m.end()
65
65
66
66
67 def difflinestates(a, b):
67 def difflinestates(a, b):
68 sm = difflib.SequenceMatcher(None, a, b)
68 sm = difflib.SequenceMatcher(None, a, b)
69 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
69 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
70 if tag == 'insert':
70 if tag == 'insert':
71 for i in pycompat.xrange(blo, bhi):
71 for i in pycompat.xrange(blo, bhi):
72 yield (b'+', b[i])
72 yield (b'+', b[i])
73 elif tag == 'delete':
73 elif tag == 'delete':
74 for i in pycompat.xrange(alo, ahi):
74 for i in pycompat.xrange(alo, ahi):
75 yield (b'-', a[i])
75 yield (b'-', a[i])
76 elif tag == 'replace':
76 elif tag == 'replace':
77 for i in pycompat.xrange(alo, ahi):
77 for i in pycompat.xrange(alo, ahi):
78 yield (b'-', a[i])
78 yield (b'-', a[i])
79 for i in pycompat.xrange(blo, bhi):
79 for i in pycompat.xrange(blo, bhi):
80 yield (b'+', b[i])
80 yield (b'+', b[i])
81
81
82
82
83 class grepsearcher(object):
83 class grepsearcher(object):
84 """Search files and revisions for lines matching the given pattern
84 """Search files and revisions for lines matching the given pattern
85
85
86 Options:
86 Options:
87 - all_files to search unchanged files at that revision.
87 - all_files to search unchanged files at that revision.
88 - diff to search files in the parent revision so diffs can be generated.
88 - diff to search files in the parent revision so diffs can be generated.
89 - follow to skip files across copies and renames.
89 - follow to skip files across copies and renames.
90 """
90 """
91
91
92 def __init__(
92 def __init__(
93 self, ui, repo, regexp, all_files=False, diff=False, follow=False
93 self, ui, repo, regexp, all_files=False, diff=False, follow=False
94 ):
94 ):
95 self._ui = ui
95 self._ui = ui
96 self._repo = repo
96 self._repo = repo
97 self._regexp = regexp
97 self._regexp = regexp
98 self._all_files = all_files
98 self._all_files = all_files
99 self._diff = diff
99 self._diff = diff
100 self._follow = follow
100 self._follow = follow
101
101
102 self._getfile = util.lrucachefunc(repo.file)
102 self._getfile = util.lrucachefunc(repo.file)
103 self._getrenamed = scmutil.getrenamedfn(repo)
103 self._getrenamed = scmutil.getrenamedfn(repo)
104
104
105 self._matches = {}
105 self._matches = {}
106 self._copies = {}
106 self._copies = {}
107 self._skip = set()
107 self._skip = set()
108 self._revfiles = {}
108 self._revfiles = {}
109
109
110 def skipfile(self, fn, rev):
110 def skipfile(self, fn, rev):
111 """Exclude the given file (and the copy at the specified revision)
111 """Exclude the given file (and the copy at the specified revision)
112 from future search"""
112 from future search"""
113 copy = self._copies.get(rev, {}).get(fn)
113 copy = self._copies.get(rev, {}).get(fn)
114 self._skip.add(fn)
114 self._skip.add(fn)
115 if copy:
115 if copy:
116 self._skip.add(copy)
116 self._skip.add(copy)
117
117
118 def searchfiles(self, revs, makefilematcher):
119 """Walk files and revisions to yield (fn, ctx, pstates, states)
120 matches
121
122 states is a list of linestate objects. pstates may be empty unless
123 diff is True.
124 """
125 for ctx in scmutil.walkchangerevs(
126 self._repo, revs, makefilematcher, self._prep
127 ):
128 rev = ctx.rev()
129 parent = ctx.p1().rev()
130 for fn in sorted(self._revfiles.get(rev, [])):
131 states = self._matches[rev][fn]
132 copy = self._copies.get(rev, {}).get(fn)
133 if fn in self._skip:
134 if copy:
135 self._skip.add(copy)
136 continue
137 pstates = self._matches.get(parent, {}).get(copy or fn, [])
138 if pstates or states:
139 yield fn, ctx, pstates, states
140 del self._revfiles[rev]
141 # We will keep the matches dict for the duration of the window
142 # clear the matches dict once the window is over
143 if not self._revfiles:
144 self._matches.clear()
145
118 def _grepbody(self, fn, rev, body):
146 def _grepbody(self, fn, rev, body):
119 self._matches[rev].setdefault(fn, [])
147 self._matches[rev].setdefault(fn, [])
120 m = self._matches[rev][fn]
148 m = self._matches[rev][fn]
121 if body is None:
149 if body is None:
122 return
150 return
123
151
124 for lnum, cstart, cend, line in matchlines(body, self._regexp):
152 for lnum, cstart, cend, line in matchlines(body, self._regexp):
125 s = linestate(line, lnum, cstart, cend)
153 s = linestate(line, lnum, cstart, cend)
126 m.append(s)
154 m.append(s)
127
155
128 def _readfile(self, ctx, fn):
156 def _readfile(self, ctx, fn):
129 rev = ctx.rev()
157 rev = ctx.rev()
130 if rev is None:
158 if rev is None:
131 fctx = ctx[fn]
159 fctx = ctx[fn]
132 try:
160 try:
133 return fctx.data()
161 return fctx.data()
134 except IOError as e:
162 except IOError as e:
135 if e.errno != errno.ENOENT:
163 if e.errno != errno.ENOENT:
136 raise
164 raise
137 else:
165 else:
138 flog = self._getfile(fn)
166 flog = self._getfile(fn)
139 fnode = ctx.filenode(fn)
167 fnode = ctx.filenode(fn)
140 try:
168 try:
141 return flog.read(fnode)
169 return flog.read(fnode)
142 except error.CensoredNodeError:
170 except error.CensoredNodeError:
143 self._ui.warn(
171 self._ui.warn(
144 _(
172 _(
145 b'cannot search in censored file: '
173 b'cannot search in censored file: '
146 b'%(filename)s:%(revnum)s\n'
174 b'%(filename)s:%(revnum)s\n'
147 )
175 )
148 % {b'filename': fn, b'revnum': pycompat.bytestr(rev)}
176 % {b'filename': fn, b'revnum': pycompat.bytestr(rev)}
149 )
177 )
150
178
151 def _prep(self, ctx, fmatch):
179 def _prep(self, ctx, fmatch):
152 rev = ctx.rev()
180 rev = ctx.rev()
153 pctx = ctx.p1()
181 pctx = ctx.p1()
154 self._matches.setdefault(rev, {})
182 self._matches.setdefault(rev, {})
155 if self._diff:
183 if self._diff:
156 parent = pctx.rev()
184 parent = pctx.rev()
157 self._matches.setdefault(parent, {})
185 self._matches.setdefault(parent, {})
158 files = self._revfiles.setdefault(rev, [])
186 files = self._revfiles.setdefault(rev, [])
159 if rev is None:
187 if rev is None:
160 # in `hg grep pattern`, 2/3 of the time is spent is spent in
188 # in `hg grep pattern`, 2/3 of the time is spent is spent in
161 # pathauditor checks without this in mozilla-central
189 # pathauditor checks without this in mozilla-central
162 contextmanager = self._repo.wvfs.audit.cached
190 contextmanager = self._repo.wvfs.audit.cached
163 else:
191 else:
164 contextmanager = util.nullcontextmanager
192 contextmanager = util.nullcontextmanager
165 with contextmanager():
193 with contextmanager():
166 # TODO: maybe better to warn missing files?
194 # TODO: maybe better to warn missing files?
167 if self._all_files:
195 if self._all_files:
168 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
196 fmatch = matchmod.badmatch(fmatch, lambda f, msg: None)
169 filenames = ctx.matches(fmatch)
197 filenames = ctx.matches(fmatch)
170 else:
198 else:
171 filenames = (f for f in ctx.files() if fmatch(f))
199 filenames = (f for f in ctx.files() if fmatch(f))
172 for fn in filenames:
200 for fn in filenames:
173 # fn might not exist in the revision (could be a file removed by
201 # fn might not exist in the revision (could be a file removed by
174 # the revision). We could check `fn not in ctx` even when rev is
202 # the revision). We could check `fn not in ctx` even when rev is
175 # None, but it's less racy to protect againt that in readfile.
203 # None, but it's less racy to protect againt that in readfile.
176 if rev is not None and fn not in ctx:
204 if rev is not None and fn not in ctx:
177 continue
205 continue
178
206
179 copy = None
207 copy = None
180 if self._follow:
208 if self._follow:
181 copy = self._getrenamed(fn, rev)
209 copy = self._getrenamed(fn, rev)
182 if copy:
210 if copy:
183 self._copies.setdefault(rev, {})[fn] = copy
211 self._copies.setdefault(rev, {})[fn] = copy
184 if fn in self._skip:
212 if fn in self._skip:
185 self._skip.add(copy)
213 self._skip.add(copy)
186 if fn in self._skip:
214 if fn in self._skip:
187 continue
215 continue
188 files.append(fn)
216 files.append(fn)
189
217
190 if fn not in self._matches[rev]:
218 if fn not in self._matches[rev]:
191 self._grepbody(fn, rev, self._readfile(ctx, fn))
219 self._grepbody(fn, rev, self._readfile(ctx, fn))
192
220
193 if self._diff:
221 if self._diff:
194 pfn = copy or fn
222 pfn = copy or fn
195 if pfn not in self._matches[parent] and pfn in pctx:
223 if pfn not in self._matches[parent] and pfn in pctx:
196 self._grepbody(pfn, parent, self._readfile(pctx, pfn))
224 self._grepbody(pfn, parent, self._readfile(pctx, pfn))
General Comments 0
You need to be logged in to leave comments. Login now