##// END OF EJS Templates
backout: leverage cmdutil.check_incompatible_arguments()...
Martin von Zweigbergk -
r46331:693da1b9 default
parent child Browse files
Show More
@@ -1,7671 +1,7668 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 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
772 opts = pycompat.byteskwargs(opts)
773 opts = pycompat.byteskwargs(opts)
773 if opts.get(b'commit') and opts.get(b'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'):
776 raise error.Abort(_(b"cannot use --merge with --no-commit"))
777
774
778 if rev and node:
775 if rev and node:
779 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
780
777
781 if not rev:
778 if not rev:
782 rev = node
779 rev = node
783
780
784 if not rev:
781 if not rev:
785 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
786
783
787 date = opts.get(b'date')
784 date = opts.get(b'date')
788 if date:
785 if date:
789 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
790
787
791 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
792 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
793 ctx = scmutil.revsingle(repo, rev)
790 ctx = scmutil.revsingle(repo, rev)
794 node = ctx.node()
791 node = ctx.node()
795
792
796 op1, op2 = repo.dirstate.parents()
793 op1, op2 = repo.dirstate.parents()
797 if not repo.changelog.isancestor(node, op1):
794 if not repo.changelog.isancestor(node, op1):
798 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
799
796
800 p1, p2 = repo.changelog.parents(node)
797 p1, p2 = repo.changelog.parents(node)
801 if p1 == nullid:
798 if p1 == nullid:
802 raise error.Abort(_(b'cannot backout a change with no parents'))
799 raise error.Abort(_(b'cannot backout a change with no parents'))
803 if p2 != nullid:
800 if p2 != nullid:
804 if not opts.get(b'parent'):
801 if not opts.get(b'parent'):
805 raise error.Abort(_(b'cannot backout a merge changeset'))
802 raise error.Abort(_(b'cannot backout a merge changeset'))
806 p = repo.lookup(opts[b'parent'])
803 p = repo.lookup(opts[b'parent'])
807 if p not in (p1, p2):
804 if p not in (p1, p2):
808 raise error.Abort(
805 raise error.Abort(
809 _(b'%s is not a parent of %s') % (short(p), short(node))
806 _(b'%s is not a parent of %s') % (short(p), short(node))
810 )
807 )
811 parent = p
808 parent = p
812 else:
809 else:
813 if opts.get(b'parent'):
810 if opts.get(b'parent'):
814 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
815 parent = p1
812 parent = p1
816
813
817 # the backout should appear on the same branch
814 # the backout should appear on the same branch
818 branch = repo.dirstate.branch()
815 branch = repo.dirstate.branch()
819 bheads = repo.branchheads(branch)
816 bheads = repo.branchheads(branch)
820 rctx = scmutil.revsingle(repo, hex(parent))
817 rctx = scmutil.revsingle(repo, hex(parent))
821 if not opts.get(b'merge') and op1 != node:
818 if not opts.get(b'merge') and op1 != node:
822 with dirstateguard.dirstateguard(repo, b'backout'):
819 with dirstateguard.dirstateguard(repo, b'backout'):
823 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
824 with ui.configoverride(overrides, b'backout'):
821 with ui.configoverride(overrides, b'backout'):
825 stats = mergemod.back_out(ctx, parent=repo[parent])
822 stats = mergemod.back_out(ctx, parent=repo[parent])
826 repo.setparents(op1, op2)
823 repo.setparents(op1, op2)
827 hg._showstats(repo, stats)
824 hg._showstats(repo, stats)
828 if stats.unresolvedcount:
825 if stats.unresolvedcount:
829 repo.ui.status(
826 repo.ui.status(
830 _(b"use 'hg resolve' to retry unresolved file merges\n")
827 _(b"use 'hg resolve' to retry unresolved file merges\n")
831 )
828 )
832 return 1
829 return 1
833 else:
830 else:
834 hg.clean(repo, node, show_stats=False)
831 hg.clean(repo, node, show_stats=False)
835 repo.dirstate.setbranch(branch)
832 repo.dirstate.setbranch(branch)
836 cmdutil.revert(ui, repo, rctx)
833 cmdutil.revert(ui, repo, rctx)
837
834
838 if opts.get(b'no_commit'):
835 if opts.get(b'no_commit'):
839 msg = _(b"changeset %s backed out, don't forget to commit.\n")
836 msg = _(b"changeset %s backed out, don't forget to commit.\n")
840 ui.status(msg % short(node))
837 ui.status(msg % short(node))
841 return 0
838 return 0
842
839
843 def commitfunc(ui, repo, message, match, opts):
840 def commitfunc(ui, repo, message, match, opts):
844 editform = b'backout'
841 editform = b'backout'
845 e = cmdutil.getcommiteditor(
842 e = cmdutil.getcommiteditor(
846 editform=editform, **pycompat.strkwargs(opts)
843 editform=editform, **pycompat.strkwargs(opts)
847 )
844 )
848 if not message:
845 if not message:
849 # we don't translate commit messages
846 # we don't translate commit messages
850 message = b"Backed out changeset %s" % short(node)
847 message = b"Backed out changeset %s" % short(node)
851 e = cmdutil.getcommiteditor(edit=True, editform=editform)
848 e = cmdutil.getcommiteditor(edit=True, editform=editform)
852 return repo.commit(
849 return repo.commit(
853 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
850 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
854 )
851 )
855
852
856 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
853 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
857 if not newnode:
854 if not newnode:
858 ui.status(_(b"nothing changed\n"))
855 ui.status(_(b"nothing changed\n"))
859 return 1
856 return 1
860 cmdutil.commitstatus(repo, newnode, branch, bheads)
857 cmdutil.commitstatus(repo, newnode, branch, bheads)
861
858
862 def nice(node):
859 def nice(node):
863 return b'%d:%s' % (repo.changelog.rev(node), short(node))
860 return b'%d:%s' % (repo.changelog.rev(node), short(node))
864
861
865 ui.status(
862 ui.status(
866 _(b'changeset %s backs out changeset %s\n')
863 _(b'changeset %s backs out changeset %s\n')
867 % (nice(repo.changelog.tip()), nice(node))
864 % (nice(repo.changelog.tip()), nice(node))
868 )
865 )
869 if opts.get(b'merge') and op1 != node:
866 if opts.get(b'merge') and op1 != node:
870 hg.clean(repo, op1, show_stats=False)
867 hg.clean(repo, op1, show_stats=False)
871 ui.status(
868 ui.status(
872 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
869 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
873 )
870 )
874 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
871 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
875 with ui.configoverride(overrides, b'backout'):
872 with ui.configoverride(overrides, b'backout'):
876 return hg.merge(repo[b'tip'])
873 return hg.merge(repo[b'tip'])
877 return 0
874 return 0
878
875
879
876
880 @command(
877 @command(
881 b'bisect',
878 b'bisect',
882 [
879 [
883 (b'r', b'reset', False, _(b'reset bisect state')),
880 (b'r', b'reset', False, _(b'reset bisect state')),
884 (b'g', b'good', False, _(b'mark changeset good')),
881 (b'g', b'good', False, _(b'mark changeset good')),
885 (b'b', b'bad', False, _(b'mark changeset bad')),
882 (b'b', b'bad', False, _(b'mark changeset bad')),
886 (b's', b'skip', False, _(b'skip testing changeset')),
883 (b's', b'skip', False, _(b'skip testing changeset')),
887 (b'e', b'extend', False, _(b'extend the bisect range')),
884 (b'e', b'extend', False, _(b'extend the bisect range')),
888 (
885 (
889 b'c',
886 b'c',
890 b'command',
887 b'command',
891 b'',
888 b'',
892 _(b'use command to check changeset state'),
889 _(b'use command to check changeset state'),
893 _(b'CMD'),
890 _(b'CMD'),
894 ),
891 ),
895 (b'U', b'noupdate', False, _(b'do not update to target')),
892 (b'U', b'noupdate', False, _(b'do not update to target')),
896 ],
893 ],
897 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
894 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
898 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
895 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
899 )
896 )
900 def bisect(
897 def bisect(
901 ui,
898 ui,
902 repo,
899 repo,
903 rev=None,
900 rev=None,
904 extra=None,
901 extra=None,
905 command=None,
902 command=None,
906 reset=None,
903 reset=None,
907 good=None,
904 good=None,
908 bad=None,
905 bad=None,
909 skip=None,
906 skip=None,
910 extend=None,
907 extend=None,
911 noupdate=None,
908 noupdate=None,
912 ):
909 ):
913 """subdivision search of changesets
910 """subdivision search of changesets
914
911
915 This command helps to find changesets which introduce problems. To
912 This command helps to find changesets which introduce problems. To
916 use, mark the earliest changeset you know exhibits the problem as
913 use, mark the earliest changeset you know exhibits the problem as
917 bad, then mark the latest changeset which is free from the problem
914 bad, then mark the latest changeset which is free from the problem
918 as good. Bisect will update your working directory to a revision
915 as good. Bisect will update your working directory to a revision
919 for testing (unless the -U/--noupdate option is specified). Once
916 for testing (unless the -U/--noupdate option is specified). Once
920 you have performed tests, mark the working directory as good or
917 you have performed tests, mark the working directory as good or
921 bad, and bisect will either update to another candidate changeset
918 bad, and bisect will either update to another candidate changeset
922 or announce that it has found the bad revision.
919 or announce that it has found the bad revision.
923
920
924 As a shortcut, you can also use the revision argument to mark a
921 As a shortcut, you can also use the revision argument to mark a
925 revision as good or bad without checking it out first.
922 revision as good or bad without checking it out first.
926
923
927 If you supply a command, it will be used for automatic bisection.
924 If you supply a command, it will be used for automatic bisection.
928 The environment variable HG_NODE will contain the ID of the
925 The environment variable HG_NODE will contain the ID of the
929 changeset being tested. The exit status of the command will be
926 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
927 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
928 means to skip the revision, 127 (command not found) will abort the
932 bisection, and any other non-zero exit status means the revision
929 bisection, and any other non-zero exit status means the revision
933 is bad.
930 is bad.
934
931
935 .. container:: verbose
932 .. container:: verbose
936
933
937 Some examples:
934 Some examples:
938
935
939 - start a bisection with known bad revision 34, and good revision 12::
936 - start a bisection with known bad revision 34, and good revision 12::
940
937
941 hg bisect --bad 34
938 hg bisect --bad 34
942 hg bisect --good 12
939 hg bisect --good 12
943
940
944 - advance the current bisection by marking current revision as good or
941 - advance the current bisection by marking current revision as good or
945 bad::
942 bad::
946
943
947 hg bisect --good
944 hg bisect --good
948 hg bisect --bad
945 hg bisect --bad
949
946
950 - mark the current revision, or a known revision, to be skipped (e.g. if
947 - mark the current revision, or a known revision, to be skipped (e.g. if
951 that revision is not usable because of another issue)::
948 that revision is not usable because of another issue)::
952
949
953 hg bisect --skip
950 hg bisect --skip
954 hg bisect --skip 23
951 hg bisect --skip 23
955
952
956 - skip all revisions that do not touch directories ``foo`` or ``bar``::
953 - skip all revisions that do not touch directories ``foo`` or ``bar``::
957
954
958 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
955 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
959
956
960 - forget the current bisection::
957 - forget the current bisection::
961
958
962 hg bisect --reset
959 hg bisect --reset
963
960
964 - use 'make && make tests' to automatically find the first broken
961 - use 'make && make tests' to automatically find the first broken
965 revision::
962 revision::
966
963
967 hg bisect --reset
964 hg bisect --reset
968 hg bisect --bad 34
965 hg bisect --bad 34
969 hg bisect --good 12
966 hg bisect --good 12
970 hg bisect --command "make && make tests"
967 hg bisect --command "make && make tests"
971
968
972 - see all changesets whose states are already known in the current
969 - see all changesets whose states are already known in the current
973 bisection::
970 bisection::
974
971
975 hg log -r "bisect(pruned)"
972 hg log -r "bisect(pruned)"
976
973
977 - see the changeset currently being bisected (especially useful
974 - see the changeset currently being bisected (especially useful
978 if running with -U/--noupdate)::
975 if running with -U/--noupdate)::
979
976
980 hg log -r "bisect(current)"
977 hg log -r "bisect(current)"
981
978
982 - see all changesets that took part in the current bisection::
979 - see all changesets that took part in the current bisection::
983
980
984 hg log -r "bisect(range)"
981 hg log -r "bisect(range)"
985
982
986 - you can even get a nice graph::
983 - you can even get a nice graph::
987
984
988 hg log --graph -r "bisect(range)"
985 hg log --graph -r "bisect(range)"
989
986
990 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
987 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
991
988
992 Returns 0 on success.
989 Returns 0 on success.
993 """
990 """
994 # backward compatibility
991 # backward compatibility
995 if rev in b"good bad reset init".split():
992 if rev in b"good bad reset init".split():
996 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
993 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
997 cmd, rev, extra = rev, extra, None
994 cmd, rev, extra = rev, extra, None
998 if cmd == b"good":
995 if cmd == b"good":
999 good = True
996 good = True
1000 elif cmd == b"bad":
997 elif cmd == b"bad":
1001 bad = True
998 bad = True
1002 else:
999 else:
1003 reset = True
1000 reset = True
1004 elif extra:
1001 elif extra:
1005 raise error.Abort(_(b'incompatible arguments'))
1002 raise error.Abort(_(b'incompatible arguments'))
1006
1003
1007 incompatibles = {
1004 incompatibles = {
1008 b'--bad': bad,
1005 b'--bad': bad,
1009 b'--command': bool(command),
1006 b'--command': bool(command),
1010 b'--extend': extend,
1007 b'--extend': extend,
1011 b'--good': good,
1008 b'--good': good,
1012 b'--reset': reset,
1009 b'--reset': reset,
1013 b'--skip': skip,
1010 b'--skip': skip,
1014 }
1011 }
1015
1012
1016 enabled = [x for x in incompatibles if incompatibles[x]]
1013 enabled = [x for x in incompatibles if incompatibles[x]]
1017
1014
1018 if len(enabled) > 1:
1015 if len(enabled) > 1:
1019 raise error.Abort(
1016 raise error.Abort(
1020 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1017 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1021 )
1018 )
1022
1019
1023 if reset:
1020 if reset:
1024 hbisect.resetstate(repo)
1021 hbisect.resetstate(repo)
1025 return
1022 return
1026
1023
1027 state = hbisect.load_state(repo)
1024 state = hbisect.load_state(repo)
1028
1025
1029 # update state
1026 # update state
1030 if good or bad or skip:
1027 if good or bad or skip:
1031 if rev:
1028 if rev:
1032 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1029 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1033 else:
1030 else:
1034 nodes = [repo.lookup(b'.')]
1031 nodes = [repo.lookup(b'.')]
1035 if good:
1032 if good:
1036 state[b'good'] += nodes
1033 state[b'good'] += nodes
1037 elif bad:
1034 elif bad:
1038 state[b'bad'] += nodes
1035 state[b'bad'] += nodes
1039 elif skip:
1036 elif skip:
1040 state[b'skip'] += nodes
1037 state[b'skip'] += nodes
1041 hbisect.save_state(repo, state)
1038 hbisect.save_state(repo, state)
1042 if not (state[b'good'] and state[b'bad']):
1039 if not (state[b'good'] and state[b'bad']):
1043 return
1040 return
1044
1041
1045 def mayupdate(repo, node, show_stats=True):
1042 def mayupdate(repo, node, show_stats=True):
1046 """common used update sequence"""
1043 """common used update sequence"""
1047 if noupdate:
1044 if noupdate:
1048 return
1045 return
1049 cmdutil.checkunfinished(repo)
1046 cmdutil.checkunfinished(repo)
1050 cmdutil.bailifchanged(repo)
1047 cmdutil.bailifchanged(repo)
1051 return hg.clean(repo, node, show_stats=show_stats)
1048 return hg.clean(repo, node, show_stats=show_stats)
1052
1049
1053 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1050 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1054
1051
1055 if command:
1052 if command:
1056 changesets = 1
1053 changesets = 1
1057 if noupdate:
1054 if noupdate:
1058 try:
1055 try:
1059 node = state[b'current'][0]
1056 node = state[b'current'][0]
1060 except LookupError:
1057 except LookupError:
1061 raise error.Abort(
1058 raise error.Abort(
1062 _(
1059 _(
1063 b'current bisect revision is unknown - '
1060 b'current bisect revision is unknown - '
1064 b'start a new bisect to fix'
1061 b'start a new bisect to fix'
1065 )
1062 )
1066 )
1063 )
1067 else:
1064 else:
1068 node, p2 = repo.dirstate.parents()
1065 node, p2 = repo.dirstate.parents()
1069 if p2 != nullid:
1066 if p2 != nullid:
1070 raise error.Abort(_(b'current bisect revision is a merge'))
1067 raise error.Abort(_(b'current bisect revision is a merge'))
1071 if rev:
1068 if rev:
1072 node = repo[scmutil.revsingle(repo, rev, node)].node()
1069 node = repo[scmutil.revsingle(repo, rev, node)].node()
1073 with hbisect.restore_state(repo, state, node):
1070 with hbisect.restore_state(repo, state, node):
1074 while changesets:
1071 while changesets:
1075 # update state
1072 # update state
1076 state[b'current'] = [node]
1073 state[b'current'] = [node]
1077 hbisect.save_state(repo, state)
1074 hbisect.save_state(repo, state)
1078 status = ui.system(
1075 status = ui.system(
1079 command,
1076 command,
1080 environ={b'HG_NODE': hex(node)},
1077 environ={b'HG_NODE': hex(node)},
1081 blockedtag=b'bisect_check',
1078 blockedtag=b'bisect_check',
1082 )
1079 )
1083 if status == 125:
1080 if status == 125:
1084 transition = b"skip"
1081 transition = b"skip"
1085 elif status == 0:
1082 elif status == 0:
1086 transition = b"good"
1083 transition = b"good"
1087 # status < 0 means process was killed
1084 # status < 0 means process was killed
1088 elif status == 127:
1085 elif status == 127:
1089 raise error.Abort(_(b"failed to execute %s") % command)
1086 raise error.Abort(_(b"failed to execute %s") % command)
1090 elif status < 0:
1087 elif status < 0:
1091 raise error.Abort(_(b"%s killed") % command)
1088 raise error.Abort(_(b"%s killed") % command)
1092 else:
1089 else:
1093 transition = b"bad"
1090 transition = b"bad"
1094 state[transition].append(node)
1091 state[transition].append(node)
1095 ctx = repo[node]
1092 ctx = repo[node]
1096 ui.status(
1093 ui.status(
1097 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1094 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1098 )
1095 )
1099 hbisect.checkstate(state)
1096 hbisect.checkstate(state)
1100 # bisect
1097 # bisect
1101 nodes, changesets, bgood = hbisect.bisect(repo, state)
1098 nodes, changesets, bgood = hbisect.bisect(repo, state)
1102 # update to next check
1099 # update to next check
1103 node = nodes[0]
1100 node = nodes[0]
1104 mayupdate(repo, node, show_stats=False)
1101 mayupdate(repo, node, show_stats=False)
1105 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1102 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1106 return
1103 return
1107
1104
1108 hbisect.checkstate(state)
1105 hbisect.checkstate(state)
1109
1106
1110 # actually bisect
1107 # actually bisect
1111 nodes, changesets, good = hbisect.bisect(repo, state)
1108 nodes, changesets, good = hbisect.bisect(repo, state)
1112 if extend:
1109 if extend:
1113 if not changesets:
1110 if not changesets:
1114 extendnode = hbisect.extendrange(repo, state, nodes, good)
1111 extendnode = hbisect.extendrange(repo, state, nodes, good)
1115 if extendnode is not None:
1112 if extendnode is not None:
1116 ui.write(
1113 ui.write(
1117 _(b"Extending search to changeset %d:%s\n")
1114 _(b"Extending search to changeset %d:%s\n")
1118 % (extendnode.rev(), extendnode)
1115 % (extendnode.rev(), extendnode)
1119 )
1116 )
1120 state[b'current'] = [extendnode.node()]
1117 state[b'current'] = [extendnode.node()]
1121 hbisect.save_state(repo, state)
1118 hbisect.save_state(repo, state)
1122 return mayupdate(repo, extendnode.node())
1119 return mayupdate(repo, extendnode.node())
1123 raise error.Abort(_(b"nothing to extend"))
1120 raise error.Abort(_(b"nothing to extend"))
1124
1121
1125 if changesets == 0:
1122 if changesets == 0:
1126 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1123 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1127 else:
1124 else:
1128 assert len(nodes) == 1 # only a single node can be tested next
1125 assert len(nodes) == 1 # only a single node can be tested next
1129 node = nodes[0]
1126 node = nodes[0]
1130 # compute the approximate number of remaining tests
1127 # compute the approximate number of remaining tests
1131 tests, size = 0, 2
1128 tests, size = 0, 2
1132 while size <= changesets:
1129 while size <= changesets:
1133 tests, size = tests + 1, size * 2
1130 tests, size = tests + 1, size * 2
1134 rev = repo.changelog.rev(node)
1131 rev = repo.changelog.rev(node)
1135 ui.write(
1132 ui.write(
1136 _(
1133 _(
1137 b"Testing changeset %d:%s "
1134 b"Testing changeset %d:%s "
1138 b"(%d changesets remaining, ~%d tests)\n"
1135 b"(%d changesets remaining, ~%d tests)\n"
1139 )
1136 )
1140 % (rev, short(node), changesets, tests)
1137 % (rev, short(node), changesets, tests)
1141 )
1138 )
1142 state[b'current'] = [node]
1139 state[b'current'] = [node]
1143 hbisect.save_state(repo, state)
1140 hbisect.save_state(repo, state)
1144 return mayupdate(repo, node)
1141 return mayupdate(repo, node)
1145
1142
1146
1143
1147 @command(
1144 @command(
1148 b'bookmarks|bookmark',
1145 b'bookmarks|bookmark',
1149 [
1146 [
1150 (b'f', b'force', False, _(b'force')),
1147 (b'f', b'force', False, _(b'force')),
1151 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1148 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1152 (b'd', b'delete', False, _(b'delete a given bookmark')),
1149 (b'd', b'delete', False, _(b'delete a given bookmark')),
1153 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1150 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1154 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1151 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1155 (b'l', b'list', False, _(b'list existing bookmarks')),
1152 (b'l', b'list', False, _(b'list existing bookmarks')),
1156 ]
1153 ]
1157 + formatteropts,
1154 + formatteropts,
1158 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1155 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1159 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1156 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1160 )
1157 )
1161 def bookmark(ui, repo, *names, **opts):
1158 def bookmark(ui, repo, *names, **opts):
1162 '''create a new bookmark or list existing bookmarks
1159 '''create a new bookmark or list existing bookmarks
1163
1160
1164 Bookmarks are labels on changesets to help track lines of development.
1161 Bookmarks are labels on changesets to help track lines of development.
1165 Bookmarks are unversioned and can be moved, renamed and deleted.
1162 Bookmarks are unversioned and can be moved, renamed and deleted.
1166 Deleting or moving a bookmark has no effect on the associated changesets.
1163 Deleting or moving a bookmark has no effect on the associated changesets.
1167
1164
1168 Creating or updating to a bookmark causes it to be marked as 'active'.
1165 Creating or updating to a bookmark causes it to be marked as 'active'.
1169 The active bookmark is indicated with a '*'.
1166 The active bookmark is indicated with a '*'.
1170 When a commit is made, the active bookmark will advance to the new commit.
1167 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.
1168 A plain :hg:`update` will also advance an active bookmark, if possible.
1172 Updating away from a bookmark will cause it to be deactivated.
1169 Updating away from a bookmark will cause it to be deactivated.
1173
1170
1174 Bookmarks can be pushed and pulled between repositories (see
1171 Bookmarks can be pushed and pulled between repositories (see
1175 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1172 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1176 diverged, a new 'divergent bookmark' of the form 'name@path' will
1173 diverged, a new 'divergent bookmark' of the form 'name@path' will
1177 be created. Using :hg:`merge` will resolve the divergence.
1174 be created. Using :hg:`merge` will resolve the divergence.
1178
1175
1179 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1176 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1180 the active bookmark's name.
1177 the active bookmark's name.
1181
1178
1182 A bookmark named '@' has the special property that :hg:`clone` will
1179 A bookmark named '@' has the special property that :hg:`clone` will
1183 check it out by default if it exists.
1180 check it out by default if it exists.
1184
1181
1185 .. container:: verbose
1182 .. container:: verbose
1186
1183
1187 Template:
1184 Template:
1188
1185
1189 The following keywords are supported in addition to the common template
1186 The following keywords are supported in addition to the common template
1190 keywords and functions such as ``{bookmark}``. See also
1187 keywords and functions such as ``{bookmark}``. See also
1191 :hg:`help templates`.
1188 :hg:`help templates`.
1192
1189
1193 :active: Boolean. True if the bookmark is active.
1190 :active: Boolean. True if the bookmark is active.
1194
1191
1195 Examples:
1192 Examples:
1196
1193
1197 - create an active bookmark for a new line of development::
1194 - create an active bookmark for a new line of development::
1198
1195
1199 hg book new-feature
1196 hg book new-feature
1200
1197
1201 - create an inactive bookmark as a place marker::
1198 - create an inactive bookmark as a place marker::
1202
1199
1203 hg book -i reviewed
1200 hg book -i reviewed
1204
1201
1205 - create an inactive bookmark on another changeset::
1202 - create an inactive bookmark on another changeset::
1206
1203
1207 hg book -r .^ tested
1204 hg book -r .^ tested
1208
1205
1209 - rename bookmark turkey to dinner::
1206 - rename bookmark turkey to dinner::
1210
1207
1211 hg book -m turkey dinner
1208 hg book -m turkey dinner
1212
1209
1213 - move the '@' bookmark from another branch::
1210 - move the '@' bookmark from another branch::
1214
1211
1215 hg book -f @
1212 hg book -f @
1216
1213
1217 - print only the active bookmark name::
1214 - print only the active bookmark name::
1218
1215
1219 hg book -ql .
1216 hg book -ql .
1220 '''
1217 '''
1221 opts = pycompat.byteskwargs(opts)
1218 opts = pycompat.byteskwargs(opts)
1222 force = opts.get(b'force')
1219 force = opts.get(b'force')
1223 rev = opts.get(b'rev')
1220 rev = opts.get(b'rev')
1224 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1221 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1225
1222
1226 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1223 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1227 if action:
1224 if action:
1228 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1225 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1229 elif names or rev:
1226 elif names or rev:
1230 action = b'add'
1227 action = b'add'
1231 elif inactive:
1228 elif inactive:
1232 action = b'inactive' # meaning deactivate
1229 action = b'inactive' # meaning deactivate
1233 else:
1230 else:
1234 action = b'list'
1231 action = b'list'
1235
1232
1236 cmdutil.check_incompatible_arguments(
1233 cmdutil.check_incompatible_arguments(
1237 opts, b'inactive', [b'delete', b'list']
1234 opts, b'inactive', [b'delete', b'list']
1238 )
1235 )
1239 if not names and action in {b'add', b'delete'}:
1236 if not names and action in {b'add', b'delete'}:
1240 raise error.Abort(_(b"bookmark name required"))
1237 raise error.Abort(_(b"bookmark name required"))
1241
1238
1242 if action in {b'add', b'delete', b'rename', b'inactive'}:
1239 if action in {b'add', b'delete', b'rename', b'inactive'}:
1243 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1240 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1244 if action == b'delete':
1241 if action == b'delete':
1245 names = pycompat.maplist(repo._bookmarks.expandname, names)
1242 names = pycompat.maplist(repo._bookmarks.expandname, names)
1246 bookmarks.delete(repo, tr, names)
1243 bookmarks.delete(repo, tr, names)
1247 elif action == b'rename':
1244 elif action == b'rename':
1248 if not names:
1245 if not names:
1249 raise error.Abort(_(b"new bookmark name required"))
1246 raise error.Abort(_(b"new bookmark name required"))
1250 elif len(names) > 1:
1247 elif len(names) > 1:
1251 raise error.Abort(_(b"only one new bookmark name allowed"))
1248 raise error.Abort(_(b"only one new bookmark name allowed"))
1252 oldname = repo._bookmarks.expandname(opts[b'rename'])
1249 oldname = repo._bookmarks.expandname(opts[b'rename'])
1253 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1250 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1254 elif action == b'add':
1251 elif action == b'add':
1255 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1252 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1256 elif action == b'inactive':
1253 elif action == b'inactive':
1257 if len(repo._bookmarks) == 0:
1254 if len(repo._bookmarks) == 0:
1258 ui.status(_(b"no bookmarks set\n"))
1255 ui.status(_(b"no bookmarks set\n"))
1259 elif not repo._activebookmark:
1256 elif not repo._activebookmark:
1260 ui.status(_(b"no active bookmark\n"))
1257 ui.status(_(b"no active bookmark\n"))
1261 else:
1258 else:
1262 bookmarks.deactivate(repo)
1259 bookmarks.deactivate(repo)
1263 elif action == b'list':
1260 elif action == b'list':
1264 names = pycompat.maplist(repo._bookmarks.expandname, names)
1261 names = pycompat.maplist(repo._bookmarks.expandname, names)
1265 with ui.formatter(b'bookmarks', opts) as fm:
1262 with ui.formatter(b'bookmarks', opts) as fm:
1266 bookmarks.printbookmarks(ui, repo, fm, names)
1263 bookmarks.printbookmarks(ui, repo, fm, names)
1267 else:
1264 else:
1268 raise error.ProgrammingError(b'invalid action: %s' % action)
1265 raise error.ProgrammingError(b'invalid action: %s' % action)
1269
1266
1270
1267
1271 @command(
1268 @command(
1272 b'branch',
1269 b'branch',
1273 [
1270 [
1274 (
1271 (
1275 b'f',
1272 b'f',
1276 b'force',
1273 b'force',
1277 None,
1274 None,
1278 _(b'set branch name even if it shadows an existing branch'),
1275 _(b'set branch name even if it shadows an existing branch'),
1279 ),
1276 ),
1280 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1277 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1281 (
1278 (
1282 b'r',
1279 b'r',
1283 b'rev',
1280 b'rev',
1284 [],
1281 [],
1285 _(b'change branches of the given revs (EXPERIMENTAL)'),
1282 _(b'change branches of the given revs (EXPERIMENTAL)'),
1286 ),
1283 ),
1287 ],
1284 ],
1288 _(b'[-fC] [NAME]'),
1285 _(b'[-fC] [NAME]'),
1289 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1286 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1290 )
1287 )
1291 def branch(ui, repo, label=None, **opts):
1288 def branch(ui, repo, label=None, **opts):
1292 """set or show the current branch name
1289 """set or show the current branch name
1293
1290
1294 .. note::
1291 .. note::
1295
1292
1296 Branch names are permanent and global. Use :hg:`bookmark` to create a
1293 Branch names are permanent and global. Use :hg:`bookmark` to create a
1297 light-weight bookmark instead. See :hg:`help glossary` for more
1294 light-weight bookmark instead. See :hg:`help glossary` for more
1298 information about named branches and bookmarks.
1295 information about named branches and bookmarks.
1299
1296
1300 With no argument, show the current branch name. With one argument,
1297 With no argument, show the current branch name. With one argument,
1301 set the working directory branch name (the branch will not exist
1298 set the working directory branch name (the branch will not exist
1302 in the repository until the next commit). Standard practice
1299 in the repository until the next commit). Standard practice
1303 recommends that primary development take place on the 'default'
1300 recommends that primary development take place on the 'default'
1304 branch.
1301 branch.
1305
1302
1306 Unless -f/--force is specified, branch will not let you set a
1303 Unless -f/--force is specified, branch will not let you set a
1307 branch name that already exists.
1304 branch name that already exists.
1308
1305
1309 Use -C/--clean to reset the working directory branch to that of
1306 Use -C/--clean to reset the working directory branch to that of
1310 the parent of the working directory, negating a previous branch
1307 the parent of the working directory, negating a previous branch
1311 change.
1308 change.
1312
1309
1313 Use the command :hg:`update` to switch to an existing branch. Use
1310 Use the command :hg:`update` to switch to an existing branch. Use
1314 :hg:`commit --close-branch` to mark this branch head as closed.
1311 :hg:`commit --close-branch` to mark this branch head as closed.
1315 When all heads of a branch are closed, the branch will be
1312 When all heads of a branch are closed, the branch will be
1316 considered closed.
1313 considered closed.
1317
1314
1318 Returns 0 on success.
1315 Returns 0 on success.
1319 """
1316 """
1320 opts = pycompat.byteskwargs(opts)
1317 opts = pycompat.byteskwargs(opts)
1321 revs = opts.get(b'rev')
1318 revs = opts.get(b'rev')
1322 if label:
1319 if label:
1323 label = label.strip()
1320 label = label.strip()
1324
1321
1325 if not opts.get(b'clean') and not label:
1322 if not opts.get(b'clean') and not label:
1326 if revs:
1323 if revs:
1327 raise error.Abort(_(b"no branch name specified for the revisions"))
1324 raise error.Abort(_(b"no branch name specified for the revisions"))
1328 ui.write(b"%s\n" % repo.dirstate.branch())
1325 ui.write(b"%s\n" % repo.dirstate.branch())
1329 return
1326 return
1330
1327
1331 with repo.wlock():
1328 with repo.wlock():
1332 if opts.get(b'clean'):
1329 if opts.get(b'clean'):
1333 label = repo[b'.'].branch()
1330 label = repo[b'.'].branch()
1334 repo.dirstate.setbranch(label)
1331 repo.dirstate.setbranch(label)
1335 ui.status(_(b'reset working directory to branch %s\n') % label)
1332 ui.status(_(b'reset working directory to branch %s\n') % label)
1336 elif label:
1333 elif label:
1337
1334
1338 scmutil.checknewlabel(repo, label, b'branch')
1335 scmutil.checknewlabel(repo, label, b'branch')
1339 if revs:
1336 if revs:
1340 return cmdutil.changebranch(ui, repo, revs, label, opts)
1337 return cmdutil.changebranch(ui, repo, revs, label, opts)
1341
1338
1342 if not opts.get(b'force') and label in repo.branchmap():
1339 if not opts.get(b'force') and label in repo.branchmap():
1343 if label not in [p.branch() for p in repo[None].parents()]:
1340 if label not in [p.branch() for p in repo[None].parents()]:
1344 raise error.Abort(
1341 raise error.Abort(
1345 _(b'a branch of the same name already exists'),
1342 _(b'a branch of the same name already exists'),
1346 # i18n: "it" refers to an existing branch
1343 # i18n: "it" refers to an existing branch
1347 hint=_(b"use 'hg update' to switch to it"),
1344 hint=_(b"use 'hg update' to switch to it"),
1348 )
1345 )
1349
1346
1350 repo.dirstate.setbranch(label)
1347 repo.dirstate.setbranch(label)
1351 ui.status(_(b'marked working directory as branch %s\n') % label)
1348 ui.status(_(b'marked working directory as branch %s\n') % label)
1352
1349
1353 # find any open named branches aside from default
1350 # find any open named branches aside from default
1354 for n, h, t, c in repo.branchmap().iterbranches():
1351 for n, h, t, c in repo.branchmap().iterbranches():
1355 if n != b"default" and not c:
1352 if n != b"default" and not c:
1356 return 0
1353 return 0
1357 ui.status(
1354 ui.status(
1358 _(
1355 _(
1359 b'(branches are permanent and global, '
1356 b'(branches are permanent and global, '
1360 b'did you want a bookmark?)\n'
1357 b'did you want a bookmark?)\n'
1361 )
1358 )
1362 )
1359 )
1363
1360
1364
1361
1365 @command(
1362 @command(
1366 b'branches',
1363 b'branches',
1367 [
1364 [
1368 (
1365 (
1369 b'a',
1366 b'a',
1370 b'active',
1367 b'active',
1371 False,
1368 False,
1372 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1369 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1373 ),
1370 ),
1374 (b'c', b'closed', False, _(b'show normal and closed branches')),
1371 (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')),
1372 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1376 ]
1373 ]
1377 + formatteropts,
1374 + formatteropts,
1378 _(b'[-c]'),
1375 _(b'[-c]'),
1379 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1376 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1380 intents={INTENT_READONLY},
1377 intents={INTENT_READONLY},
1381 )
1378 )
1382 def branches(ui, repo, active=False, closed=False, **opts):
1379 def branches(ui, repo, active=False, closed=False, **opts):
1383 """list repository named branches
1380 """list repository named branches
1384
1381
1385 List the repository's named branches, indicating which ones are
1382 List the repository's named branches, indicating which ones are
1386 inactive. If -c/--closed is specified, also list branches which have
1383 inactive. If -c/--closed is specified, also list branches which have
1387 been marked closed (see :hg:`commit --close-branch`).
1384 been marked closed (see :hg:`commit --close-branch`).
1388
1385
1389 Use the command :hg:`update` to switch to an existing branch.
1386 Use the command :hg:`update` to switch to an existing branch.
1390
1387
1391 .. container:: verbose
1388 .. container:: verbose
1392
1389
1393 Template:
1390 Template:
1394
1391
1395 The following keywords are supported in addition to the common template
1392 The following keywords are supported in addition to the common template
1396 keywords and functions such as ``{branch}``. See also
1393 keywords and functions such as ``{branch}``. See also
1397 :hg:`help templates`.
1394 :hg:`help templates`.
1398
1395
1399 :active: Boolean. True if the branch is active.
1396 :active: Boolean. True if the branch is active.
1400 :closed: Boolean. True if the branch is closed.
1397 :closed: Boolean. True if the branch is closed.
1401 :current: Boolean. True if it is the current branch.
1398 :current: Boolean. True if it is the current branch.
1402
1399
1403 Returns 0.
1400 Returns 0.
1404 """
1401 """
1405
1402
1406 opts = pycompat.byteskwargs(opts)
1403 opts = pycompat.byteskwargs(opts)
1407 revs = opts.get(b'rev')
1404 revs = opts.get(b'rev')
1408 selectedbranches = None
1405 selectedbranches = None
1409 if revs:
1406 if revs:
1410 revs = scmutil.revrange(repo, revs)
1407 revs = scmutil.revrange(repo, revs)
1411 getbi = repo.revbranchcache().branchinfo
1408 getbi = repo.revbranchcache().branchinfo
1412 selectedbranches = {getbi(r)[0] for r in revs}
1409 selectedbranches = {getbi(r)[0] for r in revs}
1413
1410
1414 ui.pager(b'branches')
1411 ui.pager(b'branches')
1415 fm = ui.formatter(b'branches', opts)
1412 fm = ui.formatter(b'branches', opts)
1416 hexfunc = fm.hexfunc
1413 hexfunc = fm.hexfunc
1417
1414
1418 allheads = set(repo.heads())
1415 allheads = set(repo.heads())
1419 branches = []
1416 branches = []
1420 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1417 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1421 if selectedbranches is not None and tag not in selectedbranches:
1418 if selectedbranches is not None and tag not in selectedbranches:
1422 continue
1419 continue
1423 isactive = False
1420 isactive = False
1424 if not isclosed:
1421 if not isclosed:
1425 openheads = set(repo.branchmap().iteropen(heads))
1422 openheads = set(repo.branchmap().iteropen(heads))
1426 isactive = bool(openheads & allheads)
1423 isactive = bool(openheads & allheads)
1427 branches.append((tag, repo[tip], isactive, not isclosed))
1424 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)
1425 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1429
1426
1430 for tag, ctx, isactive, isopen in branches:
1427 for tag, ctx, isactive, isopen in branches:
1431 if active and not isactive:
1428 if active and not isactive:
1432 continue
1429 continue
1433 if isactive:
1430 if isactive:
1434 label = b'branches.active'
1431 label = b'branches.active'
1435 notice = b''
1432 notice = b''
1436 elif not isopen:
1433 elif not isopen:
1437 if not closed:
1434 if not closed:
1438 continue
1435 continue
1439 label = b'branches.closed'
1436 label = b'branches.closed'
1440 notice = _(b' (closed)')
1437 notice = _(b' (closed)')
1441 else:
1438 else:
1442 label = b'branches.inactive'
1439 label = b'branches.inactive'
1443 notice = _(b' (inactive)')
1440 notice = _(b' (inactive)')
1444 current = tag == repo.dirstate.branch()
1441 current = tag == repo.dirstate.branch()
1445 if current:
1442 if current:
1446 label = b'branches.current'
1443 label = b'branches.current'
1447
1444
1448 fm.startitem()
1445 fm.startitem()
1449 fm.write(b'branch', b'%s', tag, label=label)
1446 fm.write(b'branch', b'%s', tag, label=label)
1450 rev = ctx.rev()
1447 rev = ctx.rev()
1451 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1448 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1452 fmt = b' ' * padsize + b' %d:%s'
1449 fmt = b' ' * padsize + b' %d:%s'
1453 fm.condwrite(
1450 fm.condwrite(
1454 not ui.quiet,
1451 not ui.quiet,
1455 b'rev node',
1452 b'rev node',
1456 fmt,
1453 fmt,
1457 rev,
1454 rev,
1458 hexfunc(ctx.node()),
1455 hexfunc(ctx.node()),
1459 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1456 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1460 )
1457 )
1461 fm.context(ctx=ctx)
1458 fm.context(ctx=ctx)
1462 fm.data(active=isactive, closed=not isopen, current=current)
1459 fm.data(active=isactive, closed=not isopen, current=current)
1463 if not ui.quiet:
1460 if not ui.quiet:
1464 fm.plain(notice)
1461 fm.plain(notice)
1465 fm.plain(b'\n')
1462 fm.plain(b'\n')
1466 fm.end()
1463 fm.end()
1467
1464
1468
1465
1469 @command(
1466 @command(
1470 b'bundle',
1467 b'bundle',
1471 [
1468 [
1472 (
1469 (
1473 b'f',
1470 b'f',
1474 b'force',
1471 b'force',
1475 None,
1472 None,
1476 _(b'run even when the destination is unrelated'),
1473 _(b'run even when the destination is unrelated'),
1477 ),
1474 ),
1478 (
1475 (
1479 b'r',
1476 b'r',
1480 b'rev',
1477 b'rev',
1481 [],
1478 [],
1482 _(b'a changeset intended to be added to the destination'),
1479 _(b'a changeset intended to be added to the destination'),
1483 _(b'REV'),
1480 _(b'REV'),
1484 ),
1481 ),
1485 (
1482 (
1486 b'b',
1483 b'b',
1487 b'branch',
1484 b'branch',
1488 [],
1485 [],
1489 _(b'a specific branch you would like to bundle'),
1486 _(b'a specific branch you would like to bundle'),
1490 _(b'BRANCH'),
1487 _(b'BRANCH'),
1491 ),
1488 ),
1492 (
1489 (
1493 b'',
1490 b'',
1494 b'base',
1491 b'base',
1495 [],
1492 [],
1496 _(b'a base changeset assumed to be available at the destination'),
1493 _(b'a base changeset assumed to be available at the destination'),
1497 _(b'REV'),
1494 _(b'REV'),
1498 ),
1495 ),
1499 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1496 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1500 (
1497 (
1501 b't',
1498 b't',
1502 b'type',
1499 b'type',
1503 b'bzip2',
1500 b'bzip2',
1504 _(b'bundle compression type to use'),
1501 _(b'bundle compression type to use'),
1505 _(b'TYPE'),
1502 _(b'TYPE'),
1506 ),
1503 ),
1507 ]
1504 ]
1508 + remoteopts,
1505 + remoteopts,
1509 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1506 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1510 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1507 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1511 )
1508 )
1512 def bundle(ui, repo, fname, dest=None, **opts):
1509 def bundle(ui, repo, fname, dest=None, **opts):
1513 """create a bundle file
1510 """create a bundle file
1514
1511
1515 Generate a bundle file containing data to be transferred to another
1512 Generate a bundle file containing data to be transferred to another
1516 repository.
1513 repository.
1517
1514
1518 To create a bundle containing all changesets, use -a/--all
1515 To create a bundle containing all changesets, use -a/--all
1519 (or --base null). Otherwise, hg assumes the destination will have
1516 (or --base null). Otherwise, hg assumes the destination will have
1520 all the nodes you specify with --base parameters. Otherwise, hg
1517 all the nodes you specify with --base parameters. Otherwise, hg
1521 will assume the repository has all the nodes in destination, or
1518 will assume the repository has all the nodes in destination, or
1522 default-push/default if no destination is specified, where destination
1519 default-push/default if no destination is specified, where destination
1523 is the repository you provide through DEST option.
1520 is the repository you provide through DEST option.
1524
1521
1525 You can change bundle format with the -t/--type option. See
1522 You can change bundle format with the -t/--type option. See
1526 :hg:`help bundlespec` for documentation on this format. By default,
1523 :hg:`help bundlespec` for documentation on this format. By default,
1527 the most appropriate format is used and compression defaults to
1524 the most appropriate format is used and compression defaults to
1528 bzip2.
1525 bzip2.
1529
1526
1530 The bundle file can then be transferred using conventional means
1527 The bundle file can then be transferred using conventional means
1531 and applied to another repository with the unbundle or pull
1528 and applied to another repository with the unbundle or pull
1532 command. This is useful when direct push and pull are not
1529 command. This is useful when direct push and pull are not
1533 available or when exporting an entire repository is undesirable.
1530 available or when exporting an entire repository is undesirable.
1534
1531
1535 Applying bundles preserves all changeset contents including
1532 Applying bundles preserves all changeset contents including
1536 permissions, copy/rename information, and revision history.
1533 permissions, copy/rename information, and revision history.
1537
1534
1538 Returns 0 on success, 1 if no changes found.
1535 Returns 0 on success, 1 if no changes found.
1539 """
1536 """
1540 opts = pycompat.byteskwargs(opts)
1537 opts = pycompat.byteskwargs(opts)
1541 revs = None
1538 revs = None
1542 if b'rev' in opts:
1539 if b'rev' in opts:
1543 revstrings = opts[b'rev']
1540 revstrings = opts[b'rev']
1544 revs = scmutil.revrange(repo, revstrings)
1541 revs = scmutil.revrange(repo, revstrings)
1545 if revstrings and not revs:
1542 if revstrings and not revs:
1546 raise error.Abort(_(b'no commits to bundle'))
1543 raise error.Abort(_(b'no commits to bundle'))
1547
1544
1548 bundletype = opts.get(b'type', b'bzip2').lower()
1545 bundletype = opts.get(b'type', b'bzip2').lower()
1549 try:
1546 try:
1550 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1547 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1551 except error.UnsupportedBundleSpecification as e:
1548 except error.UnsupportedBundleSpecification as e:
1552 raise error.Abort(
1549 raise error.Abort(
1553 pycompat.bytestr(e),
1550 pycompat.bytestr(e),
1554 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1551 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1555 )
1552 )
1556 cgversion = bundlespec.contentopts[b"cg.version"]
1553 cgversion = bundlespec.contentopts[b"cg.version"]
1557
1554
1558 # Packed bundles are a pseudo bundle format for now.
1555 # Packed bundles are a pseudo bundle format for now.
1559 if cgversion == b's1':
1556 if cgversion == b's1':
1560 raise error.Abort(
1557 raise error.Abort(
1561 _(b'packed bundles cannot be produced by "hg bundle"'),
1558 _(b'packed bundles cannot be produced by "hg bundle"'),
1562 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1559 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1563 )
1560 )
1564
1561
1565 if opts.get(b'all'):
1562 if opts.get(b'all'):
1566 if dest:
1563 if dest:
1567 raise error.Abort(
1564 raise error.Abort(
1568 _(b"--all is incompatible with specifying a destination")
1565 _(b"--all is incompatible with specifying a destination")
1569 )
1566 )
1570 if opts.get(b'base'):
1567 if opts.get(b'base'):
1571 ui.warn(_(b"ignoring --base because --all was specified\n"))
1568 ui.warn(_(b"ignoring --base because --all was specified\n"))
1572 base = [nullrev]
1569 base = [nullrev]
1573 else:
1570 else:
1574 base = scmutil.revrange(repo, opts.get(b'base'))
1571 base = scmutil.revrange(repo, opts.get(b'base'))
1575 if cgversion not in changegroup.supportedoutgoingversions(repo):
1572 if cgversion not in changegroup.supportedoutgoingversions(repo):
1576 raise error.Abort(
1573 raise error.Abort(
1577 _(b"repository does not support bundle version %s") % cgversion
1574 _(b"repository does not support bundle version %s") % cgversion
1578 )
1575 )
1579
1576
1580 if base:
1577 if base:
1581 if dest:
1578 if dest:
1582 raise error.Abort(
1579 raise error.Abort(
1583 _(b"--base is incompatible with specifying a destination")
1580 _(b"--base is incompatible with specifying a destination")
1584 )
1581 )
1585 common = [repo[rev].node() for rev in base]
1582 common = [repo[rev].node() for rev in base]
1586 heads = [repo[r].node() for r in revs] if revs else None
1583 heads = [repo[r].node() for r in revs] if revs else None
1587 outgoing = discovery.outgoing(repo, common, heads)
1584 outgoing = discovery.outgoing(repo, common, heads)
1588 else:
1585 else:
1589 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1586 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1590 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1587 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1591 other = hg.peer(repo, opts, dest)
1588 other = hg.peer(repo, opts, dest)
1592 revs = [repo[r].hex() for r in revs]
1589 revs = [repo[r].hex() for r in revs]
1593 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1590 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1594 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1591 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1595 outgoing = discovery.findcommonoutgoing(
1592 outgoing = discovery.findcommonoutgoing(
1596 repo,
1593 repo,
1597 other,
1594 other,
1598 onlyheads=heads,
1595 onlyheads=heads,
1599 force=opts.get(b'force'),
1596 force=opts.get(b'force'),
1600 portable=True,
1597 portable=True,
1601 )
1598 )
1602
1599
1603 if not outgoing.missing:
1600 if not outgoing.missing:
1604 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1601 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1605 return 1
1602 return 1
1606
1603
1607 if cgversion == b'01': # bundle1
1604 if cgversion == b'01': # bundle1
1608 bversion = b'HG10' + bundlespec.wirecompression
1605 bversion = b'HG10' + bundlespec.wirecompression
1609 bcompression = None
1606 bcompression = None
1610 elif cgversion in (b'02', b'03'):
1607 elif cgversion in (b'02', b'03'):
1611 bversion = b'HG20'
1608 bversion = b'HG20'
1612 bcompression = bundlespec.wirecompression
1609 bcompression = bundlespec.wirecompression
1613 else:
1610 else:
1614 raise error.ProgrammingError(
1611 raise error.ProgrammingError(
1615 b'bundle: unexpected changegroup version %s' % cgversion
1612 b'bundle: unexpected changegroup version %s' % cgversion
1616 )
1613 )
1617
1614
1618 # TODO compression options should be derived from bundlespec parsing.
1615 # TODO compression options should be derived from bundlespec parsing.
1619 # This is a temporary hack to allow adjusting bundle compression
1616 # This is a temporary hack to allow adjusting bundle compression
1620 # level without a) formalizing the bundlespec changes to declare it
1617 # level without a) formalizing the bundlespec changes to declare it
1621 # b) introducing a command flag.
1618 # b) introducing a command flag.
1622 compopts = {}
1619 compopts = {}
1623 complevel = ui.configint(
1620 complevel = ui.configint(
1624 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1621 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1625 )
1622 )
1626 if complevel is None:
1623 if complevel is None:
1627 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1624 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1628 if complevel is not None:
1625 if complevel is not None:
1629 compopts[b'level'] = complevel
1626 compopts[b'level'] = complevel
1630
1627
1631 # Allow overriding the bundling of obsmarker in phases through
1628 # Allow overriding the bundling of obsmarker in phases through
1632 # configuration while we don't have a bundle version that include them
1629 # configuration while we don't have a bundle version that include them
1633 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1630 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1634 bundlespec.contentopts[b'obsolescence'] = True
1631 bundlespec.contentopts[b'obsolescence'] = True
1635 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1632 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1636 bundlespec.contentopts[b'phases'] = True
1633 bundlespec.contentopts[b'phases'] = True
1637
1634
1638 bundle2.writenewbundle(
1635 bundle2.writenewbundle(
1639 ui,
1636 ui,
1640 repo,
1637 repo,
1641 b'bundle',
1638 b'bundle',
1642 fname,
1639 fname,
1643 bversion,
1640 bversion,
1644 outgoing,
1641 outgoing,
1645 bundlespec.contentopts,
1642 bundlespec.contentopts,
1646 compression=bcompression,
1643 compression=bcompression,
1647 compopts=compopts,
1644 compopts=compopts,
1648 )
1645 )
1649
1646
1650
1647
1651 @command(
1648 @command(
1652 b'cat',
1649 b'cat',
1653 [
1650 [
1654 (
1651 (
1655 b'o',
1652 b'o',
1656 b'output',
1653 b'output',
1657 b'',
1654 b'',
1658 _(b'print output to file with formatted name'),
1655 _(b'print output to file with formatted name'),
1659 _(b'FORMAT'),
1656 _(b'FORMAT'),
1660 ),
1657 ),
1661 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1658 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1662 (b'', b'decode', None, _(b'apply any matching decode filter')),
1659 (b'', b'decode', None, _(b'apply any matching decode filter')),
1663 ]
1660 ]
1664 + walkopts
1661 + walkopts
1665 + formatteropts,
1662 + formatteropts,
1666 _(b'[OPTION]... FILE...'),
1663 _(b'[OPTION]... FILE...'),
1667 helpcategory=command.CATEGORY_FILE_CONTENTS,
1664 helpcategory=command.CATEGORY_FILE_CONTENTS,
1668 inferrepo=True,
1665 inferrepo=True,
1669 intents={INTENT_READONLY},
1666 intents={INTENT_READONLY},
1670 )
1667 )
1671 def cat(ui, repo, file1, *pats, **opts):
1668 def cat(ui, repo, file1, *pats, **opts):
1672 """output the current or given revision of files
1669 """output the current or given revision of files
1673
1670
1674 Print the specified files as they were at the given revision. If
1671 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.
1672 no revision is given, the parent of the working directory is used.
1676
1673
1677 Output may be to a file, in which case the name of the file is
1674 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
1675 given using a template string. See :hg:`help templates`. In addition
1679 to the common template keywords, the following formatting rules are
1676 to the common template keywords, the following formatting rules are
1680 supported:
1677 supported:
1681
1678
1682 :``%%``: literal "%" character
1679 :``%%``: literal "%" character
1683 :``%s``: basename of file being printed
1680 :``%s``: basename of file being printed
1684 :``%d``: dirname of file being printed, or '.' if in repository root
1681 :``%d``: dirname of file being printed, or '.' if in repository root
1685 :``%p``: root-relative path name of file being printed
1682 :``%p``: root-relative path name of file being printed
1686 :``%H``: changeset hash (40 hexadecimal digits)
1683 :``%H``: changeset hash (40 hexadecimal digits)
1687 :``%R``: changeset revision number
1684 :``%R``: changeset revision number
1688 :``%h``: short-form changeset hash (12 hexadecimal digits)
1685 :``%h``: short-form changeset hash (12 hexadecimal digits)
1689 :``%r``: zero-padded changeset revision number
1686 :``%r``: zero-padded changeset revision number
1690 :``%b``: basename of the exporting repository
1687 :``%b``: basename of the exporting repository
1691 :``\\``: literal "\\" character
1688 :``\\``: literal "\\" character
1692
1689
1693 .. container:: verbose
1690 .. container:: verbose
1694
1691
1695 Template:
1692 Template:
1696
1693
1697 The following keywords are supported in addition to the common template
1694 The following keywords are supported in addition to the common template
1698 keywords and functions. See also :hg:`help templates`.
1695 keywords and functions. See also :hg:`help templates`.
1699
1696
1700 :data: String. File content.
1697 :data: String. File content.
1701 :path: String. Repository-absolute path of the file.
1698 :path: String. Repository-absolute path of the file.
1702
1699
1703 Returns 0 on success.
1700 Returns 0 on success.
1704 """
1701 """
1705 opts = pycompat.byteskwargs(opts)
1702 opts = pycompat.byteskwargs(opts)
1706 rev = opts.get(b'rev')
1703 rev = opts.get(b'rev')
1707 if rev:
1704 if rev:
1708 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1705 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1709 ctx = scmutil.revsingle(repo, rev)
1706 ctx = scmutil.revsingle(repo, rev)
1710 m = scmutil.match(ctx, (file1,) + pats, opts)
1707 m = scmutil.match(ctx, (file1,) + pats, opts)
1711 fntemplate = opts.pop(b'output', b'')
1708 fntemplate = opts.pop(b'output', b'')
1712 if cmdutil.isstdiofilename(fntemplate):
1709 if cmdutil.isstdiofilename(fntemplate):
1713 fntemplate = b''
1710 fntemplate = b''
1714
1711
1715 if fntemplate:
1712 if fntemplate:
1716 fm = formatter.nullformatter(ui, b'cat', opts)
1713 fm = formatter.nullformatter(ui, b'cat', opts)
1717 else:
1714 else:
1718 ui.pager(b'cat')
1715 ui.pager(b'cat')
1719 fm = ui.formatter(b'cat', opts)
1716 fm = ui.formatter(b'cat', opts)
1720 with fm:
1717 with fm:
1721 return cmdutil.cat(
1718 return cmdutil.cat(
1722 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1719 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1723 )
1720 )
1724
1721
1725
1722
1726 @command(
1723 @command(
1727 b'clone',
1724 b'clone',
1728 [
1725 [
1729 (
1726 (
1730 b'U',
1727 b'U',
1731 b'noupdate',
1728 b'noupdate',
1732 None,
1729 None,
1733 _(
1730 _(
1734 b'the clone will include an empty working '
1731 b'the clone will include an empty working '
1735 b'directory (only a repository)'
1732 b'directory (only a repository)'
1736 ),
1733 ),
1737 ),
1734 ),
1738 (
1735 (
1739 b'u',
1736 b'u',
1740 b'updaterev',
1737 b'updaterev',
1741 b'',
1738 b'',
1742 _(b'revision, tag, or branch to check out'),
1739 _(b'revision, tag, or branch to check out'),
1743 _(b'REV'),
1740 _(b'REV'),
1744 ),
1741 ),
1745 (
1742 (
1746 b'r',
1743 b'r',
1747 b'rev',
1744 b'rev',
1748 [],
1745 [],
1749 _(
1746 _(
1750 b'do not clone everything, but include this changeset'
1747 b'do not clone everything, but include this changeset'
1751 b' and its ancestors'
1748 b' and its ancestors'
1752 ),
1749 ),
1753 _(b'REV'),
1750 _(b'REV'),
1754 ),
1751 ),
1755 (
1752 (
1756 b'b',
1753 b'b',
1757 b'branch',
1754 b'branch',
1758 [],
1755 [],
1759 _(
1756 _(
1760 b'do not clone everything, but include this branch\'s'
1757 b'do not clone everything, but include this branch\'s'
1761 b' changesets and their ancestors'
1758 b' changesets and their ancestors'
1762 ),
1759 ),
1763 _(b'BRANCH'),
1760 _(b'BRANCH'),
1764 ),
1761 ),
1765 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1762 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1766 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1763 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1767 (b'', b'stream', None, _(b'clone with minimal data processing')),
1764 (b'', b'stream', None, _(b'clone with minimal data processing')),
1768 ]
1765 ]
1769 + remoteopts,
1766 + remoteopts,
1770 _(b'[OPTION]... SOURCE [DEST]'),
1767 _(b'[OPTION]... SOURCE [DEST]'),
1771 helpcategory=command.CATEGORY_REPO_CREATION,
1768 helpcategory=command.CATEGORY_REPO_CREATION,
1772 helpbasic=True,
1769 helpbasic=True,
1773 norepo=True,
1770 norepo=True,
1774 )
1771 )
1775 def clone(ui, source, dest=None, **opts):
1772 def clone(ui, source, dest=None, **opts):
1776 """make a copy of an existing repository
1773 """make a copy of an existing repository
1777
1774
1778 Create a copy of an existing repository in a new directory.
1775 Create a copy of an existing repository in a new directory.
1779
1776
1780 If no destination directory name is specified, it defaults to the
1777 If no destination directory name is specified, it defaults to the
1781 basename of the source.
1778 basename of the source.
1782
1779
1783 The location of the source is added to the new repository's
1780 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.
1781 ``.hg/hgrc`` file, as the default to be used for future pulls.
1785
1782
1786 Only local paths and ``ssh://`` URLs are supported as
1783 Only local paths and ``ssh://`` URLs are supported as
1787 destinations. For ``ssh://`` destinations, no working directory or
1784 destinations. For ``ssh://`` destinations, no working directory or
1788 ``.hg/hgrc`` will be created on the remote side.
1785 ``.hg/hgrc`` will be created on the remote side.
1789
1786
1790 If the source repository has a bookmark called '@' set, that
1787 If the source repository has a bookmark called '@' set, that
1791 revision will be checked out in the new repository by default.
1788 revision will be checked out in the new repository by default.
1792
1789
1793 To check out a particular version, use -u/--update, or
1790 To check out a particular version, use -u/--update, or
1794 -U/--noupdate to create a clone with no working directory.
1791 -U/--noupdate to create a clone with no working directory.
1795
1792
1796 To pull only a subset of changesets, specify one or more revisions
1793 To pull only a subset of changesets, specify one or more revisions
1797 identifiers with -r/--rev or branches with -b/--branch. The
1794 identifiers with -r/--rev or branches with -b/--branch. The
1798 resulting clone will contain only the specified changesets and
1795 resulting clone will contain only the specified changesets and
1799 their ancestors. These options (or 'clone src#rev dest') imply
1796 their ancestors. These options (or 'clone src#rev dest') imply
1800 --pull, even for local source repositories.
1797 --pull, even for local source repositories.
1801
1798
1802 In normal clone mode, the remote normalizes repository data into a common
1799 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
1800 exchange format and the receiving end translates this data into its local
1804 storage format. --stream activates a different clone mode that essentially
1801 storage format. --stream activates a different clone mode that essentially
1805 copies repository files from the remote with minimal data processing. This
1802 copies repository files from the remote with minimal data processing. This
1806 significantly reduces the CPU cost of a clone both remotely and locally.
1803 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
1804 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,
1805 result in substantially faster clones where I/O throughput is plentiful,
1809 especially for larger repositories. A side-effect of --stream clones is
1806 especially for larger repositories. A side-effect of --stream clones is
1810 that storage settings and requirements on the remote are applied locally:
1807 that storage settings and requirements on the remote are applied locally:
1811 a modern client may inherit legacy or inefficient storage used by the
1808 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
1809 remote or a legacy Mercurial client may not be able to clone from a
1813 modern Mercurial remote.
1810 modern Mercurial remote.
1814
1811
1815 .. note::
1812 .. note::
1816
1813
1817 Specifying a tag will include the tagged changeset but not the
1814 Specifying a tag will include the tagged changeset but not the
1818 changeset containing the tag.
1815 changeset containing the tag.
1819
1816
1820 .. container:: verbose
1817 .. container:: verbose
1821
1818
1822 For efficiency, hardlinks are used for cloning whenever the
1819 For efficiency, hardlinks are used for cloning whenever the
1823 source and destination are on the same filesystem (note this
1820 source and destination are on the same filesystem (note this
1824 applies only to the repository data, not to the working
1821 applies only to the repository data, not to the working
1825 directory). Some filesystems, such as AFS, implement hardlinking
1822 directory). Some filesystems, such as AFS, implement hardlinking
1826 incorrectly, but do not report errors. In these cases, use the
1823 incorrectly, but do not report errors. In these cases, use the
1827 --pull option to avoid hardlinking.
1824 --pull option to avoid hardlinking.
1828
1825
1829 Mercurial will update the working directory to the first applicable
1826 Mercurial will update the working directory to the first applicable
1830 revision from this list:
1827 revision from this list:
1831
1828
1832 a) null if -U or the source repository has no changesets
1829 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
1830 b) if -u . and the source repository is local, the first parent of
1834 the source repository's working directory
1831 the source repository's working directory
1835 c) the changeset specified with -u (if a branch name, this means the
1832 c) the changeset specified with -u (if a branch name, this means the
1836 latest head of that branch)
1833 latest head of that branch)
1837 d) the changeset specified with -r
1834 d) the changeset specified with -r
1838 e) the tipmost head specified with -b
1835 e) the tipmost head specified with -b
1839 f) the tipmost head specified with the url#branch source syntax
1836 f) the tipmost head specified with the url#branch source syntax
1840 g) the revision marked with the '@' bookmark, if present
1837 g) the revision marked with the '@' bookmark, if present
1841 h) the tipmost head of the default branch
1838 h) the tipmost head of the default branch
1842 i) tip
1839 i) tip
1843
1840
1844 When cloning from servers that support it, Mercurial may fetch
1841 When cloning from servers that support it, Mercurial may fetch
1845 pre-generated data from a server-advertised URL or inline from the
1842 pre-generated data from a server-advertised URL or inline from the
1846 same stream. When this is done, hooks operating on incoming changesets
1843 same stream. When this is done, hooks operating on incoming changesets
1847 and changegroups may fire more than once, once for each pre-generated
1844 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,
1845 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
1846 if an error occurs, the repository may be rolled back to a partial
1850 clone. This behavior may change in future releases.
1847 clone. This behavior may change in future releases.
1851 See :hg:`help -e clonebundles` for more.
1848 See :hg:`help -e clonebundles` for more.
1852
1849
1853 Examples:
1850 Examples:
1854
1851
1855 - clone a remote repository to a new directory named hg/::
1852 - clone a remote repository to a new directory named hg/::
1856
1853
1857 hg clone https://www.mercurial-scm.org/repo/hg/
1854 hg clone https://www.mercurial-scm.org/repo/hg/
1858
1855
1859 - create a lightweight local clone::
1856 - create a lightweight local clone::
1860
1857
1861 hg clone project/ project-feature/
1858 hg clone project/ project-feature/
1862
1859
1863 - clone from an absolute path on an ssh server (note double-slash)::
1860 - clone from an absolute path on an ssh server (note double-slash)::
1864
1861
1865 hg clone ssh://user@server//home/projects/alpha/
1862 hg clone ssh://user@server//home/projects/alpha/
1866
1863
1867 - do a streaming clone while checking out a specified version::
1864 - do a streaming clone while checking out a specified version::
1868
1865
1869 hg clone --stream http://server/repo -u 1.5
1866 hg clone --stream http://server/repo -u 1.5
1870
1867
1871 - create a repository without changesets after a particular revision::
1868 - create a repository without changesets after a particular revision::
1872
1869
1873 hg clone -r 04e544 experimental/ good/
1870 hg clone -r 04e544 experimental/ good/
1874
1871
1875 - clone (and track) a particular named branch::
1872 - clone (and track) a particular named branch::
1876
1873
1877 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1874 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1878
1875
1879 See :hg:`help urls` for details on specifying URLs.
1876 See :hg:`help urls` for details on specifying URLs.
1880
1877
1881 Returns 0 on success.
1878 Returns 0 on success.
1882 """
1879 """
1883 opts = pycompat.byteskwargs(opts)
1880 opts = pycompat.byteskwargs(opts)
1884 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1881 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1885
1882
1886 # --include/--exclude can come from narrow or sparse.
1883 # --include/--exclude can come from narrow or sparse.
1887 includepats, excludepats = None, None
1884 includepats, excludepats = None, None
1888
1885
1889 # hg.clone() differentiates between None and an empty set. So make sure
1886 # hg.clone() differentiates between None and an empty set. So make sure
1890 # patterns are sets if narrow is requested without patterns.
1887 # patterns are sets if narrow is requested without patterns.
1891 if opts.get(b'narrow'):
1888 if opts.get(b'narrow'):
1892 includepats = set()
1889 includepats = set()
1893 excludepats = set()
1890 excludepats = set()
1894
1891
1895 if opts.get(b'include'):
1892 if opts.get(b'include'):
1896 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1893 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1897 if opts.get(b'exclude'):
1894 if opts.get(b'exclude'):
1898 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1895 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1899
1896
1900 r = hg.clone(
1897 r = hg.clone(
1901 ui,
1898 ui,
1902 opts,
1899 opts,
1903 source,
1900 source,
1904 dest,
1901 dest,
1905 pull=opts.get(b'pull'),
1902 pull=opts.get(b'pull'),
1906 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1903 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1907 revs=opts.get(b'rev'),
1904 revs=opts.get(b'rev'),
1908 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1905 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1909 branch=opts.get(b'branch'),
1906 branch=opts.get(b'branch'),
1910 shareopts=opts.get(b'shareopts'),
1907 shareopts=opts.get(b'shareopts'),
1911 storeincludepats=includepats,
1908 storeincludepats=includepats,
1912 storeexcludepats=excludepats,
1909 storeexcludepats=excludepats,
1913 depth=opts.get(b'depth') or None,
1910 depth=opts.get(b'depth') or None,
1914 )
1911 )
1915
1912
1916 return r is None
1913 return r is None
1917
1914
1918
1915
1919 @command(
1916 @command(
1920 b'commit|ci',
1917 b'commit|ci',
1921 [
1918 [
1922 (
1919 (
1923 b'A',
1920 b'A',
1924 b'addremove',
1921 b'addremove',
1925 None,
1922 None,
1926 _(b'mark new/missing files as added/removed before committing'),
1923 _(b'mark new/missing files as added/removed before committing'),
1927 ),
1924 ),
1928 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1925 (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')),
1926 (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')),
1927 (b's', b'secret', None, _(b'use the secret phase for committing')),
1931 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1928 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1932 (
1929 (
1933 b'',
1930 b'',
1934 b'force-close-branch',
1931 b'force-close-branch',
1935 None,
1932 None,
1936 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1933 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1937 ),
1934 ),
1938 (b'i', b'interactive', None, _(b'use interactive mode')),
1935 (b'i', b'interactive', None, _(b'use interactive mode')),
1939 ]
1936 ]
1940 + walkopts
1937 + walkopts
1941 + commitopts
1938 + commitopts
1942 + commitopts2
1939 + commitopts2
1943 + subrepoopts,
1940 + subrepoopts,
1944 _(b'[OPTION]... [FILE]...'),
1941 _(b'[OPTION]... [FILE]...'),
1945 helpcategory=command.CATEGORY_COMMITTING,
1942 helpcategory=command.CATEGORY_COMMITTING,
1946 helpbasic=True,
1943 helpbasic=True,
1947 inferrepo=True,
1944 inferrepo=True,
1948 )
1945 )
1949 def commit(ui, repo, *pats, **opts):
1946 def commit(ui, repo, *pats, **opts):
1950 """commit the specified files or all outstanding changes
1947 """commit the specified files or all outstanding changes
1951
1948
1952 Commit changes to the given files into the repository. Unlike a
1949 Commit changes to the given files into the repository. Unlike a
1953 centralized SCM, this operation is a local operation. See
1950 centralized SCM, this operation is a local operation. See
1954 :hg:`push` for a way to actively distribute your changes.
1951 :hg:`push` for a way to actively distribute your changes.
1955
1952
1956 If a list of files is omitted, all changes reported by :hg:`status`
1953 If a list of files is omitted, all changes reported by :hg:`status`
1957 will be committed.
1954 will be committed.
1958
1955
1959 If you are committing the result of a merge, do not provide any
1956 If you are committing the result of a merge, do not provide any
1960 filenames or -I/-X filters.
1957 filenames or -I/-X filters.
1961
1958
1962 If no commit message is specified, Mercurial starts your
1959 If no commit message is specified, Mercurial starts your
1963 configured editor where you can enter a message. In case your
1960 configured editor where you can enter a message. In case your
1964 commit fails, you will find a backup of your message in
1961 commit fails, you will find a backup of your message in
1965 ``.hg/last-message.txt``.
1962 ``.hg/last-message.txt``.
1966
1963
1967 The --close-branch flag can be used to mark the current branch
1964 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
1965 head closed. When all heads of a branch are closed, the branch
1969 will be considered closed and no longer listed.
1966 will be considered closed and no longer listed.
1970
1967
1971 The --amend flag can be used to amend the parent of the
1968 The --amend flag can be used to amend the parent of the
1972 working directory with a new commit that contains the changes
1969 working directory with a new commit that contains the changes
1973 in the parent in addition to those currently reported by :hg:`status`,
1970 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
1971 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`
1972 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1976 on how to restore it).
1973 on how to restore it).
1977
1974
1978 Message, user and date are taken from the amended commit unless
1975 Message, user and date are taken from the amended commit unless
1979 specified. When a message isn't specified on the command line,
1976 specified. When a message isn't specified on the command line,
1980 the editor will open with the message of the amended commit.
1977 the editor will open with the message of the amended commit.
1981
1978
1982 It is not possible to amend public changesets (see :hg:`help phases`)
1979 It is not possible to amend public changesets (see :hg:`help phases`)
1983 or changesets that have children.
1980 or changesets that have children.
1984
1981
1985 See :hg:`help dates` for a list of formats valid for -d/--date.
1982 See :hg:`help dates` for a list of formats valid for -d/--date.
1986
1983
1987 Returns 0 on success, 1 if nothing changed.
1984 Returns 0 on success, 1 if nothing changed.
1988
1985
1989 .. container:: verbose
1986 .. container:: verbose
1990
1987
1991 Examples:
1988 Examples:
1992
1989
1993 - commit all files ending in .py::
1990 - commit all files ending in .py::
1994
1991
1995 hg commit --include "set:**.py"
1992 hg commit --include "set:**.py"
1996
1993
1997 - commit all non-binary files::
1994 - commit all non-binary files::
1998
1995
1999 hg commit --exclude "set:binary()"
1996 hg commit --exclude "set:binary()"
2000
1997
2001 - amend the current commit and set the date to now::
1998 - amend the current commit and set the date to now::
2002
1999
2003 hg commit --amend --date now
2000 hg commit --amend --date now
2004 """
2001 """
2005 with repo.wlock(), repo.lock():
2002 with repo.wlock(), repo.lock():
2006 return _docommit(ui, repo, *pats, **opts)
2003 return _docommit(ui, repo, *pats, **opts)
2007
2004
2008
2005
2009 def _docommit(ui, repo, *pats, **opts):
2006 def _docommit(ui, repo, *pats, **opts):
2010 if opts.get('interactive'):
2007 if opts.get('interactive'):
2011 opts.pop('interactive')
2008 opts.pop('interactive')
2012 ret = cmdutil.dorecord(
2009 ret = cmdutil.dorecord(
2013 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2010 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2014 )
2011 )
2015 # ret can be 0 (no changes to record) or the value returned by
2012 # ret can be 0 (no changes to record) or the value returned by
2016 # commit(), 1 if nothing changed or None on success.
2013 # commit(), 1 if nothing changed or None on success.
2017 return 1 if ret == 0 else ret
2014 return 1 if ret == 0 else ret
2018
2015
2019 opts = pycompat.byteskwargs(opts)
2016 opts = pycompat.byteskwargs(opts)
2020 if opts.get(b'subrepos'):
2017 if opts.get(b'subrepos'):
2021 if opts.get(b'amend'):
2018 if opts.get(b'amend'):
2022 raise error.Abort(_(b'cannot amend with --subrepos'))
2019 raise error.Abort(_(b'cannot amend with --subrepos'))
2023 # Let --subrepos on the command line override config setting.
2020 # Let --subrepos on the command line override config setting.
2024 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2021 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2025
2022
2026 cmdutil.checkunfinished(repo, commit=True)
2023 cmdutil.checkunfinished(repo, commit=True)
2027
2024
2028 branch = repo[None].branch()
2025 branch = repo[None].branch()
2029 bheads = repo.branchheads(branch)
2026 bheads = repo.branchheads(branch)
2030
2027
2031 extra = {}
2028 extra = {}
2032 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2029 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2033 extra[b'close'] = b'1'
2030 extra[b'close'] = b'1'
2034
2031
2035 if repo[b'.'].closesbranch():
2032 if repo[b'.'].closesbranch():
2036 raise error.Abort(
2033 raise error.Abort(
2037 _(b'current revision is already a branch closing head')
2034 _(b'current revision is already a branch closing head')
2038 )
2035 )
2039 elif not bheads:
2036 elif not bheads:
2040 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2037 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2041 elif (
2038 elif (
2042 branch == repo[b'.'].branch()
2039 branch == repo[b'.'].branch()
2043 and repo[b'.'].node() not in bheads
2040 and repo[b'.'].node() not in bheads
2044 and not opts.get(b'force_close_branch')
2041 and not opts.get(b'force_close_branch')
2045 ):
2042 ):
2046 hint = _(
2043 hint = _(
2047 b'use --force-close-branch to close branch from a non-head'
2044 b'use --force-close-branch to close branch from a non-head'
2048 b' changeset'
2045 b' changeset'
2049 )
2046 )
2050 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2047 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2051 elif opts.get(b'amend'):
2048 elif opts.get(b'amend'):
2052 if (
2049 if (
2053 repo[b'.'].p1().branch() != branch
2050 repo[b'.'].p1().branch() != branch
2054 and repo[b'.'].p2().branch() != branch
2051 and repo[b'.'].p2().branch() != branch
2055 ):
2052 ):
2056 raise error.Abort(_(b'can only close branch heads'))
2053 raise error.Abort(_(b'can only close branch heads'))
2057
2054
2058 if opts.get(b'amend'):
2055 if opts.get(b'amend'):
2059 if ui.configbool(b'ui', b'commitsubrepos'):
2056 if ui.configbool(b'ui', b'commitsubrepos'):
2060 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2057 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2061
2058
2062 old = repo[b'.']
2059 old = repo[b'.']
2063 rewriteutil.precheck(repo, [old.rev()], b'amend')
2060 rewriteutil.precheck(repo, [old.rev()], b'amend')
2064
2061
2065 # Currently histedit gets confused if an amend happens while histedit
2062 # Currently histedit gets confused if an amend happens while histedit
2066 # is in progress. Since we have a checkunfinished command, we are
2063 # is in progress. Since we have a checkunfinished command, we are
2067 # temporarily honoring it.
2064 # temporarily honoring it.
2068 #
2065 #
2069 # Note: eventually this guard will be removed. Please do not expect
2066 # Note: eventually this guard will be removed. Please do not expect
2070 # this behavior to remain.
2067 # this behavior to remain.
2071 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2068 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2072 cmdutil.checkunfinished(repo)
2069 cmdutil.checkunfinished(repo)
2073
2070
2074 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2071 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2075 if node == old.node():
2072 if node == old.node():
2076 ui.status(_(b"nothing changed\n"))
2073 ui.status(_(b"nothing changed\n"))
2077 return 1
2074 return 1
2078 else:
2075 else:
2079
2076
2080 def commitfunc(ui, repo, message, match, opts):
2077 def commitfunc(ui, repo, message, match, opts):
2081 overrides = {}
2078 overrides = {}
2082 if opts.get(b'secret'):
2079 if opts.get(b'secret'):
2083 overrides[(b'phases', b'new-commit')] = b'secret'
2080 overrides[(b'phases', b'new-commit')] = b'secret'
2084
2081
2085 baseui = repo.baseui
2082 baseui = repo.baseui
2086 with baseui.configoverride(overrides, b'commit'):
2083 with baseui.configoverride(overrides, b'commit'):
2087 with ui.configoverride(overrides, b'commit'):
2084 with ui.configoverride(overrides, b'commit'):
2088 editform = cmdutil.mergeeditform(
2085 editform = cmdutil.mergeeditform(
2089 repo[None], b'commit.normal'
2086 repo[None], b'commit.normal'
2090 )
2087 )
2091 editor = cmdutil.getcommiteditor(
2088 editor = cmdutil.getcommiteditor(
2092 editform=editform, **pycompat.strkwargs(opts)
2089 editform=editform, **pycompat.strkwargs(opts)
2093 )
2090 )
2094 return repo.commit(
2091 return repo.commit(
2095 message,
2092 message,
2096 opts.get(b'user'),
2093 opts.get(b'user'),
2097 opts.get(b'date'),
2094 opts.get(b'date'),
2098 match,
2095 match,
2099 editor=editor,
2096 editor=editor,
2100 extra=extra,
2097 extra=extra,
2101 )
2098 )
2102
2099
2103 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2100 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2104
2101
2105 if not node:
2102 if not node:
2106 stat = cmdutil.postcommitstatus(repo, pats, opts)
2103 stat = cmdutil.postcommitstatus(repo, pats, opts)
2107 if stat.deleted:
2104 if stat.deleted:
2108 ui.status(
2105 ui.status(
2109 _(
2106 _(
2110 b"nothing changed (%d missing files, see "
2107 b"nothing changed (%d missing files, see "
2111 b"'hg status')\n"
2108 b"'hg status')\n"
2112 )
2109 )
2113 % len(stat.deleted)
2110 % len(stat.deleted)
2114 )
2111 )
2115 else:
2112 else:
2116 ui.status(_(b"nothing changed\n"))
2113 ui.status(_(b"nothing changed\n"))
2117 return 1
2114 return 1
2118
2115
2119 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2116 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2120
2117
2121 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2118 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2122 status(
2119 status(
2123 ui,
2120 ui,
2124 repo,
2121 repo,
2125 modified=True,
2122 modified=True,
2126 added=True,
2123 added=True,
2127 removed=True,
2124 removed=True,
2128 deleted=True,
2125 deleted=True,
2129 unknown=True,
2126 unknown=True,
2130 subrepos=opts.get(b'subrepos'),
2127 subrepos=opts.get(b'subrepos'),
2131 )
2128 )
2132
2129
2133
2130
2134 @command(
2131 @command(
2135 b'config|showconfig|debugconfig',
2132 b'config|showconfig|debugconfig',
2136 [
2133 [
2137 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2134 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2138 (b'e', b'edit', None, _(b'edit user config')),
2135 (b'e', b'edit', None, _(b'edit user config')),
2139 (b'l', b'local', None, _(b'edit repository config')),
2136 (b'l', b'local', None, _(b'edit repository config')),
2140 (
2137 (
2141 b'',
2138 b'',
2142 b'shared',
2139 b'shared',
2143 None,
2140 None,
2144 _(b'edit shared source repository config (EXPERIMENTAL)'),
2141 _(b'edit shared source repository config (EXPERIMENTAL)'),
2145 ),
2142 ),
2146 (b'g', b'global', None, _(b'edit global config')),
2143 (b'g', b'global', None, _(b'edit global config')),
2147 ]
2144 ]
2148 + formatteropts,
2145 + formatteropts,
2149 _(b'[-u] [NAME]...'),
2146 _(b'[-u] [NAME]...'),
2150 helpcategory=command.CATEGORY_HELP,
2147 helpcategory=command.CATEGORY_HELP,
2151 optionalrepo=True,
2148 optionalrepo=True,
2152 intents={INTENT_READONLY},
2149 intents={INTENT_READONLY},
2153 )
2150 )
2154 def config(ui, repo, *values, **opts):
2151 def config(ui, repo, *values, **opts):
2155 """show combined config settings from all hgrc files
2152 """show combined config settings from all hgrc files
2156
2153
2157 With no arguments, print names and values of all config items.
2154 With no arguments, print names and values of all config items.
2158
2155
2159 With one argument of the form section.name, print just the value
2156 With one argument of the form section.name, print just the value
2160 of that config item.
2157 of that config item.
2161
2158
2162 With multiple arguments, print names and values of all config
2159 With multiple arguments, print names and values of all config
2163 items with matching section names or section.names.
2160 items with matching section names or section.names.
2164
2161
2165 With --edit, start an editor on the user-level config file. With
2162 With --edit, start an editor on the user-level config file. With
2166 --global, edit the system-wide config file. With --local, edit the
2163 --global, edit the system-wide config file. With --local, edit the
2167 repository-level config file.
2164 repository-level config file.
2168
2165
2169 With --debug, the source (filename and line number) is printed
2166 With --debug, the source (filename and line number) is printed
2170 for each config item.
2167 for each config item.
2171
2168
2172 See :hg:`help config` for more information about config files.
2169 See :hg:`help config` for more information about config files.
2173
2170
2174 .. container:: verbose
2171 .. container:: verbose
2175
2172
2176 Template:
2173 Template:
2177
2174
2178 The following keywords are supported. See also :hg:`help templates`.
2175 The following keywords are supported. See also :hg:`help templates`.
2179
2176
2180 :name: String. Config name.
2177 :name: String. Config name.
2181 :source: String. Filename and line number where the item is defined.
2178 :source: String. Filename and line number where the item is defined.
2182 :value: String. Config value.
2179 :value: String. Config value.
2183
2180
2184 The --shared flag can be used to edit the config file of shared source
2181 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
2182 repository. It only works when you have shared using the experimental
2186 share safe feature.
2183 share safe feature.
2187
2184
2188 Returns 0 on success, 1 if NAME does not exist.
2185 Returns 0 on success, 1 if NAME does not exist.
2189
2186
2190 """
2187 """
2191
2188
2192 opts = pycompat.byteskwargs(opts)
2189 opts = pycompat.byteskwargs(opts)
2193 editopts = (b'edit', b'local', b'global', b'shared')
2190 editopts = (b'edit', b'local', b'global', b'shared')
2194 if any(opts.get(o) for o in editopts):
2191 if any(opts.get(o) for o in editopts):
2195 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2192 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2196 if opts.get(b'local'):
2193 if opts.get(b'local'):
2197 if not repo:
2194 if not repo:
2198 raise error.Abort(_(b"can't use --local outside a repository"))
2195 raise error.Abort(_(b"can't use --local outside a repository"))
2199 paths = [repo.vfs.join(b'hgrc')]
2196 paths = [repo.vfs.join(b'hgrc')]
2200 elif opts.get(b'global'):
2197 elif opts.get(b'global'):
2201 paths = rcutil.systemrcpath()
2198 paths = rcutil.systemrcpath()
2202 elif opts.get(b'shared'):
2199 elif opts.get(b'shared'):
2203 if not repo.shared():
2200 if not repo.shared():
2204 raise error.Abort(
2201 raise error.Abort(
2205 _(b"repository is not shared; can't use --shared")
2202 _(b"repository is not shared; can't use --shared")
2206 )
2203 )
2207 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2204 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2208 raise error.Abort(
2205 raise error.Abort(
2209 _(
2206 _(
2210 b"share safe feature not unabled; "
2207 b"share safe feature not unabled; "
2211 b"unable to edit shared source repository config"
2208 b"unable to edit shared source repository config"
2212 )
2209 )
2213 )
2210 )
2214 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2211 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2215 else:
2212 else:
2216 paths = rcutil.userrcpath()
2213 paths = rcutil.userrcpath()
2217
2214
2218 for f in paths:
2215 for f in paths:
2219 if os.path.exists(f):
2216 if os.path.exists(f):
2220 break
2217 break
2221 else:
2218 else:
2222 if opts.get(b'global'):
2219 if opts.get(b'global'):
2223 samplehgrc = uimod.samplehgrcs[b'global']
2220 samplehgrc = uimod.samplehgrcs[b'global']
2224 elif opts.get(b'local'):
2221 elif opts.get(b'local'):
2225 samplehgrc = uimod.samplehgrcs[b'local']
2222 samplehgrc = uimod.samplehgrcs[b'local']
2226 else:
2223 else:
2227 samplehgrc = uimod.samplehgrcs[b'user']
2224 samplehgrc = uimod.samplehgrcs[b'user']
2228
2225
2229 f = paths[0]
2226 f = paths[0]
2230 fp = open(f, b"wb")
2227 fp = open(f, b"wb")
2231 fp.write(util.tonativeeol(samplehgrc))
2228 fp.write(util.tonativeeol(samplehgrc))
2232 fp.close()
2229 fp.close()
2233
2230
2234 editor = ui.geteditor()
2231 editor = ui.geteditor()
2235 ui.system(
2232 ui.system(
2236 b"%s \"%s\"" % (editor, f),
2233 b"%s \"%s\"" % (editor, f),
2237 onerr=error.Abort,
2234 onerr=error.Abort,
2238 errprefix=_(b"edit failed"),
2235 errprefix=_(b"edit failed"),
2239 blockedtag=b'config_edit',
2236 blockedtag=b'config_edit',
2240 )
2237 )
2241 return
2238 return
2242 ui.pager(b'config')
2239 ui.pager(b'config')
2243 fm = ui.formatter(b'config', opts)
2240 fm = ui.formatter(b'config', opts)
2244 for t, f in rcutil.rccomponents():
2241 for t, f in rcutil.rccomponents():
2245 if t == b'path':
2242 if t == b'path':
2246 ui.debug(b'read config from: %s\n' % f)
2243 ui.debug(b'read config from: %s\n' % f)
2247 elif t == b'resource':
2244 elif t == b'resource':
2248 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2245 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2249 elif t == b'items':
2246 elif t == b'items':
2250 # Don't print anything for 'items'.
2247 # Don't print anything for 'items'.
2251 pass
2248 pass
2252 else:
2249 else:
2253 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2250 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2254 untrusted = bool(opts.get(b'untrusted'))
2251 untrusted = bool(opts.get(b'untrusted'))
2255
2252
2256 selsections = selentries = []
2253 selsections = selentries = []
2257 if values:
2254 if values:
2258 selsections = [v for v in values if b'.' not in v]
2255 selsections = [v for v in values if b'.' not in v]
2259 selentries = [v for v in values if b'.' in v]
2256 selentries = [v for v in values if b'.' in v]
2260 uniquesel = len(selentries) == 1 and not selsections
2257 uniquesel = len(selentries) == 1 and not selsections
2261 selsections = set(selsections)
2258 selsections = set(selsections)
2262 selentries = set(selentries)
2259 selentries = set(selentries)
2263
2260
2264 matched = False
2261 matched = False
2265 for section, name, value in ui.walkconfig(untrusted=untrusted):
2262 for section, name, value in ui.walkconfig(untrusted=untrusted):
2266 source = ui.configsource(section, name, untrusted)
2263 source = ui.configsource(section, name, untrusted)
2267 value = pycompat.bytestr(value)
2264 value = pycompat.bytestr(value)
2268 defaultvalue = ui.configdefault(section, name)
2265 defaultvalue = ui.configdefault(section, name)
2269 if fm.isplain():
2266 if fm.isplain():
2270 source = source or b'none'
2267 source = source or b'none'
2271 value = value.replace(b'\n', b'\\n')
2268 value = value.replace(b'\n', b'\\n')
2272 entryname = section + b'.' + name
2269 entryname = section + b'.' + name
2273 if values and not (section in selsections or entryname in selentries):
2270 if values and not (section in selsections or entryname in selentries):
2274 continue
2271 continue
2275 fm.startitem()
2272 fm.startitem()
2276 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2273 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2277 if uniquesel:
2274 if uniquesel:
2278 fm.data(name=entryname)
2275 fm.data(name=entryname)
2279 fm.write(b'value', b'%s\n', value)
2276 fm.write(b'value', b'%s\n', value)
2280 else:
2277 else:
2281 fm.write(b'name value', b'%s=%s\n', entryname, value)
2278 fm.write(b'name value', b'%s=%s\n', entryname, value)
2282 if formatter.isprintable(defaultvalue):
2279 if formatter.isprintable(defaultvalue):
2283 fm.data(defaultvalue=defaultvalue)
2280 fm.data(defaultvalue=defaultvalue)
2284 elif isinstance(defaultvalue, list) and all(
2281 elif isinstance(defaultvalue, list) and all(
2285 formatter.isprintable(e) for e in defaultvalue
2282 formatter.isprintable(e) for e in defaultvalue
2286 ):
2283 ):
2287 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2284 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2288 # TODO: no idea how to process unsupported defaultvalue types
2285 # TODO: no idea how to process unsupported defaultvalue types
2289 matched = True
2286 matched = True
2290 fm.end()
2287 fm.end()
2291 if matched:
2288 if matched:
2292 return 0
2289 return 0
2293 return 1
2290 return 1
2294
2291
2295
2292
2296 @command(
2293 @command(
2297 b'continue',
2294 b'continue',
2298 dryrunopts,
2295 dryrunopts,
2299 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2296 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2300 helpbasic=True,
2297 helpbasic=True,
2301 )
2298 )
2302 def continuecmd(ui, repo, **opts):
2299 def continuecmd(ui, repo, **opts):
2303 """resumes an interrupted operation (EXPERIMENTAL)
2300 """resumes an interrupted operation (EXPERIMENTAL)
2304
2301
2305 Finishes a multistep operation like graft, histedit, rebase, merge,
2302 Finishes a multistep operation like graft, histedit, rebase, merge,
2306 and unshelve if they are in an interrupted state.
2303 and unshelve if they are in an interrupted state.
2307
2304
2308 use --dry-run/-n to dry run the command.
2305 use --dry-run/-n to dry run the command.
2309 """
2306 """
2310 dryrun = opts.get('dry_run')
2307 dryrun = opts.get('dry_run')
2311 contstate = cmdutil.getunfinishedstate(repo)
2308 contstate = cmdutil.getunfinishedstate(repo)
2312 if not contstate:
2309 if not contstate:
2313 raise error.Abort(_(b'no operation in progress'))
2310 raise error.Abort(_(b'no operation in progress'))
2314 if not contstate.continuefunc:
2311 if not contstate.continuefunc:
2315 raise error.Abort(
2312 raise error.Abort(
2316 (
2313 (
2317 _(b"%s in progress but does not support 'hg continue'")
2314 _(b"%s in progress but does not support 'hg continue'")
2318 % (contstate._opname)
2315 % (contstate._opname)
2319 ),
2316 ),
2320 hint=contstate.continuemsg(),
2317 hint=contstate.continuemsg(),
2321 )
2318 )
2322 if dryrun:
2319 if dryrun:
2323 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2320 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2324 return
2321 return
2325 return contstate.continuefunc(ui, repo)
2322 return contstate.continuefunc(ui, repo)
2326
2323
2327
2324
2328 @command(
2325 @command(
2329 b'copy|cp',
2326 b'copy|cp',
2330 [
2327 [
2331 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2328 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2332 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2329 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2333 (
2330 (
2334 b'',
2331 b'',
2335 b'at-rev',
2332 b'at-rev',
2336 b'',
2333 b'',
2337 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2334 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2338 _(b'REV'),
2335 _(b'REV'),
2339 ),
2336 ),
2340 (
2337 (
2341 b'f',
2338 b'f',
2342 b'force',
2339 b'force',
2343 None,
2340 None,
2344 _(b'forcibly copy over an existing managed file'),
2341 _(b'forcibly copy over an existing managed file'),
2345 ),
2342 ),
2346 ]
2343 ]
2347 + walkopts
2344 + walkopts
2348 + dryrunopts,
2345 + dryrunopts,
2349 _(b'[OPTION]... SOURCE... DEST'),
2346 _(b'[OPTION]... SOURCE... DEST'),
2350 helpcategory=command.CATEGORY_FILE_CONTENTS,
2347 helpcategory=command.CATEGORY_FILE_CONTENTS,
2351 )
2348 )
2352 def copy(ui, repo, *pats, **opts):
2349 def copy(ui, repo, *pats, **opts):
2353 """mark files as copied for the next commit
2350 """mark files as copied for the next commit
2354
2351
2355 Mark dest as having copies of source files. If dest is a
2352 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,
2353 directory, copies are put in that directory. If dest is a file,
2357 the source must be a single file.
2354 the source must be a single file.
2358
2355
2359 By default, this command copies the contents of files as they
2356 By default, this command copies the contents of files as they
2360 exist in the working directory. If invoked with -A/--after, the
2357 exist in the working directory. If invoked with -A/--after, the
2361 operation is recorded, but no copying is performed.
2358 operation is recorded, but no copying is performed.
2362
2359
2363 To undo marking a destination file as copied, use --forget. With that
2360 To undo marking a destination file as copied, use --forget. With that
2364 option, all given (positional) arguments are unmarked as copies. The
2361 option, all given (positional) arguments are unmarked as copies. The
2365 destination file(s) will be left in place (still tracked).
2362 destination file(s) will be left in place (still tracked).
2366
2363
2367 This command takes effect with the next commit by default.
2364 This command takes effect with the next commit by default.
2368
2365
2369 Returns 0 on success, 1 if errors are encountered.
2366 Returns 0 on success, 1 if errors are encountered.
2370 """
2367 """
2371 opts = pycompat.byteskwargs(opts)
2368 opts = pycompat.byteskwargs(opts)
2372 with repo.wlock():
2369 with repo.wlock():
2373 return cmdutil.copy(ui, repo, pats, opts)
2370 return cmdutil.copy(ui, repo, pats, opts)
2374
2371
2375
2372
2376 @command(
2373 @command(
2377 b'debugcommands',
2374 b'debugcommands',
2378 [],
2375 [],
2379 _(b'[COMMAND]'),
2376 _(b'[COMMAND]'),
2380 helpcategory=command.CATEGORY_HELP,
2377 helpcategory=command.CATEGORY_HELP,
2381 norepo=True,
2378 norepo=True,
2382 )
2379 )
2383 def debugcommands(ui, cmd=b'', *args):
2380 def debugcommands(ui, cmd=b'', *args):
2384 """list all available commands and options"""
2381 """list all available commands and options"""
2385 for cmd, vals in sorted(pycompat.iteritems(table)):
2382 for cmd, vals in sorted(pycompat.iteritems(table)):
2386 cmd = cmd.split(b'|')[0]
2383 cmd = cmd.split(b'|')[0]
2387 opts = b', '.join([i[1] for i in vals[1]])
2384 opts = b', '.join([i[1] for i in vals[1]])
2388 ui.write(b'%s: %s\n' % (cmd, opts))
2385 ui.write(b'%s: %s\n' % (cmd, opts))
2389
2386
2390
2387
2391 @command(
2388 @command(
2392 b'debugcomplete',
2389 b'debugcomplete',
2393 [(b'o', b'options', None, _(b'show the command options'))],
2390 [(b'o', b'options', None, _(b'show the command options'))],
2394 _(b'[-o] CMD'),
2391 _(b'[-o] CMD'),
2395 helpcategory=command.CATEGORY_HELP,
2392 helpcategory=command.CATEGORY_HELP,
2396 norepo=True,
2393 norepo=True,
2397 )
2394 )
2398 def debugcomplete(ui, cmd=b'', **opts):
2395 def debugcomplete(ui, cmd=b'', **opts):
2399 """returns the completion list associated with the given command"""
2396 """returns the completion list associated with the given command"""
2400
2397
2401 if opts.get('options'):
2398 if opts.get('options'):
2402 options = []
2399 options = []
2403 otables = [globalopts]
2400 otables = [globalopts]
2404 if cmd:
2401 if cmd:
2405 aliases, entry = cmdutil.findcmd(cmd, table, False)
2402 aliases, entry = cmdutil.findcmd(cmd, table, False)
2406 otables.append(entry[1])
2403 otables.append(entry[1])
2407 for t in otables:
2404 for t in otables:
2408 for o in t:
2405 for o in t:
2409 if b"(DEPRECATED)" in o[3]:
2406 if b"(DEPRECATED)" in o[3]:
2410 continue
2407 continue
2411 if o[0]:
2408 if o[0]:
2412 options.append(b'-%s' % o[0])
2409 options.append(b'-%s' % o[0])
2413 options.append(b'--%s' % o[1])
2410 options.append(b'--%s' % o[1])
2414 ui.write(b"%s\n" % b"\n".join(options))
2411 ui.write(b"%s\n" % b"\n".join(options))
2415 return
2412 return
2416
2413
2417 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2414 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2418 if ui.verbose:
2415 if ui.verbose:
2419 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2416 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2420 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2417 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2421
2418
2422
2419
2423 @command(
2420 @command(
2424 b'diff',
2421 b'diff',
2425 [
2422 [
2426 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2423 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2427 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2424 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2428 ]
2425 ]
2429 + diffopts
2426 + diffopts
2430 + diffopts2
2427 + diffopts2
2431 + walkopts
2428 + walkopts
2432 + subrepoopts,
2429 + subrepoopts,
2433 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2430 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2434 helpcategory=command.CATEGORY_FILE_CONTENTS,
2431 helpcategory=command.CATEGORY_FILE_CONTENTS,
2435 helpbasic=True,
2432 helpbasic=True,
2436 inferrepo=True,
2433 inferrepo=True,
2437 intents={INTENT_READONLY},
2434 intents={INTENT_READONLY},
2438 )
2435 )
2439 def diff(ui, repo, *pats, **opts):
2436 def diff(ui, repo, *pats, **opts):
2440 """diff repository (or selected files)
2437 """diff repository (or selected files)
2441
2438
2442 Show differences between revisions for the specified files.
2439 Show differences between revisions for the specified files.
2443
2440
2444 Differences between files are shown using the unified diff format.
2441 Differences between files are shown using the unified diff format.
2445
2442
2446 .. note::
2443 .. note::
2447
2444
2448 :hg:`diff` may generate unexpected results for merges, as it will
2445 :hg:`diff` may generate unexpected results for merges, as it will
2449 default to comparing against the working directory's first
2446 default to comparing against the working directory's first
2450 parent changeset if no revisions are specified.
2447 parent changeset if no revisions are specified.
2451
2448
2452 When two revision arguments are given, then changes are shown
2449 When two revision arguments are given, then changes are shown
2453 between those revisions. If only one revision is specified then
2450 between those revisions. If only one revision is specified then
2454 that revision is compared to the working directory, and, when no
2451 that revision is compared to the working directory, and, when no
2455 revisions are specified, the working directory files are compared
2452 revisions are specified, the working directory files are compared
2456 to its first parent.
2453 to its first parent.
2457
2454
2458 Alternatively you can specify -c/--change with a revision to see
2455 Alternatively you can specify -c/--change with a revision to see
2459 the changes in that changeset relative to its first parent.
2456 the changes in that changeset relative to its first parent.
2460
2457
2461 Without the -a/--text option, diff will avoid generating diffs of
2458 Without the -a/--text option, diff will avoid generating diffs of
2462 files it detects as binary. With -a, diff will generate a diff
2459 files it detects as binary. With -a, diff will generate a diff
2463 anyway, probably with undesirable results.
2460 anyway, probably with undesirable results.
2464
2461
2465 Use the -g/--git option to generate diffs in the git extended diff
2462 Use the -g/--git option to generate diffs in the git extended diff
2466 format. For more information, read :hg:`help diffs`.
2463 format. For more information, read :hg:`help diffs`.
2467
2464
2468 .. container:: verbose
2465 .. container:: verbose
2469
2466
2470 Examples:
2467 Examples:
2471
2468
2472 - compare a file in the current working directory to its parent::
2469 - compare a file in the current working directory to its parent::
2473
2470
2474 hg diff foo.c
2471 hg diff foo.c
2475
2472
2476 - compare two historical versions of a directory, with rename info::
2473 - compare two historical versions of a directory, with rename info::
2477
2474
2478 hg diff --git -r 1.0:1.2 lib/
2475 hg diff --git -r 1.0:1.2 lib/
2479
2476
2480 - get change stats relative to the last change on some date::
2477 - get change stats relative to the last change on some date::
2481
2478
2482 hg diff --stat -r "date('may 2')"
2479 hg diff --stat -r "date('may 2')"
2483
2480
2484 - diff all newly-added files that contain a keyword::
2481 - diff all newly-added files that contain a keyword::
2485
2482
2486 hg diff "set:added() and grep(GNU)"
2483 hg diff "set:added() and grep(GNU)"
2487
2484
2488 - compare a revision and its parents::
2485 - compare a revision and its parents::
2489
2486
2490 hg diff -c 9353 # compare against first parent
2487 hg diff -c 9353 # compare against first parent
2491 hg diff -r 9353^:9353 # same using revset syntax
2488 hg diff -r 9353^:9353 # same using revset syntax
2492 hg diff -r 9353^2:9353 # compare against the second parent
2489 hg diff -r 9353^2:9353 # compare against the second parent
2493
2490
2494 Returns 0 on success.
2491 Returns 0 on success.
2495 """
2492 """
2496
2493
2497 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2494 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2498 opts = pycompat.byteskwargs(opts)
2495 opts = pycompat.byteskwargs(opts)
2499 revs = opts.get(b'rev')
2496 revs = opts.get(b'rev')
2500 change = opts.get(b'change')
2497 change = opts.get(b'change')
2501 stat = opts.get(b'stat')
2498 stat = opts.get(b'stat')
2502 reverse = opts.get(b'reverse')
2499 reverse = opts.get(b'reverse')
2503
2500
2504 if change:
2501 if change:
2505 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2502 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2506 ctx2 = scmutil.revsingle(repo, change, None)
2503 ctx2 = scmutil.revsingle(repo, change, None)
2507 ctx1 = ctx2.p1()
2504 ctx1 = ctx2.p1()
2508 else:
2505 else:
2509 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2506 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2510 ctx1, ctx2 = scmutil.revpair(repo, revs)
2507 ctx1, ctx2 = scmutil.revpair(repo, revs)
2511
2508
2512 if reverse:
2509 if reverse:
2513 ctxleft = ctx2
2510 ctxleft = ctx2
2514 ctxright = ctx1
2511 ctxright = ctx1
2515 else:
2512 else:
2516 ctxleft = ctx1
2513 ctxleft = ctx1
2517 ctxright = ctx2
2514 ctxright = ctx2
2518
2515
2519 diffopts = patch.diffallopts(ui, opts)
2516 diffopts = patch.diffallopts(ui, opts)
2520 m = scmutil.match(ctx2, pats, opts)
2517 m = scmutil.match(ctx2, pats, opts)
2521 m = repo.narrowmatch(m)
2518 m = repo.narrowmatch(m)
2522 ui.pager(b'diff')
2519 ui.pager(b'diff')
2523 logcmdutil.diffordiffstat(
2520 logcmdutil.diffordiffstat(
2524 ui,
2521 ui,
2525 repo,
2522 repo,
2526 diffopts,
2523 diffopts,
2527 ctxleft,
2524 ctxleft,
2528 ctxright,
2525 ctxright,
2529 m,
2526 m,
2530 stat=stat,
2527 stat=stat,
2531 listsubrepos=opts.get(b'subrepos'),
2528 listsubrepos=opts.get(b'subrepos'),
2532 root=opts.get(b'root'),
2529 root=opts.get(b'root'),
2533 )
2530 )
2534
2531
2535
2532
2536 @command(
2533 @command(
2537 b'export',
2534 b'export',
2538 [
2535 [
2539 (
2536 (
2540 b'B',
2537 b'B',
2541 b'bookmark',
2538 b'bookmark',
2542 b'',
2539 b'',
2543 _(b'export changes only reachable by given bookmark'),
2540 _(b'export changes only reachable by given bookmark'),
2544 _(b'BOOKMARK'),
2541 _(b'BOOKMARK'),
2545 ),
2542 ),
2546 (
2543 (
2547 b'o',
2544 b'o',
2548 b'output',
2545 b'output',
2549 b'',
2546 b'',
2550 _(b'print output to file with formatted name'),
2547 _(b'print output to file with formatted name'),
2551 _(b'FORMAT'),
2548 _(b'FORMAT'),
2552 ),
2549 ),
2553 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2550 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2554 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2551 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2555 ]
2552 ]
2556 + diffopts
2553 + diffopts
2557 + formatteropts,
2554 + formatteropts,
2558 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2555 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2559 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2556 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2560 helpbasic=True,
2557 helpbasic=True,
2561 intents={INTENT_READONLY},
2558 intents={INTENT_READONLY},
2562 )
2559 )
2563 def export(ui, repo, *changesets, **opts):
2560 def export(ui, repo, *changesets, **opts):
2564 """dump the header and diffs for one or more changesets
2561 """dump the header and diffs for one or more changesets
2565
2562
2566 Print the changeset header and diffs for one or more revisions.
2563 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.
2564 If no revision is given, the parent of the working directory is used.
2568
2565
2569 The information shown in the changeset header is: author, date,
2566 The information shown in the changeset header is: author, date,
2570 branch name (if non-default), changeset hash, parent(s) and commit
2567 branch name (if non-default), changeset hash, parent(s) and commit
2571 comment.
2568 comment.
2572
2569
2573 .. note::
2570 .. note::
2574
2571
2575 :hg:`export` may generate unexpected diff output for merge
2572 :hg:`export` may generate unexpected diff output for merge
2576 changesets, as it will compare the merge changeset against its
2573 changesets, as it will compare the merge changeset against its
2577 first parent only.
2574 first parent only.
2578
2575
2579 Output may be to a file, in which case the name of the file is
2576 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
2577 given using a template string. See :hg:`help templates`. In addition
2581 to the common template keywords, the following formatting rules are
2578 to the common template keywords, the following formatting rules are
2582 supported:
2579 supported:
2583
2580
2584 :``%%``: literal "%" character
2581 :``%%``: literal "%" character
2585 :``%H``: changeset hash (40 hexadecimal digits)
2582 :``%H``: changeset hash (40 hexadecimal digits)
2586 :``%N``: number of patches being generated
2583 :``%N``: number of patches being generated
2587 :``%R``: changeset revision number
2584 :``%R``: changeset revision number
2588 :``%b``: basename of the exporting repository
2585 :``%b``: basename of the exporting repository
2589 :``%h``: short-form changeset hash (12 hexadecimal digits)
2586 :``%h``: short-form changeset hash (12 hexadecimal digits)
2590 :``%m``: first line of the commit message (only alphanumeric characters)
2587 :``%m``: first line of the commit message (only alphanumeric characters)
2591 :``%n``: zero-padded sequence number, starting at 1
2588 :``%n``: zero-padded sequence number, starting at 1
2592 :``%r``: zero-padded changeset revision number
2589 :``%r``: zero-padded changeset revision number
2593 :``\\``: literal "\\" character
2590 :``\\``: literal "\\" character
2594
2591
2595 Without the -a/--text option, export will avoid generating diffs
2592 Without the -a/--text option, export will avoid generating diffs
2596 of files it detects as binary. With -a, export will generate a
2593 of files it detects as binary. With -a, export will generate a
2597 diff anyway, probably with undesirable results.
2594 diff anyway, probably with undesirable results.
2598
2595
2599 With -B/--bookmark changesets reachable by the given bookmark are
2596 With -B/--bookmark changesets reachable by the given bookmark are
2600 selected.
2597 selected.
2601
2598
2602 Use the -g/--git option to generate diffs in the git extended diff
2599 Use the -g/--git option to generate diffs in the git extended diff
2603 format. See :hg:`help diffs` for more information.
2600 format. See :hg:`help diffs` for more information.
2604
2601
2605 With the --switch-parent option, the diff will be against the
2602 With the --switch-parent option, the diff will be against the
2606 second parent. It can be useful to review a merge.
2603 second parent. It can be useful to review a merge.
2607
2604
2608 .. container:: verbose
2605 .. container:: verbose
2609
2606
2610 Template:
2607 Template:
2611
2608
2612 The following keywords are supported in addition to the common template
2609 The following keywords are supported in addition to the common template
2613 keywords and functions. See also :hg:`help templates`.
2610 keywords and functions. See also :hg:`help templates`.
2614
2611
2615 :diff: String. Diff content.
2612 :diff: String. Diff content.
2616 :parents: List of strings. Parent nodes of the changeset.
2613 :parents: List of strings. Parent nodes of the changeset.
2617
2614
2618 Examples:
2615 Examples:
2619
2616
2620 - use export and import to transplant a bugfix to the current
2617 - use export and import to transplant a bugfix to the current
2621 branch::
2618 branch::
2622
2619
2623 hg export -r 9353 | hg import -
2620 hg export -r 9353 | hg import -
2624
2621
2625 - export all the changesets between two revisions to a file with
2622 - export all the changesets between two revisions to a file with
2626 rename information::
2623 rename information::
2627
2624
2628 hg export --git -r 123:150 > changes.txt
2625 hg export --git -r 123:150 > changes.txt
2629
2626
2630 - split outgoing changes into a series of patches with
2627 - split outgoing changes into a series of patches with
2631 descriptive names::
2628 descriptive names::
2632
2629
2633 hg export -r "outgoing()" -o "%n-%m.patch"
2630 hg export -r "outgoing()" -o "%n-%m.patch"
2634
2631
2635 Returns 0 on success.
2632 Returns 0 on success.
2636 """
2633 """
2637 opts = pycompat.byteskwargs(opts)
2634 opts = pycompat.byteskwargs(opts)
2638 bookmark = opts.get(b'bookmark')
2635 bookmark = opts.get(b'bookmark')
2639 changesets += tuple(opts.get(b'rev', []))
2636 changesets += tuple(opts.get(b'rev', []))
2640
2637
2641 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2638 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2642
2639
2643 if bookmark:
2640 if bookmark:
2644 if bookmark not in repo._bookmarks:
2641 if bookmark not in repo._bookmarks:
2645 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2642 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2646
2643
2647 revs = scmutil.bookmarkrevs(repo, bookmark)
2644 revs = scmutil.bookmarkrevs(repo, bookmark)
2648 else:
2645 else:
2649 if not changesets:
2646 if not changesets:
2650 changesets = [b'.']
2647 changesets = [b'.']
2651
2648
2652 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2649 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2653 revs = scmutil.revrange(repo, changesets)
2650 revs = scmutil.revrange(repo, changesets)
2654
2651
2655 if not revs:
2652 if not revs:
2656 raise error.Abort(_(b"export requires at least one changeset"))
2653 raise error.Abort(_(b"export requires at least one changeset"))
2657 if len(revs) > 1:
2654 if len(revs) > 1:
2658 ui.note(_(b'exporting patches:\n'))
2655 ui.note(_(b'exporting patches:\n'))
2659 else:
2656 else:
2660 ui.note(_(b'exporting patch:\n'))
2657 ui.note(_(b'exporting patch:\n'))
2661
2658
2662 fntemplate = opts.get(b'output')
2659 fntemplate = opts.get(b'output')
2663 if cmdutil.isstdiofilename(fntemplate):
2660 if cmdutil.isstdiofilename(fntemplate):
2664 fntemplate = b''
2661 fntemplate = b''
2665
2662
2666 if fntemplate:
2663 if fntemplate:
2667 fm = formatter.nullformatter(ui, b'export', opts)
2664 fm = formatter.nullformatter(ui, b'export', opts)
2668 else:
2665 else:
2669 ui.pager(b'export')
2666 ui.pager(b'export')
2670 fm = ui.formatter(b'export', opts)
2667 fm = ui.formatter(b'export', opts)
2671 with fm:
2668 with fm:
2672 cmdutil.export(
2669 cmdutil.export(
2673 repo,
2670 repo,
2674 revs,
2671 revs,
2675 fm,
2672 fm,
2676 fntemplate=fntemplate,
2673 fntemplate=fntemplate,
2677 switch_parent=opts.get(b'switch_parent'),
2674 switch_parent=opts.get(b'switch_parent'),
2678 opts=patch.diffallopts(ui, opts),
2675 opts=patch.diffallopts(ui, opts),
2679 )
2676 )
2680
2677
2681
2678
2682 @command(
2679 @command(
2683 b'files',
2680 b'files',
2684 [
2681 [
2685 (
2682 (
2686 b'r',
2683 b'r',
2687 b'rev',
2684 b'rev',
2688 b'',
2685 b'',
2689 _(b'search the repository as it is in REV'),
2686 _(b'search the repository as it is in REV'),
2690 _(b'REV'),
2687 _(b'REV'),
2691 ),
2688 ),
2692 (
2689 (
2693 b'0',
2690 b'0',
2694 b'print0',
2691 b'print0',
2695 None,
2692 None,
2696 _(b'end filenames with NUL, for use with xargs'),
2693 _(b'end filenames with NUL, for use with xargs'),
2697 ),
2694 ),
2698 ]
2695 ]
2699 + walkopts
2696 + walkopts
2700 + formatteropts
2697 + formatteropts
2701 + subrepoopts,
2698 + subrepoopts,
2702 _(b'[OPTION]... [FILE]...'),
2699 _(b'[OPTION]... [FILE]...'),
2703 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2700 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2704 intents={INTENT_READONLY},
2701 intents={INTENT_READONLY},
2705 )
2702 )
2706 def files(ui, repo, *pats, **opts):
2703 def files(ui, repo, *pats, **opts):
2707 """list tracked files
2704 """list tracked files
2708
2705
2709 Print files under Mercurial control in the working directory or
2706 Print files under Mercurial control in the working directory or
2710 specified revision for given files (excluding removed files).
2707 specified revision for given files (excluding removed files).
2711 Files can be specified as filenames or filesets.
2708 Files can be specified as filenames or filesets.
2712
2709
2713 If no files are given to match, this command prints the names
2710 If no files are given to match, this command prints the names
2714 of all files under Mercurial control.
2711 of all files under Mercurial control.
2715
2712
2716 .. container:: verbose
2713 .. container:: verbose
2717
2714
2718 Template:
2715 Template:
2719
2716
2720 The following keywords are supported in addition to the common template
2717 The following keywords are supported in addition to the common template
2721 keywords and functions. See also :hg:`help templates`.
2718 keywords and functions. See also :hg:`help templates`.
2722
2719
2723 :flags: String. Character denoting file's symlink and executable bits.
2720 :flags: String. Character denoting file's symlink and executable bits.
2724 :path: String. Repository-absolute path of the file.
2721 :path: String. Repository-absolute path of the file.
2725 :size: Integer. Size of the file in bytes.
2722 :size: Integer. Size of the file in bytes.
2726
2723
2727 Examples:
2724 Examples:
2728
2725
2729 - list all files under the current directory::
2726 - list all files under the current directory::
2730
2727
2731 hg files .
2728 hg files .
2732
2729
2733 - shows sizes and flags for current revision::
2730 - shows sizes and flags for current revision::
2734
2731
2735 hg files -vr .
2732 hg files -vr .
2736
2733
2737 - list all files named README::
2734 - list all files named README::
2738
2735
2739 hg files -I "**/README"
2736 hg files -I "**/README"
2740
2737
2741 - list all binary files::
2738 - list all binary files::
2742
2739
2743 hg files "set:binary()"
2740 hg files "set:binary()"
2744
2741
2745 - find files containing a regular expression::
2742 - find files containing a regular expression::
2746
2743
2747 hg files "set:grep('bob')"
2744 hg files "set:grep('bob')"
2748
2745
2749 - search tracked file contents with xargs and grep::
2746 - search tracked file contents with xargs and grep::
2750
2747
2751 hg files -0 | xargs -0 grep foo
2748 hg files -0 | xargs -0 grep foo
2752
2749
2753 See :hg:`help patterns` and :hg:`help filesets` for more information
2750 See :hg:`help patterns` and :hg:`help filesets` for more information
2754 on specifying file patterns.
2751 on specifying file patterns.
2755
2752
2756 Returns 0 if a match is found, 1 otherwise.
2753 Returns 0 if a match is found, 1 otherwise.
2757
2754
2758 """
2755 """
2759
2756
2760 opts = pycompat.byteskwargs(opts)
2757 opts = pycompat.byteskwargs(opts)
2761 rev = opts.get(b'rev')
2758 rev = opts.get(b'rev')
2762 if rev:
2759 if rev:
2763 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2760 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2764 ctx = scmutil.revsingle(repo, rev, None)
2761 ctx = scmutil.revsingle(repo, rev, None)
2765
2762
2766 end = b'\n'
2763 end = b'\n'
2767 if opts.get(b'print0'):
2764 if opts.get(b'print0'):
2768 end = b'\0'
2765 end = b'\0'
2769 fmt = b'%s' + end
2766 fmt = b'%s' + end
2770
2767
2771 m = scmutil.match(ctx, pats, opts)
2768 m = scmutil.match(ctx, pats, opts)
2772 ui.pager(b'files')
2769 ui.pager(b'files')
2773 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2770 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2774 with ui.formatter(b'files', opts) as fm:
2771 with ui.formatter(b'files', opts) as fm:
2775 return cmdutil.files(
2772 return cmdutil.files(
2776 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2773 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2777 )
2774 )
2778
2775
2779
2776
2780 @command(
2777 @command(
2781 b'forget',
2778 b'forget',
2782 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2779 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2783 + walkopts
2780 + walkopts
2784 + dryrunopts,
2781 + dryrunopts,
2785 _(b'[OPTION]... FILE...'),
2782 _(b'[OPTION]... FILE...'),
2786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2783 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2787 helpbasic=True,
2784 helpbasic=True,
2788 inferrepo=True,
2785 inferrepo=True,
2789 )
2786 )
2790 def forget(ui, repo, *pats, **opts):
2787 def forget(ui, repo, *pats, **opts):
2791 """forget the specified files on the next commit
2788 """forget the specified files on the next commit
2792
2789
2793 Mark the specified files so they will no longer be tracked
2790 Mark the specified files so they will no longer be tracked
2794 after the next commit.
2791 after the next commit.
2795
2792
2796 This only removes files from the current branch, not from the
2793 This only removes files from the current branch, not from the
2797 entire project history, and it does not delete them from the
2794 entire project history, and it does not delete them from the
2798 working directory.
2795 working directory.
2799
2796
2800 To delete the file from the working directory, see :hg:`remove`.
2797 To delete the file from the working directory, see :hg:`remove`.
2801
2798
2802 To undo a forget before the next commit, see :hg:`add`.
2799 To undo a forget before the next commit, see :hg:`add`.
2803
2800
2804 .. container:: verbose
2801 .. container:: verbose
2805
2802
2806 Examples:
2803 Examples:
2807
2804
2808 - forget newly-added binary files::
2805 - forget newly-added binary files::
2809
2806
2810 hg forget "set:added() and binary()"
2807 hg forget "set:added() and binary()"
2811
2808
2812 - forget files that would be excluded by .hgignore::
2809 - forget files that would be excluded by .hgignore::
2813
2810
2814 hg forget "set:hgignore()"
2811 hg forget "set:hgignore()"
2815
2812
2816 Returns 0 on success.
2813 Returns 0 on success.
2817 """
2814 """
2818
2815
2819 opts = pycompat.byteskwargs(opts)
2816 opts = pycompat.byteskwargs(opts)
2820 if not pats:
2817 if not pats:
2821 raise error.Abort(_(b'no files specified'))
2818 raise error.Abort(_(b'no files specified'))
2822
2819
2823 m = scmutil.match(repo[None], pats, opts)
2820 m = scmutil.match(repo[None], pats, opts)
2824 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2821 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2825 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2822 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2826 rejected = cmdutil.forget(
2823 rejected = cmdutil.forget(
2827 ui,
2824 ui,
2828 repo,
2825 repo,
2829 m,
2826 m,
2830 prefix=b"",
2827 prefix=b"",
2831 uipathfn=uipathfn,
2828 uipathfn=uipathfn,
2832 explicitonly=False,
2829 explicitonly=False,
2833 dryrun=dryrun,
2830 dryrun=dryrun,
2834 interactive=interactive,
2831 interactive=interactive,
2835 )[0]
2832 )[0]
2836 return rejected and 1 or 0
2833 return rejected and 1 or 0
2837
2834
2838
2835
2839 @command(
2836 @command(
2840 b'graft',
2837 b'graft',
2841 [
2838 [
2842 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2839 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2843 (
2840 (
2844 b'',
2841 b'',
2845 b'base',
2842 b'base',
2846 b'',
2843 b'',
2847 _(b'base revision when doing the graft merge (ADVANCED)'),
2844 _(b'base revision when doing the graft merge (ADVANCED)'),
2848 _(b'REV'),
2845 _(b'REV'),
2849 ),
2846 ),
2850 (b'c', b'continue', False, _(b'resume interrupted graft')),
2847 (b'c', b'continue', False, _(b'resume interrupted graft')),
2851 (b'', b'stop', False, _(b'stop interrupted graft')),
2848 (b'', b'stop', False, _(b'stop interrupted graft')),
2852 (b'', b'abort', False, _(b'abort interrupted graft')),
2849 (b'', b'abort', False, _(b'abort interrupted graft')),
2853 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2850 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2854 (b'', b'log', None, _(b'append graft info to log message')),
2851 (b'', b'log', None, _(b'append graft info to log message')),
2855 (
2852 (
2856 b'',
2853 b'',
2857 b'no-commit',
2854 b'no-commit',
2858 None,
2855 None,
2859 _(b"don't commit, just apply the changes in working directory"),
2856 _(b"don't commit, just apply the changes in working directory"),
2860 ),
2857 ),
2861 (b'f', b'force', False, _(b'force graft')),
2858 (b'f', b'force', False, _(b'force graft')),
2862 (
2859 (
2863 b'D',
2860 b'D',
2864 b'currentdate',
2861 b'currentdate',
2865 False,
2862 False,
2866 _(b'record the current date as commit date'),
2863 _(b'record the current date as commit date'),
2867 ),
2864 ),
2868 (
2865 (
2869 b'U',
2866 b'U',
2870 b'currentuser',
2867 b'currentuser',
2871 False,
2868 False,
2872 _(b'record the current user as committer'),
2869 _(b'record the current user as committer'),
2873 ),
2870 ),
2874 ]
2871 ]
2875 + commitopts2
2872 + commitopts2
2876 + mergetoolopts
2873 + mergetoolopts
2877 + dryrunopts,
2874 + dryrunopts,
2878 _(b'[OPTION]... [-r REV]... REV...'),
2875 _(b'[OPTION]... [-r REV]... REV...'),
2879 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2876 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2880 )
2877 )
2881 def graft(ui, repo, *revs, **opts):
2878 def graft(ui, repo, *revs, **opts):
2882 '''copy changes from other branches onto the current branch
2879 '''copy changes from other branches onto the current branch
2883
2880
2884 This command uses Mercurial's merge logic to copy individual
2881 This command uses Mercurial's merge logic to copy individual
2885 changes from other branches without merging branches in the
2882 changes from other branches without merging branches in the
2886 history graph. This is sometimes known as 'backporting' or
2883 history graph. This is sometimes known as 'backporting' or
2887 'cherry-picking'. By default, graft will copy user, date, and
2884 'cherry-picking'. By default, graft will copy user, date, and
2888 description from the source changesets.
2885 description from the source changesets.
2889
2886
2890 Changesets that are ancestors of the current revision, that have
2887 Changesets that are ancestors of the current revision, that have
2891 already been grafted, or that are merges will be skipped.
2888 already been grafted, or that are merges will be skipped.
2892
2889
2893 If --log is specified, log messages will have a comment appended
2890 If --log is specified, log messages will have a comment appended
2894 of the form::
2891 of the form::
2895
2892
2896 (grafted from CHANGESETHASH)
2893 (grafted from CHANGESETHASH)
2897
2894
2898 If --force is specified, revisions will be grafted even if they
2895 If --force is specified, revisions will be grafted even if they
2899 are already ancestors of, or have been grafted to, the destination.
2896 are already ancestors of, or have been grafted to, the destination.
2900 This is useful when the revisions have since been backed out.
2897 This is useful when the revisions have since been backed out.
2901
2898
2902 If a graft merge results in conflicts, the graft process is
2899 If a graft merge results in conflicts, the graft process is
2903 interrupted so that the current merge can be manually resolved.
2900 interrupted so that the current merge can be manually resolved.
2904 Once all conflicts are addressed, the graft process can be
2901 Once all conflicts are addressed, the graft process can be
2905 continued with the -c/--continue option.
2902 continued with the -c/--continue option.
2906
2903
2907 The -c/--continue option reapplies all the earlier options.
2904 The -c/--continue option reapplies all the earlier options.
2908
2905
2909 .. container:: verbose
2906 .. container:: verbose
2910
2907
2911 The --base option exposes more of how graft internally uses merge with a
2908 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
2909 custom base revision. --base can be used to specify another ancestor than
2913 the first and only parent.
2910 the first and only parent.
2914
2911
2915 The command::
2912 The command::
2916
2913
2917 hg graft -r 345 --base 234
2914 hg graft -r 345 --base 234
2918
2915
2919 is thus pretty much the same as::
2916 is thus pretty much the same as::
2920
2917
2921 hg diff -r 234 -r 345 | hg import
2918 hg diff -r 234 -r 345 | hg import
2922
2919
2923 but using merge to resolve conflicts and track moved files.
2920 but using merge to resolve conflicts and track moved files.
2924
2921
2925 The result of a merge can thus be backported as a single commit by
2922 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
2923 specifying one of the merge parents as base, and thus effectively
2927 grafting the changes from the other side.
2924 grafting the changes from the other side.
2928
2925
2929 It is also possible to collapse multiple changesets and clean up history
2926 It is also possible to collapse multiple changesets and clean up history
2930 by specifying another ancestor as base, much like rebase --collapse
2927 by specifying another ancestor as base, much like rebase --collapse
2931 --keep.
2928 --keep.
2932
2929
2933 The commit message can be tweaked after the fact using commit --amend .
2930 The commit message can be tweaked after the fact using commit --amend .
2934
2931
2935 For using non-ancestors as the base to backout changes, see the backout
2932 For using non-ancestors as the base to backout changes, see the backout
2936 command and the hidden --parent option.
2933 command and the hidden --parent option.
2937
2934
2938 .. container:: verbose
2935 .. container:: verbose
2939
2936
2940 Examples:
2937 Examples:
2941
2938
2942 - copy a single change to the stable branch and edit its description::
2939 - copy a single change to the stable branch and edit its description::
2943
2940
2944 hg update stable
2941 hg update stable
2945 hg graft --edit 9393
2942 hg graft --edit 9393
2946
2943
2947 - graft a range of changesets with one exception, updating dates::
2944 - graft a range of changesets with one exception, updating dates::
2948
2945
2949 hg graft -D "2085::2093 and not 2091"
2946 hg graft -D "2085::2093 and not 2091"
2950
2947
2951 - continue a graft after resolving conflicts::
2948 - continue a graft after resolving conflicts::
2952
2949
2953 hg graft -c
2950 hg graft -c
2954
2951
2955 - show the source of a grafted changeset::
2952 - show the source of a grafted changeset::
2956
2953
2957 hg log --debug -r .
2954 hg log --debug -r .
2958
2955
2959 - show revisions sorted by date::
2956 - show revisions sorted by date::
2960
2957
2961 hg log -r "sort(all(), date)"
2958 hg log -r "sort(all(), date)"
2962
2959
2963 - backport the result of a merge as a single commit::
2960 - backport the result of a merge as a single commit::
2964
2961
2965 hg graft -r 123 --base 123^
2962 hg graft -r 123 --base 123^
2966
2963
2967 - land a feature branch as one changeset::
2964 - land a feature branch as one changeset::
2968
2965
2969 hg up -cr default
2966 hg up -cr default
2970 hg graft -r featureX --base "ancestor('featureX', 'default')"
2967 hg graft -r featureX --base "ancestor('featureX', 'default')"
2971
2968
2972 See :hg:`help revisions` for more about specifying revisions.
2969 See :hg:`help revisions` for more about specifying revisions.
2973
2970
2974 Returns 0 on successful completion, 1 if there are unresolved files.
2971 Returns 0 on successful completion, 1 if there are unresolved files.
2975 '''
2972 '''
2976 with repo.wlock():
2973 with repo.wlock():
2977 return _dograft(ui, repo, *revs, **opts)
2974 return _dograft(ui, repo, *revs, **opts)
2978
2975
2979
2976
2980 def _dograft(ui, repo, *revs, **opts):
2977 def _dograft(ui, repo, *revs, **opts):
2981 opts = pycompat.byteskwargs(opts)
2978 opts = pycompat.byteskwargs(opts)
2982 if revs and opts.get(b'rev'):
2979 if revs and opts.get(b'rev'):
2983 ui.warn(
2980 ui.warn(
2984 _(
2981 _(
2985 b'warning: inconsistent use of --rev might give unexpected '
2982 b'warning: inconsistent use of --rev might give unexpected '
2986 b'revision ordering!\n'
2983 b'revision ordering!\n'
2987 )
2984 )
2988 )
2985 )
2989
2986
2990 revs = list(revs)
2987 revs = list(revs)
2991 revs.extend(opts.get(b'rev'))
2988 revs.extend(opts.get(b'rev'))
2992 # a dict of data to be stored in state file
2989 # a dict of data to be stored in state file
2993 statedata = {}
2990 statedata = {}
2994 # list of new nodes created by ongoing graft
2991 # list of new nodes created by ongoing graft
2995 statedata[b'newnodes'] = []
2992 statedata[b'newnodes'] = []
2996
2993
2997 cmdutil.resolvecommitoptions(ui, opts)
2994 cmdutil.resolvecommitoptions(ui, opts)
2998
2995
2999 editor = cmdutil.getcommiteditor(
2996 editor = cmdutil.getcommiteditor(
3000 editform=b'graft', **pycompat.strkwargs(opts)
2997 editform=b'graft', **pycompat.strkwargs(opts)
3001 )
2998 )
3002
2999
3003 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3000 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3004
3001
3005 cont = False
3002 cont = False
3006 if opts.get(b'no_commit'):
3003 if opts.get(b'no_commit'):
3007 cmdutil.check_incompatible_arguments(
3004 cmdutil.check_incompatible_arguments(
3008 opts,
3005 opts,
3009 b'no_commit',
3006 b'no_commit',
3010 [b'edit', b'currentuser', b'currentdate', b'log'],
3007 [b'edit', b'currentuser', b'currentdate', b'log'],
3011 )
3008 )
3012
3009
3013 graftstate = statemod.cmdstate(repo, b'graftstate')
3010 graftstate = statemod.cmdstate(repo, b'graftstate')
3014
3011
3015 if opts.get(b'stop'):
3012 if opts.get(b'stop'):
3016 cmdutil.check_incompatible_arguments(
3013 cmdutil.check_incompatible_arguments(
3017 opts,
3014 opts,
3018 b'stop',
3015 b'stop',
3019 [
3016 [
3020 b'edit',
3017 b'edit',
3021 b'log',
3018 b'log',
3022 b'user',
3019 b'user',
3023 b'date',
3020 b'date',
3024 b'currentdate',
3021 b'currentdate',
3025 b'currentuser',
3022 b'currentuser',
3026 b'rev',
3023 b'rev',
3027 ],
3024 ],
3028 )
3025 )
3029 return _stopgraft(ui, repo, graftstate)
3026 return _stopgraft(ui, repo, graftstate)
3030 elif opts.get(b'abort'):
3027 elif opts.get(b'abort'):
3031 cmdutil.check_incompatible_arguments(
3028 cmdutil.check_incompatible_arguments(
3032 opts,
3029 opts,
3033 b'abort',
3030 b'abort',
3034 [
3031 [
3035 b'edit',
3032 b'edit',
3036 b'log',
3033 b'log',
3037 b'user',
3034 b'user',
3038 b'date',
3035 b'date',
3039 b'currentdate',
3036 b'currentdate',
3040 b'currentuser',
3037 b'currentuser',
3041 b'rev',
3038 b'rev',
3042 ],
3039 ],
3043 )
3040 )
3044 return cmdutil.abortgraft(ui, repo, graftstate)
3041 return cmdutil.abortgraft(ui, repo, graftstate)
3045 elif opts.get(b'continue'):
3042 elif opts.get(b'continue'):
3046 cont = True
3043 cont = True
3047 if revs:
3044 if revs:
3048 raise error.Abort(_(b"can't specify --continue and revisions"))
3045 raise error.Abort(_(b"can't specify --continue and revisions"))
3049 # read in unfinished revisions
3046 # read in unfinished revisions
3050 if graftstate.exists():
3047 if graftstate.exists():
3051 statedata = cmdutil.readgraftstate(repo, graftstate)
3048 statedata = cmdutil.readgraftstate(repo, graftstate)
3052 if statedata.get(b'date'):
3049 if statedata.get(b'date'):
3053 opts[b'date'] = statedata[b'date']
3050 opts[b'date'] = statedata[b'date']
3054 if statedata.get(b'user'):
3051 if statedata.get(b'user'):
3055 opts[b'user'] = statedata[b'user']
3052 opts[b'user'] = statedata[b'user']
3056 if statedata.get(b'log'):
3053 if statedata.get(b'log'):
3057 opts[b'log'] = True
3054 opts[b'log'] = True
3058 if statedata.get(b'no_commit'):
3055 if statedata.get(b'no_commit'):
3059 opts[b'no_commit'] = statedata.get(b'no_commit')
3056 opts[b'no_commit'] = statedata.get(b'no_commit')
3060 if statedata.get(b'base'):
3057 if statedata.get(b'base'):
3061 opts[b'base'] = statedata.get(b'base')
3058 opts[b'base'] = statedata.get(b'base')
3062 nodes = statedata[b'nodes']
3059 nodes = statedata[b'nodes']
3063 revs = [repo[node].rev() for node in nodes]
3060 revs = [repo[node].rev() for node in nodes]
3064 else:
3061 else:
3065 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3062 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3066 else:
3063 else:
3067 if not revs:
3064 if not revs:
3068 raise error.Abort(_(b'no revisions specified'))
3065 raise error.Abort(_(b'no revisions specified'))
3069 cmdutil.checkunfinished(repo)
3066 cmdutil.checkunfinished(repo)
3070 cmdutil.bailifchanged(repo)
3067 cmdutil.bailifchanged(repo)
3071 revs = scmutil.revrange(repo, revs)
3068 revs = scmutil.revrange(repo, revs)
3072
3069
3073 skipped = set()
3070 skipped = set()
3074 basectx = None
3071 basectx = None
3075 if opts.get(b'base'):
3072 if opts.get(b'base'):
3076 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3073 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3077 if basectx is None:
3074 if basectx is None:
3078 # check for merges
3075 # check for merges
3079 for rev in repo.revs(b'%ld and merge()', revs):
3076 for rev in repo.revs(b'%ld and merge()', revs):
3080 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3077 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3081 skipped.add(rev)
3078 skipped.add(rev)
3082 revs = [r for r in revs if r not in skipped]
3079 revs = [r for r in revs if r not in skipped]
3083 if not revs:
3080 if not revs:
3084 return -1
3081 return -1
3085 if basectx is not None and len(revs) != 1:
3082 if basectx is not None and len(revs) != 1:
3086 raise error.Abort(_(b'only one revision allowed with --base '))
3083 raise error.Abort(_(b'only one revision allowed with --base '))
3087
3084
3088 # Don't check in the --continue case, in effect retaining --force across
3085 # Don't check in the --continue case, in effect retaining --force across
3089 # --continues. That's because without --force, any revisions we decided to
3086 # --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
3087 # 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
3088 # 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
3089 # skipped would not have been filtered out, and if they hadn't been applied
3093 # already, they'd have been in the graftstate.
3090 # already, they'd have been in the graftstate.
3094 if not (cont or opts.get(b'force')) and basectx is None:
3091 if not (cont or opts.get(b'force')) and basectx is None:
3095 # check for ancestors of dest branch
3092 # check for ancestors of dest branch
3096 ancestors = repo.revs(b'%ld & (::.)', revs)
3093 ancestors = repo.revs(b'%ld & (::.)', revs)
3097 for rev in ancestors:
3094 for rev in ancestors:
3098 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3095 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3099
3096
3100 revs = [r for r in revs if r not in ancestors]
3097 revs = [r for r in revs if r not in ancestors]
3101
3098
3102 if not revs:
3099 if not revs:
3103 return -1
3100 return -1
3104
3101
3105 # analyze revs for earlier grafts
3102 # analyze revs for earlier grafts
3106 ids = {}
3103 ids = {}
3107 for ctx in repo.set(b"%ld", revs):
3104 for ctx in repo.set(b"%ld", revs):
3108 ids[ctx.hex()] = ctx.rev()
3105 ids[ctx.hex()] = ctx.rev()
3109 n = ctx.extra().get(b'source')
3106 n = ctx.extra().get(b'source')
3110 if n:
3107 if n:
3111 ids[n] = ctx.rev()
3108 ids[n] = ctx.rev()
3112
3109
3113 # check ancestors for earlier grafts
3110 # check ancestors for earlier grafts
3114 ui.debug(b'scanning for duplicate grafts\n')
3111 ui.debug(b'scanning for duplicate grafts\n')
3115
3112
3116 # The only changesets we can be sure doesn't contain grafts of any
3113 # 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:
3114 # 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):
3115 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3119 ctx = repo[rev]
3116 ctx = repo[rev]
3120 n = ctx.extra().get(b'source')
3117 n = ctx.extra().get(b'source')
3121 if n in ids:
3118 if n in ids:
3122 try:
3119 try:
3123 r = repo[n].rev()
3120 r = repo[n].rev()
3124 except error.RepoLookupError:
3121 except error.RepoLookupError:
3125 r = None
3122 r = None
3126 if r in revs:
3123 if r in revs:
3127 ui.warn(
3124 ui.warn(
3128 _(
3125 _(
3129 b'skipping revision %d:%s '
3126 b'skipping revision %d:%s '
3130 b'(already grafted to %d:%s)\n'
3127 b'(already grafted to %d:%s)\n'
3131 )
3128 )
3132 % (r, repo[r], rev, ctx)
3129 % (r, repo[r], rev, ctx)
3133 )
3130 )
3134 revs.remove(r)
3131 revs.remove(r)
3135 elif ids[n] in revs:
3132 elif ids[n] in revs:
3136 if r is None:
3133 if r is None:
3137 ui.warn(
3134 ui.warn(
3138 _(
3135 _(
3139 b'skipping already grafted revision %d:%s '
3136 b'skipping already grafted revision %d:%s '
3140 b'(%d:%s also has unknown origin %s)\n'
3137 b'(%d:%s also has unknown origin %s)\n'
3141 )
3138 )
3142 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3139 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3143 )
3140 )
3144 else:
3141 else:
3145 ui.warn(
3142 ui.warn(
3146 _(
3143 _(
3147 b'skipping already grafted revision %d:%s '
3144 b'skipping already grafted revision %d:%s '
3148 b'(%d:%s also has origin %d:%s)\n'
3145 b'(%d:%s also has origin %d:%s)\n'
3149 )
3146 )
3150 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3147 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3151 )
3148 )
3152 revs.remove(ids[n])
3149 revs.remove(ids[n])
3153 elif ctx.hex() in ids:
3150 elif ctx.hex() in ids:
3154 r = ids[ctx.hex()]
3151 r = ids[ctx.hex()]
3155 if r in revs:
3152 if r in revs:
3156 ui.warn(
3153 ui.warn(
3157 _(
3154 _(
3158 b'skipping already grafted revision %d:%s '
3155 b'skipping already grafted revision %d:%s '
3159 b'(was grafted from %d:%s)\n'
3156 b'(was grafted from %d:%s)\n'
3160 )
3157 )
3161 % (r, repo[r], rev, ctx)
3158 % (r, repo[r], rev, ctx)
3162 )
3159 )
3163 revs.remove(r)
3160 revs.remove(r)
3164 if not revs:
3161 if not revs:
3165 return -1
3162 return -1
3166
3163
3167 if opts.get(b'no_commit'):
3164 if opts.get(b'no_commit'):
3168 statedata[b'no_commit'] = True
3165 statedata[b'no_commit'] = True
3169 if opts.get(b'base'):
3166 if opts.get(b'base'):
3170 statedata[b'base'] = opts[b'base']
3167 statedata[b'base'] = opts[b'base']
3171 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3168 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3172 desc = b'%d:%s "%s"' % (
3169 desc = b'%d:%s "%s"' % (
3173 ctx.rev(),
3170 ctx.rev(),
3174 ctx,
3171 ctx,
3175 ctx.description().split(b'\n', 1)[0],
3172 ctx.description().split(b'\n', 1)[0],
3176 )
3173 )
3177 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3174 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3178 if names:
3175 if names:
3179 desc += b' (%s)' % b' '.join(names)
3176 desc += b' (%s)' % b' '.join(names)
3180 ui.status(_(b'grafting %s\n') % desc)
3177 ui.status(_(b'grafting %s\n') % desc)
3181 if opts.get(b'dry_run'):
3178 if opts.get(b'dry_run'):
3182 continue
3179 continue
3183
3180
3184 source = ctx.extra().get(b'source')
3181 source = ctx.extra().get(b'source')
3185 extra = {}
3182 extra = {}
3186 if source:
3183 if source:
3187 extra[b'source'] = source
3184 extra[b'source'] = source
3188 extra[b'intermediate-source'] = ctx.hex()
3185 extra[b'intermediate-source'] = ctx.hex()
3189 else:
3186 else:
3190 extra[b'source'] = ctx.hex()
3187 extra[b'source'] = ctx.hex()
3191 user = ctx.user()
3188 user = ctx.user()
3192 if opts.get(b'user'):
3189 if opts.get(b'user'):
3193 user = opts[b'user']
3190 user = opts[b'user']
3194 statedata[b'user'] = user
3191 statedata[b'user'] = user
3195 date = ctx.date()
3192 date = ctx.date()
3196 if opts.get(b'date'):
3193 if opts.get(b'date'):
3197 date = opts[b'date']
3194 date = opts[b'date']
3198 statedata[b'date'] = date
3195 statedata[b'date'] = date
3199 message = ctx.description()
3196 message = ctx.description()
3200 if opts.get(b'log'):
3197 if opts.get(b'log'):
3201 message += b'\n(grafted from %s)' % ctx.hex()
3198 message += b'\n(grafted from %s)' % ctx.hex()
3202 statedata[b'log'] = True
3199 statedata[b'log'] = True
3203
3200
3204 # we don't merge the first commit when continuing
3201 # we don't merge the first commit when continuing
3205 if not cont:
3202 if not cont:
3206 # perform the graft merge with p1(rev) as 'ancestor'
3203 # perform the graft merge with p1(rev) as 'ancestor'
3207 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3204 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3208 base = ctx.p1() if basectx is None else basectx
3205 base = ctx.p1() if basectx is None else basectx
3209 with ui.configoverride(overrides, b'graft'):
3206 with ui.configoverride(overrides, b'graft'):
3210 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3207 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3211 # report any conflicts
3208 # report any conflicts
3212 if stats.unresolvedcount > 0:
3209 if stats.unresolvedcount > 0:
3213 # write out state for --continue
3210 # write out state for --continue
3214 nodes = [repo[rev].hex() for rev in revs[pos:]]
3211 nodes = [repo[rev].hex() for rev in revs[pos:]]
3215 statedata[b'nodes'] = nodes
3212 statedata[b'nodes'] = nodes
3216 stateversion = 1
3213 stateversion = 1
3217 graftstate.save(stateversion, statedata)
3214 graftstate.save(stateversion, statedata)
3218 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3215 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3219 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3216 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3220 return 1
3217 return 1
3221 else:
3218 else:
3222 cont = False
3219 cont = False
3223
3220
3224 # commit if --no-commit is false
3221 # commit if --no-commit is false
3225 if not opts.get(b'no_commit'):
3222 if not opts.get(b'no_commit'):
3226 node = repo.commit(
3223 node = repo.commit(
3227 text=message, user=user, date=date, extra=extra, editor=editor
3224 text=message, user=user, date=date, extra=extra, editor=editor
3228 )
3225 )
3229 if node is None:
3226 if node is None:
3230 ui.warn(
3227 ui.warn(
3231 _(b'note: graft of %d:%s created no changes to commit\n')
3228 _(b'note: graft of %d:%s created no changes to commit\n')
3232 % (ctx.rev(), ctx)
3229 % (ctx.rev(), ctx)
3233 )
3230 )
3234 # checking that newnodes exist because old state files won't have it
3231 # checking that newnodes exist because old state files won't have it
3235 elif statedata.get(b'newnodes') is not None:
3232 elif statedata.get(b'newnodes') is not None:
3236 statedata[b'newnodes'].append(node)
3233 statedata[b'newnodes'].append(node)
3237
3234
3238 # remove state when we complete successfully
3235 # remove state when we complete successfully
3239 if not opts.get(b'dry_run'):
3236 if not opts.get(b'dry_run'):
3240 graftstate.delete()
3237 graftstate.delete()
3241
3238
3242 return 0
3239 return 0
3243
3240
3244
3241
3245 def _stopgraft(ui, repo, graftstate):
3242 def _stopgraft(ui, repo, graftstate):
3246 """stop the interrupted graft"""
3243 """stop the interrupted graft"""
3247 if not graftstate.exists():
3244 if not graftstate.exists():
3248 raise error.Abort(_(b"no interrupted graft found"))
3245 raise error.Abort(_(b"no interrupted graft found"))
3249 pctx = repo[b'.']
3246 pctx = repo[b'.']
3250 mergemod.clean_update(pctx)
3247 mergemod.clean_update(pctx)
3251 graftstate.delete()
3248 graftstate.delete()
3252 ui.status(_(b"stopped the interrupted graft\n"))
3249 ui.status(_(b"stopped the interrupted graft\n"))
3253 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3250 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3254 return 0
3251 return 0
3255
3252
3256
3253
3257 statemod.addunfinished(
3254 statemod.addunfinished(
3258 b'graft',
3255 b'graft',
3259 fname=b'graftstate',
3256 fname=b'graftstate',
3260 clearable=True,
3257 clearable=True,
3261 stopflag=True,
3258 stopflag=True,
3262 continueflag=True,
3259 continueflag=True,
3263 abortfunc=cmdutil.hgabortgraft,
3260 abortfunc=cmdutil.hgabortgraft,
3264 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3261 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3265 )
3262 )
3266
3263
3267
3264
3268 @command(
3265 @command(
3269 b'grep',
3266 b'grep',
3270 [
3267 [
3271 (b'0', b'print0', None, _(b'end fields with NUL')),
3268 (b'0', b'print0', None, _(b'end fields with NUL')),
3272 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3269 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3273 (
3270 (
3274 b'',
3271 b'',
3275 b'diff',
3272 b'diff',
3276 None,
3273 None,
3277 _(
3274 _(
3278 b'search revision differences for when the pattern was added '
3275 b'search revision differences for when the pattern was added '
3279 b'or removed'
3276 b'or removed'
3280 ),
3277 ),
3281 ),
3278 ),
3282 (b'a', b'text', None, _(b'treat all files as text')),
3279 (b'a', b'text', None, _(b'treat all files as text')),
3283 (
3280 (
3284 b'f',
3281 b'f',
3285 b'follow',
3282 b'follow',
3286 None,
3283 None,
3287 _(
3284 _(
3288 b'follow changeset history,'
3285 b'follow changeset history,'
3289 b' or file history across copies and renames'
3286 b' or file history across copies and renames'
3290 ),
3287 ),
3291 ),
3288 ),
3292 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3289 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3293 (
3290 (
3294 b'l',
3291 b'l',
3295 b'files-with-matches',
3292 b'files-with-matches',
3296 None,
3293 None,
3297 _(b'print only filenames and revisions that match'),
3294 _(b'print only filenames and revisions that match'),
3298 ),
3295 ),
3299 (b'n', b'line-number', None, _(b'print matching line numbers')),
3296 (b'n', b'line-number', None, _(b'print matching line numbers')),
3300 (
3297 (
3301 b'r',
3298 b'r',
3302 b'rev',
3299 b'rev',
3303 [],
3300 [],
3304 _(b'search files changed within revision range'),
3301 _(b'search files changed within revision range'),
3305 _(b'REV'),
3302 _(b'REV'),
3306 ),
3303 ),
3307 (
3304 (
3308 b'',
3305 b'',
3309 b'all-files',
3306 b'all-files',
3310 None,
3307 None,
3311 _(
3308 _(
3312 b'include all files in the changeset while grepping (DEPRECATED)'
3309 b'include all files in the changeset while grepping (DEPRECATED)'
3313 ),
3310 ),
3314 ),
3311 ),
3315 (b'u', b'user', None, _(b'list the author (long with -v)')),
3312 (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)')),
3313 (b'd', b'date', None, _(b'list the date (short with -q)')),
3317 ]
3314 ]
3318 + formatteropts
3315 + formatteropts
3319 + walkopts,
3316 + walkopts,
3320 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3317 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3321 helpcategory=command.CATEGORY_FILE_CONTENTS,
3318 helpcategory=command.CATEGORY_FILE_CONTENTS,
3322 inferrepo=True,
3319 inferrepo=True,
3323 intents={INTENT_READONLY},
3320 intents={INTENT_READONLY},
3324 )
3321 )
3325 def grep(ui, repo, pattern, *pats, **opts):
3322 def grep(ui, repo, pattern, *pats, **opts):
3326 """search for a pattern in specified files
3323 """search for a pattern in specified files
3327
3324
3328 Search the working directory or revision history for a regular
3325 Search the working directory or revision history for a regular
3329 expression in the specified files for the entire repository.
3326 expression in the specified files for the entire repository.
3330
3327
3331 By default, grep searches the repository files in the working
3328 By default, grep searches the repository files in the working
3332 directory and prints the files where it finds a match. To specify
3329 directory and prints the files where it finds a match. To specify
3333 historical revisions instead of the working directory, use the
3330 historical revisions instead of the working directory, use the
3334 --rev flag.
3331 --rev flag.
3335
3332
3336 To search instead historical revision differences that contains a
3333 To search instead historical revision differences that contains a
3337 change in match status ("-" for a match that becomes a non-match,
3334 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.
3335 or "+" for a non-match that becomes a match), use the --diff flag.
3339
3336
3340 PATTERN can be any Python (roughly Perl-compatible) regular
3337 PATTERN can be any Python (roughly Perl-compatible) regular
3341 expression.
3338 expression.
3342
3339
3343 If no FILEs are specified and the --rev flag isn't supplied, all
3340 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
3341 files in the working directory are searched. When using the --rev
3345 flag and specifying FILEs, use the --follow argument to also
3342 flag and specifying FILEs, use the --follow argument to also
3346 follow the specified FILEs across renames and copies.
3343 follow the specified FILEs across renames and copies.
3347
3344
3348 .. container:: verbose
3345 .. container:: verbose
3349
3346
3350 Template:
3347 Template:
3351
3348
3352 The following keywords are supported in addition to the common template
3349 The following keywords are supported in addition to the common template
3353 keywords and functions. See also :hg:`help templates`.
3350 keywords and functions. See also :hg:`help templates`.
3354
3351
3355 :change: String. Character denoting insertion ``+`` or removal ``-``.
3352 :change: String. Character denoting insertion ``+`` or removal ``-``.
3356 Available if ``--diff`` is specified.
3353 Available if ``--diff`` is specified.
3357 :lineno: Integer. Line number of the match.
3354 :lineno: Integer. Line number of the match.
3358 :path: String. Repository-absolute path of the file.
3355 :path: String. Repository-absolute path of the file.
3359 :texts: List of text chunks.
3356 :texts: List of text chunks.
3360
3357
3361 And each entry of ``{texts}`` provides the following sub-keywords.
3358 And each entry of ``{texts}`` provides the following sub-keywords.
3362
3359
3363 :matched: Boolean. True if the chunk matches the specified pattern.
3360 :matched: Boolean. True if the chunk matches the specified pattern.
3364 :text: String. Chunk content.
3361 :text: String. Chunk content.
3365
3362
3366 See :hg:`help templates.operators` for the list expansion syntax.
3363 See :hg:`help templates.operators` for the list expansion syntax.
3367
3364
3368 Returns 0 if a match is found, 1 otherwise.
3365 Returns 0 if a match is found, 1 otherwise.
3369
3366
3370 """
3367 """
3371 opts = pycompat.byteskwargs(opts)
3368 opts = pycompat.byteskwargs(opts)
3372 diff = opts.get(b'all') or opts.get(b'diff')
3369 diff = opts.get(b'all') or opts.get(b'diff')
3373 follow = opts.get(b'follow')
3370 follow = opts.get(b'follow')
3374 if diff and opts.get(b'all_files'):
3371 if diff and opts.get(b'all_files'):
3375 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3372 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3376 if opts.get(b'all_files') is None and not diff:
3373 if opts.get(b'all_files') is None and not diff:
3377 opts[b'all_files'] = True
3374 opts[b'all_files'] = True
3378 plaingrep = (
3375 plaingrep = (
3379 opts.get(b'all_files')
3376 opts.get(b'all_files')
3380 and not opts.get(b'rev')
3377 and not opts.get(b'rev')
3381 and not opts.get(b'follow')
3378 and not opts.get(b'follow')
3382 )
3379 )
3383 all_files = opts.get(b'all_files')
3380 all_files = opts.get(b'all_files')
3384 if plaingrep:
3381 if plaingrep:
3385 opts[b'rev'] = [b'wdir()']
3382 opts[b'rev'] = [b'wdir()']
3386
3383
3387 reflags = re.M
3384 reflags = re.M
3388 if opts.get(b'ignore_case'):
3385 if opts.get(b'ignore_case'):
3389 reflags |= re.I
3386 reflags |= re.I
3390 try:
3387 try:
3391 regexp = util.re.compile(pattern, reflags)
3388 regexp = util.re.compile(pattern, reflags)
3392 except re.error as inst:
3389 except re.error as inst:
3393 ui.warn(
3390 ui.warn(
3394 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3391 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3395 )
3392 )
3396 return 1
3393 return 1
3397 sep, eol = b':', b'\n'
3394 sep, eol = b':', b'\n'
3398 if opts.get(b'print0'):
3395 if opts.get(b'print0'):
3399 sep = eol = b'\0'
3396 sep = eol = b'\0'
3400
3397
3401 searcher = grepmod.grepsearcher(
3398 searcher = grepmod.grepsearcher(
3402 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3399 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3403 )
3400 )
3404
3401
3405 getfile = searcher._getfile
3402 getfile = searcher._getfile
3406
3403
3407 uipathfn = scmutil.getuipathfn(repo)
3404 uipathfn = scmutil.getuipathfn(repo)
3408
3405
3409 def display(fm, fn, ctx, pstates, states):
3406 def display(fm, fn, ctx, pstates, states):
3410 rev = scmutil.intrev(ctx)
3407 rev = scmutil.intrev(ctx)
3411 if fm.isplain():
3408 if fm.isplain():
3412 formatuser = ui.shortuser
3409 formatuser = ui.shortuser
3413 else:
3410 else:
3414 formatuser = pycompat.bytestr
3411 formatuser = pycompat.bytestr
3415 if ui.quiet:
3412 if ui.quiet:
3416 datefmt = b'%Y-%m-%d'
3413 datefmt = b'%Y-%m-%d'
3417 else:
3414 else:
3418 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3415 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3419 found = False
3416 found = False
3420
3417
3421 @util.cachefunc
3418 @util.cachefunc
3422 def binary():
3419 def binary():
3423 flog = getfile(fn)
3420 flog = getfile(fn)
3424 try:
3421 try:
3425 return stringutil.binary(flog.read(ctx.filenode(fn)))
3422 return stringutil.binary(flog.read(ctx.filenode(fn)))
3426 except error.WdirUnsupported:
3423 except error.WdirUnsupported:
3427 return ctx[fn].isbinary()
3424 return ctx[fn].isbinary()
3428
3425
3429 fieldnamemap = {b'linenumber': b'lineno'}
3426 fieldnamemap = {b'linenumber': b'lineno'}
3430 if diff:
3427 if diff:
3431 iter = grepmod.difflinestates(pstates, states)
3428 iter = grepmod.difflinestates(pstates, states)
3432 else:
3429 else:
3433 iter = [(b'', l) for l in states]
3430 iter = [(b'', l) for l in states]
3434 for change, l in iter:
3431 for change, l in iter:
3435 fm.startitem()
3432 fm.startitem()
3436 fm.context(ctx=ctx)
3433 fm.context(ctx=ctx)
3437 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3434 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3438 fm.plain(uipathfn(fn), label=b'grep.filename')
3435 fm.plain(uipathfn(fn), label=b'grep.filename')
3439
3436
3440 cols = [
3437 cols = [
3441 (b'rev', b'%d', rev, not plaingrep, b''),
3438 (b'rev', b'%d', rev, not plaingrep, b''),
3442 (
3439 (
3443 b'linenumber',
3440 b'linenumber',
3444 b'%d',
3441 b'%d',
3445 l.linenum,
3442 l.linenum,
3446 opts.get(b'line_number'),
3443 opts.get(b'line_number'),
3447 b'',
3444 b'',
3448 ),
3445 ),
3449 ]
3446 ]
3450 if diff:
3447 if diff:
3451 cols.append(
3448 cols.append(
3452 (
3449 (
3453 b'change',
3450 b'change',
3454 b'%s',
3451 b'%s',
3455 change,
3452 change,
3456 True,
3453 True,
3457 b'grep.inserted '
3454 b'grep.inserted '
3458 if change == b'+'
3455 if change == b'+'
3459 else b'grep.deleted ',
3456 else b'grep.deleted ',
3460 )
3457 )
3461 )
3458 )
3462 cols.extend(
3459 cols.extend(
3463 [
3460 [
3464 (
3461 (
3465 b'user',
3462 b'user',
3466 b'%s',
3463 b'%s',
3467 formatuser(ctx.user()),
3464 formatuser(ctx.user()),
3468 opts.get(b'user'),
3465 opts.get(b'user'),
3469 b'',
3466 b'',
3470 ),
3467 ),
3471 (
3468 (
3472 b'date',
3469 b'date',
3473 b'%s',
3470 b'%s',
3474 fm.formatdate(ctx.date(), datefmt),
3471 fm.formatdate(ctx.date(), datefmt),
3475 opts.get(b'date'),
3472 opts.get(b'date'),
3476 b'',
3473 b'',
3477 ),
3474 ),
3478 ]
3475 ]
3479 )
3476 )
3480 for name, fmt, data, cond, extra_label in cols:
3477 for name, fmt, data, cond, extra_label in cols:
3481 if cond:
3478 if cond:
3482 fm.plain(sep, label=b'grep.sep')
3479 fm.plain(sep, label=b'grep.sep')
3483 field = fieldnamemap.get(name, name)
3480 field = fieldnamemap.get(name, name)
3484 label = extra_label + (b'grep.%s' % name)
3481 label = extra_label + (b'grep.%s' % name)
3485 fm.condwrite(cond, field, fmt, data, label=label)
3482 fm.condwrite(cond, field, fmt, data, label=label)
3486 if not opts.get(b'files_with_matches'):
3483 if not opts.get(b'files_with_matches'):
3487 fm.plain(sep, label=b'grep.sep')
3484 fm.plain(sep, label=b'grep.sep')
3488 if not opts.get(b'text') and binary():
3485 if not opts.get(b'text') and binary():
3489 fm.plain(_(b" Binary file matches"))
3486 fm.plain(_(b" Binary file matches"))
3490 else:
3487 else:
3491 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3488 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3492 fm.plain(eol)
3489 fm.plain(eol)
3493 found = True
3490 found = True
3494 if opts.get(b'files_with_matches'):
3491 if opts.get(b'files_with_matches'):
3495 break
3492 break
3496 return found
3493 return found
3497
3494
3498 def displaymatches(fm, l):
3495 def displaymatches(fm, l):
3499 p = 0
3496 p = 0
3500 for s, e in l.findpos(regexp):
3497 for s, e in l.findpos(regexp):
3501 if p < s:
3498 if p < s:
3502 fm.startitem()
3499 fm.startitem()
3503 fm.write(b'text', b'%s', l.line[p:s])
3500 fm.write(b'text', b'%s', l.line[p:s])
3504 fm.data(matched=False)
3501 fm.data(matched=False)
3505 fm.startitem()
3502 fm.startitem()
3506 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3503 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3507 fm.data(matched=True)
3504 fm.data(matched=True)
3508 p = e
3505 p = e
3509 if p < len(l.line):
3506 if p < len(l.line):
3510 fm.startitem()
3507 fm.startitem()
3511 fm.write(b'text', b'%s', l.line[p:])
3508 fm.write(b'text', b'%s', l.line[p:])
3512 fm.data(matched=False)
3509 fm.data(matched=False)
3513 fm.end()
3510 fm.end()
3514
3511
3515 found = False
3512 found = False
3516
3513
3517 wopts = logcmdutil.walkopts(
3514 wopts = logcmdutil.walkopts(
3518 pats=pats,
3515 pats=pats,
3519 opts=opts,
3516 opts=opts,
3520 revspec=opts[b'rev'],
3517 revspec=opts[b'rev'],
3521 include_pats=opts[b'include'],
3518 include_pats=opts[b'include'],
3522 exclude_pats=opts[b'exclude'],
3519 exclude_pats=opts[b'exclude'],
3523 follow=follow,
3520 follow=follow,
3524 force_changelog_traversal=all_files,
3521 force_changelog_traversal=all_files,
3525 filter_revisions_by_pats=not all_files,
3522 filter_revisions_by_pats=not all_files,
3526 )
3523 )
3527 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3524 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3528
3525
3529 ui.pager(b'grep')
3526 ui.pager(b'grep')
3530 fm = ui.formatter(b'grep', opts)
3527 fm = ui.formatter(b'grep', opts)
3531 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3528 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3532 r = display(fm, fn, ctx, pstates, states)
3529 r = display(fm, fn, ctx, pstates, states)
3533 found = found or r
3530 found = found or r
3534 if r and not diff and not all_files:
3531 if r and not diff and not all_files:
3535 searcher.skipfile(fn, ctx.rev())
3532 searcher.skipfile(fn, ctx.rev())
3536 fm.end()
3533 fm.end()
3537
3534
3538 return not found
3535 return not found
3539
3536
3540
3537
3541 @command(
3538 @command(
3542 b'heads',
3539 b'heads',
3543 [
3540 [
3544 (
3541 (
3545 b'r',
3542 b'r',
3546 b'rev',
3543 b'rev',
3547 b'',
3544 b'',
3548 _(b'show only heads which are descendants of STARTREV'),
3545 _(b'show only heads which are descendants of STARTREV'),
3549 _(b'STARTREV'),
3546 _(b'STARTREV'),
3550 ),
3547 ),
3551 (b't', b'topo', False, _(b'show topological heads only')),
3548 (b't', b'topo', False, _(b'show topological heads only')),
3552 (
3549 (
3553 b'a',
3550 b'a',
3554 b'active',
3551 b'active',
3555 False,
3552 False,
3556 _(b'show active branchheads only (DEPRECATED)'),
3553 _(b'show active branchheads only (DEPRECATED)'),
3557 ),
3554 ),
3558 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3555 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3559 ]
3556 ]
3560 + templateopts,
3557 + templateopts,
3561 _(b'[-ct] [-r STARTREV] [REV]...'),
3558 _(b'[-ct] [-r STARTREV] [REV]...'),
3562 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3559 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3563 intents={INTENT_READONLY},
3560 intents={INTENT_READONLY},
3564 )
3561 )
3565 def heads(ui, repo, *branchrevs, **opts):
3562 def heads(ui, repo, *branchrevs, **opts):
3566 """show branch heads
3563 """show branch heads
3567
3564
3568 With no arguments, show all open branch heads in the repository.
3565 With no arguments, show all open branch heads in the repository.
3569 Branch heads are changesets that have no descendants on the
3566 Branch heads are changesets that have no descendants on the
3570 same branch. They are where development generally takes place and
3567 same branch. They are where development generally takes place and
3571 are the usual targets for update and merge operations.
3568 are the usual targets for update and merge operations.
3572
3569
3573 If one or more REVs are given, only open branch heads on the
3570 If one or more REVs are given, only open branch heads on the
3574 branches associated with the specified changesets are shown. This
3571 branches associated with the specified changesets are shown. This
3575 means that you can use :hg:`heads .` to see the heads on the
3572 means that you can use :hg:`heads .` to see the heads on the
3576 currently checked-out branch.
3573 currently checked-out branch.
3577
3574
3578 If -c/--closed is specified, also show branch heads marked closed
3575 If -c/--closed is specified, also show branch heads marked closed
3579 (see :hg:`commit --close-branch`).
3576 (see :hg:`commit --close-branch`).
3580
3577
3581 If STARTREV is specified, only those heads that are descendants of
3578 If STARTREV is specified, only those heads that are descendants of
3582 STARTREV will be displayed.
3579 STARTREV will be displayed.
3583
3580
3584 If -t/--topo is specified, named branch mechanics will be ignored and only
3581 If -t/--topo is specified, named branch mechanics will be ignored and only
3585 topological heads (changesets with no children) will be shown.
3582 topological heads (changesets with no children) will be shown.
3586
3583
3587 Returns 0 if matching heads are found, 1 if not.
3584 Returns 0 if matching heads are found, 1 if not.
3588 """
3585 """
3589
3586
3590 opts = pycompat.byteskwargs(opts)
3587 opts = pycompat.byteskwargs(opts)
3591 start = None
3588 start = None
3592 rev = opts.get(b'rev')
3589 rev = opts.get(b'rev')
3593 if rev:
3590 if rev:
3594 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3591 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3595 start = scmutil.revsingle(repo, rev, None).node()
3592 start = scmutil.revsingle(repo, rev, None).node()
3596
3593
3597 if opts.get(b'topo'):
3594 if opts.get(b'topo'):
3598 heads = [repo[h] for h in repo.heads(start)]
3595 heads = [repo[h] for h in repo.heads(start)]
3599 else:
3596 else:
3600 heads = []
3597 heads = []
3601 for branch in repo.branchmap():
3598 for branch in repo.branchmap():
3602 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3599 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3603 heads = [repo[h] for h in heads]
3600 heads = [repo[h] for h in heads]
3604
3601
3605 if branchrevs:
3602 if branchrevs:
3606 branches = {
3603 branches = {
3607 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3604 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3608 }
3605 }
3609 heads = [h for h in heads if h.branch() in branches]
3606 heads = [h for h in heads if h.branch() in branches]
3610
3607
3611 if opts.get(b'active') and branchrevs:
3608 if opts.get(b'active') and branchrevs:
3612 dagheads = repo.heads(start)
3609 dagheads = repo.heads(start)
3613 heads = [h for h in heads if h.node() in dagheads]
3610 heads = [h for h in heads if h.node() in dagheads]
3614
3611
3615 if branchrevs:
3612 if branchrevs:
3616 haveheads = {h.branch() for h in heads}
3613 haveheads = {h.branch() for h in heads}
3617 if branches - haveheads:
3614 if branches - haveheads:
3618 headless = b', '.join(b for b in branches - haveheads)
3615 headless = b', '.join(b for b in branches - haveheads)
3619 msg = _(b'no open branch heads found on branches %s')
3616 msg = _(b'no open branch heads found on branches %s')
3620 if opts.get(b'rev'):
3617 if opts.get(b'rev'):
3621 msg += _(b' (started at %s)') % opts[b'rev']
3618 msg += _(b' (started at %s)') % opts[b'rev']
3622 ui.warn((msg + b'\n') % headless)
3619 ui.warn((msg + b'\n') % headless)
3623
3620
3624 if not heads:
3621 if not heads:
3625 return 1
3622 return 1
3626
3623
3627 ui.pager(b'heads')
3624 ui.pager(b'heads')
3628 heads = sorted(heads, key=lambda x: -(x.rev()))
3625 heads = sorted(heads, key=lambda x: -(x.rev()))
3629 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3626 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3630 for ctx in heads:
3627 for ctx in heads:
3631 displayer.show(ctx)
3628 displayer.show(ctx)
3632 displayer.close()
3629 displayer.close()
3633
3630
3634
3631
3635 @command(
3632 @command(
3636 b'help',
3633 b'help',
3637 [
3634 [
3638 (b'e', b'extension', None, _(b'show only help for extensions')),
3635 (b'e', b'extension', None, _(b'show only help for extensions')),
3639 (b'c', b'command', None, _(b'show only help for commands')),
3636 (b'c', b'command', None, _(b'show only help for commands')),
3640 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3637 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3641 (
3638 (
3642 b's',
3639 b's',
3643 b'system',
3640 b'system',
3644 [],
3641 [],
3645 _(b'show help for specific platform(s)'),
3642 _(b'show help for specific platform(s)'),
3646 _(b'PLATFORM'),
3643 _(b'PLATFORM'),
3647 ),
3644 ),
3648 ],
3645 ],
3649 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3646 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3650 helpcategory=command.CATEGORY_HELP,
3647 helpcategory=command.CATEGORY_HELP,
3651 norepo=True,
3648 norepo=True,
3652 intents={INTENT_READONLY},
3649 intents={INTENT_READONLY},
3653 )
3650 )
3654 def help_(ui, name=None, **opts):
3651 def help_(ui, name=None, **opts):
3655 """show help for a given topic or a help overview
3652 """show help for a given topic or a help overview
3656
3653
3657 With no arguments, print a list of commands with short help messages.
3654 With no arguments, print a list of commands with short help messages.
3658
3655
3659 Given a topic, extension, or command name, print help for that
3656 Given a topic, extension, or command name, print help for that
3660 topic.
3657 topic.
3661
3658
3662 Returns 0 if successful.
3659 Returns 0 if successful.
3663 """
3660 """
3664
3661
3665 keep = opts.get('system') or []
3662 keep = opts.get('system') or []
3666 if len(keep) == 0:
3663 if len(keep) == 0:
3667 if pycompat.sysplatform.startswith(b'win'):
3664 if pycompat.sysplatform.startswith(b'win'):
3668 keep.append(b'windows')
3665 keep.append(b'windows')
3669 elif pycompat.sysplatform == b'OpenVMS':
3666 elif pycompat.sysplatform == b'OpenVMS':
3670 keep.append(b'vms')
3667 keep.append(b'vms')
3671 elif pycompat.sysplatform == b'plan9':
3668 elif pycompat.sysplatform == b'plan9':
3672 keep.append(b'plan9')
3669 keep.append(b'plan9')
3673 else:
3670 else:
3674 keep.append(b'unix')
3671 keep.append(b'unix')
3675 keep.append(pycompat.sysplatform.lower())
3672 keep.append(pycompat.sysplatform.lower())
3676 if ui.verbose:
3673 if ui.verbose:
3677 keep.append(b'verbose')
3674 keep.append(b'verbose')
3678
3675
3679 commands = sys.modules[__name__]
3676 commands = sys.modules[__name__]
3680 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3677 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3681 ui.pager(b'help')
3678 ui.pager(b'help')
3682 ui.write(formatted)
3679 ui.write(formatted)
3683
3680
3684
3681
3685 @command(
3682 @command(
3686 b'identify|id',
3683 b'identify|id',
3687 [
3684 [
3688 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3685 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3689 (b'n', b'num', None, _(b'show local revision number')),
3686 (b'n', b'num', None, _(b'show local revision number')),
3690 (b'i', b'id', None, _(b'show global revision id')),
3687 (b'i', b'id', None, _(b'show global revision id')),
3691 (b'b', b'branch', None, _(b'show branch')),
3688 (b'b', b'branch', None, _(b'show branch')),
3692 (b't', b'tags', None, _(b'show tags')),
3689 (b't', b'tags', None, _(b'show tags')),
3693 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3690 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3694 ]
3691 ]
3695 + remoteopts
3692 + remoteopts
3696 + formatteropts,
3693 + formatteropts,
3697 _(b'[-nibtB] [-r REV] [SOURCE]'),
3694 _(b'[-nibtB] [-r REV] [SOURCE]'),
3698 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3695 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3699 optionalrepo=True,
3696 optionalrepo=True,
3700 intents={INTENT_READONLY},
3697 intents={INTENT_READONLY},
3701 )
3698 )
3702 def identify(
3699 def identify(
3703 ui,
3700 ui,
3704 repo,
3701 repo,
3705 source=None,
3702 source=None,
3706 rev=None,
3703 rev=None,
3707 num=None,
3704 num=None,
3708 id=None,
3705 id=None,
3709 branch=None,
3706 branch=None,
3710 tags=None,
3707 tags=None,
3711 bookmarks=None,
3708 bookmarks=None,
3712 **opts
3709 **opts
3713 ):
3710 ):
3714 """identify the working directory or specified revision
3711 """identify the working directory or specified revision
3715
3712
3716 Print a summary identifying the repository state at REV using one or
3713 Print a summary identifying the repository state at REV using one or
3717 two parent hash identifiers, followed by a "+" if the working
3714 two parent hash identifiers, followed by a "+" if the working
3718 directory has uncommitted changes, the branch name (if not default),
3715 directory has uncommitted changes, the branch name (if not default),
3719 a list of tags, and a list of bookmarks.
3716 a list of tags, and a list of bookmarks.
3720
3717
3721 When REV is not given, print a summary of the current state of the
3718 When REV is not given, print a summary of the current state of the
3722 repository including the working directory. Specify -r. to get information
3719 repository including the working directory. Specify -r. to get information
3723 of the working directory parent without scanning uncommitted changes.
3720 of the working directory parent without scanning uncommitted changes.
3724
3721
3725 Specifying a path to a repository root or Mercurial bundle will
3722 Specifying a path to a repository root or Mercurial bundle will
3726 cause lookup to operate on that repository/bundle.
3723 cause lookup to operate on that repository/bundle.
3727
3724
3728 .. container:: verbose
3725 .. container:: verbose
3729
3726
3730 Template:
3727 Template:
3731
3728
3732 The following keywords are supported in addition to the common template
3729 The following keywords are supported in addition to the common template
3733 keywords and functions. See also :hg:`help templates`.
3730 keywords and functions. See also :hg:`help templates`.
3734
3731
3735 :dirty: String. Character ``+`` denoting if the working directory has
3732 :dirty: String. Character ``+`` denoting if the working directory has
3736 uncommitted changes.
3733 uncommitted changes.
3737 :id: String. One or two nodes, optionally followed by ``+``.
3734 :id: String. One or two nodes, optionally followed by ``+``.
3738 :parents: List of strings. Parent nodes of the changeset.
3735 :parents: List of strings. Parent nodes of the changeset.
3739
3736
3740 Examples:
3737 Examples:
3741
3738
3742 - generate a build identifier for the working directory::
3739 - generate a build identifier for the working directory::
3743
3740
3744 hg id --id > build-id.dat
3741 hg id --id > build-id.dat
3745
3742
3746 - find the revision corresponding to a tag::
3743 - find the revision corresponding to a tag::
3747
3744
3748 hg id -n -r 1.3
3745 hg id -n -r 1.3
3749
3746
3750 - check the most recent revision of a remote repository::
3747 - check the most recent revision of a remote repository::
3751
3748
3752 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3749 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3753
3750
3754 See :hg:`log` for generating more information about specific revisions,
3751 See :hg:`log` for generating more information about specific revisions,
3755 including full hash identifiers.
3752 including full hash identifiers.
3756
3753
3757 Returns 0 if successful.
3754 Returns 0 if successful.
3758 """
3755 """
3759
3756
3760 opts = pycompat.byteskwargs(opts)
3757 opts = pycompat.byteskwargs(opts)
3761 if not repo and not source:
3758 if not repo and not source:
3762 raise error.Abort(
3759 raise error.Abort(
3763 _(b"there is no Mercurial repository here (.hg not found)")
3760 _(b"there is no Mercurial repository here (.hg not found)")
3764 )
3761 )
3765
3762
3766 default = not (num or id or branch or tags or bookmarks)
3763 default = not (num or id or branch or tags or bookmarks)
3767 output = []
3764 output = []
3768 revs = []
3765 revs = []
3769
3766
3770 if source:
3767 if source:
3771 source, branches = hg.parseurl(ui.expandpath(source))
3768 source, branches = hg.parseurl(ui.expandpath(source))
3772 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3769 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3773 repo = peer.local()
3770 repo = peer.local()
3774 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3771 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3775
3772
3776 fm = ui.formatter(b'identify', opts)
3773 fm = ui.formatter(b'identify', opts)
3777 fm.startitem()
3774 fm.startitem()
3778
3775
3779 if not repo:
3776 if not repo:
3780 if num or branch or tags:
3777 if num or branch or tags:
3781 raise error.Abort(
3778 raise error.Abort(
3782 _(b"can't query remote revision number, branch, or tags")
3779 _(b"can't query remote revision number, branch, or tags")
3783 )
3780 )
3784 if not rev and revs:
3781 if not rev and revs:
3785 rev = revs[0]
3782 rev = revs[0]
3786 if not rev:
3783 if not rev:
3787 rev = b"tip"
3784 rev = b"tip"
3788
3785
3789 remoterev = peer.lookup(rev)
3786 remoterev = peer.lookup(rev)
3790 hexrev = fm.hexfunc(remoterev)
3787 hexrev = fm.hexfunc(remoterev)
3791 if default or id:
3788 if default or id:
3792 output = [hexrev]
3789 output = [hexrev]
3793 fm.data(id=hexrev)
3790 fm.data(id=hexrev)
3794
3791
3795 @util.cachefunc
3792 @util.cachefunc
3796 def getbms():
3793 def getbms():
3797 bms = []
3794 bms = []
3798
3795
3799 if b'bookmarks' in peer.listkeys(b'namespaces'):
3796 if b'bookmarks' in peer.listkeys(b'namespaces'):
3800 hexremoterev = hex(remoterev)
3797 hexremoterev = hex(remoterev)
3801 bms = [
3798 bms = [
3802 bm
3799 bm
3803 for bm, bmr in pycompat.iteritems(
3800 for bm, bmr in pycompat.iteritems(
3804 peer.listkeys(b'bookmarks')
3801 peer.listkeys(b'bookmarks')
3805 )
3802 )
3806 if bmr == hexremoterev
3803 if bmr == hexremoterev
3807 ]
3804 ]
3808
3805
3809 return sorted(bms)
3806 return sorted(bms)
3810
3807
3811 if fm.isplain():
3808 if fm.isplain():
3812 if bookmarks:
3809 if bookmarks:
3813 output.extend(getbms())
3810 output.extend(getbms())
3814 elif default and not ui.quiet:
3811 elif default and not ui.quiet:
3815 # multiple bookmarks for a single parent separated by '/'
3812 # multiple bookmarks for a single parent separated by '/'
3816 bm = b'/'.join(getbms())
3813 bm = b'/'.join(getbms())
3817 if bm:
3814 if bm:
3818 output.append(bm)
3815 output.append(bm)
3819 else:
3816 else:
3820 fm.data(node=hex(remoterev))
3817 fm.data(node=hex(remoterev))
3821 if bookmarks or b'bookmarks' in fm.datahint():
3818 if bookmarks or b'bookmarks' in fm.datahint():
3822 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3819 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3823 else:
3820 else:
3824 if rev:
3821 if rev:
3825 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3822 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3826 ctx = scmutil.revsingle(repo, rev, None)
3823 ctx = scmutil.revsingle(repo, rev, None)
3827
3824
3828 if ctx.rev() is None:
3825 if ctx.rev() is None:
3829 ctx = repo[None]
3826 ctx = repo[None]
3830 parents = ctx.parents()
3827 parents = ctx.parents()
3831 taglist = []
3828 taglist = []
3832 for p in parents:
3829 for p in parents:
3833 taglist.extend(p.tags())
3830 taglist.extend(p.tags())
3834
3831
3835 dirty = b""
3832 dirty = b""
3836 if ctx.dirty(missing=True, merge=False, branch=False):
3833 if ctx.dirty(missing=True, merge=False, branch=False):
3837 dirty = b'+'
3834 dirty = b'+'
3838 fm.data(dirty=dirty)
3835 fm.data(dirty=dirty)
3839
3836
3840 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3837 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3841 if default or id:
3838 if default or id:
3842 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3839 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3843 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3840 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3844
3841
3845 if num:
3842 if num:
3846 numoutput = [b"%d" % p.rev() for p in parents]
3843 numoutput = [b"%d" % p.rev() for p in parents]
3847 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3844 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3848
3845
3849 fm.data(
3846 fm.data(
3850 parents=fm.formatlist(
3847 parents=fm.formatlist(
3851 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3848 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3852 )
3849 )
3853 )
3850 )
3854 else:
3851 else:
3855 hexoutput = fm.hexfunc(ctx.node())
3852 hexoutput = fm.hexfunc(ctx.node())
3856 if default or id:
3853 if default or id:
3857 output = [hexoutput]
3854 output = [hexoutput]
3858 fm.data(id=hexoutput)
3855 fm.data(id=hexoutput)
3859
3856
3860 if num:
3857 if num:
3861 output.append(pycompat.bytestr(ctx.rev()))
3858 output.append(pycompat.bytestr(ctx.rev()))
3862 taglist = ctx.tags()
3859 taglist = ctx.tags()
3863
3860
3864 if default and not ui.quiet:
3861 if default and not ui.quiet:
3865 b = ctx.branch()
3862 b = ctx.branch()
3866 if b != b'default':
3863 if b != b'default':
3867 output.append(b"(%s)" % b)
3864 output.append(b"(%s)" % b)
3868
3865
3869 # multiple tags for a single parent separated by '/'
3866 # multiple tags for a single parent separated by '/'
3870 t = b'/'.join(taglist)
3867 t = b'/'.join(taglist)
3871 if t:
3868 if t:
3872 output.append(t)
3869 output.append(t)
3873
3870
3874 # multiple bookmarks for a single parent separated by '/'
3871 # multiple bookmarks for a single parent separated by '/'
3875 bm = b'/'.join(ctx.bookmarks())
3872 bm = b'/'.join(ctx.bookmarks())
3876 if bm:
3873 if bm:
3877 output.append(bm)
3874 output.append(bm)
3878 else:
3875 else:
3879 if branch:
3876 if branch:
3880 output.append(ctx.branch())
3877 output.append(ctx.branch())
3881
3878
3882 if tags:
3879 if tags:
3883 output.extend(taglist)
3880 output.extend(taglist)
3884
3881
3885 if bookmarks:
3882 if bookmarks:
3886 output.extend(ctx.bookmarks())
3883 output.extend(ctx.bookmarks())
3887
3884
3888 fm.data(node=ctx.hex())
3885 fm.data(node=ctx.hex())
3889 fm.data(branch=ctx.branch())
3886 fm.data(branch=ctx.branch())
3890 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3887 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3891 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3888 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3892 fm.context(ctx=ctx)
3889 fm.context(ctx=ctx)
3893
3890
3894 fm.plain(b"%s\n" % b' '.join(output))
3891 fm.plain(b"%s\n" % b' '.join(output))
3895 fm.end()
3892 fm.end()
3896
3893
3897
3894
3898 @command(
3895 @command(
3899 b'import|patch',
3896 b'import|patch',
3900 [
3897 [
3901 (
3898 (
3902 b'p',
3899 b'p',
3903 b'strip',
3900 b'strip',
3904 1,
3901 1,
3905 _(
3902 _(
3906 b'directory strip option for patch. This has the same '
3903 b'directory strip option for patch. This has the same '
3907 b'meaning as the corresponding patch option'
3904 b'meaning as the corresponding patch option'
3908 ),
3905 ),
3909 _(b'NUM'),
3906 _(b'NUM'),
3910 ),
3907 ),
3911 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3908 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3912 (b'', b'secret', None, _(b'use the secret phase for committing')),
3909 (b'', b'secret', None, _(b'use the secret phase for committing')),
3913 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3910 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3914 (
3911 (
3915 b'f',
3912 b'f',
3916 b'force',
3913 b'force',
3917 None,
3914 None,
3918 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3915 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3919 ),
3916 ),
3920 (
3917 (
3921 b'',
3918 b'',
3922 b'no-commit',
3919 b'no-commit',
3923 None,
3920 None,
3924 _(b"don't commit, just update the working directory"),
3921 _(b"don't commit, just update the working directory"),
3925 ),
3922 ),
3926 (
3923 (
3927 b'',
3924 b'',
3928 b'bypass',
3925 b'bypass',
3929 None,
3926 None,
3930 _(b"apply patch without touching the working directory"),
3927 _(b"apply patch without touching the working directory"),
3931 ),
3928 ),
3932 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3929 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3933 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3930 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3934 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3931 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3935 (
3932 (
3936 b'',
3933 b'',
3937 b'import-branch',
3934 b'import-branch',
3938 None,
3935 None,
3939 _(b'use any branch information in patch (implied by --exact)'),
3936 _(b'use any branch information in patch (implied by --exact)'),
3940 ),
3937 ),
3941 ]
3938 ]
3942 + commitopts
3939 + commitopts
3943 + commitopts2
3940 + commitopts2
3944 + similarityopts,
3941 + similarityopts,
3945 _(b'[OPTION]... PATCH...'),
3942 _(b'[OPTION]... PATCH...'),
3946 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3943 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3947 )
3944 )
3948 def import_(ui, repo, patch1=None, *patches, **opts):
3945 def import_(ui, repo, patch1=None, *patches, **opts):
3949 """import an ordered set of patches
3946 """import an ordered set of patches
3950
3947
3951 Import a list of patches and commit them individually (unless
3948 Import a list of patches and commit them individually (unless
3952 --no-commit is specified).
3949 --no-commit is specified).
3953
3950
3954 To read a patch from standard input (stdin), use "-" as the patch
3951 To read a patch from standard input (stdin), use "-" as the patch
3955 name. If a URL is specified, the patch will be downloaded from
3952 name. If a URL is specified, the patch will be downloaded from
3956 there.
3953 there.
3957
3954
3958 Import first applies changes to the working directory (unless
3955 Import first applies changes to the working directory (unless
3959 --bypass is specified), import will abort if there are outstanding
3956 --bypass is specified), import will abort if there are outstanding
3960 changes.
3957 changes.
3961
3958
3962 Use --bypass to apply and commit patches directly to the
3959 Use --bypass to apply and commit patches directly to the
3963 repository, without affecting the working directory. Without
3960 repository, without affecting the working directory. Without
3964 --exact, patches will be applied on top of the working directory
3961 --exact, patches will be applied on top of the working directory
3965 parent revision.
3962 parent revision.
3966
3963
3967 You can import a patch straight from a mail message. Even patches
3964 You can import a patch straight from a mail message. Even patches
3968 as attachments work (to use the body part, it must have type
3965 as attachments work (to use the body part, it must have type
3969 text/plain or text/x-patch). From and Subject headers of email
3966 text/plain or text/x-patch). From and Subject headers of email
3970 message are used as default committer and commit message. All
3967 message are used as default committer and commit message. All
3971 text/plain body parts before first diff are added to the commit
3968 text/plain body parts before first diff are added to the commit
3972 message.
3969 message.
3973
3970
3974 If the imported patch was generated by :hg:`export`, user and
3971 If the imported patch was generated by :hg:`export`, user and
3975 description from patch override values from message headers and
3972 description from patch override values from message headers and
3976 body. Values given on command line with -m/--message and -u/--user
3973 body. Values given on command line with -m/--message and -u/--user
3977 override these.
3974 override these.
3978
3975
3979 If --exact is specified, import will set the working directory to
3976 If --exact is specified, import will set the working directory to
3980 the parent of each patch before applying it, and will abort if the
3977 the parent of each patch before applying it, and will abort if the
3981 resulting changeset has a different ID than the one recorded in
3978 resulting changeset has a different ID than the one recorded in
3982 the patch. This will guard against various ways that portable
3979 the patch. This will guard against various ways that portable
3983 patch formats and mail systems might fail to transfer Mercurial
3980 patch formats and mail systems might fail to transfer Mercurial
3984 data or metadata. See :hg:`bundle` for lossless transmission.
3981 data or metadata. See :hg:`bundle` for lossless transmission.
3985
3982
3986 Use --partial to ensure a changeset will be created from the patch
3983 Use --partial to ensure a changeset will be created from the patch
3987 even if some hunks fail to apply. Hunks that fail to apply will be
3984 even if some hunks fail to apply. Hunks that fail to apply will be
3988 written to a <target-file>.rej file. Conflicts can then be resolved
3985 written to a <target-file>.rej file. Conflicts can then be resolved
3989 by hand before :hg:`commit --amend` is run to update the created
3986 by hand before :hg:`commit --amend` is run to update the created
3990 changeset. This flag exists to let people import patches that
3987 changeset. This flag exists to let people import patches that
3991 partially apply without losing the associated metadata (author,
3988 partially apply without losing the associated metadata (author,
3992 date, description, ...).
3989 date, description, ...).
3993
3990
3994 .. note::
3991 .. note::
3995
3992
3996 When no hunks apply cleanly, :hg:`import --partial` will create
3993 When no hunks apply cleanly, :hg:`import --partial` will create
3997 an empty changeset, importing only the patch metadata.
3994 an empty changeset, importing only the patch metadata.
3998
3995
3999 With -s/--similarity, hg will attempt to discover renames and
3996 With -s/--similarity, hg will attempt to discover renames and
4000 copies in the patch in the same way as :hg:`addremove`.
3997 copies in the patch in the same way as :hg:`addremove`.
4001
3998
4002 It is possible to use external patch programs to perform the patch
3999 It is possible to use external patch programs to perform the patch
4003 by setting the ``ui.patch`` configuration option. For the default
4000 by setting the ``ui.patch`` configuration option. For the default
4004 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4001 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4005 See :hg:`help config` for more information about configuration
4002 See :hg:`help config` for more information about configuration
4006 files and how to use these options.
4003 files and how to use these options.
4007
4004
4008 See :hg:`help dates` for a list of formats valid for -d/--date.
4005 See :hg:`help dates` for a list of formats valid for -d/--date.
4009
4006
4010 .. container:: verbose
4007 .. container:: verbose
4011
4008
4012 Examples:
4009 Examples:
4013
4010
4014 - import a traditional patch from a website and detect renames::
4011 - import a traditional patch from a website and detect renames::
4015
4012
4016 hg import -s 80 http://example.com/bugfix.patch
4013 hg import -s 80 http://example.com/bugfix.patch
4017
4014
4018 - import a changeset from an hgweb server::
4015 - import a changeset from an hgweb server::
4019
4016
4020 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4017 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4021
4018
4022 - import all the patches in an Unix-style mbox::
4019 - import all the patches in an Unix-style mbox::
4023
4020
4024 hg import incoming-patches.mbox
4021 hg import incoming-patches.mbox
4025
4022
4026 - import patches from stdin::
4023 - import patches from stdin::
4027
4024
4028 hg import -
4025 hg import -
4029
4026
4030 - attempt to exactly restore an exported changeset (not always
4027 - attempt to exactly restore an exported changeset (not always
4031 possible)::
4028 possible)::
4032
4029
4033 hg import --exact proposed-fix.patch
4030 hg import --exact proposed-fix.patch
4034
4031
4035 - use an external tool to apply a patch which is too fuzzy for
4032 - use an external tool to apply a patch which is too fuzzy for
4036 the default internal tool.
4033 the default internal tool.
4037
4034
4038 hg import --config ui.patch="patch --merge" fuzzy.patch
4035 hg import --config ui.patch="patch --merge" fuzzy.patch
4039
4036
4040 - change the default fuzzing from 2 to a less strict 7
4037 - change the default fuzzing from 2 to a less strict 7
4041
4038
4042 hg import --config ui.fuzz=7 fuzz.patch
4039 hg import --config ui.fuzz=7 fuzz.patch
4043
4040
4044 Returns 0 on success, 1 on partial success (see --partial).
4041 Returns 0 on success, 1 on partial success (see --partial).
4045 """
4042 """
4046
4043
4047 opts = pycompat.byteskwargs(opts)
4044 opts = pycompat.byteskwargs(opts)
4048 if not patch1:
4045 if not patch1:
4049 raise error.Abort(_(b'need at least one patch to import'))
4046 raise error.Abort(_(b'need at least one patch to import'))
4050
4047
4051 patches = (patch1,) + patches
4048 patches = (patch1,) + patches
4052
4049
4053 date = opts.get(b'date')
4050 date = opts.get(b'date')
4054 if date:
4051 if date:
4055 opts[b'date'] = dateutil.parsedate(date)
4052 opts[b'date'] = dateutil.parsedate(date)
4056
4053
4057 exact = opts.get(b'exact')
4054 exact = opts.get(b'exact')
4058 update = not opts.get(b'bypass')
4055 update = not opts.get(b'bypass')
4059 if not update and opts.get(b'no_commit'):
4056 if not update and opts.get(b'no_commit'):
4060 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4057 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4061 if opts.get(b'secret') and opts.get(b'no_commit'):
4058 if opts.get(b'secret') and opts.get(b'no_commit'):
4062 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4059 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4063 try:
4060 try:
4064 sim = float(opts.get(b'similarity') or 0)
4061 sim = float(opts.get(b'similarity') or 0)
4065 except ValueError:
4062 except ValueError:
4066 raise error.Abort(_(b'similarity must be a number'))
4063 raise error.Abort(_(b'similarity must be a number'))
4067 if sim < 0 or sim > 100:
4064 if sim < 0 or sim > 100:
4068 raise error.Abort(_(b'similarity must be between 0 and 100'))
4065 raise error.Abort(_(b'similarity must be between 0 and 100'))
4069 if sim and not update:
4066 if sim and not update:
4070 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4067 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4071 if exact:
4068 if exact:
4072 if opts.get(b'edit'):
4069 if opts.get(b'edit'):
4073 raise error.Abort(_(b'cannot use --exact with --edit'))
4070 raise error.Abort(_(b'cannot use --exact with --edit'))
4074 if opts.get(b'prefix'):
4071 if opts.get(b'prefix'):
4075 raise error.Abort(_(b'cannot use --exact with --prefix'))
4072 raise error.Abort(_(b'cannot use --exact with --prefix'))
4076
4073
4077 base = opts[b"base"]
4074 base = opts[b"base"]
4078 msgs = []
4075 msgs = []
4079 ret = 0
4076 ret = 0
4080
4077
4081 with repo.wlock():
4078 with repo.wlock():
4082 if update:
4079 if update:
4083 cmdutil.checkunfinished(repo)
4080 cmdutil.checkunfinished(repo)
4084 if exact or not opts.get(b'force'):
4081 if exact or not opts.get(b'force'):
4085 cmdutil.bailifchanged(repo)
4082 cmdutil.bailifchanged(repo)
4086
4083
4087 if not opts.get(b'no_commit'):
4084 if not opts.get(b'no_commit'):
4088 lock = repo.lock
4085 lock = repo.lock
4089 tr = lambda: repo.transaction(b'import')
4086 tr = lambda: repo.transaction(b'import')
4090 dsguard = util.nullcontextmanager
4087 dsguard = util.nullcontextmanager
4091 else:
4088 else:
4092 lock = util.nullcontextmanager
4089 lock = util.nullcontextmanager
4093 tr = util.nullcontextmanager
4090 tr = util.nullcontextmanager
4094 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4091 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4095 with lock(), tr(), dsguard():
4092 with lock(), tr(), dsguard():
4096 parents = repo[None].parents()
4093 parents = repo[None].parents()
4097 for patchurl in patches:
4094 for patchurl in patches:
4098 if patchurl == b'-':
4095 if patchurl == b'-':
4099 ui.status(_(b'applying patch from stdin\n'))
4096 ui.status(_(b'applying patch from stdin\n'))
4100 patchfile = ui.fin
4097 patchfile = ui.fin
4101 patchurl = b'stdin' # for error message
4098 patchurl = b'stdin' # for error message
4102 else:
4099 else:
4103 patchurl = os.path.join(base, patchurl)
4100 patchurl = os.path.join(base, patchurl)
4104 ui.status(_(b'applying %s\n') % patchurl)
4101 ui.status(_(b'applying %s\n') % patchurl)
4105 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4102 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4106
4103
4107 haspatch = False
4104 haspatch = False
4108 for hunk in patch.split(patchfile):
4105 for hunk in patch.split(patchfile):
4109 with patch.extract(ui, hunk) as patchdata:
4106 with patch.extract(ui, hunk) as patchdata:
4110 msg, node, rej = cmdutil.tryimportone(
4107 msg, node, rej = cmdutil.tryimportone(
4111 ui, repo, patchdata, parents, opts, msgs, hg.clean
4108 ui, repo, patchdata, parents, opts, msgs, hg.clean
4112 )
4109 )
4113 if msg:
4110 if msg:
4114 haspatch = True
4111 haspatch = True
4115 ui.note(msg + b'\n')
4112 ui.note(msg + b'\n')
4116 if update or exact:
4113 if update or exact:
4117 parents = repo[None].parents()
4114 parents = repo[None].parents()
4118 else:
4115 else:
4119 parents = [repo[node]]
4116 parents = [repo[node]]
4120 if rej:
4117 if rej:
4121 ui.write_err(_(b"patch applied partially\n"))
4118 ui.write_err(_(b"patch applied partially\n"))
4122 ui.write_err(
4119 ui.write_err(
4123 _(
4120 _(
4124 b"(fix the .rej files and run "
4121 b"(fix the .rej files and run "
4125 b"`hg commit --amend`)\n"
4122 b"`hg commit --amend`)\n"
4126 )
4123 )
4127 )
4124 )
4128 ret = 1
4125 ret = 1
4129 break
4126 break
4130
4127
4131 if not haspatch:
4128 if not haspatch:
4132 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4129 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4133
4130
4134 if msgs:
4131 if msgs:
4135 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4132 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4136 return ret
4133 return ret
4137
4134
4138
4135
4139 @command(
4136 @command(
4140 b'incoming|in',
4137 b'incoming|in',
4141 [
4138 [
4142 (
4139 (
4143 b'f',
4140 b'f',
4144 b'force',
4141 b'force',
4145 None,
4142 None,
4146 _(b'run even if remote repository is unrelated'),
4143 _(b'run even if remote repository is unrelated'),
4147 ),
4144 ),
4148 (b'n', b'newest-first', None, _(b'show newest record first')),
4145 (b'n', b'newest-first', None, _(b'show newest record first')),
4149 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4146 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4150 (
4147 (
4151 b'r',
4148 b'r',
4152 b'rev',
4149 b'rev',
4153 [],
4150 [],
4154 _(b'a remote changeset intended to be added'),
4151 _(b'a remote changeset intended to be added'),
4155 _(b'REV'),
4152 _(b'REV'),
4156 ),
4153 ),
4157 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4154 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4158 (
4155 (
4159 b'b',
4156 b'b',
4160 b'branch',
4157 b'branch',
4161 [],
4158 [],
4162 _(b'a specific branch you would like to pull'),
4159 _(b'a specific branch you would like to pull'),
4163 _(b'BRANCH'),
4160 _(b'BRANCH'),
4164 ),
4161 ),
4165 ]
4162 ]
4166 + logopts
4163 + logopts
4167 + remoteopts
4164 + remoteopts
4168 + subrepoopts,
4165 + subrepoopts,
4169 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4166 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4170 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4167 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4171 )
4168 )
4172 def incoming(ui, repo, source=b"default", **opts):
4169 def incoming(ui, repo, source=b"default", **opts):
4173 """show new changesets found in source
4170 """show new changesets found in source
4174
4171
4175 Show new changesets found in the specified path/URL or the default
4172 Show new changesets found in the specified path/URL or the default
4176 pull location. These are the changesets that would have been pulled
4173 pull location. These are the changesets that would have been pulled
4177 by :hg:`pull` at the time you issued this command.
4174 by :hg:`pull` at the time you issued this command.
4178
4175
4179 See pull for valid source format details.
4176 See pull for valid source format details.
4180
4177
4181 .. container:: verbose
4178 .. container:: verbose
4182
4179
4183 With -B/--bookmarks, the result of bookmark comparison between
4180 With -B/--bookmarks, the result of bookmark comparison between
4184 local and remote repositories is displayed. With -v/--verbose,
4181 local and remote repositories is displayed. With -v/--verbose,
4185 status is also displayed for each bookmark like below::
4182 status is also displayed for each bookmark like below::
4186
4183
4187 BM1 01234567890a added
4184 BM1 01234567890a added
4188 BM2 1234567890ab advanced
4185 BM2 1234567890ab advanced
4189 BM3 234567890abc diverged
4186 BM3 234567890abc diverged
4190 BM4 34567890abcd changed
4187 BM4 34567890abcd changed
4191
4188
4192 The action taken locally when pulling depends on the
4189 The action taken locally when pulling depends on the
4193 status of each bookmark:
4190 status of each bookmark:
4194
4191
4195 :``added``: pull will create it
4192 :``added``: pull will create it
4196 :``advanced``: pull will update it
4193 :``advanced``: pull will update it
4197 :``diverged``: pull will create a divergent bookmark
4194 :``diverged``: pull will create a divergent bookmark
4198 :``changed``: result depends on remote changesets
4195 :``changed``: result depends on remote changesets
4199
4196
4200 From the point of view of pulling behavior, bookmark
4197 From the point of view of pulling behavior, bookmark
4201 existing only in the remote repository are treated as ``added``,
4198 existing only in the remote repository are treated as ``added``,
4202 even if it is in fact locally deleted.
4199 even if it is in fact locally deleted.
4203
4200
4204 .. container:: verbose
4201 .. container:: verbose
4205
4202
4206 For remote repository, using --bundle avoids downloading the
4203 For remote repository, using --bundle avoids downloading the
4207 changesets twice if the incoming is followed by a pull.
4204 changesets twice if the incoming is followed by a pull.
4208
4205
4209 Examples:
4206 Examples:
4210
4207
4211 - show incoming changes with patches and full description::
4208 - show incoming changes with patches and full description::
4212
4209
4213 hg incoming -vp
4210 hg incoming -vp
4214
4211
4215 - show incoming changes excluding merges, store a bundle::
4212 - show incoming changes excluding merges, store a bundle::
4216
4213
4217 hg in -vpM --bundle incoming.hg
4214 hg in -vpM --bundle incoming.hg
4218 hg pull incoming.hg
4215 hg pull incoming.hg
4219
4216
4220 - briefly list changes inside a bundle::
4217 - briefly list changes inside a bundle::
4221
4218
4222 hg in changes.hg -T "{desc|firstline}\\n"
4219 hg in changes.hg -T "{desc|firstline}\\n"
4223
4220
4224 Returns 0 if there are incoming changes, 1 otherwise.
4221 Returns 0 if there are incoming changes, 1 otherwise.
4225 """
4222 """
4226 opts = pycompat.byteskwargs(opts)
4223 opts = pycompat.byteskwargs(opts)
4227 if opts.get(b'graph'):
4224 if opts.get(b'graph'):
4228 logcmdutil.checkunsupportedgraphflags([], opts)
4225 logcmdutil.checkunsupportedgraphflags([], opts)
4229
4226
4230 def display(other, chlist, displayer):
4227 def display(other, chlist, displayer):
4231 revdag = logcmdutil.graphrevs(other, chlist, opts)
4228 revdag = logcmdutil.graphrevs(other, chlist, opts)
4232 logcmdutil.displaygraph(
4229 logcmdutil.displaygraph(
4233 ui, repo, revdag, displayer, graphmod.asciiedges
4230 ui, repo, revdag, displayer, graphmod.asciiedges
4234 )
4231 )
4235
4232
4236 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4233 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4237 return 0
4234 return 0
4238
4235
4239 if opts.get(b'bundle') and opts.get(b'subrepos'):
4236 if opts.get(b'bundle') and opts.get(b'subrepos'):
4240 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4237 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4241
4238
4242 if opts.get(b'bookmarks'):
4239 if opts.get(b'bookmarks'):
4243 source, branches = hg.parseurl(
4240 source, branches = hg.parseurl(
4244 ui.expandpath(source), opts.get(b'branch')
4241 ui.expandpath(source), opts.get(b'branch')
4245 )
4242 )
4246 other = hg.peer(repo, opts, source)
4243 other = hg.peer(repo, opts, source)
4247 if b'bookmarks' not in other.listkeys(b'namespaces'):
4244 if b'bookmarks' not in other.listkeys(b'namespaces'):
4248 ui.warn(_(b"remote doesn't support bookmarks\n"))
4245 ui.warn(_(b"remote doesn't support bookmarks\n"))
4249 return 0
4246 return 0
4250 ui.pager(b'incoming')
4247 ui.pager(b'incoming')
4251 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4248 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4252 return bookmarks.incoming(ui, repo, other)
4249 return bookmarks.incoming(ui, repo, other)
4253
4250
4254 repo._subtoppath = ui.expandpath(source)
4251 repo._subtoppath = ui.expandpath(source)
4255 try:
4252 try:
4256 return hg.incoming(ui, repo, source, opts)
4253 return hg.incoming(ui, repo, source, opts)
4257 finally:
4254 finally:
4258 del repo._subtoppath
4255 del repo._subtoppath
4259
4256
4260
4257
4261 @command(
4258 @command(
4262 b'init',
4259 b'init',
4263 remoteopts,
4260 remoteopts,
4264 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4261 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4265 helpcategory=command.CATEGORY_REPO_CREATION,
4262 helpcategory=command.CATEGORY_REPO_CREATION,
4266 helpbasic=True,
4263 helpbasic=True,
4267 norepo=True,
4264 norepo=True,
4268 )
4265 )
4269 def init(ui, dest=b".", **opts):
4266 def init(ui, dest=b".", **opts):
4270 """create a new repository in the given directory
4267 """create a new repository in the given directory
4271
4268
4272 Initialize a new repository in the given directory. If the given
4269 Initialize a new repository in the given directory. If the given
4273 directory does not exist, it will be created.
4270 directory does not exist, it will be created.
4274
4271
4275 If no directory is given, the current directory is used.
4272 If no directory is given, the current directory is used.
4276
4273
4277 It is possible to specify an ``ssh://`` URL as the destination.
4274 It is possible to specify an ``ssh://`` URL as the destination.
4278 See :hg:`help urls` for more information.
4275 See :hg:`help urls` for more information.
4279
4276
4280 Returns 0 on success.
4277 Returns 0 on success.
4281 """
4278 """
4282 opts = pycompat.byteskwargs(opts)
4279 opts = pycompat.byteskwargs(opts)
4283 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4280 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4284
4281
4285
4282
4286 @command(
4283 @command(
4287 b'locate',
4284 b'locate',
4288 [
4285 [
4289 (
4286 (
4290 b'r',
4287 b'r',
4291 b'rev',
4288 b'rev',
4292 b'',
4289 b'',
4293 _(b'search the repository as it is in REV'),
4290 _(b'search the repository as it is in REV'),
4294 _(b'REV'),
4291 _(b'REV'),
4295 ),
4292 ),
4296 (
4293 (
4297 b'0',
4294 b'0',
4298 b'print0',
4295 b'print0',
4299 None,
4296 None,
4300 _(b'end filenames with NUL, for use with xargs'),
4297 _(b'end filenames with NUL, for use with xargs'),
4301 ),
4298 ),
4302 (
4299 (
4303 b'f',
4300 b'f',
4304 b'fullpath',
4301 b'fullpath',
4305 None,
4302 None,
4306 _(b'print complete paths from the filesystem root'),
4303 _(b'print complete paths from the filesystem root'),
4307 ),
4304 ),
4308 ]
4305 ]
4309 + walkopts,
4306 + walkopts,
4310 _(b'[OPTION]... [PATTERN]...'),
4307 _(b'[OPTION]... [PATTERN]...'),
4311 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4308 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4312 )
4309 )
4313 def locate(ui, repo, *pats, **opts):
4310 def locate(ui, repo, *pats, **opts):
4314 """locate files matching specific patterns (DEPRECATED)
4311 """locate files matching specific patterns (DEPRECATED)
4315
4312
4316 Print files under Mercurial control in the working directory whose
4313 Print files under Mercurial control in the working directory whose
4317 names match the given patterns.
4314 names match the given patterns.
4318
4315
4319 By default, this command searches all directories in the working
4316 By default, this command searches all directories in the working
4320 directory. To search just the current directory and its
4317 directory. To search just the current directory and its
4321 subdirectories, use "--include .".
4318 subdirectories, use "--include .".
4322
4319
4323 If no patterns are given to match, this command prints the names
4320 If no patterns are given to match, this command prints the names
4324 of all files under Mercurial control in the working directory.
4321 of all files under Mercurial control in the working directory.
4325
4322
4326 If you want to feed the output of this command into the "xargs"
4323 If you want to feed the output of this command into the "xargs"
4327 command, use the -0 option to both this command and "xargs". This
4324 command, use the -0 option to both this command and "xargs". This
4328 will avoid the problem of "xargs" treating single filenames that
4325 will avoid the problem of "xargs" treating single filenames that
4329 contain whitespace as multiple filenames.
4326 contain whitespace as multiple filenames.
4330
4327
4331 See :hg:`help files` for a more versatile command.
4328 See :hg:`help files` for a more versatile command.
4332
4329
4333 Returns 0 if a match is found, 1 otherwise.
4330 Returns 0 if a match is found, 1 otherwise.
4334 """
4331 """
4335 opts = pycompat.byteskwargs(opts)
4332 opts = pycompat.byteskwargs(opts)
4336 if opts.get(b'print0'):
4333 if opts.get(b'print0'):
4337 end = b'\0'
4334 end = b'\0'
4338 else:
4335 else:
4339 end = b'\n'
4336 end = b'\n'
4340 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4337 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4341
4338
4342 ret = 1
4339 ret = 1
4343 m = scmutil.match(
4340 m = scmutil.match(
4344 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4341 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4345 )
4342 )
4346
4343
4347 ui.pager(b'locate')
4344 ui.pager(b'locate')
4348 if ctx.rev() is None:
4345 if ctx.rev() is None:
4349 # When run on the working copy, "locate" includes removed files, so
4346 # When run on the working copy, "locate" includes removed files, so
4350 # we get the list of files from the dirstate.
4347 # we get the list of files from the dirstate.
4351 filesgen = sorted(repo.dirstate.matches(m))
4348 filesgen = sorted(repo.dirstate.matches(m))
4352 else:
4349 else:
4353 filesgen = ctx.matches(m)
4350 filesgen = ctx.matches(m)
4354 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4351 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4355 for abs in filesgen:
4352 for abs in filesgen:
4356 if opts.get(b'fullpath'):
4353 if opts.get(b'fullpath'):
4357 ui.write(repo.wjoin(abs), end)
4354 ui.write(repo.wjoin(abs), end)
4358 else:
4355 else:
4359 ui.write(uipathfn(abs), end)
4356 ui.write(uipathfn(abs), end)
4360 ret = 0
4357 ret = 0
4361
4358
4362 return ret
4359 return ret
4363
4360
4364
4361
4365 @command(
4362 @command(
4366 b'log|history',
4363 b'log|history',
4367 [
4364 [
4368 (
4365 (
4369 b'f',
4366 b'f',
4370 b'follow',
4367 b'follow',
4371 None,
4368 None,
4372 _(
4369 _(
4373 b'follow changeset history, or file history across copies and renames'
4370 b'follow changeset history, or file history across copies and renames'
4374 ),
4371 ),
4375 ),
4372 ),
4376 (
4373 (
4377 b'',
4374 b'',
4378 b'follow-first',
4375 b'follow-first',
4379 None,
4376 None,
4380 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4377 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4381 ),
4378 ),
4382 (
4379 (
4383 b'd',
4380 b'd',
4384 b'date',
4381 b'date',
4385 b'',
4382 b'',
4386 _(b'show revisions matching date spec'),
4383 _(b'show revisions matching date spec'),
4387 _(b'DATE'),
4384 _(b'DATE'),
4388 ),
4385 ),
4389 (b'C', b'copies', None, _(b'show copied files')),
4386 (b'C', b'copies', None, _(b'show copied files')),
4390 (
4387 (
4391 b'k',
4388 b'k',
4392 b'keyword',
4389 b'keyword',
4393 [],
4390 [],
4394 _(b'do case-insensitive search for a given text'),
4391 _(b'do case-insensitive search for a given text'),
4395 _(b'TEXT'),
4392 _(b'TEXT'),
4396 ),
4393 ),
4397 (
4394 (
4398 b'r',
4395 b'r',
4399 b'rev',
4396 b'rev',
4400 [],
4397 [],
4401 _(b'show the specified revision or revset'),
4398 _(b'show the specified revision or revset'),
4402 _(b'REV'),
4399 _(b'REV'),
4403 ),
4400 ),
4404 (
4401 (
4405 b'L',
4402 b'L',
4406 b'line-range',
4403 b'line-range',
4407 [],
4404 [],
4408 _(b'follow line range of specified file (EXPERIMENTAL)'),
4405 _(b'follow line range of specified file (EXPERIMENTAL)'),
4409 _(b'FILE,RANGE'),
4406 _(b'FILE,RANGE'),
4410 ),
4407 ),
4411 (
4408 (
4412 b'',
4409 b'',
4413 b'removed',
4410 b'removed',
4414 None,
4411 None,
4415 _(b'include revisions where files were removed'),
4412 _(b'include revisions where files were removed'),
4416 ),
4413 ),
4417 (
4414 (
4418 b'm',
4415 b'm',
4419 b'only-merges',
4416 b'only-merges',
4420 None,
4417 None,
4421 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4418 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4422 ),
4419 ),
4423 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4420 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4424 (
4421 (
4425 b'',
4422 b'',
4426 b'only-branch',
4423 b'only-branch',
4427 [],
4424 [],
4428 _(
4425 _(
4429 b'show only changesets within the given named branch (DEPRECATED)'
4426 b'show only changesets within the given named branch (DEPRECATED)'
4430 ),
4427 ),
4431 _(b'BRANCH'),
4428 _(b'BRANCH'),
4432 ),
4429 ),
4433 (
4430 (
4434 b'b',
4431 b'b',
4435 b'branch',
4432 b'branch',
4436 [],
4433 [],
4437 _(b'show changesets within the given named branch'),
4434 _(b'show changesets within the given named branch'),
4438 _(b'BRANCH'),
4435 _(b'BRANCH'),
4439 ),
4436 ),
4440 (
4437 (
4441 b'P',
4438 b'P',
4442 b'prune',
4439 b'prune',
4443 [],
4440 [],
4444 _(b'do not display revision or any of its ancestors'),
4441 _(b'do not display revision or any of its ancestors'),
4445 _(b'REV'),
4442 _(b'REV'),
4446 ),
4443 ),
4447 ]
4444 ]
4448 + logopts
4445 + logopts
4449 + walkopts,
4446 + walkopts,
4450 _(b'[OPTION]... [FILE]'),
4447 _(b'[OPTION]... [FILE]'),
4451 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4448 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4452 helpbasic=True,
4449 helpbasic=True,
4453 inferrepo=True,
4450 inferrepo=True,
4454 intents={INTENT_READONLY},
4451 intents={INTENT_READONLY},
4455 )
4452 )
4456 def log(ui, repo, *pats, **opts):
4453 def log(ui, repo, *pats, **opts):
4457 """show revision history of entire repository or files
4454 """show revision history of entire repository or files
4458
4455
4459 Print the revision history of the specified files or the entire
4456 Print the revision history of the specified files or the entire
4460 project.
4457 project.
4461
4458
4462 If no revision range is specified, the default is ``tip:0`` unless
4459 If no revision range is specified, the default is ``tip:0`` unless
4463 --follow is set, in which case the working directory parent is
4460 --follow is set, in which case the working directory parent is
4464 used as the starting revision.
4461 used as the starting revision.
4465
4462
4466 File history is shown without following rename or copy history of
4463 File history is shown without following rename or copy history of
4467 files. Use -f/--follow with a filename to follow history across
4464 files. Use -f/--follow with a filename to follow history across
4468 renames and copies. --follow without a filename will only show
4465 renames and copies. --follow without a filename will only show
4469 ancestors of the starting revision.
4466 ancestors of the starting revision.
4470
4467
4471 By default this command prints revision number and changeset id,
4468 By default this command prints revision number and changeset id,
4472 tags, non-trivial parents, user, date and time, and a summary for
4469 tags, non-trivial parents, user, date and time, and a summary for
4473 each commit. When the -v/--verbose switch is used, the list of
4470 each commit. When the -v/--verbose switch is used, the list of
4474 changed files and full commit message are shown.
4471 changed files and full commit message are shown.
4475
4472
4476 With --graph the revisions are shown as an ASCII art DAG with the most
4473 With --graph the revisions are shown as an ASCII art DAG with the most
4477 recent changeset at the top.
4474 recent changeset at the top.
4478 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4475 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4479 involved in an unresolved merge conflict, '_' closes a branch,
4476 involved in an unresolved merge conflict, '_' closes a branch,
4480 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4477 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4481 changeset from the lines below is a parent of the 'o' merge on the same
4478 changeset from the lines below is a parent of the 'o' merge on the same
4482 line.
4479 line.
4483 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4480 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4484 of a '|' indicates one or more revisions in a path are omitted.
4481 of a '|' indicates one or more revisions in a path are omitted.
4485
4482
4486 .. container:: verbose
4483 .. container:: verbose
4487
4484
4488 Use -L/--line-range FILE,M:N options to follow the history of lines
4485 Use -L/--line-range FILE,M:N options to follow the history of lines
4489 from M to N in FILE. With -p/--patch only diff hunks affecting
4486 from M to N in FILE. With -p/--patch only diff hunks affecting
4490 specified line range will be shown. This option requires --follow;
4487 specified line range will be shown. This option requires --follow;
4491 it can be specified multiple times. Currently, this option is not
4488 it can be specified multiple times. Currently, this option is not
4492 compatible with --graph. This option is experimental.
4489 compatible with --graph. This option is experimental.
4493
4490
4494 .. note::
4491 .. note::
4495
4492
4496 :hg:`log --patch` may generate unexpected diff output for merge
4493 :hg:`log --patch` may generate unexpected diff output for merge
4497 changesets, as it will only compare the merge changeset against
4494 changesets, as it will only compare the merge changeset against
4498 its first parent. Also, only files different from BOTH parents
4495 its first parent. Also, only files different from BOTH parents
4499 will appear in files:.
4496 will appear in files:.
4500
4497
4501 .. note::
4498 .. note::
4502
4499
4503 For performance reasons, :hg:`log FILE` may omit duplicate changes
4500 For performance reasons, :hg:`log FILE` may omit duplicate changes
4504 made on branches and will not show removals or mode changes. To
4501 made on branches and will not show removals or mode changes. To
4505 see all such changes, use the --removed switch.
4502 see all such changes, use the --removed switch.
4506
4503
4507 .. container:: verbose
4504 .. container:: verbose
4508
4505
4509 .. note::
4506 .. note::
4510
4507
4511 The history resulting from -L/--line-range options depends on diff
4508 The history resulting from -L/--line-range options depends on diff
4512 options; for instance if white-spaces are ignored, respective changes
4509 options; for instance if white-spaces are ignored, respective changes
4513 with only white-spaces in specified line range will not be listed.
4510 with only white-spaces in specified line range will not be listed.
4514
4511
4515 .. container:: verbose
4512 .. container:: verbose
4516
4513
4517 Some examples:
4514 Some examples:
4518
4515
4519 - changesets with full descriptions and file lists::
4516 - changesets with full descriptions and file lists::
4520
4517
4521 hg log -v
4518 hg log -v
4522
4519
4523 - changesets ancestral to the working directory::
4520 - changesets ancestral to the working directory::
4524
4521
4525 hg log -f
4522 hg log -f
4526
4523
4527 - last 10 commits on the current branch::
4524 - last 10 commits on the current branch::
4528
4525
4529 hg log -l 10 -b .
4526 hg log -l 10 -b .
4530
4527
4531 - changesets showing all modifications of a file, including removals::
4528 - changesets showing all modifications of a file, including removals::
4532
4529
4533 hg log --removed file.c
4530 hg log --removed file.c
4534
4531
4535 - all changesets that touch a directory, with diffs, excluding merges::
4532 - all changesets that touch a directory, with diffs, excluding merges::
4536
4533
4537 hg log -Mp lib/
4534 hg log -Mp lib/
4538
4535
4539 - all revision numbers that match a keyword::
4536 - all revision numbers that match a keyword::
4540
4537
4541 hg log -k bug --template "{rev}\\n"
4538 hg log -k bug --template "{rev}\\n"
4542
4539
4543 - the full hash identifier of the working directory parent::
4540 - the full hash identifier of the working directory parent::
4544
4541
4545 hg log -r . --template "{node}\\n"
4542 hg log -r . --template "{node}\\n"
4546
4543
4547 - list available log templates::
4544 - list available log templates::
4548
4545
4549 hg log -T list
4546 hg log -T list
4550
4547
4551 - check if a given changeset is included in a tagged release::
4548 - check if a given changeset is included in a tagged release::
4552
4549
4553 hg log -r "a21ccf and ancestor(1.9)"
4550 hg log -r "a21ccf and ancestor(1.9)"
4554
4551
4555 - find all changesets by some user in a date range::
4552 - find all changesets by some user in a date range::
4556
4553
4557 hg log -k alice -d "may 2008 to jul 2008"
4554 hg log -k alice -d "may 2008 to jul 2008"
4558
4555
4559 - summary of all changesets after the last tag::
4556 - summary of all changesets after the last tag::
4560
4557
4561 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4558 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4562
4559
4563 - changesets touching lines 13 to 23 for file.c::
4560 - changesets touching lines 13 to 23 for file.c::
4564
4561
4565 hg log -L file.c,13:23
4562 hg log -L file.c,13:23
4566
4563
4567 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4564 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4568 main.c with patch::
4565 main.c with patch::
4569
4566
4570 hg log -L file.c,13:23 -L main.c,2:6 -p
4567 hg log -L file.c,13:23 -L main.c,2:6 -p
4571
4568
4572 See :hg:`help dates` for a list of formats valid for -d/--date.
4569 See :hg:`help dates` for a list of formats valid for -d/--date.
4573
4570
4574 See :hg:`help revisions` for more about specifying and ordering
4571 See :hg:`help revisions` for more about specifying and ordering
4575 revisions.
4572 revisions.
4576
4573
4577 See :hg:`help templates` for more about pre-packaged styles and
4574 See :hg:`help templates` for more about pre-packaged styles and
4578 specifying custom templates. The default template used by the log
4575 specifying custom templates. The default template used by the log
4579 command can be customized via the ``ui.logtemplate`` configuration
4576 command can be customized via the ``ui.logtemplate`` configuration
4580 setting.
4577 setting.
4581
4578
4582 Returns 0 on success.
4579 Returns 0 on success.
4583
4580
4584 """
4581 """
4585 opts = pycompat.byteskwargs(opts)
4582 opts = pycompat.byteskwargs(opts)
4586 linerange = opts.get(b'line_range')
4583 linerange = opts.get(b'line_range')
4587
4584
4588 if linerange and not opts.get(b'follow'):
4585 if linerange and not opts.get(b'follow'):
4589 raise error.Abort(_(b'--line-range requires --follow'))
4586 raise error.Abort(_(b'--line-range requires --follow'))
4590
4587
4591 if linerange and pats:
4588 if linerange and pats:
4592 # TODO: take pats as patterns with no line-range filter
4589 # TODO: take pats as patterns with no line-range filter
4593 raise error.Abort(
4590 raise error.Abort(
4594 _(b'FILE arguments are not compatible with --line-range option')
4591 _(b'FILE arguments are not compatible with --line-range option')
4595 )
4592 )
4596
4593
4597 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4594 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4598 revs, differ = logcmdutil.getrevs(
4595 revs, differ = logcmdutil.getrevs(
4599 repo, logcmdutil.parseopts(ui, pats, opts)
4596 repo, logcmdutil.parseopts(ui, pats, opts)
4600 )
4597 )
4601 if linerange:
4598 if linerange:
4602 # TODO: should follow file history from logcmdutil._initialrevs(),
4599 # TODO: should follow file history from logcmdutil._initialrevs(),
4603 # then filter the result by logcmdutil._makerevset() and --limit
4600 # then filter the result by logcmdutil._makerevset() and --limit
4604 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4601 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4605
4602
4606 getcopies = None
4603 getcopies = None
4607 if opts.get(b'copies'):
4604 if opts.get(b'copies'):
4608 endrev = None
4605 endrev = None
4609 if revs:
4606 if revs:
4610 endrev = revs.max() + 1
4607 endrev = revs.max() + 1
4611 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4608 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4612
4609
4613 ui.pager(b'log')
4610 ui.pager(b'log')
4614 displayer = logcmdutil.changesetdisplayer(
4611 displayer = logcmdutil.changesetdisplayer(
4615 ui, repo, opts, differ, buffered=True
4612 ui, repo, opts, differ, buffered=True
4616 )
4613 )
4617 if opts.get(b'graph'):
4614 if opts.get(b'graph'):
4618 displayfn = logcmdutil.displaygraphrevs
4615 displayfn = logcmdutil.displaygraphrevs
4619 else:
4616 else:
4620 displayfn = logcmdutil.displayrevs
4617 displayfn = logcmdutil.displayrevs
4621 displayfn(ui, repo, revs, displayer, getcopies)
4618 displayfn(ui, repo, revs, displayer, getcopies)
4622
4619
4623
4620
4624 @command(
4621 @command(
4625 b'manifest',
4622 b'manifest',
4626 [
4623 [
4627 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4624 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4628 (b'', b'all', False, _(b"list files from all revisions")),
4625 (b'', b'all', False, _(b"list files from all revisions")),
4629 ]
4626 ]
4630 + formatteropts,
4627 + formatteropts,
4631 _(b'[-r REV]'),
4628 _(b'[-r REV]'),
4632 helpcategory=command.CATEGORY_MAINTENANCE,
4629 helpcategory=command.CATEGORY_MAINTENANCE,
4633 intents={INTENT_READONLY},
4630 intents={INTENT_READONLY},
4634 )
4631 )
4635 def manifest(ui, repo, node=None, rev=None, **opts):
4632 def manifest(ui, repo, node=None, rev=None, **opts):
4636 """output the current or given revision of the project manifest
4633 """output the current or given revision of the project manifest
4637
4634
4638 Print a list of version controlled files for the given revision.
4635 Print a list of version controlled files for the given revision.
4639 If no revision is given, the first parent of the working directory
4636 If no revision is given, the first parent of the working directory
4640 is used, or the null revision if no revision is checked out.
4637 is used, or the null revision if no revision is checked out.
4641
4638
4642 With -v, print file permissions, symlink and executable bits.
4639 With -v, print file permissions, symlink and executable bits.
4643 With --debug, print file revision hashes.
4640 With --debug, print file revision hashes.
4644
4641
4645 If option --all is specified, the list of all files from all revisions
4642 If option --all is specified, the list of all files from all revisions
4646 is printed. This includes deleted and renamed files.
4643 is printed. This includes deleted and renamed files.
4647
4644
4648 Returns 0 on success.
4645 Returns 0 on success.
4649 """
4646 """
4650 opts = pycompat.byteskwargs(opts)
4647 opts = pycompat.byteskwargs(opts)
4651 fm = ui.formatter(b'manifest', opts)
4648 fm = ui.formatter(b'manifest', opts)
4652
4649
4653 if opts.get(b'all'):
4650 if opts.get(b'all'):
4654 if rev or node:
4651 if rev or node:
4655 raise error.Abort(_(b"can't specify a revision with --all"))
4652 raise error.Abort(_(b"can't specify a revision with --all"))
4656
4653
4657 res = set()
4654 res = set()
4658 for rev in repo:
4655 for rev in repo:
4659 ctx = repo[rev]
4656 ctx = repo[rev]
4660 res |= set(ctx.files())
4657 res |= set(ctx.files())
4661
4658
4662 ui.pager(b'manifest')
4659 ui.pager(b'manifest')
4663 for f in sorted(res):
4660 for f in sorted(res):
4664 fm.startitem()
4661 fm.startitem()
4665 fm.write(b"path", b'%s\n', f)
4662 fm.write(b"path", b'%s\n', f)
4666 fm.end()
4663 fm.end()
4667 return
4664 return
4668
4665
4669 if rev and node:
4666 if rev and node:
4670 raise error.Abort(_(b"please specify just one revision"))
4667 raise error.Abort(_(b"please specify just one revision"))
4671
4668
4672 if not node:
4669 if not node:
4673 node = rev
4670 node = rev
4674
4671
4675 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4672 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4676 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4673 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4677 if node:
4674 if node:
4678 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4675 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4679 ctx = scmutil.revsingle(repo, node)
4676 ctx = scmutil.revsingle(repo, node)
4680 mf = ctx.manifest()
4677 mf = ctx.manifest()
4681 ui.pager(b'manifest')
4678 ui.pager(b'manifest')
4682 for f in ctx:
4679 for f in ctx:
4683 fm.startitem()
4680 fm.startitem()
4684 fm.context(ctx=ctx)
4681 fm.context(ctx=ctx)
4685 fl = ctx[f].flags()
4682 fl = ctx[f].flags()
4686 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4683 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4687 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4684 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4688 fm.write(b'path', b'%s\n', f)
4685 fm.write(b'path', b'%s\n', f)
4689 fm.end()
4686 fm.end()
4690
4687
4691
4688
4692 @command(
4689 @command(
4693 b'merge',
4690 b'merge',
4694 [
4691 [
4695 (
4692 (
4696 b'f',
4693 b'f',
4697 b'force',
4694 b'force',
4698 None,
4695 None,
4699 _(b'force a merge including outstanding changes (DEPRECATED)'),
4696 _(b'force a merge including outstanding changes (DEPRECATED)'),
4700 ),
4697 ),
4701 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4698 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4702 (
4699 (
4703 b'P',
4700 b'P',
4704 b'preview',
4701 b'preview',
4705 None,
4702 None,
4706 _(b'review revisions to merge (no merge is performed)'),
4703 _(b'review revisions to merge (no merge is performed)'),
4707 ),
4704 ),
4708 (b'', b'abort', None, _(b'abort the ongoing merge')),
4705 (b'', b'abort', None, _(b'abort the ongoing merge')),
4709 ]
4706 ]
4710 + mergetoolopts,
4707 + mergetoolopts,
4711 _(b'[-P] [[-r] REV]'),
4708 _(b'[-P] [[-r] REV]'),
4712 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4709 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4713 helpbasic=True,
4710 helpbasic=True,
4714 )
4711 )
4715 def merge(ui, repo, node=None, **opts):
4712 def merge(ui, repo, node=None, **opts):
4716 """merge another revision into working directory
4713 """merge another revision into working directory
4717
4714
4718 The current working directory is updated with all changes made in
4715 The current working directory is updated with all changes made in
4719 the requested revision since the last common predecessor revision.
4716 the requested revision since the last common predecessor revision.
4720
4717
4721 Files that changed between either parent are marked as changed for
4718 Files that changed between either parent are marked as changed for
4722 the next commit and a commit must be performed before any further
4719 the next commit and a commit must be performed before any further
4723 updates to the repository are allowed. The next commit will have
4720 updates to the repository are allowed. The next commit will have
4724 two parents.
4721 two parents.
4725
4722
4726 ``--tool`` can be used to specify the merge tool used for file
4723 ``--tool`` can be used to specify the merge tool used for file
4727 merges. It overrides the HGMERGE environment variable and your
4724 merges. It overrides the HGMERGE environment variable and your
4728 configuration files. See :hg:`help merge-tools` for options.
4725 configuration files. See :hg:`help merge-tools` for options.
4729
4726
4730 If no revision is specified, the working directory's parent is a
4727 If no revision is specified, the working directory's parent is a
4731 head revision, and the current branch contains exactly one other
4728 head revision, and the current branch contains exactly one other
4732 head, the other head is merged with by default. Otherwise, an
4729 head, the other head is merged with by default. Otherwise, an
4733 explicit revision with which to merge must be provided.
4730 explicit revision with which to merge must be provided.
4734
4731
4735 See :hg:`help resolve` for information on handling file conflicts.
4732 See :hg:`help resolve` for information on handling file conflicts.
4736
4733
4737 To undo an uncommitted merge, use :hg:`merge --abort` which
4734 To undo an uncommitted merge, use :hg:`merge --abort` which
4738 will check out a clean copy of the original merge parent, losing
4735 will check out a clean copy of the original merge parent, losing
4739 all changes.
4736 all changes.
4740
4737
4741 Returns 0 on success, 1 if there are unresolved files.
4738 Returns 0 on success, 1 if there are unresolved files.
4742 """
4739 """
4743
4740
4744 opts = pycompat.byteskwargs(opts)
4741 opts = pycompat.byteskwargs(opts)
4745 abort = opts.get(b'abort')
4742 abort = opts.get(b'abort')
4746 if abort and repo.dirstate.p2() == nullid:
4743 if abort and repo.dirstate.p2() == nullid:
4747 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4744 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4748 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4745 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4749 if abort:
4746 if abort:
4750 state = cmdutil.getunfinishedstate(repo)
4747 state = cmdutil.getunfinishedstate(repo)
4751 if state and state._opname != b'merge':
4748 if state and state._opname != b'merge':
4752 raise error.Abort(
4749 raise error.Abort(
4753 _(b'cannot abort merge with %s in progress') % (state._opname),
4750 _(b'cannot abort merge with %s in progress') % (state._opname),
4754 hint=state.hint(),
4751 hint=state.hint(),
4755 )
4752 )
4756 if node:
4753 if node:
4757 raise error.Abort(_(b"cannot specify a node with --abort"))
4754 raise error.Abort(_(b"cannot specify a node with --abort"))
4758 return hg.abortmerge(repo.ui, repo)
4755 return hg.abortmerge(repo.ui, repo)
4759
4756
4760 if opts.get(b'rev') and node:
4757 if opts.get(b'rev') and node:
4761 raise error.Abort(_(b"please specify just one revision"))
4758 raise error.Abort(_(b"please specify just one revision"))
4762 if not node:
4759 if not node:
4763 node = opts.get(b'rev')
4760 node = opts.get(b'rev')
4764
4761
4765 if node:
4762 if node:
4766 ctx = scmutil.revsingle(repo, node)
4763 ctx = scmutil.revsingle(repo, node)
4767 else:
4764 else:
4768 if ui.configbool(b'commands', b'merge.require-rev'):
4765 if ui.configbool(b'commands', b'merge.require-rev'):
4769 raise error.Abort(
4766 raise error.Abort(
4770 _(
4767 _(
4771 b'configuration requires specifying revision to merge '
4768 b'configuration requires specifying revision to merge '
4772 b'with'
4769 b'with'
4773 )
4770 )
4774 )
4771 )
4775 ctx = repo[destutil.destmerge(repo)]
4772 ctx = repo[destutil.destmerge(repo)]
4776
4773
4777 if ctx.node() is None:
4774 if ctx.node() is None:
4778 raise error.Abort(_(b'merging with the working copy has no effect'))
4775 raise error.Abort(_(b'merging with the working copy has no effect'))
4779
4776
4780 if opts.get(b'preview'):
4777 if opts.get(b'preview'):
4781 # find nodes that are ancestors of p2 but not of p1
4778 # find nodes that are ancestors of p2 but not of p1
4782 p1 = repo[b'.'].node()
4779 p1 = repo[b'.'].node()
4783 p2 = ctx.node()
4780 p2 = ctx.node()
4784 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4781 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4785
4782
4786 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4783 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4787 for node in nodes:
4784 for node in nodes:
4788 displayer.show(repo[node])
4785 displayer.show(repo[node])
4789 displayer.close()
4786 displayer.close()
4790 return 0
4787 return 0
4791
4788
4792 # ui.forcemerge is an internal variable, do not document
4789 # ui.forcemerge is an internal variable, do not document
4793 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4790 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4794 with ui.configoverride(overrides, b'merge'):
4791 with ui.configoverride(overrides, b'merge'):
4795 force = opts.get(b'force')
4792 force = opts.get(b'force')
4796 labels = [b'working copy', b'merge rev']
4793 labels = [b'working copy', b'merge rev']
4797 return hg.merge(ctx, force=force, labels=labels)
4794 return hg.merge(ctx, force=force, labels=labels)
4798
4795
4799
4796
4800 statemod.addunfinished(
4797 statemod.addunfinished(
4801 b'merge',
4798 b'merge',
4802 fname=None,
4799 fname=None,
4803 clearable=True,
4800 clearable=True,
4804 allowcommit=True,
4801 allowcommit=True,
4805 cmdmsg=_(b'outstanding uncommitted merge'),
4802 cmdmsg=_(b'outstanding uncommitted merge'),
4806 abortfunc=hg.abortmerge,
4803 abortfunc=hg.abortmerge,
4807 statushint=_(
4804 statushint=_(
4808 b'To continue: hg commit\nTo abort: hg merge --abort'
4805 b'To continue: hg commit\nTo abort: hg merge --abort'
4809 ),
4806 ),
4810 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4807 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4811 )
4808 )
4812
4809
4813
4810
4814 @command(
4811 @command(
4815 b'outgoing|out',
4812 b'outgoing|out',
4816 [
4813 [
4817 (
4814 (
4818 b'f',
4815 b'f',
4819 b'force',
4816 b'force',
4820 None,
4817 None,
4821 _(b'run even when the destination is unrelated'),
4818 _(b'run even when the destination is unrelated'),
4822 ),
4819 ),
4823 (
4820 (
4824 b'r',
4821 b'r',
4825 b'rev',
4822 b'rev',
4826 [],
4823 [],
4827 _(b'a changeset intended to be included in the destination'),
4824 _(b'a changeset intended to be included in the destination'),
4828 _(b'REV'),
4825 _(b'REV'),
4829 ),
4826 ),
4830 (b'n', b'newest-first', None, _(b'show newest record first')),
4827 (b'n', b'newest-first', None, _(b'show newest record first')),
4831 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4828 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4832 (
4829 (
4833 b'b',
4830 b'b',
4834 b'branch',
4831 b'branch',
4835 [],
4832 [],
4836 _(b'a specific branch you would like to push'),
4833 _(b'a specific branch you would like to push'),
4837 _(b'BRANCH'),
4834 _(b'BRANCH'),
4838 ),
4835 ),
4839 ]
4836 ]
4840 + logopts
4837 + logopts
4841 + remoteopts
4838 + remoteopts
4842 + subrepoopts,
4839 + subrepoopts,
4843 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4840 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4844 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4841 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4845 )
4842 )
4846 def outgoing(ui, repo, dest=None, **opts):
4843 def outgoing(ui, repo, dest=None, **opts):
4847 """show changesets not found in the destination
4844 """show changesets not found in the destination
4848
4845
4849 Show changesets not found in the specified destination repository
4846 Show changesets not found in the specified destination repository
4850 or the default push location. These are the changesets that would
4847 or the default push location. These are the changesets that would
4851 be pushed if a push was requested.
4848 be pushed if a push was requested.
4852
4849
4853 See pull for details of valid destination formats.
4850 See pull for details of valid destination formats.
4854
4851
4855 .. container:: verbose
4852 .. container:: verbose
4856
4853
4857 With -B/--bookmarks, the result of bookmark comparison between
4854 With -B/--bookmarks, the result of bookmark comparison between
4858 local and remote repositories is displayed. With -v/--verbose,
4855 local and remote repositories is displayed. With -v/--verbose,
4859 status is also displayed for each bookmark like below::
4856 status is also displayed for each bookmark like below::
4860
4857
4861 BM1 01234567890a added
4858 BM1 01234567890a added
4862 BM2 deleted
4859 BM2 deleted
4863 BM3 234567890abc advanced
4860 BM3 234567890abc advanced
4864 BM4 34567890abcd diverged
4861 BM4 34567890abcd diverged
4865 BM5 4567890abcde changed
4862 BM5 4567890abcde changed
4866
4863
4867 The action taken when pushing depends on the
4864 The action taken when pushing depends on the
4868 status of each bookmark:
4865 status of each bookmark:
4869
4866
4870 :``added``: push with ``-B`` will create it
4867 :``added``: push with ``-B`` will create it
4871 :``deleted``: push with ``-B`` will delete it
4868 :``deleted``: push with ``-B`` will delete it
4872 :``advanced``: push will update it
4869 :``advanced``: push will update it
4873 :``diverged``: push with ``-B`` will update it
4870 :``diverged``: push with ``-B`` will update it
4874 :``changed``: push with ``-B`` will update it
4871 :``changed``: push with ``-B`` will update it
4875
4872
4876 From the point of view of pushing behavior, bookmarks
4873 From the point of view of pushing behavior, bookmarks
4877 existing only in the remote repository are treated as
4874 existing only in the remote repository are treated as
4878 ``deleted``, even if it is in fact added remotely.
4875 ``deleted``, even if it is in fact added remotely.
4879
4876
4880 Returns 0 if there are outgoing changes, 1 otherwise.
4877 Returns 0 if there are outgoing changes, 1 otherwise.
4881 """
4878 """
4882 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4879 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4883 # style URLs, so don't overwrite dest.
4880 # style URLs, so don't overwrite dest.
4884 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4881 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4885 if not path:
4882 if not path:
4886 raise error.Abort(
4883 raise error.Abort(
4887 _(b'default repository not configured!'),
4884 _(b'default repository not configured!'),
4888 hint=_(b"see 'hg help config.paths'"),
4885 hint=_(b"see 'hg help config.paths'"),
4889 )
4886 )
4890
4887
4891 opts = pycompat.byteskwargs(opts)
4888 opts = pycompat.byteskwargs(opts)
4892 if opts.get(b'graph'):
4889 if opts.get(b'graph'):
4893 logcmdutil.checkunsupportedgraphflags([], opts)
4890 logcmdutil.checkunsupportedgraphflags([], opts)
4894 o, other = hg._outgoing(ui, repo, dest, opts)
4891 o, other = hg._outgoing(ui, repo, dest, opts)
4895 if not o:
4892 if not o:
4896 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4893 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4897 return
4894 return
4898
4895
4899 revdag = logcmdutil.graphrevs(repo, o, opts)
4896 revdag = logcmdutil.graphrevs(repo, o, opts)
4900 ui.pager(b'outgoing')
4897 ui.pager(b'outgoing')
4901 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4898 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4902 logcmdutil.displaygraph(
4899 logcmdutil.displaygraph(
4903 ui, repo, revdag, displayer, graphmod.asciiedges
4900 ui, repo, revdag, displayer, graphmod.asciiedges
4904 )
4901 )
4905 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4902 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4906 return 0
4903 return 0
4907
4904
4908 if opts.get(b'bookmarks'):
4905 if opts.get(b'bookmarks'):
4909 dest = path.pushloc or path.loc
4906 dest = path.pushloc or path.loc
4910 other = hg.peer(repo, opts, dest)
4907 other = hg.peer(repo, opts, dest)
4911 if b'bookmarks' not in other.listkeys(b'namespaces'):
4908 if b'bookmarks' not in other.listkeys(b'namespaces'):
4912 ui.warn(_(b"remote doesn't support bookmarks\n"))
4909 ui.warn(_(b"remote doesn't support bookmarks\n"))
4913 return 0
4910 return 0
4914 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4911 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4915 ui.pager(b'outgoing')
4912 ui.pager(b'outgoing')
4916 return bookmarks.outgoing(ui, repo, other)
4913 return bookmarks.outgoing(ui, repo, other)
4917
4914
4918 repo._subtoppath = path.pushloc or path.loc
4915 repo._subtoppath = path.pushloc or path.loc
4919 try:
4916 try:
4920 return hg.outgoing(ui, repo, dest, opts)
4917 return hg.outgoing(ui, repo, dest, opts)
4921 finally:
4918 finally:
4922 del repo._subtoppath
4919 del repo._subtoppath
4923
4920
4924
4921
4925 @command(
4922 @command(
4926 b'parents',
4923 b'parents',
4927 [
4924 [
4928 (
4925 (
4929 b'r',
4926 b'r',
4930 b'rev',
4927 b'rev',
4931 b'',
4928 b'',
4932 _(b'show parents of the specified revision'),
4929 _(b'show parents of the specified revision'),
4933 _(b'REV'),
4930 _(b'REV'),
4934 ),
4931 ),
4935 ]
4932 ]
4936 + templateopts,
4933 + templateopts,
4937 _(b'[-r REV] [FILE]'),
4934 _(b'[-r REV] [FILE]'),
4938 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4935 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4939 inferrepo=True,
4936 inferrepo=True,
4940 )
4937 )
4941 def parents(ui, repo, file_=None, **opts):
4938 def parents(ui, repo, file_=None, **opts):
4942 """show the parents of the working directory or revision (DEPRECATED)
4939 """show the parents of the working directory or revision (DEPRECATED)
4943
4940
4944 Print the working directory's parent revisions. If a revision is
4941 Print the working directory's parent revisions. If a revision is
4945 given via -r/--rev, the parent of that revision will be printed.
4942 given via -r/--rev, the parent of that revision will be printed.
4946 If a file argument is given, the revision in which the file was
4943 If a file argument is given, the revision in which the file was
4947 last changed (before the working directory revision or the
4944 last changed (before the working directory revision or the
4948 argument to --rev if given) is printed.
4945 argument to --rev if given) is printed.
4949
4946
4950 This command is equivalent to::
4947 This command is equivalent to::
4951
4948
4952 hg log -r "p1()+p2()" or
4949 hg log -r "p1()+p2()" or
4953 hg log -r "p1(REV)+p2(REV)" or
4950 hg log -r "p1(REV)+p2(REV)" or
4954 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4951 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4955 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4952 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4956
4953
4957 See :hg:`summary` and :hg:`help revsets` for related information.
4954 See :hg:`summary` and :hg:`help revsets` for related information.
4958
4955
4959 Returns 0 on success.
4956 Returns 0 on success.
4960 """
4957 """
4961
4958
4962 opts = pycompat.byteskwargs(opts)
4959 opts = pycompat.byteskwargs(opts)
4963 rev = opts.get(b'rev')
4960 rev = opts.get(b'rev')
4964 if rev:
4961 if rev:
4965 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4962 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
4966 ctx = scmutil.revsingle(repo, rev, None)
4963 ctx = scmutil.revsingle(repo, rev, None)
4967
4964
4968 if file_:
4965 if file_:
4969 m = scmutil.match(ctx, (file_,), opts)
4966 m = scmutil.match(ctx, (file_,), opts)
4970 if m.anypats() or len(m.files()) != 1:
4967 if m.anypats() or len(m.files()) != 1:
4971 raise error.Abort(_(b'can only specify an explicit filename'))
4968 raise error.Abort(_(b'can only specify an explicit filename'))
4972 file_ = m.files()[0]
4969 file_ = m.files()[0]
4973 filenodes = []
4970 filenodes = []
4974 for cp in ctx.parents():
4971 for cp in ctx.parents():
4975 if not cp:
4972 if not cp:
4976 continue
4973 continue
4977 try:
4974 try:
4978 filenodes.append(cp.filenode(file_))
4975 filenodes.append(cp.filenode(file_))
4979 except error.LookupError:
4976 except error.LookupError:
4980 pass
4977 pass
4981 if not filenodes:
4978 if not filenodes:
4982 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
4979 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
4983 p = []
4980 p = []
4984 for fn in filenodes:
4981 for fn in filenodes:
4985 fctx = repo.filectx(file_, fileid=fn)
4982 fctx = repo.filectx(file_, fileid=fn)
4986 p.append(fctx.node())
4983 p.append(fctx.node())
4987 else:
4984 else:
4988 p = [cp.node() for cp in ctx.parents()]
4985 p = [cp.node() for cp in ctx.parents()]
4989
4986
4990 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4987 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4991 for n in p:
4988 for n in p:
4992 if n != nullid:
4989 if n != nullid:
4993 displayer.show(repo[n])
4990 displayer.show(repo[n])
4994 displayer.close()
4991 displayer.close()
4995
4992
4996
4993
4997 @command(
4994 @command(
4998 b'paths',
4995 b'paths',
4999 formatteropts,
4996 formatteropts,
5000 _(b'[NAME]'),
4997 _(b'[NAME]'),
5001 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4998 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5002 optionalrepo=True,
4999 optionalrepo=True,
5003 intents={INTENT_READONLY},
5000 intents={INTENT_READONLY},
5004 )
5001 )
5005 def paths(ui, repo, search=None, **opts):
5002 def paths(ui, repo, search=None, **opts):
5006 """show aliases for remote repositories
5003 """show aliases for remote repositories
5007
5004
5008 Show definition of symbolic path name NAME. If no name is given,
5005 Show definition of symbolic path name NAME. If no name is given,
5009 show definition of all available names.
5006 show definition of all available names.
5010
5007
5011 Option -q/--quiet suppresses all output when searching for NAME
5008 Option -q/--quiet suppresses all output when searching for NAME
5012 and shows only the path names when listing all definitions.
5009 and shows only the path names when listing all definitions.
5013
5010
5014 Path names are defined in the [paths] section of your
5011 Path names are defined in the [paths] section of your
5015 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5012 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5016 repository, ``.hg/hgrc`` is used, too.
5013 repository, ``.hg/hgrc`` is used, too.
5017
5014
5018 The path names ``default`` and ``default-push`` have a special
5015 The path names ``default`` and ``default-push`` have a special
5019 meaning. When performing a push or pull operation, they are used
5016 meaning. When performing a push or pull operation, they are used
5020 as fallbacks if no location is specified on the command-line.
5017 as fallbacks if no location is specified on the command-line.
5021 When ``default-push`` is set, it will be used for push and
5018 When ``default-push`` is set, it will be used for push and
5022 ``default`` will be used for pull; otherwise ``default`` is used
5019 ``default`` will be used for pull; otherwise ``default`` is used
5023 as the fallback for both. When cloning a repository, the clone
5020 as the fallback for both. When cloning a repository, the clone
5024 source is written as ``default`` in ``.hg/hgrc``.
5021 source is written as ``default`` in ``.hg/hgrc``.
5025
5022
5026 .. note::
5023 .. note::
5027
5024
5028 ``default`` and ``default-push`` apply to all inbound (e.g.
5025 ``default`` and ``default-push`` apply to all inbound (e.g.
5029 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5026 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5030 and :hg:`bundle`) operations.
5027 and :hg:`bundle`) operations.
5031
5028
5032 See :hg:`help urls` for more information.
5029 See :hg:`help urls` for more information.
5033
5030
5034 .. container:: verbose
5031 .. container:: verbose
5035
5032
5036 Template:
5033 Template:
5037
5034
5038 The following keywords are supported. See also :hg:`help templates`.
5035 The following keywords are supported. See also :hg:`help templates`.
5039
5036
5040 :name: String. Symbolic name of the path alias.
5037 :name: String. Symbolic name of the path alias.
5041 :pushurl: String. URL for push operations.
5038 :pushurl: String. URL for push operations.
5042 :url: String. URL or directory path for the other operations.
5039 :url: String. URL or directory path for the other operations.
5043
5040
5044 Returns 0 on success.
5041 Returns 0 on success.
5045 """
5042 """
5046
5043
5047 opts = pycompat.byteskwargs(opts)
5044 opts = pycompat.byteskwargs(opts)
5048 ui.pager(b'paths')
5045 ui.pager(b'paths')
5049 if search:
5046 if search:
5050 pathitems = [
5047 pathitems = [
5051 (name, path)
5048 (name, path)
5052 for name, path in pycompat.iteritems(ui.paths)
5049 for name, path in pycompat.iteritems(ui.paths)
5053 if name == search
5050 if name == search
5054 ]
5051 ]
5055 else:
5052 else:
5056 pathitems = sorted(pycompat.iteritems(ui.paths))
5053 pathitems = sorted(pycompat.iteritems(ui.paths))
5057
5054
5058 fm = ui.formatter(b'paths', opts)
5055 fm = ui.formatter(b'paths', opts)
5059 if fm.isplain():
5056 if fm.isplain():
5060 hidepassword = util.hidepassword
5057 hidepassword = util.hidepassword
5061 else:
5058 else:
5062 hidepassword = bytes
5059 hidepassword = bytes
5063 if ui.quiet:
5060 if ui.quiet:
5064 namefmt = b'%s\n'
5061 namefmt = b'%s\n'
5065 else:
5062 else:
5066 namefmt = b'%s = '
5063 namefmt = b'%s = '
5067 showsubopts = not search and not ui.quiet
5064 showsubopts = not search and not ui.quiet
5068
5065
5069 for name, path in pathitems:
5066 for name, path in pathitems:
5070 fm.startitem()
5067 fm.startitem()
5071 fm.condwrite(not search, b'name', namefmt, name)
5068 fm.condwrite(not search, b'name', namefmt, name)
5072 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5069 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5073 for subopt, value in sorted(path.suboptions.items()):
5070 for subopt, value in sorted(path.suboptions.items()):
5074 assert subopt not in (b'name', b'url')
5071 assert subopt not in (b'name', b'url')
5075 if showsubopts:
5072 if showsubopts:
5076 fm.plain(b'%s:%s = ' % (name, subopt))
5073 fm.plain(b'%s:%s = ' % (name, subopt))
5077 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5074 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5078
5075
5079 fm.end()
5076 fm.end()
5080
5077
5081 if search and not pathitems:
5078 if search and not pathitems:
5082 if not ui.quiet:
5079 if not ui.quiet:
5083 ui.warn(_(b"not found!\n"))
5080 ui.warn(_(b"not found!\n"))
5084 return 1
5081 return 1
5085 else:
5082 else:
5086 return 0
5083 return 0
5087
5084
5088
5085
5089 @command(
5086 @command(
5090 b'phase',
5087 b'phase',
5091 [
5088 [
5092 (b'p', b'public', False, _(b'set changeset phase to public')),
5089 (b'p', b'public', False, _(b'set changeset phase to public')),
5093 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5090 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5094 (b's', b'secret', False, _(b'set changeset phase to secret')),
5091 (b's', b'secret', False, _(b'set changeset phase to secret')),
5095 (b'f', b'force', False, _(b'allow to move boundary backward')),
5092 (b'f', b'force', False, _(b'allow to move boundary backward')),
5096 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5093 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5097 ],
5094 ],
5098 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5095 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5099 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5096 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5100 )
5097 )
5101 def phase(ui, repo, *revs, **opts):
5098 def phase(ui, repo, *revs, **opts):
5102 """set or show the current phase name
5099 """set or show the current phase name
5103
5100
5104 With no argument, show the phase name of the current revision(s).
5101 With no argument, show the phase name of the current revision(s).
5105
5102
5106 With one of -p/--public, -d/--draft or -s/--secret, change the
5103 With one of -p/--public, -d/--draft or -s/--secret, change the
5107 phase value of the specified revisions.
5104 phase value of the specified revisions.
5108
5105
5109 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5106 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5110 lower phase to a higher phase. Phases are ordered as follows::
5107 lower phase to a higher phase. Phases are ordered as follows::
5111
5108
5112 public < draft < secret
5109 public < draft < secret
5113
5110
5114 Returns 0 on success, 1 if some phases could not be changed.
5111 Returns 0 on success, 1 if some phases could not be changed.
5115
5112
5116 (For more information about the phases concept, see :hg:`help phases`.)
5113 (For more information about the phases concept, see :hg:`help phases`.)
5117 """
5114 """
5118 opts = pycompat.byteskwargs(opts)
5115 opts = pycompat.byteskwargs(opts)
5119 # search for a unique phase argument
5116 # search for a unique phase argument
5120 targetphase = None
5117 targetphase = None
5121 for idx, name in enumerate(phases.cmdphasenames):
5118 for idx, name in enumerate(phases.cmdphasenames):
5122 if opts[name]:
5119 if opts[name]:
5123 if targetphase is not None:
5120 if targetphase is not None:
5124 raise error.Abort(_(b'only one phase can be specified'))
5121 raise error.Abort(_(b'only one phase can be specified'))
5125 targetphase = idx
5122 targetphase = idx
5126
5123
5127 # look for specified revision
5124 # look for specified revision
5128 revs = list(revs)
5125 revs = list(revs)
5129 revs.extend(opts[b'rev'])
5126 revs.extend(opts[b'rev'])
5130 if not revs:
5127 if not revs:
5131 # display both parents as the second parent phase can influence
5128 # display both parents as the second parent phase can influence
5132 # the phase of a merge commit
5129 # the phase of a merge commit
5133 revs = [c.rev() for c in repo[None].parents()]
5130 revs = [c.rev() for c in repo[None].parents()]
5134
5131
5135 revs = scmutil.revrange(repo, revs)
5132 revs = scmutil.revrange(repo, revs)
5136
5133
5137 ret = 0
5134 ret = 0
5138 if targetphase is None:
5135 if targetphase is None:
5139 # display
5136 # display
5140 for r in revs:
5137 for r in revs:
5141 ctx = repo[r]
5138 ctx = repo[r]
5142 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5139 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5143 else:
5140 else:
5144 with repo.lock(), repo.transaction(b"phase") as tr:
5141 with repo.lock(), repo.transaction(b"phase") as tr:
5145 # set phase
5142 # set phase
5146 if not revs:
5143 if not revs:
5147 raise error.Abort(_(b'empty revision set'))
5144 raise error.Abort(_(b'empty revision set'))
5148 nodes = [repo[r].node() for r in revs]
5145 nodes = [repo[r].node() for r in revs]
5149 # moving revision from public to draft may hide them
5146 # moving revision from public to draft may hide them
5150 # We have to check result on an unfiltered repository
5147 # We have to check result on an unfiltered repository
5151 unfi = repo.unfiltered()
5148 unfi = repo.unfiltered()
5152 getphase = unfi._phasecache.phase
5149 getphase = unfi._phasecache.phase
5153 olddata = [getphase(unfi, r) for r in unfi]
5150 olddata = [getphase(unfi, r) for r in unfi]
5154 phases.advanceboundary(repo, tr, targetphase, nodes)
5151 phases.advanceboundary(repo, tr, targetphase, nodes)
5155 if opts[b'force']:
5152 if opts[b'force']:
5156 phases.retractboundary(repo, tr, targetphase, nodes)
5153 phases.retractboundary(repo, tr, targetphase, nodes)
5157 getphase = unfi._phasecache.phase
5154 getphase = unfi._phasecache.phase
5158 newdata = [getphase(unfi, r) for r in unfi]
5155 newdata = [getphase(unfi, r) for r in unfi]
5159 changes = sum(newdata[r] != olddata[r] for r in unfi)
5156 changes = sum(newdata[r] != olddata[r] for r in unfi)
5160 cl = unfi.changelog
5157 cl = unfi.changelog
5161 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5158 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5162 if rejected:
5159 if rejected:
5163 ui.warn(
5160 ui.warn(
5164 _(
5161 _(
5165 b'cannot move %i changesets to a higher '
5162 b'cannot move %i changesets to a higher '
5166 b'phase, use --force\n'
5163 b'phase, use --force\n'
5167 )
5164 )
5168 % len(rejected)
5165 % len(rejected)
5169 )
5166 )
5170 ret = 1
5167 ret = 1
5171 if changes:
5168 if changes:
5172 msg = _(b'phase changed for %i changesets\n') % changes
5169 msg = _(b'phase changed for %i changesets\n') % changes
5173 if ret:
5170 if ret:
5174 ui.status(msg)
5171 ui.status(msg)
5175 else:
5172 else:
5176 ui.note(msg)
5173 ui.note(msg)
5177 else:
5174 else:
5178 ui.warn(_(b'no phases changed\n'))
5175 ui.warn(_(b'no phases changed\n'))
5179 return ret
5176 return ret
5180
5177
5181
5178
5182 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5179 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5183 """Run after a changegroup has been added via pull/unbundle
5180 """Run after a changegroup has been added via pull/unbundle
5184
5181
5185 This takes arguments below:
5182 This takes arguments below:
5186
5183
5187 :modheads: change of heads by pull/unbundle
5184 :modheads: change of heads by pull/unbundle
5188 :optupdate: updating working directory is needed or not
5185 :optupdate: updating working directory is needed or not
5189 :checkout: update destination revision (or None to default destination)
5186 :checkout: update destination revision (or None to default destination)
5190 :brev: a name, which might be a bookmark to be activated after updating
5187 :brev: a name, which might be a bookmark to be activated after updating
5191 """
5188 """
5192 if modheads == 0:
5189 if modheads == 0:
5193 return
5190 return
5194 if optupdate:
5191 if optupdate:
5195 try:
5192 try:
5196 return hg.updatetotally(ui, repo, checkout, brev)
5193 return hg.updatetotally(ui, repo, checkout, brev)
5197 except error.UpdateAbort as inst:
5194 except error.UpdateAbort as inst:
5198 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5195 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5199 hint = inst.hint
5196 hint = inst.hint
5200 raise error.UpdateAbort(msg, hint=hint)
5197 raise error.UpdateAbort(msg, hint=hint)
5201 if modheads is not None and modheads > 1:
5198 if modheads is not None and modheads > 1:
5202 currentbranchheads = len(repo.branchheads())
5199 currentbranchheads = len(repo.branchheads())
5203 if currentbranchheads == modheads:
5200 if currentbranchheads == modheads:
5204 ui.status(
5201 ui.status(
5205 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5202 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5206 )
5203 )
5207 elif currentbranchheads > 1:
5204 elif currentbranchheads > 1:
5208 ui.status(
5205 ui.status(
5209 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5206 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5210 )
5207 )
5211 else:
5208 else:
5212 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5209 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5213 elif not ui.configbool(b'commands', b'update.requiredest'):
5210 elif not ui.configbool(b'commands', b'update.requiredest'):
5214 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5211 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5215
5212
5216
5213
5217 @command(
5214 @command(
5218 b'pull',
5215 b'pull',
5219 [
5216 [
5220 (
5217 (
5221 b'u',
5218 b'u',
5222 b'update',
5219 b'update',
5223 None,
5220 None,
5224 _(b'update to new branch head if new descendants were pulled'),
5221 _(b'update to new branch head if new descendants were pulled'),
5225 ),
5222 ),
5226 (
5223 (
5227 b'f',
5224 b'f',
5228 b'force',
5225 b'force',
5229 None,
5226 None,
5230 _(b'run even when remote repository is unrelated'),
5227 _(b'run even when remote repository is unrelated'),
5231 ),
5228 ),
5232 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5229 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5233 (
5230 (
5234 b'r',
5231 b'r',
5235 b'rev',
5232 b'rev',
5236 [],
5233 [],
5237 _(b'a remote changeset intended to be added'),
5234 _(b'a remote changeset intended to be added'),
5238 _(b'REV'),
5235 _(b'REV'),
5239 ),
5236 ),
5240 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5237 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5241 (
5238 (
5242 b'b',
5239 b'b',
5243 b'branch',
5240 b'branch',
5244 [],
5241 [],
5245 _(b'a specific branch you would like to pull'),
5242 _(b'a specific branch you would like to pull'),
5246 _(b'BRANCH'),
5243 _(b'BRANCH'),
5247 ),
5244 ),
5248 ]
5245 ]
5249 + remoteopts,
5246 + remoteopts,
5250 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5247 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5251 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5248 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5252 helpbasic=True,
5249 helpbasic=True,
5253 )
5250 )
5254 def pull(ui, repo, source=b"default", **opts):
5251 def pull(ui, repo, source=b"default", **opts):
5255 """pull changes from the specified source
5252 """pull changes from the specified source
5256
5253
5257 Pull changes from a remote repository to a local one.
5254 Pull changes from a remote repository to a local one.
5258
5255
5259 This finds all changes from the repository at the specified path
5256 This finds all changes from the repository at the specified path
5260 or URL and adds them to a local repository (the current one unless
5257 or URL and adds them to a local repository (the current one unless
5261 -R is specified). By default, this does not update the copy of the
5258 -R is specified). By default, this does not update the copy of the
5262 project in the working directory.
5259 project in the working directory.
5263
5260
5264 When cloning from servers that support it, Mercurial may fetch
5261 When cloning from servers that support it, Mercurial may fetch
5265 pre-generated data. When this is done, hooks operating on incoming
5262 pre-generated data. When this is done, hooks operating on incoming
5266 changesets and changegroups may fire more than once, once for each
5263 changesets and changegroups may fire more than once, once for each
5267 pre-generated bundle and as well as for any additional remaining
5264 pre-generated bundle and as well as for any additional remaining
5268 data. See :hg:`help -e clonebundles` for more.
5265 data. See :hg:`help -e clonebundles` for more.
5269
5266
5270 Use :hg:`incoming` if you want to see what would have been added
5267 Use :hg:`incoming` if you want to see what would have been added
5271 by a pull at the time you issued this command. If you then decide
5268 by a pull at the time you issued this command. If you then decide
5272 to add those changes to the repository, you should use :hg:`pull
5269 to add those changes to the repository, you should use :hg:`pull
5273 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5270 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5274
5271
5275 If SOURCE is omitted, the 'default' path will be used.
5272 If SOURCE is omitted, the 'default' path will be used.
5276 See :hg:`help urls` for more information.
5273 See :hg:`help urls` for more information.
5277
5274
5278 Specifying bookmark as ``.`` is equivalent to specifying the active
5275 Specifying bookmark as ``.`` is equivalent to specifying the active
5279 bookmark's name.
5276 bookmark's name.
5280
5277
5281 Returns 0 on success, 1 if an update had unresolved files.
5278 Returns 0 on success, 1 if an update had unresolved files.
5282 """
5279 """
5283
5280
5284 opts = pycompat.byteskwargs(opts)
5281 opts = pycompat.byteskwargs(opts)
5285 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5282 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5286 b'update'
5283 b'update'
5287 ):
5284 ):
5288 msg = _(b'update destination required by configuration')
5285 msg = _(b'update destination required by configuration')
5289 hint = _(b'use hg pull followed by hg update DEST')
5286 hint = _(b'use hg pull followed by hg update DEST')
5290 raise error.Abort(msg, hint=hint)
5287 raise error.Abort(msg, hint=hint)
5291
5288
5292 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5289 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5293 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5290 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5294 other = hg.peer(repo, opts, source)
5291 other = hg.peer(repo, opts, source)
5295 try:
5292 try:
5296 revs, checkout = hg.addbranchrevs(
5293 revs, checkout = hg.addbranchrevs(
5297 repo, other, branches, opts.get(b'rev')
5294 repo, other, branches, opts.get(b'rev')
5298 )
5295 )
5299
5296
5300 pullopargs = {}
5297 pullopargs = {}
5301
5298
5302 nodes = None
5299 nodes = None
5303 if opts.get(b'bookmark') or revs:
5300 if opts.get(b'bookmark') or revs:
5304 # The list of bookmark used here is the same used to actually update
5301 # The list of bookmark used here is the same used to actually update
5305 # the bookmark names, to avoid the race from issue 4689 and we do
5302 # the bookmark names, to avoid the race from issue 4689 and we do
5306 # all lookup and bookmark queries in one go so they see the same
5303 # all lookup and bookmark queries in one go so they see the same
5307 # version of the server state (issue 4700).
5304 # version of the server state (issue 4700).
5308 nodes = []
5305 nodes = []
5309 fnodes = []
5306 fnodes = []
5310 revs = revs or []
5307 revs = revs or []
5311 if revs and not other.capable(b'lookup'):
5308 if revs and not other.capable(b'lookup'):
5312 err = _(
5309 err = _(
5313 b"other repository doesn't support revision lookup, "
5310 b"other repository doesn't support revision lookup, "
5314 b"so a rev cannot be specified."
5311 b"so a rev cannot be specified."
5315 )
5312 )
5316 raise error.Abort(err)
5313 raise error.Abort(err)
5317 with other.commandexecutor() as e:
5314 with other.commandexecutor() as e:
5318 fremotebookmarks = e.callcommand(
5315 fremotebookmarks = e.callcommand(
5319 b'listkeys', {b'namespace': b'bookmarks'}
5316 b'listkeys', {b'namespace': b'bookmarks'}
5320 )
5317 )
5321 for r in revs:
5318 for r in revs:
5322 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5319 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5323 remotebookmarks = fremotebookmarks.result()
5320 remotebookmarks = fremotebookmarks.result()
5324 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5321 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5325 pullopargs[b'remotebookmarks'] = remotebookmarks
5322 pullopargs[b'remotebookmarks'] = remotebookmarks
5326 for b in opts.get(b'bookmark', []):
5323 for b in opts.get(b'bookmark', []):
5327 b = repo._bookmarks.expandname(b)
5324 b = repo._bookmarks.expandname(b)
5328 if b not in remotebookmarks:
5325 if b not in remotebookmarks:
5329 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5326 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5330 nodes.append(remotebookmarks[b])
5327 nodes.append(remotebookmarks[b])
5331 for i, rev in enumerate(revs):
5328 for i, rev in enumerate(revs):
5332 node = fnodes[i].result()
5329 node = fnodes[i].result()
5333 nodes.append(node)
5330 nodes.append(node)
5334 if rev == checkout:
5331 if rev == checkout:
5335 checkout = node
5332 checkout = node
5336
5333
5337 wlock = util.nullcontextmanager()
5334 wlock = util.nullcontextmanager()
5338 if opts.get(b'update'):
5335 if opts.get(b'update'):
5339 wlock = repo.wlock()
5336 wlock = repo.wlock()
5340 with wlock:
5337 with wlock:
5341 pullopargs.update(opts.get(b'opargs', {}))
5338 pullopargs.update(opts.get(b'opargs', {}))
5342 modheads = exchange.pull(
5339 modheads = exchange.pull(
5343 repo,
5340 repo,
5344 other,
5341 other,
5345 heads=nodes,
5342 heads=nodes,
5346 force=opts.get(b'force'),
5343 force=opts.get(b'force'),
5347 bookmarks=opts.get(b'bookmark', ()),
5344 bookmarks=opts.get(b'bookmark', ()),
5348 opargs=pullopargs,
5345 opargs=pullopargs,
5349 confirm=opts.get(b'confirm'),
5346 confirm=opts.get(b'confirm'),
5350 ).cgresult
5347 ).cgresult
5351
5348
5352 # brev is a name, which might be a bookmark to be activated at
5349 # brev is a name, which might be a bookmark to be activated at
5353 # the end of the update. In other words, it is an explicit
5350 # the end of the update. In other words, it is an explicit
5354 # destination of the update
5351 # destination of the update
5355 brev = None
5352 brev = None
5356
5353
5357 if checkout:
5354 if checkout:
5358 checkout = repo.unfiltered().changelog.rev(checkout)
5355 checkout = repo.unfiltered().changelog.rev(checkout)
5359
5356
5360 # order below depends on implementation of
5357 # order below depends on implementation of
5361 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5358 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5362 # because 'checkout' is determined without it.
5359 # because 'checkout' is determined without it.
5363 if opts.get(b'rev'):
5360 if opts.get(b'rev'):
5364 brev = opts[b'rev'][0]
5361 brev = opts[b'rev'][0]
5365 elif opts.get(b'branch'):
5362 elif opts.get(b'branch'):
5366 brev = opts[b'branch'][0]
5363 brev = opts[b'branch'][0]
5367 else:
5364 else:
5368 brev = branches[0]
5365 brev = branches[0]
5369 repo._subtoppath = source
5366 repo._subtoppath = source
5370 try:
5367 try:
5371 ret = postincoming(
5368 ret = postincoming(
5372 ui, repo, modheads, opts.get(b'update'), checkout, brev
5369 ui, repo, modheads, opts.get(b'update'), checkout, brev
5373 )
5370 )
5374 except error.FilteredRepoLookupError as exc:
5371 except error.FilteredRepoLookupError as exc:
5375 msg = _(b'cannot update to target: %s') % exc.args[0]
5372 msg = _(b'cannot update to target: %s') % exc.args[0]
5376 exc.args = (msg,) + exc.args[1:]
5373 exc.args = (msg,) + exc.args[1:]
5377 raise
5374 raise
5378 finally:
5375 finally:
5379 del repo._subtoppath
5376 del repo._subtoppath
5380
5377
5381 finally:
5378 finally:
5382 other.close()
5379 other.close()
5383 return ret
5380 return ret
5384
5381
5385
5382
5386 @command(
5383 @command(
5387 b'push',
5384 b'push',
5388 [
5385 [
5389 (b'f', b'force', None, _(b'force push')),
5386 (b'f', b'force', None, _(b'force push')),
5390 (
5387 (
5391 b'r',
5388 b'r',
5392 b'rev',
5389 b'rev',
5393 [],
5390 [],
5394 _(b'a changeset intended to be included in the destination'),
5391 _(b'a changeset intended to be included in the destination'),
5395 _(b'REV'),
5392 _(b'REV'),
5396 ),
5393 ),
5397 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5394 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5398 (
5395 (
5399 b'b',
5396 b'b',
5400 b'branch',
5397 b'branch',
5401 [],
5398 [],
5402 _(b'a specific branch you would like to push'),
5399 _(b'a specific branch you would like to push'),
5403 _(b'BRANCH'),
5400 _(b'BRANCH'),
5404 ),
5401 ),
5405 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5402 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5406 (
5403 (
5407 b'',
5404 b'',
5408 b'pushvars',
5405 b'pushvars',
5409 [],
5406 [],
5410 _(b'variables that can be sent to server (ADVANCED)'),
5407 _(b'variables that can be sent to server (ADVANCED)'),
5411 ),
5408 ),
5412 (
5409 (
5413 b'',
5410 b'',
5414 b'publish',
5411 b'publish',
5415 False,
5412 False,
5416 _(b'push the changeset as public (EXPERIMENTAL)'),
5413 _(b'push the changeset as public (EXPERIMENTAL)'),
5417 ),
5414 ),
5418 ]
5415 ]
5419 + remoteopts,
5416 + remoteopts,
5420 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5417 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5421 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5418 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5422 helpbasic=True,
5419 helpbasic=True,
5423 )
5420 )
5424 def push(ui, repo, dest=None, **opts):
5421 def push(ui, repo, dest=None, **opts):
5425 """push changes to the specified destination
5422 """push changes to the specified destination
5426
5423
5427 Push changesets from the local repository to the specified
5424 Push changesets from the local repository to the specified
5428 destination.
5425 destination.
5429
5426
5430 This operation is symmetrical to pull: it is identical to a pull
5427 This operation is symmetrical to pull: it is identical to a pull
5431 in the destination repository from the current one.
5428 in the destination repository from the current one.
5432
5429
5433 By default, push will not allow creation of new heads at the
5430 By default, push will not allow creation of new heads at the
5434 destination, since multiple heads would make it unclear which head
5431 destination, since multiple heads would make it unclear which head
5435 to use. In this situation, it is recommended to pull and merge
5432 to use. In this situation, it is recommended to pull and merge
5436 before pushing.
5433 before pushing.
5437
5434
5438 Use --new-branch if you want to allow push to create a new named
5435 Use --new-branch if you want to allow push to create a new named
5439 branch that is not present at the destination. This allows you to
5436 branch that is not present at the destination. This allows you to
5440 only create a new branch without forcing other changes.
5437 only create a new branch without forcing other changes.
5441
5438
5442 .. note::
5439 .. note::
5443
5440
5444 Extra care should be taken with the -f/--force option,
5441 Extra care should be taken with the -f/--force option,
5445 which will push all new heads on all branches, an action which will
5442 which will push all new heads on all branches, an action which will
5446 almost always cause confusion for collaborators.
5443 almost always cause confusion for collaborators.
5447
5444
5448 If -r/--rev is used, the specified revision and all its ancestors
5445 If -r/--rev is used, the specified revision and all its ancestors
5449 will be pushed to the remote repository.
5446 will be pushed to the remote repository.
5450
5447
5451 If -B/--bookmark is used, the specified bookmarked revision, its
5448 If -B/--bookmark is used, the specified bookmarked revision, its
5452 ancestors, and the bookmark will be pushed to the remote
5449 ancestors, and the bookmark will be pushed to the remote
5453 repository. Specifying ``.`` is equivalent to specifying the active
5450 repository. Specifying ``.`` is equivalent to specifying the active
5454 bookmark's name.
5451 bookmark's name.
5455
5452
5456 Please see :hg:`help urls` for important details about ``ssh://``
5453 Please see :hg:`help urls` for important details about ``ssh://``
5457 URLs. If DESTINATION is omitted, a default path will be used.
5454 URLs. If DESTINATION is omitted, a default path will be used.
5458
5455
5459 .. container:: verbose
5456 .. container:: verbose
5460
5457
5461 The --pushvars option sends strings to the server that become
5458 The --pushvars option sends strings to the server that become
5462 environment variables prepended with ``HG_USERVAR_``. For example,
5459 environment variables prepended with ``HG_USERVAR_``. For example,
5463 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5460 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5464 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5461 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5465
5462
5466 pushvars can provide for user-overridable hooks as well as set debug
5463 pushvars can provide for user-overridable hooks as well as set debug
5467 levels. One example is having a hook that blocks commits containing
5464 levels. One example is having a hook that blocks commits containing
5468 conflict markers, but enables the user to override the hook if the file
5465 conflict markers, but enables the user to override the hook if the file
5469 is using conflict markers for testing purposes or the file format has
5466 is using conflict markers for testing purposes or the file format has
5470 strings that look like conflict markers.
5467 strings that look like conflict markers.
5471
5468
5472 By default, servers will ignore `--pushvars`. To enable it add the
5469 By default, servers will ignore `--pushvars`. To enable it add the
5473 following to your configuration file::
5470 following to your configuration file::
5474
5471
5475 [push]
5472 [push]
5476 pushvars.server = true
5473 pushvars.server = true
5477
5474
5478 Returns 0 if push was successful, 1 if nothing to push.
5475 Returns 0 if push was successful, 1 if nothing to push.
5479 """
5476 """
5480
5477
5481 opts = pycompat.byteskwargs(opts)
5478 opts = pycompat.byteskwargs(opts)
5482 if opts.get(b'bookmark'):
5479 if opts.get(b'bookmark'):
5483 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5480 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5484 for b in opts[b'bookmark']:
5481 for b in opts[b'bookmark']:
5485 # translate -B options to -r so changesets get pushed
5482 # translate -B options to -r so changesets get pushed
5486 b = repo._bookmarks.expandname(b)
5483 b = repo._bookmarks.expandname(b)
5487 if b in repo._bookmarks:
5484 if b in repo._bookmarks:
5488 opts.setdefault(b'rev', []).append(b)
5485 opts.setdefault(b'rev', []).append(b)
5489 else:
5486 else:
5490 # if we try to push a deleted bookmark, translate it to null
5487 # if we try to push a deleted bookmark, translate it to null
5491 # this lets simultaneous -r, -b options continue working
5488 # this lets simultaneous -r, -b options continue working
5492 opts.setdefault(b'rev', []).append(b"null")
5489 opts.setdefault(b'rev', []).append(b"null")
5493
5490
5494 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5491 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5495 if not path:
5492 if not path:
5496 raise error.Abort(
5493 raise error.Abort(
5497 _(b'default repository not configured!'),
5494 _(b'default repository not configured!'),
5498 hint=_(b"see 'hg help config.paths'"),
5495 hint=_(b"see 'hg help config.paths'"),
5499 )
5496 )
5500 dest = path.pushloc or path.loc
5497 dest = path.pushloc or path.loc
5501 branches = (path.branch, opts.get(b'branch') or [])
5498 branches = (path.branch, opts.get(b'branch') or [])
5502 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5499 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5503 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5500 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5504 other = hg.peer(repo, opts, dest)
5501 other = hg.peer(repo, opts, dest)
5505
5502
5506 if revs:
5503 if revs:
5507 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5504 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5508 if not revs:
5505 if not revs:
5509 raise error.Abort(
5506 raise error.Abort(
5510 _(b"specified revisions evaluate to an empty set"),
5507 _(b"specified revisions evaluate to an empty set"),
5511 hint=_(b"use different revision arguments"),
5508 hint=_(b"use different revision arguments"),
5512 )
5509 )
5513 elif path.pushrev:
5510 elif path.pushrev:
5514 # It doesn't make any sense to specify ancestor revisions. So limit
5511 # It doesn't make any sense to specify ancestor revisions. So limit
5515 # to DAG heads to make discovery simpler.
5512 # to DAG heads to make discovery simpler.
5516 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5513 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5517 revs = scmutil.revrange(repo, [expr])
5514 revs = scmutil.revrange(repo, [expr])
5518 revs = [repo[rev].node() for rev in revs]
5515 revs = [repo[rev].node() for rev in revs]
5519 if not revs:
5516 if not revs:
5520 raise error.Abort(
5517 raise error.Abort(
5521 _(b'default push revset for path evaluates to an empty set')
5518 _(b'default push revset for path evaluates to an empty set')
5522 )
5519 )
5523 elif ui.configbool(b'commands', b'push.require-revs'):
5520 elif ui.configbool(b'commands', b'push.require-revs'):
5524 raise error.Abort(
5521 raise error.Abort(
5525 _(b'no revisions specified to push'),
5522 _(b'no revisions specified to push'),
5526 hint=_(b'did you mean "hg push -r ."?'),
5523 hint=_(b'did you mean "hg push -r ."?'),
5527 )
5524 )
5528
5525
5529 repo._subtoppath = dest
5526 repo._subtoppath = dest
5530 try:
5527 try:
5531 # push subrepos depth-first for coherent ordering
5528 # push subrepos depth-first for coherent ordering
5532 c = repo[b'.']
5529 c = repo[b'.']
5533 subs = c.substate # only repos that are committed
5530 subs = c.substate # only repos that are committed
5534 for s in sorted(subs):
5531 for s in sorted(subs):
5535 result = c.sub(s).push(opts)
5532 result = c.sub(s).push(opts)
5536 if result == 0:
5533 if result == 0:
5537 return not result
5534 return not result
5538 finally:
5535 finally:
5539 del repo._subtoppath
5536 del repo._subtoppath
5540
5537
5541 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5538 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5542 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5539 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5543
5540
5544 pushop = exchange.push(
5541 pushop = exchange.push(
5545 repo,
5542 repo,
5546 other,
5543 other,
5547 opts.get(b'force'),
5544 opts.get(b'force'),
5548 revs=revs,
5545 revs=revs,
5549 newbranch=opts.get(b'new_branch'),
5546 newbranch=opts.get(b'new_branch'),
5550 bookmarks=opts.get(b'bookmark', ()),
5547 bookmarks=opts.get(b'bookmark', ()),
5551 publish=opts.get(b'publish'),
5548 publish=opts.get(b'publish'),
5552 opargs=opargs,
5549 opargs=opargs,
5553 )
5550 )
5554
5551
5555 result = not pushop.cgresult
5552 result = not pushop.cgresult
5556
5553
5557 if pushop.bkresult is not None:
5554 if pushop.bkresult is not None:
5558 if pushop.bkresult == 2:
5555 if pushop.bkresult == 2:
5559 result = 2
5556 result = 2
5560 elif not result and pushop.bkresult:
5557 elif not result and pushop.bkresult:
5561 result = 2
5558 result = 2
5562
5559
5563 return result
5560 return result
5564
5561
5565
5562
5566 @command(
5563 @command(
5567 b'recover',
5564 b'recover',
5568 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5565 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5569 helpcategory=command.CATEGORY_MAINTENANCE,
5566 helpcategory=command.CATEGORY_MAINTENANCE,
5570 )
5567 )
5571 def recover(ui, repo, **opts):
5568 def recover(ui, repo, **opts):
5572 """roll back an interrupted transaction
5569 """roll back an interrupted transaction
5573
5570
5574 Recover from an interrupted commit or pull.
5571 Recover from an interrupted commit or pull.
5575
5572
5576 This command tries to fix the repository status after an
5573 This command tries to fix the repository status after an
5577 interrupted operation. It should only be necessary when Mercurial
5574 interrupted operation. It should only be necessary when Mercurial
5578 suggests it.
5575 suggests it.
5579
5576
5580 Returns 0 if successful, 1 if nothing to recover or verify fails.
5577 Returns 0 if successful, 1 if nothing to recover or verify fails.
5581 """
5578 """
5582 ret = repo.recover()
5579 ret = repo.recover()
5583 if ret:
5580 if ret:
5584 if opts['verify']:
5581 if opts['verify']:
5585 return hg.verify(repo)
5582 return hg.verify(repo)
5586 else:
5583 else:
5587 msg = _(
5584 msg = _(
5588 b"(verify step skipped, run `hg verify` to check your "
5585 b"(verify step skipped, run `hg verify` to check your "
5589 b"repository content)\n"
5586 b"repository content)\n"
5590 )
5587 )
5591 ui.warn(msg)
5588 ui.warn(msg)
5592 return 0
5589 return 0
5593 return 1
5590 return 1
5594
5591
5595
5592
5596 @command(
5593 @command(
5597 b'remove|rm',
5594 b'remove|rm',
5598 [
5595 [
5599 (b'A', b'after', None, _(b'record delete for missing files')),
5596 (b'A', b'after', None, _(b'record delete for missing files')),
5600 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5597 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5601 ]
5598 ]
5602 + subrepoopts
5599 + subrepoopts
5603 + walkopts
5600 + walkopts
5604 + dryrunopts,
5601 + dryrunopts,
5605 _(b'[OPTION]... FILE...'),
5602 _(b'[OPTION]... FILE...'),
5606 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5603 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5607 helpbasic=True,
5604 helpbasic=True,
5608 inferrepo=True,
5605 inferrepo=True,
5609 )
5606 )
5610 def remove(ui, repo, *pats, **opts):
5607 def remove(ui, repo, *pats, **opts):
5611 """remove the specified files on the next commit
5608 """remove the specified files on the next commit
5612
5609
5613 Schedule the indicated files for removal from the current branch.
5610 Schedule the indicated files for removal from the current branch.
5614
5611
5615 This command schedules the files to be removed at the next commit.
5612 This command schedules the files to be removed at the next commit.
5616 To undo a remove before that, see :hg:`revert`. To undo added
5613 To undo a remove before that, see :hg:`revert`. To undo added
5617 files, see :hg:`forget`.
5614 files, see :hg:`forget`.
5618
5615
5619 .. container:: verbose
5616 .. container:: verbose
5620
5617
5621 -A/--after can be used to remove only files that have already
5618 -A/--after can be used to remove only files that have already
5622 been deleted, -f/--force can be used to force deletion, and -Af
5619 been deleted, -f/--force can be used to force deletion, and -Af
5623 can be used to remove files from the next revision without
5620 can be used to remove files from the next revision without
5624 deleting them from the working directory.
5621 deleting them from the working directory.
5625
5622
5626 The following table details the behavior of remove for different
5623 The following table details the behavior of remove for different
5627 file states (columns) and option combinations (rows). The file
5624 file states (columns) and option combinations (rows). The file
5628 states are Added [A], Clean [C], Modified [M] and Missing [!]
5625 states are Added [A], Clean [C], Modified [M] and Missing [!]
5629 (as reported by :hg:`status`). The actions are Warn, Remove
5626 (as reported by :hg:`status`). The actions are Warn, Remove
5630 (from branch) and Delete (from disk):
5627 (from branch) and Delete (from disk):
5631
5628
5632 ========= == == == ==
5629 ========= == == == ==
5633 opt/state A C M !
5630 opt/state A C M !
5634 ========= == == == ==
5631 ========= == == == ==
5635 none W RD W R
5632 none W RD W R
5636 -f R RD RD R
5633 -f R RD RD R
5637 -A W W W R
5634 -A W W W R
5638 -Af R R R R
5635 -Af R R R R
5639 ========= == == == ==
5636 ========= == == == ==
5640
5637
5641 .. note::
5638 .. note::
5642
5639
5643 :hg:`remove` never deletes files in Added [A] state from the
5640 :hg:`remove` never deletes files in Added [A] state from the
5644 working directory, not even if ``--force`` is specified.
5641 working directory, not even if ``--force`` is specified.
5645
5642
5646 Returns 0 on success, 1 if any warnings encountered.
5643 Returns 0 on success, 1 if any warnings encountered.
5647 """
5644 """
5648
5645
5649 opts = pycompat.byteskwargs(opts)
5646 opts = pycompat.byteskwargs(opts)
5650 after, force = opts.get(b'after'), opts.get(b'force')
5647 after, force = opts.get(b'after'), opts.get(b'force')
5651 dryrun = opts.get(b'dry_run')
5648 dryrun = opts.get(b'dry_run')
5652 if not pats and not after:
5649 if not pats and not after:
5653 raise error.Abort(_(b'no files specified'))
5650 raise error.Abort(_(b'no files specified'))
5654
5651
5655 m = scmutil.match(repo[None], pats, opts)
5652 m = scmutil.match(repo[None], pats, opts)
5656 subrepos = opts.get(b'subrepos')
5653 subrepos = opts.get(b'subrepos')
5657 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5654 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5658 return cmdutil.remove(
5655 return cmdutil.remove(
5659 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5656 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5660 )
5657 )
5661
5658
5662
5659
5663 @command(
5660 @command(
5664 b'rename|move|mv',
5661 b'rename|move|mv',
5665 [
5662 [
5666 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5663 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5667 (
5664 (
5668 b'',
5665 b'',
5669 b'at-rev',
5666 b'at-rev',
5670 b'',
5667 b'',
5671 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5668 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5672 _(b'REV'),
5669 _(b'REV'),
5673 ),
5670 ),
5674 (
5671 (
5675 b'f',
5672 b'f',
5676 b'force',
5673 b'force',
5677 None,
5674 None,
5678 _(b'forcibly move over an existing managed file'),
5675 _(b'forcibly move over an existing managed file'),
5679 ),
5676 ),
5680 ]
5677 ]
5681 + walkopts
5678 + walkopts
5682 + dryrunopts,
5679 + dryrunopts,
5683 _(b'[OPTION]... SOURCE... DEST'),
5680 _(b'[OPTION]... SOURCE... DEST'),
5684 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5681 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5685 )
5682 )
5686 def rename(ui, repo, *pats, **opts):
5683 def rename(ui, repo, *pats, **opts):
5687 """rename files; equivalent of copy + remove
5684 """rename files; equivalent of copy + remove
5688
5685
5689 Mark dest as copies of sources; mark sources for deletion. If dest
5686 Mark dest as copies of sources; mark sources for deletion. If dest
5690 is a directory, copies are put in that directory. If dest is a
5687 is a directory, copies are put in that directory. If dest is a
5691 file, there can only be one source.
5688 file, there can only be one source.
5692
5689
5693 By default, this command copies the contents of files as they
5690 By default, this command copies the contents of files as they
5694 exist in the working directory. If invoked with -A/--after, the
5691 exist in the working directory. If invoked with -A/--after, the
5695 operation is recorded, but no copying is performed.
5692 operation is recorded, but no copying is performed.
5696
5693
5697 This command takes effect at the next commit. To undo a rename
5694 This command takes effect at the next commit. To undo a rename
5698 before that, see :hg:`revert`.
5695 before that, see :hg:`revert`.
5699
5696
5700 Returns 0 on success, 1 if errors are encountered.
5697 Returns 0 on success, 1 if errors are encountered.
5701 """
5698 """
5702 opts = pycompat.byteskwargs(opts)
5699 opts = pycompat.byteskwargs(opts)
5703 with repo.wlock():
5700 with repo.wlock():
5704 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5701 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5705
5702
5706
5703
5707 @command(
5704 @command(
5708 b'resolve',
5705 b'resolve',
5709 [
5706 [
5710 (b'a', b'all', None, _(b'select all unresolved files')),
5707 (b'a', b'all', None, _(b'select all unresolved files')),
5711 (b'l', b'list', None, _(b'list state of files needing merge')),
5708 (b'l', b'list', None, _(b'list state of files needing merge')),
5712 (b'm', b'mark', None, _(b'mark files as resolved')),
5709 (b'm', b'mark', None, _(b'mark files as resolved')),
5713 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5710 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5714 (b'n', b'no-status', None, _(b'hide status prefix')),
5711 (b'n', b'no-status', None, _(b'hide status prefix')),
5715 (b'', b're-merge', None, _(b're-merge files')),
5712 (b'', b're-merge', None, _(b're-merge files')),
5716 ]
5713 ]
5717 + mergetoolopts
5714 + mergetoolopts
5718 + walkopts
5715 + walkopts
5719 + formatteropts,
5716 + formatteropts,
5720 _(b'[OPTION]... [FILE]...'),
5717 _(b'[OPTION]... [FILE]...'),
5721 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5718 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5722 inferrepo=True,
5719 inferrepo=True,
5723 )
5720 )
5724 def resolve(ui, repo, *pats, **opts):
5721 def resolve(ui, repo, *pats, **opts):
5725 """redo merges or set/view the merge status of files
5722 """redo merges or set/view the merge status of files
5726
5723
5727 Merges with unresolved conflicts are often the result of
5724 Merges with unresolved conflicts are often the result of
5728 non-interactive merging using the ``internal:merge`` configuration
5725 non-interactive merging using the ``internal:merge`` configuration
5729 setting, or a command-line merge tool like ``diff3``. The resolve
5726 setting, or a command-line merge tool like ``diff3``. The resolve
5730 command is used to manage the files involved in a merge, after
5727 command is used to manage the files involved in a merge, after
5731 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5728 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5732 working directory must have two parents). See :hg:`help
5729 working directory must have two parents). See :hg:`help
5733 merge-tools` for information on configuring merge tools.
5730 merge-tools` for information on configuring merge tools.
5734
5731
5735 The resolve command can be used in the following ways:
5732 The resolve command can be used in the following ways:
5736
5733
5737 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5734 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5738 the specified files, discarding any previous merge attempts. Re-merging
5735 the specified files, discarding any previous merge attempts. Re-merging
5739 is not performed for files already marked as resolved. Use ``--all/-a``
5736 is not performed for files already marked as resolved. Use ``--all/-a``
5740 to select all unresolved files. ``--tool`` can be used to specify
5737 to select all unresolved files. ``--tool`` can be used to specify
5741 the merge tool used for the given files. It overrides the HGMERGE
5738 the merge tool used for the given files. It overrides the HGMERGE
5742 environment variable and your configuration files. Previous file
5739 environment variable and your configuration files. Previous file
5743 contents are saved with a ``.orig`` suffix.
5740 contents are saved with a ``.orig`` suffix.
5744
5741
5745 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5742 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5746 (e.g. after having manually fixed-up the files). The default is
5743 (e.g. after having manually fixed-up the files). The default is
5747 to mark all unresolved files.
5744 to mark all unresolved files.
5748
5745
5749 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5746 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5750 default is to mark all resolved files.
5747 default is to mark all resolved files.
5751
5748
5752 - :hg:`resolve -l`: list files which had or still have conflicts.
5749 - :hg:`resolve -l`: list files which had or still have conflicts.
5753 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5750 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5754 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5751 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5755 the list. See :hg:`help filesets` for details.
5752 the list. See :hg:`help filesets` for details.
5756
5753
5757 .. note::
5754 .. note::
5758
5755
5759 Mercurial will not let you commit files with unresolved merge
5756 Mercurial will not let you commit files with unresolved merge
5760 conflicts. You must use :hg:`resolve -m ...` before you can
5757 conflicts. You must use :hg:`resolve -m ...` before you can
5761 commit after a conflicting merge.
5758 commit after a conflicting merge.
5762
5759
5763 .. container:: verbose
5760 .. container:: verbose
5764
5761
5765 Template:
5762 Template:
5766
5763
5767 The following keywords are supported in addition to the common template
5764 The following keywords are supported in addition to the common template
5768 keywords and functions. See also :hg:`help templates`.
5765 keywords and functions. See also :hg:`help templates`.
5769
5766
5770 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5767 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5771 :path: String. Repository-absolute path of the file.
5768 :path: String. Repository-absolute path of the file.
5772
5769
5773 Returns 0 on success, 1 if any files fail a resolve attempt.
5770 Returns 0 on success, 1 if any files fail a resolve attempt.
5774 """
5771 """
5775
5772
5776 opts = pycompat.byteskwargs(opts)
5773 opts = pycompat.byteskwargs(opts)
5777 confirm = ui.configbool(b'commands', b'resolve.confirm')
5774 confirm = ui.configbool(b'commands', b'resolve.confirm')
5778 flaglist = b'all mark unmark list no_status re_merge'.split()
5775 flaglist = b'all mark unmark list no_status re_merge'.split()
5779 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5776 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5780
5777
5781 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5778 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5782 if actioncount > 1:
5779 if actioncount > 1:
5783 raise error.Abort(_(b"too many actions specified"))
5780 raise error.Abort(_(b"too many actions specified"))
5784 elif actioncount == 0 and ui.configbool(
5781 elif actioncount == 0 and ui.configbool(
5785 b'commands', b'resolve.explicit-re-merge'
5782 b'commands', b'resolve.explicit-re-merge'
5786 ):
5783 ):
5787 hint = _(b'use --mark, --unmark, --list or --re-merge')
5784 hint = _(b'use --mark, --unmark, --list or --re-merge')
5788 raise error.Abort(_(b'no action specified'), hint=hint)
5785 raise error.Abort(_(b'no action specified'), hint=hint)
5789 if pats and all:
5786 if pats and all:
5790 raise error.Abort(_(b"can't specify --all and patterns"))
5787 raise error.Abort(_(b"can't specify --all and patterns"))
5791 if not (all or pats or show or mark or unmark):
5788 if not (all or pats or show or mark or unmark):
5792 raise error.Abort(
5789 raise error.Abort(
5793 _(b'no files or directories specified'),
5790 _(b'no files or directories specified'),
5794 hint=b'use --all to re-merge all unresolved files',
5791 hint=b'use --all to re-merge all unresolved files',
5795 )
5792 )
5796
5793
5797 if confirm:
5794 if confirm:
5798 if all:
5795 if all:
5799 if ui.promptchoice(
5796 if ui.promptchoice(
5800 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5797 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5801 ):
5798 ):
5802 raise error.Abort(_(b'user quit'))
5799 raise error.Abort(_(b'user quit'))
5803 if mark and not pats:
5800 if mark and not pats:
5804 if ui.promptchoice(
5801 if ui.promptchoice(
5805 _(
5802 _(
5806 b'mark all unresolved files as resolved (yn)?'
5803 b'mark all unresolved files as resolved (yn)?'
5807 b'$$ &Yes $$ &No'
5804 b'$$ &Yes $$ &No'
5808 )
5805 )
5809 ):
5806 ):
5810 raise error.Abort(_(b'user quit'))
5807 raise error.Abort(_(b'user quit'))
5811 if unmark and not pats:
5808 if unmark and not pats:
5812 if ui.promptchoice(
5809 if ui.promptchoice(
5813 _(
5810 _(
5814 b'mark all resolved files as unresolved (yn)?'
5811 b'mark all resolved files as unresolved (yn)?'
5815 b'$$ &Yes $$ &No'
5812 b'$$ &Yes $$ &No'
5816 )
5813 )
5817 ):
5814 ):
5818 raise error.Abort(_(b'user quit'))
5815 raise error.Abort(_(b'user quit'))
5819
5816
5820 uipathfn = scmutil.getuipathfn(repo)
5817 uipathfn = scmutil.getuipathfn(repo)
5821
5818
5822 if show:
5819 if show:
5823 ui.pager(b'resolve')
5820 ui.pager(b'resolve')
5824 fm = ui.formatter(b'resolve', opts)
5821 fm = ui.formatter(b'resolve', opts)
5825 ms = mergestatemod.mergestate.read(repo)
5822 ms = mergestatemod.mergestate.read(repo)
5826 wctx = repo[None]
5823 wctx = repo[None]
5827 m = scmutil.match(wctx, pats, opts)
5824 m = scmutil.match(wctx, pats, opts)
5828
5825
5829 # Labels and keys based on merge state. Unresolved path conflicts show
5826 # Labels and keys based on merge state. Unresolved path conflicts show
5830 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5827 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5831 # resolved conflicts.
5828 # resolved conflicts.
5832 mergestateinfo = {
5829 mergestateinfo = {
5833 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5830 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5834 b'resolve.unresolved',
5831 b'resolve.unresolved',
5835 b'U',
5832 b'U',
5836 ),
5833 ),
5837 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5834 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5838 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5835 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5839 b'resolve.unresolved',
5836 b'resolve.unresolved',
5840 b'P',
5837 b'P',
5841 ),
5838 ),
5842 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5839 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5843 b'resolve.resolved',
5840 b'resolve.resolved',
5844 b'R',
5841 b'R',
5845 ),
5842 ),
5846 }
5843 }
5847
5844
5848 for f in ms:
5845 for f in ms:
5849 if not m(f):
5846 if not m(f):
5850 continue
5847 continue
5851
5848
5852 label, key = mergestateinfo[ms[f]]
5849 label, key = mergestateinfo[ms[f]]
5853 fm.startitem()
5850 fm.startitem()
5854 fm.context(ctx=wctx)
5851 fm.context(ctx=wctx)
5855 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5852 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5856 fm.data(path=f)
5853 fm.data(path=f)
5857 fm.plain(b'%s\n' % uipathfn(f), label=label)
5854 fm.plain(b'%s\n' % uipathfn(f), label=label)
5858 fm.end()
5855 fm.end()
5859 return 0
5856 return 0
5860
5857
5861 with repo.wlock():
5858 with repo.wlock():
5862 ms = mergestatemod.mergestate.read(repo)
5859 ms = mergestatemod.mergestate.read(repo)
5863
5860
5864 if not (ms.active() or repo.dirstate.p2() != nullid):
5861 if not (ms.active() or repo.dirstate.p2() != nullid):
5865 raise error.Abort(
5862 raise error.Abort(
5866 _(b'resolve command not applicable when not merging')
5863 _(b'resolve command not applicable when not merging')
5867 )
5864 )
5868
5865
5869 wctx = repo[None]
5866 wctx = repo[None]
5870 m = scmutil.match(wctx, pats, opts)
5867 m = scmutil.match(wctx, pats, opts)
5871 ret = 0
5868 ret = 0
5872 didwork = False
5869 didwork = False
5873
5870
5874 tocomplete = []
5871 tocomplete = []
5875 hasconflictmarkers = []
5872 hasconflictmarkers = []
5876 if mark:
5873 if mark:
5877 markcheck = ui.config(b'commands', b'resolve.mark-check')
5874 markcheck = ui.config(b'commands', b'resolve.mark-check')
5878 if markcheck not in [b'warn', b'abort']:
5875 if markcheck not in [b'warn', b'abort']:
5879 # Treat all invalid / unrecognized values as 'none'.
5876 # Treat all invalid / unrecognized values as 'none'.
5880 markcheck = False
5877 markcheck = False
5881 for f in ms:
5878 for f in ms:
5882 if not m(f):
5879 if not m(f):
5883 continue
5880 continue
5884
5881
5885 didwork = True
5882 didwork = True
5886
5883
5887 # path conflicts must be resolved manually
5884 # path conflicts must be resolved manually
5888 if ms[f] in (
5885 if ms[f] in (
5889 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5886 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5890 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5887 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5891 ):
5888 ):
5892 if mark:
5889 if mark:
5893 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5890 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5894 elif unmark:
5891 elif unmark:
5895 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5892 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5896 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5893 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5897 ui.warn(
5894 ui.warn(
5898 _(b'%s: path conflict must be resolved manually\n')
5895 _(b'%s: path conflict must be resolved manually\n')
5899 % uipathfn(f)
5896 % uipathfn(f)
5900 )
5897 )
5901 continue
5898 continue
5902
5899
5903 if mark:
5900 if mark:
5904 if markcheck:
5901 if markcheck:
5905 fdata = repo.wvfs.tryread(f)
5902 fdata = repo.wvfs.tryread(f)
5906 if (
5903 if (
5907 filemerge.hasconflictmarkers(fdata)
5904 filemerge.hasconflictmarkers(fdata)
5908 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5905 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5909 ):
5906 ):
5910 hasconflictmarkers.append(f)
5907 hasconflictmarkers.append(f)
5911 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5908 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5912 elif unmark:
5909 elif unmark:
5913 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5910 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5914 else:
5911 else:
5915 # backup pre-resolve (merge uses .orig for its own purposes)
5912 # backup pre-resolve (merge uses .orig for its own purposes)
5916 a = repo.wjoin(f)
5913 a = repo.wjoin(f)
5917 try:
5914 try:
5918 util.copyfile(a, a + b".resolve")
5915 util.copyfile(a, a + b".resolve")
5919 except (IOError, OSError) as inst:
5916 except (IOError, OSError) as inst:
5920 if inst.errno != errno.ENOENT:
5917 if inst.errno != errno.ENOENT:
5921 raise
5918 raise
5922
5919
5923 try:
5920 try:
5924 # preresolve file
5921 # preresolve file
5925 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5922 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5926 with ui.configoverride(overrides, b'resolve'):
5923 with ui.configoverride(overrides, b'resolve'):
5927 complete, r = ms.preresolve(f, wctx)
5924 complete, r = ms.preresolve(f, wctx)
5928 if not complete:
5925 if not complete:
5929 tocomplete.append(f)
5926 tocomplete.append(f)
5930 elif r:
5927 elif r:
5931 ret = 1
5928 ret = 1
5932 finally:
5929 finally:
5933 ms.commit()
5930 ms.commit()
5934
5931
5935 # replace filemerge's .orig file with our resolve file, but only
5932 # replace filemerge's .orig file with our resolve file, but only
5936 # for merges that are complete
5933 # for merges that are complete
5937 if complete:
5934 if complete:
5938 try:
5935 try:
5939 util.rename(
5936 util.rename(
5940 a + b".resolve", scmutil.backuppath(ui, repo, f)
5937 a + b".resolve", scmutil.backuppath(ui, repo, f)
5941 )
5938 )
5942 except OSError as inst:
5939 except OSError as inst:
5943 if inst.errno != errno.ENOENT:
5940 if inst.errno != errno.ENOENT:
5944 raise
5941 raise
5945
5942
5946 if hasconflictmarkers:
5943 if hasconflictmarkers:
5947 ui.warn(
5944 ui.warn(
5948 _(
5945 _(
5949 b'warning: the following files still have conflict '
5946 b'warning: the following files still have conflict '
5950 b'markers:\n'
5947 b'markers:\n'
5951 )
5948 )
5952 + b''.join(
5949 + b''.join(
5953 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5950 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
5954 )
5951 )
5955 )
5952 )
5956 if markcheck == b'abort' and not all and not pats:
5953 if markcheck == b'abort' and not all and not pats:
5957 raise error.Abort(
5954 raise error.Abort(
5958 _(b'conflict markers detected'),
5955 _(b'conflict markers detected'),
5959 hint=_(b'use --all to mark anyway'),
5956 hint=_(b'use --all to mark anyway'),
5960 )
5957 )
5961
5958
5962 for f in tocomplete:
5959 for f in tocomplete:
5963 try:
5960 try:
5964 # resolve file
5961 # resolve file
5965 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5962 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5966 with ui.configoverride(overrides, b'resolve'):
5963 with ui.configoverride(overrides, b'resolve'):
5967 r = ms.resolve(f, wctx)
5964 r = ms.resolve(f, wctx)
5968 if r:
5965 if r:
5969 ret = 1
5966 ret = 1
5970 finally:
5967 finally:
5971 ms.commit()
5968 ms.commit()
5972
5969
5973 # replace filemerge's .orig file with our resolve file
5970 # replace filemerge's .orig file with our resolve file
5974 a = repo.wjoin(f)
5971 a = repo.wjoin(f)
5975 try:
5972 try:
5976 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5973 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
5977 except OSError as inst:
5974 except OSError as inst:
5978 if inst.errno != errno.ENOENT:
5975 if inst.errno != errno.ENOENT:
5979 raise
5976 raise
5980
5977
5981 ms.commit()
5978 ms.commit()
5982 branchmerge = repo.dirstate.p2() != nullid
5979 branchmerge = repo.dirstate.p2() != nullid
5983 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5980 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
5984
5981
5985 if not didwork and pats:
5982 if not didwork and pats:
5986 hint = None
5983 hint = None
5987 if not any([p for p in pats if p.find(b':') >= 0]):
5984 if not any([p for p in pats if p.find(b':') >= 0]):
5988 pats = [b'path:%s' % p for p in pats]
5985 pats = [b'path:%s' % p for p in pats]
5989 m = scmutil.match(wctx, pats, opts)
5986 m = scmutil.match(wctx, pats, opts)
5990 for f in ms:
5987 for f in ms:
5991 if not m(f):
5988 if not m(f):
5992 continue
5989 continue
5993
5990
5994 def flag(o):
5991 def flag(o):
5995 if o == b're_merge':
5992 if o == b're_merge':
5996 return b'--re-merge '
5993 return b'--re-merge '
5997 return b'-%s ' % o[0:1]
5994 return b'-%s ' % o[0:1]
5998
5995
5999 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
5996 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6000 hint = _(b"(try: hg resolve %s%s)\n") % (
5997 hint = _(b"(try: hg resolve %s%s)\n") % (
6001 flags,
5998 flags,
6002 b' '.join(pats),
5999 b' '.join(pats),
6003 )
6000 )
6004 break
6001 break
6005 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6002 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6006 if hint:
6003 if hint:
6007 ui.warn(hint)
6004 ui.warn(hint)
6008
6005
6009 unresolvedf = list(ms.unresolved())
6006 unresolvedf = list(ms.unresolved())
6010 if not unresolvedf:
6007 if not unresolvedf:
6011 ui.status(_(b'(no more unresolved files)\n'))
6008 ui.status(_(b'(no more unresolved files)\n'))
6012 cmdutil.checkafterresolved(repo)
6009 cmdutil.checkafterresolved(repo)
6013
6010
6014 return ret
6011 return ret
6015
6012
6016
6013
6017 @command(
6014 @command(
6018 b'revert',
6015 b'revert',
6019 [
6016 [
6020 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6017 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6021 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6018 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6022 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6019 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6023 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6020 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6024 (b'i', b'interactive', None, _(b'interactively select the changes')),
6021 (b'i', b'interactive', None, _(b'interactively select the changes')),
6025 ]
6022 ]
6026 + walkopts
6023 + walkopts
6027 + dryrunopts,
6024 + dryrunopts,
6028 _(b'[OPTION]... [-r REV] [NAME]...'),
6025 _(b'[OPTION]... [-r REV] [NAME]...'),
6029 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6026 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6030 )
6027 )
6031 def revert(ui, repo, *pats, **opts):
6028 def revert(ui, repo, *pats, **opts):
6032 """restore files to their checkout state
6029 """restore files to their checkout state
6033
6030
6034 .. note::
6031 .. note::
6035
6032
6036 To check out earlier revisions, you should use :hg:`update REV`.
6033 To check out earlier revisions, you should use :hg:`update REV`.
6037 To cancel an uncommitted merge (and lose your changes),
6034 To cancel an uncommitted merge (and lose your changes),
6038 use :hg:`merge --abort`.
6035 use :hg:`merge --abort`.
6039
6036
6040 With no revision specified, revert the specified files or directories
6037 With no revision specified, revert the specified files or directories
6041 to the contents they had in the parent of the working directory.
6038 to the contents they had in the parent of the working directory.
6042 This restores the contents of files to an unmodified
6039 This restores the contents of files to an unmodified
6043 state and unschedules adds, removes, copies, and renames. If the
6040 state and unschedules adds, removes, copies, and renames. If the
6044 working directory has two parents, you must explicitly specify a
6041 working directory has two parents, you must explicitly specify a
6045 revision.
6042 revision.
6046
6043
6047 Using the -r/--rev or -d/--date options, revert the given files or
6044 Using the -r/--rev or -d/--date options, revert the given files or
6048 directories to their states as of a specific revision. Because
6045 directories to their states as of a specific revision. Because
6049 revert does not change the working directory parents, this will
6046 revert does not change the working directory parents, this will
6050 cause these files to appear modified. This can be helpful to "back
6047 cause these files to appear modified. This can be helpful to "back
6051 out" some or all of an earlier change. See :hg:`backout` for a
6048 out" some or all of an earlier change. See :hg:`backout` for a
6052 related method.
6049 related method.
6053
6050
6054 Modified files are saved with a .orig suffix before reverting.
6051 Modified files are saved with a .orig suffix before reverting.
6055 To disable these backups, use --no-backup. It is possible to store
6052 To disable these backups, use --no-backup. It is possible to store
6056 the backup files in a custom directory relative to the root of the
6053 the backup files in a custom directory relative to the root of the
6057 repository by setting the ``ui.origbackuppath`` configuration
6054 repository by setting the ``ui.origbackuppath`` configuration
6058 option.
6055 option.
6059
6056
6060 See :hg:`help dates` for a list of formats valid for -d/--date.
6057 See :hg:`help dates` for a list of formats valid for -d/--date.
6061
6058
6062 See :hg:`help backout` for a way to reverse the effect of an
6059 See :hg:`help backout` for a way to reverse the effect of an
6063 earlier changeset.
6060 earlier changeset.
6064
6061
6065 Returns 0 on success.
6062 Returns 0 on success.
6066 """
6063 """
6067
6064
6068 opts = pycompat.byteskwargs(opts)
6065 opts = pycompat.byteskwargs(opts)
6069 if opts.get(b"date"):
6066 if opts.get(b"date"):
6070 if opts.get(b"rev"):
6067 if opts.get(b"rev"):
6071 raise error.Abort(_(b"you can't specify a revision and a date"))
6068 raise error.Abort(_(b"you can't specify a revision and a date"))
6072 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6069 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6073
6070
6074 parent, p2 = repo.dirstate.parents()
6071 parent, p2 = repo.dirstate.parents()
6075 if not opts.get(b'rev') and p2 != nullid:
6072 if not opts.get(b'rev') and p2 != nullid:
6076 # revert after merge is a trap for new users (issue2915)
6073 # revert after merge is a trap for new users (issue2915)
6077 raise error.Abort(
6074 raise error.Abort(
6078 _(b'uncommitted merge with no revision specified'),
6075 _(b'uncommitted merge with no revision specified'),
6079 hint=_(b"use 'hg update' or see 'hg help revert'"),
6076 hint=_(b"use 'hg update' or see 'hg help revert'"),
6080 )
6077 )
6081
6078
6082 rev = opts.get(b'rev')
6079 rev = opts.get(b'rev')
6083 if rev:
6080 if rev:
6084 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6081 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6085 ctx = scmutil.revsingle(repo, rev)
6082 ctx = scmutil.revsingle(repo, rev)
6086
6083
6087 if not (
6084 if not (
6088 pats
6085 pats
6089 or opts.get(b'include')
6086 or opts.get(b'include')
6090 or opts.get(b'exclude')
6087 or opts.get(b'exclude')
6091 or opts.get(b'all')
6088 or opts.get(b'all')
6092 or opts.get(b'interactive')
6089 or opts.get(b'interactive')
6093 ):
6090 ):
6094 msg = _(b"no files or directories specified")
6091 msg = _(b"no files or directories specified")
6095 if p2 != nullid:
6092 if p2 != nullid:
6096 hint = _(
6093 hint = _(
6097 b"uncommitted merge, use --all to discard all changes,"
6094 b"uncommitted merge, use --all to discard all changes,"
6098 b" or 'hg update -C .' to abort the merge"
6095 b" or 'hg update -C .' to abort the merge"
6099 )
6096 )
6100 raise error.Abort(msg, hint=hint)
6097 raise error.Abort(msg, hint=hint)
6101 dirty = any(repo.status())
6098 dirty = any(repo.status())
6102 node = ctx.node()
6099 node = ctx.node()
6103 if node != parent:
6100 if node != parent:
6104 if dirty:
6101 if dirty:
6105 hint = (
6102 hint = (
6106 _(
6103 _(
6107 b"uncommitted changes, use --all to discard all"
6104 b"uncommitted changes, use --all to discard all"
6108 b" changes, or 'hg update %d' to update"
6105 b" changes, or 'hg update %d' to update"
6109 )
6106 )
6110 % ctx.rev()
6107 % ctx.rev()
6111 )
6108 )
6112 else:
6109 else:
6113 hint = (
6110 hint = (
6114 _(
6111 _(
6115 b"use --all to revert all files,"
6112 b"use --all to revert all files,"
6116 b" or 'hg update %d' to update"
6113 b" or 'hg update %d' to update"
6117 )
6114 )
6118 % ctx.rev()
6115 % ctx.rev()
6119 )
6116 )
6120 elif dirty:
6117 elif dirty:
6121 hint = _(b"uncommitted changes, use --all to discard all changes")
6118 hint = _(b"uncommitted changes, use --all to discard all changes")
6122 else:
6119 else:
6123 hint = _(b"use --all to revert all files")
6120 hint = _(b"use --all to revert all files")
6124 raise error.Abort(msg, hint=hint)
6121 raise error.Abort(msg, hint=hint)
6125
6122
6126 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6123 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6127
6124
6128
6125
6129 @command(
6126 @command(
6130 b'rollback',
6127 b'rollback',
6131 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6128 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6132 helpcategory=command.CATEGORY_MAINTENANCE,
6129 helpcategory=command.CATEGORY_MAINTENANCE,
6133 )
6130 )
6134 def rollback(ui, repo, **opts):
6131 def rollback(ui, repo, **opts):
6135 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6136
6133
6137 Please use :hg:`commit --amend` instead of rollback to correct
6134 Please use :hg:`commit --amend` instead of rollback to correct
6138 mistakes in the last commit.
6135 mistakes in the last commit.
6139
6136
6140 This command should be used with care. There is only one level of
6137 This command should be used with care. There is only one level of
6141 rollback, and there is no way to undo a rollback. It will also
6138 rollback, and there is no way to undo a rollback. It will also
6142 restore the dirstate at the time of the last transaction, losing
6139 restore the dirstate at the time of the last transaction, losing
6143 any dirstate changes since that time. This command does not alter
6140 any dirstate changes since that time. This command does not alter
6144 the working directory.
6141 the working directory.
6145
6142
6146 Transactions are used to encapsulate the effects of all commands
6143 Transactions are used to encapsulate the effects of all commands
6147 that create new changesets or propagate existing changesets into a
6144 that create new changesets or propagate existing changesets into a
6148 repository.
6145 repository.
6149
6146
6150 .. container:: verbose
6147 .. container:: verbose
6151
6148
6152 For example, the following commands are transactional, and their
6149 For example, the following commands are transactional, and their
6153 effects can be rolled back:
6150 effects can be rolled back:
6154
6151
6155 - commit
6152 - commit
6156 - import
6153 - import
6157 - pull
6154 - pull
6158 - push (with this repository as the destination)
6155 - push (with this repository as the destination)
6159 - unbundle
6156 - unbundle
6160
6157
6161 To avoid permanent data loss, rollback will refuse to rollback a
6158 To avoid permanent data loss, rollback will refuse to rollback a
6162 commit transaction if it isn't checked out. Use --force to
6159 commit transaction if it isn't checked out. Use --force to
6163 override this protection.
6160 override this protection.
6164
6161
6165 The rollback command can be entirely disabled by setting the
6162 The rollback command can be entirely disabled by setting the
6166 ``ui.rollback`` configuration setting to false. If you're here
6163 ``ui.rollback`` configuration setting to false. If you're here
6167 because you want to use rollback and it's disabled, you can
6164 because you want to use rollback and it's disabled, you can
6168 re-enable the command by setting ``ui.rollback`` to true.
6165 re-enable the command by setting ``ui.rollback`` to true.
6169
6166
6170 This command is not intended for use on public repositories. Once
6167 This command is not intended for use on public repositories. Once
6171 changes are visible for pull by other users, rolling a transaction
6168 changes are visible for pull by other users, rolling a transaction
6172 back locally is ineffective (someone else may already have pulled
6169 back locally is ineffective (someone else may already have pulled
6173 the changes). Furthermore, a race is possible with readers of the
6170 the changes). Furthermore, a race is possible with readers of the
6174 repository; for example an in-progress pull from the repository
6171 repository; for example an in-progress pull from the repository
6175 may fail if a rollback is performed.
6172 may fail if a rollback is performed.
6176
6173
6177 Returns 0 on success, 1 if no rollback data is available.
6174 Returns 0 on success, 1 if no rollback data is available.
6178 """
6175 """
6179 if not ui.configbool(b'ui', b'rollback'):
6176 if not ui.configbool(b'ui', b'rollback'):
6180 raise error.Abort(
6177 raise error.Abort(
6181 _(b'rollback is disabled because it is unsafe'),
6178 _(b'rollback is disabled because it is unsafe'),
6182 hint=b'see `hg help -v rollback` for information',
6179 hint=b'see `hg help -v rollback` for information',
6183 )
6180 )
6184 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6181 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6185
6182
6186
6183
6187 @command(
6184 @command(
6188 b'root',
6185 b'root',
6189 [] + formatteropts,
6186 [] + formatteropts,
6190 intents={INTENT_READONLY},
6187 intents={INTENT_READONLY},
6191 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6188 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6192 )
6189 )
6193 def root(ui, repo, **opts):
6190 def root(ui, repo, **opts):
6194 """print the root (top) of the current working directory
6191 """print the root (top) of the current working directory
6195
6192
6196 Print the root directory of the current repository.
6193 Print the root directory of the current repository.
6197
6194
6198 .. container:: verbose
6195 .. container:: verbose
6199
6196
6200 Template:
6197 Template:
6201
6198
6202 The following keywords are supported in addition to the common template
6199 The following keywords are supported in addition to the common template
6203 keywords and functions. See also :hg:`help templates`.
6200 keywords and functions. See also :hg:`help templates`.
6204
6201
6205 :hgpath: String. Path to the .hg directory.
6202 :hgpath: String. Path to the .hg directory.
6206 :storepath: String. Path to the directory holding versioned data.
6203 :storepath: String. Path to the directory holding versioned data.
6207
6204
6208 Returns 0 on success.
6205 Returns 0 on success.
6209 """
6206 """
6210 opts = pycompat.byteskwargs(opts)
6207 opts = pycompat.byteskwargs(opts)
6211 with ui.formatter(b'root', opts) as fm:
6208 with ui.formatter(b'root', opts) as fm:
6212 fm.startitem()
6209 fm.startitem()
6213 fm.write(b'reporoot', b'%s\n', repo.root)
6210 fm.write(b'reporoot', b'%s\n', repo.root)
6214 fm.data(hgpath=repo.path, storepath=repo.spath)
6211 fm.data(hgpath=repo.path, storepath=repo.spath)
6215
6212
6216
6213
6217 @command(
6214 @command(
6218 b'serve',
6215 b'serve',
6219 [
6216 [
6220 (
6217 (
6221 b'A',
6218 b'A',
6222 b'accesslog',
6219 b'accesslog',
6223 b'',
6220 b'',
6224 _(b'name of access log file to write to'),
6221 _(b'name of access log file to write to'),
6225 _(b'FILE'),
6222 _(b'FILE'),
6226 ),
6223 ),
6227 (b'd', b'daemon', None, _(b'run server in background')),
6224 (b'd', b'daemon', None, _(b'run server in background')),
6228 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6225 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6229 (
6226 (
6230 b'E',
6227 b'E',
6231 b'errorlog',
6228 b'errorlog',
6232 b'',
6229 b'',
6233 _(b'name of error log file to write to'),
6230 _(b'name of error log file to write to'),
6234 _(b'FILE'),
6231 _(b'FILE'),
6235 ),
6232 ),
6236 # use string type, then we can check if something was passed
6233 # use string type, then we can check if something was passed
6237 (
6234 (
6238 b'p',
6235 b'p',
6239 b'port',
6236 b'port',
6240 b'',
6237 b'',
6241 _(b'port to listen on (default: 8000)'),
6238 _(b'port to listen on (default: 8000)'),
6242 _(b'PORT'),
6239 _(b'PORT'),
6243 ),
6240 ),
6244 (
6241 (
6245 b'a',
6242 b'a',
6246 b'address',
6243 b'address',
6247 b'',
6244 b'',
6248 _(b'address to listen on (default: all interfaces)'),
6245 _(b'address to listen on (default: all interfaces)'),
6249 _(b'ADDR'),
6246 _(b'ADDR'),
6250 ),
6247 ),
6251 (
6248 (
6252 b'',
6249 b'',
6253 b'prefix',
6250 b'prefix',
6254 b'',
6251 b'',
6255 _(b'prefix path to serve from (default: server root)'),
6252 _(b'prefix path to serve from (default: server root)'),
6256 _(b'PREFIX'),
6253 _(b'PREFIX'),
6257 ),
6254 ),
6258 (
6255 (
6259 b'n',
6256 b'n',
6260 b'name',
6257 b'name',
6261 b'',
6258 b'',
6262 _(b'name to show in web pages (default: working directory)'),
6259 _(b'name to show in web pages (default: working directory)'),
6263 _(b'NAME'),
6260 _(b'NAME'),
6264 ),
6261 ),
6265 (
6262 (
6266 b'',
6263 b'',
6267 b'web-conf',
6264 b'web-conf',
6268 b'',
6265 b'',
6269 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6266 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6270 _(b'FILE'),
6267 _(b'FILE'),
6271 ),
6268 ),
6272 (
6269 (
6273 b'',
6270 b'',
6274 b'webdir-conf',
6271 b'webdir-conf',
6275 b'',
6272 b'',
6276 _(b'name of the hgweb config file (DEPRECATED)'),
6273 _(b'name of the hgweb config file (DEPRECATED)'),
6277 _(b'FILE'),
6274 _(b'FILE'),
6278 ),
6275 ),
6279 (
6276 (
6280 b'',
6277 b'',
6281 b'pid-file',
6278 b'pid-file',
6282 b'',
6279 b'',
6283 _(b'name of file to write process ID to'),
6280 _(b'name of file to write process ID to'),
6284 _(b'FILE'),
6281 _(b'FILE'),
6285 ),
6282 ),
6286 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6283 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6287 (
6284 (
6288 b'',
6285 b'',
6289 b'cmdserver',
6286 b'cmdserver',
6290 b'',
6287 b'',
6291 _(b'for remote clients (ADVANCED)'),
6288 _(b'for remote clients (ADVANCED)'),
6292 _(b'MODE'),
6289 _(b'MODE'),
6293 ),
6290 ),
6294 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6291 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6295 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6292 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6296 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6293 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6297 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6294 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6298 (b'', b'print-url', None, _(b'start and print only the URL')),
6295 (b'', b'print-url', None, _(b'start and print only the URL')),
6299 ]
6296 ]
6300 + subrepoopts,
6297 + subrepoopts,
6301 _(b'[OPTION]...'),
6298 _(b'[OPTION]...'),
6302 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6303 helpbasic=True,
6300 helpbasic=True,
6304 optionalrepo=True,
6301 optionalrepo=True,
6305 )
6302 )
6306 def serve(ui, repo, **opts):
6303 def serve(ui, repo, **opts):
6307 """start stand-alone webserver
6304 """start stand-alone webserver
6308
6305
6309 Start a local HTTP repository browser and pull server. You can use
6306 Start a local HTTP repository browser and pull server. You can use
6310 this for ad-hoc sharing and browsing of repositories. It is
6307 this for ad-hoc sharing and browsing of repositories. It is
6311 recommended to use a real web server to serve a repository for
6308 recommended to use a real web server to serve a repository for
6312 longer periods of time.
6309 longer periods of time.
6313
6310
6314 Please note that the server does not implement access control.
6311 Please note that the server does not implement access control.
6315 This means that, by default, anybody can read from the server and
6312 This means that, by default, anybody can read from the server and
6316 nobody can write to it by default. Set the ``web.allow-push``
6313 nobody can write to it by default. Set the ``web.allow-push``
6317 option to ``*`` to allow everybody to push to the server. You
6314 option to ``*`` to allow everybody to push to the server. You
6318 should use a real web server if you need to authenticate users.
6315 should use a real web server if you need to authenticate users.
6319
6316
6320 By default, the server logs accesses to stdout and errors to
6317 By default, the server logs accesses to stdout and errors to
6321 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6318 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6322 files.
6319 files.
6323
6320
6324 To have the server choose a free port number to listen on, specify
6321 To have the server choose a free port number to listen on, specify
6325 a port number of 0; in this case, the server will print the port
6322 a port number of 0; in this case, the server will print the port
6326 number it uses.
6323 number it uses.
6327
6324
6328 Returns 0 on success.
6325 Returns 0 on success.
6329 """
6326 """
6330
6327
6331 opts = pycompat.byteskwargs(opts)
6328 opts = pycompat.byteskwargs(opts)
6332 if opts[b"stdio"] and opts[b"cmdserver"]:
6329 if opts[b"stdio"] and opts[b"cmdserver"]:
6333 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6330 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6334 if opts[b"print_url"] and ui.verbose:
6331 if opts[b"print_url"] and ui.verbose:
6335 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6332 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6336
6333
6337 if opts[b"stdio"]:
6334 if opts[b"stdio"]:
6338 if repo is None:
6335 if repo is None:
6339 raise error.RepoError(
6336 raise error.RepoError(
6340 _(b"there is no Mercurial repository here (.hg not found)")
6337 _(b"there is no Mercurial repository here (.hg not found)")
6341 )
6338 )
6342 s = wireprotoserver.sshserver(ui, repo)
6339 s = wireprotoserver.sshserver(ui, repo)
6343 s.serve_forever()
6340 s.serve_forever()
6344
6341
6345 service = server.createservice(ui, repo, opts)
6342 service = server.createservice(ui, repo, opts)
6346 return server.runservice(opts, initfn=service.init, runfn=service.run)
6343 return server.runservice(opts, initfn=service.init, runfn=service.run)
6347
6344
6348
6345
6349 @command(
6346 @command(
6350 b'shelve',
6347 b'shelve',
6351 [
6348 [
6352 (
6349 (
6353 b'A',
6350 b'A',
6354 b'addremove',
6351 b'addremove',
6355 None,
6352 None,
6356 _(b'mark new/missing files as added/removed before shelving'),
6353 _(b'mark new/missing files as added/removed before shelving'),
6357 ),
6354 ),
6358 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6355 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6359 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6356 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6360 (
6357 (
6361 b'',
6358 b'',
6362 b'date',
6359 b'date',
6363 b'',
6360 b'',
6364 _(b'shelve with the specified commit date'),
6361 _(b'shelve with the specified commit date'),
6365 _(b'DATE'),
6362 _(b'DATE'),
6366 ),
6363 ),
6367 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6364 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6368 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6365 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6369 (
6366 (
6370 b'k',
6367 b'k',
6371 b'keep',
6368 b'keep',
6372 False,
6369 False,
6373 _(b'shelve, but keep changes in the working directory'),
6370 _(b'shelve, but keep changes in the working directory'),
6374 ),
6371 ),
6375 (b'l', b'list', None, _(b'list current shelves')),
6372 (b'l', b'list', None, _(b'list current shelves')),
6376 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6373 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6377 (
6374 (
6378 b'n',
6375 b'n',
6379 b'name',
6376 b'name',
6380 b'',
6377 b'',
6381 _(b'use the given name for the shelved commit'),
6378 _(b'use the given name for the shelved commit'),
6382 _(b'NAME'),
6379 _(b'NAME'),
6383 ),
6380 ),
6384 (
6381 (
6385 b'p',
6382 b'p',
6386 b'patch',
6383 b'patch',
6387 None,
6384 None,
6388 _(
6385 _(
6389 b'output patches for changes (provide the names of the shelved '
6386 b'output patches for changes (provide the names of the shelved '
6390 b'changes as positional arguments)'
6387 b'changes as positional arguments)'
6391 ),
6388 ),
6392 ),
6389 ),
6393 (b'i', b'interactive', None, _(b'interactive mode')),
6390 (b'i', b'interactive', None, _(b'interactive mode')),
6394 (
6391 (
6395 b'',
6392 b'',
6396 b'stat',
6393 b'stat',
6397 None,
6394 None,
6398 _(
6395 _(
6399 b'output diffstat-style summary of changes (provide the names of '
6396 b'output diffstat-style summary of changes (provide the names of '
6400 b'the shelved changes as positional arguments)'
6397 b'the shelved changes as positional arguments)'
6401 ),
6398 ),
6402 ),
6399 ),
6403 ]
6400 ]
6404 + cmdutil.walkopts,
6401 + cmdutil.walkopts,
6405 _(b'hg shelve [OPTION]... [FILE]...'),
6402 _(b'hg shelve [OPTION]... [FILE]...'),
6406 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6403 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6407 )
6404 )
6408 def shelve(ui, repo, *pats, **opts):
6405 def shelve(ui, repo, *pats, **opts):
6409 '''save and set aside changes from the working directory
6406 '''save and set aside changes from the working directory
6410
6407
6411 Shelving takes files that "hg status" reports as not clean, saves
6408 Shelving takes files that "hg status" reports as not clean, saves
6412 the modifications to a bundle (a shelved change), and reverts the
6409 the modifications to a bundle (a shelved change), and reverts the
6413 files so that their state in the working directory becomes clean.
6410 files so that their state in the working directory becomes clean.
6414
6411
6415 To restore these changes to the working directory, using "hg
6412 To restore these changes to the working directory, using "hg
6416 unshelve"; this will work even if you switch to a different
6413 unshelve"; this will work even if you switch to a different
6417 commit.
6414 commit.
6418
6415
6419 When no files are specified, "hg shelve" saves all not-clean
6416 When no files are specified, "hg shelve" saves all not-clean
6420 files. If specific files or directories are named, only changes to
6417 files. If specific files or directories are named, only changes to
6421 those files are shelved.
6418 those files are shelved.
6422
6419
6423 In bare shelve (when no files are specified, without interactive,
6420 In bare shelve (when no files are specified, without interactive,
6424 include and exclude option), shelving remembers information if the
6421 include and exclude option), shelving remembers information if the
6425 working directory was on newly created branch, in other words working
6422 working directory was on newly created branch, in other words working
6426 directory was on different branch than its first parent. In this
6423 directory was on different branch than its first parent. In this
6427 situation unshelving restores branch information to the working directory.
6424 situation unshelving restores branch information to the working directory.
6428
6425
6429 Each shelved change has a name that makes it easier to find later.
6426 Each shelved change has a name that makes it easier to find later.
6430 The name of a shelved change defaults to being based on the active
6427 The name of a shelved change defaults to being based on the active
6431 bookmark, or if there is no active bookmark, the current named
6428 bookmark, or if there is no active bookmark, the current named
6432 branch. To specify a different name, use ``--name``.
6429 branch. To specify a different name, use ``--name``.
6433
6430
6434 To see a list of existing shelved changes, use the ``--list``
6431 To see a list of existing shelved changes, use the ``--list``
6435 option. For each shelved change, this will print its name, age,
6432 option. For each shelved change, this will print its name, age,
6436 and description; use ``--patch`` or ``--stat`` for more details.
6433 and description; use ``--patch`` or ``--stat`` for more details.
6437
6434
6438 To delete specific shelved changes, use ``--delete``. To delete
6435 To delete specific shelved changes, use ``--delete``. To delete
6439 all shelved changes, use ``--cleanup``.
6436 all shelved changes, use ``--cleanup``.
6440 '''
6437 '''
6441 opts = pycompat.byteskwargs(opts)
6438 opts = pycompat.byteskwargs(opts)
6442 allowables = [
6439 allowables = [
6443 (b'addremove', {b'create'}), # 'create' is pseudo action
6440 (b'addremove', {b'create'}), # 'create' is pseudo action
6444 (b'unknown', {b'create'}),
6441 (b'unknown', {b'create'}),
6445 (b'cleanup', {b'cleanup'}),
6442 (b'cleanup', {b'cleanup'}),
6446 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6443 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6447 (b'delete', {b'delete'}),
6444 (b'delete', {b'delete'}),
6448 (b'edit', {b'create'}),
6445 (b'edit', {b'create'}),
6449 (b'keep', {b'create'}),
6446 (b'keep', {b'create'}),
6450 (b'list', {b'list'}),
6447 (b'list', {b'list'}),
6451 (b'message', {b'create'}),
6448 (b'message', {b'create'}),
6452 (b'name', {b'create'}),
6449 (b'name', {b'create'}),
6453 (b'patch', {b'patch', b'list'}),
6450 (b'patch', {b'patch', b'list'}),
6454 (b'stat', {b'stat', b'list'}),
6451 (b'stat', {b'stat', b'list'}),
6455 ]
6452 ]
6456
6453
6457 def checkopt(opt):
6454 def checkopt(opt):
6458 if opts.get(opt):
6455 if opts.get(opt):
6459 for i, allowable in allowables:
6456 for i, allowable in allowables:
6460 if opts[i] and opt not in allowable:
6457 if opts[i] and opt not in allowable:
6461 raise error.Abort(
6458 raise error.Abort(
6462 _(
6459 _(
6463 b"options '--%s' and '--%s' may not be "
6460 b"options '--%s' and '--%s' may not be "
6464 b"used together"
6461 b"used together"
6465 )
6462 )
6466 % (opt, i)
6463 % (opt, i)
6467 )
6464 )
6468 return True
6465 return True
6469
6466
6470 if checkopt(b'cleanup'):
6467 if checkopt(b'cleanup'):
6471 if pats:
6468 if pats:
6472 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6469 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6473 return shelvemod.cleanupcmd(ui, repo)
6470 return shelvemod.cleanupcmd(ui, repo)
6474 elif checkopt(b'delete'):
6471 elif checkopt(b'delete'):
6475 return shelvemod.deletecmd(ui, repo, pats)
6472 return shelvemod.deletecmd(ui, repo, pats)
6476 elif checkopt(b'list'):
6473 elif checkopt(b'list'):
6477 return shelvemod.listcmd(ui, repo, pats, opts)
6474 return shelvemod.listcmd(ui, repo, pats, opts)
6478 elif checkopt(b'patch') or checkopt(b'stat'):
6475 elif checkopt(b'patch') or checkopt(b'stat'):
6479 return shelvemod.patchcmds(ui, repo, pats, opts)
6476 return shelvemod.patchcmds(ui, repo, pats, opts)
6480 else:
6477 else:
6481 return shelvemod.createcmd(ui, repo, pats, opts)
6478 return shelvemod.createcmd(ui, repo, pats, opts)
6482
6479
6483
6480
6484 _NOTTERSE = b'nothing'
6481 _NOTTERSE = b'nothing'
6485
6482
6486
6483
6487 @command(
6484 @command(
6488 b'status|st',
6485 b'status|st',
6489 [
6486 [
6490 (b'A', b'all', None, _(b'show status of all files')),
6487 (b'A', b'all', None, _(b'show status of all files')),
6491 (b'm', b'modified', None, _(b'show only modified files')),
6488 (b'm', b'modified', None, _(b'show only modified files')),
6492 (b'a', b'added', None, _(b'show only added files')),
6489 (b'a', b'added', None, _(b'show only added files')),
6493 (b'r', b'removed', None, _(b'show only removed files')),
6490 (b'r', b'removed', None, _(b'show only removed files')),
6494 (b'd', b'deleted', None, _(b'show only missing files')),
6491 (b'd', b'deleted', None, _(b'show only missing files')),
6495 (b'c', b'clean', None, _(b'show only files without changes')),
6492 (b'c', b'clean', None, _(b'show only files without changes')),
6496 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6493 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6497 (b'i', b'ignored', None, _(b'show only ignored files')),
6494 (b'i', b'ignored', None, _(b'show only ignored files')),
6498 (b'n', b'no-status', None, _(b'hide status prefix')),
6495 (b'n', b'no-status', None, _(b'hide status prefix')),
6499 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6496 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6500 (
6497 (
6501 b'C',
6498 b'C',
6502 b'copies',
6499 b'copies',
6503 None,
6500 None,
6504 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6501 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6505 ),
6502 ),
6506 (
6503 (
6507 b'0',
6504 b'0',
6508 b'print0',
6505 b'print0',
6509 None,
6506 None,
6510 _(b'end filenames with NUL, for use with xargs'),
6507 _(b'end filenames with NUL, for use with xargs'),
6511 ),
6508 ),
6512 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6509 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6513 (
6510 (
6514 b'',
6511 b'',
6515 b'change',
6512 b'change',
6516 b'',
6513 b'',
6517 _(b'list the changed files of a revision'),
6514 _(b'list the changed files of a revision'),
6518 _(b'REV'),
6515 _(b'REV'),
6519 ),
6516 ),
6520 ]
6517 ]
6521 + walkopts
6518 + walkopts
6522 + subrepoopts
6519 + subrepoopts
6523 + formatteropts,
6520 + formatteropts,
6524 _(b'[OPTION]... [FILE]...'),
6521 _(b'[OPTION]... [FILE]...'),
6525 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6522 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6526 helpbasic=True,
6523 helpbasic=True,
6527 inferrepo=True,
6524 inferrepo=True,
6528 intents={INTENT_READONLY},
6525 intents={INTENT_READONLY},
6529 )
6526 )
6530 def status(ui, repo, *pats, **opts):
6527 def status(ui, repo, *pats, **opts):
6531 """show changed files in the working directory
6528 """show changed files in the working directory
6532
6529
6533 Show status of files in the repository. If names are given, only
6530 Show status of files in the repository. If names are given, only
6534 files that match are shown. Files that are clean or ignored or
6531 files that match are shown. Files that are clean or ignored or
6535 the source of a copy/move operation, are not listed unless
6532 the source of a copy/move operation, are not listed unless
6536 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6533 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6537 Unless options described with "show only ..." are given, the
6534 Unless options described with "show only ..." are given, the
6538 options -mardu are used.
6535 options -mardu are used.
6539
6536
6540 Option -q/--quiet hides untracked (unknown and ignored) files
6537 Option -q/--quiet hides untracked (unknown and ignored) files
6541 unless explicitly requested with -u/--unknown or -i/--ignored.
6538 unless explicitly requested with -u/--unknown or -i/--ignored.
6542
6539
6543 .. note::
6540 .. note::
6544
6541
6545 :hg:`status` may appear to disagree with diff if permissions have
6542 :hg:`status` may appear to disagree with diff if permissions have
6546 changed or a merge has occurred. The standard diff format does
6543 changed or a merge has occurred. The standard diff format does
6547 not report permission changes and diff only reports changes
6544 not report permission changes and diff only reports changes
6548 relative to one merge parent.
6545 relative to one merge parent.
6549
6546
6550 If one revision is given, it is used as the base revision.
6547 If one revision is given, it is used as the base revision.
6551 If two revisions are given, the differences between them are
6548 If two revisions are given, the differences between them are
6552 shown. The --change option can also be used as a shortcut to list
6549 shown. The --change option can also be used as a shortcut to list
6553 the changed files of a revision from its first parent.
6550 the changed files of a revision from its first parent.
6554
6551
6555 The codes used to show the status of files are::
6552 The codes used to show the status of files are::
6556
6553
6557 M = modified
6554 M = modified
6558 A = added
6555 A = added
6559 R = removed
6556 R = removed
6560 C = clean
6557 C = clean
6561 ! = missing (deleted by non-hg command, but still tracked)
6558 ! = missing (deleted by non-hg command, but still tracked)
6562 ? = not tracked
6559 ? = not tracked
6563 I = ignored
6560 I = ignored
6564 = origin of the previous file (with --copies)
6561 = origin of the previous file (with --copies)
6565
6562
6566 .. container:: verbose
6563 .. container:: verbose
6567
6564
6568 The -t/--terse option abbreviates the output by showing only the directory
6565 The -t/--terse option abbreviates the output by showing only the directory
6569 name if all the files in it share the same status. The option takes an
6566 name if all the files in it share the same status. The option takes an
6570 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6567 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6571 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6568 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6572 for 'ignored' and 'c' for clean.
6569 for 'ignored' and 'c' for clean.
6573
6570
6574 It abbreviates only those statuses which are passed. Note that clean and
6571 It abbreviates only those statuses which are passed. Note that clean and
6575 ignored files are not displayed with '--terse ic' unless the -c/--clean
6572 ignored files are not displayed with '--terse ic' unless the -c/--clean
6576 and -i/--ignored options are also used.
6573 and -i/--ignored options are also used.
6577
6574
6578 The -v/--verbose option shows information when the repository is in an
6575 The -v/--verbose option shows information when the repository is in an
6579 unfinished merge, shelve, rebase state etc. You can have this behavior
6576 unfinished merge, shelve, rebase state etc. You can have this behavior
6580 turned on by default by enabling the ``commands.status.verbose`` option.
6577 turned on by default by enabling the ``commands.status.verbose`` option.
6581
6578
6582 You can skip displaying some of these states by setting
6579 You can skip displaying some of these states by setting
6583 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6580 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6584 'histedit', 'merge', 'rebase', or 'unshelve'.
6581 'histedit', 'merge', 'rebase', or 'unshelve'.
6585
6582
6586 Template:
6583 Template:
6587
6584
6588 The following keywords are supported in addition to the common template
6585 The following keywords are supported in addition to the common template
6589 keywords and functions. See also :hg:`help templates`.
6586 keywords and functions. See also :hg:`help templates`.
6590
6587
6591 :path: String. Repository-absolute path of the file.
6588 :path: String. Repository-absolute path of the file.
6592 :source: String. Repository-absolute path of the file originated from.
6589 :source: String. Repository-absolute path of the file originated from.
6593 Available if ``--copies`` is specified.
6590 Available if ``--copies`` is specified.
6594 :status: String. Character denoting file's status.
6591 :status: String. Character denoting file's status.
6595
6592
6596 Examples:
6593 Examples:
6597
6594
6598 - show changes in the working directory relative to a
6595 - show changes in the working directory relative to a
6599 changeset::
6596 changeset::
6600
6597
6601 hg status --rev 9353
6598 hg status --rev 9353
6602
6599
6603 - show changes in the working directory relative to the
6600 - show changes in the working directory relative to the
6604 current directory (see :hg:`help patterns` for more information)::
6601 current directory (see :hg:`help patterns` for more information)::
6605
6602
6606 hg status re:
6603 hg status re:
6607
6604
6608 - show all changes including copies in an existing changeset::
6605 - show all changes including copies in an existing changeset::
6609
6606
6610 hg status --copies --change 9353
6607 hg status --copies --change 9353
6611
6608
6612 - get a NUL separated list of added files, suitable for xargs::
6609 - get a NUL separated list of added files, suitable for xargs::
6613
6610
6614 hg status -an0
6611 hg status -an0
6615
6612
6616 - show more information about the repository status, abbreviating
6613 - show more information about the repository status, abbreviating
6617 added, removed, modified, deleted, and untracked paths::
6614 added, removed, modified, deleted, and untracked paths::
6618
6615
6619 hg status -v -t mardu
6616 hg status -v -t mardu
6620
6617
6621 Returns 0 on success.
6618 Returns 0 on success.
6622
6619
6623 """
6620 """
6624
6621
6625 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6622 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6626 opts = pycompat.byteskwargs(opts)
6623 opts = pycompat.byteskwargs(opts)
6627 revs = opts.get(b'rev')
6624 revs = opts.get(b'rev')
6628 change = opts.get(b'change')
6625 change = opts.get(b'change')
6629 terse = opts.get(b'terse')
6626 terse = opts.get(b'terse')
6630 if terse is _NOTTERSE:
6627 if terse is _NOTTERSE:
6631 if revs:
6628 if revs:
6632 terse = b''
6629 terse = b''
6633 else:
6630 else:
6634 terse = ui.config(b'commands', b'status.terse')
6631 terse = ui.config(b'commands', b'status.terse')
6635
6632
6636 if revs and terse:
6633 if revs and terse:
6637 msg = _(b'cannot use --terse with --rev')
6634 msg = _(b'cannot use --terse with --rev')
6638 raise error.Abort(msg)
6635 raise error.Abort(msg)
6639 elif change:
6636 elif change:
6640 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6637 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6641 ctx2 = scmutil.revsingle(repo, change, None)
6638 ctx2 = scmutil.revsingle(repo, change, None)
6642 ctx1 = ctx2.p1()
6639 ctx1 = ctx2.p1()
6643 else:
6640 else:
6644 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6641 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6645 ctx1, ctx2 = scmutil.revpair(repo, revs)
6642 ctx1, ctx2 = scmutil.revpair(repo, revs)
6646
6643
6647 forcerelativevalue = None
6644 forcerelativevalue = None
6648 if ui.hasconfig(b'commands', b'status.relative'):
6645 if ui.hasconfig(b'commands', b'status.relative'):
6649 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6646 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6650 uipathfn = scmutil.getuipathfn(
6647 uipathfn = scmutil.getuipathfn(
6651 repo,
6648 repo,
6652 legacyrelativevalue=bool(pats),
6649 legacyrelativevalue=bool(pats),
6653 forcerelativevalue=forcerelativevalue,
6650 forcerelativevalue=forcerelativevalue,
6654 )
6651 )
6655
6652
6656 if opts.get(b'print0'):
6653 if opts.get(b'print0'):
6657 end = b'\0'
6654 end = b'\0'
6658 else:
6655 else:
6659 end = b'\n'
6656 end = b'\n'
6660 states = b'modified added removed deleted unknown ignored clean'.split()
6657 states = b'modified added removed deleted unknown ignored clean'.split()
6661 show = [k for k in states if opts.get(k)]
6658 show = [k for k in states if opts.get(k)]
6662 if opts.get(b'all'):
6659 if opts.get(b'all'):
6663 show += ui.quiet and (states[:4] + [b'clean']) or states
6660 show += ui.quiet and (states[:4] + [b'clean']) or states
6664
6661
6665 if not show:
6662 if not show:
6666 if ui.quiet:
6663 if ui.quiet:
6667 show = states[:4]
6664 show = states[:4]
6668 else:
6665 else:
6669 show = states[:5]
6666 show = states[:5]
6670
6667
6671 m = scmutil.match(ctx2, pats, opts)
6668 m = scmutil.match(ctx2, pats, opts)
6672 if terse:
6669 if terse:
6673 # we need to compute clean and unknown to terse
6670 # we need to compute clean and unknown to terse
6674 stat = repo.status(
6671 stat = repo.status(
6675 ctx1.node(),
6672 ctx1.node(),
6676 ctx2.node(),
6673 ctx2.node(),
6677 m,
6674 m,
6678 b'ignored' in show or b'i' in terse,
6675 b'ignored' in show or b'i' in terse,
6679 clean=True,
6676 clean=True,
6680 unknown=True,
6677 unknown=True,
6681 listsubrepos=opts.get(b'subrepos'),
6678 listsubrepos=opts.get(b'subrepos'),
6682 )
6679 )
6683
6680
6684 stat = cmdutil.tersedir(stat, terse)
6681 stat = cmdutil.tersedir(stat, terse)
6685 else:
6682 else:
6686 stat = repo.status(
6683 stat = repo.status(
6687 ctx1.node(),
6684 ctx1.node(),
6688 ctx2.node(),
6685 ctx2.node(),
6689 m,
6686 m,
6690 b'ignored' in show,
6687 b'ignored' in show,
6691 b'clean' in show,
6688 b'clean' in show,
6692 b'unknown' in show,
6689 b'unknown' in show,
6693 opts.get(b'subrepos'),
6690 opts.get(b'subrepos'),
6694 )
6691 )
6695
6692
6696 changestates = zip(
6693 changestates = zip(
6697 states,
6694 states,
6698 pycompat.iterbytestr(b'MAR!?IC'),
6695 pycompat.iterbytestr(b'MAR!?IC'),
6699 [getattr(stat, s.decode('utf8')) for s in states],
6696 [getattr(stat, s.decode('utf8')) for s in states],
6700 )
6697 )
6701
6698
6702 copy = {}
6699 copy = {}
6703 if (
6700 if (
6704 opts.get(b'all')
6701 opts.get(b'all')
6705 or opts.get(b'copies')
6702 or opts.get(b'copies')
6706 or ui.configbool(b'ui', b'statuscopies')
6703 or ui.configbool(b'ui', b'statuscopies')
6707 ) and not opts.get(b'no_status'):
6704 ) and not opts.get(b'no_status'):
6708 copy = copies.pathcopies(ctx1, ctx2, m)
6705 copy = copies.pathcopies(ctx1, ctx2, m)
6709
6706
6710 morestatus = None
6707 morestatus = None
6711 if (
6708 if (
6712 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6709 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6713 ) and not ui.plain():
6710 ) and not ui.plain():
6714 morestatus = cmdutil.readmorestatus(repo)
6711 morestatus = cmdutil.readmorestatus(repo)
6715
6712
6716 ui.pager(b'status')
6713 ui.pager(b'status')
6717 fm = ui.formatter(b'status', opts)
6714 fm = ui.formatter(b'status', opts)
6718 fmt = b'%s' + end
6715 fmt = b'%s' + end
6719 showchar = not opts.get(b'no_status')
6716 showchar = not opts.get(b'no_status')
6720
6717
6721 for state, char, files in changestates:
6718 for state, char, files in changestates:
6722 if state in show:
6719 if state in show:
6723 label = b'status.' + state
6720 label = b'status.' + state
6724 for f in files:
6721 for f in files:
6725 fm.startitem()
6722 fm.startitem()
6726 fm.context(ctx=ctx2)
6723 fm.context(ctx=ctx2)
6727 fm.data(itemtype=b'file', path=f)
6724 fm.data(itemtype=b'file', path=f)
6728 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6725 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6729 fm.plain(fmt % uipathfn(f), label=label)
6726 fm.plain(fmt % uipathfn(f), label=label)
6730 if f in copy:
6727 if f in copy:
6731 fm.data(source=copy[f])
6728 fm.data(source=copy[f])
6732 fm.plain(
6729 fm.plain(
6733 (b' %s' + end) % uipathfn(copy[f]),
6730 (b' %s' + end) % uipathfn(copy[f]),
6734 label=b'status.copied',
6731 label=b'status.copied',
6735 )
6732 )
6736 if morestatus:
6733 if morestatus:
6737 morestatus.formatfile(f, fm)
6734 morestatus.formatfile(f, fm)
6738
6735
6739 if morestatus:
6736 if morestatus:
6740 morestatus.formatfooter(fm)
6737 morestatus.formatfooter(fm)
6741 fm.end()
6738 fm.end()
6742
6739
6743
6740
6744 @command(
6741 @command(
6745 b'summary|sum',
6742 b'summary|sum',
6746 [(b'', b'remote', None, _(b'check for push and pull'))],
6743 [(b'', b'remote', None, _(b'check for push and pull'))],
6747 b'[--remote]',
6744 b'[--remote]',
6748 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6745 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6749 helpbasic=True,
6746 helpbasic=True,
6750 intents={INTENT_READONLY},
6747 intents={INTENT_READONLY},
6751 )
6748 )
6752 def summary(ui, repo, **opts):
6749 def summary(ui, repo, **opts):
6753 """summarize working directory state
6750 """summarize working directory state
6754
6751
6755 This generates a brief summary of the working directory state,
6752 This generates a brief summary of the working directory state,
6756 including parents, branch, commit status, phase and available updates.
6753 including parents, branch, commit status, phase and available updates.
6757
6754
6758 With the --remote option, this will check the default paths for
6755 With the --remote option, this will check the default paths for
6759 incoming and outgoing changes. This can be time-consuming.
6756 incoming and outgoing changes. This can be time-consuming.
6760
6757
6761 Returns 0 on success.
6758 Returns 0 on success.
6762 """
6759 """
6763
6760
6764 opts = pycompat.byteskwargs(opts)
6761 opts = pycompat.byteskwargs(opts)
6765 ui.pager(b'summary')
6762 ui.pager(b'summary')
6766 ctx = repo[None]
6763 ctx = repo[None]
6767 parents = ctx.parents()
6764 parents = ctx.parents()
6768 pnode = parents[0].node()
6765 pnode = parents[0].node()
6769 marks = []
6766 marks = []
6770
6767
6771 try:
6768 try:
6772 ms = mergestatemod.mergestate.read(repo)
6769 ms = mergestatemod.mergestate.read(repo)
6773 except error.UnsupportedMergeRecords as e:
6770 except error.UnsupportedMergeRecords as e:
6774 s = b' '.join(e.recordtypes)
6771 s = b' '.join(e.recordtypes)
6775 ui.warn(
6772 ui.warn(
6776 _(b'warning: merge state has unsupported record types: %s\n') % s
6773 _(b'warning: merge state has unsupported record types: %s\n') % s
6777 )
6774 )
6778 unresolved = []
6775 unresolved = []
6779 else:
6776 else:
6780 unresolved = list(ms.unresolved())
6777 unresolved = list(ms.unresolved())
6781
6778
6782 for p in parents:
6779 for p in parents:
6783 # label with log.changeset (instead of log.parent) since this
6780 # label with log.changeset (instead of log.parent) since this
6784 # shows a working directory parent *changeset*:
6781 # shows a working directory parent *changeset*:
6785 # i18n: column positioning for "hg summary"
6782 # i18n: column positioning for "hg summary"
6786 ui.write(
6783 ui.write(
6787 _(b'parent: %d:%s ') % (p.rev(), p),
6784 _(b'parent: %d:%s ') % (p.rev(), p),
6788 label=logcmdutil.changesetlabels(p),
6785 label=logcmdutil.changesetlabels(p),
6789 )
6786 )
6790 ui.write(b' '.join(p.tags()), label=b'log.tag')
6787 ui.write(b' '.join(p.tags()), label=b'log.tag')
6791 if p.bookmarks():
6788 if p.bookmarks():
6792 marks.extend(p.bookmarks())
6789 marks.extend(p.bookmarks())
6793 if p.rev() == -1:
6790 if p.rev() == -1:
6794 if not len(repo):
6791 if not len(repo):
6795 ui.write(_(b' (empty repository)'))
6792 ui.write(_(b' (empty repository)'))
6796 else:
6793 else:
6797 ui.write(_(b' (no revision checked out)'))
6794 ui.write(_(b' (no revision checked out)'))
6798 if p.obsolete():
6795 if p.obsolete():
6799 ui.write(_(b' (obsolete)'))
6796 ui.write(_(b' (obsolete)'))
6800 if p.isunstable():
6797 if p.isunstable():
6801 instabilities = (
6798 instabilities = (
6802 ui.label(instability, b'trouble.%s' % instability)
6799 ui.label(instability, b'trouble.%s' % instability)
6803 for instability in p.instabilities()
6800 for instability in p.instabilities()
6804 )
6801 )
6805 ui.write(b' (' + b', '.join(instabilities) + b')')
6802 ui.write(b' (' + b', '.join(instabilities) + b')')
6806 ui.write(b'\n')
6803 ui.write(b'\n')
6807 if p.description():
6804 if p.description():
6808 ui.status(
6805 ui.status(
6809 b' ' + p.description().splitlines()[0].strip() + b'\n',
6806 b' ' + p.description().splitlines()[0].strip() + b'\n',
6810 label=b'log.summary',
6807 label=b'log.summary',
6811 )
6808 )
6812
6809
6813 branch = ctx.branch()
6810 branch = ctx.branch()
6814 bheads = repo.branchheads(branch)
6811 bheads = repo.branchheads(branch)
6815 # i18n: column positioning for "hg summary"
6812 # i18n: column positioning for "hg summary"
6816 m = _(b'branch: %s\n') % branch
6813 m = _(b'branch: %s\n') % branch
6817 if branch != b'default':
6814 if branch != b'default':
6818 ui.write(m, label=b'log.branch')
6815 ui.write(m, label=b'log.branch')
6819 else:
6816 else:
6820 ui.status(m, label=b'log.branch')
6817 ui.status(m, label=b'log.branch')
6821
6818
6822 if marks:
6819 if marks:
6823 active = repo._activebookmark
6820 active = repo._activebookmark
6824 # i18n: column positioning for "hg summary"
6821 # i18n: column positioning for "hg summary"
6825 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6822 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6826 if active is not None:
6823 if active is not None:
6827 if active in marks:
6824 if active in marks:
6828 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6825 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6829 marks.remove(active)
6826 marks.remove(active)
6830 else:
6827 else:
6831 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6828 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6832 for m in marks:
6829 for m in marks:
6833 ui.write(b' ' + m, label=b'log.bookmark')
6830 ui.write(b' ' + m, label=b'log.bookmark')
6834 ui.write(b'\n', label=b'log.bookmark')
6831 ui.write(b'\n', label=b'log.bookmark')
6835
6832
6836 status = repo.status(unknown=True)
6833 status = repo.status(unknown=True)
6837
6834
6838 c = repo.dirstate.copies()
6835 c = repo.dirstate.copies()
6839 copied, renamed = [], []
6836 copied, renamed = [], []
6840 for d, s in pycompat.iteritems(c):
6837 for d, s in pycompat.iteritems(c):
6841 if s in status.removed:
6838 if s in status.removed:
6842 status.removed.remove(s)
6839 status.removed.remove(s)
6843 renamed.append(d)
6840 renamed.append(d)
6844 else:
6841 else:
6845 copied.append(d)
6842 copied.append(d)
6846 if d in status.added:
6843 if d in status.added:
6847 status.added.remove(d)
6844 status.added.remove(d)
6848
6845
6849 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6846 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6850
6847
6851 labels = [
6848 labels = [
6852 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6849 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6853 (ui.label(_(b'%d added'), b'status.added'), status.added),
6850 (ui.label(_(b'%d added'), b'status.added'), status.added),
6854 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6851 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6855 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6852 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6856 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6853 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6857 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6854 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6858 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6855 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6859 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6856 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6860 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6857 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6861 ]
6858 ]
6862 t = []
6859 t = []
6863 for l, s in labels:
6860 for l, s in labels:
6864 if s:
6861 if s:
6865 t.append(l % len(s))
6862 t.append(l % len(s))
6866
6863
6867 t = b', '.join(t)
6864 t = b', '.join(t)
6868 cleanworkdir = False
6865 cleanworkdir = False
6869
6866
6870 if repo.vfs.exists(b'graftstate'):
6867 if repo.vfs.exists(b'graftstate'):
6871 t += _(b' (graft in progress)')
6868 t += _(b' (graft in progress)')
6872 if repo.vfs.exists(b'updatestate'):
6869 if repo.vfs.exists(b'updatestate'):
6873 t += _(b' (interrupted update)')
6870 t += _(b' (interrupted update)')
6874 elif len(parents) > 1:
6871 elif len(parents) > 1:
6875 t += _(b' (merge)')
6872 t += _(b' (merge)')
6876 elif branch != parents[0].branch():
6873 elif branch != parents[0].branch():
6877 t += _(b' (new branch)')
6874 t += _(b' (new branch)')
6878 elif parents[0].closesbranch() and pnode in repo.branchheads(
6875 elif parents[0].closesbranch() and pnode in repo.branchheads(
6879 branch, closed=True
6876 branch, closed=True
6880 ):
6877 ):
6881 t += _(b' (head closed)')
6878 t += _(b' (head closed)')
6882 elif not (
6879 elif not (
6883 status.modified
6880 status.modified
6884 or status.added
6881 or status.added
6885 or status.removed
6882 or status.removed
6886 or renamed
6883 or renamed
6887 or copied
6884 or copied
6888 or subs
6885 or subs
6889 ):
6886 ):
6890 t += _(b' (clean)')
6887 t += _(b' (clean)')
6891 cleanworkdir = True
6888 cleanworkdir = True
6892 elif pnode not in bheads:
6889 elif pnode not in bheads:
6893 t += _(b' (new branch head)')
6890 t += _(b' (new branch head)')
6894
6891
6895 if parents:
6892 if parents:
6896 pendingphase = max(p.phase() for p in parents)
6893 pendingphase = max(p.phase() for p in parents)
6897 else:
6894 else:
6898 pendingphase = phases.public
6895 pendingphase = phases.public
6899
6896
6900 if pendingphase > phases.newcommitphase(ui):
6897 if pendingphase > phases.newcommitphase(ui):
6901 t += b' (%s)' % phases.phasenames[pendingphase]
6898 t += b' (%s)' % phases.phasenames[pendingphase]
6902
6899
6903 if cleanworkdir:
6900 if cleanworkdir:
6904 # i18n: column positioning for "hg summary"
6901 # i18n: column positioning for "hg summary"
6905 ui.status(_(b'commit: %s\n') % t.strip())
6902 ui.status(_(b'commit: %s\n') % t.strip())
6906 else:
6903 else:
6907 # i18n: column positioning for "hg summary"
6904 # i18n: column positioning for "hg summary"
6908 ui.write(_(b'commit: %s\n') % t.strip())
6905 ui.write(_(b'commit: %s\n') % t.strip())
6909
6906
6910 # all ancestors of branch heads - all ancestors of parent = new csets
6907 # all ancestors of branch heads - all ancestors of parent = new csets
6911 new = len(
6908 new = len(
6912 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6909 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6913 )
6910 )
6914
6911
6915 if new == 0:
6912 if new == 0:
6916 # i18n: column positioning for "hg summary"
6913 # i18n: column positioning for "hg summary"
6917 ui.status(_(b'update: (current)\n'))
6914 ui.status(_(b'update: (current)\n'))
6918 elif pnode not in bheads:
6915 elif pnode not in bheads:
6919 # i18n: column positioning for "hg summary"
6916 # i18n: column positioning for "hg summary"
6920 ui.write(_(b'update: %d new changesets (update)\n') % new)
6917 ui.write(_(b'update: %d new changesets (update)\n') % new)
6921 else:
6918 else:
6922 # i18n: column positioning for "hg summary"
6919 # i18n: column positioning for "hg summary"
6923 ui.write(
6920 ui.write(
6924 _(b'update: %d new changesets, %d branch heads (merge)\n')
6921 _(b'update: %d new changesets, %d branch heads (merge)\n')
6925 % (new, len(bheads))
6922 % (new, len(bheads))
6926 )
6923 )
6927
6924
6928 t = []
6925 t = []
6929 draft = len(repo.revs(b'draft()'))
6926 draft = len(repo.revs(b'draft()'))
6930 if draft:
6927 if draft:
6931 t.append(_(b'%d draft') % draft)
6928 t.append(_(b'%d draft') % draft)
6932 secret = len(repo.revs(b'secret()'))
6929 secret = len(repo.revs(b'secret()'))
6933 if secret:
6930 if secret:
6934 t.append(_(b'%d secret') % secret)
6931 t.append(_(b'%d secret') % secret)
6935
6932
6936 if draft or secret:
6933 if draft or secret:
6937 ui.status(_(b'phases: %s\n') % b', '.join(t))
6934 ui.status(_(b'phases: %s\n') % b', '.join(t))
6938
6935
6939 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6936 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6940 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6937 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
6941 numtrouble = len(repo.revs(trouble + b"()"))
6938 numtrouble = len(repo.revs(trouble + b"()"))
6942 # We write all the possibilities to ease translation
6939 # We write all the possibilities to ease translation
6943 troublemsg = {
6940 troublemsg = {
6944 b"orphan": _(b"orphan: %d changesets"),
6941 b"orphan": _(b"orphan: %d changesets"),
6945 b"contentdivergent": _(b"content-divergent: %d changesets"),
6942 b"contentdivergent": _(b"content-divergent: %d changesets"),
6946 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6943 b"phasedivergent": _(b"phase-divergent: %d changesets"),
6947 }
6944 }
6948 if numtrouble > 0:
6945 if numtrouble > 0:
6949 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6946 ui.status(troublemsg[trouble] % numtrouble + b"\n")
6950
6947
6951 cmdutil.summaryhooks(ui, repo)
6948 cmdutil.summaryhooks(ui, repo)
6952
6949
6953 if opts.get(b'remote'):
6950 if opts.get(b'remote'):
6954 needsincoming, needsoutgoing = True, True
6951 needsincoming, needsoutgoing = True, True
6955 else:
6952 else:
6956 needsincoming, needsoutgoing = False, False
6953 needsincoming, needsoutgoing = False, False
6957 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6954 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6958 if i:
6955 if i:
6959 needsincoming = True
6956 needsincoming = True
6960 if o:
6957 if o:
6961 needsoutgoing = True
6958 needsoutgoing = True
6962 if not needsincoming and not needsoutgoing:
6959 if not needsincoming and not needsoutgoing:
6963 return
6960 return
6964
6961
6965 def getincoming():
6962 def getincoming():
6966 source, branches = hg.parseurl(ui.expandpath(b'default'))
6963 source, branches = hg.parseurl(ui.expandpath(b'default'))
6967 sbranch = branches[0]
6964 sbranch = branches[0]
6968 try:
6965 try:
6969 other = hg.peer(repo, {}, source)
6966 other = hg.peer(repo, {}, source)
6970 except error.RepoError:
6967 except error.RepoError:
6971 if opts.get(b'remote'):
6968 if opts.get(b'remote'):
6972 raise
6969 raise
6973 return source, sbranch, None, None, None
6970 return source, sbranch, None, None, None
6974 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6971 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6975 if revs:
6972 if revs:
6976 revs = [other.lookup(rev) for rev in revs]
6973 revs = [other.lookup(rev) for rev in revs]
6977 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
6974 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
6978 repo.ui.pushbuffer()
6975 repo.ui.pushbuffer()
6979 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6976 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6980 repo.ui.popbuffer()
6977 repo.ui.popbuffer()
6981 return source, sbranch, other, commoninc, commoninc[1]
6978 return source, sbranch, other, commoninc, commoninc[1]
6982
6979
6983 if needsincoming:
6980 if needsincoming:
6984 source, sbranch, sother, commoninc, incoming = getincoming()
6981 source, sbranch, sother, commoninc, incoming = getincoming()
6985 else:
6982 else:
6986 source = sbranch = sother = commoninc = incoming = None
6983 source = sbranch = sother = commoninc = incoming = None
6987
6984
6988 def getoutgoing():
6985 def getoutgoing():
6989 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
6986 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
6990 dbranch = branches[0]
6987 dbranch = branches[0]
6991 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6988 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6992 if source != dest:
6989 if source != dest:
6993 try:
6990 try:
6994 dother = hg.peer(repo, {}, dest)
6991 dother = hg.peer(repo, {}, dest)
6995 except error.RepoError:
6992 except error.RepoError:
6996 if opts.get(b'remote'):
6993 if opts.get(b'remote'):
6997 raise
6994 raise
6998 return dest, dbranch, None, None
6995 return dest, dbranch, None, None
6999 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
6996 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7000 elif sother is None:
6997 elif sother is None:
7001 # there is no explicit destination peer, but source one is invalid
6998 # there is no explicit destination peer, but source one is invalid
7002 return dest, dbranch, None, None
6999 return dest, dbranch, None, None
7003 else:
7000 else:
7004 dother = sother
7001 dother = sother
7005 if source != dest or (sbranch is not None and sbranch != dbranch):
7002 if source != dest or (sbranch is not None and sbranch != dbranch):
7006 common = None
7003 common = None
7007 else:
7004 else:
7008 common = commoninc
7005 common = commoninc
7009 if revs:
7006 if revs:
7010 revs = [repo.lookup(rev) for rev in revs]
7007 revs = [repo.lookup(rev) for rev in revs]
7011 repo.ui.pushbuffer()
7008 repo.ui.pushbuffer()
7012 outgoing = discovery.findcommonoutgoing(
7009 outgoing = discovery.findcommonoutgoing(
7013 repo, dother, onlyheads=revs, commoninc=common
7010 repo, dother, onlyheads=revs, commoninc=common
7014 )
7011 )
7015 repo.ui.popbuffer()
7012 repo.ui.popbuffer()
7016 return dest, dbranch, dother, outgoing
7013 return dest, dbranch, dother, outgoing
7017
7014
7018 if needsoutgoing:
7015 if needsoutgoing:
7019 dest, dbranch, dother, outgoing = getoutgoing()
7016 dest, dbranch, dother, outgoing = getoutgoing()
7020 else:
7017 else:
7021 dest = dbranch = dother = outgoing = None
7018 dest = dbranch = dother = outgoing = None
7022
7019
7023 if opts.get(b'remote'):
7020 if opts.get(b'remote'):
7024 t = []
7021 t = []
7025 if incoming:
7022 if incoming:
7026 t.append(_(b'1 or more incoming'))
7023 t.append(_(b'1 or more incoming'))
7027 o = outgoing.missing
7024 o = outgoing.missing
7028 if o:
7025 if o:
7029 t.append(_(b'%d outgoing') % len(o))
7026 t.append(_(b'%d outgoing') % len(o))
7030 other = dother or sother
7027 other = dother or sother
7031 if b'bookmarks' in other.listkeys(b'namespaces'):
7028 if b'bookmarks' in other.listkeys(b'namespaces'):
7032 counts = bookmarks.summary(repo, other)
7029 counts = bookmarks.summary(repo, other)
7033 if counts[0] > 0:
7030 if counts[0] > 0:
7034 t.append(_(b'%d incoming bookmarks') % counts[0])
7031 t.append(_(b'%d incoming bookmarks') % counts[0])
7035 if counts[1] > 0:
7032 if counts[1] > 0:
7036 t.append(_(b'%d outgoing bookmarks') % counts[1])
7033 t.append(_(b'%d outgoing bookmarks') % counts[1])
7037
7034
7038 if t:
7035 if t:
7039 # i18n: column positioning for "hg summary"
7036 # i18n: column positioning for "hg summary"
7040 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7037 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7041 else:
7038 else:
7042 # i18n: column positioning for "hg summary"
7039 # i18n: column positioning for "hg summary"
7043 ui.status(_(b'remote: (synced)\n'))
7040 ui.status(_(b'remote: (synced)\n'))
7044
7041
7045 cmdutil.summaryremotehooks(
7042 cmdutil.summaryremotehooks(
7046 ui,
7043 ui,
7047 repo,
7044 repo,
7048 opts,
7045 opts,
7049 (
7046 (
7050 (source, sbranch, sother, commoninc),
7047 (source, sbranch, sother, commoninc),
7051 (dest, dbranch, dother, outgoing),
7048 (dest, dbranch, dother, outgoing),
7052 ),
7049 ),
7053 )
7050 )
7054
7051
7055
7052
7056 @command(
7053 @command(
7057 b'tag',
7054 b'tag',
7058 [
7055 [
7059 (b'f', b'force', None, _(b'force tag')),
7056 (b'f', b'force', None, _(b'force tag')),
7060 (b'l', b'local', None, _(b'make the tag local')),
7057 (b'l', b'local', None, _(b'make the tag local')),
7061 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7058 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7062 (b'', b'remove', None, _(b'remove a tag')),
7059 (b'', b'remove', None, _(b'remove a tag')),
7063 # -l/--local is already there, commitopts cannot be used
7060 # -l/--local is already there, commitopts cannot be used
7064 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7061 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7065 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7062 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7066 ]
7063 ]
7067 + commitopts2,
7064 + commitopts2,
7068 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7065 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7069 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7066 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7070 )
7067 )
7071 def tag(ui, repo, name1, *names, **opts):
7068 def tag(ui, repo, name1, *names, **opts):
7072 """add one or more tags for the current or given revision
7069 """add one or more tags for the current or given revision
7073
7070
7074 Name a particular revision using <name>.
7071 Name a particular revision using <name>.
7075
7072
7076 Tags are used to name particular revisions of the repository and are
7073 Tags are used to name particular revisions of the repository and are
7077 very useful to compare different revisions, to go back to significant
7074 very useful to compare different revisions, to go back to significant
7078 earlier versions or to mark branch points as releases, etc. Changing
7075 earlier versions or to mark branch points as releases, etc. Changing
7079 an existing tag is normally disallowed; use -f/--force to override.
7076 an existing tag is normally disallowed; use -f/--force to override.
7080
7077
7081 If no revision is given, the parent of the working directory is
7078 If no revision is given, the parent of the working directory is
7082 used.
7079 used.
7083
7080
7084 To facilitate version control, distribution, and merging of tags,
7081 To facilitate version control, distribution, and merging of tags,
7085 they are stored as a file named ".hgtags" which is managed similarly
7082 they are stored as a file named ".hgtags" which is managed similarly
7086 to other project files and can be hand-edited if necessary. This
7083 to other project files and can be hand-edited if necessary. This
7087 also means that tagging creates a new commit. The file
7084 also means that tagging creates a new commit. The file
7088 ".hg/localtags" is used for local tags (not shared among
7085 ".hg/localtags" is used for local tags (not shared among
7089 repositories).
7086 repositories).
7090
7087
7091 Tag commits are usually made at the head of a branch. If the parent
7088 Tag commits are usually made at the head of a branch. If the parent
7092 of the working directory is not a branch head, :hg:`tag` aborts; use
7089 of the working directory is not a branch head, :hg:`tag` aborts; use
7093 -f/--force to force the tag commit to be based on a non-head
7090 -f/--force to force the tag commit to be based on a non-head
7094 changeset.
7091 changeset.
7095
7092
7096 See :hg:`help dates` for a list of formats valid for -d/--date.
7093 See :hg:`help dates` for a list of formats valid for -d/--date.
7097
7094
7098 Since tag names have priority over branch names during revision
7095 Since tag names have priority over branch names during revision
7099 lookup, using an existing branch name as a tag name is discouraged.
7096 lookup, using an existing branch name as a tag name is discouraged.
7100
7097
7101 Returns 0 on success.
7098 Returns 0 on success.
7102 """
7099 """
7103 opts = pycompat.byteskwargs(opts)
7100 opts = pycompat.byteskwargs(opts)
7104 with repo.wlock(), repo.lock():
7101 with repo.wlock(), repo.lock():
7105 rev_ = b"."
7102 rev_ = b"."
7106 names = [t.strip() for t in (name1,) + names]
7103 names = [t.strip() for t in (name1,) + names]
7107 if len(names) != len(set(names)):
7104 if len(names) != len(set(names)):
7108 raise error.Abort(_(b'tag names must be unique'))
7105 raise error.Abort(_(b'tag names must be unique'))
7109 for n in names:
7106 for n in names:
7110 scmutil.checknewlabel(repo, n, b'tag')
7107 scmutil.checknewlabel(repo, n, b'tag')
7111 if not n:
7108 if not n:
7112 raise error.Abort(
7109 raise error.Abort(
7113 _(b'tag names cannot consist entirely of whitespace')
7110 _(b'tag names cannot consist entirely of whitespace')
7114 )
7111 )
7115 if opts.get(b'rev') and opts.get(b'remove'):
7112 if opts.get(b'rev') and opts.get(b'remove'):
7116 raise error.Abort(_(b"--rev and --remove are incompatible"))
7113 raise error.Abort(_(b"--rev and --remove are incompatible"))
7117 if opts.get(b'rev'):
7114 if opts.get(b'rev'):
7118 rev_ = opts[b'rev']
7115 rev_ = opts[b'rev']
7119 message = opts.get(b'message')
7116 message = opts.get(b'message')
7120 if opts.get(b'remove'):
7117 if opts.get(b'remove'):
7121 if opts.get(b'local'):
7118 if opts.get(b'local'):
7122 expectedtype = b'local'
7119 expectedtype = b'local'
7123 else:
7120 else:
7124 expectedtype = b'global'
7121 expectedtype = b'global'
7125
7122
7126 for n in names:
7123 for n in names:
7127 if repo.tagtype(n) == b'global':
7124 if repo.tagtype(n) == b'global':
7128 alltags = tagsmod.findglobaltags(ui, repo)
7125 alltags = tagsmod.findglobaltags(ui, repo)
7129 if alltags[n][0] == nullid:
7126 if alltags[n][0] == nullid:
7130 raise error.Abort(_(b"tag '%s' is already removed") % n)
7127 raise error.Abort(_(b"tag '%s' is already removed") % n)
7131 if not repo.tagtype(n):
7128 if not repo.tagtype(n):
7132 raise error.Abort(_(b"tag '%s' does not exist") % n)
7129 raise error.Abort(_(b"tag '%s' does not exist") % n)
7133 if repo.tagtype(n) != expectedtype:
7130 if repo.tagtype(n) != expectedtype:
7134 if expectedtype == b'global':
7131 if expectedtype == b'global':
7135 raise error.Abort(
7132 raise error.Abort(
7136 _(b"tag '%s' is not a global tag") % n
7133 _(b"tag '%s' is not a global tag") % n
7137 )
7134 )
7138 else:
7135 else:
7139 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7136 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7140 rev_ = b'null'
7137 rev_ = b'null'
7141 if not message:
7138 if not message:
7142 # we don't translate commit messages
7139 # we don't translate commit messages
7143 message = b'Removed tag %s' % b', '.join(names)
7140 message = b'Removed tag %s' % b', '.join(names)
7144 elif not opts.get(b'force'):
7141 elif not opts.get(b'force'):
7145 for n in names:
7142 for n in names:
7146 if n in repo.tags():
7143 if n in repo.tags():
7147 raise error.Abort(
7144 raise error.Abort(
7148 _(b"tag '%s' already exists (use -f to force)") % n
7145 _(b"tag '%s' already exists (use -f to force)") % n
7149 )
7146 )
7150 if not opts.get(b'local'):
7147 if not opts.get(b'local'):
7151 p1, p2 = repo.dirstate.parents()
7148 p1, p2 = repo.dirstate.parents()
7152 if p2 != nullid:
7149 if p2 != nullid:
7153 raise error.Abort(_(b'uncommitted merge'))
7150 raise error.Abort(_(b'uncommitted merge'))
7154 bheads = repo.branchheads()
7151 bheads = repo.branchheads()
7155 if not opts.get(b'force') and bheads and p1 not in bheads:
7152 if not opts.get(b'force') and bheads and p1 not in bheads:
7156 raise error.Abort(
7153 raise error.Abort(
7157 _(
7154 _(
7158 b'working directory is not at a branch head '
7155 b'working directory is not at a branch head '
7159 b'(use -f to force)'
7156 b'(use -f to force)'
7160 )
7157 )
7161 )
7158 )
7162 node = scmutil.revsingle(repo, rev_).node()
7159 node = scmutil.revsingle(repo, rev_).node()
7163
7160
7164 if not message:
7161 if not message:
7165 # we don't translate commit messages
7162 # we don't translate commit messages
7166 message = b'Added tag %s for changeset %s' % (
7163 message = b'Added tag %s for changeset %s' % (
7167 b', '.join(names),
7164 b', '.join(names),
7168 short(node),
7165 short(node),
7169 )
7166 )
7170
7167
7171 date = opts.get(b'date')
7168 date = opts.get(b'date')
7172 if date:
7169 if date:
7173 date = dateutil.parsedate(date)
7170 date = dateutil.parsedate(date)
7174
7171
7175 if opts.get(b'remove'):
7172 if opts.get(b'remove'):
7176 editform = b'tag.remove'
7173 editform = b'tag.remove'
7177 else:
7174 else:
7178 editform = b'tag.add'
7175 editform = b'tag.add'
7179 editor = cmdutil.getcommiteditor(
7176 editor = cmdutil.getcommiteditor(
7180 editform=editform, **pycompat.strkwargs(opts)
7177 editform=editform, **pycompat.strkwargs(opts)
7181 )
7178 )
7182
7179
7183 # don't allow tagging the null rev
7180 # don't allow tagging the null rev
7184 if (
7181 if (
7185 not opts.get(b'remove')
7182 not opts.get(b'remove')
7186 and scmutil.revsingle(repo, rev_).rev() == nullrev
7183 and scmutil.revsingle(repo, rev_).rev() == nullrev
7187 ):
7184 ):
7188 raise error.Abort(_(b"cannot tag null revision"))
7185 raise error.Abort(_(b"cannot tag null revision"))
7189
7186
7190 tagsmod.tag(
7187 tagsmod.tag(
7191 repo,
7188 repo,
7192 names,
7189 names,
7193 node,
7190 node,
7194 message,
7191 message,
7195 opts.get(b'local'),
7192 opts.get(b'local'),
7196 opts.get(b'user'),
7193 opts.get(b'user'),
7197 date,
7194 date,
7198 editor=editor,
7195 editor=editor,
7199 )
7196 )
7200
7197
7201
7198
7202 @command(
7199 @command(
7203 b'tags',
7200 b'tags',
7204 formatteropts,
7201 formatteropts,
7205 b'',
7202 b'',
7206 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7203 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7207 intents={INTENT_READONLY},
7204 intents={INTENT_READONLY},
7208 )
7205 )
7209 def tags(ui, repo, **opts):
7206 def tags(ui, repo, **opts):
7210 """list repository tags
7207 """list repository tags
7211
7208
7212 This lists both regular and local tags. When the -v/--verbose
7209 This lists both regular and local tags. When the -v/--verbose
7213 switch is used, a third column "local" is printed for local tags.
7210 switch is used, a third column "local" is printed for local tags.
7214 When the -q/--quiet switch is used, only the tag name is printed.
7211 When the -q/--quiet switch is used, only the tag name is printed.
7215
7212
7216 .. container:: verbose
7213 .. container:: verbose
7217
7214
7218 Template:
7215 Template:
7219
7216
7220 The following keywords are supported in addition to the common template
7217 The following keywords are supported in addition to the common template
7221 keywords and functions such as ``{tag}``. See also
7218 keywords and functions such as ``{tag}``. See also
7222 :hg:`help templates`.
7219 :hg:`help templates`.
7223
7220
7224 :type: String. ``local`` for local tags.
7221 :type: String. ``local`` for local tags.
7225
7222
7226 Returns 0 on success.
7223 Returns 0 on success.
7227 """
7224 """
7228
7225
7229 opts = pycompat.byteskwargs(opts)
7226 opts = pycompat.byteskwargs(opts)
7230 ui.pager(b'tags')
7227 ui.pager(b'tags')
7231 fm = ui.formatter(b'tags', opts)
7228 fm = ui.formatter(b'tags', opts)
7232 hexfunc = fm.hexfunc
7229 hexfunc = fm.hexfunc
7233
7230
7234 for t, n in reversed(repo.tagslist()):
7231 for t, n in reversed(repo.tagslist()):
7235 hn = hexfunc(n)
7232 hn = hexfunc(n)
7236 label = b'tags.normal'
7233 label = b'tags.normal'
7237 tagtype = b''
7234 tagtype = b''
7238 if repo.tagtype(t) == b'local':
7235 if repo.tagtype(t) == b'local':
7239 label = b'tags.local'
7236 label = b'tags.local'
7240 tagtype = b'local'
7237 tagtype = b'local'
7241
7238
7242 fm.startitem()
7239 fm.startitem()
7243 fm.context(repo=repo)
7240 fm.context(repo=repo)
7244 fm.write(b'tag', b'%s', t, label=label)
7241 fm.write(b'tag', b'%s', t, label=label)
7245 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7242 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7246 fm.condwrite(
7243 fm.condwrite(
7247 not ui.quiet,
7244 not ui.quiet,
7248 b'rev node',
7245 b'rev node',
7249 fmt,
7246 fmt,
7250 repo.changelog.rev(n),
7247 repo.changelog.rev(n),
7251 hn,
7248 hn,
7252 label=label,
7249 label=label,
7253 )
7250 )
7254 fm.condwrite(
7251 fm.condwrite(
7255 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7252 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7256 )
7253 )
7257 fm.plain(b'\n')
7254 fm.plain(b'\n')
7258 fm.end()
7255 fm.end()
7259
7256
7260
7257
7261 @command(
7258 @command(
7262 b'tip',
7259 b'tip',
7263 [
7260 [
7264 (b'p', b'patch', None, _(b'show patch')),
7261 (b'p', b'patch', None, _(b'show patch')),
7265 (b'g', b'git', None, _(b'use git extended diff format')),
7262 (b'g', b'git', None, _(b'use git extended diff format')),
7266 ]
7263 ]
7267 + templateopts,
7264 + templateopts,
7268 _(b'[-p] [-g]'),
7265 _(b'[-p] [-g]'),
7269 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7266 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7270 )
7267 )
7271 def tip(ui, repo, **opts):
7268 def tip(ui, repo, **opts):
7272 """show the tip revision (DEPRECATED)
7269 """show the tip revision (DEPRECATED)
7273
7270
7274 The tip revision (usually just called the tip) is the changeset
7271 The tip revision (usually just called the tip) is the changeset
7275 most recently added to the repository (and therefore the most
7272 most recently added to the repository (and therefore the most
7276 recently changed head).
7273 recently changed head).
7277
7274
7278 If you have just made a commit, that commit will be the tip. If
7275 If you have just made a commit, that commit will be the tip. If
7279 you have just pulled changes from another repository, the tip of
7276 you have just pulled changes from another repository, the tip of
7280 that repository becomes the current tip. The "tip" tag is special
7277 that repository becomes the current tip. The "tip" tag is special
7281 and cannot be renamed or assigned to a different changeset.
7278 and cannot be renamed or assigned to a different changeset.
7282
7279
7283 This command is deprecated, please use :hg:`heads` instead.
7280 This command is deprecated, please use :hg:`heads` instead.
7284
7281
7285 Returns 0 on success.
7282 Returns 0 on success.
7286 """
7283 """
7287 opts = pycompat.byteskwargs(opts)
7284 opts = pycompat.byteskwargs(opts)
7288 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7285 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7289 displayer.show(repo[b'tip'])
7286 displayer.show(repo[b'tip'])
7290 displayer.close()
7287 displayer.close()
7291
7288
7292
7289
7293 @command(
7290 @command(
7294 b'unbundle',
7291 b'unbundle',
7295 [
7292 [
7296 (
7293 (
7297 b'u',
7294 b'u',
7298 b'update',
7295 b'update',
7299 None,
7296 None,
7300 _(b'update to new branch head if changesets were unbundled'),
7297 _(b'update to new branch head if changesets were unbundled'),
7301 )
7298 )
7302 ],
7299 ],
7303 _(b'[-u] FILE...'),
7300 _(b'[-u] FILE...'),
7304 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7301 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7305 )
7302 )
7306 def unbundle(ui, repo, fname1, *fnames, **opts):
7303 def unbundle(ui, repo, fname1, *fnames, **opts):
7307 """apply one or more bundle files
7304 """apply one or more bundle files
7308
7305
7309 Apply one or more bundle files generated by :hg:`bundle`.
7306 Apply one or more bundle files generated by :hg:`bundle`.
7310
7307
7311 Returns 0 on success, 1 if an update has unresolved files.
7308 Returns 0 on success, 1 if an update has unresolved files.
7312 """
7309 """
7313 fnames = (fname1,) + fnames
7310 fnames = (fname1,) + fnames
7314
7311
7315 with repo.lock():
7312 with repo.lock():
7316 for fname in fnames:
7313 for fname in fnames:
7317 f = hg.openpath(ui, fname)
7314 f = hg.openpath(ui, fname)
7318 gen = exchange.readbundle(ui, f, fname)
7315 gen = exchange.readbundle(ui, f, fname)
7319 if isinstance(gen, streamclone.streamcloneapplier):
7316 if isinstance(gen, streamclone.streamcloneapplier):
7320 raise error.Abort(
7317 raise error.Abort(
7321 _(
7318 _(
7322 b'packed bundles cannot be applied with '
7319 b'packed bundles cannot be applied with '
7323 b'"hg unbundle"'
7320 b'"hg unbundle"'
7324 ),
7321 ),
7325 hint=_(b'use "hg debugapplystreamclonebundle"'),
7322 hint=_(b'use "hg debugapplystreamclonebundle"'),
7326 )
7323 )
7327 url = b'bundle:' + fname
7324 url = b'bundle:' + fname
7328 try:
7325 try:
7329 txnname = b'unbundle'
7326 txnname = b'unbundle'
7330 if not isinstance(gen, bundle2.unbundle20):
7327 if not isinstance(gen, bundle2.unbundle20):
7331 txnname = b'unbundle\n%s' % util.hidepassword(url)
7328 txnname = b'unbundle\n%s' % util.hidepassword(url)
7332 with repo.transaction(txnname) as tr:
7329 with repo.transaction(txnname) as tr:
7333 op = bundle2.applybundle(
7330 op = bundle2.applybundle(
7334 repo, gen, tr, source=b'unbundle', url=url
7331 repo, gen, tr, source=b'unbundle', url=url
7335 )
7332 )
7336 except error.BundleUnknownFeatureError as exc:
7333 except error.BundleUnknownFeatureError as exc:
7337 raise error.Abort(
7334 raise error.Abort(
7338 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7335 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7339 hint=_(
7336 hint=_(
7340 b"see https://mercurial-scm.org/"
7337 b"see https://mercurial-scm.org/"
7341 b"wiki/BundleFeature for more "
7338 b"wiki/BundleFeature for more "
7342 b"information"
7339 b"information"
7343 ),
7340 ),
7344 )
7341 )
7345 modheads = bundle2.combinechangegroupresults(op)
7342 modheads = bundle2.combinechangegroupresults(op)
7346
7343
7347 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7344 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7348
7345
7349
7346
7350 @command(
7347 @command(
7351 b'unshelve',
7348 b'unshelve',
7352 [
7349 [
7353 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7350 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7354 (
7351 (
7355 b'c',
7352 b'c',
7356 b'continue',
7353 b'continue',
7357 None,
7354 None,
7358 _(b'continue an incomplete unshelve operation'),
7355 _(b'continue an incomplete unshelve operation'),
7359 ),
7356 ),
7360 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7357 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7361 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7358 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7362 (
7359 (
7363 b'n',
7360 b'n',
7364 b'name',
7361 b'name',
7365 b'',
7362 b'',
7366 _(b'restore shelved change with given name'),
7363 _(b'restore shelved change with given name'),
7367 _(b'NAME'),
7364 _(b'NAME'),
7368 ),
7365 ),
7369 (b't', b'tool', b'', _(b'specify merge tool')),
7366 (b't', b'tool', b'', _(b'specify merge tool')),
7370 (
7367 (
7371 b'',
7368 b'',
7372 b'date',
7369 b'date',
7373 b'',
7370 b'',
7374 _(b'set date for temporary commits (DEPRECATED)'),
7371 _(b'set date for temporary commits (DEPRECATED)'),
7375 _(b'DATE'),
7372 _(b'DATE'),
7376 ),
7373 ),
7377 ],
7374 ],
7378 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7375 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7379 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7376 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7380 )
7377 )
7381 def unshelve(ui, repo, *shelved, **opts):
7378 def unshelve(ui, repo, *shelved, **opts):
7382 """restore a shelved change to the working directory
7379 """restore a shelved change to the working directory
7383
7380
7384 This command accepts an optional name of a shelved change to
7381 This command accepts an optional name of a shelved change to
7385 restore. If none is given, the most recent shelved change is used.
7382 restore. If none is given, the most recent shelved change is used.
7386
7383
7387 If a shelved change is applied successfully, the bundle that
7384 If a shelved change is applied successfully, the bundle that
7388 contains the shelved changes is moved to a backup location
7385 contains the shelved changes is moved to a backup location
7389 (.hg/shelve-backup).
7386 (.hg/shelve-backup).
7390
7387
7391 Since you can restore a shelved change on top of an arbitrary
7388 Since you can restore a shelved change on top of an arbitrary
7392 commit, it is possible that unshelving will result in a conflict
7389 commit, it is possible that unshelving will result in a conflict
7393 between your changes and the commits you are unshelving onto. If
7390 between your changes and the commits you are unshelving onto. If
7394 this occurs, you must resolve the conflict, then use
7391 this occurs, you must resolve the conflict, then use
7395 ``--continue`` to complete the unshelve operation. (The bundle
7392 ``--continue`` to complete the unshelve operation. (The bundle
7396 will not be moved until you successfully complete the unshelve.)
7393 will not be moved until you successfully complete the unshelve.)
7397
7394
7398 (Alternatively, you can use ``--abort`` to abandon an unshelve
7395 (Alternatively, you can use ``--abort`` to abandon an unshelve
7399 that causes a conflict. This reverts the unshelved changes, and
7396 that causes a conflict. This reverts the unshelved changes, and
7400 leaves the bundle in place.)
7397 leaves the bundle in place.)
7401
7398
7402 If bare shelved change (without interactive, include and exclude
7399 If bare shelved change (without interactive, include and exclude
7403 option) was done on newly created branch it would restore branch
7400 option) was done on newly created branch it would restore branch
7404 information to the working directory.
7401 information to the working directory.
7405
7402
7406 After a successful unshelve, the shelved changes are stored in a
7403 After a successful unshelve, the shelved changes are stored in a
7407 backup directory. Only the N most recent backups are kept. N
7404 backup directory. Only the N most recent backups are kept. N
7408 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7405 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7409 configuration option.
7406 configuration option.
7410
7407
7411 .. container:: verbose
7408 .. container:: verbose
7412
7409
7413 Timestamp in seconds is used to decide order of backups. More
7410 Timestamp in seconds is used to decide order of backups. More
7414 than ``maxbackups`` backups are kept, if same timestamp
7411 than ``maxbackups`` backups are kept, if same timestamp
7415 prevents from deciding exact order of them, for safety.
7412 prevents from deciding exact order of them, for safety.
7416
7413
7417 Selected changes can be unshelved with ``--interactive`` flag.
7414 Selected changes can be unshelved with ``--interactive`` flag.
7418 The working directory is updated with the selected changes, and
7415 The working directory is updated with the selected changes, and
7419 only the unselected changes remain shelved.
7416 only the unselected changes remain shelved.
7420 Note: The whole shelve is applied to working directory first before
7417 Note: The whole shelve is applied to working directory first before
7421 running interactively. So, this will bring up all the conflicts between
7418 running interactively. So, this will bring up all the conflicts between
7422 working directory and the shelve, irrespective of which changes will be
7419 working directory and the shelve, irrespective of which changes will be
7423 unshelved.
7420 unshelved.
7424 """
7421 """
7425 with repo.wlock():
7422 with repo.wlock():
7426 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7423 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7427
7424
7428
7425
7429 statemod.addunfinished(
7426 statemod.addunfinished(
7430 b'unshelve',
7427 b'unshelve',
7431 fname=b'shelvedstate',
7428 fname=b'shelvedstate',
7432 continueflag=True,
7429 continueflag=True,
7433 abortfunc=shelvemod.hgabortunshelve,
7430 abortfunc=shelvemod.hgabortunshelve,
7434 continuefunc=shelvemod.hgcontinueunshelve,
7431 continuefunc=shelvemod.hgcontinueunshelve,
7435 cmdmsg=_(b'unshelve already in progress'),
7432 cmdmsg=_(b'unshelve already in progress'),
7436 )
7433 )
7437
7434
7438
7435
7439 @command(
7436 @command(
7440 b'update|up|checkout|co',
7437 b'update|up|checkout|co',
7441 [
7438 [
7442 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7439 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7443 (b'c', b'check', None, _(b'require clean working directory')),
7440 (b'c', b'check', None, _(b'require clean working directory')),
7444 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7441 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7445 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7442 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7446 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7443 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7447 ]
7444 ]
7448 + mergetoolopts,
7445 + mergetoolopts,
7449 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7446 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7450 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7447 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7451 helpbasic=True,
7448 helpbasic=True,
7452 )
7449 )
7453 def update(ui, repo, node=None, **opts):
7450 def update(ui, repo, node=None, **opts):
7454 """update working directory (or switch revisions)
7451 """update working directory (or switch revisions)
7455
7452
7456 Update the repository's working directory to the specified
7453 Update the repository's working directory to the specified
7457 changeset. If no changeset is specified, update to the tip of the
7454 changeset. If no changeset is specified, update to the tip of the
7458 current named branch and move the active bookmark (see :hg:`help
7455 current named branch and move the active bookmark (see :hg:`help
7459 bookmarks`).
7456 bookmarks`).
7460
7457
7461 Update sets the working directory's parent revision to the specified
7458 Update sets the working directory's parent revision to the specified
7462 changeset (see :hg:`help parents`).
7459 changeset (see :hg:`help parents`).
7463
7460
7464 If the changeset is not a descendant or ancestor of the working
7461 If the changeset is not a descendant or ancestor of the working
7465 directory's parent and there are uncommitted changes, the update is
7462 directory's parent and there are uncommitted changes, the update is
7466 aborted. With the -c/--check option, the working directory is checked
7463 aborted. With the -c/--check option, the working directory is checked
7467 for uncommitted changes; if none are found, the working directory is
7464 for uncommitted changes; if none are found, the working directory is
7468 updated to the specified changeset.
7465 updated to the specified changeset.
7469
7466
7470 .. container:: verbose
7467 .. container:: verbose
7471
7468
7472 The -C/--clean, -c/--check, and -m/--merge options control what
7469 The -C/--clean, -c/--check, and -m/--merge options control what
7473 happens if the working directory contains uncommitted changes.
7470 happens if the working directory contains uncommitted changes.
7474 At most of one of them can be specified.
7471 At most of one of them can be specified.
7475
7472
7476 1. If no option is specified, and if
7473 1. If no option is specified, and if
7477 the requested changeset is an ancestor or descendant of
7474 the requested changeset is an ancestor or descendant of
7478 the working directory's parent, the uncommitted changes
7475 the working directory's parent, the uncommitted changes
7479 are merged into the requested changeset and the merged
7476 are merged into the requested changeset and the merged
7480 result is left uncommitted. If the requested changeset is
7477 result is left uncommitted. If the requested changeset is
7481 not an ancestor or descendant (that is, it is on another
7478 not an ancestor or descendant (that is, it is on another
7482 branch), the update is aborted and the uncommitted changes
7479 branch), the update is aborted and the uncommitted changes
7483 are preserved.
7480 are preserved.
7484
7481
7485 2. With the -m/--merge option, the update is allowed even if the
7482 2. With the -m/--merge option, the update is allowed even if the
7486 requested changeset is not an ancestor or descendant of
7483 requested changeset is not an ancestor or descendant of
7487 the working directory's parent.
7484 the working directory's parent.
7488
7485
7489 3. With the -c/--check option, the update is aborted and the
7486 3. With the -c/--check option, the update is aborted and the
7490 uncommitted changes are preserved.
7487 uncommitted changes are preserved.
7491
7488
7492 4. With the -C/--clean option, uncommitted changes are discarded and
7489 4. With the -C/--clean option, uncommitted changes are discarded and
7493 the working directory is updated to the requested changeset.
7490 the working directory is updated to the requested changeset.
7494
7491
7495 To cancel an uncommitted merge (and lose your changes), use
7492 To cancel an uncommitted merge (and lose your changes), use
7496 :hg:`merge --abort`.
7493 :hg:`merge --abort`.
7497
7494
7498 Use null as the changeset to remove the working directory (like
7495 Use null as the changeset to remove the working directory (like
7499 :hg:`clone -U`).
7496 :hg:`clone -U`).
7500
7497
7501 If you want to revert just one file to an older revision, use
7498 If you want to revert just one file to an older revision, use
7502 :hg:`revert [-r REV] NAME`.
7499 :hg:`revert [-r REV] NAME`.
7503
7500
7504 See :hg:`help dates` for a list of formats valid for -d/--date.
7501 See :hg:`help dates` for a list of formats valid for -d/--date.
7505
7502
7506 Returns 0 on success, 1 if there are unresolved files.
7503 Returns 0 on success, 1 if there are unresolved files.
7507 """
7504 """
7508 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7505 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7509 rev = opts.get('rev')
7506 rev = opts.get('rev')
7510 date = opts.get('date')
7507 date = opts.get('date')
7511 clean = opts.get('clean')
7508 clean = opts.get('clean')
7512 check = opts.get('check')
7509 check = opts.get('check')
7513 merge = opts.get('merge')
7510 merge = opts.get('merge')
7514 if rev and node:
7511 if rev and node:
7515 raise error.Abort(_(b"please specify just one revision"))
7512 raise error.Abort(_(b"please specify just one revision"))
7516
7513
7517 if ui.configbool(b'commands', b'update.requiredest'):
7514 if ui.configbool(b'commands', b'update.requiredest'):
7518 if not node and not rev and not date:
7515 if not node and not rev and not date:
7519 raise error.Abort(
7516 raise error.Abort(
7520 _(b'you must specify a destination'),
7517 _(b'you must specify a destination'),
7521 hint=_(b'for example: hg update ".::"'),
7518 hint=_(b'for example: hg update ".::"'),
7522 )
7519 )
7523
7520
7524 if rev is None or rev == b'':
7521 if rev is None or rev == b'':
7525 rev = node
7522 rev = node
7526
7523
7527 if date and rev is not None:
7524 if date and rev is not None:
7528 raise error.Abort(_(b"you can't specify a revision and a date"))
7525 raise error.Abort(_(b"you can't specify a revision and a date"))
7529
7526
7530 updatecheck = None
7527 updatecheck = None
7531 if check:
7528 if check:
7532 updatecheck = b'abort'
7529 updatecheck = b'abort'
7533 elif merge:
7530 elif merge:
7534 updatecheck = b'none'
7531 updatecheck = b'none'
7535
7532
7536 with repo.wlock():
7533 with repo.wlock():
7537 cmdutil.clearunfinished(repo)
7534 cmdutil.clearunfinished(repo)
7538 if date:
7535 if date:
7539 rev = cmdutil.finddate(ui, repo, date)
7536 rev = cmdutil.finddate(ui, repo, date)
7540
7537
7541 # if we defined a bookmark, we have to remember the original name
7538 # if we defined a bookmark, we have to remember the original name
7542 brev = rev
7539 brev = rev
7543 if rev:
7540 if rev:
7544 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7541 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7545 ctx = scmutil.revsingle(repo, rev, default=None)
7542 ctx = scmutil.revsingle(repo, rev, default=None)
7546 rev = ctx.rev()
7543 rev = ctx.rev()
7547 hidden = ctx.hidden()
7544 hidden = ctx.hidden()
7548 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7545 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7549 with ui.configoverride(overrides, b'update'):
7546 with ui.configoverride(overrides, b'update'):
7550 ret = hg.updatetotally(
7547 ret = hg.updatetotally(
7551 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7548 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7552 )
7549 )
7553 if hidden:
7550 if hidden:
7554 ctxstr = ctx.hex()[:12]
7551 ctxstr = ctx.hex()[:12]
7555 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7552 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7556
7553
7557 if ctx.obsolete():
7554 if ctx.obsolete():
7558 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7555 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7559 ui.warn(b"(%s)\n" % obsfatemsg)
7556 ui.warn(b"(%s)\n" % obsfatemsg)
7560 return ret
7557 return ret
7561
7558
7562
7559
7563 @command(
7560 @command(
7564 b'verify',
7561 b'verify',
7565 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7562 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7566 helpcategory=command.CATEGORY_MAINTENANCE,
7563 helpcategory=command.CATEGORY_MAINTENANCE,
7567 )
7564 )
7568 def verify(ui, repo, **opts):
7565 def verify(ui, repo, **opts):
7569 """verify the integrity of the repository
7566 """verify the integrity of the repository
7570
7567
7571 Verify the integrity of the current repository.
7568 Verify the integrity of the current repository.
7572
7569
7573 This will perform an extensive check of the repository's
7570 This will perform an extensive check of the repository's
7574 integrity, validating the hashes and checksums of each entry in
7571 integrity, validating the hashes and checksums of each entry in
7575 the changelog, manifest, and tracked files, as well as the
7572 the changelog, manifest, and tracked files, as well as the
7576 integrity of their crosslinks and indices.
7573 integrity of their crosslinks and indices.
7577
7574
7578 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7575 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7579 for more information about recovery from corruption of the
7576 for more information about recovery from corruption of the
7580 repository.
7577 repository.
7581
7578
7582 Returns 0 on success, 1 if errors are encountered.
7579 Returns 0 on success, 1 if errors are encountered.
7583 """
7580 """
7584 opts = pycompat.byteskwargs(opts)
7581 opts = pycompat.byteskwargs(opts)
7585
7582
7586 level = None
7583 level = None
7587 if opts[b'full']:
7584 if opts[b'full']:
7588 level = verifymod.VERIFY_FULL
7585 level = verifymod.VERIFY_FULL
7589 return hg.verify(repo, level)
7586 return hg.verify(repo, level)
7590
7587
7591
7588
7592 @command(
7589 @command(
7593 b'version',
7590 b'version',
7594 [] + formatteropts,
7591 [] + formatteropts,
7595 helpcategory=command.CATEGORY_HELP,
7592 helpcategory=command.CATEGORY_HELP,
7596 norepo=True,
7593 norepo=True,
7597 intents={INTENT_READONLY},
7594 intents={INTENT_READONLY},
7598 )
7595 )
7599 def version_(ui, **opts):
7596 def version_(ui, **opts):
7600 """output version and copyright information
7597 """output version and copyright information
7601
7598
7602 .. container:: verbose
7599 .. container:: verbose
7603
7600
7604 Template:
7601 Template:
7605
7602
7606 The following keywords are supported. See also :hg:`help templates`.
7603 The following keywords are supported. See also :hg:`help templates`.
7607
7604
7608 :extensions: List of extensions.
7605 :extensions: List of extensions.
7609 :ver: String. Version number.
7606 :ver: String. Version number.
7610
7607
7611 And each entry of ``{extensions}`` provides the following sub-keywords
7608 And each entry of ``{extensions}`` provides the following sub-keywords
7612 in addition to ``{ver}``.
7609 in addition to ``{ver}``.
7613
7610
7614 :bundled: Boolean. True if included in the release.
7611 :bundled: Boolean. True if included in the release.
7615 :name: String. Extension name.
7612 :name: String. Extension name.
7616 """
7613 """
7617 opts = pycompat.byteskwargs(opts)
7614 opts = pycompat.byteskwargs(opts)
7618 if ui.verbose:
7615 if ui.verbose:
7619 ui.pager(b'version')
7616 ui.pager(b'version')
7620 fm = ui.formatter(b"version", opts)
7617 fm = ui.formatter(b"version", opts)
7621 fm.startitem()
7618 fm.startitem()
7622 fm.write(
7619 fm.write(
7623 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7620 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7624 )
7621 )
7625 license = _(
7622 license = _(
7626 b"(see https://mercurial-scm.org for more information)\n"
7623 b"(see https://mercurial-scm.org for more information)\n"
7627 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7624 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7628 b"This is free software; see the source for copying conditions. "
7625 b"This is free software; see the source for copying conditions. "
7629 b"There is NO\nwarranty; "
7626 b"There is NO\nwarranty; "
7630 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7627 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7631 )
7628 )
7632 if not ui.quiet:
7629 if not ui.quiet:
7633 fm.plain(license)
7630 fm.plain(license)
7634
7631
7635 if ui.verbose:
7632 if ui.verbose:
7636 fm.plain(_(b"\nEnabled extensions:\n\n"))
7633 fm.plain(_(b"\nEnabled extensions:\n\n"))
7637 # format names and versions into columns
7634 # format names and versions into columns
7638 names = []
7635 names = []
7639 vers = []
7636 vers = []
7640 isinternals = []
7637 isinternals = []
7641 for name, module in sorted(extensions.extensions()):
7638 for name, module in sorted(extensions.extensions()):
7642 names.append(name)
7639 names.append(name)
7643 vers.append(extensions.moduleversion(module) or None)
7640 vers.append(extensions.moduleversion(module) or None)
7644 isinternals.append(extensions.ismoduleinternal(module))
7641 isinternals.append(extensions.ismoduleinternal(module))
7645 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7642 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7646 if names:
7643 if names:
7647 namefmt = b" %%-%ds " % max(len(n) for n in names)
7644 namefmt = b" %%-%ds " % max(len(n) for n in names)
7648 places = [_(b"external"), _(b"internal")]
7645 places = [_(b"external"), _(b"internal")]
7649 for n, v, p in zip(names, vers, isinternals):
7646 for n, v, p in zip(names, vers, isinternals):
7650 fn.startitem()
7647 fn.startitem()
7651 fn.condwrite(ui.verbose, b"name", namefmt, n)
7648 fn.condwrite(ui.verbose, b"name", namefmt, n)
7652 if ui.verbose:
7649 if ui.verbose:
7653 fn.plain(b"%s " % places[p])
7650 fn.plain(b"%s " % places[p])
7654 fn.data(bundled=p)
7651 fn.data(bundled=p)
7655 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7652 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7656 if ui.verbose:
7653 if ui.verbose:
7657 fn.plain(b"\n")
7654 fn.plain(b"\n")
7658 fn.end()
7655 fn.end()
7659 fm.end()
7656 fm.end()
7660
7657
7661
7658
7662 def loadcmdtable(ui, name, cmdtable):
7659 def loadcmdtable(ui, name, cmdtable):
7663 """Load command functions from specified cmdtable
7660 """Load command functions from specified cmdtable
7664 """
7661 """
7665 overrides = [cmd for cmd in cmdtable if cmd in table]
7662 overrides = [cmd for cmd in cmdtable if cmd in table]
7666 if overrides:
7663 if overrides:
7667 ui.warn(
7664 ui.warn(
7668 _(b"extension '%s' overrides commands: %s\n")
7665 _(b"extension '%s' overrides commands: %s\n")
7669 % (name, b" ".join(overrides))
7666 % (name, b" ".join(overrides))
7670 )
7667 )
7671 table.update(cmdtable)
7668 table.update(cmdtable)
@@ -1,808 +1,808 b''
1 $ hg init basic
1 $ hg init basic
2 $ cd basic
2 $ cd basic
3
3
4 should complain
4 should complain
5
5
6 $ hg backout
6 $ hg backout
7 abort: please specify a revision to backout
7 abort: please specify a revision to backout
8 [255]
8 [255]
9 $ hg backout -r 0 0
9 $ hg backout -r 0 0
10 abort: please specify just one revision
10 abort: please specify just one revision
11 [255]
11 [255]
12
12
13 basic operation
13 basic operation
14 (this also tests that editor is invoked if the commit message is not
14 (this also tests that editor is invoked if the commit message is not
15 specified explicitly)
15 specified explicitly)
16
16
17 $ echo a > a
17 $ echo a > a
18 $ hg commit -d '0 0' -A -m a
18 $ hg commit -d '0 0' -A -m a
19 adding a
19 adding a
20 $ echo b >> a
20 $ echo b >> a
21 $ hg commit -d '1 0' -m b
21 $ hg commit -d '1 0' -m b
22
22
23 $ hg status --rev tip --rev "tip^1"
23 $ hg status --rev tip --rev "tip^1"
24 M a
24 M a
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 reverting a
26 reverting a
27 Backed out changeset a820f4f40a57
27 Backed out changeset a820f4f40a57
28
28
29
29
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 HG: Leave message empty to abort commit.
31 HG: Leave message empty to abort commit.
32 HG: --
32 HG: --
33 HG: user: test
33 HG: user: test
34 HG: branch 'default'
34 HG: branch 'default'
35 HG: changed a
35 HG: changed a
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 $ cat a
37 $ cat a
38 a
38 a
39 $ hg summary
39 $ hg summary
40 parent: 2:2929462c3dff tip
40 parent: 2:2929462c3dff tip
41 Backed out changeset a820f4f40a57
41 Backed out changeset a820f4f40a57
42 branch: default
42 branch: default
43 commit: (clean)
43 commit: (clean)
44 update: (current)
44 update: (current)
45 phases: 3 draft
45 phases: 3 draft
46
46
47 commit option
47 commit option
48
48
49 $ cd ..
49 $ cd ..
50 $ hg init commit
50 $ hg init commit
51 $ cd commit
51 $ cd commit
52
52
53 $ echo tomatoes > a
53 $ echo tomatoes > a
54 $ hg add a
54 $ hg add a
55 $ hg commit -d '0 0' -m tomatoes
55 $ hg commit -d '0 0' -m tomatoes
56
56
57 $ echo chair > b
57 $ echo chair > b
58 $ hg add b
58 $ hg add b
59 $ hg commit -d '1 0' -m chair
59 $ hg commit -d '1 0' -m chair
60
60
61 $ echo grapes >> a
61 $ echo grapes >> a
62 $ hg commit -d '2 0' -m grapes
62 $ hg commit -d '2 0' -m grapes
63
63
64 $ hg backout -d '4 0' 1 --tool=:fail
64 $ hg backout -d '4 0' 1 --tool=:fail
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 $ hg summary
67 $ hg summary
68 parent: 3:1c2161e97c0a tip
68 parent: 3:1c2161e97c0a tip
69 Backed out changeset 22cb4f70d813
69 Backed out changeset 22cb4f70d813
70 branch: default
70 branch: default
71 commit: (clean)
71 commit: (clean)
72 update: (current)
72 update: (current)
73 phases: 4 draft
73 phases: 4 draft
74
74
75 $ echo ypples > a
75 $ echo ypples > a
76 $ hg commit -d '5 0' -m ypples
76 $ hg commit -d '5 0' -m ypples
77
77
78 $ hg backout -d '6 0' 2 --tool=:fail
78 $ hg backout -d '6 0' 2 --tool=:fail
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 use 'hg resolve' to retry unresolved file merges
80 use 'hg resolve' to retry unresolved file merges
81 [1]
81 [1]
82 $ hg summary
82 $ hg summary
83 parent: 4:ed99997b793d tip
83 parent: 4:ed99997b793d tip
84 ypples
84 ypples
85 branch: default
85 branch: default
86 commit: 1 unresolved (clean)
86 commit: 1 unresolved (clean)
87 update: (current)
87 update: (current)
88 phases: 5 draft
88 phases: 5 draft
89 $ hg log -G
89 $ hg log -G
90 @ changeset: 4:ed99997b793d
90 @ changeset: 4:ed99997b793d
91 | tag: tip
91 | tag: tip
92 | user: test
92 | user: test
93 | date: Thu Jan 01 00:00:05 1970 +0000
93 | date: Thu Jan 01 00:00:05 1970 +0000
94 | summary: ypples
94 | summary: ypples
95 |
95 |
96 o changeset: 3:1c2161e97c0a
96 o changeset: 3:1c2161e97c0a
97 | user: test
97 | user: test
98 | date: Thu Jan 01 00:00:04 1970 +0000
98 | date: Thu Jan 01 00:00:04 1970 +0000
99 | summary: Backed out changeset 22cb4f70d813
99 | summary: Backed out changeset 22cb4f70d813
100 |
100 |
101 o changeset: 2:a8c6e511cfee
101 o changeset: 2:a8c6e511cfee
102 | user: test
102 | user: test
103 | date: Thu Jan 01 00:00:02 1970 +0000
103 | date: Thu Jan 01 00:00:02 1970 +0000
104 | summary: grapes
104 | summary: grapes
105 |
105 |
106 % changeset: 1:22cb4f70d813
106 % changeset: 1:22cb4f70d813
107 | user: test
107 | user: test
108 | date: Thu Jan 01 00:00:01 1970 +0000
108 | date: Thu Jan 01 00:00:01 1970 +0000
109 | summary: chair
109 | summary: chair
110 |
110 |
111 o changeset: 0:a5cb2dde5805
111 o changeset: 0:a5cb2dde5805
112 user: test
112 user: test
113 date: Thu Jan 01 00:00:00 1970 +0000
113 date: Thu Jan 01 00:00:00 1970 +0000
114 summary: tomatoes
114 summary: tomatoes
115
115
116
116
117 file that was removed is recreated
117 file that was removed is recreated
118 (this also tests that editor is not invoked if the commit message is
118 (this also tests that editor is not invoked if the commit message is
119 specified explicitly)
119 specified explicitly)
120
120
121 $ cd ..
121 $ cd ..
122 $ hg init remove
122 $ hg init remove
123 $ cd remove
123 $ cd remove
124
124
125 $ echo content > a
125 $ echo content > a
126 $ hg commit -d '0 0' -A -m a
126 $ hg commit -d '0 0' -A -m a
127 adding a
127 adding a
128
128
129 $ hg rm a
129 $ hg rm a
130 $ hg commit -d '1 0' -m b
130 $ hg commit -d '1 0' -m b
131
131
132 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
132 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
133 adding a
133 adding a
134 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
134 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
135 $ cat a
135 $ cat a
136 content
136 content
137 $ hg summary
137 $ hg summary
138 parent: 2:de31bdc76c0d tip
138 parent: 2:de31bdc76c0d tip
139 Backed out changeset 76862dcce372
139 Backed out changeset 76862dcce372
140 branch: default
140 branch: default
141 commit: (clean)
141 commit: (clean)
142 update: (current)
142 update: (current)
143 phases: 3 draft
143 phases: 3 draft
144
144
145 backout of backout is as if nothing happened
145 backout of backout is as if nothing happened
146
146
147 $ hg backout -d '3 0' --merge tip --tool=true
147 $ hg backout -d '3 0' --merge tip --tool=true
148 removing a
148 removing a
149 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
149 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
150 $ test -f a
150 $ test -f a
151 [1]
151 [1]
152 $ hg summary
152 $ hg summary
153 parent: 3:7f6d0f120113 tip
153 parent: 3:7f6d0f120113 tip
154 Backed out changeset de31bdc76c0d
154 Backed out changeset de31bdc76c0d
155 branch: default
155 branch: default
156 commit: (clean)
156 commit: (clean)
157 update: (current)
157 update: (current)
158 phases: 4 draft
158 phases: 4 draft
159
159
160 Test that 'hg rollback' restores dirstate just before opening
160 Test that 'hg rollback' restores dirstate just before opening
161 transaction: in-memory dirstate changes should be written into
161 transaction: in-memory dirstate changes should be written into
162 '.hg/journal.dirstate' as expected.
162 '.hg/journal.dirstate' as expected.
163
163
164 $ echo 'removed soon' > b
164 $ echo 'removed soon' > b
165 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
165 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
166 adding b
166 adding b
167 $ echo 'newly added' > c
167 $ echo 'newly added' > c
168 $ hg add c
168 $ hg add c
169 $ hg remove b
169 $ hg remove b
170 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
170 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
171 $ touch -t 200001010000 c
171 $ touch -t 200001010000 c
172 $ hg status -A
172 $ hg status -A
173 C c
173 C c
174 $ hg debugstate --no-dates
174 $ hg debugstate --no-dates
175 n 644 12 set c
175 n 644 12 set c
176 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
176 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
177 removing c
177 removing c
178 adding b
178 adding b
179 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
179 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
180 $ hg rollback -q
180 $ hg rollback -q
181 $ hg status -A
181 $ hg status -A
182 A b
182 A b
183 R c
183 R c
184 $ hg debugstate --no-dates
184 $ hg debugstate --no-dates
185 a 0 -1 unset b
185 a 0 -1 unset b
186 r 0 0 set c
186 r 0 0 set c
187
187
188 across branch
188 across branch
189
189
190 $ cd ..
190 $ cd ..
191 $ hg init branch
191 $ hg init branch
192 $ cd branch
192 $ cd branch
193 $ echo a > a
193 $ echo a > a
194 $ hg ci -Am0
194 $ hg ci -Am0
195 adding a
195 adding a
196 $ echo b > b
196 $ echo b > b
197 $ hg ci -Am1
197 $ hg ci -Am1
198 adding b
198 adding b
199 $ hg co -C 0
199 $ hg co -C 0
200 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
200 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
201 $ hg summary
201 $ hg summary
202 parent: 0:f7b1eb17ad24
202 parent: 0:f7b1eb17ad24
203 0
203 0
204 branch: default
204 branch: default
205 commit: (clean)
205 commit: (clean)
206 update: 1 new changesets (update)
206 update: 1 new changesets (update)
207 phases: 2 draft
207 phases: 2 draft
208
208
209 should fail
209 should fail
210
210
211 $ hg backout 1
211 $ hg backout 1
212 abort: cannot backout change that is not an ancestor
212 abort: cannot backout change that is not an ancestor
213 [255]
213 [255]
214 $ echo c > c
214 $ echo c > c
215 $ hg ci -Am2
215 $ hg ci -Am2
216 adding c
216 adding c
217 created new head
217 created new head
218 $ hg summary
218 $ hg summary
219 parent: 2:db815d6d32e6 tip
219 parent: 2:db815d6d32e6 tip
220 2
220 2
221 branch: default
221 branch: default
222 commit: (clean)
222 commit: (clean)
223 update: 1 new changesets, 2 branch heads (merge)
223 update: 1 new changesets, 2 branch heads (merge)
224 phases: 3 draft
224 phases: 3 draft
225
225
226 should fail
226 should fail
227
227
228 $ hg backout 1
228 $ hg backout 1
229 abort: cannot backout change that is not an ancestor
229 abort: cannot backout change that is not an ancestor
230 [255]
230 [255]
231 $ hg summary
231 $ hg summary
232 parent: 2:db815d6d32e6 tip
232 parent: 2:db815d6d32e6 tip
233 2
233 2
234 branch: default
234 branch: default
235 commit: (clean)
235 commit: (clean)
236 update: 1 new changesets, 2 branch heads (merge)
236 update: 1 new changesets, 2 branch heads (merge)
237 phases: 3 draft
237 phases: 3 draft
238
238
239 backout with merge
239 backout with merge
240
240
241 $ cd ..
241 $ cd ..
242 $ hg init merge
242 $ hg init merge
243 $ cd merge
243 $ cd merge
244
244
245 $ echo line 1 > a
245 $ echo line 1 > a
246 $ echo line 2 >> a
246 $ echo line 2 >> a
247 $ hg commit -d '0 0' -A -m a
247 $ hg commit -d '0 0' -A -m a
248 adding a
248 adding a
249 $ hg summary
249 $ hg summary
250 parent: 0:59395513a13a tip
250 parent: 0:59395513a13a tip
251 a
251 a
252 branch: default
252 branch: default
253 commit: (clean)
253 commit: (clean)
254 update: (current)
254 update: (current)
255 phases: 1 draft
255 phases: 1 draft
256
256
257 remove line 1
257 remove line 1
258
258
259 $ echo line 2 > a
259 $ echo line 2 > a
260 $ hg commit -d '1 0' -m b
260 $ hg commit -d '1 0' -m b
261
261
262 $ echo line 3 >> a
262 $ echo line 3 >> a
263 $ hg commit -d '2 0' -m c
263 $ hg commit -d '2 0' -m c
264
264
265 $ hg backout --merge -d '3 0' 1 --tool=true
265 $ hg backout --merge -d '3 0' 1 --tool=true
266 reverting a
266 reverting a
267 created new head
267 created new head
268 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
268 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
269 merging with changeset 3:26b8ccb9ad91
269 merging with changeset 3:26b8ccb9ad91
270 merging a
270 merging a
271 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
271 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
272 (branch merge, don't forget to commit)
272 (branch merge, don't forget to commit)
273 $ hg commit -d '4 0' -m d
273 $ hg commit -d '4 0' -m d
274 $ hg summary
274 $ hg summary
275 parent: 4:c7df5e0b9c09 tip
275 parent: 4:c7df5e0b9c09 tip
276 d
276 d
277 branch: default
277 branch: default
278 commit: (clean)
278 commit: (clean)
279 update: (current)
279 update: (current)
280 phases: 5 draft
280 phases: 5 draft
281
281
282 check line 1 is back
282 check line 1 is back
283
283
284 $ cat a
284 $ cat a
285 line 1
285 line 1
286 line 2
286 line 2
287 line 3
287 line 3
288
288
289 Test visibility of in-memory dirstate changes outside transaction to
289 Test visibility of in-memory dirstate changes outside transaction to
290 external hook process
290 external hook process
291
291
292 $ cat > $TESTTMP/checkvisibility.sh <<EOF
292 $ cat > $TESTTMP/checkvisibility.sh <<EOF
293 > echo "==== \$1:"
293 > echo "==== \$1:"
294 > hg parents --template "{rev}:{node|short}\n"
294 > hg parents --template "{rev}:{node|short}\n"
295 > echo "===="
295 > echo "===="
296 > EOF
296 > EOF
297
297
298 "hg backout --merge REV1" at REV2 below implies steps below:
298 "hg backout --merge REV1" at REV2 below implies steps below:
299
299
300 (1) update to REV1 (REV2 => REV1)
300 (1) update to REV1 (REV2 => REV1)
301 (2) revert by REV1^1
301 (2) revert by REV1^1
302 (3) commit backing out revision (REV3)
302 (3) commit backing out revision (REV3)
303 (4) update to REV2 (REV3 => REV2)
303 (4) update to REV2 (REV3 => REV2)
304 (5) merge with REV3 (REV2 => REV2, REV3)
304 (5) merge with REV3 (REV2 => REV2, REV3)
305
305
306 == test visibility to external preupdate hook
306 == test visibility to external preupdate hook
307
307
308 $ hg update -q -C 2
308 $ hg update -q -C 2
309 $ hg --config extensions.strip= strip 3
309 $ hg --config extensions.strip= strip 3
310 saved backup bundle to * (glob)
310 saved backup bundle to * (glob)
311
311
312 $ cat >> .hg/hgrc <<EOF
312 $ cat >> .hg/hgrc <<EOF
313 > [hooks]
313 > [hooks]
314 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
314 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
315 > EOF
315 > EOF
316
316
317 ("-m" is needed to avoid writing dirstate changes out at other than
317 ("-m" is needed to avoid writing dirstate changes out at other than
318 invocation of the hook to be examined)
318 invocation of the hook to be examined)
319
319
320 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
320 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
321 ==== preupdate:
321 ==== preupdate:
322 2:6ea3f2a197a2
322 2:6ea3f2a197a2
323 ====
323 ====
324 reverting a
324 reverting a
325 created new head
325 created new head
326 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
326 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
327 ==== preupdate:
327 ==== preupdate:
328 3:d92a3f57f067
328 3:d92a3f57f067
329 ====
329 ====
330 merging with changeset 3:d92a3f57f067
330 merging with changeset 3:d92a3f57f067
331 ==== preupdate:
331 ==== preupdate:
332 2:6ea3f2a197a2
332 2:6ea3f2a197a2
333 ====
333 ====
334 merging a
334 merging a
335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
336 (branch merge, don't forget to commit)
336 (branch merge, don't forget to commit)
337
337
338 $ cat >> .hg/hgrc <<EOF
338 $ cat >> .hg/hgrc <<EOF
339 > [hooks]
339 > [hooks]
340 > preupdate.visibility =
340 > preupdate.visibility =
341 > EOF
341 > EOF
342
342
343 == test visibility to external update hook
343 == test visibility to external update hook
344
344
345 $ hg update -q -C 2
345 $ hg update -q -C 2
346 $ hg --config extensions.strip= strip 3
346 $ hg --config extensions.strip= strip 3
347 saved backup bundle to * (glob)
347 saved backup bundle to * (glob)
348
348
349 $ cat >> .hg/hgrc <<EOF
349 $ cat >> .hg/hgrc <<EOF
350 > [hooks]
350 > [hooks]
351 > update.visibility = sh $TESTTMP/checkvisibility.sh update
351 > update.visibility = sh $TESTTMP/checkvisibility.sh update
352 > EOF
352 > EOF
353
353
354 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
354 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
355 ==== update:
355 ==== update:
356 1:5a50a024c182
356 1:5a50a024c182
357 ====
357 ====
358 reverting a
358 reverting a
359 created new head
359 created new head
360 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
360 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
361 ==== update:
361 ==== update:
362 2:6ea3f2a197a2
362 2:6ea3f2a197a2
363 ====
363 ====
364 merging with changeset 3:d92a3f57f067
364 merging with changeset 3:d92a3f57f067
365 merging a
365 merging a
366 ==== update:
366 ==== update:
367 2:6ea3f2a197a2
367 2:6ea3f2a197a2
368 3:d92a3f57f067
368 3:d92a3f57f067
369 ====
369 ====
370 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
370 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
371 (branch merge, don't forget to commit)
371 (branch merge, don't forget to commit)
372
372
373 $ cat >> .hg/hgrc <<EOF
373 $ cat >> .hg/hgrc <<EOF
374 > [hooks]
374 > [hooks]
375 > update.visibility =
375 > update.visibility =
376 > EOF
376 > EOF
377
377
378 $ cd ..
378 $ cd ..
379
379
380 backout should not back out subsequent changesets
380 backout should not back out subsequent changesets
381
381
382 $ hg init onecs
382 $ hg init onecs
383 $ cd onecs
383 $ cd onecs
384 $ echo 1 > a
384 $ echo 1 > a
385 $ hg commit -d '0 0' -A -m a
385 $ hg commit -d '0 0' -A -m a
386 adding a
386 adding a
387 $ echo 2 >> a
387 $ echo 2 >> a
388 $ hg commit -d '1 0' -m b
388 $ hg commit -d '1 0' -m b
389 $ echo 1 > b
389 $ echo 1 > b
390 $ hg commit -d '2 0' -A -m c
390 $ hg commit -d '2 0' -A -m c
391 adding b
391 adding b
392 $ hg summary
392 $ hg summary
393 parent: 2:882396649954 tip
393 parent: 2:882396649954 tip
394 c
394 c
395 branch: default
395 branch: default
396 commit: (clean)
396 commit: (clean)
397 update: (current)
397 update: (current)
398 phases: 3 draft
398 phases: 3 draft
399
399
400 without --merge
400 without --merge
401 $ hg backout --no-commit -d '3 0' 1 --tool=true
401 $ hg backout --no-commit -d '3 0' 1 --tool=true
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 changeset 22bca4c721e5 backed out, don't forget to commit.
403 changeset 22bca4c721e5 backed out, don't forget to commit.
404 $ hg locate b
404 $ hg locate b
405 b
405 b
406 $ hg update -C tip
406 $ hg update -C tip
407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 $ hg locate b
408 $ hg locate b
409 b
409 b
410 $ hg summary
410 $ hg summary
411 parent: 2:882396649954 tip
411 parent: 2:882396649954 tip
412 c
412 c
413 branch: default
413 branch: default
414 commit: (clean)
414 commit: (clean)
415 update: (current)
415 update: (current)
416 phases: 3 draft
416 phases: 3 draft
417
417
418 with --merge
418 with --merge
419 $ hg backout --merge -d '3 0' 1 --tool=true
419 $ hg backout --merge -d '3 0' 1 --tool=true
420 reverting a
420 reverting a
421 created new head
421 created new head
422 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
422 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
423 merging with changeset 3:3202beb76721
423 merging with changeset 3:3202beb76721
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 (branch merge, don't forget to commit)
425 (branch merge, don't forget to commit)
426 $ hg locate b
426 $ hg locate b
427 b
427 b
428 $ hg update -C tip
428 $ hg update -C tip
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
430 $ hg locate b
430 $ hg locate b
431 [1]
431 [1]
432
432
433 $ cd ..
433 $ cd ..
434 $ hg init m
434 $ hg init m
435 $ cd m
435 $ cd m
436 $ echo a > a
436 $ echo a > a
437 $ hg commit -d '0 0' -A -m a
437 $ hg commit -d '0 0' -A -m a
438 adding a
438 adding a
439 $ echo b > b
439 $ echo b > b
440 $ hg commit -d '1 0' -A -m b
440 $ hg commit -d '1 0' -A -m b
441 adding b
441 adding b
442 $ echo c > c
442 $ echo c > c
443 $ hg commit -d '2 0' -A -m b
443 $ hg commit -d '2 0' -A -m b
444 adding c
444 adding c
445 $ hg update 1
445 $ hg update 1
446 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
446 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 $ echo d > d
447 $ echo d > d
448 $ hg commit -d '3 0' -A -m c
448 $ hg commit -d '3 0' -A -m c
449 adding d
449 adding d
450 created new head
450 created new head
451 $ hg merge 2
451 $ hg merge 2
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 (branch merge, don't forget to commit)
453 (branch merge, don't forget to commit)
454 $ hg commit -d '4 0' -A -m d
454 $ hg commit -d '4 0' -A -m d
455 $ hg summary
455 $ hg summary
456 parent: 4:b2f3bb92043e tip
456 parent: 4:b2f3bb92043e tip
457 d
457 d
458 branch: default
458 branch: default
459 commit: (clean)
459 commit: (clean)
460 update: (current)
460 update: (current)
461 phases: 5 draft
461 phases: 5 draft
462
462
463 backout of merge should fail
463 backout of merge should fail
464
464
465 $ hg backout 4
465 $ hg backout 4
466 abort: cannot backout a merge changeset
466 abort: cannot backout a merge changeset
467 [255]
467 [255]
468
468
469 backout of merge with bad parent should fail
469 backout of merge with bad parent should fail
470
470
471 $ hg backout --parent 0 4
471 $ hg backout --parent 0 4
472 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
472 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
473 [255]
473 [255]
474
474
475 backout of non-merge with parent should fail
475 backout of non-merge with parent should fail
476
476
477 $ hg backout --parent 0 3
477 $ hg backout --parent 0 3
478 abort: cannot use --parent on non-merge changeset
478 abort: cannot use --parent on non-merge changeset
479 [255]
479 [255]
480
480
481 backout with valid parent should be ok
481 backout with valid parent should be ok
482
482
483 $ hg backout -d '5 0' --parent 2 4 --tool=true
483 $ hg backout -d '5 0' --parent 2 4 --tool=true
484 removing d
484 removing d
485 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
485 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
486 $ hg summary
486 $ hg summary
487 parent: 5:10e5328c8435 tip
487 parent: 5:10e5328c8435 tip
488 Backed out changeset b2f3bb92043e
488 Backed out changeset b2f3bb92043e
489 branch: default
489 branch: default
490 commit: (clean)
490 commit: (clean)
491 update: (current)
491 update: (current)
492 phases: 6 draft
492 phases: 6 draft
493
493
494 $ hg rollback
494 $ hg rollback
495 repository tip rolled back to revision 4 (undo commit)
495 repository tip rolled back to revision 4 (undo commit)
496 working directory now based on revision 4
496 working directory now based on revision 4
497 $ hg update -C
497 $ hg update -C
498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 $ hg summary
499 $ hg summary
500 parent: 4:b2f3bb92043e tip
500 parent: 4:b2f3bb92043e tip
501 d
501 d
502 branch: default
502 branch: default
503 commit: (clean)
503 commit: (clean)
504 update: (current)
504 update: (current)
505 phases: 5 draft
505 phases: 5 draft
506
506
507 $ hg backout -d '6 0' --parent 3 4 --tool=true
507 $ hg backout -d '6 0' --parent 3 4 --tool=true
508 removing c
508 removing c
509 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
509 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
510 $ hg summary
510 $ hg summary
511 parent: 5:033590168430 tip
511 parent: 5:033590168430 tip
512 Backed out changeset b2f3bb92043e
512 Backed out changeset b2f3bb92043e
513 branch: default
513 branch: default
514 commit: (clean)
514 commit: (clean)
515 update: (current)
515 update: (current)
516 phases: 6 draft
516 phases: 6 draft
517
517
518 $ cd ..
518 $ cd ..
519
519
520 named branches
520 named branches
521
521
522 $ hg init named_branches
522 $ hg init named_branches
523 $ cd named_branches
523 $ cd named_branches
524
524
525 $ echo default > default
525 $ echo default > default
526 $ hg ci -d '0 0' -Am default
526 $ hg ci -d '0 0' -Am default
527 adding default
527 adding default
528 $ hg branch branch1
528 $ hg branch branch1
529 marked working directory as branch branch1
529 marked working directory as branch branch1
530 (branches are permanent and global, did you want a bookmark?)
530 (branches are permanent and global, did you want a bookmark?)
531 $ echo branch1 > file1
531 $ echo branch1 > file1
532 $ hg ci -d '1 0' -Am file1
532 $ hg ci -d '1 0' -Am file1
533 adding file1
533 adding file1
534 $ hg branch branch2
534 $ hg branch branch2
535 marked working directory as branch branch2
535 marked working directory as branch branch2
536 $ echo branch2 > file2
536 $ echo branch2 > file2
537 $ hg ci -d '2 0' -Am file2
537 $ hg ci -d '2 0' -Am file2
538 adding file2
538 adding file2
539
539
540 without --merge
540 without --merge
541 $ hg backout --no-commit -r 1 --tool=true
541 $ hg backout --no-commit -r 1 --tool=true
542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
542 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
543 changeset bf1602f437f3 backed out, don't forget to commit.
543 changeset bf1602f437f3 backed out, don't forget to commit.
544 $ hg branch
544 $ hg branch
545 branch2
545 branch2
546 $ hg status -A
546 $ hg status -A
547 R file1
547 R file1
548 C default
548 C default
549 C file2
549 C file2
550 $ hg summary
550 $ hg summary
551 parent: 2:45bbcd363bf0 tip
551 parent: 2:45bbcd363bf0 tip
552 file2
552 file2
553 branch: branch2
553 branch: branch2
554 commit: 1 removed
554 commit: 1 removed
555 update: (current)
555 update: (current)
556 phases: 3 draft
556 phases: 3 draft
557
557
558 with --merge
558 with --merge
559 (this also tests that editor is invoked if '--edit' is specified
559 (this also tests that editor is invoked if '--edit' is specified
560 explicitly regardless of '--message')
560 explicitly regardless of '--message')
561
561
562 $ hg update -qC
562 $ hg update -qC
563 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
563 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
564 removing file1
564 removing file1
565 backout on branch1
565 backout on branch1
566
566
567
567
568 HG: Enter commit message. Lines beginning with 'HG:' are removed.
568 HG: Enter commit message. Lines beginning with 'HG:' are removed.
569 HG: Leave message empty to abort commit.
569 HG: Leave message empty to abort commit.
570 HG: --
570 HG: --
571 HG: user: test
571 HG: user: test
572 HG: branch 'branch2'
572 HG: branch 'branch2'
573 HG: removed file1
573 HG: removed file1
574 created new head
574 created new head
575 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
575 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
576 merging with changeset 3:d4e8f6db59fb
576 merging with changeset 3:d4e8f6db59fb
577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 (branch merge, don't forget to commit)
578 (branch merge, don't forget to commit)
579 $ hg summary
579 $ hg summary
580 parent: 2:45bbcd363bf0
580 parent: 2:45bbcd363bf0
581 file2
581 file2
582 parent: 3:d4e8f6db59fb tip
582 parent: 3:d4e8f6db59fb tip
583 backout on branch1
583 backout on branch1
584 branch: branch2
584 branch: branch2
585 commit: 1 removed (merge)
585 commit: 1 removed (merge)
586 update: (current)
586 update: (current)
587 phases: 4 draft
587 phases: 4 draft
588 $ hg update -q -C 2
588 $ hg update -q -C 2
589
589
590 on branch2 with branch1 not merged, so file1 should still exist:
590 on branch2 with branch1 not merged, so file1 should still exist:
591
591
592 $ hg id
592 $ hg id
593 45bbcd363bf0 (branch2)
593 45bbcd363bf0 (branch2)
594 $ hg st -A
594 $ hg st -A
595 C default
595 C default
596 C file1
596 C file1
597 C file2
597 C file2
598 $ hg summary
598 $ hg summary
599 parent: 2:45bbcd363bf0
599 parent: 2:45bbcd363bf0
600 file2
600 file2
601 branch: branch2
601 branch: branch2
602 commit: (clean)
602 commit: (clean)
603 update: 1 new changesets, 2 branch heads (merge)
603 update: 1 new changesets, 2 branch heads (merge)
604 phases: 4 draft
604 phases: 4 draft
605
605
606 on branch2 with branch1 merged, so file1 should be gone:
606 on branch2 with branch1 merged, so file1 should be gone:
607
607
608 $ hg merge
608 $ hg merge
609 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
609 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
610 (branch merge, don't forget to commit)
610 (branch merge, don't forget to commit)
611 $ hg ci -d '4 0' -m 'merge backout of branch1'
611 $ hg ci -d '4 0' -m 'merge backout of branch1'
612 $ hg id
612 $ hg id
613 d97a8500a969 (branch2) tip
613 d97a8500a969 (branch2) tip
614 $ hg st -A
614 $ hg st -A
615 C default
615 C default
616 C file2
616 C file2
617 $ hg summary
617 $ hg summary
618 parent: 4:d97a8500a969 tip
618 parent: 4:d97a8500a969 tip
619 merge backout of branch1
619 merge backout of branch1
620 branch: branch2
620 branch: branch2
621 commit: (clean)
621 commit: (clean)
622 update: (current)
622 update: (current)
623 phases: 5 draft
623 phases: 5 draft
624
624
625 on branch1, so no file1 and file2:
625 on branch1, so no file1 and file2:
626
626
627 $ hg co -C branch1
627 $ hg co -C branch1
628 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
628 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
629 $ hg id
629 $ hg id
630 bf1602f437f3 (branch1)
630 bf1602f437f3 (branch1)
631 $ hg st -A
631 $ hg st -A
632 C default
632 C default
633 C file1
633 C file1
634 $ hg summary
634 $ hg summary
635 parent: 1:bf1602f437f3
635 parent: 1:bf1602f437f3
636 file1
636 file1
637 branch: branch1
637 branch: branch1
638 commit: (clean)
638 commit: (clean)
639 update: (current)
639 update: (current)
640 phases: 5 draft
640 phases: 5 draft
641
641
642 $ cd ..
642 $ cd ..
643
643
644 backout of empty changeset (issue4190)
644 backout of empty changeset (issue4190)
645
645
646 $ hg init emptycommit
646 $ hg init emptycommit
647 $ cd emptycommit
647 $ cd emptycommit
648
648
649 $ touch file1
649 $ touch file1
650 $ hg ci -Aqm file1
650 $ hg ci -Aqm file1
651 $ hg branch -q branch1
651 $ hg branch -q branch1
652 $ hg ci -qm branch1
652 $ hg ci -qm branch1
653 $ hg backout -v 1
653 $ hg backout -v 1
654 resolving manifests
654 resolving manifests
655 nothing changed
655 nothing changed
656 [1]
656 [1]
657
657
658 $ cd ..
658 $ cd ..
659
659
660
660
661 Test usage of `hg resolve` in case of conflict
661 Test usage of `hg resolve` in case of conflict
662 (issue4163)
662 (issue4163)
663
663
664 $ hg init issue4163
664 $ hg init issue4163
665 $ cd issue4163
665 $ cd issue4163
666 $ touch foo
666 $ touch foo
667 $ hg add foo
667 $ hg add foo
668 $ cat > foo << EOF
668 $ cat > foo << EOF
669 > one
669 > one
670 > two
670 > two
671 > three
671 > three
672 > four
672 > four
673 > five
673 > five
674 > six
674 > six
675 > seven
675 > seven
676 > height
676 > height
677 > nine
677 > nine
678 > ten
678 > ten
679 > EOF
679 > EOF
680 $ hg ci -m 'initial'
680 $ hg ci -m 'initial'
681 $ cat > foo << EOF
681 $ cat > foo << EOF
682 > one
682 > one
683 > two
683 > two
684 > THREE
684 > THREE
685 > four
685 > four
686 > five
686 > five
687 > six
687 > six
688 > seven
688 > seven
689 > height
689 > height
690 > nine
690 > nine
691 > ten
691 > ten
692 > EOF
692 > EOF
693 $ hg ci -m 'capital three'
693 $ hg ci -m 'capital three'
694 $ cat > foo << EOF
694 $ cat > foo << EOF
695 > one
695 > one
696 > two
696 > two
697 > THREE
697 > THREE
698 > four
698 > four
699 > five
699 > five
700 > six
700 > six
701 > seven
701 > seven
702 > height
702 > height
703 > nine
703 > nine
704 > TEN
704 > TEN
705 > EOF
705 > EOF
706 $ hg ci -m 'capital ten'
706 $ hg ci -m 'capital ten'
707 $ hg backout -r 'desc("capital three")' --tool internal:fail
707 $ hg backout -r 'desc("capital three")' --tool internal:fail
708 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
708 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
709 use 'hg resolve' to retry unresolved file merges
709 use 'hg resolve' to retry unresolved file merges
710 [1]
710 [1]
711 $ hg status
711 $ hg status
712 $ hg debugmergestate -v
712 $ hg debugmergestate -v
713 v1 and v2 states match: using v2
713 v1 and v2 states match: using v2
714 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
714 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
715 other: a30dd8addae3ce71b8667868478542bc417439e6
715 other: a30dd8addae3ce71b8667868478542bc417439e6
716 file: foo (state "u")
716 file: foo (state "u")
717 local path: foo (hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, flags "")
717 local path: foo (hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, flags "")
718 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
718 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
719 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
719 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
720 extra: ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553
720 extra: ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553
721 $ mv .hg/merge/state2 .hg/merge/state2-moved
721 $ mv .hg/merge/state2 .hg/merge/state2-moved
722 $ hg debugmergestate -v
722 $ hg debugmergestate -v
723 no version 2 merge state
723 no version 2 merge state
724 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
724 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
725 other: b71750c4b0fdf719734971e3ef90dbeab5919a2d
725 other: b71750c4b0fdf719734971e3ef90dbeab5919a2d
726 file: foo (state "u")
726 file: foo (state "u")
727 local path: foo (hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, flags "")
727 local path: foo (hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, flags "")
728 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
728 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
729 other path: (node foo)
729 other path: (node foo)
730 $ mv .hg/merge/state2-moved .hg/merge/state2
730 $ mv .hg/merge/state2-moved .hg/merge/state2
731 $ hg resolve -l # still unresolved
731 $ hg resolve -l # still unresolved
732 U foo
732 U foo
733 $ hg summary
733 $ hg summary
734 parent: 2:b71750c4b0fd tip
734 parent: 2:b71750c4b0fd tip
735 capital ten
735 capital ten
736 branch: default
736 branch: default
737 commit: 1 unresolved (clean)
737 commit: 1 unresolved (clean)
738 update: (current)
738 update: (current)
739 phases: 3 draft
739 phases: 3 draft
740 $ hg log -G
740 $ hg log -G
741 @ changeset: 2:b71750c4b0fd
741 @ changeset: 2:b71750c4b0fd
742 | tag: tip
742 | tag: tip
743 | user: test
743 | user: test
744 | date: Thu Jan 01 00:00:00 1970 +0000
744 | date: Thu Jan 01 00:00:00 1970 +0000
745 | summary: capital ten
745 | summary: capital ten
746 |
746 |
747 o changeset: 1:913609522437
747 o changeset: 1:913609522437
748 | user: test
748 | user: test
749 | date: Thu Jan 01 00:00:00 1970 +0000
749 | date: Thu Jan 01 00:00:00 1970 +0000
750 | summary: capital three
750 | summary: capital three
751 |
751 |
752 % changeset: 0:a30dd8addae3
752 % changeset: 0:a30dd8addae3
753 user: test
753 user: test
754 date: Thu Jan 01 00:00:00 1970 +0000
754 date: Thu Jan 01 00:00:00 1970 +0000
755 summary: initial
755 summary: initial
756
756
757 $ hg resolve --all --debug
757 $ hg resolve --all --debug
758 picked tool ':merge' for foo (binary False symlink False changedelete False)
758 picked tool ':merge' for foo (binary False symlink False changedelete False)
759 merging foo
759 merging foo
760 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
760 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
761 premerge successful
761 premerge successful
762 (no more unresolved files)
762 (no more unresolved files)
763 continue: hg commit
763 continue: hg commit
764 $ hg status
764 $ hg status
765 M foo
765 M foo
766 ? foo.orig
766 ? foo.orig
767 $ hg resolve -l
767 $ hg resolve -l
768 R foo
768 R foo
769 $ hg summary
769 $ hg summary
770 parent: 2:b71750c4b0fd tip
770 parent: 2:b71750c4b0fd tip
771 capital ten
771 capital ten
772 branch: default
772 branch: default
773 commit: 1 modified, 1 unknown
773 commit: 1 modified, 1 unknown
774 update: (current)
774 update: (current)
775 phases: 3 draft
775 phases: 3 draft
776 $ cat foo
776 $ cat foo
777 one
777 one
778 two
778 two
779 three
779 three
780 four
780 four
781 five
781 five
782 six
782 six
783 seven
783 seven
784 height
784 height
785 nine
785 nine
786 TEN
786 TEN
787
787
788 --no-commit shouldn't commit
788 --no-commit shouldn't commit
789
789
790 $ hg init a
790 $ hg init a
791 $ cd a
791 $ cd a
792 $ for i in 1 2 3; do
792 $ for i in 1 2 3; do
793 > touch $i
793 > touch $i
794 > hg ci -Am $i
794 > hg ci -Am $i
795 > done
795 > done
796 adding 1
796 adding 1
797 adding 2
797 adding 2
798 adding 3
798 adding 3
799 $ hg backout --no-commit .
799 $ hg backout --no-commit .
800 removing 3
800 removing 3
801 changeset cccc23d9d68f backed out, don't forget to commit.
801 changeset cccc23d9d68f backed out, don't forget to commit.
802 $ hg revert -aq
802 $ hg revert -aq
803
803
804 --no-commit can't be used with --merge
804 --no-commit can't be used with --merge
805
805
806 $ hg backout --merge --no-commit 2
806 $ hg backout --merge --no-commit 2
807 abort: cannot use --merge with --no-commit
807 abort: cannot specify both --no-commit and --merge
808 [255]
808 [255]
General Comments 0
You need to be logged in to leave comments. Login now