##// END OF EJS Templates
unshelve: add help text on --interactive in verbose mode...
Navaneeth Suresh -
r42867:0795bbe8 stable
parent child Browse files
Show More
@@ -1,6440 +1,6448 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 difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
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 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 revsetlang,
56 revsetlang,
57 rewriteutil,
57 rewriteutil,
58 scmutil,
58 scmutil,
59 server,
59 server,
60 shelve as shelvemod,
60 shelve as shelvemod,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
63 tags as tagsmod,
63 tags as tagsmod,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 verify as verifymod,
66 verify as verifymod,
67 wireprotoserver,
67 wireprotoserver,
68 )
68 )
69 from .utils import (
69 from .utils import (
70 dateutil,
70 dateutil,
71 stringutil,
71 stringutil,
72 )
72 )
73
73
74 table = {}
74 table = {}
75 table.update(debugcommandsmod.command._table)
75 table.update(debugcommandsmod.command._table)
76
76
77 command = registrar.command(table)
77 command = registrar.command(table)
78 INTENT_READONLY = registrar.INTENT_READONLY
78 INTENT_READONLY = registrar.INTENT_READONLY
79
79
80 # common command options
80 # common command options
81
81
82 globalopts = [
82 globalopts = [
83 ('R', 'repository', '',
83 ('R', 'repository', '',
84 _('repository root directory or name of overlay bundle file'),
84 _('repository root directory or name of overlay bundle file'),
85 _('REPO')),
85 _('REPO')),
86 ('', 'cwd', '',
86 ('', 'cwd', '',
87 _('change working directory'), _('DIR')),
87 _('change working directory'), _('DIR')),
88 ('y', 'noninteractive', None,
88 ('y', 'noninteractive', None,
89 _('do not prompt, automatically pick the first choice for all prompts')),
89 _('do not prompt, automatically pick the first choice for all prompts')),
90 ('q', 'quiet', None, _('suppress output')),
90 ('q', 'quiet', None, _('suppress output')),
91 ('v', 'verbose', None, _('enable additional output')),
91 ('v', 'verbose', None, _('enable additional output')),
92 ('', 'color', '',
92 ('', 'color', '',
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # and should not be translated
94 # and should not be translated
95 _("when to colorize (boolean, always, auto, never, or debug)"),
95 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _('TYPE')),
96 _('TYPE')),
97 ('', 'config', [],
97 ('', 'config', [],
98 _('set/override config option (use \'section.name=value\')'),
98 _('set/override config option (use \'section.name=value\')'),
99 _('CONFIG')),
99 _('CONFIG')),
100 ('', 'debug', None, _('enable debugging output')),
100 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debugger', None, _('start debugger')),
101 ('', 'debugger', None, _('start debugger')),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 _('ENCODE')),
103 _('ENCODE')),
104 ('', 'encodingmode', encoding.encodingmode,
104 ('', 'encodingmode', encoding.encodingmode,
105 _('set the charset encoding mode'), _('MODE')),
105 _('set the charset encoding mode'), _('MODE')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'time', None, _('time how long the command takes')),
107 ('', 'time', None, _('time how long the command takes')),
108 ('', 'profile', None, _('print command execution profile')),
108 ('', 'profile', None, _('print command execution profile')),
109 ('', 'version', None, _('output version information and exit')),
109 ('', 'version', None, _('output version information and exit')),
110 ('h', 'help', None, _('display help and exit')),
110 ('h', 'help', None, _('display help and exit')),
111 ('', 'hidden', False, _('consider hidden changesets')),
111 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'pager', 'auto',
112 ('', 'pager', 'auto',
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 ]
114 ]
115
115
116 dryrunopts = cmdutil.dryrunopts
116 dryrunopts = cmdutil.dryrunopts
117 remoteopts = cmdutil.remoteopts
117 remoteopts = cmdutil.remoteopts
118 walkopts = cmdutil.walkopts
118 walkopts = cmdutil.walkopts
119 commitopts = cmdutil.commitopts
119 commitopts = cmdutil.commitopts
120 commitopts2 = cmdutil.commitopts2
120 commitopts2 = cmdutil.commitopts2
121 formatteropts = cmdutil.formatteropts
121 formatteropts = cmdutil.formatteropts
122 templateopts = cmdutil.templateopts
122 templateopts = cmdutil.templateopts
123 logopts = cmdutil.logopts
123 logopts = cmdutil.logopts
124 diffopts = cmdutil.diffopts
124 diffopts = cmdutil.diffopts
125 diffwsopts = cmdutil.diffwsopts
125 diffwsopts = cmdutil.diffwsopts
126 diffopts2 = cmdutil.diffopts2
126 diffopts2 = cmdutil.diffopts2
127 mergetoolopts = cmdutil.mergetoolopts
127 mergetoolopts = cmdutil.mergetoolopts
128 similarityopts = cmdutil.similarityopts
128 similarityopts = cmdutil.similarityopts
129 subrepoopts = cmdutil.subrepoopts
129 subrepoopts = cmdutil.subrepoopts
130 debugrevlogopts = cmdutil.debugrevlogopts
130 debugrevlogopts = cmdutil.debugrevlogopts
131
131
132 # Commands start here, listed alphabetically
132 # Commands start here, listed alphabetically
133
133
134 @command('abort',
134 @command('abort',
135 dryrunopts, helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
135 dryrunopts, helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
136 helpbasic=True)
136 helpbasic=True)
137 def abort(ui, repo, **opts):
137 def abort(ui, repo, **opts):
138 """abort an unfinished operation (EXPERIMENTAL)
138 """abort an unfinished operation (EXPERIMENTAL)
139
139
140 Aborts a multistep operation like graft, histedit, rebase, merge,
140 Aborts a multistep operation like graft, histedit, rebase, merge,
141 and unshelve if they are in an unfinished state.
141 and unshelve if they are in an unfinished state.
142
142
143 use --dry-run/-n to dry run the command.
143 use --dry-run/-n to dry run the command.
144 """
144 """
145 dryrun = opts.get(r'dry_run')
145 dryrun = opts.get(r'dry_run')
146 abortstate = cmdutil.getunfinishedstate(repo)
146 abortstate = cmdutil.getunfinishedstate(repo)
147 if not abortstate:
147 if not abortstate:
148 raise error.Abort(_('no operation in progress'))
148 raise error.Abort(_('no operation in progress'))
149 if not abortstate.abortfunc:
149 if not abortstate.abortfunc:
150 raise error.Abort((_("%s in progress but does not support 'hg abort'") %
150 raise error.Abort((_("%s in progress but does not support 'hg abort'") %
151 (abortstate._opname)), hint=abortstate.hint())
151 (abortstate._opname)), hint=abortstate.hint())
152 if dryrun:
152 if dryrun:
153 ui.status(_('%s in progress, will be aborted\n') % (abortstate._opname))
153 ui.status(_('%s in progress, will be aborted\n') % (abortstate._opname))
154 return
154 return
155 return abortstate.abortfunc(ui, repo)
155 return abortstate.abortfunc(ui, repo)
156
156
157 @command('add',
157 @command('add',
158 walkopts + subrepoopts + dryrunopts,
158 walkopts + subrepoopts + dryrunopts,
159 _('[OPTION]... [FILE]...'),
159 _('[OPTION]... [FILE]...'),
160 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
160 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
161 helpbasic=True, inferrepo=True)
161 helpbasic=True, inferrepo=True)
162 def add(ui, repo, *pats, **opts):
162 def add(ui, repo, *pats, **opts):
163 """add the specified files on the next commit
163 """add the specified files on the next commit
164
164
165 Schedule files to be version controlled and added to the
165 Schedule files to be version controlled and added to the
166 repository.
166 repository.
167
167
168 The files will be added to the repository at the next commit. To
168 The files will be added to the repository at the next commit. To
169 undo an add before that, see :hg:`forget`.
169 undo an add before that, see :hg:`forget`.
170
170
171 If no names are given, add all files to the repository (except
171 If no names are given, add all files to the repository (except
172 files matching ``.hgignore``).
172 files matching ``.hgignore``).
173
173
174 .. container:: verbose
174 .. container:: verbose
175
175
176 Examples:
176 Examples:
177
177
178 - New (unknown) files are added
178 - New (unknown) files are added
179 automatically by :hg:`add`::
179 automatically by :hg:`add`::
180
180
181 $ ls
181 $ ls
182 foo.c
182 foo.c
183 $ hg status
183 $ hg status
184 ? foo.c
184 ? foo.c
185 $ hg add
185 $ hg add
186 adding foo.c
186 adding foo.c
187 $ hg status
187 $ hg status
188 A foo.c
188 A foo.c
189
189
190 - Specific files to be added can be specified::
190 - Specific files to be added can be specified::
191
191
192 $ ls
192 $ ls
193 bar.c foo.c
193 bar.c foo.c
194 $ hg status
194 $ hg status
195 ? bar.c
195 ? bar.c
196 ? foo.c
196 ? foo.c
197 $ hg add bar.c
197 $ hg add bar.c
198 $ hg status
198 $ hg status
199 A bar.c
199 A bar.c
200 ? foo.c
200 ? foo.c
201
201
202 Returns 0 if all files are successfully added.
202 Returns 0 if all files are successfully added.
203 """
203 """
204
204
205 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
205 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
206 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
206 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
207 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
207 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
208 return rejected and 1 or 0
208 return rejected and 1 or 0
209
209
210 @command('addremove',
210 @command('addremove',
211 similarityopts + subrepoopts + walkopts + dryrunopts,
211 similarityopts + subrepoopts + walkopts + dryrunopts,
212 _('[OPTION]... [FILE]...'),
212 _('[OPTION]... [FILE]...'),
213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
213 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
214 inferrepo=True)
214 inferrepo=True)
215 def addremove(ui, repo, *pats, **opts):
215 def addremove(ui, repo, *pats, **opts):
216 """add all new files, delete all missing files
216 """add all new files, delete all missing files
217
217
218 Add all new files and remove all missing files from the
218 Add all new files and remove all missing files from the
219 repository.
219 repository.
220
220
221 Unless names are given, new files are ignored if they match any of
221 Unless names are given, new files are ignored if they match any of
222 the patterns in ``.hgignore``. As with add, these changes take
222 the patterns in ``.hgignore``. As with add, these changes take
223 effect at the next commit.
223 effect at the next commit.
224
224
225 Use the -s/--similarity option to detect renamed files. This
225 Use the -s/--similarity option to detect renamed files. This
226 option takes a percentage between 0 (disabled) and 100 (files must
226 option takes a percentage between 0 (disabled) and 100 (files must
227 be identical) as its parameter. With a parameter greater than 0,
227 be identical) as its parameter. With a parameter greater than 0,
228 this compares every removed file with every added file and records
228 this compares every removed file with every added file and records
229 those similar enough as renames. Detecting renamed files this way
229 those similar enough as renames. Detecting renamed files this way
230 can be expensive. After using this option, :hg:`status -C` can be
230 can be expensive. After using this option, :hg:`status -C` can be
231 used to check which files were identified as moved or renamed. If
231 used to check which files were identified as moved or renamed. If
232 not specified, -s/--similarity defaults to 100 and only renames of
232 not specified, -s/--similarity defaults to 100 and only renames of
233 identical files are detected.
233 identical files are detected.
234
234
235 .. container:: verbose
235 .. container:: verbose
236
236
237 Examples:
237 Examples:
238
238
239 - A number of files (bar.c and foo.c) are new,
239 - A number of files (bar.c and foo.c) are new,
240 while foobar.c has been removed (without using :hg:`remove`)
240 while foobar.c has been removed (without using :hg:`remove`)
241 from the repository::
241 from the repository::
242
242
243 $ ls
243 $ ls
244 bar.c foo.c
244 bar.c foo.c
245 $ hg status
245 $ hg status
246 ! foobar.c
246 ! foobar.c
247 ? bar.c
247 ? bar.c
248 ? foo.c
248 ? foo.c
249 $ hg addremove
249 $ hg addremove
250 adding bar.c
250 adding bar.c
251 adding foo.c
251 adding foo.c
252 removing foobar.c
252 removing foobar.c
253 $ hg status
253 $ hg status
254 A bar.c
254 A bar.c
255 A foo.c
255 A foo.c
256 R foobar.c
256 R foobar.c
257
257
258 - A file foobar.c was moved to foo.c without using :hg:`rename`.
258 - A file foobar.c was moved to foo.c without using :hg:`rename`.
259 Afterwards, it was edited slightly::
259 Afterwards, it was edited slightly::
260
260
261 $ ls
261 $ ls
262 foo.c
262 foo.c
263 $ hg status
263 $ hg status
264 ! foobar.c
264 ! foobar.c
265 ? foo.c
265 ? foo.c
266 $ hg addremove --similarity 90
266 $ hg addremove --similarity 90
267 removing foobar.c
267 removing foobar.c
268 adding foo.c
268 adding foo.c
269 recording removal of foobar.c as rename to foo.c (94% similar)
269 recording removal of foobar.c as rename to foo.c (94% similar)
270 $ hg status -C
270 $ hg status -C
271 A foo.c
271 A foo.c
272 foobar.c
272 foobar.c
273 R foobar.c
273 R foobar.c
274
274
275 Returns 0 if all files are successfully added.
275 Returns 0 if all files are successfully added.
276 """
276 """
277 opts = pycompat.byteskwargs(opts)
277 opts = pycompat.byteskwargs(opts)
278 if not opts.get('similarity'):
278 if not opts.get('similarity'):
279 opts['similarity'] = '100'
279 opts['similarity'] = '100'
280 matcher = scmutil.match(repo[None], pats, opts)
280 matcher = scmutil.match(repo[None], pats, opts)
281 relative = scmutil.anypats(pats, opts)
281 relative = scmutil.anypats(pats, opts)
282 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
282 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
283 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
283 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
284
284
285 @command('annotate|blame',
285 @command('annotate|blame',
286 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
286 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
287 ('', 'follow', None,
287 ('', 'follow', None,
288 _('follow copies/renames and list the filename (DEPRECATED)')),
288 _('follow copies/renames and list the filename (DEPRECATED)')),
289 ('', 'no-follow', None, _("don't follow copies and renames")),
289 ('', 'no-follow', None, _("don't follow copies and renames")),
290 ('a', 'text', None, _('treat all files as text')),
290 ('a', 'text', None, _('treat all files as text')),
291 ('u', 'user', None, _('list the author (long with -v)')),
291 ('u', 'user', None, _('list the author (long with -v)')),
292 ('f', 'file', None, _('list the filename')),
292 ('f', 'file', None, _('list the filename')),
293 ('d', 'date', None, _('list the date (short with -q)')),
293 ('d', 'date', None, _('list the date (short with -q)')),
294 ('n', 'number', None, _('list the revision number (default)')),
294 ('n', 'number', None, _('list the revision number (default)')),
295 ('c', 'changeset', None, _('list the changeset')),
295 ('c', 'changeset', None, _('list the changeset')),
296 ('l', 'line-number', None, _('show line number at the first appearance')),
296 ('l', 'line-number', None, _('show line number at the first appearance')),
297 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
297 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
298 ] + diffwsopts + walkopts + formatteropts,
298 ] + diffwsopts + walkopts + formatteropts,
299 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
299 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
300 helpcategory=command.CATEGORY_FILE_CONTENTS,
300 helpcategory=command.CATEGORY_FILE_CONTENTS,
301 helpbasic=True, inferrepo=True)
301 helpbasic=True, inferrepo=True)
302 def annotate(ui, repo, *pats, **opts):
302 def annotate(ui, repo, *pats, **opts):
303 """show changeset information by line for each file
303 """show changeset information by line for each file
304
304
305 List changes in files, showing the revision id responsible for
305 List changes in files, showing the revision id responsible for
306 each line.
306 each line.
307
307
308 This command is useful for discovering when a change was made and
308 This command is useful for discovering when a change was made and
309 by whom.
309 by whom.
310
310
311 If you include --file, --user, or --date, the revision number is
311 If you include --file, --user, or --date, the revision number is
312 suppressed unless you also include --number.
312 suppressed unless you also include --number.
313
313
314 Without the -a/--text option, annotate will avoid processing files
314 Without the -a/--text option, annotate will avoid processing files
315 it detects as binary. With -a, annotate will annotate the file
315 it detects as binary. With -a, annotate will annotate the file
316 anyway, although the results will probably be neither useful
316 anyway, although the results will probably be neither useful
317 nor desirable.
317 nor desirable.
318
318
319 .. container:: verbose
319 .. container:: verbose
320
320
321 Template:
321 Template:
322
322
323 The following keywords are supported in addition to the common template
323 The following keywords are supported in addition to the common template
324 keywords and functions. See also :hg:`help templates`.
324 keywords and functions. See also :hg:`help templates`.
325
325
326 :lines: List of lines with annotation data.
326 :lines: List of lines with annotation data.
327 :path: String. Repository-absolute path of the specified file.
327 :path: String. Repository-absolute path of the specified file.
328
328
329 And each entry of ``{lines}`` provides the following sub-keywords in
329 And each entry of ``{lines}`` provides the following sub-keywords in
330 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
330 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
331
331
332 :line: String. Line content.
332 :line: String. Line content.
333 :lineno: Integer. Line number at that revision.
333 :lineno: Integer. Line number at that revision.
334 :path: String. Repository-absolute path of the file at that revision.
334 :path: String. Repository-absolute path of the file at that revision.
335
335
336 See :hg:`help templates.operators` for the list expansion syntax.
336 See :hg:`help templates.operators` for the list expansion syntax.
337
337
338 Returns 0 on success.
338 Returns 0 on success.
339 """
339 """
340 opts = pycompat.byteskwargs(opts)
340 opts = pycompat.byteskwargs(opts)
341 if not pats:
341 if not pats:
342 raise error.Abort(_('at least one filename or pattern is required'))
342 raise error.Abort(_('at least one filename or pattern is required'))
343
343
344 if opts.get('follow'):
344 if opts.get('follow'):
345 # --follow is deprecated and now just an alias for -f/--file
345 # --follow is deprecated and now just an alias for -f/--file
346 # to mimic the behavior of Mercurial before version 1.5
346 # to mimic the behavior of Mercurial before version 1.5
347 opts['file'] = True
347 opts['file'] = True
348
348
349 if (not opts.get('user') and not opts.get('changeset')
349 if (not opts.get('user') and not opts.get('changeset')
350 and not opts.get('date') and not opts.get('file')):
350 and not opts.get('date') and not opts.get('file')):
351 opts['number'] = True
351 opts['number'] = True
352
352
353 linenumber = opts.get('line_number') is not None
353 linenumber = opts.get('line_number') is not None
354 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
354 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
355 raise error.Abort(_('at least one of -n/-c is required for -l'))
355 raise error.Abort(_('at least one of -n/-c is required for -l'))
356
356
357 rev = opts.get('rev')
357 rev = opts.get('rev')
358 if rev:
358 if rev:
359 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
359 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
360 ctx = scmutil.revsingle(repo, rev)
360 ctx = scmutil.revsingle(repo, rev)
361
361
362 ui.pager('annotate')
362 ui.pager('annotate')
363 rootfm = ui.formatter('annotate', opts)
363 rootfm = ui.formatter('annotate', opts)
364 if ui.debugflag:
364 if ui.debugflag:
365 shorthex = pycompat.identity
365 shorthex = pycompat.identity
366 else:
366 else:
367 def shorthex(h):
367 def shorthex(h):
368 return h[:12]
368 return h[:12]
369 if ui.quiet:
369 if ui.quiet:
370 datefunc = dateutil.shortdate
370 datefunc = dateutil.shortdate
371 else:
371 else:
372 datefunc = dateutil.datestr
372 datefunc = dateutil.datestr
373 if ctx.rev() is None:
373 if ctx.rev() is None:
374 if opts.get('changeset'):
374 if opts.get('changeset'):
375 # omit "+" suffix which is appended to node hex
375 # omit "+" suffix which is appended to node hex
376 def formatrev(rev):
376 def formatrev(rev):
377 if rev == wdirrev:
377 if rev == wdirrev:
378 return '%d' % ctx.p1().rev()
378 return '%d' % ctx.p1().rev()
379 else:
379 else:
380 return '%d' % rev
380 return '%d' % rev
381 else:
381 else:
382 def formatrev(rev):
382 def formatrev(rev):
383 if rev == wdirrev:
383 if rev == wdirrev:
384 return '%d+' % ctx.p1().rev()
384 return '%d+' % ctx.p1().rev()
385 else:
385 else:
386 return '%d ' % rev
386 return '%d ' % rev
387 def formathex(h):
387 def formathex(h):
388 if h == wdirhex:
388 if h == wdirhex:
389 return '%s+' % shorthex(hex(ctx.p1().node()))
389 return '%s+' % shorthex(hex(ctx.p1().node()))
390 else:
390 else:
391 return '%s ' % shorthex(h)
391 return '%s ' % shorthex(h)
392 else:
392 else:
393 formatrev = b'%d'.__mod__
393 formatrev = b'%d'.__mod__
394 formathex = shorthex
394 formathex = shorthex
395
395
396 opmap = [
396 opmap = [
397 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
397 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
398 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
398 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
399 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
399 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
400 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
400 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
401 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
401 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
402 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
402 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
403 ]
403 ]
404 opnamemap = {
404 opnamemap = {
405 'rev': 'number',
405 'rev': 'number',
406 'node': 'changeset',
406 'node': 'changeset',
407 'path': 'file',
407 'path': 'file',
408 'lineno': 'line_number',
408 'lineno': 'line_number',
409 }
409 }
410
410
411 if rootfm.isplain():
411 if rootfm.isplain():
412 def makefunc(get, fmt):
412 def makefunc(get, fmt):
413 return lambda x: fmt(get(x))
413 return lambda x: fmt(get(x))
414 else:
414 else:
415 def makefunc(get, fmt):
415 def makefunc(get, fmt):
416 return get
416 return get
417 datahint = rootfm.datahint()
417 datahint = rootfm.datahint()
418 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
418 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
419 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
419 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
420 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
420 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
421 fields = ' '.join(fn for fn, sep, get, fmt in opmap
421 fields = ' '.join(fn for fn, sep, get, fmt in opmap
422 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
422 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
423
423
424 def bad(x, y):
424 def bad(x, y):
425 raise error.Abort("%s: %s" % (x, y))
425 raise error.Abort("%s: %s" % (x, y))
426
426
427 m = scmutil.match(ctx, pats, opts, badfn=bad)
427 m = scmutil.match(ctx, pats, opts, badfn=bad)
428
428
429 follow = not opts.get('no_follow')
429 follow = not opts.get('no_follow')
430 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
430 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
431 whitespace=True)
431 whitespace=True)
432 skiprevs = opts.get('skip')
432 skiprevs = opts.get('skip')
433 if skiprevs:
433 if skiprevs:
434 skiprevs = scmutil.revrange(repo, skiprevs)
434 skiprevs = scmutil.revrange(repo, skiprevs)
435
435
436 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
436 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
437 for abs in ctx.walk(m):
437 for abs in ctx.walk(m):
438 fctx = ctx[abs]
438 fctx = ctx[abs]
439 rootfm.startitem()
439 rootfm.startitem()
440 rootfm.data(path=abs)
440 rootfm.data(path=abs)
441 if not opts.get('text') and fctx.isbinary():
441 if not opts.get('text') and fctx.isbinary():
442 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
442 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
443 continue
443 continue
444
444
445 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
445 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
446 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
446 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
447 diffopts=diffopts)
447 diffopts=diffopts)
448 if not lines:
448 if not lines:
449 fm.end()
449 fm.end()
450 continue
450 continue
451 formats = []
451 formats = []
452 pieces = []
452 pieces = []
453
453
454 for f, sep in funcmap:
454 for f, sep in funcmap:
455 l = [f(n) for n in lines]
455 l = [f(n) for n in lines]
456 if fm.isplain():
456 if fm.isplain():
457 sizes = [encoding.colwidth(x) for x in l]
457 sizes = [encoding.colwidth(x) for x in l]
458 ml = max(sizes)
458 ml = max(sizes)
459 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
459 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
460 else:
460 else:
461 formats.append(['%s' for x in l])
461 formats.append(['%s' for x in l])
462 pieces.append(l)
462 pieces.append(l)
463
463
464 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
464 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
465 fm.startitem()
465 fm.startitem()
466 fm.context(fctx=n.fctx)
466 fm.context(fctx=n.fctx)
467 fm.write(fields, "".join(f), *p)
467 fm.write(fields, "".join(f), *p)
468 if n.skip:
468 if n.skip:
469 fmt = "* %s"
469 fmt = "* %s"
470 else:
470 else:
471 fmt = ": %s"
471 fmt = ": %s"
472 fm.write('line', fmt, n.text)
472 fm.write('line', fmt, n.text)
473
473
474 if not lines[-1].text.endswith('\n'):
474 if not lines[-1].text.endswith('\n'):
475 fm.plain('\n')
475 fm.plain('\n')
476 fm.end()
476 fm.end()
477
477
478 rootfm.end()
478 rootfm.end()
479
479
480 @command('archive',
480 @command('archive',
481 [('', 'no-decode', None, _('do not pass files through decoders')),
481 [('', 'no-decode', None, _('do not pass files through decoders')),
482 ('p', 'prefix', '', _('directory prefix for files in archive'),
482 ('p', 'prefix', '', _('directory prefix for files in archive'),
483 _('PREFIX')),
483 _('PREFIX')),
484 ('r', 'rev', '', _('revision to distribute'), _('REV')),
484 ('r', 'rev', '', _('revision to distribute'), _('REV')),
485 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
485 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
486 ] + subrepoopts + walkopts,
486 ] + subrepoopts + walkopts,
487 _('[OPTION]... DEST'),
487 _('[OPTION]... DEST'),
488 helpcategory=command.CATEGORY_IMPORT_EXPORT)
488 helpcategory=command.CATEGORY_IMPORT_EXPORT)
489 def archive(ui, repo, dest, **opts):
489 def archive(ui, repo, dest, **opts):
490 '''create an unversioned archive of a repository revision
490 '''create an unversioned archive of a repository revision
491
491
492 By default, the revision used is the parent of the working
492 By default, the revision used is the parent of the working
493 directory; use -r/--rev to specify a different revision.
493 directory; use -r/--rev to specify a different revision.
494
494
495 The archive type is automatically detected based on file
495 The archive type is automatically detected based on file
496 extension (to override, use -t/--type).
496 extension (to override, use -t/--type).
497
497
498 .. container:: verbose
498 .. container:: verbose
499
499
500 Examples:
500 Examples:
501
501
502 - create a zip file containing the 1.0 release::
502 - create a zip file containing the 1.0 release::
503
503
504 hg archive -r 1.0 project-1.0.zip
504 hg archive -r 1.0 project-1.0.zip
505
505
506 - create a tarball excluding .hg files::
506 - create a tarball excluding .hg files::
507
507
508 hg archive project.tar.gz -X ".hg*"
508 hg archive project.tar.gz -X ".hg*"
509
509
510 Valid types are:
510 Valid types are:
511
511
512 :``files``: a directory full of files (default)
512 :``files``: a directory full of files (default)
513 :``tar``: tar archive, uncompressed
513 :``tar``: tar archive, uncompressed
514 :``tbz2``: tar archive, compressed using bzip2
514 :``tbz2``: tar archive, compressed using bzip2
515 :``tgz``: tar archive, compressed using gzip
515 :``tgz``: tar archive, compressed using gzip
516 :``uzip``: zip archive, uncompressed
516 :``uzip``: zip archive, uncompressed
517 :``zip``: zip archive, compressed using deflate
517 :``zip``: zip archive, compressed using deflate
518
518
519 The exact name of the destination archive or directory is given
519 The exact name of the destination archive or directory is given
520 using a format string; see :hg:`help export` for details.
520 using a format string; see :hg:`help export` for details.
521
521
522 Each member added to an archive file has a directory prefix
522 Each member added to an archive file has a directory prefix
523 prepended. Use -p/--prefix to specify a format string for the
523 prepended. Use -p/--prefix to specify a format string for the
524 prefix. The default is the basename of the archive, with suffixes
524 prefix. The default is the basename of the archive, with suffixes
525 removed.
525 removed.
526
526
527 Returns 0 on success.
527 Returns 0 on success.
528 '''
528 '''
529
529
530 opts = pycompat.byteskwargs(opts)
530 opts = pycompat.byteskwargs(opts)
531 rev = opts.get('rev')
531 rev = opts.get('rev')
532 if rev:
532 if rev:
533 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
533 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
534 ctx = scmutil.revsingle(repo, rev)
534 ctx = scmutil.revsingle(repo, rev)
535 if not ctx:
535 if not ctx:
536 raise error.Abort(_('no working directory: please specify a revision'))
536 raise error.Abort(_('no working directory: please specify a revision'))
537 node = ctx.node()
537 node = ctx.node()
538 dest = cmdutil.makefilename(ctx, dest)
538 dest = cmdutil.makefilename(ctx, dest)
539 if os.path.realpath(dest) == repo.root:
539 if os.path.realpath(dest) == repo.root:
540 raise error.Abort(_('repository root cannot be destination'))
540 raise error.Abort(_('repository root cannot be destination'))
541
541
542 kind = opts.get('type') or archival.guesskind(dest) or 'files'
542 kind = opts.get('type') or archival.guesskind(dest) or 'files'
543 prefix = opts.get('prefix')
543 prefix = opts.get('prefix')
544
544
545 if dest == '-':
545 if dest == '-':
546 if kind == 'files':
546 if kind == 'files':
547 raise error.Abort(_('cannot archive plain files to stdout'))
547 raise error.Abort(_('cannot archive plain files to stdout'))
548 dest = cmdutil.makefileobj(ctx, dest)
548 dest = cmdutil.makefileobj(ctx, dest)
549 if not prefix:
549 if not prefix:
550 prefix = os.path.basename(repo.root) + '-%h'
550 prefix = os.path.basename(repo.root) + '-%h'
551
551
552 prefix = cmdutil.makefilename(ctx, prefix)
552 prefix = cmdutil.makefilename(ctx, prefix)
553 match = scmutil.match(ctx, [], opts)
553 match = scmutil.match(ctx, [], opts)
554 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
554 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
555 match, prefix, subrepos=opts.get('subrepos'))
555 match, prefix, subrepos=opts.get('subrepos'))
556
556
557 @command('backout',
557 @command('backout',
558 [('', 'merge', None, _('merge with old dirstate parent after backout')),
558 [('', 'merge', None, _('merge with old dirstate parent after backout')),
559 ('', 'commit', None,
559 ('', 'commit', None,
560 _('commit if no conflicts were encountered (DEPRECATED)')),
560 _('commit if no conflicts were encountered (DEPRECATED)')),
561 ('', 'no-commit', None, _('do not commit')),
561 ('', 'no-commit', None, _('do not commit')),
562 ('', 'parent', '',
562 ('', 'parent', '',
563 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
563 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
564 ('r', 'rev', '', _('revision to backout'), _('REV')),
564 ('r', 'rev', '', _('revision to backout'), _('REV')),
565 ('e', 'edit', False, _('invoke editor on commit messages')),
565 ('e', 'edit', False, _('invoke editor on commit messages')),
566 ] + mergetoolopts + walkopts + commitopts + commitopts2,
566 ] + mergetoolopts + walkopts + commitopts + commitopts2,
567 _('[OPTION]... [-r] REV'),
567 _('[OPTION]... [-r] REV'),
568 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
568 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
569 def backout(ui, repo, node=None, rev=None, **opts):
569 def backout(ui, repo, node=None, rev=None, **opts):
570 '''reverse effect of earlier changeset
570 '''reverse effect of earlier changeset
571
571
572 Prepare a new changeset with the effect of REV undone in the
572 Prepare a new changeset with the effect of REV undone in the
573 current working directory. If no conflicts were encountered,
573 current working directory. If no conflicts were encountered,
574 it will be committed immediately.
574 it will be committed immediately.
575
575
576 If REV is the parent of the working directory, then this new changeset
576 If REV is the parent of the working directory, then this new changeset
577 is committed automatically (unless --no-commit is specified).
577 is committed automatically (unless --no-commit is specified).
578
578
579 .. note::
579 .. note::
580
580
581 :hg:`backout` cannot be used to fix either an unwanted or
581 :hg:`backout` cannot be used to fix either an unwanted or
582 incorrect merge.
582 incorrect merge.
583
583
584 .. container:: verbose
584 .. container:: verbose
585
585
586 Examples:
586 Examples:
587
587
588 - Reverse the effect of the parent of the working directory.
588 - Reverse the effect of the parent of the working directory.
589 This backout will be committed immediately::
589 This backout will be committed immediately::
590
590
591 hg backout -r .
591 hg backout -r .
592
592
593 - Reverse the effect of previous bad revision 23::
593 - Reverse the effect of previous bad revision 23::
594
594
595 hg backout -r 23
595 hg backout -r 23
596
596
597 - Reverse the effect of previous bad revision 23 and
597 - Reverse the effect of previous bad revision 23 and
598 leave changes uncommitted::
598 leave changes uncommitted::
599
599
600 hg backout -r 23 --no-commit
600 hg backout -r 23 --no-commit
601 hg commit -m "Backout revision 23"
601 hg commit -m "Backout revision 23"
602
602
603 By default, the pending changeset will have one parent,
603 By default, the pending changeset will have one parent,
604 maintaining a linear history. With --merge, the pending
604 maintaining a linear history. With --merge, the pending
605 changeset will instead have two parents: the old parent of the
605 changeset will instead have two parents: the old parent of the
606 working directory and a new child of REV that simply undoes REV.
606 working directory and a new child of REV that simply undoes REV.
607
607
608 Before version 1.7, the behavior without --merge was equivalent
608 Before version 1.7, the behavior without --merge was equivalent
609 to specifying --merge followed by :hg:`update --clean .` to
609 to specifying --merge followed by :hg:`update --clean .` to
610 cancel the merge and leave the child of REV as a head to be
610 cancel the merge and leave the child of REV as a head to be
611 merged separately.
611 merged separately.
612
612
613 See :hg:`help dates` for a list of formats valid for -d/--date.
613 See :hg:`help dates` for a list of formats valid for -d/--date.
614
614
615 See :hg:`help revert` for a way to restore files to the state
615 See :hg:`help revert` for a way to restore files to the state
616 of another revision.
616 of another revision.
617
617
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
618 Returns 0 on success, 1 if nothing to backout or there are unresolved
619 files.
619 files.
620 '''
620 '''
621 with repo.wlock(), repo.lock():
621 with repo.wlock(), repo.lock():
622 return _dobackout(ui, repo, node, rev, **opts)
622 return _dobackout(ui, repo, node, rev, **opts)
623
623
624 def _dobackout(ui, repo, node=None, rev=None, **opts):
624 def _dobackout(ui, repo, node=None, rev=None, **opts):
625 opts = pycompat.byteskwargs(opts)
625 opts = pycompat.byteskwargs(opts)
626 if opts.get('commit') and opts.get('no_commit'):
626 if opts.get('commit') and opts.get('no_commit'):
627 raise error.Abort(_("cannot use --commit with --no-commit"))
627 raise error.Abort(_("cannot use --commit with --no-commit"))
628 if opts.get('merge') and opts.get('no_commit'):
628 if opts.get('merge') and opts.get('no_commit'):
629 raise error.Abort(_("cannot use --merge with --no-commit"))
629 raise error.Abort(_("cannot use --merge with --no-commit"))
630
630
631 if rev and node:
631 if rev and node:
632 raise error.Abort(_("please specify just one revision"))
632 raise error.Abort(_("please specify just one revision"))
633
633
634 if not rev:
634 if not rev:
635 rev = node
635 rev = node
636
636
637 if not rev:
637 if not rev:
638 raise error.Abort(_("please specify a revision to backout"))
638 raise error.Abort(_("please specify a revision to backout"))
639
639
640 date = opts.get('date')
640 date = opts.get('date')
641 if date:
641 if date:
642 opts['date'] = dateutil.parsedate(date)
642 opts['date'] = dateutil.parsedate(date)
643
643
644 cmdutil.checkunfinished(repo)
644 cmdutil.checkunfinished(repo)
645 cmdutil.bailifchanged(repo)
645 cmdutil.bailifchanged(repo)
646 node = scmutil.revsingle(repo, rev).node()
646 node = scmutil.revsingle(repo, rev).node()
647
647
648 op1, op2 = repo.dirstate.parents()
648 op1, op2 = repo.dirstate.parents()
649 if not repo.changelog.isancestor(node, op1):
649 if not repo.changelog.isancestor(node, op1):
650 raise error.Abort(_('cannot backout change that is not an ancestor'))
650 raise error.Abort(_('cannot backout change that is not an ancestor'))
651
651
652 p1, p2 = repo.changelog.parents(node)
652 p1, p2 = repo.changelog.parents(node)
653 if p1 == nullid:
653 if p1 == nullid:
654 raise error.Abort(_('cannot backout a change with no parents'))
654 raise error.Abort(_('cannot backout a change with no parents'))
655 if p2 != nullid:
655 if p2 != nullid:
656 if not opts.get('parent'):
656 if not opts.get('parent'):
657 raise error.Abort(_('cannot backout a merge changeset'))
657 raise error.Abort(_('cannot backout a merge changeset'))
658 p = repo.lookup(opts['parent'])
658 p = repo.lookup(opts['parent'])
659 if p not in (p1, p2):
659 if p not in (p1, p2):
660 raise error.Abort(_('%s is not a parent of %s') %
660 raise error.Abort(_('%s is not a parent of %s') %
661 (short(p), short(node)))
661 (short(p), short(node)))
662 parent = p
662 parent = p
663 else:
663 else:
664 if opts.get('parent'):
664 if opts.get('parent'):
665 raise error.Abort(_('cannot use --parent on non-merge changeset'))
665 raise error.Abort(_('cannot use --parent on non-merge changeset'))
666 parent = p1
666 parent = p1
667
667
668 # the backout should appear on the same branch
668 # the backout should appear on the same branch
669 branch = repo.dirstate.branch()
669 branch = repo.dirstate.branch()
670 bheads = repo.branchheads(branch)
670 bheads = repo.branchheads(branch)
671 rctx = scmutil.revsingle(repo, hex(parent))
671 rctx = scmutil.revsingle(repo, hex(parent))
672 if not opts.get('merge') and op1 != node:
672 if not opts.get('merge') and op1 != node:
673 with dirstateguard.dirstateguard(repo, 'backout'):
673 with dirstateguard.dirstateguard(repo, 'backout'):
674 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
674 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
675 with ui.configoverride(overrides, 'backout'):
675 with ui.configoverride(overrides, 'backout'):
676 stats = mergemod.update(repo, parent, branchmerge=True,
676 stats = mergemod.update(repo, parent, branchmerge=True,
677 force=True, ancestor=node,
677 force=True, ancestor=node,
678 mergeancestor=False)
678 mergeancestor=False)
679 repo.setparents(op1, op2)
679 repo.setparents(op1, op2)
680 hg._showstats(repo, stats)
680 hg._showstats(repo, stats)
681 if stats.unresolvedcount:
681 if stats.unresolvedcount:
682 repo.ui.status(_("use 'hg resolve' to retry unresolved "
682 repo.ui.status(_("use 'hg resolve' to retry unresolved "
683 "file merges\n"))
683 "file merges\n"))
684 return 1
684 return 1
685 else:
685 else:
686 hg.clean(repo, node, show_stats=False)
686 hg.clean(repo, node, show_stats=False)
687 repo.dirstate.setbranch(branch)
687 repo.dirstate.setbranch(branch)
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
689
689
690 if opts.get('no_commit'):
690 if opts.get('no_commit'):
691 msg = _("changeset %s backed out, "
691 msg = _("changeset %s backed out, "
692 "don't forget to commit.\n")
692 "don't forget to commit.\n")
693 ui.status(msg % short(node))
693 ui.status(msg % short(node))
694 return 0
694 return 0
695
695
696 def commitfunc(ui, repo, message, match, opts):
696 def commitfunc(ui, repo, message, match, opts):
697 editform = 'backout'
697 editform = 'backout'
698 e = cmdutil.getcommiteditor(editform=editform,
698 e = cmdutil.getcommiteditor(editform=editform,
699 **pycompat.strkwargs(opts))
699 **pycompat.strkwargs(opts))
700 if not message:
700 if not message:
701 # we don't translate commit messages
701 # we don't translate commit messages
702 message = "Backed out changeset %s" % short(node)
702 message = "Backed out changeset %s" % short(node)
703 e = cmdutil.getcommiteditor(edit=True, editform=editform)
703 e = cmdutil.getcommiteditor(edit=True, editform=editform)
704 return repo.commit(message, opts.get('user'), opts.get('date'),
704 return repo.commit(message, opts.get('user'), opts.get('date'),
705 match, editor=e)
705 match, editor=e)
706 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
706 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
707 if not newnode:
707 if not newnode:
708 ui.status(_("nothing changed\n"))
708 ui.status(_("nothing changed\n"))
709 return 1
709 return 1
710 cmdutil.commitstatus(repo, newnode, branch, bheads)
710 cmdutil.commitstatus(repo, newnode, branch, bheads)
711
711
712 def nice(node):
712 def nice(node):
713 return '%d:%s' % (repo.changelog.rev(node), short(node))
713 return '%d:%s' % (repo.changelog.rev(node), short(node))
714 ui.status(_('changeset %s backs out changeset %s\n') %
714 ui.status(_('changeset %s backs out changeset %s\n') %
715 (nice(repo.changelog.tip()), nice(node)))
715 (nice(repo.changelog.tip()), nice(node)))
716 if opts.get('merge') and op1 != node:
716 if opts.get('merge') and op1 != node:
717 hg.clean(repo, op1, show_stats=False)
717 hg.clean(repo, op1, show_stats=False)
718 ui.status(_('merging with changeset %s\n')
718 ui.status(_('merging with changeset %s\n')
719 % nice(repo.changelog.tip()))
719 % nice(repo.changelog.tip()))
720 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
720 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
721 with ui.configoverride(overrides, 'backout'):
721 with ui.configoverride(overrides, 'backout'):
722 return hg.merge(repo, hex(repo.changelog.tip()))
722 return hg.merge(repo, hex(repo.changelog.tip()))
723 return 0
723 return 0
724
724
725 @command('bisect',
725 @command('bisect',
726 [('r', 'reset', False, _('reset bisect state')),
726 [('r', 'reset', False, _('reset bisect state')),
727 ('g', 'good', False, _('mark changeset good')),
727 ('g', 'good', False, _('mark changeset good')),
728 ('b', 'bad', False, _('mark changeset bad')),
728 ('b', 'bad', False, _('mark changeset bad')),
729 ('s', 'skip', False, _('skip testing changeset')),
729 ('s', 'skip', False, _('skip testing changeset')),
730 ('e', 'extend', False, _('extend the bisect range')),
730 ('e', 'extend', False, _('extend the bisect range')),
731 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
731 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
732 ('U', 'noupdate', False, _('do not update to target'))],
732 ('U', 'noupdate', False, _('do not update to target'))],
733 _("[-gbsr] [-U] [-c CMD] [REV]"),
733 _("[-gbsr] [-U] [-c CMD] [REV]"),
734 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
734 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
735 def bisect(ui, repo, rev=None, extra=None, command=None,
735 def bisect(ui, repo, rev=None, extra=None, command=None,
736 reset=None, good=None, bad=None, skip=None, extend=None,
736 reset=None, good=None, bad=None, skip=None, extend=None,
737 noupdate=None):
737 noupdate=None):
738 """subdivision search of changesets
738 """subdivision search of changesets
739
739
740 This command helps to find changesets which introduce problems. To
740 This command helps to find changesets which introduce problems. To
741 use, mark the earliest changeset you know exhibits the problem as
741 use, mark the earliest changeset you know exhibits the problem as
742 bad, then mark the latest changeset which is free from the problem
742 bad, then mark the latest changeset which is free from the problem
743 as good. Bisect will update your working directory to a revision
743 as good. Bisect will update your working directory to a revision
744 for testing (unless the -U/--noupdate option is specified). Once
744 for testing (unless the -U/--noupdate option is specified). Once
745 you have performed tests, mark the working directory as good or
745 you have performed tests, mark the working directory as good or
746 bad, and bisect will either update to another candidate changeset
746 bad, and bisect will either update to another candidate changeset
747 or announce that it has found the bad revision.
747 or announce that it has found the bad revision.
748
748
749 As a shortcut, you can also use the revision argument to mark a
749 As a shortcut, you can also use the revision argument to mark a
750 revision as good or bad without checking it out first.
750 revision as good or bad without checking it out first.
751
751
752 If you supply a command, it will be used for automatic bisection.
752 If you supply a command, it will be used for automatic bisection.
753 The environment variable HG_NODE will contain the ID of the
753 The environment variable HG_NODE will contain the ID of the
754 changeset being tested. The exit status of the command will be
754 changeset being tested. The exit status of the command will be
755 used to mark revisions as good or bad: status 0 means good, 125
755 used to mark revisions as good or bad: status 0 means good, 125
756 means to skip the revision, 127 (command not found) will abort the
756 means to skip the revision, 127 (command not found) will abort the
757 bisection, and any other non-zero exit status means the revision
757 bisection, and any other non-zero exit status means the revision
758 is bad.
758 is bad.
759
759
760 .. container:: verbose
760 .. container:: verbose
761
761
762 Some examples:
762 Some examples:
763
763
764 - start a bisection with known bad revision 34, and good revision 12::
764 - start a bisection with known bad revision 34, and good revision 12::
765
765
766 hg bisect --bad 34
766 hg bisect --bad 34
767 hg bisect --good 12
767 hg bisect --good 12
768
768
769 - advance the current bisection by marking current revision as good or
769 - advance the current bisection by marking current revision as good or
770 bad::
770 bad::
771
771
772 hg bisect --good
772 hg bisect --good
773 hg bisect --bad
773 hg bisect --bad
774
774
775 - mark the current revision, or a known revision, to be skipped (e.g. if
775 - mark the current revision, or a known revision, to be skipped (e.g. if
776 that revision is not usable because of another issue)::
776 that revision is not usable because of another issue)::
777
777
778 hg bisect --skip
778 hg bisect --skip
779 hg bisect --skip 23
779 hg bisect --skip 23
780
780
781 - skip all revisions that do not touch directories ``foo`` or ``bar``::
781 - skip all revisions that do not touch directories ``foo`` or ``bar``::
782
782
783 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
783 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
784
784
785 - forget the current bisection::
785 - forget the current bisection::
786
786
787 hg bisect --reset
787 hg bisect --reset
788
788
789 - use 'make && make tests' to automatically find the first broken
789 - use 'make && make tests' to automatically find the first broken
790 revision::
790 revision::
791
791
792 hg bisect --reset
792 hg bisect --reset
793 hg bisect --bad 34
793 hg bisect --bad 34
794 hg bisect --good 12
794 hg bisect --good 12
795 hg bisect --command "make && make tests"
795 hg bisect --command "make && make tests"
796
796
797 - see all changesets whose states are already known in the current
797 - see all changesets whose states are already known in the current
798 bisection::
798 bisection::
799
799
800 hg log -r "bisect(pruned)"
800 hg log -r "bisect(pruned)"
801
801
802 - see the changeset currently being bisected (especially useful
802 - see the changeset currently being bisected (especially useful
803 if running with -U/--noupdate)::
803 if running with -U/--noupdate)::
804
804
805 hg log -r "bisect(current)"
805 hg log -r "bisect(current)"
806
806
807 - see all changesets that took part in the current bisection::
807 - see all changesets that took part in the current bisection::
808
808
809 hg log -r "bisect(range)"
809 hg log -r "bisect(range)"
810
810
811 - you can even get a nice graph::
811 - you can even get a nice graph::
812
812
813 hg log --graph -r "bisect(range)"
813 hg log --graph -r "bisect(range)"
814
814
815 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
815 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
816
816
817 Returns 0 on success.
817 Returns 0 on success.
818 """
818 """
819 # backward compatibility
819 # backward compatibility
820 if rev in "good bad reset init".split():
820 if rev in "good bad reset init".split():
821 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
821 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
822 cmd, rev, extra = rev, extra, None
822 cmd, rev, extra = rev, extra, None
823 if cmd == "good":
823 if cmd == "good":
824 good = True
824 good = True
825 elif cmd == "bad":
825 elif cmd == "bad":
826 bad = True
826 bad = True
827 else:
827 else:
828 reset = True
828 reset = True
829 elif extra:
829 elif extra:
830 raise error.Abort(_('incompatible arguments'))
830 raise error.Abort(_('incompatible arguments'))
831
831
832 incompatibles = {
832 incompatibles = {
833 '--bad': bad,
833 '--bad': bad,
834 '--command': bool(command),
834 '--command': bool(command),
835 '--extend': extend,
835 '--extend': extend,
836 '--good': good,
836 '--good': good,
837 '--reset': reset,
837 '--reset': reset,
838 '--skip': skip,
838 '--skip': skip,
839 }
839 }
840
840
841 enabled = [x for x in incompatibles if incompatibles[x]]
841 enabled = [x for x in incompatibles if incompatibles[x]]
842
842
843 if len(enabled) > 1:
843 if len(enabled) > 1:
844 raise error.Abort(_('%s and %s are incompatible') %
844 raise error.Abort(_('%s and %s are incompatible') %
845 tuple(sorted(enabled)[0:2]))
845 tuple(sorted(enabled)[0:2]))
846
846
847 if reset:
847 if reset:
848 hbisect.resetstate(repo)
848 hbisect.resetstate(repo)
849 return
849 return
850
850
851 state = hbisect.load_state(repo)
851 state = hbisect.load_state(repo)
852
852
853 # update state
853 # update state
854 if good or bad or skip:
854 if good or bad or skip:
855 if rev:
855 if rev:
856 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
856 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
857 else:
857 else:
858 nodes = [repo.lookup('.')]
858 nodes = [repo.lookup('.')]
859 if good:
859 if good:
860 state['good'] += nodes
860 state['good'] += nodes
861 elif bad:
861 elif bad:
862 state['bad'] += nodes
862 state['bad'] += nodes
863 elif skip:
863 elif skip:
864 state['skip'] += nodes
864 state['skip'] += nodes
865 hbisect.save_state(repo, state)
865 hbisect.save_state(repo, state)
866 if not (state['good'] and state['bad']):
866 if not (state['good'] and state['bad']):
867 return
867 return
868
868
869 def mayupdate(repo, node, show_stats=True):
869 def mayupdate(repo, node, show_stats=True):
870 """common used update sequence"""
870 """common used update sequence"""
871 if noupdate:
871 if noupdate:
872 return
872 return
873 cmdutil.checkunfinished(repo)
873 cmdutil.checkunfinished(repo)
874 cmdutil.bailifchanged(repo)
874 cmdutil.bailifchanged(repo)
875 return hg.clean(repo, node, show_stats=show_stats)
875 return hg.clean(repo, node, show_stats=show_stats)
876
876
877 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
877 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
878
878
879 if command:
879 if command:
880 changesets = 1
880 changesets = 1
881 if noupdate:
881 if noupdate:
882 try:
882 try:
883 node = state['current'][0]
883 node = state['current'][0]
884 except LookupError:
884 except LookupError:
885 raise error.Abort(_('current bisect revision is unknown - '
885 raise error.Abort(_('current bisect revision is unknown - '
886 'start a new bisect to fix'))
886 'start a new bisect to fix'))
887 else:
887 else:
888 node, p2 = repo.dirstate.parents()
888 node, p2 = repo.dirstate.parents()
889 if p2 != nullid:
889 if p2 != nullid:
890 raise error.Abort(_('current bisect revision is a merge'))
890 raise error.Abort(_('current bisect revision is a merge'))
891 if rev:
891 if rev:
892 node = repo[scmutil.revsingle(repo, rev, node)].node()
892 node = repo[scmutil.revsingle(repo, rev, node)].node()
893 try:
893 try:
894 while changesets:
894 while changesets:
895 # update state
895 # update state
896 state['current'] = [node]
896 state['current'] = [node]
897 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
898 status = ui.system(command, environ={'HG_NODE': hex(node)},
898 status = ui.system(command, environ={'HG_NODE': hex(node)},
899 blockedtag='bisect_check')
899 blockedtag='bisect_check')
900 if status == 125:
900 if status == 125:
901 transition = "skip"
901 transition = "skip"
902 elif status == 0:
902 elif status == 0:
903 transition = "good"
903 transition = "good"
904 # status < 0 means process was killed
904 # status < 0 means process was killed
905 elif status == 127:
905 elif status == 127:
906 raise error.Abort(_("failed to execute %s") % command)
906 raise error.Abort(_("failed to execute %s") % command)
907 elif status < 0:
907 elif status < 0:
908 raise error.Abort(_("%s killed") % command)
908 raise error.Abort(_("%s killed") % command)
909 else:
909 else:
910 transition = "bad"
910 transition = "bad"
911 state[transition].append(node)
911 state[transition].append(node)
912 ctx = repo[node]
912 ctx = repo[node]
913 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
913 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
914 transition))
914 transition))
915 hbisect.checkstate(state)
915 hbisect.checkstate(state)
916 # bisect
916 # bisect
917 nodes, changesets, bgood = hbisect.bisect(repo, state)
917 nodes, changesets, bgood = hbisect.bisect(repo, state)
918 # update to next check
918 # update to next check
919 node = nodes[0]
919 node = nodes[0]
920 mayupdate(repo, node, show_stats=False)
920 mayupdate(repo, node, show_stats=False)
921 finally:
921 finally:
922 state['current'] = [node]
922 state['current'] = [node]
923 hbisect.save_state(repo, state)
923 hbisect.save_state(repo, state)
924 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
924 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
925 return
925 return
926
926
927 hbisect.checkstate(state)
927 hbisect.checkstate(state)
928
928
929 # actually bisect
929 # actually bisect
930 nodes, changesets, good = hbisect.bisect(repo, state)
930 nodes, changesets, good = hbisect.bisect(repo, state)
931 if extend:
931 if extend:
932 if not changesets:
932 if not changesets:
933 extendnode = hbisect.extendrange(repo, state, nodes, good)
933 extendnode = hbisect.extendrange(repo, state, nodes, good)
934 if extendnode is not None:
934 if extendnode is not None:
935 ui.write(_("Extending search to changeset %d:%s\n")
935 ui.write(_("Extending search to changeset %d:%s\n")
936 % (extendnode.rev(), extendnode))
936 % (extendnode.rev(), extendnode))
937 state['current'] = [extendnode.node()]
937 state['current'] = [extendnode.node()]
938 hbisect.save_state(repo, state)
938 hbisect.save_state(repo, state)
939 return mayupdate(repo, extendnode.node())
939 return mayupdate(repo, extendnode.node())
940 raise error.Abort(_("nothing to extend"))
940 raise error.Abort(_("nothing to extend"))
941
941
942 if changesets == 0:
942 if changesets == 0:
943 hbisect.printresult(ui, repo, state, displayer, nodes, good)
943 hbisect.printresult(ui, repo, state, displayer, nodes, good)
944 else:
944 else:
945 assert len(nodes) == 1 # only a single node can be tested next
945 assert len(nodes) == 1 # only a single node can be tested next
946 node = nodes[0]
946 node = nodes[0]
947 # compute the approximate number of remaining tests
947 # compute the approximate number of remaining tests
948 tests, size = 0, 2
948 tests, size = 0, 2
949 while size <= changesets:
949 while size <= changesets:
950 tests, size = tests + 1, size * 2
950 tests, size = tests + 1, size * 2
951 rev = repo.changelog.rev(node)
951 rev = repo.changelog.rev(node)
952 ui.write(_("Testing changeset %d:%s "
952 ui.write(_("Testing changeset %d:%s "
953 "(%d changesets remaining, ~%d tests)\n")
953 "(%d changesets remaining, ~%d tests)\n")
954 % (rev, short(node), changesets, tests))
954 % (rev, short(node), changesets, tests))
955 state['current'] = [node]
955 state['current'] = [node]
956 hbisect.save_state(repo, state)
956 hbisect.save_state(repo, state)
957 return mayupdate(repo, node)
957 return mayupdate(repo, node)
958
958
959 @command('bookmarks|bookmark',
959 @command('bookmarks|bookmark',
960 [('f', 'force', False, _('force')),
960 [('f', 'force', False, _('force')),
961 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
961 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
962 ('d', 'delete', False, _('delete a given bookmark')),
962 ('d', 'delete', False, _('delete a given bookmark')),
963 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
963 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
964 ('i', 'inactive', False, _('mark a bookmark inactive')),
964 ('i', 'inactive', False, _('mark a bookmark inactive')),
965 ('l', 'list', False, _('list existing bookmarks')),
965 ('l', 'list', False, _('list existing bookmarks')),
966 ] + formatteropts,
966 ] + formatteropts,
967 _('hg bookmarks [OPTIONS]... [NAME]...'),
967 _('hg bookmarks [OPTIONS]... [NAME]...'),
968 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
968 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
969 def bookmark(ui, repo, *names, **opts):
969 def bookmark(ui, repo, *names, **opts):
970 '''create a new bookmark or list existing bookmarks
970 '''create a new bookmark or list existing bookmarks
971
971
972 Bookmarks are labels on changesets to help track lines of development.
972 Bookmarks are labels on changesets to help track lines of development.
973 Bookmarks are unversioned and can be moved, renamed and deleted.
973 Bookmarks are unversioned and can be moved, renamed and deleted.
974 Deleting or moving a bookmark has no effect on the associated changesets.
974 Deleting or moving a bookmark has no effect on the associated changesets.
975
975
976 Creating or updating to a bookmark causes it to be marked as 'active'.
976 Creating or updating to a bookmark causes it to be marked as 'active'.
977 The active bookmark is indicated with a '*'.
977 The active bookmark is indicated with a '*'.
978 When a commit is made, the active bookmark will advance to the new commit.
978 When a commit is made, the active bookmark will advance to the new commit.
979 A plain :hg:`update` will also advance an active bookmark, if possible.
979 A plain :hg:`update` will also advance an active bookmark, if possible.
980 Updating away from a bookmark will cause it to be deactivated.
980 Updating away from a bookmark will cause it to be deactivated.
981
981
982 Bookmarks can be pushed and pulled between repositories (see
982 Bookmarks can be pushed and pulled between repositories (see
983 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
983 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
984 diverged, a new 'divergent bookmark' of the form 'name@path' will
984 diverged, a new 'divergent bookmark' of the form 'name@path' will
985 be created. Using :hg:`merge` will resolve the divergence.
985 be created. Using :hg:`merge` will resolve the divergence.
986
986
987 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
987 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
988 the active bookmark's name.
988 the active bookmark's name.
989
989
990 A bookmark named '@' has the special property that :hg:`clone` will
990 A bookmark named '@' has the special property that :hg:`clone` will
991 check it out by default if it exists.
991 check it out by default if it exists.
992
992
993 .. container:: verbose
993 .. container:: verbose
994
994
995 Template:
995 Template:
996
996
997 The following keywords are supported in addition to the common template
997 The following keywords are supported in addition to the common template
998 keywords and functions such as ``{bookmark}``. See also
998 keywords and functions such as ``{bookmark}``. See also
999 :hg:`help templates`.
999 :hg:`help templates`.
1000
1000
1001 :active: Boolean. True if the bookmark is active.
1001 :active: Boolean. True if the bookmark is active.
1002
1002
1003 Examples:
1003 Examples:
1004
1004
1005 - create an active bookmark for a new line of development::
1005 - create an active bookmark for a new line of development::
1006
1006
1007 hg book new-feature
1007 hg book new-feature
1008
1008
1009 - create an inactive bookmark as a place marker::
1009 - create an inactive bookmark as a place marker::
1010
1010
1011 hg book -i reviewed
1011 hg book -i reviewed
1012
1012
1013 - create an inactive bookmark on another changeset::
1013 - create an inactive bookmark on another changeset::
1014
1014
1015 hg book -r .^ tested
1015 hg book -r .^ tested
1016
1016
1017 - rename bookmark turkey to dinner::
1017 - rename bookmark turkey to dinner::
1018
1018
1019 hg book -m turkey dinner
1019 hg book -m turkey dinner
1020
1020
1021 - move the '@' bookmark from another branch::
1021 - move the '@' bookmark from another branch::
1022
1022
1023 hg book -f @
1023 hg book -f @
1024
1024
1025 - print only the active bookmark name::
1025 - print only the active bookmark name::
1026
1026
1027 hg book -ql .
1027 hg book -ql .
1028 '''
1028 '''
1029 opts = pycompat.byteskwargs(opts)
1029 opts = pycompat.byteskwargs(opts)
1030 force = opts.get('force')
1030 force = opts.get('force')
1031 rev = opts.get('rev')
1031 rev = opts.get('rev')
1032 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1032 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1033
1033
1034 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1034 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1035 if len(selactions) > 1:
1035 if len(selactions) > 1:
1036 raise error.Abort(_('--%s and --%s are incompatible')
1036 raise error.Abort(_('--%s and --%s are incompatible')
1037 % tuple(selactions[:2]))
1037 % tuple(selactions[:2]))
1038 if selactions:
1038 if selactions:
1039 action = selactions[0]
1039 action = selactions[0]
1040 elif names or rev:
1040 elif names or rev:
1041 action = 'add'
1041 action = 'add'
1042 elif inactive:
1042 elif inactive:
1043 action = 'inactive' # meaning deactivate
1043 action = 'inactive' # meaning deactivate
1044 else:
1044 else:
1045 action = 'list'
1045 action = 'list'
1046
1046
1047 if rev and action in {'delete', 'rename', 'list'}:
1047 if rev and action in {'delete', 'rename', 'list'}:
1048 raise error.Abort(_("--rev is incompatible with --%s") % action)
1048 raise error.Abort(_("--rev is incompatible with --%s") % action)
1049 if inactive and action in {'delete', 'list'}:
1049 if inactive and action in {'delete', 'list'}:
1050 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1050 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1051 if not names and action in {'add', 'delete'}:
1051 if not names and action in {'add', 'delete'}:
1052 raise error.Abort(_("bookmark name required"))
1052 raise error.Abort(_("bookmark name required"))
1053
1053
1054 if action in {'add', 'delete', 'rename', 'inactive'}:
1054 if action in {'add', 'delete', 'rename', 'inactive'}:
1055 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1055 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1056 if action == 'delete':
1056 if action == 'delete':
1057 names = pycompat.maplist(repo._bookmarks.expandname, names)
1057 names = pycompat.maplist(repo._bookmarks.expandname, names)
1058 bookmarks.delete(repo, tr, names)
1058 bookmarks.delete(repo, tr, names)
1059 elif action == 'rename':
1059 elif action == 'rename':
1060 if not names:
1060 if not names:
1061 raise error.Abort(_("new bookmark name required"))
1061 raise error.Abort(_("new bookmark name required"))
1062 elif len(names) > 1:
1062 elif len(names) > 1:
1063 raise error.Abort(_("only one new bookmark name allowed"))
1063 raise error.Abort(_("only one new bookmark name allowed"))
1064 oldname = repo._bookmarks.expandname(opts['rename'])
1064 oldname = repo._bookmarks.expandname(opts['rename'])
1065 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1065 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1066 elif action == 'add':
1066 elif action == 'add':
1067 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1067 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1068 elif action == 'inactive':
1068 elif action == 'inactive':
1069 if len(repo._bookmarks) == 0:
1069 if len(repo._bookmarks) == 0:
1070 ui.status(_("no bookmarks set\n"))
1070 ui.status(_("no bookmarks set\n"))
1071 elif not repo._activebookmark:
1071 elif not repo._activebookmark:
1072 ui.status(_("no active bookmark\n"))
1072 ui.status(_("no active bookmark\n"))
1073 else:
1073 else:
1074 bookmarks.deactivate(repo)
1074 bookmarks.deactivate(repo)
1075 elif action == 'list':
1075 elif action == 'list':
1076 names = pycompat.maplist(repo._bookmarks.expandname, names)
1076 names = pycompat.maplist(repo._bookmarks.expandname, names)
1077 with ui.formatter('bookmarks', opts) as fm:
1077 with ui.formatter('bookmarks', opts) as fm:
1078 bookmarks.printbookmarks(ui, repo, fm, names)
1078 bookmarks.printbookmarks(ui, repo, fm, names)
1079 else:
1079 else:
1080 raise error.ProgrammingError('invalid action: %s' % action)
1080 raise error.ProgrammingError('invalid action: %s' % action)
1081
1081
1082 @command('branch',
1082 @command('branch',
1083 [('f', 'force', None,
1083 [('f', 'force', None,
1084 _('set branch name even if it shadows an existing branch')),
1084 _('set branch name even if it shadows an existing branch')),
1085 ('C', 'clean', None, _('reset branch name to parent branch name')),
1085 ('C', 'clean', None, _('reset branch name to parent branch name')),
1086 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1086 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1087 ],
1087 ],
1088 _('[-fC] [NAME]'),
1088 _('[-fC] [NAME]'),
1089 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1089 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1090 def branch(ui, repo, label=None, **opts):
1090 def branch(ui, repo, label=None, **opts):
1091 """set or show the current branch name
1091 """set or show the current branch name
1092
1092
1093 .. note::
1093 .. note::
1094
1094
1095 Branch names are permanent and global. Use :hg:`bookmark` to create a
1095 Branch names are permanent and global. Use :hg:`bookmark` to create a
1096 light-weight bookmark instead. See :hg:`help glossary` for more
1096 light-weight bookmark instead. See :hg:`help glossary` for more
1097 information about named branches and bookmarks.
1097 information about named branches and bookmarks.
1098
1098
1099 With no argument, show the current branch name. With one argument,
1099 With no argument, show the current branch name. With one argument,
1100 set the working directory branch name (the branch will not exist
1100 set the working directory branch name (the branch will not exist
1101 in the repository until the next commit). Standard practice
1101 in the repository until the next commit). Standard practice
1102 recommends that primary development take place on the 'default'
1102 recommends that primary development take place on the 'default'
1103 branch.
1103 branch.
1104
1104
1105 Unless -f/--force is specified, branch will not let you set a
1105 Unless -f/--force is specified, branch will not let you set a
1106 branch name that already exists.
1106 branch name that already exists.
1107
1107
1108 Use -C/--clean to reset the working directory branch to that of
1108 Use -C/--clean to reset the working directory branch to that of
1109 the parent of the working directory, negating a previous branch
1109 the parent of the working directory, negating a previous branch
1110 change.
1110 change.
1111
1111
1112 Use the command :hg:`update` to switch to an existing branch. Use
1112 Use the command :hg:`update` to switch to an existing branch. Use
1113 :hg:`commit --close-branch` to mark this branch head as closed.
1113 :hg:`commit --close-branch` to mark this branch head as closed.
1114 When all heads of a branch are closed, the branch will be
1114 When all heads of a branch are closed, the branch will be
1115 considered closed.
1115 considered closed.
1116
1116
1117 Returns 0 on success.
1117 Returns 0 on success.
1118 """
1118 """
1119 opts = pycompat.byteskwargs(opts)
1119 opts = pycompat.byteskwargs(opts)
1120 revs = opts.get('rev')
1120 revs = opts.get('rev')
1121 if label:
1121 if label:
1122 label = label.strip()
1122 label = label.strip()
1123
1123
1124 if not opts.get('clean') and not label:
1124 if not opts.get('clean') and not label:
1125 if revs:
1125 if revs:
1126 raise error.Abort(_("no branch name specified for the revisions"))
1126 raise error.Abort(_("no branch name specified for the revisions"))
1127 ui.write("%s\n" % repo.dirstate.branch())
1127 ui.write("%s\n" % repo.dirstate.branch())
1128 return
1128 return
1129
1129
1130 with repo.wlock():
1130 with repo.wlock():
1131 if opts.get('clean'):
1131 if opts.get('clean'):
1132 label = repo['.'].branch()
1132 label = repo['.'].branch()
1133 repo.dirstate.setbranch(label)
1133 repo.dirstate.setbranch(label)
1134 ui.status(_('reset working directory to branch %s\n') % label)
1134 ui.status(_('reset working directory to branch %s\n') % label)
1135 elif label:
1135 elif label:
1136
1136
1137 scmutil.checknewlabel(repo, label, 'branch')
1137 scmutil.checknewlabel(repo, label, 'branch')
1138 if revs:
1138 if revs:
1139 return cmdutil.changebranch(ui, repo, revs, label)
1139 return cmdutil.changebranch(ui, repo, revs, label)
1140
1140
1141 if not opts.get('force') and label in repo.branchmap():
1141 if not opts.get('force') and label in repo.branchmap():
1142 if label not in [p.branch() for p in repo[None].parents()]:
1142 if label not in [p.branch() for p in repo[None].parents()]:
1143 raise error.Abort(_('a branch of the same name already'
1143 raise error.Abort(_('a branch of the same name already'
1144 ' exists'),
1144 ' exists'),
1145 # i18n: "it" refers to an existing branch
1145 # i18n: "it" refers to an existing branch
1146 hint=_("use 'hg update' to switch to it"))
1146 hint=_("use 'hg update' to switch to it"))
1147
1147
1148 repo.dirstate.setbranch(label)
1148 repo.dirstate.setbranch(label)
1149 ui.status(_('marked working directory as branch %s\n') % label)
1149 ui.status(_('marked working directory as branch %s\n') % label)
1150
1150
1151 # find any open named branches aside from default
1151 # find any open named branches aside from default
1152 for n, h, t, c in repo.branchmap().iterbranches():
1152 for n, h, t, c in repo.branchmap().iterbranches():
1153 if n != "default" and not c:
1153 if n != "default" and not c:
1154 return 0
1154 return 0
1155 ui.status(_('(branches are permanent and global, '
1155 ui.status(_('(branches are permanent and global, '
1156 'did you want a bookmark?)\n'))
1156 'did you want a bookmark?)\n'))
1157
1157
1158 @command('branches',
1158 @command('branches',
1159 [('a', 'active', False,
1159 [('a', 'active', False,
1160 _('show only branches that have unmerged heads (DEPRECATED)')),
1160 _('show only branches that have unmerged heads (DEPRECATED)')),
1161 ('c', 'closed', False, _('show normal and closed branches')),
1161 ('c', 'closed', False, _('show normal and closed branches')),
1162 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1162 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1163 ] + formatteropts,
1163 ] + formatteropts,
1164 _('[-c]'),
1164 _('[-c]'),
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1165 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1166 intents={INTENT_READONLY})
1166 intents={INTENT_READONLY})
1167 def branches(ui, repo, active=False, closed=False, **opts):
1167 def branches(ui, repo, active=False, closed=False, **opts):
1168 """list repository named branches
1168 """list repository named branches
1169
1169
1170 List the repository's named branches, indicating which ones are
1170 List the repository's named branches, indicating which ones are
1171 inactive. If -c/--closed is specified, also list branches which have
1171 inactive. If -c/--closed is specified, also list branches which have
1172 been marked closed (see :hg:`commit --close-branch`).
1172 been marked closed (see :hg:`commit --close-branch`).
1173
1173
1174 Use the command :hg:`update` to switch to an existing branch.
1174 Use the command :hg:`update` to switch to an existing branch.
1175
1175
1176 .. container:: verbose
1176 .. container:: verbose
1177
1177
1178 Template:
1178 Template:
1179
1179
1180 The following keywords are supported in addition to the common template
1180 The following keywords are supported in addition to the common template
1181 keywords and functions such as ``{branch}``. See also
1181 keywords and functions such as ``{branch}``. See also
1182 :hg:`help templates`.
1182 :hg:`help templates`.
1183
1183
1184 :active: Boolean. True if the branch is active.
1184 :active: Boolean. True if the branch is active.
1185 :closed: Boolean. True if the branch is closed.
1185 :closed: Boolean. True if the branch is closed.
1186 :current: Boolean. True if it is the current branch.
1186 :current: Boolean. True if it is the current branch.
1187
1187
1188 Returns 0.
1188 Returns 0.
1189 """
1189 """
1190
1190
1191 opts = pycompat.byteskwargs(opts)
1191 opts = pycompat.byteskwargs(opts)
1192 revs = opts.get('rev')
1192 revs = opts.get('rev')
1193 selectedbranches = None
1193 selectedbranches = None
1194 if revs:
1194 if revs:
1195 revs = scmutil.revrange(repo, revs)
1195 revs = scmutil.revrange(repo, revs)
1196 getbi = repo.revbranchcache().branchinfo
1196 getbi = repo.revbranchcache().branchinfo
1197 selectedbranches = {getbi(r)[0] for r in revs}
1197 selectedbranches = {getbi(r)[0] for r in revs}
1198
1198
1199 ui.pager('branches')
1199 ui.pager('branches')
1200 fm = ui.formatter('branches', opts)
1200 fm = ui.formatter('branches', opts)
1201 hexfunc = fm.hexfunc
1201 hexfunc = fm.hexfunc
1202
1202
1203 allheads = set(repo.heads())
1203 allheads = set(repo.heads())
1204 branches = []
1204 branches = []
1205 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1205 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1206 if selectedbranches is not None and tag not in selectedbranches:
1206 if selectedbranches is not None and tag not in selectedbranches:
1207 continue
1207 continue
1208 isactive = False
1208 isactive = False
1209 if not isclosed:
1209 if not isclosed:
1210 openheads = set(repo.branchmap().iteropen(heads))
1210 openheads = set(repo.branchmap().iteropen(heads))
1211 isactive = bool(openheads & allheads)
1211 isactive = bool(openheads & allheads)
1212 branches.append((tag, repo[tip], isactive, not isclosed))
1212 branches.append((tag, repo[tip], isactive, not isclosed))
1213 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1213 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1214 reverse=True)
1214 reverse=True)
1215
1215
1216 for tag, ctx, isactive, isopen in branches:
1216 for tag, ctx, isactive, isopen in branches:
1217 if active and not isactive:
1217 if active and not isactive:
1218 continue
1218 continue
1219 if isactive:
1219 if isactive:
1220 label = 'branches.active'
1220 label = 'branches.active'
1221 notice = ''
1221 notice = ''
1222 elif not isopen:
1222 elif not isopen:
1223 if not closed:
1223 if not closed:
1224 continue
1224 continue
1225 label = 'branches.closed'
1225 label = 'branches.closed'
1226 notice = _(' (closed)')
1226 notice = _(' (closed)')
1227 else:
1227 else:
1228 label = 'branches.inactive'
1228 label = 'branches.inactive'
1229 notice = _(' (inactive)')
1229 notice = _(' (inactive)')
1230 current = (tag == repo.dirstate.branch())
1230 current = (tag == repo.dirstate.branch())
1231 if current:
1231 if current:
1232 label = 'branches.current'
1232 label = 'branches.current'
1233
1233
1234 fm.startitem()
1234 fm.startitem()
1235 fm.write('branch', '%s', tag, label=label)
1235 fm.write('branch', '%s', tag, label=label)
1236 rev = ctx.rev()
1236 rev = ctx.rev()
1237 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1237 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1238 fmt = ' ' * padsize + ' %d:%s'
1238 fmt = ' ' * padsize + ' %d:%s'
1239 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1239 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1240 label='log.changeset changeset.%s' % ctx.phasestr())
1240 label='log.changeset changeset.%s' % ctx.phasestr())
1241 fm.context(ctx=ctx)
1241 fm.context(ctx=ctx)
1242 fm.data(active=isactive, closed=not isopen, current=current)
1242 fm.data(active=isactive, closed=not isopen, current=current)
1243 if not ui.quiet:
1243 if not ui.quiet:
1244 fm.plain(notice)
1244 fm.plain(notice)
1245 fm.plain('\n')
1245 fm.plain('\n')
1246 fm.end()
1246 fm.end()
1247
1247
1248 @command('bundle',
1248 @command('bundle',
1249 [('f', 'force', None, _('run even when the destination is unrelated')),
1249 [('f', 'force', None, _('run even when the destination is unrelated')),
1250 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1250 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1251 _('REV')),
1251 _('REV')),
1252 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1252 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1253 _('BRANCH')),
1253 _('BRANCH')),
1254 ('', 'base', [],
1254 ('', 'base', [],
1255 _('a base changeset assumed to be available at the destination'),
1255 _('a base changeset assumed to be available at the destination'),
1256 _('REV')),
1256 _('REV')),
1257 ('a', 'all', None, _('bundle all changesets in the repository')),
1257 ('a', 'all', None, _('bundle all changesets in the repository')),
1258 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1258 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1259 ] + remoteopts,
1259 ] + remoteopts,
1260 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1260 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1261 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1261 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1262 def bundle(ui, repo, fname, dest=None, **opts):
1262 def bundle(ui, repo, fname, dest=None, **opts):
1263 """create a bundle file
1263 """create a bundle file
1264
1264
1265 Generate a bundle file containing data to be transferred to another
1265 Generate a bundle file containing data to be transferred to another
1266 repository.
1266 repository.
1267
1267
1268 To create a bundle containing all changesets, use -a/--all
1268 To create a bundle containing all changesets, use -a/--all
1269 (or --base null). Otherwise, hg assumes the destination will have
1269 (or --base null). Otherwise, hg assumes the destination will have
1270 all the nodes you specify with --base parameters. Otherwise, hg
1270 all the nodes you specify with --base parameters. Otherwise, hg
1271 will assume the repository has all the nodes in destination, or
1271 will assume the repository has all the nodes in destination, or
1272 default-push/default if no destination is specified, where destination
1272 default-push/default if no destination is specified, where destination
1273 is the repository you provide through DEST option.
1273 is the repository you provide through DEST option.
1274
1274
1275 You can change bundle format with the -t/--type option. See
1275 You can change bundle format with the -t/--type option. See
1276 :hg:`help bundlespec` for documentation on this format. By default,
1276 :hg:`help bundlespec` for documentation on this format. By default,
1277 the most appropriate format is used and compression defaults to
1277 the most appropriate format is used and compression defaults to
1278 bzip2.
1278 bzip2.
1279
1279
1280 The bundle file can then be transferred using conventional means
1280 The bundle file can then be transferred using conventional means
1281 and applied to another repository with the unbundle or pull
1281 and applied to another repository with the unbundle or pull
1282 command. This is useful when direct push and pull are not
1282 command. This is useful when direct push and pull are not
1283 available or when exporting an entire repository is undesirable.
1283 available or when exporting an entire repository is undesirable.
1284
1284
1285 Applying bundles preserves all changeset contents including
1285 Applying bundles preserves all changeset contents including
1286 permissions, copy/rename information, and revision history.
1286 permissions, copy/rename information, and revision history.
1287
1287
1288 Returns 0 on success, 1 if no changes found.
1288 Returns 0 on success, 1 if no changes found.
1289 """
1289 """
1290 opts = pycompat.byteskwargs(opts)
1290 opts = pycompat.byteskwargs(opts)
1291 revs = None
1291 revs = None
1292 if 'rev' in opts:
1292 if 'rev' in opts:
1293 revstrings = opts['rev']
1293 revstrings = opts['rev']
1294 revs = scmutil.revrange(repo, revstrings)
1294 revs = scmutil.revrange(repo, revstrings)
1295 if revstrings and not revs:
1295 if revstrings and not revs:
1296 raise error.Abort(_('no commits to bundle'))
1296 raise error.Abort(_('no commits to bundle'))
1297
1297
1298 bundletype = opts.get('type', 'bzip2').lower()
1298 bundletype = opts.get('type', 'bzip2').lower()
1299 try:
1299 try:
1300 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1300 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1301 except error.UnsupportedBundleSpecification as e:
1301 except error.UnsupportedBundleSpecification as e:
1302 raise error.Abort(pycompat.bytestr(e),
1302 raise error.Abort(pycompat.bytestr(e),
1303 hint=_("see 'hg help bundlespec' for supported "
1303 hint=_("see 'hg help bundlespec' for supported "
1304 "values for --type"))
1304 "values for --type"))
1305 cgversion = bundlespec.contentopts["cg.version"]
1305 cgversion = bundlespec.contentopts["cg.version"]
1306
1306
1307 # Packed bundles are a pseudo bundle format for now.
1307 # Packed bundles are a pseudo bundle format for now.
1308 if cgversion == 's1':
1308 if cgversion == 's1':
1309 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1309 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1310 hint=_("use 'hg debugcreatestreamclonebundle'"))
1310 hint=_("use 'hg debugcreatestreamclonebundle'"))
1311
1311
1312 if opts.get('all'):
1312 if opts.get('all'):
1313 if dest:
1313 if dest:
1314 raise error.Abort(_("--all is incompatible with specifying "
1314 raise error.Abort(_("--all is incompatible with specifying "
1315 "a destination"))
1315 "a destination"))
1316 if opts.get('base'):
1316 if opts.get('base'):
1317 ui.warn(_("ignoring --base because --all was specified\n"))
1317 ui.warn(_("ignoring --base because --all was specified\n"))
1318 base = [nullrev]
1318 base = [nullrev]
1319 else:
1319 else:
1320 base = scmutil.revrange(repo, opts.get('base'))
1320 base = scmutil.revrange(repo, opts.get('base'))
1321 if cgversion not in changegroup.supportedoutgoingversions(repo):
1321 if cgversion not in changegroup.supportedoutgoingversions(repo):
1322 raise error.Abort(_("repository does not support bundle version %s") %
1322 raise error.Abort(_("repository does not support bundle version %s") %
1323 cgversion)
1323 cgversion)
1324
1324
1325 if base:
1325 if base:
1326 if dest:
1326 if dest:
1327 raise error.Abort(_("--base is incompatible with specifying "
1327 raise error.Abort(_("--base is incompatible with specifying "
1328 "a destination"))
1328 "a destination"))
1329 common = [repo[rev].node() for rev in base]
1329 common = [repo[rev].node() for rev in base]
1330 heads = [repo[r].node() for r in revs] if revs else None
1330 heads = [repo[r].node() for r in revs] if revs else None
1331 outgoing = discovery.outgoing(repo, common, heads)
1331 outgoing = discovery.outgoing(repo, common, heads)
1332 else:
1332 else:
1333 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1333 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1334 dest, branches = hg.parseurl(dest, opts.get('branch'))
1334 dest, branches = hg.parseurl(dest, opts.get('branch'))
1335 other = hg.peer(repo, opts, dest)
1335 other = hg.peer(repo, opts, dest)
1336 revs = [repo[r].hex() for r in revs]
1336 revs = [repo[r].hex() for r in revs]
1337 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1337 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1338 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1338 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1339 outgoing = discovery.findcommonoutgoing(repo, other,
1339 outgoing = discovery.findcommonoutgoing(repo, other,
1340 onlyheads=heads,
1340 onlyheads=heads,
1341 force=opts.get('force'),
1341 force=opts.get('force'),
1342 portable=True)
1342 portable=True)
1343
1343
1344 if not outgoing.missing:
1344 if not outgoing.missing:
1345 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1345 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1346 return 1
1346 return 1
1347
1347
1348 if cgversion == '01': #bundle1
1348 if cgversion == '01': #bundle1
1349 bversion = 'HG10' + bundlespec.wirecompression
1349 bversion = 'HG10' + bundlespec.wirecompression
1350 bcompression = None
1350 bcompression = None
1351 elif cgversion in ('02', '03'):
1351 elif cgversion in ('02', '03'):
1352 bversion = 'HG20'
1352 bversion = 'HG20'
1353 bcompression = bundlespec.wirecompression
1353 bcompression = bundlespec.wirecompression
1354 else:
1354 else:
1355 raise error.ProgrammingError(
1355 raise error.ProgrammingError(
1356 'bundle: unexpected changegroup version %s' % cgversion)
1356 'bundle: unexpected changegroup version %s' % cgversion)
1357
1357
1358 # TODO compression options should be derived from bundlespec parsing.
1358 # TODO compression options should be derived from bundlespec parsing.
1359 # This is a temporary hack to allow adjusting bundle compression
1359 # This is a temporary hack to allow adjusting bundle compression
1360 # level without a) formalizing the bundlespec changes to declare it
1360 # level without a) formalizing the bundlespec changes to declare it
1361 # b) introducing a command flag.
1361 # b) introducing a command flag.
1362 compopts = {}
1362 compopts = {}
1363 complevel = ui.configint('experimental',
1363 complevel = ui.configint('experimental',
1364 'bundlecomplevel.' + bundlespec.compression)
1364 'bundlecomplevel.' + bundlespec.compression)
1365 if complevel is None:
1365 if complevel is None:
1366 complevel = ui.configint('experimental', 'bundlecomplevel')
1366 complevel = ui.configint('experimental', 'bundlecomplevel')
1367 if complevel is not None:
1367 if complevel is not None:
1368 compopts['level'] = complevel
1368 compopts['level'] = complevel
1369
1369
1370 # Allow overriding the bundling of obsmarker in phases through
1370 # Allow overriding the bundling of obsmarker in phases through
1371 # configuration while we don't have a bundle version that include them
1371 # configuration while we don't have a bundle version that include them
1372 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1372 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1373 bundlespec.contentopts['obsolescence'] = True
1373 bundlespec.contentopts['obsolescence'] = True
1374 if repo.ui.configbool('experimental', 'bundle-phases'):
1374 if repo.ui.configbool('experimental', 'bundle-phases'):
1375 bundlespec.contentopts['phases'] = True
1375 bundlespec.contentopts['phases'] = True
1376
1376
1377 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1377 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1378 bundlespec.contentopts, compression=bcompression,
1378 bundlespec.contentopts, compression=bcompression,
1379 compopts=compopts)
1379 compopts=compopts)
1380
1380
1381 @command('cat',
1381 @command('cat',
1382 [('o', 'output', '',
1382 [('o', 'output', '',
1383 _('print output to file with formatted name'), _('FORMAT')),
1383 _('print output to file with formatted name'), _('FORMAT')),
1384 ('r', 'rev', '', _('print the given revision'), _('REV')),
1384 ('r', 'rev', '', _('print the given revision'), _('REV')),
1385 ('', 'decode', None, _('apply any matching decode filter')),
1385 ('', 'decode', None, _('apply any matching decode filter')),
1386 ] + walkopts + formatteropts,
1386 ] + walkopts + formatteropts,
1387 _('[OPTION]... FILE...'),
1387 _('[OPTION]... FILE...'),
1388 helpcategory=command.CATEGORY_FILE_CONTENTS,
1388 helpcategory=command.CATEGORY_FILE_CONTENTS,
1389 inferrepo=True,
1389 inferrepo=True,
1390 intents={INTENT_READONLY})
1390 intents={INTENT_READONLY})
1391 def cat(ui, repo, file1, *pats, **opts):
1391 def cat(ui, repo, file1, *pats, **opts):
1392 """output the current or given revision of files
1392 """output the current or given revision of files
1393
1393
1394 Print the specified files as they were at the given revision. If
1394 Print the specified files as they were at the given revision. If
1395 no revision is given, the parent of the working directory is used.
1395 no revision is given, the parent of the working directory is used.
1396
1396
1397 Output may be to a file, in which case the name of the file is
1397 Output may be to a file, in which case the name of the file is
1398 given using a template string. See :hg:`help templates`. In addition
1398 given using a template string. See :hg:`help templates`. In addition
1399 to the common template keywords, the following formatting rules are
1399 to the common template keywords, the following formatting rules are
1400 supported:
1400 supported:
1401
1401
1402 :``%%``: literal "%" character
1402 :``%%``: literal "%" character
1403 :``%s``: basename of file being printed
1403 :``%s``: basename of file being printed
1404 :``%d``: dirname of file being printed, or '.' if in repository root
1404 :``%d``: dirname of file being printed, or '.' if in repository root
1405 :``%p``: root-relative path name of file being printed
1405 :``%p``: root-relative path name of file being printed
1406 :``%H``: changeset hash (40 hexadecimal digits)
1406 :``%H``: changeset hash (40 hexadecimal digits)
1407 :``%R``: changeset revision number
1407 :``%R``: changeset revision number
1408 :``%h``: short-form changeset hash (12 hexadecimal digits)
1408 :``%h``: short-form changeset hash (12 hexadecimal digits)
1409 :``%r``: zero-padded changeset revision number
1409 :``%r``: zero-padded changeset revision number
1410 :``%b``: basename of the exporting repository
1410 :``%b``: basename of the exporting repository
1411 :``\\``: literal "\\" character
1411 :``\\``: literal "\\" character
1412
1412
1413 .. container:: verbose
1413 .. container:: verbose
1414
1414
1415 Template:
1415 Template:
1416
1416
1417 The following keywords are supported in addition to the common template
1417 The following keywords are supported in addition to the common template
1418 keywords and functions. See also :hg:`help templates`.
1418 keywords and functions. See also :hg:`help templates`.
1419
1419
1420 :data: String. File content.
1420 :data: String. File content.
1421 :path: String. Repository-absolute path of the file.
1421 :path: String. Repository-absolute path of the file.
1422
1422
1423 Returns 0 on success.
1423 Returns 0 on success.
1424 """
1424 """
1425 opts = pycompat.byteskwargs(opts)
1425 opts = pycompat.byteskwargs(opts)
1426 rev = opts.get('rev')
1426 rev = opts.get('rev')
1427 if rev:
1427 if rev:
1428 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1428 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1429 ctx = scmutil.revsingle(repo, rev)
1429 ctx = scmutil.revsingle(repo, rev)
1430 m = scmutil.match(ctx, (file1,) + pats, opts)
1430 m = scmutil.match(ctx, (file1,) + pats, opts)
1431 fntemplate = opts.pop('output', '')
1431 fntemplate = opts.pop('output', '')
1432 if cmdutil.isstdiofilename(fntemplate):
1432 if cmdutil.isstdiofilename(fntemplate):
1433 fntemplate = ''
1433 fntemplate = ''
1434
1434
1435 if fntemplate:
1435 if fntemplate:
1436 fm = formatter.nullformatter(ui, 'cat', opts)
1436 fm = formatter.nullformatter(ui, 'cat', opts)
1437 else:
1437 else:
1438 ui.pager('cat')
1438 ui.pager('cat')
1439 fm = ui.formatter('cat', opts)
1439 fm = ui.formatter('cat', opts)
1440 with fm:
1440 with fm:
1441 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1441 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1442 **pycompat.strkwargs(opts))
1442 **pycompat.strkwargs(opts))
1443
1443
1444 @command('clone',
1444 @command('clone',
1445 [('U', 'noupdate', None, _('the clone will include an empty working '
1445 [('U', 'noupdate', None, _('the clone will include an empty working '
1446 'directory (only a repository)')),
1446 'directory (only a repository)')),
1447 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1447 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1448 _('REV')),
1448 _('REV')),
1449 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1449 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1450 ' and its ancestors'), _('REV')),
1450 ' and its ancestors'), _('REV')),
1451 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1451 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1452 ' changesets and their ancestors'), _('BRANCH')),
1452 ' changesets and their ancestors'), _('BRANCH')),
1453 ('', 'pull', None, _('use pull protocol to copy metadata')),
1453 ('', 'pull', None, _('use pull protocol to copy metadata')),
1454 ('', 'uncompressed', None,
1454 ('', 'uncompressed', None,
1455 _('an alias to --stream (DEPRECATED)')),
1455 _('an alias to --stream (DEPRECATED)')),
1456 ('', 'stream', None,
1456 ('', 'stream', None,
1457 _('clone with minimal data processing')),
1457 _('clone with minimal data processing')),
1458 ] + remoteopts,
1458 ] + remoteopts,
1459 _('[OPTION]... SOURCE [DEST]'),
1459 _('[OPTION]... SOURCE [DEST]'),
1460 helpcategory=command.CATEGORY_REPO_CREATION,
1460 helpcategory=command.CATEGORY_REPO_CREATION,
1461 helpbasic=True, norepo=True)
1461 helpbasic=True, norepo=True)
1462 def clone(ui, source, dest=None, **opts):
1462 def clone(ui, source, dest=None, **opts):
1463 """make a copy of an existing repository
1463 """make a copy of an existing repository
1464
1464
1465 Create a copy of an existing repository in a new directory.
1465 Create a copy of an existing repository in a new directory.
1466
1466
1467 If no destination directory name is specified, it defaults to the
1467 If no destination directory name is specified, it defaults to the
1468 basename of the source.
1468 basename of the source.
1469
1469
1470 The location of the source is added to the new repository's
1470 The location of the source is added to the new repository's
1471 ``.hg/hgrc`` file, as the default to be used for future pulls.
1471 ``.hg/hgrc`` file, as the default to be used for future pulls.
1472
1472
1473 Only local paths and ``ssh://`` URLs are supported as
1473 Only local paths and ``ssh://`` URLs are supported as
1474 destinations. For ``ssh://`` destinations, no working directory or
1474 destinations. For ``ssh://`` destinations, no working directory or
1475 ``.hg/hgrc`` will be created on the remote side.
1475 ``.hg/hgrc`` will be created on the remote side.
1476
1476
1477 If the source repository has a bookmark called '@' set, that
1477 If the source repository has a bookmark called '@' set, that
1478 revision will be checked out in the new repository by default.
1478 revision will be checked out in the new repository by default.
1479
1479
1480 To check out a particular version, use -u/--update, or
1480 To check out a particular version, use -u/--update, or
1481 -U/--noupdate to create a clone with no working directory.
1481 -U/--noupdate to create a clone with no working directory.
1482
1482
1483 To pull only a subset of changesets, specify one or more revisions
1483 To pull only a subset of changesets, specify one or more revisions
1484 identifiers with -r/--rev or branches with -b/--branch. The
1484 identifiers with -r/--rev or branches with -b/--branch. The
1485 resulting clone will contain only the specified changesets and
1485 resulting clone will contain only the specified changesets and
1486 their ancestors. These options (or 'clone src#rev dest') imply
1486 their ancestors. These options (or 'clone src#rev dest') imply
1487 --pull, even for local source repositories.
1487 --pull, even for local source repositories.
1488
1488
1489 In normal clone mode, the remote normalizes repository data into a common
1489 In normal clone mode, the remote normalizes repository data into a common
1490 exchange format and the receiving end translates this data into its local
1490 exchange format and the receiving end translates this data into its local
1491 storage format. --stream activates a different clone mode that essentially
1491 storage format. --stream activates a different clone mode that essentially
1492 copies repository files from the remote with minimal data processing. This
1492 copies repository files from the remote with minimal data processing. This
1493 significantly reduces the CPU cost of a clone both remotely and locally.
1493 significantly reduces the CPU cost of a clone both remotely and locally.
1494 However, it often increases the transferred data size by 30-40%. This can
1494 However, it often increases the transferred data size by 30-40%. This can
1495 result in substantially faster clones where I/O throughput is plentiful,
1495 result in substantially faster clones where I/O throughput is plentiful,
1496 especially for larger repositories. A side-effect of --stream clones is
1496 especially for larger repositories. A side-effect of --stream clones is
1497 that storage settings and requirements on the remote are applied locally:
1497 that storage settings and requirements on the remote are applied locally:
1498 a modern client may inherit legacy or inefficient storage used by the
1498 a modern client may inherit legacy or inefficient storage used by the
1499 remote or a legacy Mercurial client may not be able to clone from a
1499 remote or a legacy Mercurial client may not be able to clone from a
1500 modern Mercurial remote.
1500 modern Mercurial remote.
1501
1501
1502 .. note::
1502 .. note::
1503
1503
1504 Specifying a tag will include the tagged changeset but not the
1504 Specifying a tag will include the tagged changeset but not the
1505 changeset containing the tag.
1505 changeset containing the tag.
1506
1506
1507 .. container:: verbose
1507 .. container:: verbose
1508
1508
1509 For efficiency, hardlinks are used for cloning whenever the
1509 For efficiency, hardlinks are used for cloning whenever the
1510 source and destination are on the same filesystem (note this
1510 source and destination are on the same filesystem (note this
1511 applies only to the repository data, not to the working
1511 applies only to the repository data, not to the working
1512 directory). Some filesystems, such as AFS, implement hardlinking
1512 directory). Some filesystems, such as AFS, implement hardlinking
1513 incorrectly, but do not report errors. In these cases, use the
1513 incorrectly, but do not report errors. In these cases, use the
1514 --pull option to avoid hardlinking.
1514 --pull option to avoid hardlinking.
1515
1515
1516 Mercurial will update the working directory to the first applicable
1516 Mercurial will update the working directory to the first applicable
1517 revision from this list:
1517 revision from this list:
1518
1518
1519 a) null if -U or the source repository has no changesets
1519 a) null if -U or the source repository has no changesets
1520 b) if -u . and the source repository is local, the first parent of
1520 b) if -u . and the source repository is local, the first parent of
1521 the source repository's working directory
1521 the source repository's working directory
1522 c) the changeset specified with -u (if a branch name, this means the
1522 c) the changeset specified with -u (if a branch name, this means the
1523 latest head of that branch)
1523 latest head of that branch)
1524 d) the changeset specified with -r
1524 d) the changeset specified with -r
1525 e) the tipmost head specified with -b
1525 e) the tipmost head specified with -b
1526 f) the tipmost head specified with the url#branch source syntax
1526 f) the tipmost head specified with the url#branch source syntax
1527 g) the revision marked with the '@' bookmark, if present
1527 g) the revision marked with the '@' bookmark, if present
1528 h) the tipmost head of the default branch
1528 h) the tipmost head of the default branch
1529 i) tip
1529 i) tip
1530
1530
1531 When cloning from servers that support it, Mercurial may fetch
1531 When cloning from servers that support it, Mercurial may fetch
1532 pre-generated data from a server-advertised URL or inline from the
1532 pre-generated data from a server-advertised URL or inline from the
1533 same stream. When this is done, hooks operating on incoming changesets
1533 same stream. When this is done, hooks operating on incoming changesets
1534 and changegroups may fire more than once, once for each pre-generated
1534 and changegroups may fire more than once, once for each pre-generated
1535 bundle and as well as for any additional remaining data. In addition,
1535 bundle and as well as for any additional remaining data. In addition,
1536 if an error occurs, the repository may be rolled back to a partial
1536 if an error occurs, the repository may be rolled back to a partial
1537 clone. This behavior may change in future releases.
1537 clone. This behavior may change in future releases.
1538 See :hg:`help -e clonebundles` for more.
1538 See :hg:`help -e clonebundles` for more.
1539
1539
1540 Examples:
1540 Examples:
1541
1541
1542 - clone a remote repository to a new directory named hg/::
1542 - clone a remote repository to a new directory named hg/::
1543
1543
1544 hg clone https://www.mercurial-scm.org/repo/hg/
1544 hg clone https://www.mercurial-scm.org/repo/hg/
1545
1545
1546 - create a lightweight local clone::
1546 - create a lightweight local clone::
1547
1547
1548 hg clone project/ project-feature/
1548 hg clone project/ project-feature/
1549
1549
1550 - clone from an absolute path on an ssh server (note double-slash)::
1550 - clone from an absolute path on an ssh server (note double-slash)::
1551
1551
1552 hg clone ssh://user@server//home/projects/alpha/
1552 hg clone ssh://user@server//home/projects/alpha/
1553
1553
1554 - do a streaming clone while checking out a specified version::
1554 - do a streaming clone while checking out a specified version::
1555
1555
1556 hg clone --stream http://server/repo -u 1.5
1556 hg clone --stream http://server/repo -u 1.5
1557
1557
1558 - create a repository without changesets after a particular revision::
1558 - create a repository without changesets after a particular revision::
1559
1559
1560 hg clone -r 04e544 experimental/ good/
1560 hg clone -r 04e544 experimental/ good/
1561
1561
1562 - clone (and track) a particular named branch::
1562 - clone (and track) a particular named branch::
1563
1563
1564 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1564 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1565
1565
1566 See :hg:`help urls` for details on specifying URLs.
1566 See :hg:`help urls` for details on specifying URLs.
1567
1567
1568 Returns 0 on success.
1568 Returns 0 on success.
1569 """
1569 """
1570 opts = pycompat.byteskwargs(opts)
1570 opts = pycompat.byteskwargs(opts)
1571 if opts.get('noupdate') and opts.get('updaterev'):
1571 if opts.get('noupdate') and opts.get('updaterev'):
1572 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1572 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1573
1573
1574 # --include/--exclude can come from narrow or sparse.
1574 # --include/--exclude can come from narrow or sparse.
1575 includepats, excludepats = None, None
1575 includepats, excludepats = None, None
1576
1576
1577 # hg.clone() differentiates between None and an empty set. So make sure
1577 # hg.clone() differentiates between None and an empty set. So make sure
1578 # patterns are sets if narrow is requested without patterns.
1578 # patterns are sets if narrow is requested without patterns.
1579 if opts.get('narrow'):
1579 if opts.get('narrow'):
1580 includepats = set()
1580 includepats = set()
1581 excludepats = set()
1581 excludepats = set()
1582
1582
1583 if opts.get('include'):
1583 if opts.get('include'):
1584 includepats = narrowspec.parsepatterns(opts.get('include'))
1584 includepats = narrowspec.parsepatterns(opts.get('include'))
1585 if opts.get('exclude'):
1585 if opts.get('exclude'):
1586 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1586 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1587
1587
1588 r = hg.clone(ui, opts, source, dest,
1588 r = hg.clone(ui, opts, source, dest,
1589 pull=opts.get('pull'),
1589 pull=opts.get('pull'),
1590 stream=opts.get('stream') or opts.get('uncompressed'),
1590 stream=opts.get('stream') or opts.get('uncompressed'),
1591 revs=opts.get('rev'),
1591 revs=opts.get('rev'),
1592 update=opts.get('updaterev') or not opts.get('noupdate'),
1592 update=opts.get('updaterev') or not opts.get('noupdate'),
1593 branch=opts.get('branch'),
1593 branch=opts.get('branch'),
1594 shareopts=opts.get('shareopts'),
1594 shareopts=opts.get('shareopts'),
1595 storeincludepats=includepats,
1595 storeincludepats=includepats,
1596 storeexcludepats=excludepats,
1596 storeexcludepats=excludepats,
1597 depth=opts.get('depth') or None)
1597 depth=opts.get('depth') or None)
1598
1598
1599 return r is None
1599 return r is None
1600
1600
1601 @command('commit|ci',
1601 @command('commit|ci',
1602 [('A', 'addremove', None,
1602 [('A', 'addremove', None,
1603 _('mark new/missing files as added/removed before committing')),
1603 _('mark new/missing files as added/removed before committing')),
1604 ('', 'close-branch', None,
1604 ('', 'close-branch', None,
1605 _('mark a branch head as closed')),
1605 _('mark a branch head as closed')),
1606 ('', 'amend', None, _('amend the parent of the working directory')),
1606 ('', 'amend', None, _('amend the parent of the working directory')),
1607 ('s', 'secret', None, _('use the secret phase for committing')),
1607 ('s', 'secret', None, _('use the secret phase for committing')),
1608 ('e', 'edit', None, _('invoke editor on commit messages')),
1608 ('e', 'edit', None, _('invoke editor on commit messages')),
1609 ('', 'force-close-branch', None,
1609 ('', 'force-close-branch', None,
1610 _('forcibly close branch from a non-head changeset (ADVANCED)')),
1610 _('forcibly close branch from a non-head changeset (ADVANCED)')),
1611 ('i', 'interactive', None, _('use interactive mode')),
1611 ('i', 'interactive', None, _('use interactive mode')),
1612 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1612 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1613 _('[OPTION]... [FILE]...'),
1613 _('[OPTION]... [FILE]...'),
1614 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1614 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1615 inferrepo=True)
1615 inferrepo=True)
1616 def commit(ui, repo, *pats, **opts):
1616 def commit(ui, repo, *pats, **opts):
1617 """commit the specified files or all outstanding changes
1617 """commit the specified files or all outstanding changes
1618
1618
1619 Commit changes to the given files into the repository. Unlike a
1619 Commit changes to the given files into the repository. Unlike a
1620 centralized SCM, this operation is a local operation. See
1620 centralized SCM, this operation is a local operation. See
1621 :hg:`push` for a way to actively distribute your changes.
1621 :hg:`push` for a way to actively distribute your changes.
1622
1622
1623 If a list of files is omitted, all changes reported by :hg:`status`
1623 If a list of files is omitted, all changes reported by :hg:`status`
1624 will be committed.
1624 will be committed.
1625
1625
1626 If you are committing the result of a merge, do not provide any
1626 If you are committing the result of a merge, do not provide any
1627 filenames or -I/-X filters.
1627 filenames or -I/-X filters.
1628
1628
1629 If no commit message is specified, Mercurial starts your
1629 If no commit message is specified, Mercurial starts your
1630 configured editor where you can enter a message. In case your
1630 configured editor where you can enter a message. In case your
1631 commit fails, you will find a backup of your message in
1631 commit fails, you will find a backup of your message in
1632 ``.hg/last-message.txt``.
1632 ``.hg/last-message.txt``.
1633
1633
1634 The --close-branch flag can be used to mark the current branch
1634 The --close-branch flag can be used to mark the current branch
1635 head closed. When all heads of a branch are closed, the branch
1635 head closed. When all heads of a branch are closed, the branch
1636 will be considered closed and no longer listed.
1636 will be considered closed and no longer listed.
1637
1637
1638 The --amend flag can be used to amend the parent of the
1638 The --amend flag can be used to amend the parent of the
1639 working directory with a new commit that contains the changes
1639 working directory with a new commit that contains the changes
1640 in the parent in addition to those currently reported by :hg:`status`,
1640 in the parent in addition to those currently reported by :hg:`status`,
1641 if there are any. The old commit is stored in a backup bundle in
1641 if there are any. The old commit is stored in a backup bundle in
1642 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1642 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1643 on how to restore it).
1643 on how to restore it).
1644
1644
1645 Message, user and date are taken from the amended commit unless
1645 Message, user and date are taken from the amended commit unless
1646 specified. When a message isn't specified on the command line,
1646 specified. When a message isn't specified on the command line,
1647 the editor will open with the message of the amended commit.
1647 the editor will open with the message of the amended commit.
1648
1648
1649 It is not possible to amend public changesets (see :hg:`help phases`)
1649 It is not possible to amend public changesets (see :hg:`help phases`)
1650 or changesets that have children.
1650 or changesets that have children.
1651
1651
1652 See :hg:`help dates` for a list of formats valid for -d/--date.
1652 See :hg:`help dates` for a list of formats valid for -d/--date.
1653
1653
1654 Returns 0 on success, 1 if nothing changed.
1654 Returns 0 on success, 1 if nothing changed.
1655
1655
1656 .. container:: verbose
1656 .. container:: verbose
1657
1657
1658 Examples:
1658 Examples:
1659
1659
1660 - commit all files ending in .py::
1660 - commit all files ending in .py::
1661
1661
1662 hg commit --include "set:**.py"
1662 hg commit --include "set:**.py"
1663
1663
1664 - commit all non-binary files::
1664 - commit all non-binary files::
1665
1665
1666 hg commit --exclude "set:binary()"
1666 hg commit --exclude "set:binary()"
1667
1667
1668 - amend the current commit and set the date to now::
1668 - amend the current commit and set the date to now::
1669
1669
1670 hg commit --amend --date now
1670 hg commit --amend --date now
1671 """
1671 """
1672 with repo.wlock(), repo.lock():
1672 with repo.wlock(), repo.lock():
1673 return _docommit(ui, repo, *pats, **opts)
1673 return _docommit(ui, repo, *pats, **opts)
1674
1674
1675 def _docommit(ui, repo, *pats, **opts):
1675 def _docommit(ui, repo, *pats, **opts):
1676 if opts.get(r'interactive'):
1676 if opts.get(r'interactive'):
1677 opts.pop(r'interactive')
1677 opts.pop(r'interactive')
1678 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1678 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1679 cmdutil.recordfilter, *pats,
1679 cmdutil.recordfilter, *pats,
1680 **opts)
1680 **opts)
1681 # ret can be 0 (no changes to record) or the value returned by
1681 # ret can be 0 (no changes to record) or the value returned by
1682 # commit(), 1 if nothing changed or None on success.
1682 # commit(), 1 if nothing changed or None on success.
1683 return 1 if ret == 0 else ret
1683 return 1 if ret == 0 else ret
1684
1684
1685 opts = pycompat.byteskwargs(opts)
1685 opts = pycompat.byteskwargs(opts)
1686 if opts.get('subrepos'):
1686 if opts.get('subrepos'):
1687 if opts.get('amend'):
1687 if opts.get('amend'):
1688 raise error.Abort(_('cannot amend with --subrepos'))
1688 raise error.Abort(_('cannot amend with --subrepos'))
1689 # Let --subrepos on the command line override config setting.
1689 # Let --subrepos on the command line override config setting.
1690 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1690 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1691
1691
1692 cmdutil.checkunfinished(repo, commit=True)
1692 cmdutil.checkunfinished(repo, commit=True)
1693
1693
1694 branch = repo[None].branch()
1694 branch = repo[None].branch()
1695 bheads = repo.branchheads(branch)
1695 bheads = repo.branchheads(branch)
1696
1696
1697 extra = {}
1697 extra = {}
1698 if opts.get('close_branch') or opts.get('force_close_branch'):
1698 if opts.get('close_branch') or opts.get('force_close_branch'):
1699 extra['close'] = '1'
1699 extra['close'] = '1'
1700
1700
1701 if repo['.'].closesbranch():
1701 if repo['.'].closesbranch():
1702 raise error.Abort(_('current revision is already a branch closing'
1702 raise error.Abort(_('current revision is already a branch closing'
1703 ' head'))
1703 ' head'))
1704 elif not bheads:
1704 elif not bheads:
1705 raise error.Abort(_('branch "%s" has no heads to close') % branch)
1705 raise error.Abort(_('branch "%s" has no heads to close') % branch)
1706 elif (branch == repo['.'].branch() and repo['.'].node() not in bheads
1706 elif (branch == repo['.'].branch() and repo['.'].node() not in bheads
1707 and not opts.get('force_close_branch')):
1707 and not opts.get('force_close_branch')):
1708 hint = _('use --force-close-branch to close branch from a non-head'
1708 hint = _('use --force-close-branch to close branch from a non-head'
1709 ' changeset')
1709 ' changeset')
1710 raise error.Abort(_('can only close branch heads'), hint=hint)
1710 raise error.Abort(_('can only close branch heads'), hint=hint)
1711 elif opts.get('amend'):
1711 elif opts.get('amend'):
1712 if (repo['.'].p1().branch() != branch and
1712 if (repo['.'].p1().branch() != branch and
1713 repo['.'].p2().branch() != branch):
1713 repo['.'].p2().branch() != branch):
1714 raise error.Abort(_('can only close branch heads'))
1714 raise error.Abort(_('can only close branch heads'))
1715
1715
1716 if opts.get('amend'):
1716 if opts.get('amend'):
1717 if ui.configbool('ui', 'commitsubrepos'):
1717 if ui.configbool('ui', 'commitsubrepos'):
1718 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1718 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1719
1719
1720 old = repo['.']
1720 old = repo['.']
1721 rewriteutil.precheck(repo, [old.rev()], 'amend')
1721 rewriteutil.precheck(repo, [old.rev()], 'amend')
1722
1722
1723 # Currently histedit gets confused if an amend happens while histedit
1723 # Currently histedit gets confused if an amend happens while histedit
1724 # is in progress. Since we have a checkunfinished command, we are
1724 # is in progress. Since we have a checkunfinished command, we are
1725 # temporarily honoring it.
1725 # temporarily honoring it.
1726 #
1726 #
1727 # Note: eventually this guard will be removed. Please do not expect
1727 # Note: eventually this guard will be removed. Please do not expect
1728 # this behavior to remain.
1728 # this behavior to remain.
1729 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1729 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1730 cmdutil.checkunfinished(repo)
1730 cmdutil.checkunfinished(repo)
1731
1731
1732 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1732 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1733 if node == old.node():
1733 if node == old.node():
1734 ui.status(_("nothing changed\n"))
1734 ui.status(_("nothing changed\n"))
1735 return 1
1735 return 1
1736 else:
1736 else:
1737 def commitfunc(ui, repo, message, match, opts):
1737 def commitfunc(ui, repo, message, match, opts):
1738 overrides = {}
1738 overrides = {}
1739 if opts.get('secret'):
1739 if opts.get('secret'):
1740 overrides[('phases', 'new-commit')] = 'secret'
1740 overrides[('phases', 'new-commit')] = 'secret'
1741
1741
1742 baseui = repo.baseui
1742 baseui = repo.baseui
1743 with baseui.configoverride(overrides, 'commit'):
1743 with baseui.configoverride(overrides, 'commit'):
1744 with ui.configoverride(overrides, 'commit'):
1744 with ui.configoverride(overrides, 'commit'):
1745 editform = cmdutil.mergeeditform(repo[None],
1745 editform = cmdutil.mergeeditform(repo[None],
1746 'commit.normal')
1746 'commit.normal')
1747 editor = cmdutil.getcommiteditor(
1747 editor = cmdutil.getcommiteditor(
1748 editform=editform, **pycompat.strkwargs(opts))
1748 editform=editform, **pycompat.strkwargs(opts))
1749 return repo.commit(message,
1749 return repo.commit(message,
1750 opts.get('user'),
1750 opts.get('user'),
1751 opts.get('date'),
1751 opts.get('date'),
1752 match,
1752 match,
1753 editor=editor,
1753 editor=editor,
1754 extra=extra)
1754 extra=extra)
1755
1755
1756 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1756 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1757
1757
1758 if not node:
1758 if not node:
1759 stat = cmdutil.postcommitstatus(repo, pats, opts)
1759 stat = cmdutil.postcommitstatus(repo, pats, opts)
1760 if stat[3]:
1760 if stat[3]:
1761 ui.status(_("nothing changed (%d missing files, see "
1761 ui.status(_("nothing changed (%d missing files, see "
1762 "'hg status')\n") % len(stat[3]))
1762 "'hg status')\n") % len(stat[3]))
1763 else:
1763 else:
1764 ui.status(_("nothing changed\n"))
1764 ui.status(_("nothing changed\n"))
1765 return 1
1765 return 1
1766
1766
1767 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1767 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1768
1768
1769 if not ui.quiet and ui.configbool('commands', 'commit.post-status'):
1769 if not ui.quiet and ui.configbool('commands', 'commit.post-status'):
1770 status(ui, repo, modified=True, added=True, removed=True, deleted=True,
1770 status(ui, repo, modified=True, added=True, removed=True, deleted=True,
1771 unknown=True, subrepos=opts.get('subrepos'))
1771 unknown=True, subrepos=opts.get('subrepos'))
1772
1772
1773 @command('config|showconfig|debugconfig',
1773 @command('config|showconfig|debugconfig',
1774 [('u', 'untrusted', None, _('show untrusted configuration options')),
1774 [('u', 'untrusted', None, _('show untrusted configuration options')),
1775 ('e', 'edit', None, _('edit user config')),
1775 ('e', 'edit', None, _('edit user config')),
1776 ('l', 'local', None, _('edit repository config')),
1776 ('l', 'local', None, _('edit repository config')),
1777 ('g', 'global', None, _('edit global config'))] + formatteropts,
1777 ('g', 'global', None, _('edit global config'))] + formatteropts,
1778 _('[-u] [NAME]...'),
1778 _('[-u] [NAME]...'),
1779 helpcategory=command.CATEGORY_HELP,
1779 helpcategory=command.CATEGORY_HELP,
1780 optionalrepo=True,
1780 optionalrepo=True,
1781 intents={INTENT_READONLY})
1781 intents={INTENT_READONLY})
1782 def config(ui, repo, *values, **opts):
1782 def config(ui, repo, *values, **opts):
1783 """show combined config settings from all hgrc files
1783 """show combined config settings from all hgrc files
1784
1784
1785 With no arguments, print names and values of all config items.
1785 With no arguments, print names and values of all config items.
1786
1786
1787 With one argument of the form section.name, print just the value
1787 With one argument of the form section.name, print just the value
1788 of that config item.
1788 of that config item.
1789
1789
1790 With multiple arguments, print names and values of all config
1790 With multiple arguments, print names and values of all config
1791 items with matching section names or section.names.
1791 items with matching section names or section.names.
1792
1792
1793 With --edit, start an editor on the user-level config file. With
1793 With --edit, start an editor on the user-level config file. With
1794 --global, edit the system-wide config file. With --local, edit the
1794 --global, edit the system-wide config file. With --local, edit the
1795 repository-level config file.
1795 repository-level config file.
1796
1796
1797 With --debug, the source (filename and line number) is printed
1797 With --debug, the source (filename and line number) is printed
1798 for each config item.
1798 for each config item.
1799
1799
1800 See :hg:`help config` for more information about config files.
1800 See :hg:`help config` for more information about config files.
1801
1801
1802 .. container:: verbose
1802 .. container:: verbose
1803
1803
1804 Template:
1804 Template:
1805
1805
1806 The following keywords are supported. See also :hg:`help templates`.
1806 The following keywords are supported. See also :hg:`help templates`.
1807
1807
1808 :name: String. Config name.
1808 :name: String. Config name.
1809 :source: String. Filename and line number where the item is defined.
1809 :source: String. Filename and line number where the item is defined.
1810 :value: String. Config value.
1810 :value: String. Config value.
1811
1811
1812 Returns 0 on success, 1 if NAME does not exist.
1812 Returns 0 on success, 1 if NAME does not exist.
1813
1813
1814 """
1814 """
1815
1815
1816 opts = pycompat.byteskwargs(opts)
1816 opts = pycompat.byteskwargs(opts)
1817 if opts.get('edit') or opts.get('local') or opts.get('global'):
1817 if opts.get('edit') or opts.get('local') or opts.get('global'):
1818 if opts.get('local') and opts.get('global'):
1818 if opts.get('local') and opts.get('global'):
1819 raise error.Abort(_("can't use --local and --global together"))
1819 raise error.Abort(_("can't use --local and --global together"))
1820
1820
1821 if opts.get('local'):
1821 if opts.get('local'):
1822 if not repo:
1822 if not repo:
1823 raise error.Abort(_("can't use --local outside a repository"))
1823 raise error.Abort(_("can't use --local outside a repository"))
1824 paths = [repo.vfs.join('hgrc')]
1824 paths = [repo.vfs.join('hgrc')]
1825 elif opts.get('global'):
1825 elif opts.get('global'):
1826 paths = rcutil.systemrcpath()
1826 paths = rcutil.systemrcpath()
1827 else:
1827 else:
1828 paths = rcutil.userrcpath()
1828 paths = rcutil.userrcpath()
1829
1829
1830 for f in paths:
1830 for f in paths:
1831 if os.path.exists(f):
1831 if os.path.exists(f):
1832 break
1832 break
1833 else:
1833 else:
1834 if opts.get('global'):
1834 if opts.get('global'):
1835 samplehgrc = uimod.samplehgrcs['global']
1835 samplehgrc = uimod.samplehgrcs['global']
1836 elif opts.get('local'):
1836 elif opts.get('local'):
1837 samplehgrc = uimod.samplehgrcs['local']
1837 samplehgrc = uimod.samplehgrcs['local']
1838 else:
1838 else:
1839 samplehgrc = uimod.samplehgrcs['user']
1839 samplehgrc = uimod.samplehgrcs['user']
1840
1840
1841 f = paths[0]
1841 f = paths[0]
1842 fp = open(f, "wb")
1842 fp = open(f, "wb")
1843 fp.write(util.tonativeeol(samplehgrc))
1843 fp.write(util.tonativeeol(samplehgrc))
1844 fp.close()
1844 fp.close()
1845
1845
1846 editor = ui.geteditor()
1846 editor = ui.geteditor()
1847 ui.system("%s \"%s\"" % (editor, f),
1847 ui.system("%s \"%s\"" % (editor, f),
1848 onerr=error.Abort, errprefix=_("edit failed"),
1848 onerr=error.Abort, errprefix=_("edit failed"),
1849 blockedtag='config_edit')
1849 blockedtag='config_edit')
1850 return
1850 return
1851 ui.pager('config')
1851 ui.pager('config')
1852 fm = ui.formatter('config', opts)
1852 fm = ui.formatter('config', opts)
1853 for t, f in rcutil.rccomponents():
1853 for t, f in rcutil.rccomponents():
1854 if t == 'path':
1854 if t == 'path':
1855 ui.debug('read config from: %s\n' % f)
1855 ui.debug('read config from: %s\n' % f)
1856 elif t == 'items':
1856 elif t == 'items':
1857 for section, name, value, source in f:
1857 for section, name, value, source in f:
1858 ui.debug('set config by: %s\n' % source)
1858 ui.debug('set config by: %s\n' % source)
1859 else:
1859 else:
1860 raise error.ProgrammingError('unknown rctype: %s' % t)
1860 raise error.ProgrammingError('unknown rctype: %s' % t)
1861 untrusted = bool(opts.get('untrusted'))
1861 untrusted = bool(opts.get('untrusted'))
1862
1862
1863 selsections = selentries = []
1863 selsections = selentries = []
1864 if values:
1864 if values:
1865 selsections = [v for v in values if '.' not in v]
1865 selsections = [v for v in values if '.' not in v]
1866 selentries = [v for v in values if '.' in v]
1866 selentries = [v for v in values if '.' in v]
1867 uniquesel = (len(selentries) == 1 and not selsections)
1867 uniquesel = (len(selentries) == 1 and not selsections)
1868 selsections = set(selsections)
1868 selsections = set(selsections)
1869 selentries = set(selentries)
1869 selentries = set(selentries)
1870
1870
1871 matched = False
1871 matched = False
1872 for section, name, value in ui.walkconfig(untrusted=untrusted):
1872 for section, name, value in ui.walkconfig(untrusted=untrusted):
1873 source = ui.configsource(section, name, untrusted)
1873 source = ui.configsource(section, name, untrusted)
1874 value = pycompat.bytestr(value)
1874 value = pycompat.bytestr(value)
1875 if fm.isplain():
1875 if fm.isplain():
1876 source = source or 'none'
1876 source = source or 'none'
1877 value = value.replace('\n', '\\n')
1877 value = value.replace('\n', '\\n')
1878 entryname = section + '.' + name
1878 entryname = section + '.' + name
1879 if values and not (section in selsections or entryname in selentries):
1879 if values and not (section in selsections or entryname in selentries):
1880 continue
1880 continue
1881 fm.startitem()
1881 fm.startitem()
1882 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1882 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1883 if uniquesel:
1883 if uniquesel:
1884 fm.data(name=entryname)
1884 fm.data(name=entryname)
1885 fm.write('value', '%s\n', value)
1885 fm.write('value', '%s\n', value)
1886 else:
1886 else:
1887 fm.write('name value', '%s=%s\n', entryname, value)
1887 fm.write('name value', '%s=%s\n', entryname, value)
1888 matched = True
1888 matched = True
1889 fm.end()
1889 fm.end()
1890 if matched:
1890 if matched:
1891 return 0
1891 return 0
1892 return 1
1892 return 1
1893
1893
1894 @command('continue',
1894 @command('continue',
1895 dryrunopts, helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
1895 dryrunopts, helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
1896 helpbasic=True)
1896 helpbasic=True)
1897 def continuecmd(ui, repo, **opts):
1897 def continuecmd(ui, repo, **opts):
1898 """resumes an interrupted operation (EXPERIMENTAL)
1898 """resumes an interrupted operation (EXPERIMENTAL)
1899
1899
1900 Finishes a multistep operation like graft, histedit, rebase, merge,
1900 Finishes a multistep operation like graft, histedit, rebase, merge,
1901 and unshelve if they are in an interrupted state.
1901 and unshelve if they are in an interrupted state.
1902
1902
1903 use --dry-run/-n to dry run the command.
1903 use --dry-run/-n to dry run the command.
1904 """
1904 """
1905 dryrun = opts.get(r'dry_run')
1905 dryrun = opts.get(r'dry_run')
1906 contstate = cmdutil.getunfinishedstate(repo)
1906 contstate = cmdutil.getunfinishedstate(repo)
1907 if not contstate:
1907 if not contstate:
1908 raise error.Abort(_('no operation in progress'))
1908 raise error.Abort(_('no operation in progress'))
1909 if not contstate.continuefunc:
1909 if not contstate.continuefunc:
1910 raise error.Abort((_("%s in progress but does not support "
1910 raise error.Abort((_("%s in progress but does not support "
1911 "'hg continue'") % (contstate._opname)),
1911 "'hg continue'") % (contstate._opname)),
1912 hint=contstate.continuemsg())
1912 hint=contstate.continuemsg())
1913 if dryrun:
1913 if dryrun:
1914 ui.status(_('%s in progress, will be resumed\n') % (contstate._opname))
1914 ui.status(_('%s in progress, will be resumed\n') % (contstate._opname))
1915 return
1915 return
1916 return contstate.continuefunc(ui, repo)
1916 return contstate.continuefunc(ui, repo)
1917
1917
1918 @command('copy|cp',
1918 @command('copy|cp',
1919 [('A', 'after', None, _('record a copy that has already occurred')),
1919 [('A', 'after', None, _('record a copy that has already occurred')),
1920 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1920 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1921 ] + walkopts + dryrunopts,
1921 ] + walkopts + dryrunopts,
1922 _('[OPTION]... SOURCE... DEST'),
1922 _('[OPTION]... SOURCE... DEST'),
1923 helpcategory=command.CATEGORY_FILE_CONTENTS)
1923 helpcategory=command.CATEGORY_FILE_CONTENTS)
1924 def copy(ui, repo, *pats, **opts):
1924 def copy(ui, repo, *pats, **opts):
1925 """mark files as copied for the next commit
1925 """mark files as copied for the next commit
1926
1926
1927 Mark dest as having copies of source files. If dest is a
1927 Mark dest as having copies of source files. If dest is a
1928 directory, copies are put in that directory. If dest is a file,
1928 directory, copies are put in that directory. If dest is a file,
1929 the source must be a single file.
1929 the source must be a single file.
1930
1930
1931 By default, this command copies the contents of files as they
1931 By default, this command copies the contents of files as they
1932 exist in the working directory. If invoked with -A/--after, the
1932 exist in the working directory. If invoked with -A/--after, the
1933 operation is recorded, but no copying is performed.
1933 operation is recorded, but no copying is performed.
1934
1934
1935 This command takes effect with the next commit. To undo a copy
1935 This command takes effect with the next commit. To undo a copy
1936 before that, see :hg:`revert`.
1936 before that, see :hg:`revert`.
1937
1937
1938 Returns 0 on success, 1 if errors are encountered.
1938 Returns 0 on success, 1 if errors are encountered.
1939 """
1939 """
1940 opts = pycompat.byteskwargs(opts)
1940 opts = pycompat.byteskwargs(opts)
1941 with repo.wlock(False):
1941 with repo.wlock(False):
1942 return cmdutil.copy(ui, repo, pats, opts)
1942 return cmdutil.copy(ui, repo, pats, opts)
1943
1943
1944 @command(
1944 @command(
1945 'debugcommands', [], _('[COMMAND]'),
1945 'debugcommands', [], _('[COMMAND]'),
1946 helpcategory=command.CATEGORY_HELP,
1946 helpcategory=command.CATEGORY_HELP,
1947 norepo=True)
1947 norepo=True)
1948 def debugcommands(ui, cmd='', *args):
1948 def debugcommands(ui, cmd='', *args):
1949 """list all available commands and options"""
1949 """list all available commands and options"""
1950 for cmd, vals in sorted(table.iteritems()):
1950 for cmd, vals in sorted(table.iteritems()):
1951 cmd = cmd.split('|')[0]
1951 cmd = cmd.split('|')[0]
1952 opts = ', '.join([i[1] for i in vals[1]])
1952 opts = ', '.join([i[1] for i in vals[1]])
1953 ui.write('%s: %s\n' % (cmd, opts))
1953 ui.write('%s: %s\n' % (cmd, opts))
1954
1954
1955 @command('debugcomplete',
1955 @command('debugcomplete',
1956 [('o', 'options', None, _('show the command options'))],
1956 [('o', 'options', None, _('show the command options'))],
1957 _('[-o] CMD'),
1957 _('[-o] CMD'),
1958 helpcategory=command.CATEGORY_HELP,
1958 helpcategory=command.CATEGORY_HELP,
1959 norepo=True)
1959 norepo=True)
1960 def debugcomplete(ui, cmd='', **opts):
1960 def debugcomplete(ui, cmd='', **opts):
1961 """returns the completion list associated with the given command"""
1961 """returns the completion list associated with the given command"""
1962
1962
1963 if opts.get(r'options'):
1963 if opts.get(r'options'):
1964 options = []
1964 options = []
1965 otables = [globalopts]
1965 otables = [globalopts]
1966 if cmd:
1966 if cmd:
1967 aliases, entry = cmdutil.findcmd(cmd, table, False)
1967 aliases, entry = cmdutil.findcmd(cmd, table, False)
1968 otables.append(entry[1])
1968 otables.append(entry[1])
1969 for t in otables:
1969 for t in otables:
1970 for o in t:
1970 for o in t:
1971 if "(DEPRECATED)" in o[3]:
1971 if "(DEPRECATED)" in o[3]:
1972 continue
1972 continue
1973 if o[0]:
1973 if o[0]:
1974 options.append('-%s' % o[0])
1974 options.append('-%s' % o[0])
1975 options.append('--%s' % o[1])
1975 options.append('--%s' % o[1])
1976 ui.write("%s\n" % "\n".join(options))
1976 ui.write("%s\n" % "\n".join(options))
1977 return
1977 return
1978
1978
1979 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1979 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1980 if ui.verbose:
1980 if ui.verbose:
1981 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1981 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1982 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1982 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1983
1983
1984 @command('diff',
1984 @command('diff',
1985 [('r', 'rev', [], _('revision'), _('REV')),
1985 [('r', 'rev', [], _('revision'), _('REV')),
1986 ('c', 'change', '', _('change made by revision'), _('REV'))
1986 ('c', 'change', '', _('change made by revision'), _('REV'))
1987 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1987 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1988 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1988 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1989 helpcategory=command.CATEGORY_FILE_CONTENTS,
1989 helpcategory=command.CATEGORY_FILE_CONTENTS,
1990 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1990 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1991 def diff(ui, repo, *pats, **opts):
1991 def diff(ui, repo, *pats, **opts):
1992 """diff repository (or selected files)
1992 """diff repository (or selected files)
1993
1993
1994 Show differences between revisions for the specified files.
1994 Show differences between revisions for the specified files.
1995
1995
1996 Differences between files are shown using the unified diff format.
1996 Differences between files are shown using the unified diff format.
1997
1997
1998 .. note::
1998 .. note::
1999
1999
2000 :hg:`diff` may generate unexpected results for merges, as it will
2000 :hg:`diff` may generate unexpected results for merges, as it will
2001 default to comparing against the working directory's first
2001 default to comparing against the working directory's first
2002 parent changeset if no revisions are specified.
2002 parent changeset if no revisions are specified.
2003
2003
2004 When two revision arguments are given, then changes are shown
2004 When two revision arguments are given, then changes are shown
2005 between those revisions. If only one revision is specified then
2005 between those revisions. If only one revision is specified then
2006 that revision is compared to the working directory, and, when no
2006 that revision is compared to the working directory, and, when no
2007 revisions are specified, the working directory files are compared
2007 revisions are specified, the working directory files are compared
2008 to its first parent.
2008 to its first parent.
2009
2009
2010 Alternatively you can specify -c/--change with a revision to see
2010 Alternatively you can specify -c/--change with a revision to see
2011 the changes in that changeset relative to its first parent.
2011 the changes in that changeset relative to its first parent.
2012
2012
2013 Without the -a/--text option, diff will avoid generating diffs of
2013 Without the -a/--text option, diff will avoid generating diffs of
2014 files it detects as binary. With -a, diff will generate a diff
2014 files it detects as binary. With -a, diff will generate a diff
2015 anyway, probably with undesirable results.
2015 anyway, probably with undesirable results.
2016
2016
2017 Use the -g/--git option to generate diffs in the git extended diff
2017 Use the -g/--git option to generate diffs in the git extended diff
2018 format. For more information, read :hg:`help diffs`.
2018 format. For more information, read :hg:`help diffs`.
2019
2019
2020 .. container:: verbose
2020 .. container:: verbose
2021
2021
2022 Examples:
2022 Examples:
2023
2023
2024 - compare a file in the current working directory to its parent::
2024 - compare a file in the current working directory to its parent::
2025
2025
2026 hg diff foo.c
2026 hg diff foo.c
2027
2027
2028 - compare two historical versions of a directory, with rename info::
2028 - compare two historical versions of a directory, with rename info::
2029
2029
2030 hg diff --git -r 1.0:1.2 lib/
2030 hg diff --git -r 1.0:1.2 lib/
2031
2031
2032 - get change stats relative to the last change on some date::
2032 - get change stats relative to the last change on some date::
2033
2033
2034 hg diff --stat -r "date('may 2')"
2034 hg diff --stat -r "date('may 2')"
2035
2035
2036 - diff all newly-added files that contain a keyword::
2036 - diff all newly-added files that contain a keyword::
2037
2037
2038 hg diff "set:added() and grep(GNU)"
2038 hg diff "set:added() and grep(GNU)"
2039
2039
2040 - compare a revision and its parents::
2040 - compare a revision and its parents::
2041
2041
2042 hg diff -c 9353 # compare against first parent
2042 hg diff -c 9353 # compare against first parent
2043 hg diff -r 9353^:9353 # same using revset syntax
2043 hg diff -r 9353^:9353 # same using revset syntax
2044 hg diff -r 9353^2:9353 # compare against the second parent
2044 hg diff -r 9353^2:9353 # compare against the second parent
2045
2045
2046 Returns 0 on success.
2046 Returns 0 on success.
2047 """
2047 """
2048
2048
2049 opts = pycompat.byteskwargs(opts)
2049 opts = pycompat.byteskwargs(opts)
2050 revs = opts.get('rev')
2050 revs = opts.get('rev')
2051 change = opts.get('change')
2051 change = opts.get('change')
2052 stat = opts.get('stat')
2052 stat = opts.get('stat')
2053 reverse = opts.get('reverse')
2053 reverse = opts.get('reverse')
2054
2054
2055 if revs and change:
2055 if revs and change:
2056 msg = _('cannot specify --rev and --change at the same time')
2056 msg = _('cannot specify --rev and --change at the same time')
2057 raise error.Abort(msg)
2057 raise error.Abort(msg)
2058 elif change:
2058 elif change:
2059 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
2059 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
2060 ctx2 = scmutil.revsingle(repo, change, None)
2060 ctx2 = scmutil.revsingle(repo, change, None)
2061 ctx1 = ctx2.p1()
2061 ctx1 = ctx2.p1()
2062 else:
2062 else:
2063 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2063 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2064 ctx1, ctx2 = scmutil.revpair(repo, revs)
2064 ctx1, ctx2 = scmutil.revpair(repo, revs)
2065 node1, node2 = ctx1.node(), ctx2.node()
2065 node1, node2 = ctx1.node(), ctx2.node()
2066
2066
2067 if reverse:
2067 if reverse:
2068 node1, node2 = node2, node1
2068 node1, node2 = node2, node1
2069
2069
2070 diffopts = patch.diffallopts(ui, opts)
2070 diffopts = patch.diffallopts(ui, opts)
2071 m = scmutil.match(ctx2, pats, opts)
2071 m = scmutil.match(ctx2, pats, opts)
2072 m = repo.narrowmatch(m)
2072 m = repo.narrowmatch(m)
2073 ui.pager('diff')
2073 ui.pager('diff')
2074 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2074 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2075 listsubrepos=opts.get('subrepos'),
2075 listsubrepos=opts.get('subrepos'),
2076 root=opts.get('root'))
2076 root=opts.get('root'))
2077
2077
2078 @command('export',
2078 @command('export',
2079 [('B', 'bookmark', '',
2079 [('B', 'bookmark', '',
2080 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2080 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2081 ('o', 'output', '',
2081 ('o', 'output', '',
2082 _('print output to file with formatted name'), _('FORMAT')),
2082 _('print output to file with formatted name'), _('FORMAT')),
2083 ('', 'switch-parent', None, _('diff against the second parent')),
2083 ('', 'switch-parent', None, _('diff against the second parent')),
2084 ('r', 'rev', [], _('revisions to export'), _('REV')),
2084 ('r', 'rev', [], _('revisions to export'), _('REV')),
2085 ] + diffopts + formatteropts,
2085 ] + diffopts + formatteropts,
2086 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2086 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2087 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2087 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2088 helpbasic=True, intents={INTENT_READONLY})
2088 helpbasic=True, intents={INTENT_READONLY})
2089 def export(ui, repo, *changesets, **opts):
2089 def export(ui, repo, *changesets, **opts):
2090 """dump the header and diffs for one or more changesets
2090 """dump the header and diffs for one or more changesets
2091
2091
2092 Print the changeset header and diffs for one or more revisions.
2092 Print the changeset header and diffs for one or more revisions.
2093 If no revision is given, the parent of the working directory is used.
2093 If no revision is given, the parent of the working directory is used.
2094
2094
2095 The information shown in the changeset header is: author, date,
2095 The information shown in the changeset header is: author, date,
2096 branch name (if non-default), changeset hash, parent(s) and commit
2096 branch name (if non-default), changeset hash, parent(s) and commit
2097 comment.
2097 comment.
2098
2098
2099 .. note::
2099 .. note::
2100
2100
2101 :hg:`export` may generate unexpected diff output for merge
2101 :hg:`export` may generate unexpected diff output for merge
2102 changesets, as it will compare the merge changeset against its
2102 changesets, as it will compare the merge changeset against its
2103 first parent only.
2103 first parent only.
2104
2104
2105 Output may be to a file, in which case the name of the file is
2105 Output may be to a file, in which case the name of the file is
2106 given using a template string. See :hg:`help templates`. In addition
2106 given using a template string. See :hg:`help templates`. In addition
2107 to the common template keywords, the following formatting rules are
2107 to the common template keywords, the following formatting rules are
2108 supported:
2108 supported:
2109
2109
2110 :``%%``: literal "%" character
2110 :``%%``: literal "%" character
2111 :``%H``: changeset hash (40 hexadecimal digits)
2111 :``%H``: changeset hash (40 hexadecimal digits)
2112 :``%N``: number of patches being generated
2112 :``%N``: number of patches being generated
2113 :``%R``: changeset revision number
2113 :``%R``: changeset revision number
2114 :``%b``: basename of the exporting repository
2114 :``%b``: basename of the exporting repository
2115 :``%h``: short-form changeset hash (12 hexadecimal digits)
2115 :``%h``: short-form changeset hash (12 hexadecimal digits)
2116 :``%m``: first line of the commit message (only alphanumeric characters)
2116 :``%m``: first line of the commit message (only alphanumeric characters)
2117 :``%n``: zero-padded sequence number, starting at 1
2117 :``%n``: zero-padded sequence number, starting at 1
2118 :``%r``: zero-padded changeset revision number
2118 :``%r``: zero-padded changeset revision number
2119 :``\\``: literal "\\" character
2119 :``\\``: literal "\\" character
2120
2120
2121 Without the -a/--text option, export will avoid generating diffs
2121 Without the -a/--text option, export will avoid generating diffs
2122 of files it detects as binary. With -a, export will generate a
2122 of files it detects as binary. With -a, export will generate a
2123 diff anyway, probably with undesirable results.
2123 diff anyway, probably with undesirable results.
2124
2124
2125 With -B/--bookmark changesets reachable by the given bookmark are
2125 With -B/--bookmark changesets reachable by the given bookmark are
2126 selected.
2126 selected.
2127
2127
2128 Use the -g/--git option to generate diffs in the git extended diff
2128 Use the -g/--git option to generate diffs in the git extended diff
2129 format. See :hg:`help diffs` for more information.
2129 format. See :hg:`help diffs` for more information.
2130
2130
2131 With the --switch-parent option, the diff will be against the
2131 With the --switch-parent option, the diff will be against the
2132 second parent. It can be useful to review a merge.
2132 second parent. It can be useful to review a merge.
2133
2133
2134 .. container:: verbose
2134 .. container:: verbose
2135
2135
2136 Template:
2136 Template:
2137
2137
2138 The following keywords are supported in addition to the common template
2138 The following keywords are supported in addition to the common template
2139 keywords and functions. See also :hg:`help templates`.
2139 keywords and functions. See also :hg:`help templates`.
2140
2140
2141 :diff: String. Diff content.
2141 :diff: String. Diff content.
2142 :parents: List of strings. Parent nodes of the changeset.
2142 :parents: List of strings. Parent nodes of the changeset.
2143
2143
2144 Examples:
2144 Examples:
2145
2145
2146 - use export and import to transplant a bugfix to the current
2146 - use export and import to transplant a bugfix to the current
2147 branch::
2147 branch::
2148
2148
2149 hg export -r 9353 | hg import -
2149 hg export -r 9353 | hg import -
2150
2150
2151 - export all the changesets between two revisions to a file with
2151 - export all the changesets between two revisions to a file with
2152 rename information::
2152 rename information::
2153
2153
2154 hg export --git -r 123:150 > changes.txt
2154 hg export --git -r 123:150 > changes.txt
2155
2155
2156 - split outgoing changes into a series of patches with
2156 - split outgoing changes into a series of patches with
2157 descriptive names::
2157 descriptive names::
2158
2158
2159 hg export -r "outgoing()" -o "%n-%m.patch"
2159 hg export -r "outgoing()" -o "%n-%m.patch"
2160
2160
2161 Returns 0 on success.
2161 Returns 0 on success.
2162 """
2162 """
2163 opts = pycompat.byteskwargs(opts)
2163 opts = pycompat.byteskwargs(opts)
2164 bookmark = opts.get('bookmark')
2164 bookmark = opts.get('bookmark')
2165 changesets += tuple(opts.get('rev', []))
2165 changesets += tuple(opts.get('rev', []))
2166
2166
2167 if bookmark and changesets:
2167 if bookmark and changesets:
2168 raise error.Abort(_("-r and -B are mutually exclusive"))
2168 raise error.Abort(_("-r and -B are mutually exclusive"))
2169
2169
2170 if bookmark:
2170 if bookmark:
2171 if bookmark not in repo._bookmarks:
2171 if bookmark not in repo._bookmarks:
2172 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2172 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2173
2173
2174 revs = scmutil.bookmarkrevs(repo, bookmark)
2174 revs = scmutil.bookmarkrevs(repo, bookmark)
2175 else:
2175 else:
2176 if not changesets:
2176 if not changesets:
2177 changesets = ['.']
2177 changesets = ['.']
2178
2178
2179 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2179 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2180 revs = scmutil.revrange(repo, changesets)
2180 revs = scmutil.revrange(repo, changesets)
2181
2181
2182 if not revs:
2182 if not revs:
2183 raise error.Abort(_("export requires at least one changeset"))
2183 raise error.Abort(_("export requires at least one changeset"))
2184 if len(revs) > 1:
2184 if len(revs) > 1:
2185 ui.note(_('exporting patches:\n'))
2185 ui.note(_('exporting patches:\n'))
2186 else:
2186 else:
2187 ui.note(_('exporting patch:\n'))
2187 ui.note(_('exporting patch:\n'))
2188
2188
2189 fntemplate = opts.get('output')
2189 fntemplate = opts.get('output')
2190 if cmdutil.isstdiofilename(fntemplate):
2190 if cmdutil.isstdiofilename(fntemplate):
2191 fntemplate = ''
2191 fntemplate = ''
2192
2192
2193 if fntemplate:
2193 if fntemplate:
2194 fm = formatter.nullformatter(ui, 'export', opts)
2194 fm = formatter.nullformatter(ui, 'export', opts)
2195 else:
2195 else:
2196 ui.pager('export')
2196 ui.pager('export')
2197 fm = ui.formatter('export', opts)
2197 fm = ui.formatter('export', opts)
2198 with fm:
2198 with fm:
2199 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2199 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2200 switch_parent=opts.get('switch_parent'),
2200 switch_parent=opts.get('switch_parent'),
2201 opts=patch.diffallopts(ui, opts))
2201 opts=patch.diffallopts(ui, opts))
2202
2202
2203 @command('files',
2203 @command('files',
2204 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2204 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2205 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2205 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2206 ] + walkopts + formatteropts + subrepoopts,
2206 ] + walkopts + formatteropts + subrepoopts,
2207 _('[OPTION]... [FILE]...'),
2207 _('[OPTION]... [FILE]...'),
2208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2209 intents={INTENT_READONLY})
2209 intents={INTENT_READONLY})
2210 def files(ui, repo, *pats, **opts):
2210 def files(ui, repo, *pats, **opts):
2211 """list tracked files
2211 """list tracked files
2212
2212
2213 Print files under Mercurial control in the working directory or
2213 Print files under Mercurial control in the working directory or
2214 specified revision for given files (excluding removed files).
2214 specified revision for given files (excluding removed files).
2215 Files can be specified as filenames or filesets.
2215 Files can be specified as filenames or filesets.
2216
2216
2217 If no files are given to match, this command prints the names
2217 If no files are given to match, this command prints the names
2218 of all files under Mercurial control.
2218 of all files under Mercurial control.
2219
2219
2220 .. container:: verbose
2220 .. container:: verbose
2221
2221
2222 Template:
2222 Template:
2223
2223
2224 The following keywords are supported in addition to the common template
2224 The following keywords are supported in addition to the common template
2225 keywords and functions. See also :hg:`help templates`.
2225 keywords and functions. See also :hg:`help templates`.
2226
2226
2227 :flags: String. Character denoting file's symlink and executable bits.
2227 :flags: String. Character denoting file's symlink and executable bits.
2228 :path: String. Repository-absolute path of the file.
2228 :path: String. Repository-absolute path of the file.
2229 :size: Integer. Size of the file in bytes.
2229 :size: Integer. Size of the file in bytes.
2230
2230
2231 Examples:
2231 Examples:
2232
2232
2233 - list all files under the current directory::
2233 - list all files under the current directory::
2234
2234
2235 hg files .
2235 hg files .
2236
2236
2237 - shows sizes and flags for current revision::
2237 - shows sizes and flags for current revision::
2238
2238
2239 hg files -vr .
2239 hg files -vr .
2240
2240
2241 - list all files named README::
2241 - list all files named README::
2242
2242
2243 hg files -I "**/README"
2243 hg files -I "**/README"
2244
2244
2245 - list all binary files::
2245 - list all binary files::
2246
2246
2247 hg files "set:binary()"
2247 hg files "set:binary()"
2248
2248
2249 - find files containing a regular expression::
2249 - find files containing a regular expression::
2250
2250
2251 hg files "set:grep('bob')"
2251 hg files "set:grep('bob')"
2252
2252
2253 - search tracked file contents with xargs and grep::
2253 - search tracked file contents with xargs and grep::
2254
2254
2255 hg files -0 | xargs -0 grep foo
2255 hg files -0 | xargs -0 grep foo
2256
2256
2257 See :hg:`help patterns` and :hg:`help filesets` for more information
2257 See :hg:`help patterns` and :hg:`help filesets` for more information
2258 on specifying file patterns.
2258 on specifying file patterns.
2259
2259
2260 Returns 0 if a match is found, 1 otherwise.
2260 Returns 0 if a match is found, 1 otherwise.
2261
2261
2262 """
2262 """
2263
2263
2264 opts = pycompat.byteskwargs(opts)
2264 opts = pycompat.byteskwargs(opts)
2265 rev = opts.get('rev')
2265 rev = opts.get('rev')
2266 if rev:
2266 if rev:
2267 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2267 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2268 ctx = scmutil.revsingle(repo, rev, None)
2268 ctx = scmutil.revsingle(repo, rev, None)
2269
2269
2270 end = '\n'
2270 end = '\n'
2271 if opts.get('print0'):
2271 if opts.get('print0'):
2272 end = '\0'
2272 end = '\0'
2273 fmt = '%s' + end
2273 fmt = '%s' + end
2274
2274
2275 m = scmutil.match(ctx, pats, opts)
2275 m = scmutil.match(ctx, pats, opts)
2276 ui.pager('files')
2276 ui.pager('files')
2277 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2277 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2278 with ui.formatter('files', opts) as fm:
2278 with ui.formatter('files', opts) as fm:
2279 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2279 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2280 opts.get('subrepos'))
2280 opts.get('subrepos'))
2281
2281
2282 @command(
2282 @command(
2283 'forget',
2283 'forget',
2284 [('i', 'interactive', None, _('use interactive mode')),
2284 [('i', 'interactive', None, _('use interactive mode')),
2285 ] + walkopts + dryrunopts,
2285 ] + walkopts + dryrunopts,
2286 _('[OPTION]... FILE...'),
2286 _('[OPTION]... FILE...'),
2287 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2287 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2288 helpbasic=True, inferrepo=True)
2288 helpbasic=True, inferrepo=True)
2289 def forget(ui, repo, *pats, **opts):
2289 def forget(ui, repo, *pats, **opts):
2290 """forget the specified files on the next commit
2290 """forget the specified files on the next commit
2291
2291
2292 Mark the specified files so they will no longer be tracked
2292 Mark the specified files so they will no longer be tracked
2293 after the next commit.
2293 after the next commit.
2294
2294
2295 This only removes files from the current branch, not from the
2295 This only removes files from the current branch, not from the
2296 entire project history, and it does not delete them from the
2296 entire project history, and it does not delete them from the
2297 working directory.
2297 working directory.
2298
2298
2299 To delete the file from the working directory, see :hg:`remove`.
2299 To delete the file from the working directory, see :hg:`remove`.
2300
2300
2301 To undo a forget before the next commit, see :hg:`add`.
2301 To undo a forget before the next commit, see :hg:`add`.
2302
2302
2303 .. container:: verbose
2303 .. container:: verbose
2304
2304
2305 Examples:
2305 Examples:
2306
2306
2307 - forget newly-added binary files::
2307 - forget newly-added binary files::
2308
2308
2309 hg forget "set:added() and binary()"
2309 hg forget "set:added() and binary()"
2310
2310
2311 - forget files that would be excluded by .hgignore::
2311 - forget files that would be excluded by .hgignore::
2312
2312
2313 hg forget "set:hgignore()"
2313 hg forget "set:hgignore()"
2314
2314
2315 Returns 0 on success.
2315 Returns 0 on success.
2316 """
2316 """
2317
2317
2318 opts = pycompat.byteskwargs(opts)
2318 opts = pycompat.byteskwargs(opts)
2319 if not pats:
2319 if not pats:
2320 raise error.Abort(_('no files specified'))
2320 raise error.Abort(_('no files specified'))
2321
2321
2322 m = scmutil.match(repo[None], pats, opts)
2322 m = scmutil.match(repo[None], pats, opts)
2323 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2323 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2324 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2324 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2325 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2325 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2326 explicitonly=False, dryrun=dryrun,
2326 explicitonly=False, dryrun=dryrun,
2327 interactive=interactive)[0]
2327 interactive=interactive)[0]
2328 return rejected and 1 or 0
2328 return rejected and 1 or 0
2329
2329
2330 @command(
2330 @command(
2331 'graft',
2331 'graft',
2332 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2332 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2333 ('', 'base', '',
2333 ('', 'base', '',
2334 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2334 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2335 ('c', 'continue', False, _('resume interrupted graft')),
2335 ('c', 'continue', False, _('resume interrupted graft')),
2336 ('', 'stop', False, _('stop interrupted graft')),
2336 ('', 'stop', False, _('stop interrupted graft')),
2337 ('', 'abort', False, _('abort interrupted graft')),
2337 ('', 'abort', False, _('abort interrupted graft')),
2338 ('e', 'edit', False, _('invoke editor on commit messages')),
2338 ('e', 'edit', False, _('invoke editor on commit messages')),
2339 ('', 'log', None, _('append graft info to log message')),
2339 ('', 'log', None, _('append graft info to log message')),
2340 ('', 'no-commit', None,
2340 ('', 'no-commit', None,
2341 _("don't commit, just apply the changes in working directory")),
2341 _("don't commit, just apply the changes in working directory")),
2342 ('f', 'force', False, _('force graft')),
2342 ('f', 'force', False, _('force graft')),
2343 ('D', 'currentdate', False,
2343 ('D', 'currentdate', False,
2344 _('record the current date as commit date')),
2344 _('record the current date as commit date')),
2345 ('U', 'currentuser', False,
2345 ('U', 'currentuser', False,
2346 _('record the current user as committer'))]
2346 _('record the current user as committer'))]
2347 + commitopts2 + mergetoolopts + dryrunopts,
2347 + commitopts2 + mergetoolopts + dryrunopts,
2348 _('[OPTION]... [-r REV]... REV...'),
2348 _('[OPTION]... [-r REV]... REV...'),
2349 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2349 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2350 def graft(ui, repo, *revs, **opts):
2350 def graft(ui, repo, *revs, **opts):
2351 '''copy changes from other branches onto the current branch
2351 '''copy changes from other branches onto the current branch
2352
2352
2353 This command uses Mercurial's merge logic to copy individual
2353 This command uses Mercurial's merge logic to copy individual
2354 changes from other branches without merging branches in the
2354 changes from other branches without merging branches in the
2355 history graph. This is sometimes known as 'backporting' or
2355 history graph. This is sometimes known as 'backporting' or
2356 'cherry-picking'. By default, graft will copy user, date, and
2356 'cherry-picking'. By default, graft will copy user, date, and
2357 description from the source changesets.
2357 description from the source changesets.
2358
2358
2359 Changesets that are ancestors of the current revision, that have
2359 Changesets that are ancestors of the current revision, that have
2360 already been grafted, or that are merges will be skipped.
2360 already been grafted, or that are merges will be skipped.
2361
2361
2362 If --log is specified, log messages will have a comment appended
2362 If --log is specified, log messages will have a comment appended
2363 of the form::
2363 of the form::
2364
2364
2365 (grafted from CHANGESETHASH)
2365 (grafted from CHANGESETHASH)
2366
2366
2367 If --force is specified, revisions will be grafted even if they
2367 If --force is specified, revisions will be grafted even if they
2368 are already ancestors of, or have been grafted to, the destination.
2368 are already ancestors of, or have been grafted to, the destination.
2369 This is useful when the revisions have since been backed out.
2369 This is useful when the revisions have since been backed out.
2370
2370
2371 If a graft merge results in conflicts, the graft process is
2371 If a graft merge results in conflicts, the graft process is
2372 interrupted so that the current merge can be manually resolved.
2372 interrupted so that the current merge can be manually resolved.
2373 Once all conflicts are addressed, the graft process can be
2373 Once all conflicts are addressed, the graft process can be
2374 continued with the -c/--continue option.
2374 continued with the -c/--continue option.
2375
2375
2376 The -c/--continue option reapplies all the earlier options.
2376 The -c/--continue option reapplies all the earlier options.
2377
2377
2378 .. container:: verbose
2378 .. container:: verbose
2379
2379
2380 The --base option exposes more of how graft internally uses merge with a
2380 The --base option exposes more of how graft internally uses merge with a
2381 custom base revision. --base can be used to specify another ancestor than
2381 custom base revision. --base can be used to specify another ancestor than
2382 the first and only parent.
2382 the first and only parent.
2383
2383
2384 The command::
2384 The command::
2385
2385
2386 hg graft -r 345 --base 234
2386 hg graft -r 345 --base 234
2387
2387
2388 is thus pretty much the same as::
2388 is thus pretty much the same as::
2389
2389
2390 hg diff -r 234 -r 345 | hg import
2390 hg diff -r 234 -r 345 | hg import
2391
2391
2392 but using merge to resolve conflicts and track moved files.
2392 but using merge to resolve conflicts and track moved files.
2393
2393
2394 The result of a merge can thus be backported as a single commit by
2394 The result of a merge can thus be backported as a single commit by
2395 specifying one of the merge parents as base, and thus effectively
2395 specifying one of the merge parents as base, and thus effectively
2396 grafting the changes from the other side.
2396 grafting the changes from the other side.
2397
2397
2398 It is also possible to collapse multiple changesets and clean up history
2398 It is also possible to collapse multiple changesets and clean up history
2399 by specifying another ancestor as base, much like rebase --collapse
2399 by specifying another ancestor as base, much like rebase --collapse
2400 --keep.
2400 --keep.
2401
2401
2402 The commit message can be tweaked after the fact using commit --amend .
2402 The commit message can be tweaked after the fact using commit --amend .
2403
2403
2404 For using non-ancestors as the base to backout changes, see the backout
2404 For using non-ancestors as the base to backout changes, see the backout
2405 command and the hidden --parent option.
2405 command and the hidden --parent option.
2406
2406
2407 .. container:: verbose
2407 .. container:: verbose
2408
2408
2409 Examples:
2409 Examples:
2410
2410
2411 - copy a single change to the stable branch and edit its description::
2411 - copy a single change to the stable branch and edit its description::
2412
2412
2413 hg update stable
2413 hg update stable
2414 hg graft --edit 9393
2414 hg graft --edit 9393
2415
2415
2416 - graft a range of changesets with one exception, updating dates::
2416 - graft a range of changesets with one exception, updating dates::
2417
2417
2418 hg graft -D "2085::2093 and not 2091"
2418 hg graft -D "2085::2093 and not 2091"
2419
2419
2420 - continue a graft after resolving conflicts::
2420 - continue a graft after resolving conflicts::
2421
2421
2422 hg graft -c
2422 hg graft -c
2423
2423
2424 - show the source of a grafted changeset::
2424 - show the source of a grafted changeset::
2425
2425
2426 hg log --debug -r .
2426 hg log --debug -r .
2427
2427
2428 - show revisions sorted by date::
2428 - show revisions sorted by date::
2429
2429
2430 hg log -r "sort(all(), date)"
2430 hg log -r "sort(all(), date)"
2431
2431
2432 - backport the result of a merge as a single commit::
2432 - backport the result of a merge as a single commit::
2433
2433
2434 hg graft -r 123 --base 123^
2434 hg graft -r 123 --base 123^
2435
2435
2436 - land a feature branch as one changeset::
2436 - land a feature branch as one changeset::
2437
2437
2438 hg up -cr default
2438 hg up -cr default
2439 hg graft -r featureX --base "ancestor('featureX', 'default')"
2439 hg graft -r featureX --base "ancestor('featureX', 'default')"
2440
2440
2441 See :hg:`help revisions` for more about specifying revisions.
2441 See :hg:`help revisions` for more about specifying revisions.
2442
2442
2443 Returns 0 on successful completion.
2443 Returns 0 on successful completion.
2444 '''
2444 '''
2445 with repo.wlock():
2445 with repo.wlock():
2446 return _dograft(ui, repo, *revs, **opts)
2446 return _dograft(ui, repo, *revs, **opts)
2447
2447
2448 def _dograft(ui, repo, *revs, **opts):
2448 def _dograft(ui, repo, *revs, **opts):
2449 opts = pycompat.byteskwargs(opts)
2449 opts = pycompat.byteskwargs(opts)
2450 if revs and opts.get('rev'):
2450 if revs and opts.get('rev'):
2451 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2451 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2452 'revision ordering!\n'))
2452 'revision ordering!\n'))
2453
2453
2454 revs = list(revs)
2454 revs = list(revs)
2455 revs.extend(opts.get('rev'))
2455 revs.extend(opts.get('rev'))
2456 basectx = None
2456 basectx = None
2457 if opts.get('base'):
2457 if opts.get('base'):
2458 basectx = scmutil.revsingle(repo, opts['base'], None)
2458 basectx = scmutil.revsingle(repo, opts['base'], None)
2459 # a dict of data to be stored in state file
2459 # a dict of data to be stored in state file
2460 statedata = {}
2460 statedata = {}
2461 # list of new nodes created by ongoing graft
2461 # list of new nodes created by ongoing graft
2462 statedata['newnodes'] = []
2462 statedata['newnodes'] = []
2463
2463
2464 if opts.get('user') and opts.get('currentuser'):
2464 if opts.get('user') and opts.get('currentuser'):
2465 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2465 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2466 if opts.get('date') and opts.get('currentdate'):
2466 if opts.get('date') and opts.get('currentdate'):
2467 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2467 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2468 if not opts.get('user') and opts.get('currentuser'):
2468 if not opts.get('user') and opts.get('currentuser'):
2469 opts['user'] = ui.username()
2469 opts['user'] = ui.username()
2470 if not opts.get('date') and opts.get('currentdate'):
2470 if not opts.get('date') and opts.get('currentdate'):
2471 opts['date'] = "%d %d" % dateutil.makedate()
2471 opts['date'] = "%d %d" % dateutil.makedate()
2472
2472
2473 editor = cmdutil.getcommiteditor(editform='graft',
2473 editor = cmdutil.getcommiteditor(editform='graft',
2474 **pycompat.strkwargs(opts))
2474 **pycompat.strkwargs(opts))
2475
2475
2476 cont = False
2476 cont = False
2477 if opts.get('no_commit'):
2477 if opts.get('no_commit'):
2478 if opts.get('edit'):
2478 if opts.get('edit'):
2479 raise error.Abort(_("cannot specify --no-commit and "
2479 raise error.Abort(_("cannot specify --no-commit and "
2480 "--edit together"))
2480 "--edit together"))
2481 if opts.get('currentuser'):
2481 if opts.get('currentuser'):
2482 raise error.Abort(_("cannot specify --no-commit and "
2482 raise error.Abort(_("cannot specify --no-commit and "
2483 "--currentuser together"))
2483 "--currentuser together"))
2484 if opts.get('currentdate'):
2484 if opts.get('currentdate'):
2485 raise error.Abort(_("cannot specify --no-commit and "
2485 raise error.Abort(_("cannot specify --no-commit and "
2486 "--currentdate together"))
2486 "--currentdate together"))
2487 if opts.get('log'):
2487 if opts.get('log'):
2488 raise error.Abort(_("cannot specify --no-commit and "
2488 raise error.Abort(_("cannot specify --no-commit and "
2489 "--log together"))
2489 "--log together"))
2490
2490
2491 graftstate = statemod.cmdstate(repo, 'graftstate')
2491 graftstate = statemod.cmdstate(repo, 'graftstate')
2492
2492
2493 if opts.get('stop'):
2493 if opts.get('stop'):
2494 if opts.get('continue'):
2494 if opts.get('continue'):
2495 raise error.Abort(_("cannot use '--continue' and "
2495 raise error.Abort(_("cannot use '--continue' and "
2496 "'--stop' together"))
2496 "'--stop' together"))
2497 if opts.get('abort'):
2497 if opts.get('abort'):
2498 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2498 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2499
2499
2500 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2500 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2501 opts.get('date'), opts.get('currentdate'),
2501 opts.get('date'), opts.get('currentdate'),
2502 opts.get('currentuser'), opts.get('rev'))):
2502 opts.get('currentuser'), opts.get('rev'))):
2503 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2503 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2504 return _stopgraft(ui, repo, graftstate)
2504 return _stopgraft(ui, repo, graftstate)
2505 elif opts.get('abort'):
2505 elif opts.get('abort'):
2506 if opts.get('continue'):
2506 if opts.get('continue'):
2507 raise error.Abort(_("cannot use '--continue' and "
2507 raise error.Abort(_("cannot use '--continue' and "
2508 "'--abort' together"))
2508 "'--abort' together"))
2509 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2509 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2510 opts.get('date'), opts.get('currentdate'),
2510 opts.get('date'), opts.get('currentdate'),
2511 opts.get('currentuser'), opts.get('rev'))):
2511 opts.get('currentuser'), opts.get('rev'))):
2512 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2512 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2513
2513
2514 return cmdutil.abortgraft(ui, repo, graftstate)
2514 return cmdutil.abortgraft(ui, repo, graftstate)
2515 elif opts.get('continue'):
2515 elif opts.get('continue'):
2516 cont = True
2516 cont = True
2517 if revs:
2517 if revs:
2518 raise error.Abort(_("can't specify --continue and revisions"))
2518 raise error.Abort(_("can't specify --continue and revisions"))
2519 # read in unfinished revisions
2519 # read in unfinished revisions
2520 if graftstate.exists():
2520 if graftstate.exists():
2521 statedata = cmdutil.readgraftstate(repo, graftstate)
2521 statedata = cmdutil.readgraftstate(repo, graftstate)
2522 if statedata.get('date'):
2522 if statedata.get('date'):
2523 opts['date'] = statedata['date']
2523 opts['date'] = statedata['date']
2524 if statedata.get('user'):
2524 if statedata.get('user'):
2525 opts['user'] = statedata['user']
2525 opts['user'] = statedata['user']
2526 if statedata.get('log'):
2526 if statedata.get('log'):
2527 opts['log'] = True
2527 opts['log'] = True
2528 if statedata.get('no_commit'):
2528 if statedata.get('no_commit'):
2529 opts['no_commit'] = statedata.get('no_commit')
2529 opts['no_commit'] = statedata.get('no_commit')
2530 nodes = statedata['nodes']
2530 nodes = statedata['nodes']
2531 revs = [repo[node].rev() for node in nodes]
2531 revs = [repo[node].rev() for node in nodes]
2532 else:
2532 else:
2533 cmdutil.wrongtooltocontinue(repo, _('graft'))
2533 cmdutil.wrongtooltocontinue(repo, _('graft'))
2534 else:
2534 else:
2535 if not revs:
2535 if not revs:
2536 raise error.Abort(_('no revisions specified'))
2536 raise error.Abort(_('no revisions specified'))
2537 cmdutil.checkunfinished(repo)
2537 cmdutil.checkunfinished(repo)
2538 cmdutil.bailifchanged(repo)
2538 cmdutil.bailifchanged(repo)
2539 revs = scmutil.revrange(repo, revs)
2539 revs = scmutil.revrange(repo, revs)
2540
2540
2541 skipped = set()
2541 skipped = set()
2542 if basectx is None:
2542 if basectx is None:
2543 # check for merges
2543 # check for merges
2544 for rev in repo.revs('%ld and merge()', revs):
2544 for rev in repo.revs('%ld and merge()', revs):
2545 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2545 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2546 skipped.add(rev)
2546 skipped.add(rev)
2547 revs = [r for r in revs if r not in skipped]
2547 revs = [r for r in revs if r not in skipped]
2548 if not revs:
2548 if not revs:
2549 return -1
2549 return -1
2550 if basectx is not None and len(revs) != 1:
2550 if basectx is not None and len(revs) != 1:
2551 raise error.Abort(_('only one revision allowed with --base '))
2551 raise error.Abort(_('only one revision allowed with --base '))
2552
2552
2553 # Don't check in the --continue case, in effect retaining --force across
2553 # Don't check in the --continue case, in effect retaining --force across
2554 # --continues. That's because without --force, any revisions we decided to
2554 # --continues. That's because without --force, any revisions we decided to
2555 # skip would have been filtered out here, so they wouldn't have made their
2555 # skip would have been filtered out here, so they wouldn't have made their
2556 # way to the graftstate. With --force, any revisions we would have otherwise
2556 # way to the graftstate. With --force, any revisions we would have otherwise
2557 # skipped would not have been filtered out, and if they hadn't been applied
2557 # skipped would not have been filtered out, and if they hadn't been applied
2558 # already, they'd have been in the graftstate.
2558 # already, they'd have been in the graftstate.
2559 if not (cont or opts.get('force')) and basectx is None:
2559 if not (cont or opts.get('force')) and basectx is None:
2560 # check for ancestors of dest branch
2560 # check for ancestors of dest branch
2561 crev = repo['.'].rev()
2561 crev = repo['.'].rev()
2562 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2562 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2563 # XXX make this lazy in the future
2563 # XXX make this lazy in the future
2564 # don't mutate while iterating, create a copy
2564 # don't mutate while iterating, create a copy
2565 for rev in list(revs):
2565 for rev in list(revs):
2566 if rev in ancestors:
2566 if rev in ancestors:
2567 ui.warn(_('skipping ancestor revision %d:%s\n') %
2567 ui.warn(_('skipping ancestor revision %d:%s\n') %
2568 (rev, repo[rev]))
2568 (rev, repo[rev]))
2569 # XXX remove on list is slow
2569 # XXX remove on list is slow
2570 revs.remove(rev)
2570 revs.remove(rev)
2571 if not revs:
2571 if not revs:
2572 return -1
2572 return -1
2573
2573
2574 # analyze revs for earlier grafts
2574 # analyze revs for earlier grafts
2575 ids = {}
2575 ids = {}
2576 for ctx in repo.set("%ld", revs):
2576 for ctx in repo.set("%ld", revs):
2577 ids[ctx.hex()] = ctx.rev()
2577 ids[ctx.hex()] = ctx.rev()
2578 n = ctx.extra().get('source')
2578 n = ctx.extra().get('source')
2579 if n:
2579 if n:
2580 ids[n] = ctx.rev()
2580 ids[n] = ctx.rev()
2581
2581
2582 # check ancestors for earlier grafts
2582 # check ancestors for earlier grafts
2583 ui.debug('scanning for duplicate grafts\n')
2583 ui.debug('scanning for duplicate grafts\n')
2584
2584
2585 # The only changesets we can be sure doesn't contain grafts of any
2585 # The only changesets we can be sure doesn't contain grafts of any
2586 # revs, are the ones that are common ancestors of *all* revs:
2586 # revs, are the ones that are common ancestors of *all* revs:
2587 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2587 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2588 ctx = repo[rev]
2588 ctx = repo[rev]
2589 n = ctx.extra().get('source')
2589 n = ctx.extra().get('source')
2590 if n in ids:
2590 if n in ids:
2591 try:
2591 try:
2592 r = repo[n].rev()
2592 r = repo[n].rev()
2593 except error.RepoLookupError:
2593 except error.RepoLookupError:
2594 r = None
2594 r = None
2595 if r in revs:
2595 if r in revs:
2596 ui.warn(_('skipping revision %d:%s '
2596 ui.warn(_('skipping revision %d:%s '
2597 '(already grafted to %d:%s)\n')
2597 '(already grafted to %d:%s)\n')
2598 % (r, repo[r], rev, ctx))
2598 % (r, repo[r], rev, ctx))
2599 revs.remove(r)
2599 revs.remove(r)
2600 elif ids[n] in revs:
2600 elif ids[n] in revs:
2601 if r is None:
2601 if r is None:
2602 ui.warn(_('skipping already grafted revision %d:%s '
2602 ui.warn(_('skipping already grafted revision %d:%s '
2603 '(%d:%s also has unknown origin %s)\n')
2603 '(%d:%s also has unknown origin %s)\n')
2604 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2604 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2605 else:
2605 else:
2606 ui.warn(_('skipping already grafted revision %d:%s '
2606 ui.warn(_('skipping already grafted revision %d:%s '
2607 '(%d:%s also has origin %d:%s)\n')
2607 '(%d:%s also has origin %d:%s)\n')
2608 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2608 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2609 revs.remove(ids[n])
2609 revs.remove(ids[n])
2610 elif ctx.hex() in ids:
2610 elif ctx.hex() in ids:
2611 r = ids[ctx.hex()]
2611 r = ids[ctx.hex()]
2612 if r in revs:
2612 if r in revs:
2613 ui.warn(_('skipping already grafted revision %d:%s '
2613 ui.warn(_('skipping already grafted revision %d:%s '
2614 '(was grafted from %d:%s)\n') %
2614 '(was grafted from %d:%s)\n') %
2615 (r, repo[r], rev, ctx))
2615 (r, repo[r], rev, ctx))
2616 revs.remove(r)
2616 revs.remove(r)
2617 if not revs:
2617 if not revs:
2618 return -1
2618 return -1
2619
2619
2620 if opts.get('no_commit'):
2620 if opts.get('no_commit'):
2621 statedata['no_commit'] = True
2621 statedata['no_commit'] = True
2622 for pos, ctx in enumerate(repo.set("%ld", revs)):
2622 for pos, ctx in enumerate(repo.set("%ld", revs)):
2623 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2623 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2624 ctx.description().split('\n', 1)[0])
2624 ctx.description().split('\n', 1)[0])
2625 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2625 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2626 if names:
2626 if names:
2627 desc += ' (%s)' % ' '.join(names)
2627 desc += ' (%s)' % ' '.join(names)
2628 ui.status(_('grafting %s\n') % desc)
2628 ui.status(_('grafting %s\n') % desc)
2629 if opts.get('dry_run'):
2629 if opts.get('dry_run'):
2630 continue
2630 continue
2631
2631
2632 source = ctx.extra().get('source')
2632 source = ctx.extra().get('source')
2633 extra = {}
2633 extra = {}
2634 if source:
2634 if source:
2635 extra['source'] = source
2635 extra['source'] = source
2636 extra['intermediate-source'] = ctx.hex()
2636 extra['intermediate-source'] = ctx.hex()
2637 else:
2637 else:
2638 extra['source'] = ctx.hex()
2638 extra['source'] = ctx.hex()
2639 user = ctx.user()
2639 user = ctx.user()
2640 if opts.get('user'):
2640 if opts.get('user'):
2641 user = opts['user']
2641 user = opts['user']
2642 statedata['user'] = user
2642 statedata['user'] = user
2643 date = ctx.date()
2643 date = ctx.date()
2644 if opts.get('date'):
2644 if opts.get('date'):
2645 date = opts['date']
2645 date = opts['date']
2646 statedata['date'] = date
2646 statedata['date'] = date
2647 message = ctx.description()
2647 message = ctx.description()
2648 if opts.get('log'):
2648 if opts.get('log'):
2649 message += '\n(grafted from %s)' % ctx.hex()
2649 message += '\n(grafted from %s)' % ctx.hex()
2650 statedata['log'] = True
2650 statedata['log'] = True
2651
2651
2652 # we don't merge the first commit when continuing
2652 # we don't merge the first commit when continuing
2653 if not cont:
2653 if not cont:
2654 # perform the graft merge with p1(rev) as 'ancestor'
2654 # perform the graft merge with p1(rev) as 'ancestor'
2655 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2655 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2656 base = ctx.p1() if basectx is None else basectx
2656 base = ctx.p1() if basectx is None else basectx
2657 with ui.configoverride(overrides, 'graft'):
2657 with ui.configoverride(overrides, 'graft'):
2658 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2658 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2659 # report any conflicts
2659 # report any conflicts
2660 if stats.unresolvedcount > 0:
2660 if stats.unresolvedcount > 0:
2661 # write out state for --continue
2661 # write out state for --continue
2662 nodes = [repo[rev].hex() for rev in revs[pos:]]
2662 nodes = [repo[rev].hex() for rev in revs[pos:]]
2663 statedata['nodes'] = nodes
2663 statedata['nodes'] = nodes
2664 stateversion = 1
2664 stateversion = 1
2665 graftstate.save(stateversion, statedata)
2665 graftstate.save(stateversion, statedata)
2666 hint = _("use 'hg resolve' and 'hg graft --continue'")
2666 hint = _("use 'hg resolve' and 'hg graft --continue'")
2667 raise error.Abort(
2667 raise error.Abort(
2668 _("unresolved conflicts, can't continue"),
2668 _("unresolved conflicts, can't continue"),
2669 hint=hint)
2669 hint=hint)
2670 else:
2670 else:
2671 cont = False
2671 cont = False
2672
2672
2673 # commit if --no-commit is false
2673 # commit if --no-commit is false
2674 if not opts.get('no_commit'):
2674 if not opts.get('no_commit'):
2675 node = repo.commit(text=message, user=user, date=date, extra=extra,
2675 node = repo.commit(text=message, user=user, date=date, extra=extra,
2676 editor=editor)
2676 editor=editor)
2677 if node is None:
2677 if node is None:
2678 ui.warn(
2678 ui.warn(
2679 _('note: graft of %d:%s created no changes to commit\n') %
2679 _('note: graft of %d:%s created no changes to commit\n') %
2680 (ctx.rev(), ctx))
2680 (ctx.rev(), ctx))
2681 # checking that newnodes exist because old state files won't have it
2681 # checking that newnodes exist because old state files won't have it
2682 elif statedata.get('newnodes') is not None:
2682 elif statedata.get('newnodes') is not None:
2683 statedata['newnodes'].append(node)
2683 statedata['newnodes'].append(node)
2684
2684
2685 # remove state when we complete successfully
2685 # remove state when we complete successfully
2686 if not opts.get('dry_run'):
2686 if not opts.get('dry_run'):
2687 graftstate.delete()
2687 graftstate.delete()
2688
2688
2689 return 0
2689 return 0
2690
2690
2691 def _stopgraft(ui, repo, graftstate):
2691 def _stopgraft(ui, repo, graftstate):
2692 """stop the interrupted graft"""
2692 """stop the interrupted graft"""
2693 if not graftstate.exists():
2693 if not graftstate.exists():
2694 raise error.Abort(_("no interrupted graft found"))
2694 raise error.Abort(_("no interrupted graft found"))
2695 pctx = repo['.']
2695 pctx = repo['.']
2696 hg.updaterepo(repo, pctx.node(), overwrite=True)
2696 hg.updaterepo(repo, pctx.node(), overwrite=True)
2697 graftstate.delete()
2697 graftstate.delete()
2698 ui.status(_("stopped the interrupted graft\n"))
2698 ui.status(_("stopped the interrupted graft\n"))
2699 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2699 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2700 return 0
2700 return 0
2701
2701
2702 statemod.addunfinished(
2702 statemod.addunfinished(
2703 'graft', fname='graftstate', clearable=True, stopflag=True,
2703 'graft', fname='graftstate', clearable=True, stopflag=True,
2704 continueflag=True, abortfunc=cmdutil.hgabortgraft,
2704 continueflag=True, abortfunc=cmdutil.hgabortgraft,
2705 cmdhint=_("use 'hg graft --continue' or 'hg graft --stop' to stop")
2705 cmdhint=_("use 'hg graft --continue' or 'hg graft --stop' to stop")
2706 )
2706 )
2707
2707
2708 @command('grep',
2708 @command('grep',
2709 [('0', 'print0', None, _('end fields with NUL')),
2709 [('0', 'print0', None, _('end fields with NUL')),
2710 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2710 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2711 ('', 'diff', None, _('print all revisions when the term was introduced '
2711 ('', 'diff', None, _('print all revisions when the term was introduced '
2712 'or removed')),
2712 'or removed')),
2713 ('a', 'text', None, _('treat all files as text')),
2713 ('a', 'text', None, _('treat all files as text')),
2714 ('f', 'follow', None,
2714 ('f', 'follow', None,
2715 _('follow changeset history,'
2715 _('follow changeset history,'
2716 ' or file history across copies and renames')),
2716 ' or file history across copies and renames')),
2717 ('i', 'ignore-case', None, _('ignore case when matching')),
2717 ('i', 'ignore-case', None, _('ignore case when matching')),
2718 ('l', 'files-with-matches', None,
2718 ('l', 'files-with-matches', None,
2719 _('print only filenames and revisions that match')),
2719 _('print only filenames and revisions that match')),
2720 ('n', 'line-number', None, _('print matching line numbers')),
2720 ('n', 'line-number', None, _('print matching line numbers')),
2721 ('r', 'rev', [],
2721 ('r', 'rev', [],
2722 _('only search files changed within revision range'), _('REV')),
2722 _('only search files changed within revision range'), _('REV')),
2723 ('', 'all-files', None,
2723 ('', 'all-files', None,
2724 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2724 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2725 ('u', 'user', None, _('list the author (long with -v)')),
2725 ('u', 'user', None, _('list the author (long with -v)')),
2726 ('d', 'date', None, _('list the date (short with -q)')),
2726 ('d', 'date', None, _('list the date (short with -q)')),
2727 ] + formatteropts + walkopts,
2727 ] + formatteropts + walkopts,
2728 _('[OPTION]... PATTERN [FILE]...'),
2728 _('[OPTION]... PATTERN [FILE]...'),
2729 helpcategory=command.CATEGORY_FILE_CONTENTS,
2729 helpcategory=command.CATEGORY_FILE_CONTENTS,
2730 inferrepo=True,
2730 inferrepo=True,
2731 intents={INTENT_READONLY})
2731 intents={INTENT_READONLY})
2732 def grep(ui, repo, pattern, *pats, **opts):
2732 def grep(ui, repo, pattern, *pats, **opts):
2733 """search revision history for a pattern in specified files
2733 """search revision history for a pattern in specified files
2734
2734
2735 Search revision history for a regular expression in the specified
2735 Search revision history for a regular expression in the specified
2736 files or the entire project.
2736 files or the entire project.
2737
2737
2738 By default, grep prints the most recent revision number for each
2738 By default, grep prints the most recent revision number for each
2739 file in which it finds a match. To get it to print every revision
2739 file in which it finds a match. To get it to print every revision
2740 that contains a change in match status ("-" for a match that becomes
2740 that contains a change in match status ("-" for a match that becomes
2741 a non-match, or "+" for a non-match that becomes a match), use the
2741 a non-match, or "+" for a non-match that becomes a match), use the
2742 --diff flag.
2742 --diff flag.
2743
2743
2744 PATTERN can be any Python (roughly Perl-compatible) regular
2744 PATTERN can be any Python (roughly Perl-compatible) regular
2745 expression.
2745 expression.
2746
2746
2747 If no FILEs are specified (and -f/--follow isn't set), all files in
2747 If no FILEs are specified (and -f/--follow isn't set), all files in
2748 the repository are searched, including those that don't exist in the
2748 the repository are searched, including those that don't exist in the
2749 current branch or have been deleted in a prior changeset.
2749 current branch or have been deleted in a prior changeset.
2750
2750
2751 .. container:: verbose
2751 .. container:: verbose
2752
2752
2753 Template:
2753 Template:
2754
2754
2755 The following keywords are supported in addition to the common template
2755 The following keywords are supported in addition to the common template
2756 keywords and functions. See also :hg:`help templates`.
2756 keywords and functions. See also :hg:`help templates`.
2757
2757
2758 :change: String. Character denoting insertion ``+`` or removal ``-``.
2758 :change: String. Character denoting insertion ``+`` or removal ``-``.
2759 Available if ``--diff`` is specified.
2759 Available if ``--diff`` is specified.
2760 :lineno: Integer. Line number of the match.
2760 :lineno: Integer. Line number of the match.
2761 :path: String. Repository-absolute path of the file.
2761 :path: String. Repository-absolute path of the file.
2762 :texts: List of text chunks.
2762 :texts: List of text chunks.
2763
2763
2764 And each entry of ``{texts}`` provides the following sub-keywords.
2764 And each entry of ``{texts}`` provides the following sub-keywords.
2765
2765
2766 :matched: Boolean. True if the chunk matches the specified pattern.
2766 :matched: Boolean. True if the chunk matches the specified pattern.
2767 :text: String. Chunk content.
2767 :text: String. Chunk content.
2768
2768
2769 See :hg:`help templates.operators` for the list expansion syntax.
2769 See :hg:`help templates.operators` for the list expansion syntax.
2770
2770
2771 Returns 0 if a match is found, 1 otherwise.
2771 Returns 0 if a match is found, 1 otherwise.
2772 """
2772 """
2773 opts = pycompat.byteskwargs(opts)
2773 opts = pycompat.byteskwargs(opts)
2774 diff = opts.get('all') or opts.get('diff')
2774 diff = opts.get('all') or opts.get('diff')
2775 all_files = opts.get('all_files')
2775 all_files = opts.get('all_files')
2776 if diff and opts.get('all_files'):
2776 if diff and opts.get('all_files'):
2777 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2777 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2778 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2778 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2779 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2779 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2780 # experimental config: commands.grep.all-files
2780 # experimental config: commands.grep.all-files
2781 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2781 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2782 plaingrep = opts.get('all_files') and not opts.get('rev')
2782 plaingrep = opts.get('all_files') and not opts.get('rev')
2783 if plaingrep:
2783 if plaingrep:
2784 opts['rev'] = ['wdir()']
2784 opts['rev'] = ['wdir()']
2785
2785
2786 reflags = re.M
2786 reflags = re.M
2787 if opts.get('ignore_case'):
2787 if opts.get('ignore_case'):
2788 reflags |= re.I
2788 reflags |= re.I
2789 try:
2789 try:
2790 regexp = util.re.compile(pattern, reflags)
2790 regexp = util.re.compile(pattern, reflags)
2791 except re.error as inst:
2791 except re.error as inst:
2792 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2792 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2793 return 1
2793 return 1
2794 sep, eol = ':', '\n'
2794 sep, eol = ':', '\n'
2795 if opts.get('print0'):
2795 if opts.get('print0'):
2796 sep = eol = '\0'
2796 sep = eol = '\0'
2797
2797
2798 getfile = util.lrucachefunc(repo.file)
2798 getfile = util.lrucachefunc(repo.file)
2799
2799
2800 def matchlines(body):
2800 def matchlines(body):
2801 begin = 0
2801 begin = 0
2802 linenum = 0
2802 linenum = 0
2803 while begin < len(body):
2803 while begin < len(body):
2804 match = regexp.search(body, begin)
2804 match = regexp.search(body, begin)
2805 if not match:
2805 if not match:
2806 break
2806 break
2807 mstart, mend = match.span()
2807 mstart, mend = match.span()
2808 linenum += body.count('\n', begin, mstart) + 1
2808 linenum += body.count('\n', begin, mstart) + 1
2809 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2809 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2810 begin = body.find('\n', mend) + 1 or len(body) + 1
2810 begin = body.find('\n', mend) + 1 or len(body) + 1
2811 lend = begin - 1
2811 lend = begin - 1
2812 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2812 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2813
2813
2814 class linestate(object):
2814 class linestate(object):
2815 def __init__(self, line, linenum, colstart, colend):
2815 def __init__(self, line, linenum, colstart, colend):
2816 self.line = line
2816 self.line = line
2817 self.linenum = linenum
2817 self.linenum = linenum
2818 self.colstart = colstart
2818 self.colstart = colstart
2819 self.colend = colend
2819 self.colend = colend
2820
2820
2821 def __hash__(self):
2821 def __hash__(self):
2822 return hash((self.linenum, self.line))
2822 return hash((self.linenum, self.line))
2823
2823
2824 def __eq__(self, other):
2824 def __eq__(self, other):
2825 return self.line == other.line
2825 return self.line == other.line
2826
2826
2827 def findpos(self):
2827 def findpos(self):
2828 """Iterate all (start, end) indices of matches"""
2828 """Iterate all (start, end) indices of matches"""
2829 yield self.colstart, self.colend
2829 yield self.colstart, self.colend
2830 p = self.colend
2830 p = self.colend
2831 while p < len(self.line):
2831 while p < len(self.line):
2832 m = regexp.search(self.line, p)
2832 m = regexp.search(self.line, p)
2833 if not m:
2833 if not m:
2834 break
2834 break
2835 yield m.span()
2835 yield m.span()
2836 p = m.end()
2836 p = m.end()
2837
2837
2838 matches = {}
2838 matches = {}
2839 copies = {}
2839 copies = {}
2840 def grepbody(fn, rev, body):
2840 def grepbody(fn, rev, body):
2841 matches[rev].setdefault(fn, [])
2841 matches[rev].setdefault(fn, [])
2842 m = matches[rev][fn]
2842 m = matches[rev][fn]
2843 for lnum, cstart, cend, line in matchlines(body):
2843 for lnum, cstart, cend, line in matchlines(body):
2844 s = linestate(line, lnum, cstart, cend)
2844 s = linestate(line, lnum, cstart, cend)
2845 m.append(s)
2845 m.append(s)
2846
2846
2847 def difflinestates(a, b):
2847 def difflinestates(a, b):
2848 sm = difflib.SequenceMatcher(None, a, b)
2848 sm = difflib.SequenceMatcher(None, a, b)
2849 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2849 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2850 if tag == r'insert':
2850 if tag == r'insert':
2851 for i in pycompat.xrange(blo, bhi):
2851 for i in pycompat.xrange(blo, bhi):
2852 yield ('+', b[i])
2852 yield ('+', b[i])
2853 elif tag == r'delete':
2853 elif tag == r'delete':
2854 for i in pycompat.xrange(alo, ahi):
2854 for i in pycompat.xrange(alo, ahi):
2855 yield ('-', a[i])
2855 yield ('-', a[i])
2856 elif tag == r'replace':
2856 elif tag == r'replace':
2857 for i in pycompat.xrange(alo, ahi):
2857 for i in pycompat.xrange(alo, ahi):
2858 yield ('-', a[i])
2858 yield ('-', a[i])
2859 for i in pycompat.xrange(blo, bhi):
2859 for i in pycompat.xrange(blo, bhi):
2860 yield ('+', b[i])
2860 yield ('+', b[i])
2861
2861
2862 uipathfn = scmutil.getuipathfn(repo)
2862 uipathfn = scmutil.getuipathfn(repo)
2863 def display(fm, fn, ctx, pstates, states):
2863 def display(fm, fn, ctx, pstates, states):
2864 rev = scmutil.intrev(ctx)
2864 rev = scmutil.intrev(ctx)
2865 if fm.isplain():
2865 if fm.isplain():
2866 formatuser = ui.shortuser
2866 formatuser = ui.shortuser
2867 else:
2867 else:
2868 formatuser = pycompat.bytestr
2868 formatuser = pycompat.bytestr
2869 if ui.quiet:
2869 if ui.quiet:
2870 datefmt = '%Y-%m-%d'
2870 datefmt = '%Y-%m-%d'
2871 else:
2871 else:
2872 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2872 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2873 found = False
2873 found = False
2874 @util.cachefunc
2874 @util.cachefunc
2875 def binary():
2875 def binary():
2876 flog = getfile(fn)
2876 flog = getfile(fn)
2877 try:
2877 try:
2878 return stringutil.binary(flog.read(ctx.filenode(fn)))
2878 return stringutil.binary(flog.read(ctx.filenode(fn)))
2879 except error.WdirUnsupported:
2879 except error.WdirUnsupported:
2880 return ctx[fn].isbinary()
2880 return ctx[fn].isbinary()
2881
2881
2882 fieldnamemap = {'linenumber': 'lineno'}
2882 fieldnamemap = {'linenumber': 'lineno'}
2883 if diff:
2883 if diff:
2884 iter = difflinestates(pstates, states)
2884 iter = difflinestates(pstates, states)
2885 else:
2885 else:
2886 iter = [('', l) for l in states]
2886 iter = [('', l) for l in states]
2887 for change, l in iter:
2887 for change, l in iter:
2888 fm.startitem()
2888 fm.startitem()
2889 fm.context(ctx=ctx)
2889 fm.context(ctx=ctx)
2890 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2890 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2891 fm.plain(uipathfn(fn), label='grep.filename')
2891 fm.plain(uipathfn(fn), label='grep.filename')
2892
2892
2893 cols = [
2893 cols = [
2894 ('rev', '%d', rev, not plaingrep, ''),
2894 ('rev', '%d', rev, not plaingrep, ''),
2895 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2895 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2896 ]
2896 ]
2897 if diff:
2897 if diff:
2898 cols.append(
2898 cols.append(
2899 ('change', '%s', change, True,
2899 ('change', '%s', change, True,
2900 'grep.inserted ' if change == '+' else 'grep.deleted ')
2900 'grep.inserted ' if change == '+' else 'grep.deleted ')
2901 )
2901 )
2902 cols.extend([
2902 cols.extend([
2903 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2903 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2904 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2904 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2905 opts.get('date'), ''),
2905 opts.get('date'), ''),
2906 ])
2906 ])
2907 for name, fmt, data, cond, extra_label in cols:
2907 for name, fmt, data, cond, extra_label in cols:
2908 if cond:
2908 if cond:
2909 fm.plain(sep, label='grep.sep')
2909 fm.plain(sep, label='grep.sep')
2910 field = fieldnamemap.get(name, name)
2910 field = fieldnamemap.get(name, name)
2911 label = extra_label + ('grep.%s' % name)
2911 label = extra_label + ('grep.%s' % name)
2912 fm.condwrite(cond, field, fmt, data, label=label)
2912 fm.condwrite(cond, field, fmt, data, label=label)
2913 if not opts.get('files_with_matches'):
2913 if not opts.get('files_with_matches'):
2914 fm.plain(sep, label='grep.sep')
2914 fm.plain(sep, label='grep.sep')
2915 if not opts.get('text') and binary():
2915 if not opts.get('text') and binary():
2916 fm.plain(_(" Binary file matches"))
2916 fm.plain(_(" Binary file matches"))
2917 else:
2917 else:
2918 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2918 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2919 fm.plain(eol)
2919 fm.plain(eol)
2920 found = True
2920 found = True
2921 if opts.get('files_with_matches'):
2921 if opts.get('files_with_matches'):
2922 break
2922 break
2923 return found
2923 return found
2924
2924
2925 def displaymatches(fm, l):
2925 def displaymatches(fm, l):
2926 p = 0
2926 p = 0
2927 for s, e in l.findpos():
2927 for s, e in l.findpos():
2928 if p < s:
2928 if p < s:
2929 fm.startitem()
2929 fm.startitem()
2930 fm.write('text', '%s', l.line[p:s])
2930 fm.write('text', '%s', l.line[p:s])
2931 fm.data(matched=False)
2931 fm.data(matched=False)
2932 fm.startitem()
2932 fm.startitem()
2933 fm.write('text', '%s', l.line[s:e], label='grep.match')
2933 fm.write('text', '%s', l.line[s:e], label='grep.match')
2934 fm.data(matched=True)
2934 fm.data(matched=True)
2935 p = e
2935 p = e
2936 if p < len(l.line):
2936 if p < len(l.line):
2937 fm.startitem()
2937 fm.startitem()
2938 fm.write('text', '%s', l.line[p:])
2938 fm.write('text', '%s', l.line[p:])
2939 fm.data(matched=False)
2939 fm.data(matched=False)
2940 fm.end()
2940 fm.end()
2941
2941
2942 skip = set()
2942 skip = set()
2943 revfiles = {}
2943 revfiles = {}
2944 match = scmutil.match(repo[None], pats, opts)
2944 match = scmutil.match(repo[None], pats, opts)
2945 found = False
2945 found = False
2946 follow = opts.get('follow')
2946 follow = opts.get('follow')
2947
2947
2948 getrenamed = scmutil.getrenamedfn(repo)
2948 getrenamed = scmutil.getrenamedfn(repo)
2949 def prep(ctx, fns):
2949 def prep(ctx, fns):
2950 rev = ctx.rev()
2950 rev = ctx.rev()
2951 pctx = ctx.p1()
2951 pctx = ctx.p1()
2952 parent = pctx.rev()
2952 parent = pctx.rev()
2953 matches.setdefault(rev, {})
2953 matches.setdefault(rev, {})
2954 matches.setdefault(parent, {})
2954 matches.setdefault(parent, {})
2955 files = revfiles.setdefault(rev, [])
2955 files = revfiles.setdefault(rev, [])
2956 for fn in fns:
2956 for fn in fns:
2957 flog = getfile(fn)
2957 flog = getfile(fn)
2958 try:
2958 try:
2959 fnode = ctx.filenode(fn)
2959 fnode = ctx.filenode(fn)
2960 except error.LookupError:
2960 except error.LookupError:
2961 continue
2961 continue
2962
2962
2963 copy = None
2963 copy = None
2964 if follow:
2964 if follow:
2965 copy = getrenamed(fn, rev)
2965 copy = getrenamed(fn, rev)
2966 if copy:
2966 if copy:
2967 copies.setdefault(rev, {})[fn] = copy
2967 copies.setdefault(rev, {})[fn] = copy
2968 if fn in skip:
2968 if fn in skip:
2969 skip.add(copy)
2969 skip.add(copy)
2970 if fn in skip:
2970 if fn in skip:
2971 continue
2971 continue
2972 files.append(fn)
2972 files.append(fn)
2973
2973
2974 if fn not in matches[rev]:
2974 if fn not in matches[rev]:
2975 try:
2975 try:
2976 content = flog.read(fnode)
2976 content = flog.read(fnode)
2977 except error.WdirUnsupported:
2977 except error.WdirUnsupported:
2978 content = ctx[fn].data()
2978 content = ctx[fn].data()
2979 grepbody(fn, rev, content)
2979 grepbody(fn, rev, content)
2980
2980
2981 pfn = copy or fn
2981 pfn = copy or fn
2982 if pfn not in matches[parent]:
2982 if pfn not in matches[parent]:
2983 try:
2983 try:
2984 fnode = pctx.filenode(pfn)
2984 fnode = pctx.filenode(pfn)
2985 grepbody(pfn, parent, flog.read(fnode))
2985 grepbody(pfn, parent, flog.read(fnode))
2986 except error.LookupError:
2986 except error.LookupError:
2987 pass
2987 pass
2988
2988
2989 ui.pager('grep')
2989 ui.pager('grep')
2990 fm = ui.formatter('grep', opts)
2990 fm = ui.formatter('grep', opts)
2991 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2991 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2992 rev = ctx.rev()
2992 rev = ctx.rev()
2993 parent = ctx.p1().rev()
2993 parent = ctx.p1().rev()
2994 for fn in sorted(revfiles.get(rev, [])):
2994 for fn in sorted(revfiles.get(rev, [])):
2995 states = matches[rev][fn]
2995 states = matches[rev][fn]
2996 copy = copies.get(rev, {}).get(fn)
2996 copy = copies.get(rev, {}).get(fn)
2997 if fn in skip:
2997 if fn in skip:
2998 if copy:
2998 if copy:
2999 skip.add(copy)
2999 skip.add(copy)
3000 continue
3000 continue
3001 pstates = matches.get(parent, {}).get(copy or fn, [])
3001 pstates = matches.get(parent, {}).get(copy or fn, [])
3002 if pstates or states:
3002 if pstates or states:
3003 r = display(fm, fn, ctx, pstates, states)
3003 r = display(fm, fn, ctx, pstates, states)
3004 found = found or r
3004 found = found or r
3005 if r and not diff and not all_files:
3005 if r and not diff and not all_files:
3006 skip.add(fn)
3006 skip.add(fn)
3007 if copy:
3007 if copy:
3008 skip.add(copy)
3008 skip.add(copy)
3009 del revfiles[rev]
3009 del revfiles[rev]
3010 # We will keep the matches dict for the duration of the window
3010 # We will keep the matches dict for the duration of the window
3011 # clear the matches dict once the window is over
3011 # clear the matches dict once the window is over
3012 if not revfiles:
3012 if not revfiles:
3013 matches.clear()
3013 matches.clear()
3014 fm.end()
3014 fm.end()
3015
3015
3016 return not found
3016 return not found
3017
3017
3018 @command('heads',
3018 @command('heads',
3019 [('r', 'rev', '',
3019 [('r', 'rev', '',
3020 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3020 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3021 ('t', 'topo', False, _('show topological heads only')),
3021 ('t', 'topo', False, _('show topological heads only')),
3022 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3022 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3023 ('c', 'closed', False, _('show normal and closed branch heads')),
3023 ('c', 'closed', False, _('show normal and closed branch heads')),
3024 ] + templateopts,
3024 ] + templateopts,
3025 _('[-ct] [-r STARTREV] [REV]...'),
3025 _('[-ct] [-r STARTREV] [REV]...'),
3026 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3026 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3027 intents={INTENT_READONLY})
3027 intents={INTENT_READONLY})
3028 def heads(ui, repo, *branchrevs, **opts):
3028 def heads(ui, repo, *branchrevs, **opts):
3029 """show branch heads
3029 """show branch heads
3030
3030
3031 With no arguments, show all open branch heads in the repository.
3031 With no arguments, show all open branch heads in the repository.
3032 Branch heads are changesets that have no descendants on the
3032 Branch heads are changesets that have no descendants on the
3033 same branch. They are where development generally takes place and
3033 same branch. They are where development generally takes place and
3034 are the usual targets for update and merge operations.
3034 are the usual targets for update and merge operations.
3035
3035
3036 If one or more REVs are given, only open branch heads on the
3036 If one or more REVs are given, only open branch heads on the
3037 branches associated with the specified changesets are shown. This
3037 branches associated with the specified changesets are shown. This
3038 means that you can use :hg:`heads .` to see the heads on the
3038 means that you can use :hg:`heads .` to see the heads on the
3039 currently checked-out branch.
3039 currently checked-out branch.
3040
3040
3041 If -c/--closed is specified, also show branch heads marked closed
3041 If -c/--closed is specified, also show branch heads marked closed
3042 (see :hg:`commit --close-branch`).
3042 (see :hg:`commit --close-branch`).
3043
3043
3044 If STARTREV is specified, only those heads that are descendants of
3044 If STARTREV is specified, only those heads that are descendants of
3045 STARTREV will be displayed.
3045 STARTREV will be displayed.
3046
3046
3047 If -t/--topo is specified, named branch mechanics will be ignored and only
3047 If -t/--topo is specified, named branch mechanics will be ignored and only
3048 topological heads (changesets with no children) will be shown.
3048 topological heads (changesets with no children) will be shown.
3049
3049
3050 Returns 0 if matching heads are found, 1 if not.
3050 Returns 0 if matching heads are found, 1 if not.
3051 """
3051 """
3052
3052
3053 opts = pycompat.byteskwargs(opts)
3053 opts = pycompat.byteskwargs(opts)
3054 start = None
3054 start = None
3055 rev = opts.get('rev')
3055 rev = opts.get('rev')
3056 if rev:
3056 if rev:
3057 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3057 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3058 start = scmutil.revsingle(repo, rev, None).node()
3058 start = scmutil.revsingle(repo, rev, None).node()
3059
3059
3060 if opts.get('topo'):
3060 if opts.get('topo'):
3061 heads = [repo[h] for h in repo.heads(start)]
3061 heads = [repo[h] for h in repo.heads(start)]
3062 else:
3062 else:
3063 heads = []
3063 heads = []
3064 for branch in repo.branchmap():
3064 for branch in repo.branchmap():
3065 heads += repo.branchheads(branch, start, opts.get('closed'))
3065 heads += repo.branchheads(branch, start, opts.get('closed'))
3066 heads = [repo[h] for h in heads]
3066 heads = [repo[h] for h in heads]
3067
3067
3068 if branchrevs:
3068 if branchrevs:
3069 branches = set(repo[r].branch()
3069 branches = set(repo[r].branch()
3070 for r in scmutil.revrange(repo, branchrevs))
3070 for r in scmutil.revrange(repo, branchrevs))
3071 heads = [h for h in heads if h.branch() in branches]
3071 heads = [h for h in heads if h.branch() in branches]
3072
3072
3073 if opts.get('active') and branchrevs:
3073 if opts.get('active') and branchrevs:
3074 dagheads = repo.heads(start)
3074 dagheads = repo.heads(start)
3075 heads = [h for h in heads if h.node() in dagheads]
3075 heads = [h for h in heads if h.node() in dagheads]
3076
3076
3077 if branchrevs:
3077 if branchrevs:
3078 haveheads = set(h.branch() for h in heads)
3078 haveheads = set(h.branch() for h in heads)
3079 if branches - haveheads:
3079 if branches - haveheads:
3080 headless = ', '.join(b for b in branches - haveheads)
3080 headless = ', '.join(b for b in branches - haveheads)
3081 msg = _('no open branch heads found on branches %s')
3081 msg = _('no open branch heads found on branches %s')
3082 if opts.get('rev'):
3082 if opts.get('rev'):
3083 msg += _(' (started at %s)') % opts['rev']
3083 msg += _(' (started at %s)') % opts['rev']
3084 ui.warn((msg + '\n') % headless)
3084 ui.warn((msg + '\n') % headless)
3085
3085
3086 if not heads:
3086 if not heads:
3087 return 1
3087 return 1
3088
3088
3089 ui.pager('heads')
3089 ui.pager('heads')
3090 heads = sorted(heads, key=lambda x: -x.rev())
3090 heads = sorted(heads, key=lambda x: -x.rev())
3091 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3091 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3092 for ctx in heads:
3092 for ctx in heads:
3093 displayer.show(ctx)
3093 displayer.show(ctx)
3094 displayer.close()
3094 displayer.close()
3095
3095
3096 @command('help',
3096 @command('help',
3097 [('e', 'extension', None, _('show only help for extensions')),
3097 [('e', 'extension', None, _('show only help for extensions')),
3098 ('c', 'command', None, _('show only help for commands')),
3098 ('c', 'command', None, _('show only help for commands')),
3099 ('k', 'keyword', None, _('show topics matching keyword')),
3099 ('k', 'keyword', None, _('show topics matching keyword')),
3100 ('s', 'system', [],
3100 ('s', 'system', [],
3101 _('show help for specific platform(s)'), _('PLATFORM')),
3101 _('show help for specific platform(s)'), _('PLATFORM')),
3102 ],
3102 ],
3103 _('[-eck] [-s PLATFORM] [TOPIC]'),
3103 _('[-eck] [-s PLATFORM] [TOPIC]'),
3104 helpcategory=command.CATEGORY_HELP,
3104 helpcategory=command.CATEGORY_HELP,
3105 norepo=True,
3105 norepo=True,
3106 intents={INTENT_READONLY})
3106 intents={INTENT_READONLY})
3107 def help_(ui, name=None, **opts):
3107 def help_(ui, name=None, **opts):
3108 """show help for a given topic or a help overview
3108 """show help for a given topic or a help overview
3109
3109
3110 With no arguments, print a list of commands with short help messages.
3110 With no arguments, print a list of commands with short help messages.
3111
3111
3112 Given a topic, extension, or command name, print help for that
3112 Given a topic, extension, or command name, print help for that
3113 topic.
3113 topic.
3114
3114
3115 Returns 0 if successful.
3115 Returns 0 if successful.
3116 """
3116 """
3117
3117
3118 keep = opts.get(r'system') or []
3118 keep = opts.get(r'system') or []
3119 if len(keep) == 0:
3119 if len(keep) == 0:
3120 if pycompat.sysplatform.startswith('win'):
3120 if pycompat.sysplatform.startswith('win'):
3121 keep.append('windows')
3121 keep.append('windows')
3122 elif pycompat.sysplatform == 'OpenVMS':
3122 elif pycompat.sysplatform == 'OpenVMS':
3123 keep.append('vms')
3123 keep.append('vms')
3124 elif pycompat.sysplatform == 'plan9':
3124 elif pycompat.sysplatform == 'plan9':
3125 keep.append('plan9')
3125 keep.append('plan9')
3126 else:
3126 else:
3127 keep.append('unix')
3127 keep.append('unix')
3128 keep.append(pycompat.sysplatform.lower())
3128 keep.append(pycompat.sysplatform.lower())
3129 if ui.verbose:
3129 if ui.verbose:
3130 keep.append('verbose')
3130 keep.append('verbose')
3131
3131
3132 commands = sys.modules[__name__]
3132 commands = sys.modules[__name__]
3133 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3133 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3134 ui.pager('help')
3134 ui.pager('help')
3135 ui.write(formatted)
3135 ui.write(formatted)
3136
3136
3137
3137
3138 @command('identify|id',
3138 @command('identify|id',
3139 [('r', 'rev', '',
3139 [('r', 'rev', '',
3140 _('identify the specified revision'), _('REV')),
3140 _('identify the specified revision'), _('REV')),
3141 ('n', 'num', None, _('show local revision number')),
3141 ('n', 'num', None, _('show local revision number')),
3142 ('i', 'id', None, _('show global revision id')),
3142 ('i', 'id', None, _('show global revision id')),
3143 ('b', 'branch', None, _('show branch')),
3143 ('b', 'branch', None, _('show branch')),
3144 ('t', 'tags', None, _('show tags')),
3144 ('t', 'tags', None, _('show tags')),
3145 ('B', 'bookmarks', None, _('show bookmarks')),
3145 ('B', 'bookmarks', None, _('show bookmarks')),
3146 ] + remoteopts + formatteropts,
3146 ] + remoteopts + formatteropts,
3147 _('[-nibtB] [-r REV] [SOURCE]'),
3147 _('[-nibtB] [-r REV] [SOURCE]'),
3148 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3148 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3149 optionalrepo=True,
3149 optionalrepo=True,
3150 intents={INTENT_READONLY})
3150 intents={INTENT_READONLY})
3151 def identify(ui, repo, source=None, rev=None,
3151 def identify(ui, repo, source=None, rev=None,
3152 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3152 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3153 """identify the working directory or specified revision
3153 """identify the working directory or specified revision
3154
3154
3155 Print a summary identifying the repository state at REV using one or
3155 Print a summary identifying the repository state at REV using one or
3156 two parent hash identifiers, followed by a "+" if the working
3156 two parent hash identifiers, followed by a "+" if the working
3157 directory has uncommitted changes, the branch name (if not default),
3157 directory has uncommitted changes, the branch name (if not default),
3158 a list of tags, and a list of bookmarks.
3158 a list of tags, and a list of bookmarks.
3159
3159
3160 When REV is not given, print a summary of the current state of the
3160 When REV is not given, print a summary of the current state of the
3161 repository including the working directory. Specify -r. to get information
3161 repository including the working directory. Specify -r. to get information
3162 of the working directory parent without scanning uncommitted changes.
3162 of the working directory parent without scanning uncommitted changes.
3163
3163
3164 Specifying a path to a repository root or Mercurial bundle will
3164 Specifying a path to a repository root or Mercurial bundle will
3165 cause lookup to operate on that repository/bundle.
3165 cause lookup to operate on that repository/bundle.
3166
3166
3167 .. container:: verbose
3167 .. container:: verbose
3168
3168
3169 Template:
3169 Template:
3170
3170
3171 The following keywords are supported in addition to the common template
3171 The following keywords are supported in addition to the common template
3172 keywords and functions. See also :hg:`help templates`.
3172 keywords and functions. See also :hg:`help templates`.
3173
3173
3174 :dirty: String. Character ``+`` denoting if the working directory has
3174 :dirty: String. Character ``+`` denoting if the working directory has
3175 uncommitted changes.
3175 uncommitted changes.
3176 :id: String. One or two nodes, optionally followed by ``+``.
3176 :id: String. One or two nodes, optionally followed by ``+``.
3177 :parents: List of strings. Parent nodes of the changeset.
3177 :parents: List of strings. Parent nodes of the changeset.
3178
3178
3179 Examples:
3179 Examples:
3180
3180
3181 - generate a build identifier for the working directory::
3181 - generate a build identifier for the working directory::
3182
3182
3183 hg id --id > build-id.dat
3183 hg id --id > build-id.dat
3184
3184
3185 - find the revision corresponding to a tag::
3185 - find the revision corresponding to a tag::
3186
3186
3187 hg id -n -r 1.3
3187 hg id -n -r 1.3
3188
3188
3189 - check the most recent revision of a remote repository::
3189 - check the most recent revision of a remote repository::
3190
3190
3191 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3191 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3192
3192
3193 See :hg:`log` for generating more information about specific revisions,
3193 See :hg:`log` for generating more information about specific revisions,
3194 including full hash identifiers.
3194 including full hash identifiers.
3195
3195
3196 Returns 0 if successful.
3196 Returns 0 if successful.
3197 """
3197 """
3198
3198
3199 opts = pycompat.byteskwargs(opts)
3199 opts = pycompat.byteskwargs(opts)
3200 if not repo and not source:
3200 if not repo and not source:
3201 raise error.Abort(_("there is no Mercurial repository here "
3201 raise error.Abort(_("there is no Mercurial repository here "
3202 "(.hg not found)"))
3202 "(.hg not found)"))
3203
3203
3204 default = not (num or id or branch or tags or bookmarks)
3204 default = not (num or id or branch or tags or bookmarks)
3205 output = []
3205 output = []
3206 revs = []
3206 revs = []
3207
3207
3208 if source:
3208 if source:
3209 source, branches = hg.parseurl(ui.expandpath(source))
3209 source, branches = hg.parseurl(ui.expandpath(source))
3210 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3210 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3211 repo = peer.local()
3211 repo = peer.local()
3212 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3212 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3213
3213
3214 fm = ui.formatter('identify', opts)
3214 fm = ui.formatter('identify', opts)
3215 fm.startitem()
3215 fm.startitem()
3216
3216
3217 if not repo:
3217 if not repo:
3218 if num or branch or tags:
3218 if num or branch or tags:
3219 raise error.Abort(
3219 raise error.Abort(
3220 _("can't query remote revision number, branch, or tags"))
3220 _("can't query remote revision number, branch, or tags"))
3221 if not rev and revs:
3221 if not rev and revs:
3222 rev = revs[0]
3222 rev = revs[0]
3223 if not rev:
3223 if not rev:
3224 rev = "tip"
3224 rev = "tip"
3225
3225
3226 remoterev = peer.lookup(rev)
3226 remoterev = peer.lookup(rev)
3227 hexrev = fm.hexfunc(remoterev)
3227 hexrev = fm.hexfunc(remoterev)
3228 if default or id:
3228 if default or id:
3229 output = [hexrev]
3229 output = [hexrev]
3230 fm.data(id=hexrev)
3230 fm.data(id=hexrev)
3231
3231
3232 @util.cachefunc
3232 @util.cachefunc
3233 def getbms():
3233 def getbms():
3234 bms = []
3234 bms = []
3235
3235
3236 if 'bookmarks' in peer.listkeys('namespaces'):
3236 if 'bookmarks' in peer.listkeys('namespaces'):
3237 hexremoterev = hex(remoterev)
3237 hexremoterev = hex(remoterev)
3238 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3238 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3239 if bmr == hexremoterev]
3239 if bmr == hexremoterev]
3240
3240
3241 return sorted(bms)
3241 return sorted(bms)
3242
3242
3243 if fm.isplain():
3243 if fm.isplain():
3244 if bookmarks:
3244 if bookmarks:
3245 output.extend(getbms())
3245 output.extend(getbms())
3246 elif default and not ui.quiet:
3246 elif default and not ui.quiet:
3247 # multiple bookmarks for a single parent separated by '/'
3247 # multiple bookmarks for a single parent separated by '/'
3248 bm = '/'.join(getbms())
3248 bm = '/'.join(getbms())
3249 if bm:
3249 if bm:
3250 output.append(bm)
3250 output.append(bm)
3251 else:
3251 else:
3252 fm.data(node=hex(remoterev))
3252 fm.data(node=hex(remoterev))
3253 if bookmarks or 'bookmarks' in fm.datahint():
3253 if bookmarks or 'bookmarks' in fm.datahint():
3254 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3254 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3255 else:
3255 else:
3256 if rev:
3256 if rev:
3257 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3257 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3258 ctx = scmutil.revsingle(repo, rev, None)
3258 ctx = scmutil.revsingle(repo, rev, None)
3259
3259
3260 if ctx.rev() is None:
3260 if ctx.rev() is None:
3261 ctx = repo[None]
3261 ctx = repo[None]
3262 parents = ctx.parents()
3262 parents = ctx.parents()
3263 taglist = []
3263 taglist = []
3264 for p in parents:
3264 for p in parents:
3265 taglist.extend(p.tags())
3265 taglist.extend(p.tags())
3266
3266
3267 dirty = ""
3267 dirty = ""
3268 if ctx.dirty(missing=True, merge=False, branch=False):
3268 if ctx.dirty(missing=True, merge=False, branch=False):
3269 dirty = '+'
3269 dirty = '+'
3270 fm.data(dirty=dirty)
3270 fm.data(dirty=dirty)
3271
3271
3272 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3272 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3273 if default or id:
3273 if default or id:
3274 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3274 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3275 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3275 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3276
3276
3277 if num:
3277 if num:
3278 numoutput = ["%d" % p.rev() for p in parents]
3278 numoutput = ["%d" % p.rev() for p in parents]
3279 output.append("%s%s" % ('+'.join(numoutput), dirty))
3279 output.append("%s%s" % ('+'.join(numoutput), dirty))
3280
3280
3281 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3281 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3282 for p in parents], name='node'))
3282 for p in parents], name='node'))
3283 else:
3283 else:
3284 hexoutput = fm.hexfunc(ctx.node())
3284 hexoutput = fm.hexfunc(ctx.node())
3285 if default or id:
3285 if default or id:
3286 output = [hexoutput]
3286 output = [hexoutput]
3287 fm.data(id=hexoutput)
3287 fm.data(id=hexoutput)
3288
3288
3289 if num:
3289 if num:
3290 output.append(pycompat.bytestr(ctx.rev()))
3290 output.append(pycompat.bytestr(ctx.rev()))
3291 taglist = ctx.tags()
3291 taglist = ctx.tags()
3292
3292
3293 if default and not ui.quiet:
3293 if default and not ui.quiet:
3294 b = ctx.branch()
3294 b = ctx.branch()
3295 if b != 'default':
3295 if b != 'default':
3296 output.append("(%s)" % b)
3296 output.append("(%s)" % b)
3297
3297
3298 # multiple tags for a single parent separated by '/'
3298 # multiple tags for a single parent separated by '/'
3299 t = '/'.join(taglist)
3299 t = '/'.join(taglist)
3300 if t:
3300 if t:
3301 output.append(t)
3301 output.append(t)
3302
3302
3303 # multiple bookmarks for a single parent separated by '/'
3303 # multiple bookmarks for a single parent separated by '/'
3304 bm = '/'.join(ctx.bookmarks())
3304 bm = '/'.join(ctx.bookmarks())
3305 if bm:
3305 if bm:
3306 output.append(bm)
3306 output.append(bm)
3307 else:
3307 else:
3308 if branch:
3308 if branch:
3309 output.append(ctx.branch())
3309 output.append(ctx.branch())
3310
3310
3311 if tags:
3311 if tags:
3312 output.extend(taglist)
3312 output.extend(taglist)
3313
3313
3314 if bookmarks:
3314 if bookmarks:
3315 output.extend(ctx.bookmarks())
3315 output.extend(ctx.bookmarks())
3316
3316
3317 fm.data(node=ctx.hex())
3317 fm.data(node=ctx.hex())
3318 fm.data(branch=ctx.branch())
3318 fm.data(branch=ctx.branch())
3319 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3319 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3320 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3320 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3321 fm.context(ctx=ctx)
3321 fm.context(ctx=ctx)
3322
3322
3323 fm.plain("%s\n" % ' '.join(output))
3323 fm.plain("%s\n" % ' '.join(output))
3324 fm.end()
3324 fm.end()
3325
3325
3326 @command('import|patch',
3326 @command('import|patch',
3327 [('p', 'strip', 1,
3327 [('p', 'strip', 1,
3328 _('directory strip option for patch. This has the same '
3328 _('directory strip option for patch. This has the same '
3329 'meaning as the corresponding patch option'), _('NUM')),
3329 'meaning as the corresponding patch option'), _('NUM')),
3330 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3330 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3331 ('e', 'edit', False, _('invoke editor on commit messages')),
3331 ('e', 'edit', False, _('invoke editor on commit messages')),
3332 ('f', 'force', None,
3332 ('f', 'force', None,
3333 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3333 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3334 ('', 'no-commit', None,
3334 ('', 'no-commit', None,
3335 _("don't commit, just update the working directory")),
3335 _("don't commit, just update the working directory")),
3336 ('', 'bypass', None,
3336 ('', 'bypass', None,
3337 _("apply patch without touching the working directory")),
3337 _("apply patch without touching the working directory")),
3338 ('', 'partial', None,
3338 ('', 'partial', None,
3339 _('commit even if some hunks fail')),
3339 _('commit even if some hunks fail')),
3340 ('', 'exact', None,
3340 ('', 'exact', None,
3341 _('abort if patch would apply lossily')),
3341 _('abort if patch would apply lossily')),
3342 ('', 'prefix', '',
3342 ('', 'prefix', '',
3343 _('apply patch to subdirectory'), _('DIR')),
3343 _('apply patch to subdirectory'), _('DIR')),
3344 ('', 'import-branch', None,
3344 ('', 'import-branch', None,
3345 _('use any branch information in patch (implied by --exact)'))] +
3345 _('use any branch information in patch (implied by --exact)'))] +
3346 commitopts + commitopts2 + similarityopts,
3346 commitopts + commitopts2 + similarityopts,
3347 _('[OPTION]... PATCH...'),
3347 _('[OPTION]... PATCH...'),
3348 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3348 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3349 def import_(ui, repo, patch1=None, *patches, **opts):
3349 def import_(ui, repo, patch1=None, *patches, **opts):
3350 """import an ordered set of patches
3350 """import an ordered set of patches
3351
3351
3352 Import a list of patches and commit them individually (unless
3352 Import a list of patches and commit them individually (unless
3353 --no-commit is specified).
3353 --no-commit is specified).
3354
3354
3355 To read a patch from standard input (stdin), use "-" as the patch
3355 To read a patch from standard input (stdin), use "-" as the patch
3356 name. If a URL is specified, the patch will be downloaded from
3356 name. If a URL is specified, the patch will be downloaded from
3357 there.
3357 there.
3358
3358
3359 Import first applies changes to the working directory (unless
3359 Import first applies changes to the working directory (unless
3360 --bypass is specified), import will abort if there are outstanding
3360 --bypass is specified), import will abort if there are outstanding
3361 changes.
3361 changes.
3362
3362
3363 Use --bypass to apply and commit patches directly to the
3363 Use --bypass to apply and commit patches directly to the
3364 repository, without affecting the working directory. Without
3364 repository, without affecting the working directory. Without
3365 --exact, patches will be applied on top of the working directory
3365 --exact, patches will be applied on top of the working directory
3366 parent revision.
3366 parent revision.
3367
3367
3368 You can import a patch straight from a mail message. Even patches
3368 You can import a patch straight from a mail message. Even patches
3369 as attachments work (to use the body part, it must have type
3369 as attachments work (to use the body part, it must have type
3370 text/plain or text/x-patch). From and Subject headers of email
3370 text/plain or text/x-patch). From and Subject headers of email
3371 message are used as default committer and commit message. All
3371 message are used as default committer and commit message. All
3372 text/plain body parts before first diff are added to the commit
3372 text/plain body parts before first diff are added to the commit
3373 message.
3373 message.
3374
3374
3375 If the imported patch was generated by :hg:`export`, user and
3375 If the imported patch was generated by :hg:`export`, user and
3376 description from patch override values from message headers and
3376 description from patch override values from message headers and
3377 body. Values given on command line with -m/--message and -u/--user
3377 body. Values given on command line with -m/--message and -u/--user
3378 override these.
3378 override these.
3379
3379
3380 If --exact is specified, import will set the working directory to
3380 If --exact is specified, import will set the working directory to
3381 the parent of each patch before applying it, and will abort if the
3381 the parent of each patch before applying it, and will abort if the
3382 resulting changeset has a different ID than the one recorded in
3382 resulting changeset has a different ID than the one recorded in
3383 the patch. This will guard against various ways that portable
3383 the patch. This will guard against various ways that portable
3384 patch formats and mail systems might fail to transfer Mercurial
3384 patch formats and mail systems might fail to transfer Mercurial
3385 data or metadata. See :hg:`bundle` for lossless transmission.
3385 data or metadata. See :hg:`bundle` for lossless transmission.
3386
3386
3387 Use --partial to ensure a changeset will be created from the patch
3387 Use --partial to ensure a changeset will be created from the patch
3388 even if some hunks fail to apply. Hunks that fail to apply will be
3388 even if some hunks fail to apply. Hunks that fail to apply will be
3389 written to a <target-file>.rej file. Conflicts can then be resolved
3389 written to a <target-file>.rej file. Conflicts can then be resolved
3390 by hand before :hg:`commit --amend` is run to update the created
3390 by hand before :hg:`commit --amend` is run to update the created
3391 changeset. This flag exists to let people import patches that
3391 changeset. This flag exists to let people import patches that
3392 partially apply without losing the associated metadata (author,
3392 partially apply without losing the associated metadata (author,
3393 date, description, ...).
3393 date, description, ...).
3394
3394
3395 .. note::
3395 .. note::
3396
3396
3397 When no hunks apply cleanly, :hg:`import --partial` will create
3397 When no hunks apply cleanly, :hg:`import --partial` will create
3398 an empty changeset, importing only the patch metadata.
3398 an empty changeset, importing only the patch metadata.
3399
3399
3400 With -s/--similarity, hg will attempt to discover renames and
3400 With -s/--similarity, hg will attempt to discover renames and
3401 copies in the patch in the same way as :hg:`addremove`.
3401 copies in the patch in the same way as :hg:`addremove`.
3402
3402
3403 It is possible to use external patch programs to perform the patch
3403 It is possible to use external patch programs to perform the patch
3404 by setting the ``ui.patch`` configuration option. For the default
3404 by setting the ``ui.patch`` configuration option. For the default
3405 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3405 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3406 See :hg:`help config` for more information about configuration
3406 See :hg:`help config` for more information about configuration
3407 files and how to use these options.
3407 files and how to use these options.
3408
3408
3409 See :hg:`help dates` for a list of formats valid for -d/--date.
3409 See :hg:`help dates` for a list of formats valid for -d/--date.
3410
3410
3411 .. container:: verbose
3411 .. container:: verbose
3412
3412
3413 Examples:
3413 Examples:
3414
3414
3415 - import a traditional patch from a website and detect renames::
3415 - import a traditional patch from a website and detect renames::
3416
3416
3417 hg import -s 80 http://example.com/bugfix.patch
3417 hg import -s 80 http://example.com/bugfix.patch
3418
3418
3419 - import a changeset from an hgweb server::
3419 - import a changeset from an hgweb server::
3420
3420
3421 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3421 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3422
3422
3423 - import all the patches in an Unix-style mbox::
3423 - import all the patches in an Unix-style mbox::
3424
3424
3425 hg import incoming-patches.mbox
3425 hg import incoming-patches.mbox
3426
3426
3427 - import patches from stdin::
3427 - import patches from stdin::
3428
3428
3429 hg import -
3429 hg import -
3430
3430
3431 - attempt to exactly restore an exported changeset (not always
3431 - attempt to exactly restore an exported changeset (not always
3432 possible)::
3432 possible)::
3433
3433
3434 hg import --exact proposed-fix.patch
3434 hg import --exact proposed-fix.patch
3435
3435
3436 - use an external tool to apply a patch which is too fuzzy for
3436 - use an external tool to apply a patch which is too fuzzy for
3437 the default internal tool.
3437 the default internal tool.
3438
3438
3439 hg import --config ui.patch="patch --merge" fuzzy.patch
3439 hg import --config ui.patch="patch --merge" fuzzy.patch
3440
3440
3441 - change the default fuzzing from 2 to a less strict 7
3441 - change the default fuzzing from 2 to a less strict 7
3442
3442
3443 hg import --config ui.fuzz=7 fuzz.patch
3443 hg import --config ui.fuzz=7 fuzz.patch
3444
3444
3445 Returns 0 on success, 1 on partial success (see --partial).
3445 Returns 0 on success, 1 on partial success (see --partial).
3446 """
3446 """
3447
3447
3448 opts = pycompat.byteskwargs(opts)
3448 opts = pycompat.byteskwargs(opts)
3449 if not patch1:
3449 if not patch1:
3450 raise error.Abort(_('need at least one patch to import'))
3450 raise error.Abort(_('need at least one patch to import'))
3451
3451
3452 patches = (patch1,) + patches
3452 patches = (patch1,) + patches
3453
3453
3454 date = opts.get('date')
3454 date = opts.get('date')
3455 if date:
3455 if date:
3456 opts['date'] = dateutil.parsedate(date)
3456 opts['date'] = dateutil.parsedate(date)
3457
3457
3458 exact = opts.get('exact')
3458 exact = opts.get('exact')
3459 update = not opts.get('bypass')
3459 update = not opts.get('bypass')
3460 if not update and opts.get('no_commit'):
3460 if not update and opts.get('no_commit'):
3461 raise error.Abort(_('cannot use --no-commit with --bypass'))
3461 raise error.Abort(_('cannot use --no-commit with --bypass'))
3462 try:
3462 try:
3463 sim = float(opts.get('similarity') or 0)
3463 sim = float(opts.get('similarity') or 0)
3464 except ValueError:
3464 except ValueError:
3465 raise error.Abort(_('similarity must be a number'))
3465 raise error.Abort(_('similarity must be a number'))
3466 if sim < 0 or sim > 100:
3466 if sim < 0 or sim > 100:
3467 raise error.Abort(_('similarity must be between 0 and 100'))
3467 raise error.Abort(_('similarity must be between 0 and 100'))
3468 if sim and not update:
3468 if sim and not update:
3469 raise error.Abort(_('cannot use --similarity with --bypass'))
3469 raise error.Abort(_('cannot use --similarity with --bypass'))
3470 if exact:
3470 if exact:
3471 if opts.get('edit'):
3471 if opts.get('edit'):
3472 raise error.Abort(_('cannot use --exact with --edit'))
3472 raise error.Abort(_('cannot use --exact with --edit'))
3473 if opts.get('prefix'):
3473 if opts.get('prefix'):
3474 raise error.Abort(_('cannot use --exact with --prefix'))
3474 raise error.Abort(_('cannot use --exact with --prefix'))
3475
3475
3476 base = opts["base"]
3476 base = opts["base"]
3477 msgs = []
3477 msgs = []
3478 ret = 0
3478 ret = 0
3479
3479
3480 with repo.wlock():
3480 with repo.wlock():
3481 if update:
3481 if update:
3482 cmdutil.checkunfinished(repo)
3482 cmdutil.checkunfinished(repo)
3483 if (exact or not opts.get('force')):
3483 if (exact or not opts.get('force')):
3484 cmdutil.bailifchanged(repo)
3484 cmdutil.bailifchanged(repo)
3485
3485
3486 if not opts.get('no_commit'):
3486 if not opts.get('no_commit'):
3487 lock = repo.lock
3487 lock = repo.lock
3488 tr = lambda: repo.transaction('import')
3488 tr = lambda: repo.transaction('import')
3489 dsguard = util.nullcontextmanager
3489 dsguard = util.nullcontextmanager
3490 else:
3490 else:
3491 lock = util.nullcontextmanager
3491 lock = util.nullcontextmanager
3492 tr = util.nullcontextmanager
3492 tr = util.nullcontextmanager
3493 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3493 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3494 with lock(), tr(), dsguard():
3494 with lock(), tr(), dsguard():
3495 parents = repo[None].parents()
3495 parents = repo[None].parents()
3496 for patchurl in patches:
3496 for patchurl in patches:
3497 if patchurl == '-':
3497 if patchurl == '-':
3498 ui.status(_('applying patch from stdin\n'))
3498 ui.status(_('applying patch from stdin\n'))
3499 patchfile = ui.fin
3499 patchfile = ui.fin
3500 patchurl = 'stdin' # for error message
3500 patchurl = 'stdin' # for error message
3501 else:
3501 else:
3502 patchurl = os.path.join(base, patchurl)
3502 patchurl = os.path.join(base, patchurl)
3503 ui.status(_('applying %s\n') % patchurl)
3503 ui.status(_('applying %s\n') % patchurl)
3504 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3504 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3505
3505
3506 haspatch = False
3506 haspatch = False
3507 for hunk in patch.split(patchfile):
3507 for hunk in patch.split(patchfile):
3508 with patch.extract(ui, hunk) as patchdata:
3508 with patch.extract(ui, hunk) as patchdata:
3509 msg, node, rej = cmdutil.tryimportone(ui, repo,
3509 msg, node, rej = cmdutil.tryimportone(ui, repo,
3510 patchdata,
3510 patchdata,
3511 parents, opts,
3511 parents, opts,
3512 msgs, hg.clean)
3512 msgs, hg.clean)
3513 if msg:
3513 if msg:
3514 haspatch = True
3514 haspatch = True
3515 ui.note(msg + '\n')
3515 ui.note(msg + '\n')
3516 if update or exact:
3516 if update or exact:
3517 parents = repo[None].parents()
3517 parents = repo[None].parents()
3518 else:
3518 else:
3519 parents = [repo[node]]
3519 parents = [repo[node]]
3520 if rej:
3520 if rej:
3521 ui.write_err(_("patch applied partially\n"))
3521 ui.write_err(_("patch applied partially\n"))
3522 ui.write_err(_("(fix the .rej files and run "
3522 ui.write_err(_("(fix the .rej files and run "
3523 "`hg commit --amend`)\n"))
3523 "`hg commit --amend`)\n"))
3524 ret = 1
3524 ret = 1
3525 break
3525 break
3526
3526
3527 if not haspatch:
3527 if not haspatch:
3528 raise error.Abort(_('%s: no diffs found') % patchurl)
3528 raise error.Abort(_('%s: no diffs found') % patchurl)
3529
3529
3530 if msgs:
3530 if msgs:
3531 repo.savecommitmessage('\n* * *\n'.join(msgs))
3531 repo.savecommitmessage('\n* * *\n'.join(msgs))
3532 return ret
3532 return ret
3533
3533
3534 @command('incoming|in',
3534 @command('incoming|in',
3535 [('f', 'force', None,
3535 [('f', 'force', None,
3536 _('run even if remote repository is unrelated')),
3536 _('run even if remote repository is unrelated')),
3537 ('n', 'newest-first', None, _('show newest record first')),
3537 ('n', 'newest-first', None, _('show newest record first')),
3538 ('', 'bundle', '',
3538 ('', 'bundle', '',
3539 _('file to store the bundles into'), _('FILE')),
3539 _('file to store the bundles into'), _('FILE')),
3540 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3540 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3541 ('B', 'bookmarks', False, _("compare bookmarks")),
3541 ('B', 'bookmarks', False, _("compare bookmarks")),
3542 ('b', 'branch', [],
3542 ('b', 'branch', [],
3543 _('a specific branch you would like to pull'), _('BRANCH')),
3543 _('a specific branch you would like to pull'), _('BRANCH')),
3544 ] + logopts + remoteopts + subrepoopts,
3544 ] + logopts + remoteopts + subrepoopts,
3545 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3545 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3546 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3546 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3547 def incoming(ui, repo, source="default", **opts):
3547 def incoming(ui, repo, source="default", **opts):
3548 """show new changesets found in source
3548 """show new changesets found in source
3549
3549
3550 Show new changesets found in the specified path/URL or the default
3550 Show new changesets found in the specified path/URL or the default
3551 pull location. These are the changesets that would have been pulled
3551 pull location. These are the changesets that would have been pulled
3552 by :hg:`pull` at the time you issued this command.
3552 by :hg:`pull` at the time you issued this command.
3553
3553
3554 See pull for valid source format details.
3554 See pull for valid source format details.
3555
3555
3556 .. container:: verbose
3556 .. container:: verbose
3557
3557
3558 With -B/--bookmarks, the result of bookmark comparison between
3558 With -B/--bookmarks, the result of bookmark comparison between
3559 local and remote repositories is displayed. With -v/--verbose,
3559 local and remote repositories is displayed. With -v/--verbose,
3560 status is also displayed for each bookmark like below::
3560 status is also displayed for each bookmark like below::
3561
3561
3562 BM1 01234567890a added
3562 BM1 01234567890a added
3563 BM2 1234567890ab advanced
3563 BM2 1234567890ab advanced
3564 BM3 234567890abc diverged
3564 BM3 234567890abc diverged
3565 BM4 34567890abcd changed
3565 BM4 34567890abcd changed
3566
3566
3567 The action taken locally when pulling depends on the
3567 The action taken locally when pulling depends on the
3568 status of each bookmark:
3568 status of each bookmark:
3569
3569
3570 :``added``: pull will create it
3570 :``added``: pull will create it
3571 :``advanced``: pull will update it
3571 :``advanced``: pull will update it
3572 :``diverged``: pull will create a divergent bookmark
3572 :``diverged``: pull will create a divergent bookmark
3573 :``changed``: result depends on remote changesets
3573 :``changed``: result depends on remote changesets
3574
3574
3575 From the point of view of pulling behavior, bookmark
3575 From the point of view of pulling behavior, bookmark
3576 existing only in the remote repository are treated as ``added``,
3576 existing only in the remote repository are treated as ``added``,
3577 even if it is in fact locally deleted.
3577 even if it is in fact locally deleted.
3578
3578
3579 .. container:: verbose
3579 .. container:: verbose
3580
3580
3581 For remote repository, using --bundle avoids downloading the
3581 For remote repository, using --bundle avoids downloading the
3582 changesets twice if the incoming is followed by a pull.
3582 changesets twice if the incoming is followed by a pull.
3583
3583
3584 Examples:
3584 Examples:
3585
3585
3586 - show incoming changes with patches and full description::
3586 - show incoming changes with patches and full description::
3587
3587
3588 hg incoming -vp
3588 hg incoming -vp
3589
3589
3590 - show incoming changes excluding merges, store a bundle::
3590 - show incoming changes excluding merges, store a bundle::
3591
3591
3592 hg in -vpM --bundle incoming.hg
3592 hg in -vpM --bundle incoming.hg
3593 hg pull incoming.hg
3593 hg pull incoming.hg
3594
3594
3595 - briefly list changes inside a bundle::
3595 - briefly list changes inside a bundle::
3596
3596
3597 hg in changes.hg -T "{desc|firstline}\\n"
3597 hg in changes.hg -T "{desc|firstline}\\n"
3598
3598
3599 Returns 0 if there are incoming changes, 1 otherwise.
3599 Returns 0 if there are incoming changes, 1 otherwise.
3600 """
3600 """
3601 opts = pycompat.byteskwargs(opts)
3601 opts = pycompat.byteskwargs(opts)
3602 if opts.get('graph'):
3602 if opts.get('graph'):
3603 logcmdutil.checkunsupportedgraphflags([], opts)
3603 logcmdutil.checkunsupportedgraphflags([], opts)
3604 def display(other, chlist, displayer):
3604 def display(other, chlist, displayer):
3605 revdag = logcmdutil.graphrevs(other, chlist, opts)
3605 revdag = logcmdutil.graphrevs(other, chlist, opts)
3606 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3606 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3607 graphmod.asciiedges)
3607 graphmod.asciiedges)
3608
3608
3609 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3609 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3610 return 0
3610 return 0
3611
3611
3612 if opts.get('bundle') and opts.get('subrepos'):
3612 if opts.get('bundle') and opts.get('subrepos'):
3613 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3613 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3614
3614
3615 if opts.get('bookmarks'):
3615 if opts.get('bookmarks'):
3616 source, branches = hg.parseurl(ui.expandpath(source),
3616 source, branches = hg.parseurl(ui.expandpath(source),
3617 opts.get('branch'))
3617 opts.get('branch'))
3618 other = hg.peer(repo, opts, source)
3618 other = hg.peer(repo, opts, source)
3619 if 'bookmarks' not in other.listkeys('namespaces'):
3619 if 'bookmarks' not in other.listkeys('namespaces'):
3620 ui.warn(_("remote doesn't support bookmarks\n"))
3620 ui.warn(_("remote doesn't support bookmarks\n"))
3621 return 0
3621 return 0
3622 ui.pager('incoming')
3622 ui.pager('incoming')
3623 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3623 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3624 return bookmarks.incoming(ui, repo, other)
3624 return bookmarks.incoming(ui, repo, other)
3625
3625
3626 repo._subtoppath = ui.expandpath(source)
3626 repo._subtoppath = ui.expandpath(source)
3627 try:
3627 try:
3628 return hg.incoming(ui, repo, source, opts)
3628 return hg.incoming(ui, repo, source, opts)
3629 finally:
3629 finally:
3630 del repo._subtoppath
3630 del repo._subtoppath
3631
3631
3632
3632
3633 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3633 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3634 helpcategory=command.CATEGORY_REPO_CREATION,
3634 helpcategory=command.CATEGORY_REPO_CREATION,
3635 helpbasic=True, norepo=True)
3635 helpbasic=True, norepo=True)
3636 def init(ui, dest=".", **opts):
3636 def init(ui, dest=".", **opts):
3637 """create a new repository in the given directory
3637 """create a new repository in the given directory
3638
3638
3639 Initialize a new repository in the given directory. If the given
3639 Initialize a new repository in the given directory. If the given
3640 directory does not exist, it will be created.
3640 directory does not exist, it will be created.
3641
3641
3642 If no directory is given, the current directory is used.
3642 If no directory is given, the current directory is used.
3643
3643
3644 It is possible to specify an ``ssh://`` URL as the destination.
3644 It is possible to specify an ``ssh://`` URL as the destination.
3645 See :hg:`help urls` for more information.
3645 See :hg:`help urls` for more information.
3646
3646
3647 Returns 0 on success.
3647 Returns 0 on success.
3648 """
3648 """
3649 opts = pycompat.byteskwargs(opts)
3649 opts = pycompat.byteskwargs(opts)
3650 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3650 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3651
3651
3652 @command('locate',
3652 @command('locate',
3653 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3653 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3654 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3654 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3655 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3655 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3656 ] + walkopts,
3656 ] + walkopts,
3657 _('[OPTION]... [PATTERN]...'),
3657 _('[OPTION]... [PATTERN]...'),
3658 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3658 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3659 def locate(ui, repo, *pats, **opts):
3659 def locate(ui, repo, *pats, **opts):
3660 """locate files matching specific patterns (DEPRECATED)
3660 """locate files matching specific patterns (DEPRECATED)
3661
3661
3662 Print files under Mercurial control in the working directory whose
3662 Print files under Mercurial control in the working directory whose
3663 names match the given patterns.
3663 names match the given patterns.
3664
3664
3665 By default, this command searches all directories in the working
3665 By default, this command searches all directories in the working
3666 directory. To search just the current directory and its
3666 directory. To search just the current directory and its
3667 subdirectories, use "--include .".
3667 subdirectories, use "--include .".
3668
3668
3669 If no patterns are given to match, this command prints the names
3669 If no patterns are given to match, this command prints the names
3670 of all files under Mercurial control in the working directory.
3670 of all files under Mercurial control in the working directory.
3671
3671
3672 If you want to feed the output of this command into the "xargs"
3672 If you want to feed the output of this command into the "xargs"
3673 command, use the -0 option to both this command and "xargs". This
3673 command, use the -0 option to both this command and "xargs". This
3674 will avoid the problem of "xargs" treating single filenames that
3674 will avoid the problem of "xargs" treating single filenames that
3675 contain whitespace as multiple filenames.
3675 contain whitespace as multiple filenames.
3676
3676
3677 See :hg:`help files` for a more versatile command.
3677 See :hg:`help files` for a more versatile command.
3678
3678
3679 Returns 0 if a match is found, 1 otherwise.
3679 Returns 0 if a match is found, 1 otherwise.
3680 """
3680 """
3681 opts = pycompat.byteskwargs(opts)
3681 opts = pycompat.byteskwargs(opts)
3682 if opts.get('print0'):
3682 if opts.get('print0'):
3683 end = '\0'
3683 end = '\0'
3684 else:
3684 else:
3685 end = '\n'
3685 end = '\n'
3686 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3686 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3687
3687
3688 ret = 1
3688 ret = 1
3689 m = scmutil.match(ctx, pats, opts, default='relglob',
3689 m = scmutil.match(ctx, pats, opts, default='relglob',
3690 badfn=lambda x, y: False)
3690 badfn=lambda x, y: False)
3691
3691
3692 ui.pager('locate')
3692 ui.pager('locate')
3693 if ctx.rev() is None:
3693 if ctx.rev() is None:
3694 # When run on the working copy, "locate" includes removed files, so
3694 # When run on the working copy, "locate" includes removed files, so
3695 # we get the list of files from the dirstate.
3695 # we get the list of files from the dirstate.
3696 filesgen = sorted(repo.dirstate.matches(m))
3696 filesgen = sorted(repo.dirstate.matches(m))
3697 else:
3697 else:
3698 filesgen = ctx.matches(m)
3698 filesgen = ctx.matches(m)
3699 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3699 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3700 for abs in filesgen:
3700 for abs in filesgen:
3701 if opts.get('fullpath'):
3701 if opts.get('fullpath'):
3702 ui.write(repo.wjoin(abs), end)
3702 ui.write(repo.wjoin(abs), end)
3703 else:
3703 else:
3704 ui.write(uipathfn(abs), end)
3704 ui.write(uipathfn(abs), end)
3705 ret = 0
3705 ret = 0
3706
3706
3707 return ret
3707 return ret
3708
3708
3709 @command('log|history',
3709 @command('log|history',
3710 [('f', 'follow', None,
3710 [('f', 'follow', None,
3711 _('follow changeset history, or file history across copies and renames')),
3711 _('follow changeset history, or file history across copies and renames')),
3712 ('', 'follow-first', None,
3712 ('', 'follow-first', None,
3713 _('only follow the first parent of merge changesets (DEPRECATED)')),
3713 _('only follow the first parent of merge changesets (DEPRECATED)')),
3714 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3714 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3715 ('C', 'copies', None, _('show copied files')),
3715 ('C', 'copies', None, _('show copied files')),
3716 ('k', 'keyword', [],
3716 ('k', 'keyword', [],
3717 _('do case-insensitive search for a given text'), _('TEXT')),
3717 _('do case-insensitive search for a given text'), _('TEXT')),
3718 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3718 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3719 ('L', 'line-range', [],
3719 ('L', 'line-range', [],
3720 _('follow line range of specified file (EXPERIMENTAL)'),
3720 _('follow line range of specified file (EXPERIMENTAL)'),
3721 _('FILE,RANGE')),
3721 _('FILE,RANGE')),
3722 ('', 'removed', None, _('include revisions where files were removed')),
3722 ('', 'removed', None, _('include revisions where files were removed')),
3723 ('m', 'only-merges', None,
3723 ('m', 'only-merges', None,
3724 _('show only merges (DEPRECATED) (use -r "merge()" instead)')),
3724 _('show only merges (DEPRECATED) (use -r "merge()" instead)')),
3725 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3725 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3726 ('', 'only-branch', [],
3726 ('', 'only-branch', [],
3727 _('show only changesets within the given named branch (DEPRECATED)'),
3727 _('show only changesets within the given named branch (DEPRECATED)'),
3728 _('BRANCH')),
3728 _('BRANCH')),
3729 ('b', 'branch', [],
3729 ('b', 'branch', [],
3730 _('show changesets within the given named branch'), _('BRANCH')),
3730 _('show changesets within the given named branch'), _('BRANCH')),
3731 ('P', 'prune', [],
3731 ('P', 'prune', [],
3732 _('do not display revision or any of its ancestors'), _('REV')),
3732 _('do not display revision or any of its ancestors'), _('REV')),
3733 ] + logopts + walkopts,
3733 ] + logopts + walkopts,
3734 _('[OPTION]... [FILE]'),
3734 _('[OPTION]... [FILE]'),
3735 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3735 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3736 helpbasic=True, inferrepo=True,
3736 helpbasic=True, inferrepo=True,
3737 intents={INTENT_READONLY})
3737 intents={INTENT_READONLY})
3738 def log(ui, repo, *pats, **opts):
3738 def log(ui, repo, *pats, **opts):
3739 """show revision history of entire repository or files
3739 """show revision history of entire repository or files
3740
3740
3741 Print the revision history of the specified files or the entire
3741 Print the revision history of the specified files or the entire
3742 project.
3742 project.
3743
3743
3744 If no revision range is specified, the default is ``tip:0`` unless
3744 If no revision range is specified, the default is ``tip:0`` unless
3745 --follow is set, in which case the working directory parent is
3745 --follow is set, in which case the working directory parent is
3746 used as the starting revision.
3746 used as the starting revision.
3747
3747
3748 File history is shown without following rename or copy history of
3748 File history is shown without following rename or copy history of
3749 files. Use -f/--follow with a filename to follow history across
3749 files. Use -f/--follow with a filename to follow history across
3750 renames and copies. --follow without a filename will only show
3750 renames and copies. --follow without a filename will only show
3751 ancestors of the starting revision.
3751 ancestors of the starting revision.
3752
3752
3753 By default this command prints revision number and changeset id,
3753 By default this command prints revision number and changeset id,
3754 tags, non-trivial parents, user, date and time, and a summary for
3754 tags, non-trivial parents, user, date and time, and a summary for
3755 each commit. When the -v/--verbose switch is used, the list of
3755 each commit. When the -v/--verbose switch is used, the list of
3756 changed files and full commit message are shown.
3756 changed files and full commit message are shown.
3757
3757
3758 With --graph the revisions are shown as an ASCII art DAG with the most
3758 With --graph the revisions are shown as an ASCII art DAG with the most
3759 recent changeset at the top.
3759 recent changeset at the top.
3760 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3760 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3761 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3761 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3762 changeset from the lines below is a parent of the 'o' merge on the same
3762 changeset from the lines below is a parent of the 'o' merge on the same
3763 line.
3763 line.
3764 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3764 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3765 of a '|' indicates one or more revisions in a path are omitted.
3765 of a '|' indicates one or more revisions in a path are omitted.
3766
3766
3767 .. container:: verbose
3767 .. container:: verbose
3768
3768
3769 Use -L/--line-range FILE,M:N options to follow the history of lines
3769 Use -L/--line-range FILE,M:N options to follow the history of lines
3770 from M to N in FILE. With -p/--patch only diff hunks affecting
3770 from M to N in FILE. With -p/--patch only diff hunks affecting
3771 specified line range will be shown. This option requires --follow;
3771 specified line range will be shown. This option requires --follow;
3772 it can be specified multiple times. Currently, this option is not
3772 it can be specified multiple times. Currently, this option is not
3773 compatible with --graph. This option is experimental.
3773 compatible with --graph. This option is experimental.
3774
3774
3775 .. note::
3775 .. note::
3776
3776
3777 :hg:`log --patch` may generate unexpected diff output for merge
3777 :hg:`log --patch` may generate unexpected diff output for merge
3778 changesets, as it will only compare the merge changeset against
3778 changesets, as it will only compare the merge changeset against
3779 its first parent. Also, only files different from BOTH parents
3779 its first parent. Also, only files different from BOTH parents
3780 will appear in files:.
3780 will appear in files:.
3781
3781
3782 .. note::
3782 .. note::
3783
3783
3784 For performance reasons, :hg:`log FILE` may omit duplicate changes
3784 For performance reasons, :hg:`log FILE` may omit duplicate changes
3785 made on branches and will not show removals or mode changes. To
3785 made on branches and will not show removals or mode changes. To
3786 see all such changes, use the --removed switch.
3786 see all such changes, use the --removed switch.
3787
3787
3788 .. container:: verbose
3788 .. container:: verbose
3789
3789
3790 .. note::
3790 .. note::
3791
3791
3792 The history resulting from -L/--line-range options depends on diff
3792 The history resulting from -L/--line-range options depends on diff
3793 options; for instance if white-spaces are ignored, respective changes
3793 options; for instance if white-spaces are ignored, respective changes
3794 with only white-spaces in specified line range will not be listed.
3794 with only white-spaces in specified line range will not be listed.
3795
3795
3796 .. container:: verbose
3796 .. container:: verbose
3797
3797
3798 Some examples:
3798 Some examples:
3799
3799
3800 - changesets with full descriptions and file lists::
3800 - changesets with full descriptions and file lists::
3801
3801
3802 hg log -v
3802 hg log -v
3803
3803
3804 - changesets ancestral to the working directory::
3804 - changesets ancestral to the working directory::
3805
3805
3806 hg log -f
3806 hg log -f
3807
3807
3808 - last 10 commits on the current branch::
3808 - last 10 commits on the current branch::
3809
3809
3810 hg log -l 10 -b .
3810 hg log -l 10 -b .
3811
3811
3812 - changesets showing all modifications of a file, including removals::
3812 - changesets showing all modifications of a file, including removals::
3813
3813
3814 hg log --removed file.c
3814 hg log --removed file.c
3815
3815
3816 - all changesets that touch a directory, with diffs, excluding merges::
3816 - all changesets that touch a directory, with diffs, excluding merges::
3817
3817
3818 hg log -Mp lib/
3818 hg log -Mp lib/
3819
3819
3820 - all revision numbers that match a keyword::
3820 - all revision numbers that match a keyword::
3821
3821
3822 hg log -k bug --template "{rev}\\n"
3822 hg log -k bug --template "{rev}\\n"
3823
3823
3824 - the full hash identifier of the working directory parent::
3824 - the full hash identifier of the working directory parent::
3825
3825
3826 hg log -r . --template "{node}\\n"
3826 hg log -r . --template "{node}\\n"
3827
3827
3828 - list available log templates::
3828 - list available log templates::
3829
3829
3830 hg log -T list
3830 hg log -T list
3831
3831
3832 - check if a given changeset is included in a tagged release::
3832 - check if a given changeset is included in a tagged release::
3833
3833
3834 hg log -r "a21ccf and ancestor(1.9)"
3834 hg log -r "a21ccf and ancestor(1.9)"
3835
3835
3836 - find all changesets by some user in a date range::
3836 - find all changesets by some user in a date range::
3837
3837
3838 hg log -k alice -d "may 2008 to jul 2008"
3838 hg log -k alice -d "may 2008 to jul 2008"
3839
3839
3840 - summary of all changesets after the last tag::
3840 - summary of all changesets after the last tag::
3841
3841
3842 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3842 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3843
3843
3844 - changesets touching lines 13 to 23 for file.c::
3844 - changesets touching lines 13 to 23 for file.c::
3845
3845
3846 hg log -L file.c,13:23
3846 hg log -L file.c,13:23
3847
3847
3848 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3848 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3849 main.c with patch::
3849 main.c with patch::
3850
3850
3851 hg log -L file.c,13:23 -L main.c,2:6 -p
3851 hg log -L file.c,13:23 -L main.c,2:6 -p
3852
3852
3853 See :hg:`help dates` for a list of formats valid for -d/--date.
3853 See :hg:`help dates` for a list of formats valid for -d/--date.
3854
3854
3855 See :hg:`help revisions` for more about specifying and ordering
3855 See :hg:`help revisions` for more about specifying and ordering
3856 revisions.
3856 revisions.
3857
3857
3858 See :hg:`help templates` for more about pre-packaged styles and
3858 See :hg:`help templates` for more about pre-packaged styles and
3859 specifying custom templates. The default template used by the log
3859 specifying custom templates. The default template used by the log
3860 command can be customized via the ``ui.logtemplate`` configuration
3860 command can be customized via the ``ui.logtemplate`` configuration
3861 setting.
3861 setting.
3862
3862
3863 Returns 0 on success.
3863 Returns 0 on success.
3864
3864
3865 """
3865 """
3866 opts = pycompat.byteskwargs(opts)
3866 opts = pycompat.byteskwargs(opts)
3867 linerange = opts.get('line_range')
3867 linerange = opts.get('line_range')
3868
3868
3869 if linerange and not opts.get('follow'):
3869 if linerange and not opts.get('follow'):
3870 raise error.Abort(_('--line-range requires --follow'))
3870 raise error.Abort(_('--line-range requires --follow'))
3871
3871
3872 if linerange and pats:
3872 if linerange and pats:
3873 # TODO: take pats as patterns with no line-range filter
3873 # TODO: take pats as patterns with no line-range filter
3874 raise error.Abort(
3874 raise error.Abort(
3875 _('FILE arguments are not compatible with --line-range option')
3875 _('FILE arguments are not compatible with --line-range option')
3876 )
3876 )
3877
3877
3878 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3878 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3879 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3879 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3880 if linerange:
3880 if linerange:
3881 # TODO: should follow file history from logcmdutil._initialrevs(),
3881 # TODO: should follow file history from logcmdutil._initialrevs(),
3882 # then filter the result by logcmdutil._makerevset() and --limit
3882 # then filter the result by logcmdutil._makerevset() and --limit
3883 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3883 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3884
3884
3885 getcopies = None
3885 getcopies = None
3886 if opts.get('copies'):
3886 if opts.get('copies'):
3887 endrev = None
3887 endrev = None
3888 if revs:
3888 if revs:
3889 endrev = revs.max() + 1
3889 endrev = revs.max() + 1
3890 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
3890 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
3891
3891
3892 ui.pager('log')
3892 ui.pager('log')
3893 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3893 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3894 buffered=True)
3894 buffered=True)
3895 if opts.get('graph'):
3895 if opts.get('graph'):
3896 displayfn = logcmdutil.displaygraphrevs
3896 displayfn = logcmdutil.displaygraphrevs
3897 else:
3897 else:
3898 displayfn = logcmdutil.displayrevs
3898 displayfn = logcmdutil.displayrevs
3899 displayfn(ui, repo, revs, displayer, getcopies)
3899 displayfn(ui, repo, revs, displayer, getcopies)
3900
3900
3901 @command('manifest',
3901 @command('manifest',
3902 [('r', 'rev', '', _('revision to display'), _('REV')),
3902 [('r', 'rev', '', _('revision to display'), _('REV')),
3903 ('', 'all', False, _("list files from all revisions"))]
3903 ('', 'all', False, _("list files from all revisions"))]
3904 + formatteropts,
3904 + formatteropts,
3905 _('[-r REV]'),
3905 _('[-r REV]'),
3906 helpcategory=command.CATEGORY_MAINTENANCE,
3906 helpcategory=command.CATEGORY_MAINTENANCE,
3907 intents={INTENT_READONLY})
3907 intents={INTENT_READONLY})
3908 def manifest(ui, repo, node=None, rev=None, **opts):
3908 def manifest(ui, repo, node=None, rev=None, **opts):
3909 """output the current or given revision of the project manifest
3909 """output the current or given revision of the project manifest
3910
3910
3911 Print a list of version controlled files for the given revision.
3911 Print a list of version controlled files for the given revision.
3912 If no revision is given, the first parent of the working directory
3912 If no revision is given, the first parent of the working directory
3913 is used, or the null revision if no revision is checked out.
3913 is used, or the null revision if no revision is checked out.
3914
3914
3915 With -v, print file permissions, symlink and executable bits.
3915 With -v, print file permissions, symlink and executable bits.
3916 With --debug, print file revision hashes.
3916 With --debug, print file revision hashes.
3917
3917
3918 If option --all is specified, the list of all files from all revisions
3918 If option --all is specified, the list of all files from all revisions
3919 is printed. This includes deleted and renamed files.
3919 is printed. This includes deleted and renamed files.
3920
3920
3921 Returns 0 on success.
3921 Returns 0 on success.
3922 """
3922 """
3923 opts = pycompat.byteskwargs(opts)
3923 opts = pycompat.byteskwargs(opts)
3924 fm = ui.formatter('manifest', opts)
3924 fm = ui.formatter('manifest', opts)
3925
3925
3926 if opts.get('all'):
3926 if opts.get('all'):
3927 if rev or node:
3927 if rev or node:
3928 raise error.Abort(_("can't specify a revision with --all"))
3928 raise error.Abort(_("can't specify a revision with --all"))
3929
3929
3930 res = set()
3930 res = set()
3931 for rev in repo:
3931 for rev in repo:
3932 ctx = repo[rev]
3932 ctx = repo[rev]
3933 res |= set(ctx.files())
3933 res |= set(ctx.files())
3934
3934
3935 ui.pager('manifest')
3935 ui.pager('manifest')
3936 for f in sorted(res):
3936 for f in sorted(res):
3937 fm.startitem()
3937 fm.startitem()
3938 fm.write("path", '%s\n', f)
3938 fm.write("path", '%s\n', f)
3939 fm.end()
3939 fm.end()
3940 return
3940 return
3941
3941
3942 if rev and node:
3942 if rev and node:
3943 raise error.Abort(_("please specify just one revision"))
3943 raise error.Abort(_("please specify just one revision"))
3944
3944
3945 if not node:
3945 if not node:
3946 node = rev
3946 node = rev
3947
3947
3948 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3948 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3949 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3949 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3950 if node:
3950 if node:
3951 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3951 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3952 ctx = scmutil.revsingle(repo, node)
3952 ctx = scmutil.revsingle(repo, node)
3953 mf = ctx.manifest()
3953 mf = ctx.manifest()
3954 ui.pager('manifest')
3954 ui.pager('manifest')
3955 for f in ctx:
3955 for f in ctx:
3956 fm.startitem()
3956 fm.startitem()
3957 fm.context(ctx=ctx)
3957 fm.context(ctx=ctx)
3958 fl = ctx[f].flags()
3958 fl = ctx[f].flags()
3959 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3959 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3960 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3960 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3961 fm.write('path', '%s\n', f)
3961 fm.write('path', '%s\n', f)
3962 fm.end()
3962 fm.end()
3963
3963
3964 @command('merge',
3964 @command('merge',
3965 [('f', 'force', None,
3965 [('f', 'force', None,
3966 _('force a merge including outstanding changes (DEPRECATED)')),
3966 _('force a merge including outstanding changes (DEPRECATED)')),
3967 ('r', 'rev', '', _('revision to merge'), _('REV')),
3967 ('r', 'rev', '', _('revision to merge'), _('REV')),
3968 ('P', 'preview', None,
3968 ('P', 'preview', None,
3969 _('review revisions to merge (no merge is performed)')),
3969 _('review revisions to merge (no merge is performed)')),
3970 ('', 'abort', None, _('abort the ongoing merge')),
3970 ('', 'abort', None, _('abort the ongoing merge')),
3971 ] + mergetoolopts,
3971 ] + mergetoolopts,
3972 _('[-P] [[-r] REV]'),
3972 _('[-P] [[-r] REV]'),
3973 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3973 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3974 def merge(ui, repo, node=None, **opts):
3974 def merge(ui, repo, node=None, **opts):
3975 """merge another revision into working directory
3975 """merge another revision into working directory
3976
3976
3977 The current working directory is updated with all changes made in
3977 The current working directory is updated with all changes made in
3978 the requested revision since the last common predecessor revision.
3978 the requested revision since the last common predecessor revision.
3979
3979
3980 Files that changed between either parent are marked as changed for
3980 Files that changed between either parent are marked as changed for
3981 the next commit and a commit must be performed before any further
3981 the next commit and a commit must be performed before any further
3982 updates to the repository are allowed. The next commit will have
3982 updates to the repository are allowed. The next commit will have
3983 two parents.
3983 two parents.
3984
3984
3985 ``--tool`` can be used to specify the merge tool used for file
3985 ``--tool`` can be used to specify the merge tool used for file
3986 merges. It overrides the HGMERGE environment variable and your
3986 merges. It overrides the HGMERGE environment variable and your
3987 configuration files. See :hg:`help merge-tools` for options.
3987 configuration files. See :hg:`help merge-tools` for options.
3988
3988
3989 If no revision is specified, the working directory's parent is a
3989 If no revision is specified, the working directory's parent is a
3990 head revision, and the current branch contains exactly one other
3990 head revision, and the current branch contains exactly one other
3991 head, the other head is merged with by default. Otherwise, an
3991 head, the other head is merged with by default. Otherwise, an
3992 explicit revision with which to merge must be provided.
3992 explicit revision with which to merge must be provided.
3993
3993
3994 See :hg:`help resolve` for information on handling file conflicts.
3994 See :hg:`help resolve` for information on handling file conflicts.
3995
3995
3996 To undo an uncommitted merge, use :hg:`merge --abort` which
3996 To undo an uncommitted merge, use :hg:`merge --abort` which
3997 will check out a clean copy of the original merge parent, losing
3997 will check out a clean copy of the original merge parent, losing
3998 all changes.
3998 all changes.
3999
3999
4000 Returns 0 on success, 1 if there are unresolved files.
4000 Returns 0 on success, 1 if there are unresolved files.
4001 """
4001 """
4002
4002
4003 opts = pycompat.byteskwargs(opts)
4003 opts = pycompat.byteskwargs(opts)
4004 abort = opts.get('abort')
4004 abort = opts.get('abort')
4005 if abort and repo.dirstate.p2() == nullid:
4005 if abort and repo.dirstate.p2() == nullid:
4006 cmdutil.wrongtooltocontinue(repo, _('merge'))
4006 cmdutil.wrongtooltocontinue(repo, _('merge'))
4007 if abort:
4007 if abort:
4008 state = cmdutil.getunfinishedstate(repo)
4008 state = cmdutil.getunfinishedstate(repo)
4009 if state and state._opname != 'merge':
4009 if state and state._opname != 'merge':
4010 raise error.Abort(_('cannot abort merge with %s in progress') %
4010 raise error.Abort(_('cannot abort merge with %s in progress') %
4011 (state._opname), hint=state.hint())
4011 (state._opname), hint=state.hint())
4012 if node:
4012 if node:
4013 raise error.Abort(_("cannot specify a node with --abort"))
4013 raise error.Abort(_("cannot specify a node with --abort"))
4014 if opts.get('rev'):
4014 if opts.get('rev'):
4015 raise error.Abort(_("cannot specify both --rev and --abort"))
4015 raise error.Abort(_("cannot specify both --rev and --abort"))
4016 if opts.get('preview'):
4016 if opts.get('preview'):
4017 raise error.Abort(_("cannot specify --preview with --abort"))
4017 raise error.Abort(_("cannot specify --preview with --abort"))
4018 if opts.get('rev') and node:
4018 if opts.get('rev') and node:
4019 raise error.Abort(_("please specify just one revision"))
4019 raise error.Abort(_("please specify just one revision"))
4020 if not node:
4020 if not node:
4021 node = opts.get('rev')
4021 node = opts.get('rev')
4022
4022
4023 if node:
4023 if node:
4024 node = scmutil.revsingle(repo, node).node()
4024 node = scmutil.revsingle(repo, node).node()
4025
4025
4026 if not node and not abort:
4026 if not node and not abort:
4027 node = repo[destutil.destmerge(repo)].node()
4027 node = repo[destutil.destmerge(repo)].node()
4028
4028
4029 if opts.get('preview'):
4029 if opts.get('preview'):
4030 # find nodes that are ancestors of p2 but not of p1
4030 # find nodes that are ancestors of p2 but not of p1
4031 p1 = repo.lookup('.')
4031 p1 = repo.lookup('.')
4032 p2 = node
4032 p2 = node
4033 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4033 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4034
4034
4035 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4035 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4036 for node in nodes:
4036 for node in nodes:
4037 displayer.show(repo[node])
4037 displayer.show(repo[node])
4038 displayer.close()
4038 displayer.close()
4039 return 0
4039 return 0
4040
4040
4041 # ui.forcemerge is an internal variable, do not document
4041 # ui.forcemerge is an internal variable, do not document
4042 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4042 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4043 with ui.configoverride(overrides, 'merge'):
4043 with ui.configoverride(overrides, 'merge'):
4044 force = opts.get('force')
4044 force = opts.get('force')
4045 labels = ['working copy', 'merge rev']
4045 labels = ['working copy', 'merge rev']
4046 return hg.merge(repo, node, force=force, mergeforce=force,
4046 return hg.merge(repo, node, force=force, mergeforce=force,
4047 labels=labels, abort=abort)
4047 labels=labels, abort=abort)
4048
4048
4049 statemod.addunfinished(
4049 statemod.addunfinished(
4050 'merge', fname=None, clearable=True, allowcommit=True,
4050 'merge', fname=None, clearable=True, allowcommit=True,
4051 cmdmsg=_('outstanding uncommitted merge'), abortfunc=hg.abortmerge,
4051 cmdmsg=_('outstanding uncommitted merge'), abortfunc=hg.abortmerge,
4052 statushint=_('To continue: hg commit\n'
4052 statushint=_('To continue: hg commit\n'
4053 'To abort: hg merge --abort'),
4053 'To abort: hg merge --abort'),
4054 cmdhint=_("use 'hg commit' or 'hg merge --abort'")
4054 cmdhint=_("use 'hg commit' or 'hg merge --abort'")
4055 )
4055 )
4056
4056
4057 @command('outgoing|out',
4057 @command('outgoing|out',
4058 [('f', 'force', None, _('run even when the destination is unrelated')),
4058 [('f', 'force', None, _('run even when the destination is unrelated')),
4059 ('r', 'rev', [],
4059 ('r', 'rev', [],
4060 _('a changeset intended to be included in the destination'), _('REV')),
4060 _('a changeset intended to be included in the destination'), _('REV')),
4061 ('n', 'newest-first', None, _('show newest record first')),
4061 ('n', 'newest-first', None, _('show newest record first')),
4062 ('B', 'bookmarks', False, _('compare bookmarks')),
4062 ('B', 'bookmarks', False, _('compare bookmarks')),
4063 ('b', 'branch', [], _('a specific branch you would like to push'),
4063 ('b', 'branch', [], _('a specific branch you would like to push'),
4064 _('BRANCH')),
4064 _('BRANCH')),
4065 ] + logopts + remoteopts + subrepoopts,
4065 ] + logopts + remoteopts + subrepoopts,
4066 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4066 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4067 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4067 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4068 def outgoing(ui, repo, dest=None, **opts):
4068 def outgoing(ui, repo, dest=None, **opts):
4069 """show changesets not found in the destination
4069 """show changesets not found in the destination
4070
4070
4071 Show changesets not found in the specified destination repository
4071 Show changesets not found in the specified destination repository
4072 or the default push location. These are the changesets that would
4072 or the default push location. These are the changesets that would
4073 be pushed if a push was requested.
4073 be pushed if a push was requested.
4074
4074
4075 See pull for details of valid destination formats.
4075 See pull for details of valid destination formats.
4076
4076
4077 .. container:: verbose
4077 .. container:: verbose
4078
4078
4079 With -B/--bookmarks, the result of bookmark comparison between
4079 With -B/--bookmarks, the result of bookmark comparison between
4080 local and remote repositories is displayed. With -v/--verbose,
4080 local and remote repositories is displayed. With -v/--verbose,
4081 status is also displayed for each bookmark like below::
4081 status is also displayed for each bookmark like below::
4082
4082
4083 BM1 01234567890a added
4083 BM1 01234567890a added
4084 BM2 deleted
4084 BM2 deleted
4085 BM3 234567890abc advanced
4085 BM3 234567890abc advanced
4086 BM4 34567890abcd diverged
4086 BM4 34567890abcd diverged
4087 BM5 4567890abcde changed
4087 BM5 4567890abcde changed
4088
4088
4089 The action taken when pushing depends on the
4089 The action taken when pushing depends on the
4090 status of each bookmark:
4090 status of each bookmark:
4091
4091
4092 :``added``: push with ``-B`` will create it
4092 :``added``: push with ``-B`` will create it
4093 :``deleted``: push with ``-B`` will delete it
4093 :``deleted``: push with ``-B`` will delete it
4094 :``advanced``: push will update it
4094 :``advanced``: push will update it
4095 :``diverged``: push with ``-B`` will update it
4095 :``diverged``: push with ``-B`` will update it
4096 :``changed``: push with ``-B`` will update it
4096 :``changed``: push with ``-B`` will update it
4097
4097
4098 From the point of view of pushing behavior, bookmarks
4098 From the point of view of pushing behavior, bookmarks
4099 existing only in the remote repository are treated as
4099 existing only in the remote repository are treated as
4100 ``deleted``, even if it is in fact added remotely.
4100 ``deleted``, even if it is in fact added remotely.
4101
4101
4102 Returns 0 if there are outgoing changes, 1 otherwise.
4102 Returns 0 if there are outgoing changes, 1 otherwise.
4103 """
4103 """
4104 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4104 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4105 # style URLs, so don't overwrite dest.
4105 # style URLs, so don't overwrite dest.
4106 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4106 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4107 if not path:
4107 if not path:
4108 raise error.Abort(_('default repository not configured!'),
4108 raise error.Abort(_('default repository not configured!'),
4109 hint=_("see 'hg help config.paths'"))
4109 hint=_("see 'hg help config.paths'"))
4110
4110
4111 opts = pycompat.byteskwargs(opts)
4111 opts = pycompat.byteskwargs(opts)
4112 if opts.get('graph'):
4112 if opts.get('graph'):
4113 logcmdutil.checkunsupportedgraphflags([], opts)
4113 logcmdutil.checkunsupportedgraphflags([], opts)
4114 o, other = hg._outgoing(ui, repo, dest, opts)
4114 o, other = hg._outgoing(ui, repo, dest, opts)
4115 if not o:
4115 if not o:
4116 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4116 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4117 return
4117 return
4118
4118
4119 revdag = logcmdutil.graphrevs(repo, o, opts)
4119 revdag = logcmdutil.graphrevs(repo, o, opts)
4120 ui.pager('outgoing')
4120 ui.pager('outgoing')
4121 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4121 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4122 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4122 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4123 graphmod.asciiedges)
4123 graphmod.asciiedges)
4124 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4124 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4125 return 0
4125 return 0
4126
4126
4127 if opts.get('bookmarks'):
4127 if opts.get('bookmarks'):
4128 dest = path.pushloc or path.loc
4128 dest = path.pushloc or path.loc
4129 other = hg.peer(repo, opts, dest)
4129 other = hg.peer(repo, opts, dest)
4130 if 'bookmarks' not in other.listkeys('namespaces'):
4130 if 'bookmarks' not in other.listkeys('namespaces'):
4131 ui.warn(_("remote doesn't support bookmarks\n"))
4131 ui.warn(_("remote doesn't support bookmarks\n"))
4132 return 0
4132 return 0
4133 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4133 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4134 ui.pager('outgoing')
4134 ui.pager('outgoing')
4135 return bookmarks.outgoing(ui, repo, other)
4135 return bookmarks.outgoing(ui, repo, other)
4136
4136
4137 repo._subtoppath = path.pushloc or path.loc
4137 repo._subtoppath = path.pushloc or path.loc
4138 try:
4138 try:
4139 return hg.outgoing(ui, repo, dest, opts)
4139 return hg.outgoing(ui, repo, dest, opts)
4140 finally:
4140 finally:
4141 del repo._subtoppath
4141 del repo._subtoppath
4142
4142
4143 @command('parents',
4143 @command('parents',
4144 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4144 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4145 ] + templateopts,
4145 ] + templateopts,
4146 _('[-r REV] [FILE]'),
4146 _('[-r REV] [FILE]'),
4147 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4147 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4148 inferrepo=True)
4148 inferrepo=True)
4149 def parents(ui, repo, file_=None, **opts):
4149 def parents(ui, repo, file_=None, **opts):
4150 """show the parents of the working directory or revision (DEPRECATED)
4150 """show the parents of the working directory or revision (DEPRECATED)
4151
4151
4152 Print the working directory's parent revisions. If a revision is
4152 Print the working directory's parent revisions. If a revision is
4153 given via -r/--rev, the parent of that revision will be printed.
4153 given via -r/--rev, the parent of that revision will be printed.
4154 If a file argument is given, the revision in which the file was
4154 If a file argument is given, the revision in which the file was
4155 last changed (before the working directory revision or the
4155 last changed (before the working directory revision or the
4156 argument to --rev if given) is printed.
4156 argument to --rev if given) is printed.
4157
4157
4158 This command is equivalent to::
4158 This command is equivalent to::
4159
4159
4160 hg log -r "p1()+p2()" or
4160 hg log -r "p1()+p2()" or
4161 hg log -r "p1(REV)+p2(REV)" or
4161 hg log -r "p1(REV)+p2(REV)" or
4162 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4162 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4163 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4163 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4164
4164
4165 See :hg:`summary` and :hg:`help revsets` for related information.
4165 See :hg:`summary` and :hg:`help revsets` for related information.
4166
4166
4167 Returns 0 on success.
4167 Returns 0 on success.
4168 """
4168 """
4169
4169
4170 opts = pycompat.byteskwargs(opts)
4170 opts = pycompat.byteskwargs(opts)
4171 rev = opts.get('rev')
4171 rev = opts.get('rev')
4172 if rev:
4172 if rev:
4173 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4173 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4174 ctx = scmutil.revsingle(repo, rev, None)
4174 ctx = scmutil.revsingle(repo, rev, None)
4175
4175
4176 if file_:
4176 if file_:
4177 m = scmutil.match(ctx, (file_,), opts)
4177 m = scmutil.match(ctx, (file_,), opts)
4178 if m.anypats() or len(m.files()) != 1:
4178 if m.anypats() or len(m.files()) != 1:
4179 raise error.Abort(_('can only specify an explicit filename'))
4179 raise error.Abort(_('can only specify an explicit filename'))
4180 file_ = m.files()[0]
4180 file_ = m.files()[0]
4181 filenodes = []
4181 filenodes = []
4182 for cp in ctx.parents():
4182 for cp in ctx.parents():
4183 if not cp:
4183 if not cp:
4184 continue
4184 continue
4185 try:
4185 try:
4186 filenodes.append(cp.filenode(file_))
4186 filenodes.append(cp.filenode(file_))
4187 except error.LookupError:
4187 except error.LookupError:
4188 pass
4188 pass
4189 if not filenodes:
4189 if not filenodes:
4190 raise error.Abort(_("'%s' not found in manifest!") % file_)
4190 raise error.Abort(_("'%s' not found in manifest!") % file_)
4191 p = []
4191 p = []
4192 for fn in filenodes:
4192 for fn in filenodes:
4193 fctx = repo.filectx(file_, fileid=fn)
4193 fctx = repo.filectx(file_, fileid=fn)
4194 p.append(fctx.node())
4194 p.append(fctx.node())
4195 else:
4195 else:
4196 p = [cp.node() for cp in ctx.parents()]
4196 p = [cp.node() for cp in ctx.parents()]
4197
4197
4198 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4198 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4199 for n in p:
4199 for n in p:
4200 if n != nullid:
4200 if n != nullid:
4201 displayer.show(repo[n])
4201 displayer.show(repo[n])
4202 displayer.close()
4202 displayer.close()
4203
4203
4204 @command('paths', formatteropts, _('[NAME]'),
4204 @command('paths', formatteropts, _('[NAME]'),
4205 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4205 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4206 optionalrepo=True, intents={INTENT_READONLY})
4206 optionalrepo=True, intents={INTENT_READONLY})
4207 def paths(ui, repo, search=None, **opts):
4207 def paths(ui, repo, search=None, **opts):
4208 """show aliases for remote repositories
4208 """show aliases for remote repositories
4209
4209
4210 Show definition of symbolic path name NAME. If no name is given,
4210 Show definition of symbolic path name NAME. If no name is given,
4211 show definition of all available names.
4211 show definition of all available names.
4212
4212
4213 Option -q/--quiet suppresses all output when searching for NAME
4213 Option -q/--quiet suppresses all output when searching for NAME
4214 and shows only the path names when listing all definitions.
4214 and shows only the path names when listing all definitions.
4215
4215
4216 Path names are defined in the [paths] section of your
4216 Path names are defined in the [paths] section of your
4217 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4217 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4218 repository, ``.hg/hgrc`` is used, too.
4218 repository, ``.hg/hgrc`` is used, too.
4219
4219
4220 The path names ``default`` and ``default-push`` have a special
4220 The path names ``default`` and ``default-push`` have a special
4221 meaning. When performing a push or pull operation, they are used
4221 meaning. When performing a push or pull operation, they are used
4222 as fallbacks if no location is specified on the command-line.
4222 as fallbacks if no location is specified on the command-line.
4223 When ``default-push`` is set, it will be used for push and
4223 When ``default-push`` is set, it will be used for push and
4224 ``default`` will be used for pull; otherwise ``default`` is used
4224 ``default`` will be used for pull; otherwise ``default`` is used
4225 as the fallback for both. When cloning a repository, the clone
4225 as the fallback for both. When cloning a repository, the clone
4226 source is written as ``default`` in ``.hg/hgrc``.
4226 source is written as ``default`` in ``.hg/hgrc``.
4227
4227
4228 .. note::
4228 .. note::
4229
4229
4230 ``default`` and ``default-push`` apply to all inbound (e.g.
4230 ``default`` and ``default-push`` apply to all inbound (e.g.
4231 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4231 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4232 and :hg:`bundle`) operations.
4232 and :hg:`bundle`) operations.
4233
4233
4234 See :hg:`help urls` for more information.
4234 See :hg:`help urls` for more information.
4235
4235
4236 .. container:: verbose
4236 .. container:: verbose
4237
4237
4238 Template:
4238 Template:
4239
4239
4240 The following keywords are supported. See also :hg:`help templates`.
4240 The following keywords are supported. See also :hg:`help templates`.
4241
4241
4242 :name: String. Symbolic name of the path alias.
4242 :name: String. Symbolic name of the path alias.
4243 :pushurl: String. URL for push operations.
4243 :pushurl: String. URL for push operations.
4244 :url: String. URL or directory path for the other operations.
4244 :url: String. URL or directory path for the other operations.
4245
4245
4246 Returns 0 on success.
4246 Returns 0 on success.
4247 """
4247 """
4248
4248
4249 opts = pycompat.byteskwargs(opts)
4249 opts = pycompat.byteskwargs(opts)
4250 ui.pager('paths')
4250 ui.pager('paths')
4251 if search:
4251 if search:
4252 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4252 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4253 if name == search]
4253 if name == search]
4254 else:
4254 else:
4255 pathitems = sorted(ui.paths.iteritems())
4255 pathitems = sorted(ui.paths.iteritems())
4256
4256
4257 fm = ui.formatter('paths', opts)
4257 fm = ui.formatter('paths', opts)
4258 if fm.isplain():
4258 if fm.isplain():
4259 hidepassword = util.hidepassword
4259 hidepassword = util.hidepassword
4260 else:
4260 else:
4261 hidepassword = bytes
4261 hidepassword = bytes
4262 if ui.quiet:
4262 if ui.quiet:
4263 namefmt = '%s\n'
4263 namefmt = '%s\n'
4264 else:
4264 else:
4265 namefmt = '%s = '
4265 namefmt = '%s = '
4266 showsubopts = not search and not ui.quiet
4266 showsubopts = not search and not ui.quiet
4267
4267
4268 for name, path in pathitems:
4268 for name, path in pathitems:
4269 fm.startitem()
4269 fm.startitem()
4270 fm.condwrite(not search, 'name', namefmt, name)
4270 fm.condwrite(not search, 'name', namefmt, name)
4271 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4271 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4272 for subopt, value in sorted(path.suboptions.items()):
4272 for subopt, value in sorted(path.suboptions.items()):
4273 assert subopt not in ('name', 'url')
4273 assert subopt not in ('name', 'url')
4274 if showsubopts:
4274 if showsubopts:
4275 fm.plain('%s:%s = ' % (name, subopt))
4275 fm.plain('%s:%s = ' % (name, subopt))
4276 fm.condwrite(showsubopts, subopt, '%s\n', value)
4276 fm.condwrite(showsubopts, subopt, '%s\n', value)
4277
4277
4278 fm.end()
4278 fm.end()
4279
4279
4280 if search and not pathitems:
4280 if search and not pathitems:
4281 if not ui.quiet:
4281 if not ui.quiet:
4282 ui.warn(_("not found!\n"))
4282 ui.warn(_("not found!\n"))
4283 return 1
4283 return 1
4284 else:
4284 else:
4285 return 0
4285 return 0
4286
4286
4287 @command('phase',
4287 @command('phase',
4288 [('p', 'public', False, _('set changeset phase to public')),
4288 [('p', 'public', False, _('set changeset phase to public')),
4289 ('d', 'draft', False, _('set changeset phase to draft')),
4289 ('d', 'draft', False, _('set changeset phase to draft')),
4290 ('s', 'secret', False, _('set changeset phase to secret')),
4290 ('s', 'secret', False, _('set changeset phase to secret')),
4291 ('f', 'force', False, _('allow to move boundary backward')),
4291 ('f', 'force', False, _('allow to move boundary backward')),
4292 ('r', 'rev', [], _('target revision'), _('REV')),
4292 ('r', 'rev', [], _('target revision'), _('REV')),
4293 ],
4293 ],
4294 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4294 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4295 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4295 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4296 def phase(ui, repo, *revs, **opts):
4296 def phase(ui, repo, *revs, **opts):
4297 """set or show the current phase name
4297 """set or show the current phase name
4298
4298
4299 With no argument, show the phase name of the current revision(s).
4299 With no argument, show the phase name of the current revision(s).
4300
4300
4301 With one of -p/--public, -d/--draft or -s/--secret, change the
4301 With one of -p/--public, -d/--draft or -s/--secret, change the
4302 phase value of the specified revisions.
4302 phase value of the specified revisions.
4303
4303
4304 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4304 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4305 lower phase to a higher phase. Phases are ordered as follows::
4305 lower phase to a higher phase. Phases are ordered as follows::
4306
4306
4307 public < draft < secret
4307 public < draft < secret
4308
4308
4309 Returns 0 on success, 1 if some phases could not be changed.
4309 Returns 0 on success, 1 if some phases could not be changed.
4310
4310
4311 (For more information about the phases concept, see :hg:`help phases`.)
4311 (For more information about the phases concept, see :hg:`help phases`.)
4312 """
4312 """
4313 opts = pycompat.byteskwargs(opts)
4313 opts = pycompat.byteskwargs(opts)
4314 # search for a unique phase argument
4314 # search for a unique phase argument
4315 targetphase = None
4315 targetphase = None
4316 for idx, name in enumerate(phases.cmdphasenames):
4316 for idx, name in enumerate(phases.cmdphasenames):
4317 if opts[name]:
4317 if opts[name]:
4318 if targetphase is not None:
4318 if targetphase is not None:
4319 raise error.Abort(_('only one phase can be specified'))
4319 raise error.Abort(_('only one phase can be specified'))
4320 targetphase = idx
4320 targetphase = idx
4321
4321
4322 # look for specified revision
4322 # look for specified revision
4323 revs = list(revs)
4323 revs = list(revs)
4324 revs.extend(opts['rev'])
4324 revs.extend(opts['rev'])
4325 if not revs:
4325 if not revs:
4326 # display both parents as the second parent phase can influence
4326 # display both parents as the second parent phase can influence
4327 # the phase of a merge commit
4327 # the phase of a merge commit
4328 revs = [c.rev() for c in repo[None].parents()]
4328 revs = [c.rev() for c in repo[None].parents()]
4329
4329
4330 revs = scmutil.revrange(repo, revs)
4330 revs = scmutil.revrange(repo, revs)
4331
4331
4332 ret = 0
4332 ret = 0
4333 if targetphase is None:
4333 if targetphase is None:
4334 # display
4334 # display
4335 for r in revs:
4335 for r in revs:
4336 ctx = repo[r]
4336 ctx = repo[r]
4337 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4337 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4338 else:
4338 else:
4339 with repo.lock(), repo.transaction("phase") as tr:
4339 with repo.lock(), repo.transaction("phase") as tr:
4340 # set phase
4340 # set phase
4341 if not revs:
4341 if not revs:
4342 raise error.Abort(_('empty revision set'))
4342 raise error.Abort(_('empty revision set'))
4343 nodes = [repo[r].node() for r in revs]
4343 nodes = [repo[r].node() for r in revs]
4344 # moving revision from public to draft may hide them
4344 # moving revision from public to draft may hide them
4345 # We have to check result on an unfiltered repository
4345 # We have to check result on an unfiltered repository
4346 unfi = repo.unfiltered()
4346 unfi = repo.unfiltered()
4347 getphase = unfi._phasecache.phase
4347 getphase = unfi._phasecache.phase
4348 olddata = [getphase(unfi, r) for r in unfi]
4348 olddata = [getphase(unfi, r) for r in unfi]
4349 phases.advanceboundary(repo, tr, targetphase, nodes)
4349 phases.advanceboundary(repo, tr, targetphase, nodes)
4350 if opts['force']:
4350 if opts['force']:
4351 phases.retractboundary(repo, tr, targetphase, nodes)
4351 phases.retractboundary(repo, tr, targetphase, nodes)
4352 getphase = unfi._phasecache.phase
4352 getphase = unfi._phasecache.phase
4353 newdata = [getphase(unfi, r) for r in unfi]
4353 newdata = [getphase(unfi, r) for r in unfi]
4354 changes = sum(newdata[r] != olddata[r] for r in unfi)
4354 changes = sum(newdata[r] != olddata[r] for r in unfi)
4355 cl = unfi.changelog
4355 cl = unfi.changelog
4356 rejected = [n for n in nodes
4356 rejected = [n for n in nodes
4357 if newdata[cl.rev(n)] < targetphase]
4357 if newdata[cl.rev(n)] < targetphase]
4358 if rejected:
4358 if rejected:
4359 ui.warn(_('cannot move %i changesets to a higher '
4359 ui.warn(_('cannot move %i changesets to a higher '
4360 'phase, use --force\n') % len(rejected))
4360 'phase, use --force\n') % len(rejected))
4361 ret = 1
4361 ret = 1
4362 if changes:
4362 if changes:
4363 msg = _('phase changed for %i changesets\n') % changes
4363 msg = _('phase changed for %i changesets\n') % changes
4364 if ret:
4364 if ret:
4365 ui.status(msg)
4365 ui.status(msg)
4366 else:
4366 else:
4367 ui.note(msg)
4367 ui.note(msg)
4368 else:
4368 else:
4369 ui.warn(_('no phases changed\n'))
4369 ui.warn(_('no phases changed\n'))
4370 return ret
4370 return ret
4371
4371
4372 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4372 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4373 """Run after a changegroup has been added via pull/unbundle
4373 """Run after a changegroup has been added via pull/unbundle
4374
4374
4375 This takes arguments below:
4375 This takes arguments below:
4376
4376
4377 :modheads: change of heads by pull/unbundle
4377 :modheads: change of heads by pull/unbundle
4378 :optupdate: updating working directory is needed or not
4378 :optupdate: updating working directory is needed or not
4379 :checkout: update destination revision (or None to default destination)
4379 :checkout: update destination revision (or None to default destination)
4380 :brev: a name, which might be a bookmark to be activated after updating
4380 :brev: a name, which might be a bookmark to be activated after updating
4381 """
4381 """
4382 if modheads == 0:
4382 if modheads == 0:
4383 return
4383 return
4384 if optupdate:
4384 if optupdate:
4385 try:
4385 try:
4386 return hg.updatetotally(ui, repo, checkout, brev)
4386 return hg.updatetotally(ui, repo, checkout, brev)
4387 except error.UpdateAbort as inst:
4387 except error.UpdateAbort as inst:
4388 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4388 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4389 hint = inst.hint
4389 hint = inst.hint
4390 raise error.UpdateAbort(msg, hint=hint)
4390 raise error.UpdateAbort(msg, hint=hint)
4391 if modheads is not None and modheads > 1:
4391 if modheads is not None and modheads > 1:
4392 currentbranchheads = len(repo.branchheads())
4392 currentbranchheads = len(repo.branchheads())
4393 if currentbranchheads == modheads:
4393 if currentbranchheads == modheads:
4394 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4394 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4395 elif currentbranchheads > 1:
4395 elif currentbranchheads > 1:
4396 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4396 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4397 "merge)\n"))
4397 "merge)\n"))
4398 else:
4398 else:
4399 ui.status(_("(run 'hg heads' to see heads)\n"))
4399 ui.status(_("(run 'hg heads' to see heads)\n"))
4400 elif not ui.configbool('commands', 'update.requiredest'):
4400 elif not ui.configbool('commands', 'update.requiredest'):
4401 ui.status(_("(run 'hg update' to get a working copy)\n"))
4401 ui.status(_("(run 'hg update' to get a working copy)\n"))
4402
4402
4403 @command('pull',
4403 @command('pull',
4404 [('u', 'update', None,
4404 [('u', 'update', None,
4405 _('update to new branch head if new descendants were pulled')),
4405 _('update to new branch head if new descendants were pulled')),
4406 ('f', 'force', None, _('run even when remote repository is unrelated')),
4406 ('f', 'force', None, _('run even when remote repository is unrelated')),
4407 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4407 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4408 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4408 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4409 ('b', 'branch', [], _('a specific branch you would like to pull'),
4409 ('b', 'branch', [], _('a specific branch you would like to pull'),
4410 _('BRANCH')),
4410 _('BRANCH')),
4411 ] + remoteopts,
4411 ] + remoteopts,
4412 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4412 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4413 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4413 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4414 helpbasic=True)
4414 helpbasic=True)
4415 def pull(ui, repo, source="default", **opts):
4415 def pull(ui, repo, source="default", **opts):
4416 """pull changes from the specified source
4416 """pull changes from the specified source
4417
4417
4418 Pull changes from a remote repository to a local one.
4418 Pull changes from a remote repository to a local one.
4419
4419
4420 This finds all changes from the repository at the specified path
4420 This finds all changes from the repository at the specified path
4421 or URL and adds them to a local repository (the current one unless
4421 or URL and adds them to a local repository (the current one unless
4422 -R is specified). By default, this does not update the copy of the
4422 -R is specified). By default, this does not update the copy of the
4423 project in the working directory.
4423 project in the working directory.
4424
4424
4425 When cloning from servers that support it, Mercurial may fetch
4425 When cloning from servers that support it, Mercurial may fetch
4426 pre-generated data. When this is done, hooks operating on incoming
4426 pre-generated data. When this is done, hooks operating on incoming
4427 changesets and changegroups may fire more than once, once for each
4427 changesets and changegroups may fire more than once, once for each
4428 pre-generated bundle and as well as for any additional remaining
4428 pre-generated bundle and as well as for any additional remaining
4429 data. See :hg:`help -e clonebundles` for more.
4429 data. See :hg:`help -e clonebundles` for more.
4430
4430
4431 Use :hg:`incoming` if you want to see what would have been added
4431 Use :hg:`incoming` if you want to see what would have been added
4432 by a pull at the time you issued this command. If you then decide
4432 by a pull at the time you issued this command. If you then decide
4433 to add those changes to the repository, you should use :hg:`pull
4433 to add those changes to the repository, you should use :hg:`pull
4434 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4434 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4435
4435
4436 If SOURCE is omitted, the 'default' path will be used.
4436 If SOURCE is omitted, the 'default' path will be used.
4437 See :hg:`help urls` for more information.
4437 See :hg:`help urls` for more information.
4438
4438
4439 Specifying bookmark as ``.`` is equivalent to specifying the active
4439 Specifying bookmark as ``.`` is equivalent to specifying the active
4440 bookmark's name.
4440 bookmark's name.
4441
4441
4442 Returns 0 on success, 1 if an update had unresolved files.
4442 Returns 0 on success, 1 if an update had unresolved files.
4443 """
4443 """
4444
4444
4445 opts = pycompat.byteskwargs(opts)
4445 opts = pycompat.byteskwargs(opts)
4446 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4446 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4447 msg = _('update destination required by configuration')
4447 msg = _('update destination required by configuration')
4448 hint = _('use hg pull followed by hg update DEST')
4448 hint = _('use hg pull followed by hg update DEST')
4449 raise error.Abort(msg, hint=hint)
4449 raise error.Abort(msg, hint=hint)
4450
4450
4451 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4451 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4452 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4452 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4453 other = hg.peer(repo, opts, source)
4453 other = hg.peer(repo, opts, source)
4454 try:
4454 try:
4455 revs, checkout = hg.addbranchrevs(repo, other, branches,
4455 revs, checkout = hg.addbranchrevs(repo, other, branches,
4456 opts.get('rev'))
4456 opts.get('rev'))
4457
4457
4458 pullopargs = {}
4458 pullopargs = {}
4459
4459
4460 nodes = None
4460 nodes = None
4461 if opts.get('bookmark') or revs:
4461 if opts.get('bookmark') or revs:
4462 # The list of bookmark used here is the same used to actually update
4462 # The list of bookmark used here is the same used to actually update
4463 # the bookmark names, to avoid the race from issue 4689 and we do
4463 # the bookmark names, to avoid the race from issue 4689 and we do
4464 # all lookup and bookmark queries in one go so they see the same
4464 # all lookup and bookmark queries in one go so they see the same
4465 # version of the server state (issue 4700).
4465 # version of the server state (issue 4700).
4466 nodes = []
4466 nodes = []
4467 fnodes = []
4467 fnodes = []
4468 revs = revs or []
4468 revs = revs or []
4469 if revs and not other.capable('lookup'):
4469 if revs and not other.capable('lookup'):
4470 err = _("other repository doesn't support revision lookup, "
4470 err = _("other repository doesn't support revision lookup, "
4471 "so a rev cannot be specified.")
4471 "so a rev cannot be specified.")
4472 raise error.Abort(err)
4472 raise error.Abort(err)
4473 with other.commandexecutor() as e:
4473 with other.commandexecutor() as e:
4474 fremotebookmarks = e.callcommand('listkeys', {
4474 fremotebookmarks = e.callcommand('listkeys', {
4475 'namespace': 'bookmarks'
4475 'namespace': 'bookmarks'
4476 })
4476 })
4477 for r in revs:
4477 for r in revs:
4478 fnodes.append(e.callcommand('lookup', {'key': r}))
4478 fnodes.append(e.callcommand('lookup', {'key': r}))
4479 remotebookmarks = fremotebookmarks.result()
4479 remotebookmarks = fremotebookmarks.result()
4480 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4480 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4481 pullopargs['remotebookmarks'] = remotebookmarks
4481 pullopargs['remotebookmarks'] = remotebookmarks
4482 for b in opts.get('bookmark', []):
4482 for b in opts.get('bookmark', []):
4483 b = repo._bookmarks.expandname(b)
4483 b = repo._bookmarks.expandname(b)
4484 if b not in remotebookmarks:
4484 if b not in remotebookmarks:
4485 raise error.Abort(_('remote bookmark %s not found!') % b)
4485 raise error.Abort(_('remote bookmark %s not found!') % b)
4486 nodes.append(remotebookmarks[b])
4486 nodes.append(remotebookmarks[b])
4487 for i, rev in enumerate(revs):
4487 for i, rev in enumerate(revs):
4488 node = fnodes[i].result()
4488 node = fnodes[i].result()
4489 nodes.append(node)
4489 nodes.append(node)
4490 if rev == checkout:
4490 if rev == checkout:
4491 checkout = node
4491 checkout = node
4492
4492
4493 wlock = util.nullcontextmanager()
4493 wlock = util.nullcontextmanager()
4494 if opts.get('update'):
4494 if opts.get('update'):
4495 wlock = repo.wlock()
4495 wlock = repo.wlock()
4496 with wlock:
4496 with wlock:
4497 pullopargs.update(opts.get('opargs', {}))
4497 pullopargs.update(opts.get('opargs', {}))
4498 modheads = exchange.pull(repo, other, heads=nodes,
4498 modheads = exchange.pull(repo, other, heads=nodes,
4499 force=opts.get('force'),
4499 force=opts.get('force'),
4500 bookmarks=opts.get('bookmark', ()),
4500 bookmarks=opts.get('bookmark', ()),
4501 opargs=pullopargs).cgresult
4501 opargs=pullopargs).cgresult
4502
4502
4503 # brev is a name, which might be a bookmark to be activated at
4503 # brev is a name, which might be a bookmark to be activated at
4504 # the end of the update. In other words, it is an explicit
4504 # the end of the update. In other words, it is an explicit
4505 # destination of the update
4505 # destination of the update
4506 brev = None
4506 brev = None
4507
4507
4508 if checkout:
4508 if checkout:
4509 checkout = repo.unfiltered().changelog.rev(checkout)
4509 checkout = repo.unfiltered().changelog.rev(checkout)
4510
4510
4511 # order below depends on implementation of
4511 # order below depends on implementation of
4512 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4512 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4513 # because 'checkout' is determined without it.
4513 # because 'checkout' is determined without it.
4514 if opts.get('rev'):
4514 if opts.get('rev'):
4515 brev = opts['rev'][0]
4515 brev = opts['rev'][0]
4516 elif opts.get('branch'):
4516 elif opts.get('branch'):
4517 brev = opts['branch'][0]
4517 brev = opts['branch'][0]
4518 else:
4518 else:
4519 brev = branches[0]
4519 brev = branches[0]
4520 repo._subtoppath = source
4520 repo._subtoppath = source
4521 try:
4521 try:
4522 ret = postincoming(ui, repo, modheads, opts.get('update'),
4522 ret = postincoming(ui, repo, modheads, opts.get('update'),
4523 checkout, brev)
4523 checkout, brev)
4524 except error.FilteredRepoLookupError as exc:
4524 except error.FilteredRepoLookupError as exc:
4525 msg = _('cannot update to target: %s') % exc.args[0]
4525 msg = _('cannot update to target: %s') % exc.args[0]
4526 exc.args = (msg,) + exc.args[1:]
4526 exc.args = (msg,) + exc.args[1:]
4527 raise
4527 raise
4528 finally:
4528 finally:
4529 del repo._subtoppath
4529 del repo._subtoppath
4530
4530
4531 finally:
4531 finally:
4532 other.close()
4532 other.close()
4533 return ret
4533 return ret
4534
4534
4535 @command('push',
4535 @command('push',
4536 [('f', 'force', None, _('force push')),
4536 [('f', 'force', None, _('force push')),
4537 ('r', 'rev', [],
4537 ('r', 'rev', [],
4538 _('a changeset intended to be included in the destination'),
4538 _('a changeset intended to be included in the destination'),
4539 _('REV')),
4539 _('REV')),
4540 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4540 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4541 ('b', 'branch', [],
4541 ('b', 'branch', [],
4542 _('a specific branch you would like to push'), _('BRANCH')),
4542 _('a specific branch you would like to push'), _('BRANCH')),
4543 ('', 'new-branch', False, _('allow pushing a new branch')),
4543 ('', 'new-branch', False, _('allow pushing a new branch')),
4544 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4544 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4545 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4545 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4546 ] + remoteopts,
4546 ] + remoteopts,
4547 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4547 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4548 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4548 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4549 helpbasic=True)
4549 helpbasic=True)
4550 def push(ui, repo, dest=None, **opts):
4550 def push(ui, repo, dest=None, **opts):
4551 """push changes to the specified destination
4551 """push changes to the specified destination
4552
4552
4553 Push changesets from the local repository to the specified
4553 Push changesets from the local repository to the specified
4554 destination.
4554 destination.
4555
4555
4556 This operation is symmetrical to pull: it is identical to a pull
4556 This operation is symmetrical to pull: it is identical to a pull
4557 in the destination repository from the current one.
4557 in the destination repository from the current one.
4558
4558
4559 By default, push will not allow creation of new heads at the
4559 By default, push will not allow creation of new heads at the
4560 destination, since multiple heads would make it unclear which head
4560 destination, since multiple heads would make it unclear which head
4561 to use. In this situation, it is recommended to pull and merge
4561 to use. In this situation, it is recommended to pull and merge
4562 before pushing.
4562 before pushing.
4563
4563
4564 Use --new-branch if you want to allow push to create a new named
4564 Use --new-branch if you want to allow push to create a new named
4565 branch that is not present at the destination. This allows you to
4565 branch that is not present at the destination. This allows you to
4566 only create a new branch without forcing other changes.
4566 only create a new branch without forcing other changes.
4567
4567
4568 .. note::
4568 .. note::
4569
4569
4570 Extra care should be taken with the -f/--force option,
4570 Extra care should be taken with the -f/--force option,
4571 which will push all new heads on all branches, an action which will
4571 which will push all new heads on all branches, an action which will
4572 almost always cause confusion for collaborators.
4572 almost always cause confusion for collaborators.
4573
4573
4574 If -r/--rev is used, the specified revision and all its ancestors
4574 If -r/--rev is used, the specified revision and all its ancestors
4575 will be pushed to the remote repository.
4575 will be pushed to the remote repository.
4576
4576
4577 If -B/--bookmark is used, the specified bookmarked revision, its
4577 If -B/--bookmark is used, the specified bookmarked revision, its
4578 ancestors, and the bookmark will be pushed to the remote
4578 ancestors, and the bookmark will be pushed to the remote
4579 repository. Specifying ``.`` is equivalent to specifying the active
4579 repository. Specifying ``.`` is equivalent to specifying the active
4580 bookmark's name.
4580 bookmark's name.
4581
4581
4582 Please see :hg:`help urls` for important details about ``ssh://``
4582 Please see :hg:`help urls` for important details about ``ssh://``
4583 URLs. If DESTINATION is omitted, a default path will be used.
4583 URLs. If DESTINATION is omitted, a default path will be used.
4584
4584
4585 .. container:: verbose
4585 .. container:: verbose
4586
4586
4587 The --pushvars option sends strings to the server that become
4587 The --pushvars option sends strings to the server that become
4588 environment variables prepended with ``HG_USERVAR_``. For example,
4588 environment variables prepended with ``HG_USERVAR_``. For example,
4589 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4589 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4590 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4590 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4591
4591
4592 pushvars can provide for user-overridable hooks as well as set debug
4592 pushvars can provide for user-overridable hooks as well as set debug
4593 levels. One example is having a hook that blocks commits containing
4593 levels. One example is having a hook that blocks commits containing
4594 conflict markers, but enables the user to override the hook if the file
4594 conflict markers, but enables the user to override the hook if the file
4595 is using conflict markers for testing purposes or the file format has
4595 is using conflict markers for testing purposes or the file format has
4596 strings that look like conflict markers.
4596 strings that look like conflict markers.
4597
4597
4598 By default, servers will ignore `--pushvars`. To enable it add the
4598 By default, servers will ignore `--pushvars`. To enable it add the
4599 following to your configuration file::
4599 following to your configuration file::
4600
4600
4601 [push]
4601 [push]
4602 pushvars.server = true
4602 pushvars.server = true
4603
4603
4604 Returns 0 if push was successful, 1 if nothing to push.
4604 Returns 0 if push was successful, 1 if nothing to push.
4605 """
4605 """
4606
4606
4607 opts = pycompat.byteskwargs(opts)
4607 opts = pycompat.byteskwargs(opts)
4608 if opts.get('bookmark'):
4608 if opts.get('bookmark'):
4609 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4609 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4610 for b in opts['bookmark']:
4610 for b in opts['bookmark']:
4611 # translate -B options to -r so changesets get pushed
4611 # translate -B options to -r so changesets get pushed
4612 b = repo._bookmarks.expandname(b)
4612 b = repo._bookmarks.expandname(b)
4613 if b in repo._bookmarks:
4613 if b in repo._bookmarks:
4614 opts.setdefault('rev', []).append(b)
4614 opts.setdefault('rev', []).append(b)
4615 else:
4615 else:
4616 # if we try to push a deleted bookmark, translate it to null
4616 # if we try to push a deleted bookmark, translate it to null
4617 # this lets simultaneous -r, -b options continue working
4617 # this lets simultaneous -r, -b options continue working
4618 opts.setdefault('rev', []).append("null")
4618 opts.setdefault('rev', []).append("null")
4619
4619
4620 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4620 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4621 if not path:
4621 if not path:
4622 raise error.Abort(_('default repository not configured!'),
4622 raise error.Abort(_('default repository not configured!'),
4623 hint=_("see 'hg help config.paths'"))
4623 hint=_("see 'hg help config.paths'"))
4624 dest = path.pushloc or path.loc
4624 dest = path.pushloc or path.loc
4625 branches = (path.branch, opts.get('branch') or [])
4625 branches = (path.branch, opts.get('branch') or [])
4626 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4626 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4627 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4627 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4628 other = hg.peer(repo, opts, dest)
4628 other = hg.peer(repo, opts, dest)
4629
4629
4630 if revs:
4630 if revs:
4631 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4631 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4632 if not revs:
4632 if not revs:
4633 raise error.Abort(_("specified revisions evaluate to an empty set"),
4633 raise error.Abort(_("specified revisions evaluate to an empty set"),
4634 hint=_("use different revision arguments"))
4634 hint=_("use different revision arguments"))
4635 elif path.pushrev:
4635 elif path.pushrev:
4636 # It doesn't make any sense to specify ancestor revisions. So limit
4636 # It doesn't make any sense to specify ancestor revisions. So limit
4637 # to DAG heads to make discovery simpler.
4637 # to DAG heads to make discovery simpler.
4638 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4638 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4639 revs = scmutil.revrange(repo, [expr])
4639 revs = scmutil.revrange(repo, [expr])
4640 revs = [repo[rev].node() for rev in revs]
4640 revs = [repo[rev].node() for rev in revs]
4641 if not revs:
4641 if not revs:
4642 raise error.Abort(_('default push revset for path evaluates to an '
4642 raise error.Abort(_('default push revset for path evaluates to an '
4643 'empty set'))
4643 'empty set'))
4644
4644
4645 repo._subtoppath = dest
4645 repo._subtoppath = dest
4646 try:
4646 try:
4647 # push subrepos depth-first for coherent ordering
4647 # push subrepos depth-first for coherent ordering
4648 c = repo['.']
4648 c = repo['.']
4649 subs = c.substate # only repos that are committed
4649 subs = c.substate # only repos that are committed
4650 for s in sorted(subs):
4650 for s in sorted(subs):
4651 result = c.sub(s).push(opts)
4651 result = c.sub(s).push(opts)
4652 if result == 0:
4652 if result == 0:
4653 return not result
4653 return not result
4654 finally:
4654 finally:
4655 del repo._subtoppath
4655 del repo._subtoppath
4656
4656
4657 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4657 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4658 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4658 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4659
4659
4660 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4660 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4661 newbranch=opts.get('new_branch'),
4661 newbranch=opts.get('new_branch'),
4662 bookmarks=opts.get('bookmark', ()),
4662 bookmarks=opts.get('bookmark', ()),
4663 publish=opts.get('publish'),
4663 publish=opts.get('publish'),
4664 opargs=opargs)
4664 opargs=opargs)
4665
4665
4666 result = not pushop.cgresult
4666 result = not pushop.cgresult
4667
4667
4668 if pushop.bkresult is not None:
4668 if pushop.bkresult is not None:
4669 if pushop.bkresult == 2:
4669 if pushop.bkresult == 2:
4670 result = 2
4670 result = 2
4671 elif not result and pushop.bkresult:
4671 elif not result and pushop.bkresult:
4672 result = 2
4672 result = 2
4673
4673
4674 return result
4674 return result
4675
4675
4676 @command('recover',
4676 @command('recover',
4677 [('','verify', True, "run `hg verify` after succesful recover"),
4677 [('','verify', True, "run `hg verify` after succesful recover"),
4678 ],
4678 ],
4679 helpcategory=command.CATEGORY_MAINTENANCE)
4679 helpcategory=command.CATEGORY_MAINTENANCE)
4680 def recover(ui, repo, **opts):
4680 def recover(ui, repo, **opts):
4681 """roll back an interrupted transaction
4681 """roll back an interrupted transaction
4682
4682
4683 Recover from an interrupted commit or pull.
4683 Recover from an interrupted commit or pull.
4684
4684
4685 This command tries to fix the repository status after an
4685 This command tries to fix the repository status after an
4686 interrupted operation. It should only be necessary when Mercurial
4686 interrupted operation. It should only be necessary when Mercurial
4687 suggests it.
4687 suggests it.
4688
4688
4689 Returns 0 if successful, 1 if nothing to recover or verify fails.
4689 Returns 0 if successful, 1 if nothing to recover or verify fails.
4690 """
4690 """
4691 ret = repo.recover()
4691 ret = repo.recover()
4692 if ret:
4692 if ret:
4693 if opts[r'verify']:
4693 if opts[r'verify']:
4694 return hg.verify(repo)
4694 return hg.verify(repo)
4695 else:
4695 else:
4696 msg = _("(verify step skipped, run `hg verify` to check your "
4696 msg = _("(verify step skipped, run `hg verify` to check your "
4697 "repository content)\n")
4697 "repository content)\n")
4698 ui.warn(msg)
4698 ui.warn(msg)
4699 return 0
4699 return 0
4700 return 1
4700 return 1
4701
4701
4702 @command('remove|rm',
4702 @command('remove|rm',
4703 [('A', 'after', None, _('record delete for missing files')),
4703 [('A', 'after', None, _('record delete for missing files')),
4704 ('f', 'force', None,
4704 ('f', 'force', None,
4705 _('forget added files, delete modified files')),
4705 _('forget added files, delete modified files')),
4706 ] + subrepoopts + walkopts + dryrunopts,
4706 ] + subrepoopts + walkopts + dryrunopts,
4707 _('[OPTION]... FILE...'),
4707 _('[OPTION]... FILE...'),
4708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4709 helpbasic=True, inferrepo=True)
4709 helpbasic=True, inferrepo=True)
4710 def remove(ui, repo, *pats, **opts):
4710 def remove(ui, repo, *pats, **opts):
4711 """remove the specified files on the next commit
4711 """remove the specified files on the next commit
4712
4712
4713 Schedule the indicated files for removal from the current branch.
4713 Schedule the indicated files for removal from the current branch.
4714
4714
4715 This command schedules the files to be removed at the next commit.
4715 This command schedules the files to be removed at the next commit.
4716 To undo a remove before that, see :hg:`revert`. To undo added
4716 To undo a remove before that, see :hg:`revert`. To undo added
4717 files, see :hg:`forget`.
4717 files, see :hg:`forget`.
4718
4718
4719 .. container:: verbose
4719 .. container:: verbose
4720
4720
4721 -A/--after can be used to remove only files that have already
4721 -A/--after can be used to remove only files that have already
4722 been deleted, -f/--force can be used to force deletion, and -Af
4722 been deleted, -f/--force can be used to force deletion, and -Af
4723 can be used to remove files from the next revision without
4723 can be used to remove files from the next revision without
4724 deleting them from the working directory.
4724 deleting them from the working directory.
4725
4725
4726 The following table details the behavior of remove for different
4726 The following table details the behavior of remove for different
4727 file states (columns) and option combinations (rows). The file
4727 file states (columns) and option combinations (rows). The file
4728 states are Added [A], Clean [C], Modified [M] and Missing [!]
4728 states are Added [A], Clean [C], Modified [M] and Missing [!]
4729 (as reported by :hg:`status`). The actions are Warn, Remove
4729 (as reported by :hg:`status`). The actions are Warn, Remove
4730 (from branch) and Delete (from disk):
4730 (from branch) and Delete (from disk):
4731
4731
4732 ========= == == == ==
4732 ========= == == == ==
4733 opt/state A C M !
4733 opt/state A C M !
4734 ========= == == == ==
4734 ========= == == == ==
4735 none W RD W R
4735 none W RD W R
4736 -f R RD RD R
4736 -f R RD RD R
4737 -A W W W R
4737 -A W W W R
4738 -Af R R R R
4738 -Af R R R R
4739 ========= == == == ==
4739 ========= == == == ==
4740
4740
4741 .. note::
4741 .. note::
4742
4742
4743 :hg:`remove` never deletes files in Added [A] state from the
4743 :hg:`remove` never deletes files in Added [A] state from the
4744 working directory, not even if ``--force`` is specified.
4744 working directory, not even if ``--force`` is specified.
4745
4745
4746 Returns 0 on success, 1 if any warnings encountered.
4746 Returns 0 on success, 1 if any warnings encountered.
4747 """
4747 """
4748
4748
4749 opts = pycompat.byteskwargs(opts)
4749 opts = pycompat.byteskwargs(opts)
4750 after, force = opts.get('after'), opts.get('force')
4750 after, force = opts.get('after'), opts.get('force')
4751 dryrun = opts.get('dry_run')
4751 dryrun = opts.get('dry_run')
4752 if not pats and not after:
4752 if not pats and not after:
4753 raise error.Abort(_('no files specified'))
4753 raise error.Abort(_('no files specified'))
4754
4754
4755 m = scmutil.match(repo[None], pats, opts)
4755 m = scmutil.match(repo[None], pats, opts)
4756 subrepos = opts.get('subrepos')
4756 subrepos = opts.get('subrepos')
4757 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4757 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4758 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4758 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4759 dryrun=dryrun)
4759 dryrun=dryrun)
4760
4760
4761 @command('rename|move|mv',
4761 @command('rename|move|mv',
4762 [('A', 'after', None, _('record a rename that has already occurred')),
4762 [('A', 'after', None, _('record a rename that has already occurred')),
4763 ('f', 'force', None, _('forcibly move over an existing managed file')),
4763 ('f', 'force', None, _('forcibly move over an existing managed file')),
4764 ] + walkopts + dryrunopts,
4764 ] + walkopts + dryrunopts,
4765 _('[OPTION]... SOURCE... DEST'),
4765 _('[OPTION]... SOURCE... DEST'),
4766 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4766 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4767 def rename(ui, repo, *pats, **opts):
4767 def rename(ui, repo, *pats, **opts):
4768 """rename files; equivalent of copy + remove
4768 """rename files; equivalent of copy + remove
4769
4769
4770 Mark dest as copies of sources; mark sources for deletion. If dest
4770 Mark dest as copies of sources; mark sources for deletion. If dest
4771 is a directory, copies are put in that directory. If dest is a
4771 is a directory, copies are put in that directory. If dest is a
4772 file, there can only be one source.
4772 file, there can only be one source.
4773
4773
4774 By default, this command copies the contents of files as they
4774 By default, this command copies the contents of files as they
4775 exist in the working directory. If invoked with -A/--after, the
4775 exist in the working directory. If invoked with -A/--after, the
4776 operation is recorded, but no copying is performed.
4776 operation is recorded, but no copying is performed.
4777
4777
4778 This command takes effect at the next commit. To undo a rename
4778 This command takes effect at the next commit. To undo a rename
4779 before that, see :hg:`revert`.
4779 before that, see :hg:`revert`.
4780
4780
4781 Returns 0 on success, 1 if errors are encountered.
4781 Returns 0 on success, 1 if errors are encountered.
4782 """
4782 """
4783 opts = pycompat.byteskwargs(opts)
4783 opts = pycompat.byteskwargs(opts)
4784 with repo.wlock(False):
4784 with repo.wlock(False):
4785 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4785 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4786
4786
4787 @command('resolve',
4787 @command('resolve',
4788 [('a', 'all', None, _('select all unresolved files')),
4788 [('a', 'all', None, _('select all unresolved files')),
4789 ('l', 'list', None, _('list state of files needing merge')),
4789 ('l', 'list', None, _('list state of files needing merge')),
4790 ('m', 'mark', None, _('mark files as resolved')),
4790 ('m', 'mark', None, _('mark files as resolved')),
4791 ('u', 'unmark', None, _('mark files as unresolved')),
4791 ('u', 'unmark', None, _('mark files as unresolved')),
4792 ('n', 'no-status', None, _('hide status prefix')),
4792 ('n', 'no-status', None, _('hide status prefix')),
4793 ('', 're-merge', None, _('re-merge files'))]
4793 ('', 're-merge', None, _('re-merge files'))]
4794 + mergetoolopts + walkopts + formatteropts,
4794 + mergetoolopts + walkopts + formatteropts,
4795 _('[OPTION]... [FILE]...'),
4795 _('[OPTION]... [FILE]...'),
4796 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4796 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4797 inferrepo=True)
4797 inferrepo=True)
4798 def resolve(ui, repo, *pats, **opts):
4798 def resolve(ui, repo, *pats, **opts):
4799 """redo merges or set/view the merge status of files
4799 """redo merges or set/view the merge status of files
4800
4800
4801 Merges with unresolved conflicts are often the result of
4801 Merges with unresolved conflicts are often the result of
4802 non-interactive merging using the ``internal:merge`` configuration
4802 non-interactive merging using the ``internal:merge`` configuration
4803 setting, or a command-line merge tool like ``diff3``. The resolve
4803 setting, or a command-line merge tool like ``diff3``. The resolve
4804 command is used to manage the files involved in a merge, after
4804 command is used to manage the files involved in a merge, after
4805 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4805 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4806 working directory must have two parents). See :hg:`help
4806 working directory must have two parents). See :hg:`help
4807 merge-tools` for information on configuring merge tools.
4807 merge-tools` for information on configuring merge tools.
4808
4808
4809 The resolve command can be used in the following ways:
4809 The resolve command can be used in the following ways:
4810
4810
4811 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4811 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4812 the specified files, discarding any previous merge attempts. Re-merging
4812 the specified files, discarding any previous merge attempts. Re-merging
4813 is not performed for files already marked as resolved. Use ``--all/-a``
4813 is not performed for files already marked as resolved. Use ``--all/-a``
4814 to select all unresolved files. ``--tool`` can be used to specify
4814 to select all unresolved files. ``--tool`` can be used to specify
4815 the merge tool used for the given files. It overrides the HGMERGE
4815 the merge tool used for the given files. It overrides the HGMERGE
4816 environment variable and your configuration files. Previous file
4816 environment variable and your configuration files. Previous file
4817 contents are saved with a ``.orig`` suffix.
4817 contents are saved with a ``.orig`` suffix.
4818
4818
4819 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4819 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4820 (e.g. after having manually fixed-up the files). The default is
4820 (e.g. after having manually fixed-up the files). The default is
4821 to mark all unresolved files.
4821 to mark all unresolved files.
4822
4822
4823 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4823 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4824 default is to mark all resolved files.
4824 default is to mark all resolved files.
4825
4825
4826 - :hg:`resolve -l`: list files which had or still have conflicts.
4826 - :hg:`resolve -l`: list files which had or still have conflicts.
4827 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4827 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4828 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4828 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4829 the list. See :hg:`help filesets` for details.
4829 the list. See :hg:`help filesets` for details.
4830
4830
4831 .. note::
4831 .. note::
4832
4832
4833 Mercurial will not let you commit files with unresolved merge
4833 Mercurial will not let you commit files with unresolved merge
4834 conflicts. You must use :hg:`resolve -m ...` before you can
4834 conflicts. You must use :hg:`resolve -m ...` before you can
4835 commit after a conflicting merge.
4835 commit after a conflicting merge.
4836
4836
4837 .. container:: verbose
4837 .. container:: verbose
4838
4838
4839 Template:
4839 Template:
4840
4840
4841 The following keywords are supported in addition to the common template
4841 The following keywords are supported in addition to the common template
4842 keywords and functions. See also :hg:`help templates`.
4842 keywords and functions. See also :hg:`help templates`.
4843
4843
4844 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4844 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4845 :path: String. Repository-absolute path of the file.
4845 :path: String. Repository-absolute path of the file.
4846
4846
4847 Returns 0 on success, 1 if any files fail a resolve attempt.
4847 Returns 0 on success, 1 if any files fail a resolve attempt.
4848 """
4848 """
4849
4849
4850 opts = pycompat.byteskwargs(opts)
4850 opts = pycompat.byteskwargs(opts)
4851 confirm = ui.configbool('commands', 'resolve.confirm')
4851 confirm = ui.configbool('commands', 'resolve.confirm')
4852 flaglist = 'all mark unmark list no_status re_merge'.split()
4852 flaglist = 'all mark unmark list no_status re_merge'.split()
4853 all, mark, unmark, show, nostatus, remerge = [
4853 all, mark, unmark, show, nostatus, remerge = [
4854 opts.get(o) for o in flaglist]
4854 opts.get(o) for o in flaglist]
4855
4855
4856 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4856 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4857 if actioncount > 1:
4857 if actioncount > 1:
4858 raise error.Abort(_("too many actions specified"))
4858 raise error.Abort(_("too many actions specified"))
4859 elif (actioncount == 0
4859 elif (actioncount == 0
4860 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4860 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4861 hint = _('use --mark, --unmark, --list or --re-merge')
4861 hint = _('use --mark, --unmark, --list or --re-merge')
4862 raise error.Abort(_('no action specified'), hint=hint)
4862 raise error.Abort(_('no action specified'), hint=hint)
4863 if pats and all:
4863 if pats and all:
4864 raise error.Abort(_("can't specify --all and patterns"))
4864 raise error.Abort(_("can't specify --all and patterns"))
4865 if not (all or pats or show or mark or unmark):
4865 if not (all or pats or show or mark or unmark):
4866 raise error.Abort(_('no files or directories specified'),
4866 raise error.Abort(_('no files or directories specified'),
4867 hint=('use --all to re-merge all unresolved files'))
4867 hint=('use --all to re-merge all unresolved files'))
4868
4868
4869 if confirm:
4869 if confirm:
4870 if all:
4870 if all:
4871 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4871 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4872 b'$$ &Yes $$ &No')):
4872 b'$$ &Yes $$ &No')):
4873 raise error.Abort(_('user quit'))
4873 raise error.Abort(_('user quit'))
4874 if mark and not pats:
4874 if mark and not pats:
4875 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4875 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4876 b'$$ &Yes $$ &No')):
4876 b'$$ &Yes $$ &No')):
4877 raise error.Abort(_('user quit'))
4877 raise error.Abort(_('user quit'))
4878 if unmark and not pats:
4878 if unmark and not pats:
4879 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4879 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4880 b'$$ &Yes $$ &No')):
4880 b'$$ &Yes $$ &No')):
4881 raise error.Abort(_('user quit'))
4881 raise error.Abort(_('user quit'))
4882
4882
4883 uipathfn = scmutil.getuipathfn(repo)
4883 uipathfn = scmutil.getuipathfn(repo)
4884
4884
4885 if show:
4885 if show:
4886 ui.pager('resolve')
4886 ui.pager('resolve')
4887 fm = ui.formatter('resolve', opts)
4887 fm = ui.formatter('resolve', opts)
4888 ms = mergemod.mergestate.read(repo)
4888 ms = mergemod.mergestate.read(repo)
4889 wctx = repo[None]
4889 wctx = repo[None]
4890 m = scmutil.match(wctx, pats, opts)
4890 m = scmutil.match(wctx, pats, opts)
4891
4891
4892 # Labels and keys based on merge state. Unresolved path conflicts show
4892 # Labels and keys based on merge state. Unresolved path conflicts show
4893 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4893 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4894 # resolved conflicts.
4894 # resolved conflicts.
4895 mergestateinfo = {
4895 mergestateinfo = {
4896 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4896 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4897 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4897 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4898 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4898 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4899 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4899 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4900 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4900 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4901 'D'),
4901 'D'),
4902 }
4902 }
4903
4903
4904 for f in ms:
4904 for f in ms:
4905 if not m(f):
4905 if not m(f):
4906 continue
4906 continue
4907
4907
4908 label, key = mergestateinfo[ms[f]]
4908 label, key = mergestateinfo[ms[f]]
4909 fm.startitem()
4909 fm.startitem()
4910 fm.context(ctx=wctx)
4910 fm.context(ctx=wctx)
4911 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4911 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4912 fm.data(path=f)
4912 fm.data(path=f)
4913 fm.plain('%s\n' % uipathfn(f), label=label)
4913 fm.plain('%s\n' % uipathfn(f), label=label)
4914 fm.end()
4914 fm.end()
4915 return 0
4915 return 0
4916
4916
4917 with repo.wlock():
4917 with repo.wlock():
4918 ms = mergemod.mergestate.read(repo)
4918 ms = mergemod.mergestate.read(repo)
4919
4919
4920 if not (ms.active() or repo.dirstate.p2() != nullid):
4920 if not (ms.active() or repo.dirstate.p2() != nullid):
4921 raise error.Abort(
4921 raise error.Abort(
4922 _('resolve command not applicable when not merging'))
4922 _('resolve command not applicable when not merging'))
4923
4923
4924 wctx = repo[None]
4924 wctx = repo[None]
4925
4925
4926 if (ms.mergedriver
4926 if (ms.mergedriver
4927 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4927 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4928 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4928 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4929 ms.commit()
4929 ms.commit()
4930 # allow mark and unmark to go through
4930 # allow mark and unmark to go through
4931 if not mark and not unmark and not proceed:
4931 if not mark and not unmark and not proceed:
4932 return 1
4932 return 1
4933
4933
4934 m = scmutil.match(wctx, pats, opts)
4934 m = scmutil.match(wctx, pats, opts)
4935 ret = 0
4935 ret = 0
4936 didwork = False
4936 didwork = False
4937 runconclude = False
4937 runconclude = False
4938
4938
4939 tocomplete = []
4939 tocomplete = []
4940 hasconflictmarkers = []
4940 hasconflictmarkers = []
4941 if mark:
4941 if mark:
4942 markcheck = ui.config('commands', 'resolve.mark-check')
4942 markcheck = ui.config('commands', 'resolve.mark-check')
4943 if markcheck not in ['warn', 'abort']:
4943 if markcheck not in ['warn', 'abort']:
4944 # Treat all invalid / unrecognized values as 'none'.
4944 # Treat all invalid / unrecognized values as 'none'.
4945 markcheck = False
4945 markcheck = False
4946 for f in ms:
4946 for f in ms:
4947 if not m(f):
4947 if not m(f):
4948 continue
4948 continue
4949
4949
4950 didwork = True
4950 didwork = True
4951
4951
4952 # don't let driver-resolved files be marked, and run the conclude
4952 # don't let driver-resolved files be marked, and run the conclude
4953 # step if asked to resolve
4953 # step if asked to resolve
4954 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4954 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4955 exact = m.exact(f)
4955 exact = m.exact(f)
4956 if mark:
4956 if mark:
4957 if exact:
4957 if exact:
4958 ui.warn(_('not marking %s as it is driver-resolved\n')
4958 ui.warn(_('not marking %s as it is driver-resolved\n')
4959 % uipathfn(f))
4959 % uipathfn(f))
4960 elif unmark:
4960 elif unmark:
4961 if exact:
4961 if exact:
4962 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4962 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4963 % uipathfn(f))
4963 % uipathfn(f))
4964 else:
4964 else:
4965 runconclude = True
4965 runconclude = True
4966 continue
4966 continue
4967
4967
4968 # path conflicts must be resolved manually
4968 # path conflicts must be resolved manually
4969 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4969 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4970 mergemod.MERGE_RECORD_RESOLVED_PATH):
4970 mergemod.MERGE_RECORD_RESOLVED_PATH):
4971 if mark:
4971 if mark:
4972 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4972 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4973 elif unmark:
4973 elif unmark:
4974 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4974 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4975 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4975 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4976 ui.warn(_('%s: path conflict must be resolved manually\n')
4976 ui.warn(_('%s: path conflict must be resolved manually\n')
4977 % uipathfn(f))
4977 % uipathfn(f))
4978 continue
4978 continue
4979
4979
4980 if mark:
4980 if mark:
4981 if markcheck:
4981 if markcheck:
4982 fdata = repo.wvfs.tryread(f)
4982 fdata = repo.wvfs.tryread(f)
4983 if (filemerge.hasconflictmarkers(fdata) and
4983 if (filemerge.hasconflictmarkers(fdata) and
4984 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4984 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4985 hasconflictmarkers.append(f)
4985 hasconflictmarkers.append(f)
4986 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4986 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4987 elif unmark:
4987 elif unmark:
4988 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4988 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4989 else:
4989 else:
4990 # backup pre-resolve (merge uses .orig for its own purposes)
4990 # backup pre-resolve (merge uses .orig for its own purposes)
4991 a = repo.wjoin(f)
4991 a = repo.wjoin(f)
4992 try:
4992 try:
4993 util.copyfile(a, a + ".resolve")
4993 util.copyfile(a, a + ".resolve")
4994 except (IOError, OSError) as inst:
4994 except (IOError, OSError) as inst:
4995 if inst.errno != errno.ENOENT:
4995 if inst.errno != errno.ENOENT:
4996 raise
4996 raise
4997
4997
4998 try:
4998 try:
4999 # preresolve file
4999 # preresolve file
5000 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5000 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5001 with ui.configoverride(overrides, 'resolve'):
5001 with ui.configoverride(overrides, 'resolve'):
5002 complete, r = ms.preresolve(f, wctx)
5002 complete, r = ms.preresolve(f, wctx)
5003 if not complete:
5003 if not complete:
5004 tocomplete.append(f)
5004 tocomplete.append(f)
5005 elif r:
5005 elif r:
5006 ret = 1
5006 ret = 1
5007 finally:
5007 finally:
5008 ms.commit()
5008 ms.commit()
5009
5009
5010 # replace filemerge's .orig file with our resolve file, but only
5010 # replace filemerge's .orig file with our resolve file, but only
5011 # for merges that are complete
5011 # for merges that are complete
5012 if complete:
5012 if complete:
5013 try:
5013 try:
5014 util.rename(a + ".resolve",
5014 util.rename(a + ".resolve",
5015 scmutil.backuppath(ui, repo, f))
5015 scmutil.backuppath(ui, repo, f))
5016 except OSError as inst:
5016 except OSError as inst:
5017 if inst.errno != errno.ENOENT:
5017 if inst.errno != errno.ENOENT:
5018 raise
5018 raise
5019
5019
5020 if hasconflictmarkers:
5020 if hasconflictmarkers:
5021 ui.warn(_('warning: the following files still have conflict '
5021 ui.warn(_('warning: the following files still have conflict '
5022 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5022 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5023 for f in hasconflictmarkers))
5023 for f in hasconflictmarkers))
5024 if markcheck == 'abort' and not all and not pats:
5024 if markcheck == 'abort' and not all and not pats:
5025 raise error.Abort(_('conflict markers detected'),
5025 raise error.Abort(_('conflict markers detected'),
5026 hint=_('use --all to mark anyway'))
5026 hint=_('use --all to mark anyway'))
5027
5027
5028 for f in tocomplete:
5028 for f in tocomplete:
5029 try:
5029 try:
5030 # resolve file
5030 # resolve file
5031 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5031 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5032 with ui.configoverride(overrides, 'resolve'):
5032 with ui.configoverride(overrides, 'resolve'):
5033 r = ms.resolve(f, wctx)
5033 r = ms.resolve(f, wctx)
5034 if r:
5034 if r:
5035 ret = 1
5035 ret = 1
5036 finally:
5036 finally:
5037 ms.commit()
5037 ms.commit()
5038
5038
5039 # replace filemerge's .orig file with our resolve file
5039 # replace filemerge's .orig file with our resolve file
5040 a = repo.wjoin(f)
5040 a = repo.wjoin(f)
5041 try:
5041 try:
5042 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5042 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5043 except OSError as inst:
5043 except OSError as inst:
5044 if inst.errno != errno.ENOENT:
5044 if inst.errno != errno.ENOENT:
5045 raise
5045 raise
5046
5046
5047 ms.commit()
5047 ms.commit()
5048 ms.recordactions()
5048 ms.recordactions()
5049
5049
5050 if not didwork and pats:
5050 if not didwork and pats:
5051 hint = None
5051 hint = None
5052 if not any([p for p in pats if p.find(':') >= 0]):
5052 if not any([p for p in pats if p.find(':') >= 0]):
5053 pats = ['path:%s' % p for p in pats]
5053 pats = ['path:%s' % p for p in pats]
5054 m = scmutil.match(wctx, pats, opts)
5054 m = scmutil.match(wctx, pats, opts)
5055 for f in ms:
5055 for f in ms:
5056 if not m(f):
5056 if not m(f):
5057 continue
5057 continue
5058 def flag(o):
5058 def flag(o):
5059 if o == 're_merge':
5059 if o == 're_merge':
5060 return '--re-merge '
5060 return '--re-merge '
5061 return '-%s ' % o[0:1]
5061 return '-%s ' % o[0:1]
5062 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5062 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5063 hint = _("(try: hg resolve %s%s)\n") % (
5063 hint = _("(try: hg resolve %s%s)\n") % (
5064 flags,
5064 flags,
5065 ' '.join(pats))
5065 ' '.join(pats))
5066 break
5066 break
5067 ui.warn(_("arguments do not match paths that need resolving\n"))
5067 ui.warn(_("arguments do not match paths that need resolving\n"))
5068 if hint:
5068 if hint:
5069 ui.warn(hint)
5069 ui.warn(hint)
5070 elif ms.mergedriver and ms.mdstate() != 's':
5070 elif ms.mergedriver and ms.mdstate() != 's':
5071 # run conclude step when either a driver-resolved file is requested
5071 # run conclude step when either a driver-resolved file is requested
5072 # or there are no driver-resolved files
5072 # or there are no driver-resolved files
5073 # we can't use 'ret' to determine whether any files are unresolved
5073 # we can't use 'ret' to determine whether any files are unresolved
5074 # because we might not have tried to resolve some
5074 # because we might not have tried to resolve some
5075 if ((runconclude or not list(ms.driverresolved()))
5075 if ((runconclude or not list(ms.driverresolved()))
5076 and not list(ms.unresolved())):
5076 and not list(ms.unresolved())):
5077 proceed = mergemod.driverconclude(repo, ms, wctx)
5077 proceed = mergemod.driverconclude(repo, ms, wctx)
5078 ms.commit()
5078 ms.commit()
5079 if not proceed:
5079 if not proceed:
5080 return 1
5080 return 1
5081
5081
5082 # Nudge users into finishing an unfinished operation
5082 # Nudge users into finishing an unfinished operation
5083 unresolvedf = list(ms.unresolved())
5083 unresolvedf = list(ms.unresolved())
5084 driverresolvedf = list(ms.driverresolved())
5084 driverresolvedf = list(ms.driverresolved())
5085 if not unresolvedf and not driverresolvedf:
5085 if not unresolvedf and not driverresolvedf:
5086 ui.status(_('(no more unresolved files)\n'))
5086 ui.status(_('(no more unresolved files)\n'))
5087 cmdutil.checkafterresolved(repo)
5087 cmdutil.checkafterresolved(repo)
5088 elif not unresolvedf:
5088 elif not unresolvedf:
5089 ui.status(_('(no more unresolved files -- '
5089 ui.status(_('(no more unresolved files -- '
5090 'run "hg resolve --all" to conclude)\n'))
5090 'run "hg resolve --all" to conclude)\n'))
5091
5091
5092 return ret
5092 return ret
5093
5093
5094 @command('revert',
5094 @command('revert',
5095 [('a', 'all', None, _('revert all changes when no arguments given')),
5095 [('a', 'all', None, _('revert all changes when no arguments given')),
5096 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5096 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5097 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5097 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5098 ('C', 'no-backup', None, _('do not save backup copies of files')),
5098 ('C', 'no-backup', None, _('do not save backup copies of files')),
5099 ('i', 'interactive', None, _('interactively select the changes')),
5099 ('i', 'interactive', None, _('interactively select the changes')),
5100 ] + walkopts + dryrunopts,
5100 ] + walkopts + dryrunopts,
5101 _('[OPTION]... [-r REV] [NAME]...'),
5101 _('[OPTION]... [-r REV] [NAME]...'),
5102 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5102 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5103 def revert(ui, repo, *pats, **opts):
5103 def revert(ui, repo, *pats, **opts):
5104 """restore files to their checkout state
5104 """restore files to their checkout state
5105
5105
5106 .. note::
5106 .. note::
5107
5107
5108 To check out earlier revisions, you should use :hg:`update REV`.
5108 To check out earlier revisions, you should use :hg:`update REV`.
5109 To cancel an uncommitted merge (and lose your changes),
5109 To cancel an uncommitted merge (and lose your changes),
5110 use :hg:`merge --abort`.
5110 use :hg:`merge --abort`.
5111
5111
5112 With no revision specified, revert the specified files or directories
5112 With no revision specified, revert the specified files or directories
5113 to the contents they had in the parent of the working directory.
5113 to the contents they had in the parent of the working directory.
5114 This restores the contents of files to an unmodified
5114 This restores the contents of files to an unmodified
5115 state and unschedules adds, removes, copies, and renames. If the
5115 state and unschedules adds, removes, copies, and renames. If the
5116 working directory has two parents, you must explicitly specify a
5116 working directory has two parents, you must explicitly specify a
5117 revision.
5117 revision.
5118
5118
5119 Using the -r/--rev or -d/--date options, revert the given files or
5119 Using the -r/--rev or -d/--date options, revert the given files or
5120 directories to their states as of a specific revision. Because
5120 directories to their states as of a specific revision. Because
5121 revert does not change the working directory parents, this will
5121 revert does not change the working directory parents, this will
5122 cause these files to appear modified. This can be helpful to "back
5122 cause these files to appear modified. This can be helpful to "back
5123 out" some or all of an earlier change. See :hg:`backout` for a
5123 out" some or all of an earlier change. See :hg:`backout` for a
5124 related method.
5124 related method.
5125
5125
5126 Modified files are saved with a .orig suffix before reverting.
5126 Modified files are saved with a .orig suffix before reverting.
5127 To disable these backups, use --no-backup. It is possible to store
5127 To disable these backups, use --no-backup. It is possible to store
5128 the backup files in a custom directory relative to the root of the
5128 the backup files in a custom directory relative to the root of the
5129 repository by setting the ``ui.origbackuppath`` configuration
5129 repository by setting the ``ui.origbackuppath`` configuration
5130 option.
5130 option.
5131
5131
5132 See :hg:`help dates` for a list of formats valid for -d/--date.
5132 See :hg:`help dates` for a list of formats valid for -d/--date.
5133
5133
5134 See :hg:`help backout` for a way to reverse the effect of an
5134 See :hg:`help backout` for a way to reverse the effect of an
5135 earlier changeset.
5135 earlier changeset.
5136
5136
5137 Returns 0 on success.
5137 Returns 0 on success.
5138 """
5138 """
5139
5139
5140 opts = pycompat.byteskwargs(opts)
5140 opts = pycompat.byteskwargs(opts)
5141 if opts.get("date"):
5141 if opts.get("date"):
5142 if opts.get("rev"):
5142 if opts.get("rev"):
5143 raise error.Abort(_("you can't specify a revision and a date"))
5143 raise error.Abort(_("you can't specify a revision and a date"))
5144 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5144 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5145
5145
5146 parent, p2 = repo.dirstate.parents()
5146 parent, p2 = repo.dirstate.parents()
5147 if not opts.get('rev') and p2 != nullid:
5147 if not opts.get('rev') and p2 != nullid:
5148 # revert after merge is a trap for new users (issue2915)
5148 # revert after merge is a trap for new users (issue2915)
5149 raise error.Abort(_('uncommitted merge with no revision specified'),
5149 raise error.Abort(_('uncommitted merge with no revision specified'),
5150 hint=_("use 'hg update' or see 'hg help revert'"))
5150 hint=_("use 'hg update' or see 'hg help revert'"))
5151
5151
5152 rev = opts.get('rev')
5152 rev = opts.get('rev')
5153 if rev:
5153 if rev:
5154 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5154 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5155 ctx = scmutil.revsingle(repo, rev)
5155 ctx = scmutil.revsingle(repo, rev)
5156
5156
5157 if (not (pats or opts.get('include') or opts.get('exclude') or
5157 if (not (pats or opts.get('include') or opts.get('exclude') or
5158 opts.get('all') or opts.get('interactive'))):
5158 opts.get('all') or opts.get('interactive'))):
5159 msg = _("no files or directories specified")
5159 msg = _("no files or directories specified")
5160 if p2 != nullid:
5160 if p2 != nullid:
5161 hint = _("uncommitted merge, use --all to discard all changes,"
5161 hint = _("uncommitted merge, use --all to discard all changes,"
5162 " or 'hg update -C .' to abort the merge")
5162 " or 'hg update -C .' to abort the merge")
5163 raise error.Abort(msg, hint=hint)
5163 raise error.Abort(msg, hint=hint)
5164 dirty = any(repo.status())
5164 dirty = any(repo.status())
5165 node = ctx.node()
5165 node = ctx.node()
5166 if node != parent:
5166 if node != parent:
5167 if dirty:
5167 if dirty:
5168 hint = _("uncommitted changes, use --all to discard all"
5168 hint = _("uncommitted changes, use --all to discard all"
5169 " changes, or 'hg update %d' to update") % ctx.rev()
5169 " changes, or 'hg update %d' to update") % ctx.rev()
5170 else:
5170 else:
5171 hint = _("use --all to revert all files,"
5171 hint = _("use --all to revert all files,"
5172 " or 'hg update %d' to update") % ctx.rev()
5172 " or 'hg update %d' to update") % ctx.rev()
5173 elif dirty:
5173 elif dirty:
5174 hint = _("uncommitted changes, use --all to discard all changes")
5174 hint = _("uncommitted changes, use --all to discard all changes")
5175 else:
5175 else:
5176 hint = _("use --all to revert all files")
5176 hint = _("use --all to revert all files")
5177 raise error.Abort(msg, hint=hint)
5177 raise error.Abort(msg, hint=hint)
5178
5178
5179 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5179 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5180 **pycompat.strkwargs(opts))
5180 **pycompat.strkwargs(opts))
5181
5181
5182 @command(
5182 @command(
5183 'rollback',
5183 'rollback',
5184 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5184 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5185 helpcategory=command.CATEGORY_MAINTENANCE)
5185 helpcategory=command.CATEGORY_MAINTENANCE)
5186 def rollback(ui, repo, **opts):
5186 def rollback(ui, repo, **opts):
5187 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5187 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5188
5188
5189 Please use :hg:`commit --amend` instead of rollback to correct
5189 Please use :hg:`commit --amend` instead of rollback to correct
5190 mistakes in the last commit.
5190 mistakes in the last commit.
5191
5191
5192 This command should be used with care. There is only one level of
5192 This command should be used with care. There is only one level of
5193 rollback, and there is no way to undo a rollback. It will also
5193 rollback, and there is no way to undo a rollback. It will also
5194 restore the dirstate at the time of the last transaction, losing
5194 restore the dirstate at the time of the last transaction, losing
5195 any dirstate changes since that time. This command does not alter
5195 any dirstate changes since that time. This command does not alter
5196 the working directory.
5196 the working directory.
5197
5197
5198 Transactions are used to encapsulate the effects of all commands
5198 Transactions are used to encapsulate the effects of all commands
5199 that create new changesets or propagate existing changesets into a
5199 that create new changesets or propagate existing changesets into a
5200 repository.
5200 repository.
5201
5201
5202 .. container:: verbose
5202 .. container:: verbose
5203
5203
5204 For example, the following commands are transactional, and their
5204 For example, the following commands are transactional, and their
5205 effects can be rolled back:
5205 effects can be rolled back:
5206
5206
5207 - commit
5207 - commit
5208 - import
5208 - import
5209 - pull
5209 - pull
5210 - push (with this repository as the destination)
5210 - push (with this repository as the destination)
5211 - unbundle
5211 - unbundle
5212
5212
5213 To avoid permanent data loss, rollback will refuse to rollback a
5213 To avoid permanent data loss, rollback will refuse to rollback a
5214 commit transaction if it isn't checked out. Use --force to
5214 commit transaction if it isn't checked out. Use --force to
5215 override this protection.
5215 override this protection.
5216
5216
5217 The rollback command can be entirely disabled by setting the
5217 The rollback command can be entirely disabled by setting the
5218 ``ui.rollback`` configuration setting to false. If you're here
5218 ``ui.rollback`` configuration setting to false. If you're here
5219 because you want to use rollback and it's disabled, you can
5219 because you want to use rollback and it's disabled, you can
5220 re-enable the command by setting ``ui.rollback`` to true.
5220 re-enable the command by setting ``ui.rollback`` to true.
5221
5221
5222 This command is not intended for use on public repositories. Once
5222 This command is not intended for use on public repositories. Once
5223 changes are visible for pull by other users, rolling a transaction
5223 changes are visible for pull by other users, rolling a transaction
5224 back locally is ineffective (someone else may already have pulled
5224 back locally is ineffective (someone else may already have pulled
5225 the changes). Furthermore, a race is possible with readers of the
5225 the changes). Furthermore, a race is possible with readers of the
5226 repository; for example an in-progress pull from the repository
5226 repository; for example an in-progress pull from the repository
5227 may fail if a rollback is performed.
5227 may fail if a rollback is performed.
5228
5228
5229 Returns 0 on success, 1 if no rollback data is available.
5229 Returns 0 on success, 1 if no rollback data is available.
5230 """
5230 """
5231 if not ui.configbool('ui', 'rollback'):
5231 if not ui.configbool('ui', 'rollback'):
5232 raise error.Abort(_('rollback is disabled because it is unsafe'),
5232 raise error.Abort(_('rollback is disabled because it is unsafe'),
5233 hint=('see `hg help -v rollback` for information'))
5233 hint=('see `hg help -v rollback` for information'))
5234 return repo.rollback(dryrun=opts.get(r'dry_run'),
5234 return repo.rollback(dryrun=opts.get(r'dry_run'),
5235 force=opts.get(r'force'))
5235 force=opts.get(r'force'))
5236
5236
5237 @command(
5237 @command(
5238 'root', [] + formatteropts, intents={INTENT_READONLY},
5238 'root', [] + formatteropts, intents={INTENT_READONLY},
5239 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5239 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5240 def root(ui, repo, **opts):
5240 def root(ui, repo, **opts):
5241 """print the root (top) of the current working directory
5241 """print the root (top) of the current working directory
5242
5242
5243 Print the root directory of the current repository.
5243 Print the root directory of the current repository.
5244
5244
5245 .. container:: verbose
5245 .. container:: verbose
5246
5246
5247 Template:
5247 Template:
5248
5248
5249 The following keywords are supported in addition to the common template
5249 The following keywords are supported in addition to the common template
5250 keywords and functions. See also :hg:`help templates`.
5250 keywords and functions. See also :hg:`help templates`.
5251
5251
5252 :hgpath: String. Path to the .hg directory.
5252 :hgpath: String. Path to the .hg directory.
5253 :storepath: String. Path to the directory holding versioned data.
5253 :storepath: String. Path to the directory holding versioned data.
5254
5254
5255 Returns 0 on success.
5255 Returns 0 on success.
5256 """
5256 """
5257 opts = pycompat.byteskwargs(opts)
5257 opts = pycompat.byteskwargs(opts)
5258 with ui.formatter('root', opts) as fm:
5258 with ui.formatter('root', opts) as fm:
5259 fm.startitem()
5259 fm.startitem()
5260 fm.write('reporoot', '%s\n', repo.root)
5260 fm.write('reporoot', '%s\n', repo.root)
5261 fm.data(hgpath=repo.path, storepath=repo.spath)
5261 fm.data(hgpath=repo.path, storepath=repo.spath)
5262
5262
5263 @command('serve',
5263 @command('serve',
5264 [('A', 'accesslog', '', _('name of access log file to write to'),
5264 [('A', 'accesslog', '', _('name of access log file to write to'),
5265 _('FILE')),
5265 _('FILE')),
5266 ('d', 'daemon', None, _('run server in background')),
5266 ('d', 'daemon', None, _('run server in background')),
5267 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5267 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5268 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5268 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5269 # use string type, then we can check if something was passed
5269 # use string type, then we can check if something was passed
5270 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5270 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5271 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5271 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5272 _('ADDR')),
5272 _('ADDR')),
5273 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5273 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5274 _('PREFIX')),
5274 _('PREFIX')),
5275 ('n', 'name', '',
5275 ('n', 'name', '',
5276 _('name to show in web pages (default: working directory)'), _('NAME')),
5276 _('name to show in web pages (default: working directory)'), _('NAME')),
5277 ('', 'web-conf', '',
5277 ('', 'web-conf', '',
5278 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5278 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5279 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5279 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5280 _('FILE')),
5280 _('FILE')),
5281 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5281 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5282 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5282 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5283 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5283 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5284 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5284 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5285 ('', 'style', '', _('template style to use'), _('STYLE')),
5285 ('', 'style', '', _('template style to use'), _('STYLE')),
5286 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5286 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5287 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5287 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5288 ('', 'print-url', None, _('start and print only the URL'))]
5288 ('', 'print-url', None, _('start and print only the URL'))]
5289 + subrepoopts,
5289 + subrepoopts,
5290 _('[OPTION]...'),
5290 _('[OPTION]...'),
5291 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5291 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5292 helpbasic=True, optionalrepo=True)
5292 helpbasic=True, optionalrepo=True)
5293 def serve(ui, repo, **opts):
5293 def serve(ui, repo, **opts):
5294 """start stand-alone webserver
5294 """start stand-alone webserver
5295
5295
5296 Start a local HTTP repository browser and pull server. You can use
5296 Start a local HTTP repository browser and pull server. You can use
5297 this for ad-hoc sharing and browsing of repositories. It is
5297 this for ad-hoc sharing and browsing of repositories. It is
5298 recommended to use a real web server to serve a repository for
5298 recommended to use a real web server to serve a repository for
5299 longer periods of time.
5299 longer periods of time.
5300
5300
5301 Please note that the server does not implement access control.
5301 Please note that the server does not implement access control.
5302 This means that, by default, anybody can read from the server and
5302 This means that, by default, anybody can read from the server and
5303 nobody can write to it by default. Set the ``web.allow-push``
5303 nobody can write to it by default. Set the ``web.allow-push``
5304 option to ``*`` to allow everybody to push to the server. You
5304 option to ``*`` to allow everybody to push to the server. You
5305 should use a real web server if you need to authenticate users.
5305 should use a real web server if you need to authenticate users.
5306
5306
5307 By default, the server logs accesses to stdout and errors to
5307 By default, the server logs accesses to stdout and errors to
5308 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5308 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5309 files.
5309 files.
5310
5310
5311 To have the server choose a free port number to listen on, specify
5311 To have the server choose a free port number to listen on, specify
5312 a port number of 0; in this case, the server will print the port
5312 a port number of 0; in this case, the server will print the port
5313 number it uses.
5313 number it uses.
5314
5314
5315 Returns 0 on success.
5315 Returns 0 on success.
5316 """
5316 """
5317
5317
5318 opts = pycompat.byteskwargs(opts)
5318 opts = pycompat.byteskwargs(opts)
5319 if opts["stdio"] and opts["cmdserver"]:
5319 if opts["stdio"] and opts["cmdserver"]:
5320 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5320 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5321 if opts["print_url"] and ui.verbose:
5321 if opts["print_url"] and ui.verbose:
5322 raise error.Abort(_("cannot use --print-url with --verbose"))
5322 raise error.Abort(_("cannot use --print-url with --verbose"))
5323
5323
5324 if opts["stdio"]:
5324 if opts["stdio"]:
5325 if repo is None:
5325 if repo is None:
5326 raise error.RepoError(_("there is no Mercurial repository here"
5326 raise error.RepoError(_("there is no Mercurial repository here"
5327 " (.hg not found)"))
5327 " (.hg not found)"))
5328 s = wireprotoserver.sshserver(ui, repo)
5328 s = wireprotoserver.sshserver(ui, repo)
5329 s.serve_forever()
5329 s.serve_forever()
5330
5330
5331 service = server.createservice(ui, repo, opts)
5331 service = server.createservice(ui, repo, opts)
5332 return server.runservice(opts, initfn=service.init, runfn=service.run)
5332 return server.runservice(opts, initfn=service.init, runfn=service.run)
5333
5333
5334 @command('shelve',
5334 @command('shelve',
5335 [('A', 'addremove', None,
5335 [('A', 'addremove', None,
5336 _('mark new/missing files as added/removed before shelving')),
5336 _('mark new/missing files as added/removed before shelving')),
5337 ('u', 'unknown', None,
5337 ('u', 'unknown', None,
5338 _('store unknown files in the shelve')),
5338 _('store unknown files in the shelve')),
5339 ('', 'cleanup', None,
5339 ('', 'cleanup', None,
5340 _('delete all shelved changes')),
5340 _('delete all shelved changes')),
5341 ('', 'date', '',
5341 ('', 'date', '',
5342 _('shelve with the specified commit date'), _('DATE')),
5342 _('shelve with the specified commit date'), _('DATE')),
5343 ('d', 'delete', None,
5343 ('d', 'delete', None,
5344 _('delete the named shelved change(s)')),
5344 _('delete the named shelved change(s)')),
5345 ('e', 'edit', False,
5345 ('e', 'edit', False,
5346 _('invoke editor on commit messages')),
5346 _('invoke editor on commit messages')),
5347 ('k', 'keep', False,
5347 ('k', 'keep', False,
5348 _('shelve, but keep changes in the working directory')),
5348 _('shelve, but keep changes in the working directory')),
5349 ('l', 'list', None,
5349 ('l', 'list', None,
5350 _('list current shelves')),
5350 _('list current shelves')),
5351 ('m', 'message', '',
5351 ('m', 'message', '',
5352 _('use text as shelve message'), _('TEXT')),
5352 _('use text as shelve message'), _('TEXT')),
5353 ('n', 'name', '',
5353 ('n', 'name', '',
5354 _('use the given name for the shelved commit'), _('NAME')),
5354 _('use the given name for the shelved commit'), _('NAME')),
5355 ('p', 'patch', None,
5355 ('p', 'patch', None,
5356 _('output patches for changes (provide the names of the shelved '
5356 _('output patches for changes (provide the names of the shelved '
5357 'changes as positional arguments)')),
5357 'changes as positional arguments)')),
5358 ('i', 'interactive', None,
5358 ('i', 'interactive', None,
5359 _('interactive mode')),
5359 _('interactive mode')),
5360 ('', 'stat', None,
5360 ('', 'stat', None,
5361 _('output diffstat-style summary of changes (provide the names of '
5361 _('output diffstat-style summary of changes (provide the names of '
5362 'the shelved changes as positional arguments)')
5362 'the shelved changes as positional arguments)')
5363 )] + cmdutil.walkopts,
5363 )] + cmdutil.walkopts,
5364 _('hg shelve [OPTION]... [FILE]...'),
5364 _('hg shelve [OPTION]... [FILE]...'),
5365 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5365 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5366 def shelve(ui, repo, *pats, **opts):
5366 def shelve(ui, repo, *pats, **opts):
5367 '''save and set aside changes from the working directory
5367 '''save and set aside changes from the working directory
5368
5368
5369 Shelving takes files that "hg status" reports as not clean, saves
5369 Shelving takes files that "hg status" reports as not clean, saves
5370 the modifications to a bundle (a shelved change), and reverts the
5370 the modifications to a bundle (a shelved change), and reverts the
5371 files so that their state in the working directory becomes clean.
5371 files so that their state in the working directory becomes clean.
5372
5372
5373 To restore these changes to the working directory, using "hg
5373 To restore these changes to the working directory, using "hg
5374 unshelve"; this will work even if you switch to a different
5374 unshelve"; this will work even if you switch to a different
5375 commit.
5375 commit.
5376
5376
5377 When no files are specified, "hg shelve" saves all not-clean
5377 When no files are specified, "hg shelve" saves all not-clean
5378 files. If specific files or directories are named, only changes to
5378 files. If specific files or directories are named, only changes to
5379 those files are shelved.
5379 those files are shelved.
5380
5380
5381 In bare shelve (when no files are specified, without interactive,
5381 In bare shelve (when no files are specified, without interactive,
5382 include and exclude option), shelving remembers information if the
5382 include and exclude option), shelving remembers information if the
5383 working directory was on newly created branch, in other words working
5383 working directory was on newly created branch, in other words working
5384 directory was on different branch than its first parent. In this
5384 directory was on different branch than its first parent. In this
5385 situation unshelving restores branch information to the working directory.
5385 situation unshelving restores branch information to the working directory.
5386
5386
5387 Each shelved change has a name that makes it easier to find later.
5387 Each shelved change has a name that makes it easier to find later.
5388 The name of a shelved change defaults to being based on the active
5388 The name of a shelved change defaults to being based on the active
5389 bookmark, or if there is no active bookmark, the current named
5389 bookmark, or if there is no active bookmark, the current named
5390 branch. To specify a different name, use ``--name``.
5390 branch. To specify a different name, use ``--name``.
5391
5391
5392 To see a list of existing shelved changes, use the ``--list``
5392 To see a list of existing shelved changes, use the ``--list``
5393 option. For each shelved change, this will print its name, age,
5393 option. For each shelved change, this will print its name, age,
5394 and description; use ``--patch`` or ``--stat`` for more details.
5394 and description; use ``--patch`` or ``--stat`` for more details.
5395
5395
5396 To delete specific shelved changes, use ``--delete``. To delete
5396 To delete specific shelved changes, use ``--delete``. To delete
5397 all shelved changes, use ``--cleanup``.
5397 all shelved changes, use ``--cleanup``.
5398 '''
5398 '''
5399 opts = pycompat.byteskwargs(opts)
5399 opts = pycompat.byteskwargs(opts)
5400 allowables = [
5400 allowables = [
5401 ('addremove', {'create'}), # 'create' is pseudo action
5401 ('addremove', {'create'}), # 'create' is pseudo action
5402 ('unknown', {'create'}),
5402 ('unknown', {'create'}),
5403 ('cleanup', {'cleanup'}),
5403 ('cleanup', {'cleanup'}),
5404 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
5404 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
5405 ('delete', {'delete'}),
5405 ('delete', {'delete'}),
5406 ('edit', {'create'}),
5406 ('edit', {'create'}),
5407 ('keep', {'create'}),
5407 ('keep', {'create'}),
5408 ('list', {'list'}),
5408 ('list', {'list'}),
5409 ('message', {'create'}),
5409 ('message', {'create'}),
5410 ('name', {'create'}),
5410 ('name', {'create'}),
5411 ('patch', {'patch', 'list'}),
5411 ('patch', {'patch', 'list'}),
5412 ('stat', {'stat', 'list'}),
5412 ('stat', {'stat', 'list'}),
5413 ]
5413 ]
5414 def checkopt(opt):
5414 def checkopt(opt):
5415 if opts.get(opt):
5415 if opts.get(opt):
5416 for i, allowable in allowables:
5416 for i, allowable in allowables:
5417 if opts[i] and opt not in allowable:
5417 if opts[i] and opt not in allowable:
5418 raise error.Abort(_("options '--%s' and '--%s' may not be "
5418 raise error.Abort(_("options '--%s' and '--%s' may not be "
5419 "used together") % (opt, i))
5419 "used together") % (opt, i))
5420 return True
5420 return True
5421 if checkopt('cleanup'):
5421 if checkopt('cleanup'):
5422 if pats:
5422 if pats:
5423 raise error.Abort(_("cannot specify names when using '--cleanup'"))
5423 raise error.Abort(_("cannot specify names when using '--cleanup'"))
5424 return shelvemod.cleanupcmd(ui, repo)
5424 return shelvemod.cleanupcmd(ui, repo)
5425 elif checkopt('delete'):
5425 elif checkopt('delete'):
5426 return shelvemod.deletecmd(ui, repo, pats)
5426 return shelvemod.deletecmd(ui, repo, pats)
5427 elif checkopt('list'):
5427 elif checkopt('list'):
5428 return shelvemod.listcmd(ui, repo, pats, opts)
5428 return shelvemod.listcmd(ui, repo, pats, opts)
5429 elif checkopt('patch') or checkopt('stat'):
5429 elif checkopt('patch') or checkopt('stat'):
5430 return shelvemod.patchcmds(ui, repo, pats, opts)
5430 return shelvemod.patchcmds(ui, repo, pats, opts)
5431 else:
5431 else:
5432 return shelvemod.createcmd(ui, repo, pats, opts)
5432 return shelvemod.createcmd(ui, repo, pats, opts)
5433
5433
5434 _NOTTERSE = 'nothing'
5434 _NOTTERSE = 'nothing'
5435
5435
5436 @command('status|st',
5436 @command('status|st',
5437 [('A', 'all', None, _('show status of all files')),
5437 [('A', 'all', None, _('show status of all files')),
5438 ('m', 'modified', None, _('show only modified files')),
5438 ('m', 'modified', None, _('show only modified files')),
5439 ('a', 'added', None, _('show only added files')),
5439 ('a', 'added', None, _('show only added files')),
5440 ('r', 'removed', None, _('show only removed files')),
5440 ('r', 'removed', None, _('show only removed files')),
5441 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5441 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5442 ('c', 'clean', None, _('show only files without changes')),
5442 ('c', 'clean', None, _('show only files without changes')),
5443 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5443 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5444 ('i', 'ignored', None, _('show only ignored files')),
5444 ('i', 'ignored', None, _('show only ignored files')),
5445 ('n', 'no-status', None, _('hide status prefix')),
5445 ('n', 'no-status', None, _('hide status prefix')),
5446 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5446 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5447 ('C', 'copies', None, _('show source of copied files')),
5447 ('C', 'copies', None, _('show source of copied files')),
5448 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5448 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5449 ('', 'rev', [], _('show difference from revision'), _('REV')),
5449 ('', 'rev', [], _('show difference from revision'), _('REV')),
5450 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5450 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5451 ] + walkopts + subrepoopts + formatteropts,
5451 ] + walkopts + subrepoopts + formatteropts,
5452 _('[OPTION]... [FILE]...'),
5452 _('[OPTION]... [FILE]...'),
5453 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5453 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5454 helpbasic=True, inferrepo=True,
5454 helpbasic=True, inferrepo=True,
5455 intents={INTENT_READONLY})
5455 intents={INTENT_READONLY})
5456 def status(ui, repo, *pats, **opts):
5456 def status(ui, repo, *pats, **opts):
5457 """show changed files in the working directory
5457 """show changed files in the working directory
5458
5458
5459 Show status of files in the repository. If names are given, only
5459 Show status of files in the repository. If names are given, only
5460 files that match are shown. Files that are clean or ignored or
5460 files that match are shown. Files that are clean or ignored or
5461 the source of a copy/move operation, are not listed unless
5461 the source of a copy/move operation, are not listed unless
5462 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5462 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5463 Unless options described with "show only ..." are given, the
5463 Unless options described with "show only ..." are given, the
5464 options -mardu are used.
5464 options -mardu are used.
5465
5465
5466 Option -q/--quiet hides untracked (unknown and ignored) files
5466 Option -q/--quiet hides untracked (unknown and ignored) files
5467 unless explicitly requested with -u/--unknown or -i/--ignored.
5467 unless explicitly requested with -u/--unknown or -i/--ignored.
5468
5468
5469 .. note::
5469 .. note::
5470
5470
5471 :hg:`status` may appear to disagree with diff if permissions have
5471 :hg:`status` may appear to disagree with diff if permissions have
5472 changed or a merge has occurred. The standard diff format does
5472 changed or a merge has occurred. The standard diff format does
5473 not report permission changes and diff only reports changes
5473 not report permission changes and diff only reports changes
5474 relative to one merge parent.
5474 relative to one merge parent.
5475
5475
5476 If one revision is given, it is used as the base revision.
5476 If one revision is given, it is used as the base revision.
5477 If two revisions are given, the differences between them are
5477 If two revisions are given, the differences between them are
5478 shown. The --change option can also be used as a shortcut to list
5478 shown. The --change option can also be used as a shortcut to list
5479 the changed files of a revision from its first parent.
5479 the changed files of a revision from its first parent.
5480
5480
5481 The codes used to show the status of files are::
5481 The codes used to show the status of files are::
5482
5482
5483 M = modified
5483 M = modified
5484 A = added
5484 A = added
5485 R = removed
5485 R = removed
5486 C = clean
5486 C = clean
5487 ! = missing (deleted by non-hg command, but still tracked)
5487 ! = missing (deleted by non-hg command, but still tracked)
5488 ? = not tracked
5488 ? = not tracked
5489 I = ignored
5489 I = ignored
5490 = origin of the previous file (with --copies)
5490 = origin of the previous file (with --copies)
5491
5491
5492 .. container:: verbose
5492 .. container:: verbose
5493
5493
5494 The -t/--terse option abbreviates the output by showing only the directory
5494 The -t/--terse option abbreviates the output by showing only the directory
5495 name if all the files in it share the same status. The option takes an
5495 name if all the files in it share the same status. The option takes an
5496 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5496 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5497 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5497 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5498 for 'ignored' and 'c' for clean.
5498 for 'ignored' and 'c' for clean.
5499
5499
5500 It abbreviates only those statuses which are passed. Note that clean and
5500 It abbreviates only those statuses which are passed. Note that clean and
5501 ignored files are not displayed with '--terse ic' unless the -c/--clean
5501 ignored files are not displayed with '--terse ic' unless the -c/--clean
5502 and -i/--ignored options are also used.
5502 and -i/--ignored options are also used.
5503
5503
5504 The -v/--verbose option shows information when the repository is in an
5504 The -v/--verbose option shows information when the repository is in an
5505 unfinished merge, shelve, rebase state etc. You can have this behavior
5505 unfinished merge, shelve, rebase state etc. You can have this behavior
5506 turned on by default by enabling the ``commands.status.verbose`` option.
5506 turned on by default by enabling the ``commands.status.verbose`` option.
5507
5507
5508 You can skip displaying some of these states by setting
5508 You can skip displaying some of these states by setting
5509 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5509 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5510 'histedit', 'merge', 'rebase', or 'unshelve'.
5510 'histedit', 'merge', 'rebase', or 'unshelve'.
5511
5511
5512 Template:
5512 Template:
5513
5513
5514 The following keywords are supported in addition to the common template
5514 The following keywords are supported in addition to the common template
5515 keywords and functions. See also :hg:`help templates`.
5515 keywords and functions. See also :hg:`help templates`.
5516
5516
5517 :path: String. Repository-absolute path of the file.
5517 :path: String. Repository-absolute path of the file.
5518 :source: String. Repository-absolute path of the file originated from.
5518 :source: String. Repository-absolute path of the file originated from.
5519 Available if ``--copies`` is specified.
5519 Available if ``--copies`` is specified.
5520 :status: String. Character denoting file's status.
5520 :status: String. Character denoting file's status.
5521
5521
5522 Examples:
5522 Examples:
5523
5523
5524 - show changes in the working directory relative to a
5524 - show changes in the working directory relative to a
5525 changeset::
5525 changeset::
5526
5526
5527 hg status --rev 9353
5527 hg status --rev 9353
5528
5528
5529 - show changes in the working directory relative to the
5529 - show changes in the working directory relative to the
5530 current directory (see :hg:`help patterns` for more information)::
5530 current directory (see :hg:`help patterns` for more information)::
5531
5531
5532 hg status re:
5532 hg status re:
5533
5533
5534 - show all changes including copies in an existing changeset::
5534 - show all changes including copies in an existing changeset::
5535
5535
5536 hg status --copies --change 9353
5536 hg status --copies --change 9353
5537
5537
5538 - get a NUL separated list of added files, suitable for xargs::
5538 - get a NUL separated list of added files, suitable for xargs::
5539
5539
5540 hg status -an0
5540 hg status -an0
5541
5541
5542 - show more information about the repository status, abbreviating
5542 - show more information about the repository status, abbreviating
5543 added, removed, modified, deleted, and untracked paths::
5543 added, removed, modified, deleted, and untracked paths::
5544
5544
5545 hg status -v -t mardu
5545 hg status -v -t mardu
5546
5546
5547 Returns 0 on success.
5547 Returns 0 on success.
5548
5548
5549 """
5549 """
5550
5550
5551 opts = pycompat.byteskwargs(opts)
5551 opts = pycompat.byteskwargs(opts)
5552 revs = opts.get('rev')
5552 revs = opts.get('rev')
5553 change = opts.get('change')
5553 change = opts.get('change')
5554 terse = opts.get('terse')
5554 terse = opts.get('terse')
5555 if terse is _NOTTERSE:
5555 if terse is _NOTTERSE:
5556 if revs:
5556 if revs:
5557 terse = ''
5557 terse = ''
5558 else:
5558 else:
5559 terse = ui.config('commands', 'status.terse')
5559 terse = ui.config('commands', 'status.terse')
5560
5560
5561 if revs and change:
5561 if revs and change:
5562 msg = _('cannot specify --rev and --change at the same time')
5562 msg = _('cannot specify --rev and --change at the same time')
5563 raise error.Abort(msg)
5563 raise error.Abort(msg)
5564 elif revs and terse:
5564 elif revs and terse:
5565 msg = _('cannot use --terse with --rev')
5565 msg = _('cannot use --terse with --rev')
5566 raise error.Abort(msg)
5566 raise error.Abort(msg)
5567 elif change:
5567 elif change:
5568 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5568 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5569 ctx2 = scmutil.revsingle(repo, change, None)
5569 ctx2 = scmutil.revsingle(repo, change, None)
5570 ctx1 = ctx2.p1()
5570 ctx1 = ctx2.p1()
5571 else:
5571 else:
5572 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5572 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5573 ctx1, ctx2 = scmutil.revpair(repo, revs)
5573 ctx1, ctx2 = scmutil.revpair(repo, revs)
5574
5574
5575 forcerelativevalue = None
5575 forcerelativevalue = None
5576 if ui.hasconfig('commands', 'status.relative'):
5576 if ui.hasconfig('commands', 'status.relative'):
5577 forcerelativevalue = ui.configbool('commands', 'status.relative')
5577 forcerelativevalue = ui.configbool('commands', 'status.relative')
5578 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5578 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5579 forcerelativevalue=forcerelativevalue)
5579 forcerelativevalue=forcerelativevalue)
5580
5580
5581 if opts.get('print0'):
5581 if opts.get('print0'):
5582 end = '\0'
5582 end = '\0'
5583 else:
5583 else:
5584 end = '\n'
5584 end = '\n'
5585 copy = {}
5585 copy = {}
5586 states = 'modified added removed deleted unknown ignored clean'.split()
5586 states = 'modified added removed deleted unknown ignored clean'.split()
5587 show = [k for k in states if opts.get(k)]
5587 show = [k for k in states if opts.get(k)]
5588 if opts.get('all'):
5588 if opts.get('all'):
5589 show += ui.quiet and (states[:4] + ['clean']) or states
5589 show += ui.quiet and (states[:4] + ['clean']) or states
5590
5590
5591 if not show:
5591 if not show:
5592 if ui.quiet:
5592 if ui.quiet:
5593 show = states[:4]
5593 show = states[:4]
5594 else:
5594 else:
5595 show = states[:5]
5595 show = states[:5]
5596
5596
5597 m = scmutil.match(ctx2, pats, opts)
5597 m = scmutil.match(ctx2, pats, opts)
5598 if terse:
5598 if terse:
5599 # we need to compute clean and unknown to terse
5599 # we need to compute clean and unknown to terse
5600 stat = repo.status(ctx1.node(), ctx2.node(), m,
5600 stat = repo.status(ctx1.node(), ctx2.node(), m,
5601 'ignored' in show or 'i' in terse,
5601 'ignored' in show or 'i' in terse,
5602 clean=True, unknown=True,
5602 clean=True, unknown=True,
5603 listsubrepos=opts.get('subrepos'))
5603 listsubrepos=opts.get('subrepos'))
5604
5604
5605 stat = cmdutil.tersedir(stat, terse)
5605 stat = cmdutil.tersedir(stat, terse)
5606 else:
5606 else:
5607 stat = repo.status(ctx1.node(), ctx2.node(), m,
5607 stat = repo.status(ctx1.node(), ctx2.node(), m,
5608 'ignored' in show, 'clean' in show,
5608 'ignored' in show, 'clean' in show,
5609 'unknown' in show, opts.get('subrepos'))
5609 'unknown' in show, opts.get('subrepos'))
5610
5610
5611 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5611 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5612
5612
5613 if (opts.get('all') or opts.get('copies')
5613 if (opts.get('all') or opts.get('copies')
5614 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5614 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5615 copy = copies.pathcopies(ctx1, ctx2, m)
5615 copy = copies.pathcopies(ctx1, ctx2, m)
5616
5616
5617 ui.pager('status')
5617 ui.pager('status')
5618 fm = ui.formatter('status', opts)
5618 fm = ui.formatter('status', opts)
5619 fmt = '%s' + end
5619 fmt = '%s' + end
5620 showchar = not opts.get('no_status')
5620 showchar = not opts.get('no_status')
5621
5621
5622 for state, char, files in changestates:
5622 for state, char, files in changestates:
5623 if state in show:
5623 if state in show:
5624 label = 'status.' + state
5624 label = 'status.' + state
5625 for f in files:
5625 for f in files:
5626 fm.startitem()
5626 fm.startitem()
5627 fm.context(ctx=ctx2)
5627 fm.context(ctx=ctx2)
5628 fm.data(path=f)
5628 fm.data(path=f)
5629 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5629 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5630 fm.plain(fmt % uipathfn(f), label=label)
5630 fm.plain(fmt % uipathfn(f), label=label)
5631 if f in copy:
5631 if f in copy:
5632 fm.data(source=copy[f])
5632 fm.data(source=copy[f])
5633 fm.plain((' %s' + end) % uipathfn(copy[f]),
5633 fm.plain((' %s' + end) % uipathfn(copy[f]),
5634 label='status.copied')
5634 label='status.copied')
5635
5635
5636 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5636 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5637 and not ui.plain()):
5637 and not ui.plain()):
5638 cmdutil.morestatus(repo, fm)
5638 cmdutil.morestatus(repo, fm)
5639 fm.end()
5639 fm.end()
5640
5640
5641 @command('summary|sum',
5641 @command('summary|sum',
5642 [('', 'remote', None, _('check for push and pull'))],
5642 [('', 'remote', None, _('check for push and pull'))],
5643 '[--remote]',
5643 '[--remote]',
5644 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5644 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5645 helpbasic=True,
5645 helpbasic=True,
5646 intents={INTENT_READONLY})
5646 intents={INTENT_READONLY})
5647 def summary(ui, repo, **opts):
5647 def summary(ui, repo, **opts):
5648 """summarize working directory state
5648 """summarize working directory state
5649
5649
5650 This generates a brief summary of the working directory state,
5650 This generates a brief summary of the working directory state,
5651 including parents, branch, commit status, phase and available updates.
5651 including parents, branch, commit status, phase and available updates.
5652
5652
5653 With the --remote option, this will check the default paths for
5653 With the --remote option, this will check the default paths for
5654 incoming and outgoing changes. This can be time-consuming.
5654 incoming and outgoing changes. This can be time-consuming.
5655
5655
5656 Returns 0 on success.
5656 Returns 0 on success.
5657 """
5657 """
5658
5658
5659 opts = pycompat.byteskwargs(opts)
5659 opts = pycompat.byteskwargs(opts)
5660 ui.pager('summary')
5660 ui.pager('summary')
5661 ctx = repo[None]
5661 ctx = repo[None]
5662 parents = ctx.parents()
5662 parents = ctx.parents()
5663 pnode = parents[0].node()
5663 pnode = parents[0].node()
5664 marks = []
5664 marks = []
5665
5665
5666 try:
5666 try:
5667 ms = mergemod.mergestate.read(repo)
5667 ms = mergemod.mergestate.read(repo)
5668 except error.UnsupportedMergeRecords as e:
5668 except error.UnsupportedMergeRecords as e:
5669 s = ' '.join(e.recordtypes)
5669 s = ' '.join(e.recordtypes)
5670 ui.warn(
5670 ui.warn(
5671 _('warning: merge state has unsupported record types: %s\n') % s)
5671 _('warning: merge state has unsupported record types: %s\n') % s)
5672 unresolved = []
5672 unresolved = []
5673 else:
5673 else:
5674 unresolved = list(ms.unresolved())
5674 unresolved = list(ms.unresolved())
5675
5675
5676 for p in parents:
5676 for p in parents:
5677 # label with log.changeset (instead of log.parent) since this
5677 # label with log.changeset (instead of log.parent) since this
5678 # shows a working directory parent *changeset*:
5678 # shows a working directory parent *changeset*:
5679 # i18n: column positioning for "hg summary"
5679 # i18n: column positioning for "hg summary"
5680 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5680 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5681 label=logcmdutil.changesetlabels(p))
5681 label=logcmdutil.changesetlabels(p))
5682 ui.write(' '.join(p.tags()), label='log.tag')
5682 ui.write(' '.join(p.tags()), label='log.tag')
5683 if p.bookmarks():
5683 if p.bookmarks():
5684 marks.extend(p.bookmarks())
5684 marks.extend(p.bookmarks())
5685 if p.rev() == -1:
5685 if p.rev() == -1:
5686 if not len(repo):
5686 if not len(repo):
5687 ui.write(_(' (empty repository)'))
5687 ui.write(_(' (empty repository)'))
5688 else:
5688 else:
5689 ui.write(_(' (no revision checked out)'))
5689 ui.write(_(' (no revision checked out)'))
5690 if p.obsolete():
5690 if p.obsolete():
5691 ui.write(_(' (obsolete)'))
5691 ui.write(_(' (obsolete)'))
5692 if p.isunstable():
5692 if p.isunstable():
5693 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5693 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5694 for instability in p.instabilities())
5694 for instability in p.instabilities())
5695 ui.write(' ('
5695 ui.write(' ('
5696 + ', '.join(instabilities)
5696 + ', '.join(instabilities)
5697 + ')')
5697 + ')')
5698 ui.write('\n')
5698 ui.write('\n')
5699 if p.description():
5699 if p.description():
5700 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5700 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5701 label='log.summary')
5701 label='log.summary')
5702
5702
5703 branch = ctx.branch()
5703 branch = ctx.branch()
5704 bheads = repo.branchheads(branch)
5704 bheads = repo.branchheads(branch)
5705 # i18n: column positioning for "hg summary"
5705 # i18n: column positioning for "hg summary"
5706 m = _('branch: %s\n') % branch
5706 m = _('branch: %s\n') % branch
5707 if branch != 'default':
5707 if branch != 'default':
5708 ui.write(m, label='log.branch')
5708 ui.write(m, label='log.branch')
5709 else:
5709 else:
5710 ui.status(m, label='log.branch')
5710 ui.status(m, label='log.branch')
5711
5711
5712 if marks:
5712 if marks:
5713 active = repo._activebookmark
5713 active = repo._activebookmark
5714 # i18n: column positioning for "hg summary"
5714 # i18n: column positioning for "hg summary"
5715 ui.write(_('bookmarks:'), label='log.bookmark')
5715 ui.write(_('bookmarks:'), label='log.bookmark')
5716 if active is not None:
5716 if active is not None:
5717 if active in marks:
5717 if active in marks:
5718 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5718 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5719 marks.remove(active)
5719 marks.remove(active)
5720 else:
5720 else:
5721 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5721 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5722 for m in marks:
5722 for m in marks:
5723 ui.write(' ' + m, label='log.bookmark')
5723 ui.write(' ' + m, label='log.bookmark')
5724 ui.write('\n', label='log.bookmark')
5724 ui.write('\n', label='log.bookmark')
5725
5725
5726 status = repo.status(unknown=True)
5726 status = repo.status(unknown=True)
5727
5727
5728 c = repo.dirstate.copies()
5728 c = repo.dirstate.copies()
5729 copied, renamed = [], []
5729 copied, renamed = [], []
5730 for d, s in c.iteritems():
5730 for d, s in c.iteritems():
5731 if s in status.removed:
5731 if s in status.removed:
5732 status.removed.remove(s)
5732 status.removed.remove(s)
5733 renamed.append(d)
5733 renamed.append(d)
5734 else:
5734 else:
5735 copied.append(d)
5735 copied.append(d)
5736 if d in status.added:
5736 if d in status.added:
5737 status.added.remove(d)
5737 status.added.remove(d)
5738
5738
5739 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5739 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5740
5740
5741 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5741 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5742 (ui.label(_('%d added'), 'status.added'), status.added),
5742 (ui.label(_('%d added'), 'status.added'), status.added),
5743 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5743 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5744 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5744 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5745 (ui.label(_('%d copied'), 'status.copied'), copied),
5745 (ui.label(_('%d copied'), 'status.copied'), copied),
5746 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5746 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5747 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5747 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5748 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5748 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5749 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5749 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5750 t = []
5750 t = []
5751 for l, s in labels:
5751 for l, s in labels:
5752 if s:
5752 if s:
5753 t.append(l % len(s))
5753 t.append(l % len(s))
5754
5754
5755 t = ', '.join(t)
5755 t = ', '.join(t)
5756 cleanworkdir = False
5756 cleanworkdir = False
5757
5757
5758 if repo.vfs.exists('graftstate'):
5758 if repo.vfs.exists('graftstate'):
5759 t += _(' (graft in progress)')
5759 t += _(' (graft in progress)')
5760 if repo.vfs.exists('updatestate'):
5760 if repo.vfs.exists('updatestate'):
5761 t += _(' (interrupted update)')
5761 t += _(' (interrupted update)')
5762 elif len(parents) > 1:
5762 elif len(parents) > 1:
5763 t += _(' (merge)')
5763 t += _(' (merge)')
5764 elif branch != parents[0].branch():
5764 elif branch != parents[0].branch():
5765 t += _(' (new branch)')
5765 t += _(' (new branch)')
5766 elif (parents[0].closesbranch() and
5766 elif (parents[0].closesbranch() and
5767 pnode in repo.branchheads(branch, closed=True)):
5767 pnode in repo.branchheads(branch, closed=True)):
5768 t += _(' (head closed)')
5768 t += _(' (head closed)')
5769 elif not (status.modified or status.added or status.removed or renamed or
5769 elif not (status.modified or status.added or status.removed or renamed or
5770 copied or subs):
5770 copied or subs):
5771 t += _(' (clean)')
5771 t += _(' (clean)')
5772 cleanworkdir = True
5772 cleanworkdir = True
5773 elif pnode not in bheads:
5773 elif pnode not in bheads:
5774 t += _(' (new branch head)')
5774 t += _(' (new branch head)')
5775
5775
5776 if parents:
5776 if parents:
5777 pendingphase = max(p.phase() for p in parents)
5777 pendingphase = max(p.phase() for p in parents)
5778 else:
5778 else:
5779 pendingphase = phases.public
5779 pendingphase = phases.public
5780
5780
5781 if pendingphase > phases.newcommitphase(ui):
5781 if pendingphase > phases.newcommitphase(ui):
5782 t += ' (%s)' % phases.phasenames[pendingphase]
5782 t += ' (%s)' % phases.phasenames[pendingphase]
5783
5783
5784 if cleanworkdir:
5784 if cleanworkdir:
5785 # i18n: column positioning for "hg summary"
5785 # i18n: column positioning for "hg summary"
5786 ui.status(_('commit: %s\n') % t.strip())
5786 ui.status(_('commit: %s\n') % t.strip())
5787 else:
5787 else:
5788 # i18n: column positioning for "hg summary"
5788 # i18n: column positioning for "hg summary"
5789 ui.write(_('commit: %s\n') % t.strip())
5789 ui.write(_('commit: %s\n') % t.strip())
5790
5790
5791 # all ancestors of branch heads - all ancestors of parent = new csets
5791 # all ancestors of branch heads - all ancestors of parent = new csets
5792 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5792 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5793 bheads))
5793 bheads))
5794
5794
5795 if new == 0:
5795 if new == 0:
5796 # i18n: column positioning for "hg summary"
5796 # i18n: column positioning for "hg summary"
5797 ui.status(_('update: (current)\n'))
5797 ui.status(_('update: (current)\n'))
5798 elif pnode not in bheads:
5798 elif pnode not in bheads:
5799 # i18n: column positioning for "hg summary"
5799 # i18n: column positioning for "hg summary"
5800 ui.write(_('update: %d new changesets (update)\n') % new)
5800 ui.write(_('update: %d new changesets (update)\n') % new)
5801 else:
5801 else:
5802 # i18n: column positioning for "hg summary"
5802 # i18n: column positioning for "hg summary"
5803 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5803 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5804 (new, len(bheads)))
5804 (new, len(bheads)))
5805
5805
5806 t = []
5806 t = []
5807 draft = len(repo.revs('draft()'))
5807 draft = len(repo.revs('draft()'))
5808 if draft:
5808 if draft:
5809 t.append(_('%d draft') % draft)
5809 t.append(_('%d draft') % draft)
5810 secret = len(repo.revs('secret()'))
5810 secret = len(repo.revs('secret()'))
5811 if secret:
5811 if secret:
5812 t.append(_('%d secret') % secret)
5812 t.append(_('%d secret') % secret)
5813
5813
5814 if draft or secret:
5814 if draft or secret:
5815 ui.status(_('phases: %s\n') % ', '.join(t))
5815 ui.status(_('phases: %s\n') % ', '.join(t))
5816
5816
5817 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5817 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5818 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5818 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5819 numtrouble = len(repo.revs(trouble + "()"))
5819 numtrouble = len(repo.revs(trouble + "()"))
5820 # We write all the possibilities to ease translation
5820 # We write all the possibilities to ease translation
5821 troublemsg = {
5821 troublemsg = {
5822 "orphan": _("orphan: %d changesets"),
5822 "orphan": _("orphan: %d changesets"),
5823 "contentdivergent": _("content-divergent: %d changesets"),
5823 "contentdivergent": _("content-divergent: %d changesets"),
5824 "phasedivergent": _("phase-divergent: %d changesets"),
5824 "phasedivergent": _("phase-divergent: %d changesets"),
5825 }
5825 }
5826 if numtrouble > 0:
5826 if numtrouble > 0:
5827 ui.status(troublemsg[trouble] % numtrouble + "\n")
5827 ui.status(troublemsg[trouble] % numtrouble + "\n")
5828
5828
5829 cmdutil.summaryhooks(ui, repo)
5829 cmdutil.summaryhooks(ui, repo)
5830
5830
5831 if opts.get('remote'):
5831 if opts.get('remote'):
5832 needsincoming, needsoutgoing = True, True
5832 needsincoming, needsoutgoing = True, True
5833 else:
5833 else:
5834 needsincoming, needsoutgoing = False, False
5834 needsincoming, needsoutgoing = False, False
5835 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5835 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5836 if i:
5836 if i:
5837 needsincoming = True
5837 needsincoming = True
5838 if o:
5838 if o:
5839 needsoutgoing = True
5839 needsoutgoing = True
5840 if not needsincoming and not needsoutgoing:
5840 if not needsincoming and not needsoutgoing:
5841 return
5841 return
5842
5842
5843 def getincoming():
5843 def getincoming():
5844 source, branches = hg.parseurl(ui.expandpath('default'))
5844 source, branches = hg.parseurl(ui.expandpath('default'))
5845 sbranch = branches[0]
5845 sbranch = branches[0]
5846 try:
5846 try:
5847 other = hg.peer(repo, {}, source)
5847 other = hg.peer(repo, {}, source)
5848 except error.RepoError:
5848 except error.RepoError:
5849 if opts.get('remote'):
5849 if opts.get('remote'):
5850 raise
5850 raise
5851 return source, sbranch, None, None, None
5851 return source, sbranch, None, None, None
5852 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5852 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5853 if revs:
5853 if revs:
5854 revs = [other.lookup(rev) for rev in revs]
5854 revs = [other.lookup(rev) for rev in revs]
5855 ui.debug('comparing with %s\n' % util.hidepassword(source))
5855 ui.debug('comparing with %s\n' % util.hidepassword(source))
5856 repo.ui.pushbuffer()
5856 repo.ui.pushbuffer()
5857 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5857 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5858 repo.ui.popbuffer()
5858 repo.ui.popbuffer()
5859 return source, sbranch, other, commoninc, commoninc[1]
5859 return source, sbranch, other, commoninc, commoninc[1]
5860
5860
5861 if needsincoming:
5861 if needsincoming:
5862 source, sbranch, sother, commoninc, incoming = getincoming()
5862 source, sbranch, sother, commoninc, incoming = getincoming()
5863 else:
5863 else:
5864 source = sbranch = sother = commoninc = incoming = None
5864 source = sbranch = sother = commoninc = incoming = None
5865
5865
5866 def getoutgoing():
5866 def getoutgoing():
5867 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5867 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5868 dbranch = branches[0]
5868 dbranch = branches[0]
5869 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5869 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5870 if source != dest:
5870 if source != dest:
5871 try:
5871 try:
5872 dother = hg.peer(repo, {}, dest)
5872 dother = hg.peer(repo, {}, dest)
5873 except error.RepoError:
5873 except error.RepoError:
5874 if opts.get('remote'):
5874 if opts.get('remote'):
5875 raise
5875 raise
5876 return dest, dbranch, None, None
5876 return dest, dbranch, None, None
5877 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5877 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5878 elif sother is None:
5878 elif sother is None:
5879 # there is no explicit destination peer, but source one is invalid
5879 # there is no explicit destination peer, but source one is invalid
5880 return dest, dbranch, None, None
5880 return dest, dbranch, None, None
5881 else:
5881 else:
5882 dother = sother
5882 dother = sother
5883 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5883 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5884 common = None
5884 common = None
5885 else:
5885 else:
5886 common = commoninc
5886 common = commoninc
5887 if revs:
5887 if revs:
5888 revs = [repo.lookup(rev) for rev in revs]
5888 revs = [repo.lookup(rev) for rev in revs]
5889 repo.ui.pushbuffer()
5889 repo.ui.pushbuffer()
5890 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5890 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5891 commoninc=common)
5891 commoninc=common)
5892 repo.ui.popbuffer()
5892 repo.ui.popbuffer()
5893 return dest, dbranch, dother, outgoing
5893 return dest, dbranch, dother, outgoing
5894
5894
5895 if needsoutgoing:
5895 if needsoutgoing:
5896 dest, dbranch, dother, outgoing = getoutgoing()
5896 dest, dbranch, dother, outgoing = getoutgoing()
5897 else:
5897 else:
5898 dest = dbranch = dother = outgoing = None
5898 dest = dbranch = dother = outgoing = None
5899
5899
5900 if opts.get('remote'):
5900 if opts.get('remote'):
5901 t = []
5901 t = []
5902 if incoming:
5902 if incoming:
5903 t.append(_('1 or more incoming'))
5903 t.append(_('1 or more incoming'))
5904 o = outgoing.missing
5904 o = outgoing.missing
5905 if o:
5905 if o:
5906 t.append(_('%d outgoing') % len(o))
5906 t.append(_('%d outgoing') % len(o))
5907 other = dother or sother
5907 other = dother or sother
5908 if 'bookmarks' in other.listkeys('namespaces'):
5908 if 'bookmarks' in other.listkeys('namespaces'):
5909 counts = bookmarks.summary(repo, other)
5909 counts = bookmarks.summary(repo, other)
5910 if counts[0] > 0:
5910 if counts[0] > 0:
5911 t.append(_('%d incoming bookmarks') % counts[0])
5911 t.append(_('%d incoming bookmarks') % counts[0])
5912 if counts[1] > 0:
5912 if counts[1] > 0:
5913 t.append(_('%d outgoing bookmarks') % counts[1])
5913 t.append(_('%d outgoing bookmarks') % counts[1])
5914
5914
5915 if t:
5915 if t:
5916 # i18n: column positioning for "hg summary"
5916 # i18n: column positioning for "hg summary"
5917 ui.write(_('remote: %s\n') % (', '.join(t)))
5917 ui.write(_('remote: %s\n') % (', '.join(t)))
5918 else:
5918 else:
5919 # i18n: column positioning for "hg summary"
5919 # i18n: column positioning for "hg summary"
5920 ui.status(_('remote: (synced)\n'))
5920 ui.status(_('remote: (synced)\n'))
5921
5921
5922 cmdutil.summaryremotehooks(ui, repo, opts,
5922 cmdutil.summaryremotehooks(ui, repo, opts,
5923 ((source, sbranch, sother, commoninc),
5923 ((source, sbranch, sother, commoninc),
5924 (dest, dbranch, dother, outgoing)))
5924 (dest, dbranch, dother, outgoing)))
5925
5925
5926 @command('tag',
5926 @command('tag',
5927 [('f', 'force', None, _('force tag')),
5927 [('f', 'force', None, _('force tag')),
5928 ('l', 'local', None, _('make the tag local')),
5928 ('l', 'local', None, _('make the tag local')),
5929 ('r', 'rev', '', _('revision to tag'), _('REV')),
5929 ('r', 'rev', '', _('revision to tag'), _('REV')),
5930 ('', 'remove', None, _('remove a tag')),
5930 ('', 'remove', None, _('remove a tag')),
5931 # -l/--local is already there, commitopts cannot be used
5931 # -l/--local is already there, commitopts cannot be used
5932 ('e', 'edit', None, _('invoke editor on commit messages')),
5932 ('e', 'edit', None, _('invoke editor on commit messages')),
5933 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5933 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5934 ] + commitopts2,
5934 ] + commitopts2,
5935 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5935 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5936 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5936 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5937 def tag(ui, repo, name1, *names, **opts):
5937 def tag(ui, repo, name1, *names, **opts):
5938 """add one or more tags for the current or given revision
5938 """add one or more tags for the current or given revision
5939
5939
5940 Name a particular revision using <name>.
5940 Name a particular revision using <name>.
5941
5941
5942 Tags are used to name particular revisions of the repository and are
5942 Tags are used to name particular revisions of the repository and are
5943 very useful to compare different revisions, to go back to significant
5943 very useful to compare different revisions, to go back to significant
5944 earlier versions or to mark branch points as releases, etc. Changing
5944 earlier versions or to mark branch points as releases, etc. Changing
5945 an existing tag is normally disallowed; use -f/--force to override.
5945 an existing tag is normally disallowed; use -f/--force to override.
5946
5946
5947 If no revision is given, the parent of the working directory is
5947 If no revision is given, the parent of the working directory is
5948 used.
5948 used.
5949
5949
5950 To facilitate version control, distribution, and merging of tags,
5950 To facilitate version control, distribution, and merging of tags,
5951 they are stored as a file named ".hgtags" which is managed similarly
5951 they are stored as a file named ".hgtags" which is managed similarly
5952 to other project files and can be hand-edited if necessary. This
5952 to other project files and can be hand-edited if necessary. This
5953 also means that tagging creates a new commit. The file
5953 also means that tagging creates a new commit. The file
5954 ".hg/localtags" is used for local tags (not shared among
5954 ".hg/localtags" is used for local tags (not shared among
5955 repositories).
5955 repositories).
5956
5956
5957 Tag commits are usually made at the head of a branch. If the parent
5957 Tag commits are usually made at the head of a branch. If the parent
5958 of the working directory is not a branch head, :hg:`tag` aborts; use
5958 of the working directory is not a branch head, :hg:`tag` aborts; use
5959 -f/--force to force the tag commit to be based on a non-head
5959 -f/--force to force the tag commit to be based on a non-head
5960 changeset.
5960 changeset.
5961
5961
5962 See :hg:`help dates` for a list of formats valid for -d/--date.
5962 See :hg:`help dates` for a list of formats valid for -d/--date.
5963
5963
5964 Since tag names have priority over branch names during revision
5964 Since tag names have priority over branch names during revision
5965 lookup, using an existing branch name as a tag name is discouraged.
5965 lookup, using an existing branch name as a tag name is discouraged.
5966
5966
5967 Returns 0 on success.
5967 Returns 0 on success.
5968 """
5968 """
5969 opts = pycompat.byteskwargs(opts)
5969 opts = pycompat.byteskwargs(opts)
5970 with repo.wlock(), repo.lock():
5970 with repo.wlock(), repo.lock():
5971 rev_ = "."
5971 rev_ = "."
5972 names = [t.strip() for t in (name1,) + names]
5972 names = [t.strip() for t in (name1,) + names]
5973 if len(names) != len(set(names)):
5973 if len(names) != len(set(names)):
5974 raise error.Abort(_('tag names must be unique'))
5974 raise error.Abort(_('tag names must be unique'))
5975 for n in names:
5975 for n in names:
5976 scmutil.checknewlabel(repo, n, 'tag')
5976 scmutil.checknewlabel(repo, n, 'tag')
5977 if not n:
5977 if not n:
5978 raise error.Abort(_('tag names cannot consist entirely of '
5978 raise error.Abort(_('tag names cannot consist entirely of '
5979 'whitespace'))
5979 'whitespace'))
5980 if opts.get('rev') and opts.get('remove'):
5980 if opts.get('rev') and opts.get('remove'):
5981 raise error.Abort(_("--rev and --remove are incompatible"))
5981 raise error.Abort(_("--rev and --remove are incompatible"))
5982 if opts.get('rev'):
5982 if opts.get('rev'):
5983 rev_ = opts['rev']
5983 rev_ = opts['rev']
5984 message = opts.get('message')
5984 message = opts.get('message')
5985 if opts.get('remove'):
5985 if opts.get('remove'):
5986 if opts.get('local'):
5986 if opts.get('local'):
5987 expectedtype = 'local'
5987 expectedtype = 'local'
5988 else:
5988 else:
5989 expectedtype = 'global'
5989 expectedtype = 'global'
5990
5990
5991 for n in names:
5991 for n in names:
5992 if repo.tagtype(n) == 'global':
5992 if repo.tagtype(n) == 'global':
5993 alltags = tagsmod.findglobaltags(ui, repo)
5993 alltags = tagsmod.findglobaltags(ui, repo)
5994 if alltags[n][0] == nullid:
5994 if alltags[n][0] == nullid:
5995 raise error.Abort(_("tag '%s' is already removed") % n)
5995 raise error.Abort(_("tag '%s' is already removed") % n)
5996 if not repo.tagtype(n):
5996 if not repo.tagtype(n):
5997 raise error.Abort(_("tag '%s' does not exist") % n)
5997 raise error.Abort(_("tag '%s' does not exist") % n)
5998 if repo.tagtype(n) != expectedtype:
5998 if repo.tagtype(n) != expectedtype:
5999 if expectedtype == 'global':
5999 if expectedtype == 'global':
6000 raise error.Abort(_("tag '%s' is not a global tag") % n)
6000 raise error.Abort(_("tag '%s' is not a global tag") % n)
6001 else:
6001 else:
6002 raise error.Abort(_("tag '%s' is not a local tag") % n)
6002 raise error.Abort(_("tag '%s' is not a local tag") % n)
6003 rev_ = 'null'
6003 rev_ = 'null'
6004 if not message:
6004 if not message:
6005 # we don't translate commit messages
6005 # we don't translate commit messages
6006 message = 'Removed tag %s' % ', '.join(names)
6006 message = 'Removed tag %s' % ', '.join(names)
6007 elif not opts.get('force'):
6007 elif not opts.get('force'):
6008 for n in names:
6008 for n in names:
6009 if n in repo.tags():
6009 if n in repo.tags():
6010 raise error.Abort(_("tag '%s' already exists "
6010 raise error.Abort(_("tag '%s' already exists "
6011 "(use -f to force)") % n)
6011 "(use -f to force)") % n)
6012 if not opts.get('local'):
6012 if not opts.get('local'):
6013 p1, p2 = repo.dirstate.parents()
6013 p1, p2 = repo.dirstate.parents()
6014 if p2 != nullid:
6014 if p2 != nullid:
6015 raise error.Abort(_('uncommitted merge'))
6015 raise error.Abort(_('uncommitted merge'))
6016 bheads = repo.branchheads()
6016 bheads = repo.branchheads()
6017 if not opts.get('force') and bheads and p1 not in bheads:
6017 if not opts.get('force') and bheads and p1 not in bheads:
6018 raise error.Abort(_('working directory is not at a branch head '
6018 raise error.Abort(_('working directory is not at a branch head '
6019 '(use -f to force)'))
6019 '(use -f to force)'))
6020 node = scmutil.revsingle(repo, rev_).node()
6020 node = scmutil.revsingle(repo, rev_).node()
6021
6021
6022 if not message:
6022 if not message:
6023 # we don't translate commit messages
6023 # we don't translate commit messages
6024 message = ('Added tag %s for changeset %s' %
6024 message = ('Added tag %s for changeset %s' %
6025 (', '.join(names), short(node)))
6025 (', '.join(names), short(node)))
6026
6026
6027 date = opts.get('date')
6027 date = opts.get('date')
6028 if date:
6028 if date:
6029 date = dateutil.parsedate(date)
6029 date = dateutil.parsedate(date)
6030
6030
6031 if opts.get('remove'):
6031 if opts.get('remove'):
6032 editform = 'tag.remove'
6032 editform = 'tag.remove'
6033 else:
6033 else:
6034 editform = 'tag.add'
6034 editform = 'tag.add'
6035 editor = cmdutil.getcommiteditor(editform=editform,
6035 editor = cmdutil.getcommiteditor(editform=editform,
6036 **pycompat.strkwargs(opts))
6036 **pycompat.strkwargs(opts))
6037
6037
6038 # don't allow tagging the null rev
6038 # don't allow tagging the null rev
6039 if (not opts.get('remove') and
6039 if (not opts.get('remove') and
6040 scmutil.revsingle(repo, rev_).rev() == nullrev):
6040 scmutil.revsingle(repo, rev_).rev() == nullrev):
6041 raise error.Abort(_("cannot tag null revision"))
6041 raise error.Abort(_("cannot tag null revision"))
6042
6042
6043 tagsmod.tag(repo, names, node, message, opts.get('local'),
6043 tagsmod.tag(repo, names, node, message, opts.get('local'),
6044 opts.get('user'), date, editor=editor)
6044 opts.get('user'), date, editor=editor)
6045
6045
6046 @command(
6046 @command(
6047 'tags', formatteropts, '',
6047 'tags', formatteropts, '',
6048 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
6048 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
6049 intents={INTENT_READONLY})
6049 intents={INTENT_READONLY})
6050 def tags(ui, repo, **opts):
6050 def tags(ui, repo, **opts):
6051 """list repository tags
6051 """list repository tags
6052
6052
6053 This lists both regular and local tags. When the -v/--verbose
6053 This lists both regular and local tags. When the -v/--verbose
6054 switch is used, a third column "local" is printed for local tags.
6054 switch is used, a third column "local" is printed for local tags.
6055 When the -q/--quiet switch is used, only the tag name is printed.
6055 When the -q/--quiet switch is used, only the tag name is printed.
6056
6056
6057 .. container:: verbose
6057 .. container:: verbose
6058
6058
6059 Template:
6059 Template:
6060
6060
6061 The following keywords are supported in addition to the common template
6061 The following keywords are supported in addition to the common template
6062 keywords and functions such as ``{tag}``. See also
6062 keywords and functions such as ``{tag}``. See also
6063 :hg:`help templates`.
6063 :hg:`help templates`.
6064
6064
6065 :type: String. ``local`` for local tags.
6065 :type: String. ``local`` for local tags.
6066
6066
6067 Returns 0 on success.
6067 Returns 0 on success.
6068 """
6068 """
6069
6069
6070 opts = pycompat.byteskwargs(opts)
6070 opts = pycompat.byteskwargs(opts)
6071 ui.pager('tags')
6071 ui.pager('tags')
6072 fm = ui.formatter('tags', opts)
6072 fm = ui.formatter('tags', opts)
6073 hexfunc = fm.hexfunc
6073 hexfunc = fm.hexfunc
6074
6074
6075 for t, n in reversed(repo.tagslist()):
6075 for t, n in reversed(repo.tagslist()):
6076 hn = hexfunc(n)
6076 hn = hexfunc(n)
6077 label = 'tags.normal'
6077 label = 'tags.normal'
6078 tagtype = ''
6078 tagtype = ''
6079 if repo.tagtype(t) == 'local':
6079 if repo.tagtype(t) == 'local':
6080 label = 'tags.local'
6080 label = 'tags.local'
6081 tagtype = 'local'
6081 tagtype = 'local'
6082
6082
6083 fm.startitem()
6083 fm.startitem()
6084 fm.context(repo=repo)
6084 fm.context(repo=repo)
6085 fm.write('tag', '%s', t, label=label)
6085 fm.write('tag', '%s', t, label=label)
6086 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6086 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6087 fm.condwrite(not ui.quiet, 'rev node', fmt,
6087 fm.condwrite(not ui.quiet, 'rev node', fmt,
6088 repo.changelog.rev(n), hn, label=label)
6088 repo.changelog.rev(n), hn, label=label)
6089 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6089 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6090 tagtype, label=label)
6090 tagtype, label=label)
6091 fm.plain('\n')
6091 fm.plain('\n')
6092 fm.end()
6092 fm.end()
6093
6093
6094 @command('tip',
6094 @command('tip',
6095 [('p', 'patch', None, _('show patch')),
6095 [('p', 'patch', None, _('show patch')),
6096 ('g', 'git', None, _('use git extended diff format')),
6096 ('g', 'git', None, _('use git extended diff format')),
6097 ] + templateopts,
6097 ] + templateopts,
6098 _('[-p] [-g]'),
6098 _('[-p] [-g]'),
6099 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
6099 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
6100 def tip(ui, repo, **opts):
6100 def tip(ui, repo, **opts):
6101 """show the tip revision (DEPRECATED)
6101 """show the tip revision (DEPRECATED)
6102
6102
6103 The tip revision (usually just called the tip) is the changeset
6103 The tip revision (usually just called the tip) is the changeset
6104 most recently added to the repository (and therefore the most
6104 most recently added to the repository (and therefore the most
6105 recently changed head).
6105 recently changed head).
6106
6106
6107 If you have just made a commit, that commit will be the tip. If
6107 If you have just made a commit, that commit will be the tip. If
6108 you have just pulled changes from another repository, the tip of
6108 you have just pulled changes from another repository, the tip of
6109 that repository becomes the current tip. The "tip" tag is special
6109 that repository becomes the current tip. The "tip" tag is special
6110 and cannot be renamed or assigned to a different changeset.
6110 and cannot be renamed or assigned to a different changeset.
6111
6111
6112 This command is deprecated, please use :hg:`heads` instead.
6112 This command is deprecated, please use :hg:`heads` instead.
6113
6113
6114 Returns 0 on success.
6114 Returns 0 on success.
6115 """
6115 """
6116 opts = pycompat.byteskwargs(opts)
6116 opts = pycompat.byteskwargs(opts)
6117 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
6117 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
6118 displayer.show(repo['tip'])
6118 displayer.show(repo['tip'])
6119 displayer.close()
6119 displayer.close()
6120
6120
6121 @command('unbundle',
6121 @command('unbundle',
6122 [('u', 'update', None,
6122 [('u', 'update', None,
6123 _('update to new branch head if changesets were unbundled'))],
6123 _('update to new branch head if changesets were unbundled'))],
6124 _('[-u] FILE...'),
6124 _('[-u] FILE...'),
6125 helpcategory=command.CATEGORY_IMPORT_EXPORT)
6125 helpcategory=command.CATEGORY_IMPORT_EXPORT)
6126 def unbundle(ui, repo, fname1, *fnames, **opts):
6126 def unbundle(ui, repo, fname1, *fnames, **opts):
6127 """apply one or more bundle files
6127 """apply one or more bundle files
6128
6128
6129 Apply one or more bundle files generated by :hg:`bundle`.
6129 Apply one or more bundle files generated by :hg:`bundle`.
6130
6130
6131 Returns 0 on success, 1 if an update has unresolved files.
6131 Returns 0 on success, 1 if an update has unresolved files.
6132 """
6132 """
6133 fnames = (fname1,) + fnames
6133 fnames = (fname1,) + fnames
6134
6134
6135 with repo.lock():
6135 with repo.lock():
6136 for fname in fnames:
6136 for fname in fnames:
6137 f = hg.openpath(ui, fname)
6137 f = hg.openpath(ui, fname)
6138 gen = exchange.readbundle(ui, f, fname)
6138 gen = exchange.readbundle(ui, f, fname)
6139 if isinstance(gen, streamclone.streamcloneapplier):
6139 if isinstance(gen, streamclone.streamcloneapplier):
6140 raise error.Abort(
6140 raise error.Abort(
6141 _('packed bundles cannot be applied with '
6141 _('packed bundles cannot be applied with '
6142 '"hg unbundle"'),
6142 '"hg unbundle"'),
6143 hint=_('use "hg debugapplystreamclonebundle"'))
6143 hint=_('use "hg debugapplystreamclonebundle"'))
6144 url = 'bundle:' + fname
6144 url = 'bundle:' + fname
6145 try:
6145 try:
6146 txnname = 'unbundle'
6146 txnname = 'unbundle'
6147 if not isinstance(gen, bundle2.unbundle20):
6147 if not isinstance(gen, bundle2.unbundle20):
6148 txnname = 'unbundle\n%s' % util.hidepassword(url)
6148 txnname = 'unbundle\n%s' % util.hidepassword(url)
6149 with repo.transaction(txnname) as tr:
6149 with repo.transaction(txnname) as tr:
6150 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6150 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6151 url=url)
6151 url=url)
6152 except error.BundleUnknownFeatureError as exc:
6152 except error.BundleUnknownFeatureError as exc:
6153 raise error.Abort(
6153 raise error.Abort(
6154 _('%s: unknown bundle feature, %s') % (fname, exc),
6154 _('%s: unknown bundle feature, %s') % (fname, exc),
6155 hint=_("see https://mercurial-scm.org/"
6155 hint=_("see https://mercurial-scm.org/"
6156 "wiki/BundleFeature for more "
6156 "wiki/BundleFeature for more "
6157 "information"))
6157 "information"))
6158 modheads = bundle2.combinechangegroupresults(op)
6158 modheads = bundle2.combinechangegroupresults(op)
6159
6159
6160 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6160 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6161
6161
6162 @command('unshelve',
6162 @command('unshelve',
6163 [('a', 'abort', None,
6163 [('a', 'abort', None,
6164 _('abort an incomplete unshelve operation')),
6164 _('abort an incomplete unshelve operation')),
6165 ('c', 'continue', None,
6165 ('c', 'continue', None,
6166 _('continue an incomplete unshelve operation')),
6166 _('continue an incomplete unshelve operation')),
6167 ('i', 'interactive', None,
6167 ('i', 'interactive', None,
6168 _('use interactive mode (EXPERIMENTAL)')),
6168 _('use interactive mode (EXPERIMENTAL)')),
6169 ('k', 'keep', None,
6169 ('k', 'keep', None,
6170 _('keep shelve after unshelving')),
6170 _('keep shelve after unshelving')),
6171 ('n', 'name', '',
6171 ('n', 'name', '',
6172 _('restore shelved change with given name'), _('NAME')),
6172 _('restore shelved change with given name'), _('NAME')),
6173 ('t', 'tool', '', _('specify merge tool')),
6173 ('t', 'tool', '', _('specify merge tool')),
6174 ('', 'date', '',
6174 ('', 'date', '',
6175 _('set date for temporary commits (DEPRECATED)'), _('DATE'))],
6175 _('set date for temporary commits (DEPRECATED)'), _('DATE'))],
6176 _('hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
6176 _('hg unshelve [OPTION]... [FILE]... [-n SHELVED]'),
6177 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
6177 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
6178 def unshelve(ui, repo, *shelved, **opts):
6178 def unshelve(ui, repo, *shelved, **opts):
6179 """restore a shelved change to the working directory
6179 """restore a shelved change to the working directory
6180
6180
6181 This command accepts an optional name of a shelved change to
6181 This command accepts an optional name of a shelved change to
6182 restore. If none is given, the most recent shelved change is used.
6182 restore. If none is given, the most recent shelved change is used.
6183
6183
6184 If a shelved change is applied successfully, the bundle that
6184 If a shelved change is applied successfully, the bundle that
6185 contains the shelved changes is moved to a backup location
6185 contains the shelved changes is moved to a backup location
6186 (.hg/shelve-backup).
6186 (.hg/shelve-backup).
6187
6187
6188 Since you can restore a shelved change on top of an arbitrary
6188 Since you can restore a shelved change on top of an arbitrary
6189 commit, it is possible that unshelving will result in a conflict
6189 commit, it is possible that unshelving will result in a conflict
6190 between your changes and the commits you are unshelving onto. If
6190 between your changes and the commits you are unshelving onto. If
6191 this occurs, you must resolve the conflict, then use
6191 this occurs, you must resolve the conflict, then use
6192 ``--continue`` to complete the unshelve operation. (The bundle
6192 ``--continue`` to complete the unshelve operation. (The bundle
6193 will not be moved until you successfully complete the unshelve.)
6193 will not be moved until you successfully complete the unshelve.)
6194
6194
6195 (Alternatively, you can use ``--abort`` to abandon an unshelve
6195 (Alternatively, you can use ``--abort`` to abandon an unshelve
6196 that causes a conflict. This reverts the unshelved changes, and
6196 that causes a conflict. This reverts the unshelved changes, and
6197 leaves the bundle in place.)
6197 leaves the bundle in place.)
6198
6198
6199 If bare shelved change (when no files are specified, without interactive,
6199 If bare shelved change (when no files are specified, without interactive,
6200 include and exclude option) was done on newly created branch it would
6200 include and exclude option) was done on newly created branch it would
6201 restore branch information to the working directory.
6201 restore branch information to the working directory.
6202
6202
6203 After a successful unshelve, the shelved changes are stored in a
6203 After a successful unshelve, the shelved changes are stored in a
6204 backup directory. Only the N most recent backups are kept. N
6204 backup directory. Only the N most recent backups are kept. N
6205 defaults to 10 but can be overridden using the ``shelve.maxbackups``
6205 defaults to 10 but can be overridden using the ``shelve.maxbackups``
6206 configuration option.
6206 configuration option.
6207
6207
6208 .. container:: verbose
6208 .. container:: verbose
6209
6209
6210 Timestamp in seconds is used to decide order of backups. More
6210 Timestamp in seconds is used to decide order of backups. More
6211 than ``maxbackups`` backups are kept, if same timestamp
6211 than ``maxbackups`` backups are kept, if same timestamp
6212 prevents from deciding exact order of them, for safety.
6212 prevents from deciding exact order of them, for safety.
6213
6214 Selected changes can be unshelved with ``--interactive`` flag.
6215 The working directory is updated with the selected changes, and
6216 only the unselected changes remain shelved.
6217 Note: The whole shelve is applied to working directory first before
6218 running interactively. So, this will bring up all the conflicts between
6219 working directory and the shelve, irrespective of which changes will be
6220 unshelved.
6213 """
6221 """
6214 with repo.wlock():
6222 with repo.wlock():
6215 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
6223 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
6216
6224
6217 statemod.addunfinished(
6225 statemod.addunfinished(
6218 'unshelve', fname='shelvedstate', continueflag=True,
6226 'unshelve', fname='shelvedstate', continueflag=True,
6219 abortfunc=shelvemod.hgabortunshelve,
6227 abortfunc=shelvemod.hgabortunshelve,
6220 continuefunc=shelvemod.hgcontinueunshelve,
6228 continuefunc=shelvemod.hgcontinueunshelve,
6221 cmdmsg=_('unshelve already in progress'),
6229 cmdmsg=_('unshelve already in progress'),
6222 )
6230 )
6223
6231
6224 @command('update|up|checkout|co',
6232 @command('update|up|checkout|co',
6225 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6233 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6226 ('c', 'check', None, _('require clean working directory')),
6234 ('c', 'check', None, _('require clean working directory')),
6227 ('m', 'merge', None, _('merge uncommitted changes')),
6235 ('m', 'merge', None, _('merge uncommitted changes')),
6228 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6236 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6229 ('r', 'rev', '', _('revision'), _('REV'))
6237 ('r', 'rev', '', _('revision'), _('REV'))
6230 ] + mergetoolopts,
6238 ] + mergetoolopts,
6231 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6239 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6232 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6240 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6233 helpbasic=True)
6241 helpbasic=True)
6234 def update(ui, repo, node=None, **opts):
6242 def update(ui, repo, node=None, **opts):
6235 """update working directory (or switch revisions)
6243 """update working directory (or switch revisions)
6236
6244
6237 Update the repository's working directory to the specified
6245 Update the repository's working directory to the specified
6238 changeset. If no changeset is specified, update to the tip of the
6246 changeset. If no changeset is specified, update to the tip of the
6239 current named branch and move the active bookmark (see :hg:`help
6247 current named branch and move the active bookmark (see :hg:`help
6240 bookmarks`).
6248 bookmarks`).
6241
6249
6242 Update sets the working directory's parent revision to the specified
6250 Update sets the working directory's parent revision to the specified
6243 changeset (see :hg:`help parents`).
6251 changeset (see :hg:`help parents`).
6244
6252
6245 If the changeset is not a descendant or ancestor of the working
6253 If the changeset is not a descendant or ancestor of the working
6246 directory's parent and there are uncommitted changes, the update is
6254 directory's parent and there are uncommitted changes, the update is
6247 aborted. With the -c/--check option, the working directory is checked
6255 aborted. With the -c/--check option, the working directory is checked
6248 for uncommitted changes; if none are found, the working directory is
6256 for uncommitted changes; if none are found, the working directory is
6249 updated to the specified changeset.
6257 updated to the specified changeset.
6250
6258
6251 .. container:: verbose
6259 .. container:: verbose
6252
6260
6253 The -C/--clean, -c/--check, and -m/--merge options control what
6261 The -C/--clean, -c/--check, and -m/--merge options control what
6254 happens if the working directory contains uncommitted changes.
6262 happens if the working directory contains uncommitted changes.
6255 At most of one of them can be specified.
6263 At most of one of them can be specified.
6256
6264
6257 1. If no option is specified, and if
6265 1. If no option is specified, and if
6258 the requested changeset is an ancestor or descendant of
6266 the requested changeset is an ancestor or descendant of
6259 the working directory's parent, the uncommitted changes
6267 the working directory's parent, the uncommitted changes
6260 are merged into the requested changeset and the merged
6268 are merged into the requested changeset and the merged
6261 result is left uncommitted. If the requested changeset is
6269 result is left uncommitted. If the requested changeset is
6262 not an ancestor or descendant (that is, it is on another
6270 not an ancestor or descendant (that is, it is on another
6263 branch), the update is aborted and the uncommitted changes
6271 branch), the update is aborted and the uncommitted changes
6264 are preserved.
6272 are preserved.
6265
6273
6266 2. With the -m/--merge option, the update is allowed even if the
6274 2. With the -m/--merge option, the update is allowed even if the
6267 requested changeset is not an ancestor or descendant of
6275 requested changeset is not an ancestor or descendant of
6268 the working directory's parent.
6276 the working directory's parent.
6269
6277
6270 3. With the -c/--check option, the update is aborted and the
6278 3. With the -c/--check option, the update is aborted and the
6271 uncommitted changes are preserved.
6279 uncommitted changes are preserved.
6272
6280
6273 4. With the -C/--clean option, uncommitted changes are discarded and
6281 4. With the -C/--clean option, uncommitted changes are discarded and
6274 the working directory is updated to the requested changeset.
6282 the working directory is updated to the requested changeset.
6275
6283
6276 To cancel an uncommitted merge (and lose your changes), use
6284 To cancel an uncommitted merge (and lose your changes), use
6277 :hg:`merge --abort`.
6285 :hg:`merge --abort`.
6278
6286
6279 Use null as the changeset to remove the working directory (like
6287 Use null as the changeset to remove the working directory (like
6280 :hg:`clone -U`).
6288 :hg:`clone -U`).
6281
6289
6282 If you want to revert just one file to an older revision, use
6290 If you want to revert just one file to an older revision, use
6283 :hg:`revert [-r REV] NAME`.
6291 :hg:`revert [-r REV] NAME`.
6284
6292
6285 See :hg:`help dates` for a list of formats valid for -d/--date.
6293 See :hg:`help dates` for a list of formats valid for -d/--date.
6286
6294
6287 Returns 0 on success, 1 if there are unresolved files.
6295 Returns 0 on success, 1 if there are unresolved files.
6288 """
6296 """
6289 rev = opts.get(r'rev')
6297 rev = opts.get(r'rev')
6290 date = opts.get(r'date')
6298 date = opts.get(r'date')
6291 clean = opts.get(r'clean')
6299 clean = opts.get(r'clean')
6292 check = opts.get(r'check')
6300 check = opts.get(r'check')
6293 merge = opts.get(r'merge')
6301 merge = opts.get(r'merge')
6294 if rev and node:
6302 if rev and node:
6295 raise error.Abort(_("please specify just one revision"))
6303 raise error.Abort(_("please specify just one revision"))
6296
6304
6297 if ui.configbool('commands', 'update.requiredest'):
6305 if ui.configbool('commands', 'update.requiredest'):
6298 if not node and not rev and not date:
6306 if not node and not rev and not date:
6299 raise error.Abort(_('you must specify a destination'),
6307 raise error.Abort(_('you must specify a destination'),
6300 hint=_('for example: hg update ".::"'))
6308 hint=_('for example: hg update ".::"'))
6301
6309
6302 if rev is None or rev == '':
6310 if rev is None or rev == '':
6303 rev = node
6311 rev = node
6304
6312
6305 if date and rev is not None:
6313 if date and rev is not None:
6306 raise error.Abort(_("you can't specify a revision and a date"))
6314 raise error.Abort(_("you can't specify a revision and a date"))
6307
6315
6308 if len([x for x in (clean, check, merge) if x]) > 1:
6316 if len([x for x in (clean, check, merge) if x]) > 1:
6309 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6317 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6310 "or -m/--merge"))
6318 "or -m/--merge"))
6311
6319
6312 updatecheck = None
6320 updatecheck = None
6313 if check:
6321 if check:
6314 updatecheck = 'abort'
6322 updatecheck = 'abort'
6315 elif merge:
6323 elif merge:
6316 updatecheck = 'none'
6324 updatecheck = 'none'
6317
6325
6318 with repo.wlock():
6326 with repo.wlock():
6319 cmdutil.clearunfinished(repo)
6327 cmdutil.clearunfinished(repo)
6320 if date:
6328 if date:
6321 rev = cmdutil.finddate(ui, repo, date)
6329 rev = cmdutil.finddate(ui, repo, date)
6322
6330
6323 # if we defined a bookmark, we have to remember the original name
6331 # if we defined a bookmark, we have to remember the original name
6324 brev = rev
6332 brev = rev
6325 if rev:
6333 if rev:
6326 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6334 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6327 ctx = scmutil.revsingle(repo, rev, default=None)
6335 ctx = scmutil.revsingle(repo, rev, default=None)
6328 rev = ctx.rev()
6336 rev = ctx.rev()
6329 hidden = ctx.hidden()
6337 hidden = ctx.hidden()
6330 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6338 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6331 with ui.configoverride(overrides, 'update'):
6339 with ui.configoverride(overrides, 'update'):
6332 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6340 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6333 updatecheck=updatecheck)
6341 updatecheck=updatecheck)
6334 if hidden:
6342 if hidden:
6335 ctxstr = ctx.hex()[:12]
6343 ctxstr = ctx.hex()[:12]
6336 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6344 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6337
6345
6338 if ctx.obsolete():
6346 if ctx.obsolete():
6339 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6347 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6340 ui.warn("(%s)\n" % obsfatemsg)
6348 ui.warn("(%s)\n" % obsfatemsg)
6341 return ret
6349 return ret
6342
6350
6343 @command('verify',
6351 @command('verify',
6344 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6352 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6345 helpcategory=command.CATEGORY_MAINTENANCE)
6353 helpcategory=command.CATEGORY_MAINTENANCE)
6346 def verify(ui, repo, **opts):
6354 def verify(ui, repo, **opts):
6347 """verify the integrity of the repository
6355 """verify the integrity of the repository
6348
6356
6349 Verify the integrity of the current repository.
6357 Verify the integrity of the current repository.
6350
6358
6351 This will perform an extensive check of the repository's
6359 This will perform an extensive check of the repository's
6352 integrity, validating the hashes and checksums of each entry in
6360 integrity, validating the hashes and checksums of each entry in
6353 the changelog, manifest, and tracked files, as well as the
6361 the changelog, manifest, and tracked files, as well as the
6354 integrity of their crosslinks and indices.
6362 integrity of their crosslinks and indices.
6355
6363
6356 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6364 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6357 for more information about recovery from corruption of the
6365 for more information about recovery from corruption of the
6358 repository.
6366 repository.
6359
6367
6360 Returns 0 on success, 1 if errors are encountered.
6368 Returns 0 on success, 1 if errors are encountered.
6361 """
6369 """
6362 opts = pycompat.byteskwargs(opts)
6370 opts = pycompat.byteskwargs(opts)
6363
6371
6364 level = None
6372 level = None
6365 if opts['full']:
6373 if opts['full']:
6366 level = verifymod.VERIFY_FULL
6374 level = verifymod.VERIFY_FULL
6367 return hg.verify(repo, level)
6375 return hg.verify(repo, level)
6368
6376
6369 @command(
6377 @command(
6370 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6378 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6371 norepo=True, intents={INTENT_READONLY})
6379 norepo=True, intents={INTENT_READONLY})
6372 def version_(ui, **opts):
6380 def version_(ui, **opts):
6373 """output version and copyright information
6381 """output version and copyright information
6374
6382
6375 .. container:: verbose
6383 .. container:: verbose
6376
6384
6377 Template:
6385 Template:
6378
6386
6379 The following keywords are supported. See also :hg:`help templates`.
6387 The following keywords are supported. See also :hg:`help templates`.
6380
6388
6381 :extensions: List of extensions.
6389 :extensions: List of extensions.
6382 :ver: String. Version number.
6390 :ver: String. Version number.
6383
6391
6384 And each entry of ``{extensions}`` provides the following sub-keywords
6392 And each entry of ``{extensions}`` provides the following sub-keywords
6385 in addition to ``{ver}``.
6393 in addition to ``{ver}``.
6386
6394
6387 :bundled: Boolean. True if included in the release.
6395 :bundled: Boolean. True if included in the release.
6388 :name: String. Extension name.
6396 :name: String. Extension name.
6389 """
6397 """
6390 opts = pycompat.byteskwargs(opts)
6398 opts = pycompat.byteskwargs(opts)
6391 if ui.verbose:
6399 if ui.verbose:
6392 ui.pager('version')
6400 ui.pager('version')
6393 fm = ui.formatter("version", opts)
6401 fm = ui.formatter("version", opts)
6394 fm.startitem()
6402 fm.startitem()
6395 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6403 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6396 util.version())
6404 util.version())
6397 license = _(
6405 license = _(
6398 "(see https://mercurial-scm.org for more information)\n"
6406 "(see https://mercurial-scm.org for more information)\n"
6399 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6407 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6400 "This is free software; see the source for copying conditions. "
6408 "This is free software; see the source for copying conditions. "
6401 "There is NO\nwarranty; "
6409 "There is NO\nwarranty; "
6402 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6410 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6403 )
6411 )
6404 if not ui.quiet:
6412 if not ui.quiet:
6405 fm.plain(license)
6413 fm.plain(license)
6406
6414
6407 if ui.verbose:
6415 if ui.verbose:
6408 fm.plain(_("\nEnabled extensions:\n\n"))
6416 fm.plain(_("\nEnabled extensions:\n\n"))
6409 # format names and versions into columns
6417 # format names and versions into columns
6410 names = []
6418 names = []
6411 vers = []
6419 vers = []
6412 isinternals = []
6420 isinternals = []
6413 for name, module in extensions.extensions():
6421 for name, module in extensions.extensions():
6414 names.append(name)
6422 names.append(name)
6415 vers.append(extensions.moduleversion(module) or None)
6423 vers.append(extensions.moduleversion(module) or None)
6416 isinternals.append(extensions.ismoduleinternal(module))
6424 isinternals.append(extensions.ismoduleinternal(module))
6417 fn = fm.nested("extensions", tmpl='{name}\n')
6425 fn = fm.nested("extensions", tmpl='{name}\n')
6418 if names:
6426 if names:
6419 namefmt = " %%-%ds " % max(len(n) for n in names)
6427 namefmt = " %%-%ds " % max(len(n) for n in names)
6420 places = [_("external"), _("internal")]
6428 places = [_("external"), _("internal")]
6421 for n, v, p in zip(names, vers, isinternals):
6429 for n, v, p in zip(names, vers, isinternals):
6422 fn.startitem()
6430 fn.startitem()
6423 fn.condwrite(ui.verbose, "name", namefmt, n)
6431 fn.condwrite(ui.verbose, "name", namefmt, n)
6424 if ui.verbose:
6432 if ui.verbose:
6425 fn.plain("%s " % places[p])
6433 fn.plain("%s " % places[p])
6426 fn.data(bundled=p)
6434 fn.data(bundled=p)
6427 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6435 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6428 if ui.verbose:
6436 if ui.verbose:
6429 fn.plain("\n")
6437 fn.plain("\n")
6430 fn.end()
6438 fn.end()
6431 fm.end()
6439 fm.end()
6432
6440
6433 def loadcmdtable(ui, name, cmdtable):
6441 def loadcmdtable(ui, name, cmdtable):
6434 """Load command functions from specified cmdtable
6442 """Load command functions from specified cmdtable
6435 """
6443 """
6436 overrides = [cmd for cmd in cmdtable if cmd in table]
6444 overrides = [cmd for cmd in cmdtable if cmd in table]
6437 if overrides:
6445 if overrides:
6438 ui.warn(_("extension '%s' overrides commands: %s\n")
6446 ui.warn(_("extension '%s' overrides commands: %s\n")
6439 % (name, " ".join(overrides)))
6447 % (name, " ".join(overrides)))
6440 table.update(cmdtable)
6448 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now