##// END OF EJS Templates
annotate: remove dead code to not convert path to relative path...
Yuya Nishihara -
r40753:92c57468 default
parent child Browse files
Show More
@@ -1,6210 +1,6209
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 repair,
56 repair,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
63 tags as tagsmod,
63 tags as tagsmod,
64 templatekw,
64 templatekw,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
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('add',
134 @command('add',
135 walkopts + subrepoopts + dryrunopts,
135 walkopts + subrepoopts + dryrunopts,
136 _('[OPTION]... [FILE]...'),
136 _('[OPTION]... [FILE]...'),
137 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
137 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
138 helpbasic=True, inferrepo=True)
138 helpbasic=True, inferrepo=True)
139 def add(ui, repo, *pats, **opts):
139 def add(ui, repo, *pats, **opts):
140 """add the specified files on the next commit
140 """add the specified files on the next commit
141
141
142 Schedule files to be version controlled and added to the
142 Schedule files to be version controlled and added to the
143 repository.
143 repository.
144
144
145 The files will be added to the repository at the next commit. To
145 The files will be added to the repository at the next commit. To
146 undo an add before that, see :hg:`forget`.
146 undo an add before that, see :hg:`forget`.
147
147
148 If no names are given, add all files to the repository (except
148 If no names are given, add all files to the repository (except
149 files matching ``.hgignore``).
149 files matching ``.hgignore``).
150
150
151 .. container:: verbose
151 .. container:: verbose
152
152
153 Examples:
153 Examples:
154
154
155 - New (unknown) files are added
155 - New (unknown) files are added
156 automatically by :hg:`add`::
156 automatically by :hg:`add`::
157
157
158 $ ls
158 $ ls
159 foo.c
159 foo.c
160 $ hg status
160 $ hg status
161 ? foo.c
161 ? foo.c
162 $ hg add
162 $ hg add
163 adding foo.c
163 adding foo.c
164 $ hg status
164 $ hg status
165 A foo.c
165 A foo.c
166
166
167 - Specific files to be added can be specified::
167 - Specific files to be added can be specified::
168
168
169 $ ls
169 $ ls
170 bar.c foo.c
170 bar.c foo.c
171 $ hg status
171 $ hg status
172 ? bar.c
172 ? bar.c
173 ? foo.c
173 ? foo.c
174 $ hg add bar.c
174 $ hg add bar.c
175 $ hg status
175 $ hg status
176 A bar.c
176 A bar.c
177 ? foo.c
177 ? foo.c
178
178
179 Returns 0 if all files are successfully added.
179 Returns 0 if all files are successfully added.
180 """
180 """
181
181
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
184 return rejected and 1 or 0
184 return rejected and 1 or 0
185
185
186 @command('addremove',
186 @command('addremove',
187 similarityopts + subrepoopts + walkopts + dryrunopts,
187 similarityopts + subrepoopts + walkopts + dryrunopts,
188 _('[OPTION]... [FILE]...'),
188 _('[OPTION]... [FILE]...'),
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
190 inferrepo=True)
190 inferrepo=True)
191 def addremove(ui, repo, *pats, **opts):
191 def addremove(ui, repo, *pats, **opts):
192 """add all new files, delete all missing files
192 """add all new files, delete all missing files
193
193
194 Add all new files and remove all missing files from the
194 Add all new files and remove all missing files from the
195 repository.
195 repository.
196
196
197 Unless names are given, new files are ignored if they match any of
197 Unless names are given, new files are ignored if they match any of
198 the patterns in ``.hgignore``. As with add, these changes take
198 the patterns in ``.hgignore``. As with add, these changes take
199 effect at the next commit.
199 effect at the next commit.
200
200
201 Use the -s/--similarity option to detect renamed files. This
201 Use the -s/--similarity option to detect renamed files. This
202 option takes a percentage between 0 (disabled) and 100 (files must
202 option takes a percentage between 0 (disabled) and 100 (files must
203 be identical) as its parameter. With a parameter greater than 0,
203 be identical) as its parameter. With a parameter greater than 0,
204 this compares every removed file with every added file and records
204 this compares every removed file with every added file and records
205 those similar enough as renames. Detecting renamed files this way
205 those similar enough as renames. Detecting renamed files this way
206 can be expensive. After using this option, :hg:`status -C` can be
206 can be expensive. After using this option, :hg:`status -C` can be
207 used to check which files were identified as moved or renamed. If
207 used to check which files were identified as moved or renamed. If
208 not specified, -s/--similarity defaults to 100 and only renames of
208 not specified, -s/--similarity defaults to 100 and only renames of
209 identical files are detected.
209 identical files are detected.
210
210
211 .. container:: verbose
211 .. container:: verbose
212
212
213 Examples:
213 Examples:
214
214
215 - A number of files (bar.c and foo.c) are new,
215 - A number of files (bar.c and foo.c) are new,
216 while foobar.c has been removed (without using :hg:`remove`)
216 while foobar.c has been removed (without using :hg:`remove`)
217 from the repository::
217 from the repository::
218
218
219 $ ls
219 $ ls
220 bar.c foo.c
220 bar.c foo.c
221 $ hg status
221 $ hg status
222 ! foobar.c
222 ! foobar.c
223 ? bar.c
223 ? bar.c
224 ? foo.c
224 ? foo.c
225 $ hg addremove
225 $ hg addremove
226 adding bar.c
226 adding bar.c
227 adding foo.c
227 adding foo.c
228 removing foobar.c
228 removing foobar.c
229 $ hg status
229 $ hg status
230 A bar.c
230 A bar.c
231 A foo.c
231 A foo.c
232 R foobar.c
232 R foobar.c
233
233
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
235 Afterwards, it was edited slightly::
235 Afterwards, it was edited slightly::
236
236
237 $ ls
237 $ ls
238 foo.c
238 foo.c
239 $ hg status
239 $ hg status
240 ! foobar.c
240 ! foobar.c
241 ? foo.c
241 ? foo.c
242 $ hg addremove --similarity 90
242 $ hg addremove --similarity 90
243 removing foobar.c
243 removing foobar.c
244 adding foo.c
244 adding foo.c
245 recording removal of foobar.c as rename to foo.c (94% similar)
245 recording removal of foobar.c as rename to foo.c (94% similar)
246 $ hg status -C
246 $ hg status -C
247 A foo.c
247 A foo.c
248 foobar.c
248 foobar.c
249 R foobar.c
249 R foobar.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253 opts = pycompat.byteskwargs(opts)
253 opts = pycompat.byteskwargs(opts)
254 if not opts.get('similarity'):
254 if not opts.get('similarity'):
255 opts['similarity'] = '100'
255 opts['similarity'] = '100'
256 matcher = scmutil.match(repo[None], pats, opts)
256 matcher = scmutil.match(repo[None], pats, opts)
257 return scmutil.addremove(repo, matcher, "", opts)
257 return scmutil.addremove(repo, matcher, "", opts)
258
258
259 @command('annotate|blame',
259 @command('annotate|blame',
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
261 ('', 'follow', None,
261 ('', 'follow', None,
262 _('follow copies/renames and list the filename (DEPRECATED)')),
262 _('follow copies/renames and list the filename (DEPRECATED)')),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
264 ('a', 'text', None, _('treat all files as text')),
264 ('a', 'text', None, _('treat all files as text')),
265 ('u', 'user', None, _('list the author (long with -v)')),
265 ('u', 'user', None, _('list the author (long with -v)')),
266 ('f', 'file', None, _('list the filename')),
266 ('f', 'file', None, _('list the filename')),
267 ('d', 'date', None, _('list the date (short with -q)')),
267 ('d', 'date', None, _('list the date (short with -q)')),
268 ('n', 'number', None, _('list the revision number (default)')),
268 ('n', 'number', None, _('list the revision number (default)')),
269 ('c', 'changeset', None, _('list the changeset')),
269 ('c', 'changeset', None, _('list the changeset')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
272 ] + diffwsopts + walkopts + formatteropts,
272 ] + diffwsopts + walkopts + formatteropts,
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
275 helpbasic=True, inferrepo=True)
275 helpbasic=True, inferrepo=True)
276 def annotate(ui, repo, *pats, **opts):
276 def annotate(ui, repo, *pats, **opts):
277 """show changeset information by line for each file
277 """show changeset information by line for each file
278
278
279 List changes in files, showing the revision id responsible for
279 List changes in files, showing the revision id responsible for
280 each line.
280 each line.
281
281
282 This command is useful for discovering when a change was made and
282 This command is useful for discovering when a change was made and
283 by whom.
283 by whom.
284
284
285 If you include --file, --user, or --date, the revision number is
285 If you include --file, --user, or --date, the revision number is
286 suppressed unless you also include --number.
286 suppressed unless you also include --number.
287
287
288 Without the -a/--text option, annotate will avoid processing files
288 Without the -a/--text option, annotate will avoid processing files
289 it detects as binary. With -a, annotate will annotate the file
289 it detects as binary. With -a, annotate will annotate the file
290 anyway, although the results will probably be neither useful
290 anyway, although the results will probably be neither useful
291 nor desirable.
291 nor desirable.
292
292
293 .. container:: verbose
293 .. container:: verbose
294
294
295 Template:
295 Template:
296
296
297 The following keywords are supported in addition to the common template
297 The following keywords are supported in addition to the common template
298 keywords and functions. See also :hg:`help templates`.
298 keywords and functions. See also :hg:`help templates`.
299
299
300 :lines: List of lines with annotation data.
300 :lines: List of lines with annotation data.
301 :path: String. Repository-absolute path of the specified file.
301 :path: String. Repository-absolute path of the specified file.
302
302
303 And each entry of ``{lines}`` provides the following sub-keywords in
303 And each entry of ``{lines}`` provides the following sub-keywords in
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
305
305
306 :line: String. Line content.
306 :line: String. Line content.
307 :lineno: Integer. Line number at that revision.
307 :lineno: Integer. Line number at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
309
309
310 See :hg:`help templates.operators` for the list expansion syntax.
310 See :hg:`help templates.operators` for the list expansion syntax.
311
311
312 Returns 0 on success.
312 Returns 0 on success.
313 """
313 """
314 opts = pycompat.byteskwargs(opts)
314 opts = pycompat.byteskwargs(opts)
315 if not pats:
315 if not pats:
316 raise error.Abort(_('at least one filename or pattern is required'))
316 raise error.Abort(_('at least one filename or pattern is required'))
317
317
318 if opts.get('follow'):
318 if opts.get('follow'):
319 # --follow is deprecated and now just an alias for -f/--file
319 # --follow is deprecated and now just an alias for -f/--file
320 # to mimic the behavior of Mercurial before version 1.5
320 # to mimic the behavior of Mercurial before version 1.5
321 opts['file'] = True
321 opts['file'] = True
322
322
323 if (not opts.get('user') and not opts.get('changeset')
323 if (not opts.get('user') and not opts.get('changeset')
324 and not opts.get('date') and not opts.get('file')):
324 and not opts.get('date') and not opts.get('file')):
325 opts['number'] = True
325 opts['number'] = True
326
326
327 linenumber = opts.get('line_number') is not None
327 linenumber = opts.get('line_number') is not None
328 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
328 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
329 raise error.Abort(_('at least one of -n/-c is required for -l'))
329 raise error.Abort(_('at least one of -n/-c is required for -l'))
330
330
331 rev = opts.get('rev')
331 rev = opts.get('rev')
332 if rev:
332 if rev:
333 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
333 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
334 ctx = scmutil.revsingle(repo, rev)
334 ctx = scmutil.revsingle(repo, rev)
335
335
336 ui.pager('annotate')
336 ui.pager('annotate')
337 rootfm = ui.formatter('annotate', opts)
337 rootfm = ui.formatter('annotate', opts)
338 if ui.debugflag:
338 if ui.debugflag:
339 shorthex = pycompat.identity
339 shorthex = pycompat.identity
340 else:
340 else:
341 def shorthex(h):
341 def shorthex(h):
342 return h[:12]
342 return h[:12]
343 if ui.quiet:
343 if ui.quiet:
344 datefunc = dateutil.shortdate
344 datefunc = dateutil.shortdate
345 else:
345 else:
346 datefunc = dateutil.datestr
346 datefunc = dateutil.datestr
347 if ctx.rev() is None:
347 if ctx.rev() is None:
348 if opts.get('changeset'):
348 if opts.get('changeset'):
349 # omit "+" suffix which is appended to node hex
349 # omit "+" suffix which is appended to node hex
350 def formatrev(rev):
350 def formatrev(rev):
351 if rev == wdirrev:
351 if rev == wdirrev:
352 return '%d' % ctx.p1().rev()
352 return '%d' % ctx.p1().rev()
353 else:
353 else:
354 return '%d' % rev
354 return '%d' % rev
355 else:
355 else:
356 def formatrev(rev):
356 def formatrev(rev):
357 if rev == wdirrev:
357 if rev == wdirrev:
358 return '%d+' % ctx.p1().rev()
358 return '%d+' % ctx.p1().rev()
359 else:
359 else:
360 return '%d ' % rev
360 return '%d ' % rev
361 def formathex(h):
361 def formathex(h):
362 if h == wdirhex:
362 if h == wdirhex:
363 return '%s+' % shorthex(hex(ctx.p1().node()))
363 return '%s+' % shorthex(hex(ctx.p1().node()))
364 else:
364 else:
365 return '%s ' % shorthex(h)
365 return '%s ' % shorthex(h)
366 else:
366 else:
367 formatrev = b'%d'.__mod__
367 formatrev = b'%d'.__mod__
368 formathex = shorthex
368 formathex = shorthex
369
369
370 opmap = [
370 opmap = [
371 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
371 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
372 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
372 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
373 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
373 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
374 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
374 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
375 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
375 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
376 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
376 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
377 ]
377 ]
378 opnamemap = {
378 opnamemap = {
379 'rev': 'number',
379 'rev': 'number',
380 'node': 'changeset',
380 'node': 'changeset',
381 'path': 'file',
381 'path': 'file',
382 'lineno': 'line_number',
382 'lineno': 'line_number',
383 }
383 }
384
384
385 if rootfm.isplain():
385 if rootfm.isplain():
386 def makefunc(get, fmt):
386 def makefunc(get, fmt):
387 return lambda x: fmt(get(x))
387 return lambda x: fmt(get(x))
388 else:
388 else:
389 def makefunc(get, fmt):
389 def makefunc(get, fmt):
390 return get
390 return get
391 datahint = rootfm.datahint()
391 datahint = rootfm.datahint()
392 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
392 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
393 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
393 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
394 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
394 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
395 fields = ' '.join(fn for fn, sep, get, fmt in opmap
395 fields = ' '.join(fn for fn, sep, get, fmt in opmap
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
397
397
398 def bad(x, y):
398 def bad(x, y):
399 raise error.Abort("%s: %s" % (x, y))
399 raise error.Abort("%s: %s" % (x, y))
400
400
401 m = scmutil.match(ctx, pats, opts, badfn=bad)
401 m = scmutil.match(ctx, pats, opts, badfn=bad)
402
402
403 follow = not opts.get('no_follow')
403 follow = not opts.get('no_follow')
404 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
404 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
405 whitespace=True)
405 whitespace=True)
406 skiprevs = opts.get('skip')
406 skiprevs = opts.get('skip')
407 if skiprevs:
407 if skiprevs:
408 skiprevs = scmutil.revrange(repo, skiprevs)
408 skiprevs = scmutil.revrange(repo, skiprevs)
409
409
410 for abs in ctx.walk(m):
410 for abs in ctx.walk(m):
411 fctx = ctx[abs]
411 fctx = ctx[abs]
412 rootfm.startitem()
412 rootfm.startitem()
413 rootfm.data(path=abs)
413 rootfm.data(path=abs)
414 if not opts.get('text') and fctx.isbinary():
414 if not opts.get('text') and fctx.isbinary():
415 rootfm.plain(_("%s: binary file\n")
415 rootfm.plain(_("%s: binary file\n") % m.rel(abs))
416 % ((pats and m.rel(abs)) or abs))
417 continue
416 continue
418
417
419 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
418 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
420 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
419 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
421 diffopts=diffopts)
420 diffopts=diffopts)
422 if not lines:
421 if not lines:
423 fm.end()
422 fm.end()
424 continue
423 continue
425 formats = []
424 formats = []
426 pieces = []
425 pieces = []
427
426
428 for f, sep in funcmap:
427 for f, sep in funcmap:
429 l = [f(n) for n in lines]
428 l = [f(n) for n in lines]
430 if fm.isplain():
429 if fm.isplain():
431 sizes = [encoding.colwidth(x) for x in l]
430 sizes = [encoding.colwidth(x) for x in l]
432 ml = max(sizes)
431 ml = max(sizes)
433 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
432 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
434 else:
433 else:
435 formats.append(['%s' for x in l])
434 formats.append(['%s' for x in l])
436 pieces.append(l)
435 pieces.append(l)
437
436
438 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
437 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
439 fm.startitem()
438 fm.startitem()
440 fm.context(fctx=n.fctx)
439 fm.context(fctx=n.fctx)
441 fm.write(fields, "".join(f), *p)
440 fm.write(fields, "".join(f), *p)
442 if n.skip:
441 if n.skip:
443 fmt = "* %s"
442 fmt = "* %s"
444 else:
443 else:
445 fmt = ": %s"
444 fmt = ": %s"
446 fm.write('line', fmt, n.text)
445 fm.write('line', fmt, n.text)
447
446
448 if not lines[-1].text.endswith('\n'):
447 if not lines[-1].text.endswith('\n'):
449 fm.plain('\n')
448 fm.plain('\n')
450 fm.end()
449 fm.end()
451
450
452 rootfm.end()
451 rootfm.end()
453
452
454 @command('archive',
453 @command('archive',
455 [('', 'no-decode', None, _('do not pass files through decoders')),
454 [('', 'no-decode', None, _('do not pass files through decoders')),
456 ('p', 'prefix', '', _('directory prefix for files in archive'),
455 ('p', 'prefix', '', _('directory prefix for files in archive'),
457 _('PREFIX')),
456 _('PREFIX')),
458 ('r', 'rev', '', _('revision to distribute'), _('REV')),
457 ('r', 'rev', '', _('revision to distribute'), _('REV')),
459 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
458 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
460 ] + subrepoopts + walkopts,
459 ] + subrepoopts + walkopts,
461 _('[OPTION]... DEST'),
460 _('[OPTION]... DEST'),
462 helpcategory=command.CATEGORY_IMPORT_EXPORT)
461 helpcategory=command.CATEGORY_IMPORT_EXPORT)
463 def archive(ui, repo, dest, **opts):
462 def archive(ui, repo, dest, **opts):
464 '''create an unversioned archive of a repository revision
463 '''create an unversioned archive of a repository revision
465
464
466 By default, the revision used is the parent of the working
465 By default, the revision used is the parent of the working
467 directory; use -r/--rev to specify a different revision.
466 directory; use -r/--rev to specify a different revision.
468
467
469 The archive type is automatically detected based on file
468 The archive type is automatically detected based on file
470 extension (to override, use -t/--type).
469 extension (to override, use -t/--type).
471
470
472 .. container:: verbose
471 .. container:: verbose
473
472
474 Examples:
473 Examples:
475
474
476 - create a zip file containing the 1.0 release::
475 - create a zip file containing the 1.0 release::
477
476
478 hg archive -r 1.0 project-1.0.zip
477 hg archive -r 1.0 project-1.0.zip
479
478
480 - create a tarball excluding .hg files::
479 - create a tarball excluding .hg files::
481
480
482 hg archive project.tar.gz -X ".hg*"
481 hg archive project.tar.gz -X ".hg*"
483
482
484 Valid types are:
483 Valid types are:
485
484
486 :``files``: a directory full of files (default)
485 :``files``: a directory full of files (default)
487 :``tar``: tar archive, uncompressed
486 :``tar``: tar archive, uncompressed
488 :``tbz2``: tar archive, compressed using bzip2
487 :``tbz2``: tar archive, compressed using bzip2
489 :``tgz``: tar archive, compressed using gzip
488 :``tgz``: tar archive, compressed using gzip
490 :``uzip``: zip archive, uncompressed
489 :``uzip``: zip archive, uncompressed
491 :``zip``: zip archive, compressed using deflate
490 :``zip``: zip archive, compressed using deflate
492
491
493 The exact name of the destination archive or directory is given
492 The exact name of the destination archive or directory is given
494 using a format string; see :hg:`help export` for details.
493 using a format string; see :hg:`help export` for details.
495
494
496 Each member added to an archive file has a directory prefix
495 Each member added to an archive file has a directory prefix
497 prepended. Use -p/--prefix to specify a format string for the
496 prepended. Use -p/--prefix to specify a format string for the
498 prefix. The default is the basename of the archive, with suffixes
497 prefix. The default is the basename of the archive, with suffixes
499 removed.
498 removed.
500
499
501 Returns 0 on success.
500 Returns 0 on success.
502 '''
501 '''
503
502
504 opts = pycompat.byteskwargs(opts)
503 opts = pycompat.byteskwargs(opts)
505 rev = opts.get('rev')
504 rev = opts.get('rev')
506 if rev:
505 if rev:
507 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
506 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
508 ctx = scmutil.revsingle(repo, rev)
507 ctx = scmutil.revsingle(repo, rev)
509 if not ctx:
508 if not ctx:
510 raise error.Abort(_('no working directory: please specify a revision'))
509 raise error.Abort(_('no working directory: please specify a revision'))
511 node = ctx.node()
510 node = ctx.node()
512 dest = cmdutil.makefilename(ctx, dest)
511 dest = cmdutil.makefilename(ctx, dest)
513 if os.path.realpath(dest) == repo.root:
512 if os.path.realpath(dest) == repo.root:
514 raise error.Abort(_('repository root cannot be destination'))
513 raise error.Abort(_('repository root cannot be destination'))
515
514
516 kind = opts.get('type') or archival.guesskind(dest) or 'files'
515 kind = opts.get('type') or archival.guesskind(dest) or 'files'
517 prefix = opts.get('prefix')
516 prefix = opts.get('prefix')
518
517
519 if dest == '-':
518 if dest == '-':
520 if kind == 'files':
519 if kind == 'files':
521 raise error.Abort(_('cannot archive plain files to stdout'))
520 raise error.Abort(_('cannot archive plain files to stdout'))
522 dest = cmdutil.makefileobj(ctx, dest)
521 dest = cmdutil.makefileobj(ctx, dest)
523 if not prefix:
522 if not prefix:
524 prefix = os.path.basename(repo.root) + '-%h'
523 prefix = os.path.basename(repo.root) + '-%h'
525
524
526 prefix = cmdutil.makefilename(ctx, prefix)
525 prefix = cmdutil.makefilename(ctx, prefix)
527 match = scmutil.match(ctx, [], opts)
526 match = scmutil.match(ctx, [], opts)
528 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
527 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
529 match, prefix, subrepos=opts.get('subrepos'))
528 match, prefix, subrepos=opts.get('subrepos'))
530
529
531 @command('backout',
530 @command('backout',
532 [('', 'merge', None, _('merge with old dirstate parent after backout')),
531 [('', 'merge', None, _('merge with old dirstate parent after backout')),
533 ('', 'commit', None,
532 ('', 'commit', None,
534 _('commit if no conflicts were encountered (DEPRECATED)')),
533 _('commit if no conflicts were encountered (DEPRECATED)')),
535 ('', 'no-commit', None, _('do not commit')),
534 ('', 'no-commit', None, _('do not commit')),
536 ('', 'parent', '',
535 ('', 'parent', '',
537 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
536 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
538 ('r', 'rev', '', _('revision to backout'), _('REV')),
537 ('r', 'rev', '', _('revision to backout'), _('REV')),
539 ('e', 'edit', False, _('invoke editor on commit messages')),
538 ('e', 'edit', False, _('invoke editor on commit messages')),
540 ] + mergetoolopts + walkopts + commitopts + commitopts2,
539 ] + mergetoolopts + walkopts + commitopts + commitopts2,
541 _('[OPTION]... [-r] REV'),
540 _('[OPTION]... [-r] REV'),
542 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
541 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
543 def backout(ui, repo, node=None, rev=None, **opts):
542 def backout(ui, repo, node=None, rev=None, **opts):
544 '''reverse effect of earlier changeset
543 '''reverse effect of earlier changeset
545
544
546 Prepare a new changeset with the effect of REV undone in the
545 Prepare a new changeset with the effect of REV undone in the
547 current working directory. If no conflicts were encountered,
546 current working directory. If no conflicts were encountered,
548 it will be committed immediately.
547 it will be committed immediately.
549
548
550 If REV is the parent of the working directory, then this new changeset
549 If REV is the parent of the working directory, then this new changeset
551 is committed automatically (unless --no-commit is specified).
550 is committed automatically (unless --no-commit is specified).
552
551
553 .. note::
552 .. note::
554
553
555 :hg:`backout` cannot be used to fix either an unwanted or
554 :hg:`backout` cannot be used to fix either an unwanted or
556 incorrect merge.
555 incorrect merge.
557
556
558 .. container:: verbose
557 .. container:: verbose
559
558
560 Examples:
559 Examples:
561
560
562 - Reverse the effect of the parent of the working directory.
561 - Reverse the effect of the parent of the working directory.
563 This backout will be committed immediately::
562 This backout will be committed immediately::
564
563
565 hg backout -r .
564 hg backout -r .
566
565
567 - Reverse the effect of previous bad revision 23::
566 - Reverse the effect of previous bad revision 23::
568
567
569 hg backout -r 23
568 hg backout -r 23
570
569
571 - Reverse the effect of previous bad revision 23 and
570 - Reverse the effect of previous bad revision 23 and
572 leave changes uncommitted::
571 leave changes uncommitted::
573
572
574 hg backout -r 23 --no-commit
573 hg backout -r 23 --no-commit
575 hg commit -m "Backout revision 23"
574 hg commit -m "Backout revision 23"
576
575
577 By default, the pending changeset will have one parent,
576 By default, the pending changeset will have one parent,
578 maintaining a linear history. With --merge, the pending
577 maintaining a linear history. With --merge, the pending
579 changeset will instead have two parents: the old parent of the
578 changeset will instead have two parents: the old parent of the
580 working directory and a new child of REV that simply undoes REV.
579 working directory and a new child of REV that simply undoes REV.
581
580
582 Before version 1.7, the behavior without --merge was equivalent
581 Before version 1.7, the behavior without --merge was equivalent
583 to specifying --merge followed by :hg:`update --clean .` to
582 to specifying --merge followed by :hg:`update --clean .` to
584 cancel the merge and leave the child of REV as a head to be
583 cancel the merge and leave the child of REV as a head to be
585 merged separately.
584 merged separately.
586
585
587 See :hg:`help dates` for a list of formats valid for -d/--date.
586 See :hg:`help dates` for a list of formats valid for -d/--date.
588
587
589 See :hg:`help revert` for a way to restore files to the state
588 See :hg:`help revert` for a way to restore files to the state
590 of another revision.
589 of another revision.
591
590
592 Returns 0 on success, 1 if nothing to backout or there are unresolved
591 Returns 0 on success, 1 if nothing to backout or there are unresolved
593 files.
592 files.
594 '''
593 '''
595 with repo.wlock(), repo.lock():
594 with repo.wlock(), repo.lock():
596 return _dobackout(ui, repo, node, rev, **opts)
595 return _dobackout(ui, repo, node, rev, **opts)
597
596
598 def _dobackout(ui, repo, node=None, rev=None, **opts):
597 def _dobackout(ui, repo, node=None, rev=None, **opts):
599 opts = pycompat.byteskwargs(opts)
598 opts = pycompat.byteskwargs(opts)
600 if opts.get('commit') and opts.get('no_commit'):
599 if opts.get('commit') and opts.get('no_commit'):
601 raise error.Abort(_("cannot use --commit with --no-commit"))
600 raise error.Abort(_("cannot use --commit with --no-commit"))
602 if opts.get('merge') and opts.get('no_commit'):
601 if opts.get('merge') and opts.get('no_commit'):
603 raise error.Abort(_("cannot use --merge with --no-commit"))
602 raise error.Abort(_("cannot use --merge with --no-commit"))
604
603
605 if rev and node:
604 if rev and node:
606 raise error.Abort(_("please specify just one revision"))
605 raise error.Abort(_("please specify just one revision"))
607
606
608 if not rev:
607 if not rev:
609 rev = node
608 rev = node
610
609
611 if not rev:
610 if not rev:
612 raise error.Abort(_("please specify a revision to backout"))
611 raise error.Abort(_("please specify a revision to backout"))
613
612
614 date = opts.get('date')
613 date = opts.get('date')
615 if date:
614 if date:
616 opts['date'] = dateutil.parsedate(date)
615 opts['date'] = dateutil.parsedate(date)
617
616
618 cmdutil.checkunfinished(repo)
617 cmdutil.checkunfinished(repo)
619 cmdutil.bailifchanged(repo)
618 cmdutil.bailifchanged(repo)
620 node = scmutil.revsingle(repo, rev).node()
619 node = scmutil.revsingle(repo, rev).node()
621
620
622 op1, op2 = repo.dirstate.parents()
621 op1, op2 = repo.dirstate.parents()
623 if not repo.changelog.isancestor(node, op1):
622 if not repo.changelog.isancestor(node, op1):
624 raise error.Abort(_('cannot backout change that is not an ancestor'))
623 raise error.Abort(_('cannot backout change that is not an ancestor'))
625
624
626 p1, p2 = repo.changelog.parents(node)
625 p1, p2 = repo.changelog.parents(node)
627 if p1 == nullid:
626 if p1 == nullid:
628 raise error.Abort(_('cannot backout a change with no parents'))
627 raise error.Abort(_('cannot backout a change with no parents'))
629 if p2 != nullid:
628 if p2 != nullid:
630 if not opts.get('parent'):
629 if not opts.get('parent'):
631 raise error.Abort(_('cannot backout a merge changeset'))
630 raise error.Abort(_('cannot backout a merge changeset'))
632 p = repo.lookup(opts['parent'])
631 p = repo.lookup(opts['parent'])
633 if p not in (p1, p2):
632 if p not in (p1, p2):
634 raise error.Abort(_('%s is not a parent of %s') %
633 raise error.Abort(_('%s is not a parent of %s') %
635 (short(p), short(node)))
634 (short(p), short(node)))
636 parent = p
635 parent = p
637 else:
636 else:
638 if opts.get('parent'):
637 if opts.get('parent'):
639 raise error.Abort(_('cannot use --parent on non-merge changeset'))
638 raise error.Abort(_('cannot use --parent on non-merge changeset'))
640 parent = p1
639 parent = p1
641
640
642 # the backout should appear on the same branch
641 # the backout should appear on the same branch
643 branch = repo.dirstate.branch()
642 branch = repo.dirstate.branch()
644 bheads = repo.branchheads(branch)
643 bheads = repo.branchheads(branch)
645 rctx = scmutil.revsingle(repo, hex(parent))
644 rctx = scmutil.revsingle(repo, hex(parent))
646 if not opts.get('merge') and op1 != node:
645 if not opts.get('merge') and op1 != node:
647 with dirstateguard.dirstateguard(repo, 'backout'):
646 with dirstateguard.dirstateguard(repo, 'backout'):
648 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
647 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
649 with ui.configoverride(overrides, 'backout'):
648 with ui.configoverride(overrides, 'backout'):
650 stats = mergemod.update(repo, parent, branchmerge=True,
649 stats = mergemod.update(repo, parent, branchmerge=True,
651 force=True, ancestor=node,
650 force=True, ancestor=node,
652 mergeancestor=False)
651 mergeancestor=False)
653 repo.setparents(op1, op2)
652 repo.setparents(op1, op2)
654 hg._showstats(repo, stats)
653 hg._showstats(repo, stats)
655 if stats.unresolvedcount:
654 if stats.unresolvedcount:
656 repo.ui.status(_("use 'hg resolve' to retry unresolved "
655 repo.ui.status(_("use 'hg resolve' to retry unresolved "
657 "file merges\n"))
656 "file merges\n"))
658 return 1
657 return 1
659 else:
658 else:
660 hg.clean(repo, node, show_stats=False)
659 hg.clean(repo, node, show_stats=False)
661 repo.dirstate.setbranch(branch)
660 repo.dirstate.setbranch(branch)
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
661 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
663
662
664 if opts.get('no_commit'):
663 if opts.get('no_commit'):
665 msg = _("changeset %s backed out, "
664 msg = _("changeset %s backed out, "
666 "don't forget to commit.\n")
665 "don't forget to commit.\n")
667 ui.status(msg % short(node))
666 ui.status(msg % short(node))
668 return 0
667 return 0
669
668
670 def commitfunc(ui, repo, message, match, opts):
669 def commitfunc(ui, repo, message, match, opts):
671 editform = 'backout'
670 editform = 'backout'
672 e = cmdutil.getcommiteditor(editform=editform,
671 e = cmdutil.getcommiteditor(editform=editform,
673 **pycompat.strkwargs(opts))
672 **pycompat.strkwargs(opts))
674 if not message:
673 if not message:
675 # we don't translate commit messages
674 # we don't translate commit messages
676 message = "Backed out changeset %s" % short(node)
675 message = "Backed out changeset %s" % short(node)
677 e = cmdutil.getcommiteditor(edit=True, editform=editform)
676 e = cmdutil.getcommiteditor(edit=True, editform=editform)
678 return repo.commit(message, opts.get('user'), opts.get('date'),
677 return repo.commit(message, opts.get('user'), opts.get('date'),
679 match, editor=e)
678 match, editor=e)
680 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
679 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
681 if not newnode:
680 if not newnode:
682 ui.status(_("nothing changed\n"))
681 ui.status(_("nothing changed\n"))
683 return 1
682 return 1
684 cmdutil.commitstatus(repo, newnode, branch, bheads)
683 cmdutil.commitstatus(repo, newnode, branch, bheads)
685
684
686 def nice(node):
685 def nice(node):
687 return '%d:%s' % (repo.changelog.rev(node), short(node))
686 return '%d:%s' % (repo.changelog.rev(node), short(node))
688 ui.status(_('changeset %s backs out changeset %s\n') %
687 ui.status(_('changeset %s backs out changeset %s\n') %
689 (nice(repo.changelog.tip()), nice(node)))
688 (nice(repo.changelog.tip()), nice(node)))
690 if opts.get('merge') and op1 != node:
689 if opts.get('merge') and op1 != node:
691 hg.clean(repo, op1, show_stats=False)
690 hg.clean(repo, op1, show_stats=False)
692 ui.status(_('merging with changeset %s\n')
691 ui.status(_('merging with changeset %s\n')
693 % nice(repo.changelog.tip()))
692 % nice(repo.changelog.tip()))
694 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
693 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
695 with ui.configoverride(overrides, 'backout'):
694 with ui.configoverride(overrides, 'backout'):
696 return hg.merge(repo, hex(repo.changelog.tip()))
695 return hg.merge(repo, hex(repo.changelog.tip()))
697 return 0
696 return 0
698
697
699 @command('bisect',
698 @command('bisect',
700 [('r', 'reset', False, _('reset bisect state')),
699 [('r', 'reset', False, _('reset bisect state')),
701 ('g', 'good', False, _('mark changeset good')),
700 ('g', 'good', False, _('mark changeset good')),
702 ('b', 'bad', False, _('mark changeset bad')),
701 ('b', 'bad', False, _('mark changeset bad')),
703 ('s', 'skip', False, _('skip testing changeset')),
702 ('s', 'skip', False, _('skip testing changeset')),
704 ('e', 'extend', False, _('extend the bisect range')),
703 ('e', 'extend', False, _('extend the bisect range')),
705 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
704 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
706 ('U', 'noupdate', False, _('do not update to target'))],
705 ('U', 'noupdate', False, _('do not update to target'))],
707 _("[-gbsr] [-U] [-c CMD] [REV]"),
706 _("[-gbsr] [-U] [-c CMD] [REV]"),
708 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
707 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
709 def bisect(ui, repo, rev=None, extra=None, command=None,
708 def bisect(ui, repo, rev=None, extra=None, command=None,
710 reset=None, good=None, bad=None, skip=None, extend=None,
709 reset=None, good=None, bad=None, skip=None, extend=None,
711 noupdate=None):
710 noupdate=None):
712 """subdivision search of changesets
711 """subdivision search of changesets
713
712
714 This command helps to find changesets which introduce problems. To
713 This command helps to find changesets which introduce problems. To
715 use, mark the earliest changeset you know exhibits the problem as
714 use, mark the earliest changeset you know exhibits the problem as
716 bad, then mark the latest changeset which is free from the problem
715 bad, then mark the latest changeset which is free from the problem
717 as good. Bisect will update your working directory to a revision
716 as good. Bisect will update your working directory to a revision
718 for testing (unless the -U/--noupdate option is specified). Once
717 for testing (unless the -U/--noupdate option is specified). Once
719 you have performed tests, mark the working directory as good or
718 you have performed tests, mark the working directory as good or
720 bad, and bisect will either update to another candidate changeset
719 bad, and bisect will either update to another candidate changeset
721 or announce that it has found the bad revision.
720 or announce that it has found the bad revision.
722
721
723 As a shortcut, you can also use the revision argument to mark a
722 As a shortcut, you can also use the revision argument to mark a
724 revision as good or bad without checking it out first.
723 revision as good or bad without checking it out first.
725
724
726 If you supply a command, it will be used for automatic bisection.
725 If you supply a command, it will be used for automatic bisection.
727 The environment variable HG_NODE will contain the ID of the
726 The environment variable HG_NODE will contain the ID of the
728 changeset being tested. The exit status of the command will be
727 changeset being tested. The exit status of the command will be
729 used to mark revisions as good or bad: status 0 means good, 125
728 used to mark revisions as good or bad: status 0 means good, 125
730 means to skip the revision, 127 (command not found) will abort the
729 means to skip the revision, 127 (command not found) will abort the
731 bisection, and any other non-zero exit status means the revision
730 bisection, and any other non-zero exit status means the revision
732 is bad.
731 is bad.
733
732
734 .. container:: verbose
733 .. container:: verbose
735
734
736 Some examples:
735 Some examples:
737
736
738 - start a bisection with known bad revision 34, and good revision 12::
737 - start a bisection with known bad revision 34, and good revision 12::
739
738
740 hg bisect --bad 34
739 hg bisect --bad 34
741 hg bisect --good 12
740 hg bisect --good 12
742
741
743 - advance the current bisection by marking current revision as good or
742 - advance the current bisection by marking current revision as good or
744 bad::
743 bad::
745
744
746 hg bisect --good
745 hg bisect --good
747 hg bisect --bad
746 hg bisect --bad
748
747
749 - mark the current revision, or a known revision, to be skipped (e.g. if
748 - mark the current revision, or a known revision, to be skipped (e.g. if
750 that revision is not usable because of another issue)::
749 that revision is not usable because of another issue)::
751
750
752 hg bisect --skip
751 hg bisect --skip
753 hg bisect --skip 23
752 hg bisect --skip 23
754
753
755 - skip all revisions that do not touch directories ``foo`` or ``bar``::
754 - skip all revisions that do not touch directories ``foo`` or ``bar``::
756
755
757 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
756 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
758
757
759 - forget the current bisection::
758 - forget the current bisection::
760
759
761 hg bisect --reset
760 hg bisect --reset
762
761
763 - use 'make && make tests' to automatically find the first broken
762 - use 'make && make tests' to automatically find the first broken
764 revision::
763 revision::
765
764
766 hg bisect --reset
765 hg bisect --reset
767 hg bisect --bad 34
766 hg bisect --bad 34
768 hg bisect --good 12
767 hg bisect --good 12
769 hg bisect --command "make && make tests"
768 hg bisect --command "make && make tests"
770
769
771 - see all changesets whose states are already known in the current
770 - see all changesets whose states are already known in the current
772 bisection::
771 bisection::
773
772
774 hg log -r "bisect(pruned)"
773 hg log -r "bisect(pruned)"
775
774
776 - see the changeset currently being bisected (especially useful
775 - see the changeset currently being bisected (especially useful
777 if running with -U/--noupdate)::
776 if running with -U/--noupdate)::
778
777
779 hg log -r "bisect(current)"
778 hg log -r "bisect(current)"
780
779
781 - see all changesets that took part in the current bisection::
780 - see all changesets that took part in the current bisection::
782
781
783 hg log -r "bisect(range)"
782 hg log -r "bisect(range)"
784
783
785 - you can even get a nice graph::
784 - you can even get a nice graph::
786
785
787 hg log --graph -r "bisect(range)"
786 hg log --graph -r "bisect(range)"
788
787
789 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
788 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
790
789
791 Returns 0 on success.
790 Returns 0 on success.
792 """
791 """
793 # backward compatibility
792 # backward compatibility
794 if rev in "good bad reset init".split():
793 if rev in "good bad reset init".split():
795 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
794 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
796 cmd, rev, extra = rev, extra, None
795 cmd, rev, extra = rev, extra, None
797 if cmd == "good":
796 if cmd == "good":
798 good = True
797 good = True
799 elif cmd == "bad":
798 elif cmd == "bad":
800 bad = True
799 bad = True
801 else:
800 else:
802 reset = True
801 reset = True
803 elif extra:
802 elif extra:
804 raise error.Abort(_('incompatible arguments'))
803 raise error.Abort(_('incompatible arguments'))
805
804
806 incompatibles = {
805 incompatibles = {
807 '--bad': bad,
806 '--bad': bad,
808 '--command': bool(command),
807 '--command': bool(command),
809 '--extend': extend,
808 '--extend': extend,
810 '--good': good,
809 '--good': good,
811 '--reset': reset,
810 '--reset': reset,
812 '--skip': skip,
811 '--skip': skip,
813 }
812 }
814
813
815 enabled = [x for x in incompatibles if incompatibles[x]]
814 enabled = [x for x in incompatibles if incompatibles[x]]
816
815
817 if len(enabled) > 1:
816 if len(enabled) > 1:
818 raise error.Abort(_('%s and %s are incompatible') %
817 raise error.Abort(_('%s and %s are incompatible') %
819 tuple(sorted(enabled)[0:2]))
818 tuple(sorted(enabled)[0:2]))
820
819
821 if reset:
820 if reset:
822 hbisect.resetstate(repo)
821 hbisect.resetstate(repo)
823 return
822 return
824
823
825 state = hbisect.load_state(repo)
824 state = hbisect.load_state(repo)
826
825
827 # update state
826 # update state
828 if good or bad or skip:
827 if good or bad or skip:
829 if rev:
828 if rev:
830 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
829 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
831 else:
830 else:
832 nodes = [repo.lookup('.')]
831 nodes = [repo.lookup('.')]
833 if good:
832 if good:
834 state['good'] += nodes
833 state['good'] += nodes
835 elif bad:
834 elif bad:
836 state['bad'] += nodes
835 state['bad'] += nodes
837 elif skip:
836 elif skip:
838 state['skip'] += nodes
837 state['skip'] += nodes
839 hbisect.save_state(repo, state)
838 hbisect.save_state(repo, state)
840 if not (state['good'] and state['bad']):
839 if not (state['good'] and state['bad']):
841 return
840 return
842
841
843 def mayupdate(repo, node, show_stats=True):
842 def mayupdate(repo, node, show_stats=True):
844 """common used update sequence"""
843 """common used update sequence"""
845 if noupdate:
844 if noupdate:
846 return
845 return
847 cmdutil.checkunfinished(repo)
846 cmdutil.checkunfinished(repo)
848 cmdutil.bailifchanged(repo)
847 cmdutil.bailifchanged(repo)
849 return hg.clean(repo, node, show_stats=show_stats)
848 return hg.clean(repo, node, show_stats=show_stats)
850
849
851 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
850 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
852
851
853 if command:
852 if command:
854 changesets = 1
853 changesets = 1
855 if noupdate:
854 if noupdate:
856 try:
855 try:
857 node = state['current'][0]
856 node = state['current'][0]
858 except LookupError:
857 except LookupError:
859 raise error.Abort(_('current bisect revision is unknown - '
858 raise error.Abort(_('current bisect revision is unknown - '
860 'start a new bisect to fix'))
859 'start a new bisect to fix'))
861 else:
860 else:
862 node, p2 = repo.dirstate.parents()
861 node, p2 = repo.dirstate.parents()
863 if p2 != nullid:
862 if p2 != nullid:
864 raise error.Abort(_('current bisect revision is a merge'))
863 raise error.Abort(_('current bisect revision is a merge'))
865 if rev:
864 if rev:
866 node = repo[scmutil.revsingle(repo, rev, node)].node()
865 node = repo[scmutil.revsingle(repo, rev, node)].node()
867 try:
866 try:
868 while changesets:
867 while changesets:
869 # update state
868 # update state
870 state['current'] = [node]
869 state['current'] = [node]
871 hbisect.save_state(repo, state)
870 hbisect.save_state(repo, state)
872 status = ui.system(command, environ={'HG_NODE': hex(node)},
871 status = ui.system(command, environ={'HG_NODE': hex(node)},
873 blockedtag='bisect_check')
872 blockedtag='bisect_check')
874 if status == 125:
873 if status == 125:
875 transition = "skip"
874 transition = "skip"
876 elif status == 0:
875 elif status == 0:
877 transition = "good"
876 transition = "good"
878 # status < 0 means process was killed
877 # status < 0 means process was killed
879 elif status == 127:
878 elif status == 127:
880 raise error.Abort(_("failed to execute %s") % command)
879 raise error.Abort(_("failed to execute %s") % command)
881 elif status < 0:
880 elif status < 0:
882 raise error.Abort(_("%s killed") % command)
881 raise error.Abort(_("%s killed") % command)
883 else:
882 else:
884 transition = "bad"
883 transition = "bad"
885 state[transition].append(node)
884 state[transition].append(node)
886 ctx = repo[node]
885 ctx = repo[node]
887 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
886 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
888 transition))
887 transition))
889 hbisect.checkstate(state)
888 hbisect.checkstate(state)
890 # bisect
889 # bisect
891 nodes, changesets, bgood = hbisect.bisect(repo, state)
890 nodes, changesets, bgood = hbisect.bisect(repo, state)
892 # update to next check
891 # update to next check
893 node = nodes[0]
892 node = nodes[0]
894 mayupdate(repo, node, show_stats=False)
893 mayupdate(repo, node, show_stats=False)
895 finally:
894 finally:
896 state['current'] = [node]
895 state['current'] = [node]
897 hbisect.save_state(repo, state)
896 hbisect.save_state(repo, state)
898 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
897 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
899 return
898 return
900
899
901 hbisect.checkstate(state)
900 hbisect.checkstate(state)
902
901
903 # actually bisect
902 # actually bisect
904 nodes, changesets, good = hbisect.bisect(repo, state)
903 nodes, changesets, good = hbisect.bisect(repo, state)
905 if extend:
904 if extend:
906 if not changesets:
905 if not changesets:
907 extendnode = hbisect.extendrange(repo, state, nodes, good)
906 extendnode = hbisect.extendrange(repo, state, nodes, good)
908 if extendnode is not None:
907 if extendnode is not None:
909 ui.write(_("Extending search to changeset %d:%s\n")
908 ui.write(_("Extending search to changeset %d:%s\n")
910 % (extendnode.rev(), extendnode))
909 % (extendnode.rev(), extendnode))
911 state['current'] = [extendnode.node()]
910 state['current'] = [extendnode.node()]
912 hbisect.save_state(repo, state)
911 hbisect.save_state(repo, state)
913 return mayupdate(repo, extendnode.node())
912 return mayupdate(repo, extendnode.node())
914 raise error.Abort(_("nothing to extend"))
913 raise error.Abort(_("nothing to extend"))
915
914
916 if changesets == 0:
915 if changesets == 0:
917 hbisect.printresult(ui, repo, state, displayer, nodes, good)
916 hbisect.printresult(ui, repo, state, displayer, nodes, good)
918 else:
917 else:
919 assert len(nodes) == 1 # only a single node can be tested next
918 assert len(nodes) == 1 # only a single node can be tested next
920 node = nodes[0]
919 node = nodes[0]
921 # compute the approximate number of remaining tests
920 # compute the approximate number of remaining tests
922 tests, size = 0, 2
921 tests, size = 0, 2
923 while size <= changesets:
922 while size <= changesets:
924 tests, size = tests + 1, size * 2
923 tests, size = tests + 1, size * 2
925 rev = repo.changelog.rev(node)
924 rev = repo.changelog.rev(node)
926 ui.write(_("Testing changeset %d:%s "
925 ui.write(_("Testing changeset %d:%s "
927 "(%d changesets remaining, ~%d tests)\n")
926 "(%d changesets remaining, ~%d tests)\n")
928 % (rev, short(node), changesets, tests))
927 % (rev, short(node), changesets, tests))
929 state['current'] = [node]
928 state['current'] = [node]
930 hbisect.save_state(repo, state)
929 hbisect.save_state(repo, state)
931 return mayupdate(repo, node)
930 return mayupdate(repo, node)
932
931
933 @command('bookmarks|bookmark',
932 @command('bookmarks|bookmark',
934 [('f', 'force', False, _('force')),
933 [('f', 'force', False, _('force')),
935 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
934 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
936 ('d', 'delete', False, _('delete a given bookmark')),
935 ('d', 'delete', False, _('delete a given bookmark')),
937 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
936 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
938 ('i', 'inactive', False, _('mark a bookmark inactive')),
937 ('i', 'inactive', False, _('mark a bookmark inactive')),
939 ('l', 'list', False, _('list existing bookmarks')),
938 ('l', 'list', False, _('list existing bookmarks')),
940 ] + formatteropts,
939 ] + formatteropts,
941 _('hg bookmarks [OPTIONS]... [NAME]...'),
940 _('hg bookmarks [OPTIONS]... [NAME]...'),
942 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
941 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
943 def bookmark(ui, repo, *names, **opts):
942 def bookmark(ui, repo, *names, **opts):
944 '''create a new bookmark or list existing bookmarks
943 '''create a new bookmark or list existing bookmarks
945
944
946 Bookmarks are labels on changesets to help track lines of development.
945 Bookmarks are labels on changesets to help track lines of development.
947 Bookmarks are unversioned and can be moved, renamed and deleted.
946 Bookmarks are unversioned and can be moved, renamed and deleted.
948 Deleting or moving a bookmark has no effect on the associated changesets.
947 Deleting or moving a bookmark has no effect on the associated changesets.
949
948
950 Creating or updating to a bookmark causes it to be marked as 'active'.
949 Creating or updating to a bookmark causes it to be marked as 'active'.
951 The active bookmark is indicated with a '*'.
950 The active bookmark is indicated with a '*'.
952 When a commit is made, the active bookmark will advance to the new commit.
951 When a commit is made, the active bookmark will advance to the new commit.
953 A plain :hg:`update` will also advance an active bookmark, if possible.
952 A plain :hg:`update` will also advance an active bookmark, if possible.
954 Updating away from a bookmark will cause it to be deactivated.
953 Updating away from a bookmark will cause it to be deactivated.
955
954
956 Bookmarks can be pushed and pulled between repositories (see
955 Bookmarks can be pushed and pulled between repositories (see
957 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
956 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
958 diverged, a new 'divergent bookmark' of the form 'name@path' will
957 diverged, a new 'divergent bookmark' of the form 'name@path' will
959 be created. Using :hg:`merge` will resolve the divergence.
958 be created. Using :hg:`merge` will resolve the divergence.
960
959
961 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
960 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
962 the active bookmark's name.
961 the active bookmark's name.
963
962
964 A bookmark named '@' has the special property that :hg:`clone` will
963 A bookmark named '@' has the special property that :hg:`clone` will
965 check it out by default if it exists.
964 check it out by default if it exists.
966
965
967 .. container:: verbose
966 .. container:: verbose
968
967
969 Template:
968 Template:
970
969
971 The following keywords are supported in addition to the common template
970 The following keywords are supported in addition to the common template
972 keywords and functions such as ``{bookmark}``. See also
971 keywords and functions such as ``{bookmark}``. See also
973 :hg:`help templates`.
972 :hg:`help templates`.
974
973
975 :active: Boolean. True if the bookmark is active.
974 :active: Boolean. True if the bookmark is active.
976
975
977 Examples:
976 Examples:
978
977
979 - create an active bookmark for a new line of development::
978 - create an active bookmark for a new line of development::
980
979
981 hg book new-feature
980 hg book new-feature
982
981
983 - create an inactive bookmark as a place marker::
982 - create an inactive bookmark as a place marker::
984
983
985 hg book -i reviewed
984 hg book -i reviewed
986
985
987 - create an inactive bookmark on another changeset::
986 - create an inactive bookmark on another changeset::
988
987
989 hg book -r .^ tested
988 hg book -r .^ tested
990
989
991 - rename bookmark turkey to dinner::
990 - rename bookmark turkey to dinner::
992
991
993 hg book -m turkey dinner
992 hg book -m turkey dinner
994
993
995 - move the '@' bookmark from another branch::
994 - move the '@' bookmark from another branch::
996
995
997 hg book -f @
996 hg book -f @
998
997
999 - print only the active bookmark name::
998 - print only the active bookmark name::
1000
999
1001 hg book -ql .
1000 hg book -ql .
1002 '''
1001 '''
1003 opts = pycompat.byteskwargs(opts)
1002 opts = pycompat.byteskwargs(opts)
1004 force = opts.get('force')
1003 force = opts.get('force')
1005 rev = opts.get('rev')
1004 rev = opts.get('rev')
1006 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1005 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1007
1006
1008 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1007 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1009 if len(selactions) > 1:
1008 if len(selactions) > 1:
1010 raise error.Abort(_('--%s and --%s are incompatible')
1009 raise error.Abort(_('--%s and --%s are incompatible')
1011 % tuple(selactions[:2]))
1010 % tuple(selactions[:2]))
1012 if selactions:
1011 if selactions:
1013 action = selactions[0]
1012 action = selactions[0]
1014 elif names or rev:
1013 elif names or rev:
1015 action = 'add'
1014 action = 'add'
1016 elif inactive:
1015 elif inactive:
1017 action = 'inactive' # meaning deactivate
1016 action = 'inactive' # meaning deactivate
1018 else:
1017 else:
1019 action = 'list'
1018 action = 'list'
1020
1019
1021 if rev and action in {'delete', 'rename', 'list'}:
1020 if rev and action in {'delete', 'rename', 'list'}:
1022 raise error.Abort(_("--rev is incompatible with --%s") % action)
1021 raise error.Abort(_("--rev is incompatible with --%s") % action)
1023 if inactive and action in {'delete', 'list'}:
1022 if inactive and action in {'delete', 'list'}:
1024 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1023 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1025 if not names and action in {'add', 'delete'}:
1024 if not names and action in {'add', 'delete'}:
1026 raise error.Abort(_("bookmark name required"))
1025 raise error.Abort(_("bookmark name required"))
1027
1026
1028 if action in {'add', 'delete', 'rename', 'inactive'}:
1027 if action in {'add', 'delete', 'rename', 'inactive'}:
1029 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1028 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1030 if action == 'delete':
1029 if action == 'delete':
1031 names = pycompat.maplist(repo._bookmarks.expandname, names)
1030 names = pycompat.maplist(repo._bookmarks.expandname, names)
1032 bookmarks.delete(repo, tr, names)
1031 bookmarks.delete(repo, tr, names)
1033 elif action == 'rename':
1032 elif action == 'rename':
1034 if not names:
1033 if not names:
1035 raise error.Abort(_("new bookmark name required"))
1034 raise error.Abort(_("new bookmark name required"))
1036 elif len(names) > 1:
1035 elif len(names) > 1:
1037 raise error.Abort(_("only one new bookmark name allowed"))
1036 raise error.Abort(_("only one new bookmark name allowed"))
1038 oldname = repo._bookmarks.expandname(opts['rename'])
1037 oldname = repo._bookmarks.expandname(opts['rename'])
1039 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1038 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1040 elif action == 'add':
1039 elif action == 'add':
1041 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1040 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1042 elif action == 'inactive':
1041 elif action == 'inactive':
1043 if len(repo._bookmarks) == 0:
1042 if len(repo._bookmarks) == 0:
1044 ui.status(_("no bookmarks set\n"))
1043 ui.status(_("no bookmarks set\n"))
1045 elif not repo._activebookmark:
1044 elif not repo._activebookmark:
1046 ui.status(_("no active bookmark\n"))
1045 ui.status(_("no active bookmark\n"))
1047 else:
1046 else:
1048 bookmarks.deactivate(repo)
1047 bookmarks.deactivate(repo)
1049 elif action == 'list':
1048 elif action == 'list':
1050 names = pycompat.maplist(repo._bookmarks.expandname, names)
1049 names = pycompat.maplist(repo._bookmarks.expandname, names)
1051 with ui.formatter('bookmarks', opts) as fm:
1050 with ui.formatter('bookmarks', opts) as fm:
1052 bookmarks.printbookmarks(ui, repo, fm, names)
1051 bookmarks.printbookmarks(ui, repo, fm, names)
1053 else:
1052 else:
1054 raise error.ProgrammingError('invalid action: %s' % action)
1053 raise error.ProgrammingError('invalid action: %s' % action)
1055
1054
1056 @command('branch',
1055 @command('branch',
1057 [('f', 'force', None,
1056 [('f', 'force', None,
1058 _('set branch name even if it shadows an existing branch')),
1057 _('set branch name even if it shadows an existing branch')),
1059 ('C', 'clean', None, _('reset branch name to parent branch name')),
1058 ('C', 'clean', None, _('reset branch name to parent branch name')),
1060 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1059 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1061 ],
1060 ],
1062 _('[-fC] [NAME]'),
1061 _('[-fC] [NAME]'),
1063 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1062 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1064 def branch(ui, repo, label=None, **opts):
1063 def branch(ui, repo, label=None, **opts):
1065 """set or show the current branch name
1064 """set or show the current branch name
1066
1065
1067 .. note::
1066 .. note::
1068
1067
1069 Branch names are permanent and global. Use :hg:`bookmark` to create a
1068 Branch names are permanent and global. Use :hg:`bookmark` to create a
1070 light-weight bookmark instead. See :hg:`help glossary` for more
1069 light-weight bookmark instead. See :hg:`help glossary` for more
1071 information about named branches and bookmarks.
1070 information about named branches and bookmarks.
1072
1071
1073 With no argument, show the current branch name. With one argument,
1072 With no argument, show the current branch name. With one argument,
1074 set the working directory branch name (the branch will not exist
1073 set the working directory branch name (the branch will not exist
1075 in the repository until the next commit). Standard practice
1074 in the repository until the next commit). Standard practice
1076 recommends that primary development take place on the 'default'
1075 recommends that primary development take place on the 'default'
1077 branch.
1076 branch.
1078
1077
1079 Unless -f/--force is specified, branch will not let you set a
1078 Unless -f/--force is specified, branch will not let you set a
1080 branch name that already exists.
1079 branch name that already exists.
1081
1080
1082 Use -C/--clean to reset the working directory branch to that of
1081 Use -C/--clean to reset the working directory branch to that of
1083 the parent of the working directory, negating a previous branch
1082 the parent of the working directory, negating a previous branch
1084 change.
1083 change.
1085
1084
1086 Use the command :hg:`update` to switch to an existing branch. Use
1085 Use the command :hg:`update` to switch to an existing branch. Use
1087 :hg:`commit --close-branch` to mark this branch head as closed.
1086 :hg:`commit --close-branch` to mark this branch head as closed.
1088 When all heads of a branch are closed, the branch will be
1087 When all heads of a branch are closed, the branch will be
1089 considered closed.
1088 considered closed.
1090
1089
1091 Returns 0 on success.
1090 Returns 0 on success.
1092 """
1091 """
1093 opts = pycompat.byteskwargs(opts)
1092 opts = pycompat.byteskwargs(opts)
1094 revs = opts.get('rev')
1093 revs = opts.get('rev')
1095 if label:
1094 if label:
1096 label = label.strip()
1095 label = label.strip()
1097
1096
1098 if not opts.get('clean') and not label:
1097 if not opts.get('clean') and not label:
1099 if revs:
1098 if revs:
1100 raise error.Abort(_("no branch name specified for the revisions"))
1099 raise error.Abort(_("no branch name specified for the revisions"))
1101 ui.write("%s\n" % repo.dirstate.branch())
1100 ui.write("%s\n" % repo.dirstate.branch())
1102 return
1101 return
1103
1102
1104 with repo.wlock():
1103 with repo.wlock():
1105 if opts.get('clean'):
1104 if opts.get('clean'):
1106 label = repo[None].p1().branch()
1105 label = repo[None].p1().branch()
1107 repo.dirstate.setbranch(label)
1106 repo.dirstate.setbranch(label)
1108 ui.status(_('reset working directory to branch %s\n') % label)
1107 ui.status(_('reset working directory to branch %s\n') % label)
1109 elif label:
1108 elif label:
1110
1109
1111 scmutil.checknewlabel(repo, label, 'branch')
1110 scmutil.checknewlabel(repo, label, 'branch')
1112 if revs:
1111 if revs:
1113 return cmdutil.changebranch(ui, repo, revs, label)
1112 return cmdutil.changebranch(ui, repo, revs, label)
1114
1113
1115 if not opts.get('force') and label in repo.branchmap():
1114 if not opts.get('force') and label in repo.branchmap():
1116 if label not in [p.branch() for p in repo[None].parents()]:
1115 if label not in [p.branch() for p in repo[None].parents()]:
1117 raise error.Abort(_('a branch of the same name already'
1116 raise error.Abort(_('a branch of the same name already'
1118 ' exists'),
1117 ' exists'),
1119 # i18n: "it" refers to an existing branch
1118 # i18n: "it" refers to an existing branch
1120 hint=_("use 'hg update' to switch to it"))
1119 hint=_("use 'hg update' to switch to it"))
1121
1120
1122 repo.dirstate.setbranch(label)
1121 repo.dirstate.setbranch(label)
1123 ui.status(_('marked working directory as branch %s\n') % label)
1122 ui.status(_('marked working directory as branch %s\n') % label)
1124
1123
1125 # find any open named branches aside from default
1124 # find any open named branches aside from default
1126 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1125 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1127 if n != "default" and not c]
1126 if n != "default" and not c]
1128 if not others:
1127 if not others:
1129 ui.status(_('(branches are permanent and global, '
1128 ui.status(_('(branches are permanent and global, '
1130 'did you want a bookmark?)\n'))
1129 'did you want a bookmark?)\n'))
1131
1130
1132 @command('branches',
1131 @command('branches',
1133 [('a', 'active', False,
1132 [('a', 'active', False,
1134 _('show only branches that have unmerged heads (DEPRECATED)')),
1133 _('show only branches that have unmerged heads (DEPRECATED)')),
1135 ('c', 'closed', False, _('show normal and closed branches')),
1134 ('c', 'closed', False, _('show normal and closed branches')),
1136 ] + formatteropts,
1135 ] + formatteropts,
1137 _('[-c]'),
1136 _('[-c]'),
1138 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1137 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1139 intents={INTENT_READONLY})
1138 intents={INTENT_READONLY})
1140 def branches(ui, repo, active=False, closed=False, **opts):
1139 def branches(ui, repo, active=False, closed=False, **opts):
1141 """list repository named branches
1140 """list repository named branches
1142
1141
1143 List the repository's named branches, indicating which ones are
1142 List the repository's named branches, indicating which ones are
1144 inactive. If -c/--closed is specified, also list branches which have
1143 inactive. If -c/--closed is specified, also list branches which have
1145 been marked closed (see :hg:`commit --close-branch`).
1144 been marked closed (see :hg:`commit --close-branch`).
1146
1145
1147 Use the command :hg:`update` to switch to an existing branch.
1146 Use the command :hg:`update` to switch to an existing branch.
1148
1147
1149 .. container:: verbose
1148 .. container:: verbose
1150
1149
1151 Template:
1150 Template:
1152
1151
1153 The following keywords are supported in addition to the common template
1152 The following keywords are supported in addition to the common template
1154 keywords and functions such as ``{branch}``. See also
1153 keywords and functions such as ``{branch}``. See also
1155 :hg:`help templates`.
1154 :hg:`help templates`.
1156
1155
1157 :active: Boolean. True if the branch is active.
1156 :active: Boolean. True if the branch is active.
1158 :closed: Boolean. True if the branch is closed.
1157 :closed: Boolean. True if the branch is closed.
1159 :current: Boolean. True if it is the current branch.
1158 :current: Boolean. True if it is the current branch.
1160
1159
1161 Returns 0.
1160 Returns 0.
1162 """
1161 """
1163
1162
1164 opts = pycompat.byteskwargs(opts)
1163 opts = pycompat.byteskwargs(opts)
1165 ui.pager('branches')
1164 ui.pager('branches')
1166 fm = ui.formatter('branches', opts)
1165 fm = ui.formatter('branches', opts)
1167 hexfunc = fm.hexfunc
1166 hexfunc = fm.hexfunc
1168
1167
1169 allheads = set(repo.heads())
1168 allheads = set(repo.heads())
1170 branches = []
1169 branches = []
1171 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1170 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1172 isactive = False
1171 isactive = False
1173 if not isclosed:
1172 if not isclosed:
1174 openheads = set(repo.branchmap().iteropen(heads))
1173 openheads = set(repo.branchmap().iteropen(heads))
1175 isactive = bool(openheads & allheads)
1174 isactive = bool(openheads & allheads)
1176 branches.append((tag, repo[tip], isactive, not isclosed))
1175 branches.append((tag, repo[tip], isactive, not isclosed))
1177 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1176 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1178 reverse=True)
1177 reverse=True)
1179
1178
1180 for tag, ctx, isactive, isopen in branches:
1179 for tag, ctx, isactive, isopen in branches:
1181 if active and not isactive:
1180 if active and not isactive:
1182 continue
1181 continue
1183 if isactive:
1182 if isactive:
1184 label = 'branches.active'
1183 label = 'branches.active'
1185 notice = ''
1184 notice = ''
1186 elif not isopen:
1185 elif not isopen:
1187 if not closed:
1186 if not closed:
1188 continue
1187 continue
1189 label = 'branches.closed'
1188 label = 'branches.closed'
1190 notice = _(' (closed)')
1189 notice = _(' (closed)')
1191 else:
1190 else:
1192 label = 'branches.inactive'
1191 label = 'branches.inactive'
1193 notice = _(' (inactive)')
1192 notice = _(' (inactive)')
1194 current = (tag == repo.dirstate.branch())
1193 current = (tag == repo.dirstate.branch())
1195 if current:
1194 if current:
1196 label = 'branches.current'
1195 label = 'branches.current'
1197
1196
1198 fm.startitem()
1197 fm.startitem()
1199 fm.write('branch', '%s', tag, label=label)
1198 fm.write('branch', '%s', tag, label=label)
1200 rev = ctx.rev()
1199 rev = ctx.rev()
1201 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1200 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1202 fmt = ' ' * padsize + ' %d:%s'
1201 fmt = ' ' * padsize + ' %d:%s'
1203 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1202 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1204 label='log.changeset changeset.%s' % ctx.phasestr())
1203 label='log.changeset changeset.%s' % ctx.phasestr())
1205 fm.context(ctx=ctx)
1204 fm.context(ctx=ctx)
1206 fm.data(active=isactive, closed=not isopen, current=current)
1205 fm.data(active=isactive, closed=not isopen, current=current)
1207 if not ui.quiet:
1206 if not ui.quiet:
1208 fm.plain(notice)
1207 fm.plain(notice)
1209 fm.plain('\n')
1208 fm.plain('\n')
1210 fm.end()
1209 fm.end()
1211
1210
1212 @command('bundle',
1211 @command('bundle',
1213 [('f', 'force', None, _('run even when the destination is unrelated')),
1212 [('f', 'force', None, _('run even when the destination is unrelated')),
1214 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1213 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1215 _('REV')),
1214 _('REV')),
1216 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1215 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1217 _('BRANCH')),
1216 _('BRANCH')),
1218 ('', 'base', [],
1217 ('', 'base', [],
1219 _('a base changeset assumed to be available at the destination'),
1218 _('a base changeset assumed to be available at the destination'),
1220 _('REV')),
1219 _('REV')),
1221 ('a', 'all', None, _('bundle all changesets in the repository')),
1220 ('a', 'all', None, _('bundle all changesets in the repository')),
1222 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1221 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1223 ] + remoteopts,
1222 ] + remoteopts,
1224 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1223 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1225 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1224 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1226 def bundle(ui, repo, fname, dest=None, **opts):
1225 def bundle(ui, repo, fname, dest=None, **opts):
1227 """create a bundle file
1226 """create a bundle file
1228
1227
1229 Generate a bundle file containing data to be transferred to another
1228 Generate a bundle file containing data to be transferred to another
1230 repository.
1229 repository.
1231
1230
1232 To create a bundle containing all changesets, use -a/--all
1231 To create a bundle containing all changesets, use -a/--all
1233 (or --base null). Otherwise, hg assumes the destination will have
1232 (or --base null). Otherwise, hg assumes the destination will have
1234 all the nodes you specify with --base parameters. Otherwise, hg
1233 all the nodes you specify with --base parameters. Otherwise, hg
1235 will assume the repository has all the nodes in destination, or
1234 will assume the repository has all the nodes in destination, or
1236 default-push/default if no destination is specified, where destination
1235 default-push/default if no destination is specified, where destination
1237 is the repository you provide through DEST option.
1236 is the repository you provide through DEST option.
1238
1237
1239 You can change bundle format with the -t/--type option. See
1238 You can change bundle format with the -t/--type option. See
1240 :hg:`help bundlespec` for documentation on this format. By default,
1239 :hg:`help bundlespec` for documentation on this format. By default,
1241 the most appropriate format is used and compression defaults to
1240 the most appropriate format is used and compression defaults to
1242 bzip2.
1241 bzip2.
1243
1242
1244 The bundle file can then be transferred using conventional means
1243 The bundle file can then be transferred using conventional means
1245 and applied to another repository with the unbundle or pull
1244 and applied to another repository with the unbundle or pull
1246 command. This is useful when direct push and pull are not
1245 command. This is useful when direct push and pull are not
1247 available or when exporting an entire repository is undesirable.
1246 available or when exporting an entire repository is undesirable.
1248
1247
1249 Applying bundles preserves all changeset contents including
1248 Applying bundles preserves all changeset contents including
1250 permissions, copy/rename information, and revision history.
1249 permissions, copy/rename information, and revision history.
1251
1250
1252 Returns 0 on success, 1 if no changes found.
1251 Returns 0 on success, 1 if no changes found.
1253 """
1252 """
1254 opts = pycompat.byteskwargs(opts)
1253 opts = pycompat.byteskwargs(opts)
1255 revs = None
1254 revs = None
1256 if 'rev' in opts:
1255 if 'rev' in opts:
1257 revstrings = opts['rev']
1256 revstrings = opts['rev']
1258 revs = scmutil.revrange(repo, revstrings)
1257 revs = scmutil.revrange(repo, revstrings)
1259 if revstrings and not revs:
1258 if revstrings and not revs:
1260 raise error.Abort(_('no commits to bundle'))
1259 raise error.Abort(_('no commits to bundle'))
1261
1260
1262 bundletype = opts.get('type', 'bzip2').lower()
1261 bundletype = opts.get('type', 'bzip2').lower()
1263 try:
1262 try:
1264 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1263 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1265 except error.UnsupportedBundleSpecification as e:
1264 except error.UnsupportedBundleSpecification as e:
1266 raise error.Abort(pycompat.bytestr(e),
1265 raise error.Abort(pycompat.bytestr(e),
1267 hint=_("see 'hg help bundlespec' for supported "
1266 hint=_("see 'hg help bundlespec' for supported "
1268 "values for --type"))
1267 "values for --type"))
1269 cgversion = bundlespec.contentopts["cg.version"]
1268 cgversion = bundlespec.contentopts["cg.version"]
1270
1269
1271 # Packed bundles are a pseudo bundle format for now.
1270 # Packed bundles are a pseudo bundle format for now.
1272 if cgversion == 's1':
1271 if cgversion == 's1':
1273 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1272 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1274 hint=_("use 'hg debugcreatestreamclonebundle'"))
1273 hint=_("use 'hg debugcreatestreamclonebundle'"))
1275
1274
1276 if opts.get('all'):
1275 if opts.get('all'):
1277 if dest:
1276 if dest:
1278 raise error.Abort(_("--all is incompatible with specifying "
1277 raise error.Abort(_("--all is incompatible with specifying "
1279 "a destination"))
1278 "a destination"))
1280 if opts.get('base'):
1279 if opts.get('base'):
1281 ui.warn(_("ignoring --base because --all was specified\n"))
1280 ui.warn(_("ignoring --base because --all was specified\n"))
1282 base = [nullrev]
1281 base = [nullrev]
1283 else:
1282 else:
1284 base = scmutil.revrange(repo, opts.get('base'))
1283 base = scmutil.revrange(repo, opts.get('base'))
1285 if cgversion not in changegroup.supportedoutgoingversions(repo):
1284 if cgversion not in changegroup.supportedoutgoingversions(repo):
1286 raise error.Abort(_("repository does not support bundle version %s") %
1285 raise error.Abort(_("repository does not support bundle version %s") %
1287 cgversion)
1286 cgversion)
1288
1287
1289 if base:
1288 if base:
1290 if dest:
1289 if dest:
1291 raise error.Abort(_("--base is incompatible with specifying "
1290 raise error.Abort(_("--base is incompatible with specifying "
1292 "a destination"))
1291 "a destination"))
1293 common = [repo[rev].node() for rev in base]
1292 common = [repo[rev].node() for rev in base]
1294 heads = [repo[r].node() for r in revs] if revs else None
1293 heads = [repo[r].node() for r in revs] if revs else None
1295 outgoing = discovery.outgoing(repo, common, heads)
1294 outgoing = discovery.outgoing(repo, common, heads)
1296 else:
1295 else:
1297 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1296 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1298 dest, branches = hg.parseurl(dest, opts.get('branch'))
1297 dest, branches = hg.parseurl(dest, opts.get('branch'))
1299 other = hg.peer(repo, opts, dest)
1298 other = hg.peer(repo, opts, dest)
1300 revs = [repo[r].hex() for r in revs]
1299 revs = [repo[r].hex() for r in revs]
1301 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1300 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1302 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1301 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1303 outgoing = discovery.findcommonoutgoing(repo, other,
1302 outgoing = discovery.findcommonoutgoing(repo, other,
1304 onlyheads=heads,
1303 onlyheads=heads,
1305 force=opts.get('force'),
1304 force=opts.get('force'),
1306 portable=True)
1305 portable=True)
1307
1306
1308 if not outgoing.missing:
1307 if not outgoing.missing:
1309 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1308 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1310 return 1
1309 return 1
1311
1310
1312 if cgversion == '01': #bundle1
1311 if cgversion == '01': #bundle1
1313 bversion = 'HG10' + bundlespec.wirecompression
1312 bversion = 'HG10' + bundlespec.wirecompression
1314 bcompression = None
1313 bcompression = None
1315 elif cgversion in ('02', '03'):
1314 elif cgversion in ('02', '03'):
1316 bversion = 'HG20'
1315 bversion = 'HG20'
1317 bcompression = bundlespec.wirecompression
1316 bcompression = bundlespec.wirecompression
1318 else:
1317 else:
1319 raise error.ProgrammingError(
1318 raise error.ProgrammingError(
1320 'bundle: unexpected changegroup version %s' % cgversion)
1319 'bundle: unexpected changegroup version %s' % cgversion)
1321
1320
1322 # TODO compression options should be derived from bundlespec parsing.
1321 # TODO compression options should be derived from bundlespec parsing.
1323 # This is a temporary hack to allow adjusting bundle compression
1322 # This is a temporary hack to allow adjusting bundle compression
1324 # level without a) formalizing the bundlespec changes to declare it
1323 # level without a) formalizing the bundlespec changes to declare it
1325 # b) introducing a command flag.
1324 # b) introducing a command flag.
1326 compopts = {}
1325 compopts = {}
1327 complevel = ui.configint('experimental',
1326 complevel = ui.configint('experimental',
1328 'bundlecomplevel.' + bundlespec.compression)
1327 'bundlecomplevel.' + bundlespec.compression)
1329 if complevel is None:
1328 if complevel is None:
1330 complevel = ui.configint('experimental', 'bundlecomplevel')
1329 complevel = ui.configint('experimental', 'bundlecomplevel')
1331 if complevel is not None:
1330 if complevel is not None:
1332 compopts['level'] = complevel
1331 compopts['level'] = complevel
1333
1332
1334 # Allow overriding the bundling of obsmarker in phases through
1333 # Allow overriding the bundling of obsmarker in phases through
1335 # configuration while we don't have a bundle version that include them
1334 # configuration while we don't have a bundle version that include them
1336 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1335 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1337 bundlespec.contentopts['obsolescence'] = True
1336 bundlespec.contentopts['obsolescence'] = True
1338 if repo.ui.configbool('experimental', 'bundle-phases'):
1337 if repo.ui.configbool('experimental', 'bundle-phases'):
1339 bundlespec.contentopts['phases'] = True
1338 bundlespec.contentopts['phases'] = True
1340
1339
1341 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1340 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1342 bundlespec.contentopts, compression=bcompression,
1341 bundlespec.contentopts, compression=bcompression,
1343 compopts=compopts)
1342 compopts=compopts)
1344
1343
1345 @command('cat',
1344 @command('cat',
1346 [('o', 'output', '',
1345 [('o', 'output', '',
1347 _('print output to file with formatted name'), _('FORMAT')),
1346 _('print output to file with formatted name'), _('FORMAT')),
1348 ('r', 'rev', '', _('print the given revision'), _('REV')),
1347 ('r', 'rev', '', _('print the given revision'), _('REV')),
1349 ('', 'decode', None, _('apply any matching decode filter')),
1348 ('', 'decode', None, _('apply any matching decode filter')),
1350 ] + walkopts + formatteropts,
1349 ] + walkopts + formatteropts,
1351 _('[OPTION]... FILE...'),
1350 _('[OPTION]... FILE...'),
1352 helpcategory=command.CATEGORY_FILE_CONTENTS,
1351 helpcategory=command.CATEGORY_FILE_CONTENTS,
1353 inferrepo=True,
1352 inferrepo=True,
1354 intents={INTENT_READONLY})
1353 intents={INTENT_READONLY})
1355 def cat(ui, repo, file1, *pats, **opts):
1354 def cat(ui, repo, file1, *pats, **opts):
1356 """output the current or given revision of files
1355 """output the current or given revision of files
1357
1356
1358 Print the specified files as they were at the given revision. If
1357 Print the specified files as they were at the given revision. If
1359 no revision is given, the parent of the working directory is used.
1358 no revision is given, the parent of the working directory is used.
1360
1359
1361 Output may be to a file, in which case the name of the file is
1360 Output may be to a file, in which case the name of the file is
1362 given using a template string. See :hg:`help templates`. In addition
1361 given using a template string. See :hg:`help templates`. In addition
1363 to the common template keywords, the following formatting rules are
1362 to the common template keywords, the following formatting rules are
1364 supported:
1363 supported:
1365
1364
1366 :``%%``: literal "%" character
1365 :``%%``: literal "%" character
1367 :``%s``: basename of file being printed
1366 :``%s``: basename of file being printed
1368 :``%d``: dirname of file being printed, or '.' if in repository root
1367 :``%d``: dirname of file being printed, or '.' if in repository root
1369 :``%p``: root-relative path name of file being printed
1368 :``%p``: root-relative path name of file being printed
1370 :``%H``: changeset hash (40 hexadecimal digits)
1369 :``%H``: changeset hash (40 hexadecimal digits)
1371 :``%R``: changeset revision number
1370 :``%R``: changeset revision number
1372 :``%h``: short-form changeset hash (12 hexadecimal digits)
1371 :``%h``: short-form changeset hash (12 hexadecimal digits)
1373 :``%r``: zero-padded changeset revision number
1372 :``%r``: zero-padded changeset revision number
1374 :``%b``: basename of the exporting repository
1373 :``%b``: basename of the exporting repository
1375 :``\\``: literal "\\" character
1374 :``\\``: literal "\\" character
1376
1375
1377 .. container:: verbose
1376 .. container:: verbose
1378
1377
1379 Template:
1378 Template:
1380
1379
1381 The following keywords are supported in addition to the common template
1380 The following keywords are supported in addition to the common template
1382 keywords and functions. See also :hg:`help templates`.
1381 keywords and functions. See also :hg:`help templates`.
1383
1382
1384 :data: String. File content.
1383 :data: String. File content.
1385 :path: String. Repository-absolute path of the file.
1384 :path: String. Repository-absolute path of the file.
1386
1385
1387 Returns 0 on success.
1386 Returns 0 on success.
1388 """
1387 """
1389 opts = pycompat.byteskwargs(opts)
1388 opts = pycompat.byteskwargs(opts)
1390 rev = opts.get('rev')
1389 rev = opts.get('rev')
1391 if rev:
1390 if rev:
1392 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1391 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1393 ctx = scmutil.revsingle(repo, rev)
1392 ctx = scmutil.revsingle(repo, rev)
1394 m = scmutil.match(ctx, (file1,) + pats, opts)
1393 m = scmutil.match(ctx, (file1,) + pats, opts)
1395 fntemplate = opts.pop('output', '')
1394 fntemplate = opts.pop('output', '')
1396 if cmdutil.isstdiofilename(fntemplate):
1395 if cmdutil.isstdiofilename(fntemplate):
1397 fntemplate = ''
1396 fntemplate = ''
1398
1397
1399 if fntemplate:
1398 if fntemplate:
1400 fm = formatter.nullformatter(ui, 'cat', opts)
1399 fm = formatter.nullformatter(ui, 'cat', opts)
1401 else:
1400 else:
1402 ui.pager('cat')
1401 ui.pager('cat')
1403 fm = ui.formatter('cat', opts)
1402 fm = ui.formatter('cat', opts)
1404 with fm:
1403 with fm:
1405 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1404 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1406 **pycompat.strkwargs(opts))
1405 **pycompat.strkwargs(opts))
1407
1406
1408 @command('clone',
1407 @command('clone',
1409 [('U', 'noupdate', None, _('the clone will include an empty working '
1408 [('U', 'noupdate', None, _('the clone will include an empty working '
1410 'directory (only a repository)')),
1409 'directory (only a repository)')),
1411 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1410 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1412 _('REV')),
1411 _('REV')),
1413 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1412 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1414 ' and its ancestors'), _('REV')),
1413 ' and its ancestors'), _('REV')),
1415 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1414 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1416 ' changesets and their ancestors'), _('BRANCH')),
1415 ' changesets and their ancestors'), _('BRANCH')),
1417 ('', 'pull', None, _('use pull protocol to copy metadata')),
1416 ('', 'pull', None, _('use pull protocol to copy metadata')),
1418 ('', 'uncompressed', None,
1417 ('', 'uncompressed', None,
1419 _('an alias to --stream (DEPRECATED)')),
1418 _('an alias to --stream (DEPRECATED)')),
1420 ('', 'stream', None,
1419 ('', 'stream', None,
1421 _('clone with minimal data processing')),
1420 _('clone with minimal data processing')),
1422 ] + remoteopts,
1421 ] + remoteopts,
1423 _('[OPTION]... SOURCE [DEST]'),
1422 _('[OPTION]... SOURCE [DEST]'),
1424 helpcategory=command.CATEGORY_REPO_CREATION,
1423 helpcategory=command.CATEGORY_REPO_CREATION,
1425 helpbasic=True, norepo=True)
1424 helpbasic=True, norepo=True)
1426 def clone(ui, source, dest=None, **opts):
1425 def clone(ui, source, dest=None, **opts):
1427 """make a copy of an existing repository
1426 """make a copy of an existing repository
1428
1427
1429 Create a copy of an existing repository in a new directory.
1428 Create a copy of an existing repository in a new directory.
1430
1429
1431 If no destination directory name is specified, it defaults to the
1430 If no destination directory name is specified, it defaults to the
1432 basename of the source.
1431 basename of the source.
1433
1432
1434 The location of the source is added to the new repository's
1433 The location of the source is added to the new repository's
1435 ``.hg/hgrc`` file, as the default to be used for future pulls.
1434 ``.hg/hgrc`` file, as the default to be used for future pulls.
1436
1435
1437 Only local paths and ``ssh://`` URLs are supported as
1436 Only local paths and ``ssh://`` URLs are supported as
1438 destinations. For ``ssh://`` destinations, no working directory or
1437 destinations. For ``ssh://`` destinations, no working directory or
1439 ``.hg/hgrc`` will be created on the remote side.
1438 ``.hg/hgrc`` will be created on the remote side.
1440
1439
1441 If the source repository has a bookmark called '@' set, that
1440 If the source repository has a bookmark called '@' set, that
1442 revision will be checked out in the new repository by default.
1441 revision will be checked out in the new repository by default.
1443
1442
1444 To check out a particular version, use -u/--update, or
1443 To check out a particular version, use -u/--update, or
1445 -U/--noupdate to create a clone with no working directory.
1444 -U/--noupdate to create a clone with no working directory.
1446
1445
1447 To pull only a subset of changesets, specify one or more revisions
1446 To pull only a subset of changesets, specify one or more revisions
1448 identifiers with -r/--rev or branches with -b/--branch. The
1447 identifiers with -r/--rev or branches with -b/--branch. The
1449 resulting clone will contain only the specified changesets and
1448 resulting clone will contain only the specified changesets and
1450 their ancestors. These options (or 'clone src#rev dest') imply
1449 their ancestors. These options (or 'clone src#rev dest') imply
1451 --pull, even for local source repositories.
1450 --pull, even for local source repositories.
1452
1451
1453 In normal clone mode, the remote normalizes repository data into a common
1452 In normal clone mode, the remote normalizes repository data into a common
1454 exchange format and the receiving end translates this data into its local
1453 exchange format and the receiving end translates this data into its local
1455 storage format. --stream activates a different clone mode that essentially
1454 storage format. --stream activates a different clone mode that essentially
1456 copies repository files from the remote with minimal data processing. This
1455 copies repository files from the remote with minimal data processing. This
1457 significantly reduces the CPU cost of a clone both remotely and locally.
1456 significantly reduces the CPU cost of a clone both remotely and locally.
1458 However, it often increases the transferred data size by 30-40%. This can
1457 However, it often increases the transferred data size by 30-40%. This can
1459 result in substantially faster clones where I/O throughput is plentiful,
1458 result in substantially faster clones where I/O throughput is plentiful,
1460 especially for larger repositories. A side-effect of --stream clones is
1459 especially for larger repositories. A side-effect of --stream clones is
1461 that storage settings and requirements on the remote are applied locally:
1460 that storage settings and requirements on the remote are applied locally:
1462 a modern client may inherit legacy or inefficient storage used by the
1461 a modern client may inherit legacy or inefficient storage used by the
1463 remote or a legacy Mercurial client may not be able to clone from a
1462 remote or a legacy Mercurial client may not be able to clone from a
1464 modern Mercurial remote.
1463 modern Mercurial remote.
1465
1464
1466 .. note::
1465 .. note::
1467
1466
1468 Specifying a tag will include the tagged changeset but not the
1467 Specifying a tag will include the tagged changeset but not the
1469 changeset containing the tag.
1468 changeset containing the tag.
1470
1469
1471 .. container:: verbose
1470 .. container:: verbose
1472
1471
1473 For efficiency, hardlinks are used for cloning whenever the
1472 For efficiency, hardlinks are used for cloning whenever the
1474 source and destination are on the same filesystem (note this
1473 source and destination are on the same filesystem (note this
1475 applies only to the repository data, not to the working
1474 applies only to the repository data, not to the working
1476 directory). Some filesystems, such as AFS, implement hardlinking
1475 directory). Some filesystems, such as AFS, implement hardlinking
1477 incorrectly, but do not report errors. In these cases, use the
1476 incorrectly, but do not report errors. In these cases, use the
1478 --pull option to avoid hardlinking.
1477 --pull option to avoid hardlinking.
1479
1478
1480 Mercurial will update the working directory to the first applicable
1479 Mercurial will update the working directory to the first applicable
1481 revision from this list:
1480 revision from this list:
1482
1481
1483 a) null if -U or the source repository has no changesets
1482 a) null if -U or the source repository has no changesets
1484 b) if -u . and the source repository is local, the first parent of
1483 b) if -u . and the source repository is local, the first parent of
1485 the source repository's working directory
1484 the source repository's working directory
1486 c) the changeset specified with -u (if a branch name, this means the
1485 c) the changeset specified with -u (if a branch name, this means the
1487 latest head of that branch)
1486 latest head of that branch)
1488 d) the changeset specified with -r
1487 d) the changeset specified with -r
1489 e) the tipmost head specified with -b
1488 e) the tipmost head specified with -b
1490 f) the tipmost head specified with the url#branch source syntax
1489 f) the tipmost head specified with the url#branch source syntax
1491 g) the revision marked with the '@' bookmark, if present
1490 g) the revision marked with the '@' bookmark, if present
1492 h) the tipmost head of the default branch
1491 h) the tipmost head of the default branch
1493 i) tip
1492 i) tip
1494
1493
1495 When cloning from servers that support it, Mercurial may fetch
1494 When cloning from servers that support it, Mercurial may fetch
1496 pre-generated data from a server-advertised URL or inline from the
1495 pre-generated data from a server-advertised URL or inline from the
1497 same stream. When this is done, hooks operating on incoming changesets
1496 same stream. When this is done, hooks operating on incoming changesets
1498 and changegroups may fire more than once, once for each pre-generated
1497 and changegroups may fire more than once, once for each pre-generated
1499 bundle and as well as for any additional remaining data. In addition,
1498 bundle and as well as for any additional remaining data. In addition,
1500 if an error occurs, the repository may be rolled back to a partial
1499 if an error occurs, the repository may be rolled back to a partial
1501 clone. This behavior may change in future releases.
1500 clone. This behavior may change in future releases.
1502 See :hg:`help -e clonebundles` for more.
1501 See :hg:`help -e clonebundles` for more.
1503
1502
1504 Examples:
1503 Examples:
1505
1504
1506 - clone a remote repository to a new directory named hg/::
1505 - clone a remote repository to a new directory named hg/::
1507
1506
1508 hg clone https://www.mercurial-scm.org/repo/hg/
1507 hg clone https://www.mercurial-scm.org/repo/hg/
1509
1508
1510 - create a lightweight local clone::
1509 - create a lightweight local clone::
1511
1510
1512 hg clone project/ project-feature/
1511 hg clone project/ project-feature/
1513
1512
1514 - clone from an absolute path on an ssh server (note double-slash)::
1513 - clone from an absolute path on an ssh server (note double-slash)::
1515
1514
1516 hg clone ssh://user@server//home/projects/alpha/
1515 hg clone ssh://user@server//home/projects/alpha/
1517
1516
1518 - do a streaming clone while checking out a specified version::
1517 - do a streaming clone while checking out a specified version::
1519
1518
1520 hg clone --stream http://server/repo -u 1.5
1519 hg clone --stream http://server/repo -u 1.5
1521
1520
1522 - create a repository without changesets after a particular revision::
1521 - create a repository without changesets after a particular revision::
1523
1522
1524 hg clone -r 04e544 experimental/ good/
1523 hg clone -r 04e544 experimental/ good/
1525
1524
1526 - clone (and track) a particular named branch::
1525 - clone (and track) a particular named branch::
1527
1526
1528 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1527 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1529
1528
1530 See :hg:`help urls` for details on specifying URLs.
1529 See :hg:`help urls` for details on specifying URLs.
1531
1530
1532 Returns 0 on success.
1531 Returns 0 on success.
1533 """
1532 """
1534 opts = pycompat.byteskwargs(opts)
1533 opts = pycompat.byteskwargs(opts)
1535 if opts.get('noupdate') and opts.get('updaterev'):
1534 if opts.get('noupdate') and opts.get('updaterev'):
1536 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1535 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1537
1536
1538 # --include/--exclude can come from narrow or sparse.
1537 # --include/--exclude can come from narrow or sparse.
1539 includepats, excludepats = None, None
1538 includepats, excludepats = None, None
1540
1539
1541 # hg.clone() differentiates between None and an empty set. So make sure
1540 # hg.clone() differentiates between None and an empty set. So make sure
1542 # patterns are sets if narrow is requested without patterns.
1541 # patterns are sets if narrow is requested without patterns.
1543 if opts.get('narrow'):
1542 if opts.get('narrow'):
1544 includepats = set()
1543 includepats = set()
1545 excludepats = set()
1544 excludepats = set()
1546
1545
1547 if opts.get('include'):
1546 if opts.get('include'):
1548 includepats = narrowspec.parsepatterns(opts.get('include'))
1547 includepats = narrowspec.parsepatterns(opts.get('include'))
1549 if opts.get('exclude'):
1548 if opts.get('exclude'):
1550 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1549 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1551
1550
1552 r = hg.clone(ui, opts, source, dest,
1551 r = hg.clone(ui, opts, source, dest,
1553 pull=opts.get('pull'),
1552 pull=opts.get('pull'),
1554 stream=opts.get('stream') or opts.get('uncompressed'),
1553 stream=opts.get('stream') or opts.get('uncompressed'),
1555 revs=opts.get('rev'),
1554 revs=opts.get('rev'),
1556 update=opts.get('updaterev') or not opts.get('noupdate'),
1555 update=opts.get('updaterev') or not opts.get('noupdate'),
1557 branch=opts.get('branch'),
1556 branch=opts.get('branch'),
1558 shareopts=opts.get('shareopts'),
1557 shareopts=opts.get('shareopts'),
1559 storeincludepats=includepats,
1558 storeincludepats=includepats,
1560 storeexcludepats=excludepats,
1559 storeexcludepats=excludepats,
1561 depth=opts.get('depth') or None)
1560 depth=opts.get('depth') or None)
1562
1561
1563 return r is None
1562 return r is None
1564
1563
1565 @command('commit|ci',
1564 @command('commit|ci',
1566 [('A', 'addremove', None,
1565 [('A', 'addremove', None,
1567 _('mark new/missing files as added/removed before committing')),
1566 _('mark new/missing files as added/removed before committing')),
1568 ('', 'close-branch', None,
1567 ('', 'close-branch', None,
1569 _('mark a branch head as closed')),
1568 _('mark a branch head as closed')),
1570 ('', 'amend', None, _('amend the parent of the working directory')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1571 ('s', 'secret', None, _('use the secret phase for committing')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1572 ('e', 'edit', None, _('invoke editor on commit messages')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1573 ('i', 'interactive', None, _('use interactive mode')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1574 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1575 _('[OPTION]... [FILE]...'),
1574 _('[OPTION]... [FILE]...'),
1576 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1575 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1577 inferrepo=True)
1576 inferrepo=True)
1578 def commit(ui, repo, *pats, **opts):
1577 def commit(ui, repo, *pats, **opts):
1579 """commit the specified files or all outstanding changes
1578 """commit the specified files or all outstanding changes
1580
1579
1581 Commit changes to the given files into the repository. Unlike a
1580 Commit changes to the given files into the repository. Unlike a
1582 centralized SCM, this operation is a local operation. See
1581 centralized SCM, this operation is a local operation. See
1583 :hg:`push` for a way to actively distribute your changes.
1582 :hg:`push` for a way to actively distribute your changes.
1584
1583
1585 If a list of files is omitted, all changes reported by :hg:`status`
1584 If a list of files is omitted, all changes reported by :hg:`status`
1586 will be committed.
1585 will be committed.
1587
1586
1588 If you are committing the result of a merge, do not provide any
1587 If you are committing the result of a merge, do not provide any
1589 filenames or -I/-X filters.
1588 filenames or -I/-X filters.
1590
1589
1591 If no commit message is specified, Mercurial starts your
1590 If no commit message is specified, Mercurial starts your
1592 configured editor where you can enter a message. In case your
1591 configured editor where you can enter a message. In case your
1593 commit fails, you will find a backup of your message in
1592 commit fails, you will find a backup of your message in
1594 ``.hg/last-message.txt``.
1593 ``.hg/last-message.txt``.
1595
1594
1596 The --close-branch flag can be used to mark the current branch
1595 The --close-branch flag can be used to mark the current branch
1597 head closed. When all heads of a branch are closed, the branch
1596 head closed. When all heads of a branch are closed, the branch
1598 will be considered closed and no longer listed.
1597 will be considered closed and no longer listed.
1599
1598
1600 The --amend flag can be used to amend the parent of the
1599 The --amend flag can be used to amend the parent of the
1601 working directory with a new commit that contains the changes
1600 working directory with a new commit that contains the changes
1602 in the parent in addition to those currently reported by :hg:`status`,
1601 in the parent in addition to those currently reported by :hg:`status`,
1603 if there are any. The old commit is stored in a backup bundle in
1602 if there are any. The old commit is stored in a backup bundle in
1604 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1605 on how to restore it).
1604 on how to restore it).
1606
1605
1607 Message, user and date are taken from the amended commit unless
1606 Message, user and date are taken from the amended commit unless
1608 specified. When a message isn't specified on the command line,
1607 specified. When a message isn't specified on the command line,
1609 the editor will open with the message of the amended commit.
1608 the editor will open with the message of the amended commit.
1610
1609
1611 It is not possible to amend public changesets (see :hg:`help phases`)
1610 It is not possible to amend public changesets (see :hg:`help phases`)
1612 or changesets that have children.
1611 or changesets that have children.
1613
1612
1614 See :hg:`help dates` for a list of formats valid for -d/--date.
1613 See :hg:`help dates` for a list of formats valid for -d/--date.
1615
1614
1616 Returns 0 on success, 1 if nothing changed.
1615 Returns 0 on success, 1 if nothing changed.
1617
1616
1618 .. container:: verbose
1617 .. container:: verbose
1619
1618
1620 Examples:
1619 Examples:
1621
1620
1622 - commit all files ending in .py::
1621 - commit all files ending in .py::
1623
1622
1624 hg commit --include "set:**.py"
1623 hg commit --include "set:**.py"
1625
1624
1626 - commit all non-binary files::
1625 - commit all non-binary files::
1627
1626
1628 hg commit --exclude "set:binary()"
1627 hg commit --exclude "set:binary()"
1629
1628
1630 - amend the current commit and set the date to now::
1629 - amend the current commit and set the date to now::
1631
1630
1632 hg commit --amend --date now
1631 hg commit --amend --date now
1633 """
1632 """
1634 with repo.wlock(), repo.lock():
1633 with repo.wlock(), repo.lock():
1635 return _docommit(ui, repo, *pats, **opts)
1634 return _docommit(ui, repo, *pats, **opts)
1636
1635
1637 def _docommit(ui, repo, *pats, **opts):
1636 def _docommit(ui, repo, *pats, **opts):
1638 if opts.get(r'interactive'):
1637 if opts.get(r'interactive'):
1639 opts.pop(r'interactive')
1638 opts.pop(r'interactive')
1640 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1639 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1641 cmdutil.recordfilter, *pats,
1640 cmdutil.recordfilter, *pats,
1642 **opts)
1641 **opts)
1643 # ret can be 0 (no changes to record) or the value returned by
1642 # ret can be 0 (no changes to record) or the value returned by
1644 # commit(), 1 if nothing changed or None on success.
1643 # commit(), 1 if nothing changed or None on success.
1645 return 1 if ret == 0 else ret
1644 return 1 if ret == 0 else ret
1646
1645
1647 opts = pycompat.byteskwargs(opts)
1646 opts = pycompat.byteskwargs(opts)
1648 if opts.get('subrepos'):
1647 if opts.get('subrepos'):
1649 if opts.get('amend'):
1648 if opts.get('amend'):
1650 raise error.Abort(_('cannot amend with --subrepos'))
1649 raise error.Abort(_('cannot amend with --subrepos'))
1651 # Let --subrepos on the command line override config setting.
1650 # Let --subrepos on the command line override config setting.
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1651 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1653
1652
1654 cmdutil.checkunfinished(repo, commit=True)
1653 cmdutil.checkunfinished(repo, commit=True)
1655
1654
1656 branch = repo[None].branch()
1655 branch = repo[None].branch()
1657 bheads = repo.branchheads(branch)
1656 bheads = repo.branchheads(branch)
1658
1657
1659 extra = {}
1658 extra = {}
1660 if opts.get('close_branch'):
1659 if opts.get('close_branch'):
1661 extra['close'] = '1'
1660 extra['close'] = '1'
1662
1661
1663 if not bheads:
1662 if not bheads:
1664 raise error.Abort(_('can only close branch heads'))
1663 raise error.Abort(_('can only close branch heads'))
1665 elif opts.get('amend'):
1664 elif opts.get('amend'):
1666 if repo[None].parents()[0].p1().branch() != branch and \
1665 if repo[None].parents()[0].p1().branch() != branch and \
1667 repo[None].parents()[0].p2().branch() != branch:
1666 repo[None].parents()[0].p2().branch() != branch:
1668 raise error.Abort(_('can only close branch heads'))
1667 raise error.Abort(_('can only close branch heads'))
1669
1668
1670 if opts.get('amend'):
1669 if opts.get('amend'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1670 if ui.configbool('ui', 'commitsubrepos'):
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1671 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1673
1672
1674 old = repo['.']
1673 old = repo['.']
1675 rewriteutil.precheck(repo, [old.rev()], 'amend')
1674 rewriteutil.precheck(repo, [old.rev()], 'amend')
1676
1675
1677 # Currently histedit gets confused if an amend happens while histedit
1676 # Currently histedit gets confused if an amend happens while histedit
1678 # is in progress. Since we have a checkunfinished command, we are
1677 # is in progress. Since we have a checkunfinished command, we are
1679 # temporarily honoring it.
1678 # temporarily honoring it.
1680 #
1679 #
1681 # Note: eventually this guard will be removed. Please do not expect
1680 # Note: eventually this guard will be removed. Please do not expect
1682 # this behavior to remain.
1681 # this behavior to remain.
1683 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1682 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1684 cmdutil.checkunfinished(repo)
1683 cmdutil.checkunfinished(repo)
1685
1684
1686 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1685 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1687 if node == old.node():
1686 if node == old.node():
1688 ui.status(_("nothing changed\n"))
1687 ui.status(_("nothing changed\n"))
1689 return 1
1688 return 1
1690 else:
1689 else:
1691 def commitfunc(ui, repo, message, match, opts):
1690 def commitfunc(ui, repo, message, match, opts):
1692 overrides = {}
1691 overrides = {}
1693 if opts.get('secret'):
1692 if opts.get('secret'):
1694 overrides[('phases', 'new-commit')] = 'secret'
1693 overrides[('phases', 'new-commit')] = 'secret'
1695
1694
1696 baseui = repo.baseui
1695 baseui = repo.baseui
1697 with baseui.configoverride(overrides, 'commit'):
1696 with baseui.configoverride(overrides, 'commit'):
1698 with ui.configoverride(overrides, 'commit'):
1697 with ui.configoverride(overrides, 'commit'):
1699 editform = cmdutil.mergeeditform(repo[None],
1698 editform = cmdutil.mergeeditform(repo[None],
1700 'commit.normal')
1699 'commit.normal')
1701 editor = cmdutil.getcommiteditor(
1700 editor = cmdutil.getcommiteditor(
1702 editform=editform, **pycompat.strkwargs(opts))
1701 editform=editform, **pycompat.strkwargs(opts))
1703 return repo.commit(message,
1702 return repo.commit(message,
1704 opts.get('user'),
1703 opts.get('user'),
1705 opts.get('date'),
1704 opts.get('date'),
1706 match,
1705 match,
1707 editor=editor,
1706 editor=editor,
1708 extra=extra)
1707 extra=extra)
1709
1708
1710 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1709 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1711
1710
1712 if not node:
1711 if not node:
1713 stat = cmdutil.postcommitstatus(repo, pats, opts)
1712 stat = cmdutil.postcommitstatus(repo, pats, opts)
1714 if stat[3]:
1713 if stat[3]:
1715 ui.status(_("nothing changed (%d missing files, see "
1714 ui.status(_("nothing changed (%d missing files, see "
1716 "'hg status')\n") % len(stat[3]))
1715 "'hg status')\n") % len(stat[3]))
1717 else:
1716 else:
1718 ui.status(_("nothing changed\n"))
1717 ui.status(_("nothing changed\n"))
1719 return 1
1718 return 1
1720
1719
1721 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1720 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1722
1721
1723 @command('config|showconfig|debugconfig',
1722 @command('config|showconfig|debugconfig',
1724 [('u', 'untrusted', None, _('show untrusted configuration options')),
1723 [('u', 'untrusted', None, _('show untrusted configuration options')),
1725 ('e', 'edit', None, _('edit user config')),
1724 ('e', 'edit', None, _('edit user config')),
1726 ('l', 'local', None, _('edit repository config')),
1725 ('l', 'local', None, _('edit repository config')),
1727 ('g', 'global', None, _('edit global config'))] + formatteropts,
1726 ('g', 'global', None, _('edit global config'))] + formatteropts,
1728 _('[-u] [NAME]...'),
1727 _('[-u] [NAME]...'),
1729 helpcategory=command.CATEGORY_HELP,
1728 helpcategory=command.CATEGORY_HELP,
1730 optionalrepo=True,
1729 optionalrepo=True,
1731 intents={INTENT_READONLY})
1730 intents={INTENT_READONLY})
1732 def config(ui, repo, *values, **opts):
1731 def config(ui, repo, *values, **opts):
1733 """show combined config settings from all hgrc files
1732 """show combined config settings from all hgrc files
1734
1733
1735 With no arguments, print names and values of all config items.
1734 With no arguments, print names and values of all config items.
1736
1735
1737 With one argument of the form section.name, print just the value
1736 With one argument of the form section.name, print just the value
1738 of that config item.
1737 of that config item.
1739
1738
1740 With multiple arguments, print names and values of all config
1739 With multiple arguments, print names and values of all config
1741 items with matching section names or section.names.
1740 items with matching section names or section.names.
1742
1741
1743 With --edit, start an editor on the user-level config file. With
1742 With --edit, start an editor on the user-level config file. With
1744 --global, edit the system-wide config file. With --local, edit the
1743 --global, edit the system-wide config file. With --local, edit the
1745 repository-level config file.
1744 repository-level config file.
1746
1745
1747 With --debug, the source (filename and line number) is printed
1746 With --debug, the source (filename and line number) is printed
1748 for each config item.
1747 for each config item.
1749
1748
1750 See :hg:`help config` for more information about config files.
1749 See :hg:`help config` for more information about config files.
1751
1750
1752 .. container:: verbose
1751 .. container:: verbose
1753
1752
1754 Template:
1753 Template:
1755
1754
1756 The following keywords are supported. See also :hg:`help templates`.
1755 The following keywords are supported. See also :hg:`help templates`.
1757
1756
1758 :name: String. Config name.
1757 :name: String. Config name.
1759 :source: String. Filename and line number where the item is defined.
1758 :source: String. Filename and line number where the item is defined.
1760 :value: String. Config value.
1759 :value: String. Config value.
1761
1760
1762 Returns 0 on success, 1 if NAME does not exist.
1761 Returns 0 on success, 1 if NAME does not exist.
1763
1762
1764 """
1763 """
1765
1764
1766 opts = pycompat.byteskwargs(opts)
1765 opts = pycompat.byteskwargs(opts)
1767 if opts.get('edit') or opts.get('local') or opts.get('global'):
1766 if opts.get('edit') or opts.get('local') or opts.get('global'):
1768 if opts.get('local') and opts.get('global'):
1767 if opts.get('local') and opts.get('global'):
1769 raise error.Abort(_("can't use --local and --global together"))
1768 raise error.Abort(_("can't use --local and --global together"))
1770
1769
1771 if opts.get('local'):
1770 if opts.get('local'):
1772 if not repo:
1771 if not repo:
1773 raise error.Abort(_("can't use --local outside a repository"))
1772 raise error.Abort(_("can't use --local outside a repository"))
1774 paths = [repo.vfs.join('hgrc')]
1773 paths = [repo.vfs.join('hgrc')]
1775 elif opts.get('global'):
1774 elif opts.get('global'):
1776 paths = rcutil.systemrcpath()
1775 paths = rcutil.systemrcpath()
1777 else:
1776 else:
1778 paths = rcutil.userrcpath()
1777 paths = rcutil.userrcpath()
1779
1778
1780 for f in paths:
1779 for f in paths:
1781 if os.path.exists(f):
1780 if os.path.exists(f):
1782 break
1781 break
1783 else:
1782 else:
1784 if opts.get('global'):
1783 if opts.get('global'):
1785 samplehgrc = uimod.samplehgrcs['global']
1784 samplehgrc = uimod.samplehgrcs['global']
1786 elif opts.get('local'):
1785 elif opts.get('local'):
1787 samplehgrc = uimod.samplehgrcs['local']
1786 samplehgrc = uimod.samplehgrcs['local']
1788 else:
1787 else:
1789 samplehgrc = uimod.samplehgrcs['user']
1788 samplehgrc = uimod.samplehgrcs['user']
1790
1789
1791 f = paths[0]
1790 f = paths[0]
1792 fp = open(f, "wb")
1791 fp = open(f, "wb")
1793 fp.write(util.tonativeeol(samplehgrc))
1792 fp.write(util.tonativeeol(samplehgrc))
1794 fp.close()
1793 fp.close()
1795
1794
1796 editor = ui.geteditor()
1795 editor = ui.geteditor()
1797 ui.system("%s \"%s\"" % (editor, f),
1796 ui.system("%s \"%s\"" % (editor, f),
1798 onerr=error.Abort, errprefix=_("edit failed"),
1797 onerr=error.Abort, errprefix=_("edit failed"),
1799 blockedtag='config_edit')
1798 blockedtag='config_edit')
1800 return
1799 return
1801 ui.pager('config')
1800 ui.pager('config')
1802 fm = ui.formatter('config', opts)
1801 fm = ui.formatter('config', opts)
1803 for t, f in rcutil.rccomponents():
1802 for t, f in rcutil.rccomponents():
1804 if t == 'path':
1803 if t == 'path':
1805 ui.debug('read config from: %s\n' % f)
1804 ui.debug('read config from: %s\n' % f)
1806 elif t == 'items':
1805 elif t == 'items':
1807 for section, name, value, source in f:
1806 for section, name, value, source in f:
1808 ui.debug('set config by: %s\n' % source)
1807 ui.debug('set config by: %s\n' % source)
1809 else:
1808 else:
1810 raise error.ProgrammingError('unknown rctype: %s' % t)
1809 raise error.ProgrammingError('unknown rctype: %s' % t)
1811 untrusted = bool(opts.get('untrusted'))
1810 untrusted = bool(opts.get('untrusted'))
1812
1811
1813 selsections = selentries = []
1812 selsections = selentries = []
1814 if values:
1813 if values:
1815 selsections = [v for v in values if '.' not in v]
1814 selsections = [v for v in values if '.' not in v]
1816 selentries = [v for v in values if '.' in v]
1815 selentries = [v for v in values if '.' in v]
1817 uniquesel = (len(selentries) == 1 and not selsections)
1816 uniquesel = (len(selentries) == 1 and not selsections)
1818 selsections = set(selsections)
1817 selsections = set(selsections)
1819 selentries = set(selentries)
1818 selentries = set(selentries)
1820
1819
1821 matched = False
1820 matched = False
1822 for section, name, value in ui.walkconfig(untrusted=untrusted):
1821 for section, name, value in ui.walkconfig(untrusted=untrusted):
1823 source = ui.configsource(section, name, untrusted)
1822 source = ui.configsource(section, name, untrusted)
1824 value = pycompat.bytestr(value)
1823 value = pycompat.bytestr(value)
1825 if fm.isplain():
1824 if fm.isplain():
1826 source = source or 'none'
1825 source = source or 'none'
1827 value = value.replace('\n', '\\n')
1826 value = value.replace('\n', '\\n')
1828 entryname = section + '.' + name
1827 entryname = section + '.' + name
1829 if values and not (section in selsections or entryname in selentries):
1828 if values and not (section in selsections or entryname in selentries):
1830 continue
1829 continue
1831 fm.startitem()
1830 fm.startitem()
1832 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1831 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1833 if uniquesel:
1832 if uniquesel:
1834 fm.data(name=entryname)
1833 fm.data(name=entryname)
1835 fm.write('value', '%s\n', value)
1834 fm.write('value', '%s\n', value)
1836 else:
1835 else:
1837 fm.write('name value', '%s=%s\n', entryname, value)
1836 fm.write('name value', '%s=%s\n', entryname, value)
1838 matched = True
1837 matched = True
1839 fm.end()
1838 fm.end()
1840 if matched:
1839 if matched:
1841 return 0
1840 return 0
1842 return 1
1841 return 1
1843
1842
1844 @command('copy|cp',
1843 @command('copy|cp',
1845 [('A', 'after', None, _('record a copy that has already occurred')),
1844 [('A', 'after', None, _('record a copy that has already occurred')),
1846 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1845 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1847 ] + walkopts + dryrunopts,
1846 ] + walkopts + dryrunopts,
1848 _('[OPTION]... [SOURCE]... DEST'),
1847 _('[OPTION]... [SOURCE]... DEST'),
1849 helpcategory=command.CATEGORY_FILE_CONTENTS)
1848 helpcategory=command.CATEGORY_FILE_CONTENTS)
1850 def copy(ui, repo, *pats, **opts):
1849 def copy(ui, repo, *pats, **opts):
1851 """mark files as copied for the next commit
1850 """mark files as copied for the next commit
1852
1851
1853 Mark dest as having copies of source files. If dest is a
1852 Mark dest as having copies of source files. If dest is a
1854 directory, copies are put in that directory. If dest is a file,
1853 directory, copies are put in that directory. If dest is a file,
1855 the source must be a single file.
1854 the source must be a single file.
1856
1855
1857 By default, this command copies the contents of files as they
1856 By default, this command copies the contents of files as they
1858 exist in the working directory. If invoked with -A/--after, the
1857 exist in the working directory. If invoked with -A/--after, the
1859 operation is recorded, but no copying is performed.
1858 operation is recorded, but no copying is performed.
1860
1859
1861 This command takes effect with the next commit. To undo a copy
1860 This command takes effect with the next commit. To undo a copy
1862 before that, see :hg:`revert`.
1861 before that, see :hg:`revert`.
1863
1862
1864 Returns 0 on success, 1 if errors are encountered.
1863 Returns 0 on success, 1 if errors are encountered.
1865 """
1864 """
1866 opts = pycompat.byteskwargs(opts)
1865 opts = pycompat.byteskwargs(opts)
1867 with repo.wlock(False):
1866 with repo.wlock(False):
1868 return cmdutil.copy(ui, repo, pats, opts)
1867 return cmdutil.copy(ui, repo, pats, opts)
1869
1868
1870 @command(
1869 @command(
1871 'debugcommands', [], _('[COMMAND]'),
1870 'debugcommands', [], _('[COMMAND]'),
1872 helpcategory=command.CATEGORY_HELP,
1871 helpcategory=command.CATEGORY_HELP,
1873 norepo=True)
1872 norepo=True)
1874 def debugcommands(ui, cmd='', *args):
1873 def debugcommands(ui, cmd='', *args):
1875 """list all available commands and options"""
1874 """list all available commands and options"""
1876 for cmd, vals in sorted(table.iteritems()):
1875 for cmd, vals in sorted(table.iteritems()):
1877 cmd = cmd.split('|')[0]
1876 cmd = cmd.split('|')[0]
1878 opts = ', '.join([i[1] for i in vals[1]])
1877 opts = ', '.join([i[1] for i in vals[1]])
1879 ui.write('%s: %s\n' % (cmd, opts))
1878 ui.write('%s: %s\n' % (cmd, opts))
1880
1879
1881 @command('debugcomplete',
1880 @command('debugcomplete',
1882 [('o', 'options', None, _('show the command options'))],
1881 [('o', 'options', None, _('show the command options'))],
1883 _('[-o] CMD'),
1882 _('[-o] CMD'),
1884 helpcategory=command.CATEGORY_HELP,
1883 helpcategory=command.CATEGORY_HELP,
1885 norepo=True)
1884 norepo=True)
1886 def debugcomplete(ui, cmd='', **opts):
1885 def debugcomplete(ui, cmd='', **opts):
1887 """returns the completion list associated with the given command"""
1886 """returns the completion list associated with the given command"""
1888
1887
1889 if opts.get(r'options'):
1888 if opts.get(r'options'):
1890 options = []
1889 options = []
1891 otables = [globalopts]
1890 otables = [globalopts]
1892 if cmd:
1891 if cmd:
1893 aliases, entry = cmdutil.findcmd(cmd, table, False)
1892 aliases, entry = cmdutil.findcmd(cmd, table, False)
1894 otables.append(entry[1])
1893 otables.append(entry[1])
1895 for t in otables:
1894 for t in otables:
1896 for o in t:
1895 for o in t:
1897 if "(DEPRECATED)" in o[3]:
1896 if "(DEPRECATED)" in o[3]:
1898 continue
1897 continue
1899 if o[0]:
1898 if o[0]:
1900 options.append('-%s' % o[0])
1899 options.append('-%s' % o[0])
1901 options.append('--%s' % o[1])
1900 options.append('--%s' % o[1])
1902 ui.write("%s\n" % "\n".join(options))
1901 ui.write("%s\n" % "\n".join(options))
1903 return
1902 return
1904
1903
1905 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1904 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1906 if ui.verbose:
1905 if ui.verbose:
1907 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1906 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1908 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1907 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1909
1908
1910 @command('diff',
1909 @command('diff',
1911 [('r', 'rev', [], _('revision'), _('REV')),
1910 [('r', 'rev', [], _('revision'), _('REV')),
1912 ('c', 'change', '', _('change made by revision'), _('REV'))
1911 ('c', 'change', '', _('change made by revision'), _('REV'))
1913 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1912 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1914 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1913 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1915 helpcategory=command.CATEGORY_FILE_CONTENTS,
1914 helpcategory=command.CATEGORY_FILE_CONTENTS,
1916 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1915 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1917 def diff(ui, repo, *pats, **opts):
1916 def diff(ui, repo, *pats, **opts):
1918 """diff repository (or selected files)
1917 """diff repository (or selected files)
1919
1918
1920 Show differences between revisions for the specified files.
1919 Show differences between revisions for the specified files.
1921
1920
1922 Differences between files are shown using the unified diff format.
1921 Differences between files are shown using the unified diff format.
1923
1922
1924 .. note::
1923 .. note::
1925
1924
1926 :hg:`diff` may generate unexpected results for merges, as it will
1925 :hg:`diff` may generate unexpected results for merges, as it will
1927 default to comparing against the working directory's first
1926 default to comparing against the working directory's first
1928 parent changeset if no revisions are specified.
1927 parent changeset if no revisions are specified.
1929
1928
1930 When two revision arguments are given, then changes are shown
1929 When two revision arguments are given, then changes are shown
1931 between those revisions. If only one revision is specified then
1930 between those revisions. If only one revision is specified then
1932 that revision is compared to the working directory, and, when no
1931 that revision is compared to the working directory, and, when no
1933 revisions are specified, the working directory files are compared
1932 revisions are specified, the working directory files are compared
1934 to its first parent.
1933 to its first parent.
1935
1934
1936 Alternatively you can specify -c/--change with a revision to see
1935 Alternatively you can specify -c/--change with a revision to see
1937 the changes in that changeset relative to its first parent.
1936 the changes in that changeset relative to its first parent.
1938
1937
1939 Without the -a/--text option, diff will avoid generating diffs of
1938 Without the -a/--text option, diff will avoid generating diffs of
1940 files it detects as binary. With -a, diff will generate a diff
1939 files it detects as binary. With -a, diff will generate a diff
1941 anyway, probably with undesirable results.
1940 anyway, probably with undesirable results.
1942
1941
1943 Use the -g/--git option to generate diffs in the git extended diff
1942 Use the -g/--git option to generate diffs in the git extended diff
1944 format. For more information, read :hg:`help diffs`.
1943 format. For more information, read :hg:`help diffs`.
1945
1944
1946 .. container:: verbose
1945 .. container:: verbose
1947
1946
1948 Examples:
1947 Examples:
1949
1948
1950 - compare a file in the current working directory to its parent::
1949 - compare a file in the current working directory to its parent::
1951
1950
1952 hg diff foo.c
1951 hg diff foo.c
1953
1952
1954 - compare two historical versions of a directory, with rename info::
1953 - compare two historical versions of a directory, with rename info::
1955
1954
1956 hg diff --git -r 1.0:1.2 lib/
1955 hg diff --git -r 1.0:1.2 lib/
1957
1956
1958 - get change stats relative to the last change on some date::
1957 - get change stats relative to the last change on some date::
1959
1958
1960 hg diff --stat -r "date('may 2')"
1959 hg diff --stat -r "date('may 2')"
1961
1960
1962 - diff all newly-added files that contain a keyword::
1961 - diff all newly-added files that contain a keyword::
1963
1962
1964 hg diff "set:added() and grep(GNU)"
1963 hg diff "set:added() and grep(GNU)"
1965
1964
1966 - compare a revision and its parents::
1965 - compare a revision and its parents::
1967
1966
1968 hg diff -c 9353 # compare against first parent
1967 hg diff -c 9353 # compare against first parent
1969 hg diff -r 9353^:9353 # same using revset syntax
1968 hg diff -r 9353^:9353 # same using revset syntax
1970 hg diff -r 9353^2:9353 # compare against the second parent
1969 hg diff -r 9353^2:9353 # compare against the second parent
1971
1970
1972 Returns 0 on success.
1971 Returns 0 on success.
1973 """
1972 """
1974
1973
1975 opts = pycompat.byteskwargs(opts)
1974 opts = pycompat.byteskwargs(opts)
1976 revs = opts.get('rev')
1975 revs = opts.get('rev')
1977 change = opts.get('change')
1976 change = opts.get('change')
1978 stat = opts.get('stat')
1977 stat = opts.get('stat')
1979 reverse = opts.get('reverse')
1978 reverse = opts.get('reverse')
1980
1979
1981 if revs and change:
1980 if revs and change:
1982 msg = _('cannot specify --rev and --change at the same time')
1981 msg = _('cannot specify --rev and --change at the same time')
1983 raise error.Abort(msg)
1982 raise error.Abort(msg)
1984 elif change:
1983 elif change:
1985 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1984 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1986 ctx2 = scmutil.revsingle(repo, change, None)
1985 ctx2 = scmutil.revsingle(repo, change, None)
1987 ctx1 = ctx2.p1()
1986 ctx1 = ctx2.p1()
1988 else:
1987 else:
1989 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1988 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1990 ctx1, ctx2 = scmutil.revpair(repo, revs)
1989 ctx1, ctx2 = scmutil.revpair(repo, revs)
1991 node1, node2 = ctx1.node(), ctx2.node()
1990 node1, node2 = ctx1.node(), ctx2.node()
1992
1991
1993 if reverse:
1992 if reverse:
1994 node1, node2 = node2, node1
1993 node1, node2 = node2, node1
1995
1994
1996 diffopts = patch.diffallopts(ui, opts)
1995 diffopts = patch.diffallopts(ui, opts)
1997 m = scmutil.match(ctx2, pats, opts)
1996 m = scmutil.match(ctx2, pats, opts)
1998 m = repo.narrowmatch(m)
1997 m = repo.narrowmatch(m)
1999 ui.pager('diff')
1998 ui.pager('diff')
2000 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1999 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2001 listsubrepos=opts.get('subrepos'),
2000 listsubrepos=opts.get('subrepos'),
2002 root=opts.get('root'))
2001 root=opts.get('root'))
2003
2002
2004 @command('export',
2003 @command('export',
2005 [('B', 'bookmark', '',
2004 [('B', 'bookmark', '',
2006 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2005 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2007 ('o', 'output', '',
2006 ('o', 'output', '',
2008 _('print output to file with formatted name'), _('FORMAT')),
2007 _('print output to file with formatted name'), _('FORMAT')),
2009 ('', 'switch-parent', None, _('diff against the second parent')),
2008 ('', 'switch-parent', None, _('diff against the second parent')),
2010 ('r', 'rev', [], _('revisions to export'), _('REV')),
2009 ('r', 'rev', [], _('revisions to export'), _('REV')),
2011 ] + diffopts + formatteropts,
2010 ] + diffopts + formatteropts,
2012 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2011 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2013 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2012 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2014 helpbasic=True, intents={INTENT_READONLY})
2013 helpbasic=True, intents={INTENT_READONLY})
2015 def export(ui, repo, *changesets, **opts):
2014 def export(ui, repo, *changesets, **opts):
2016 """dump the header and diffs for one or more changesets
2015 """dump the header and diffs for one or more changesets
2017
2016
2018 Print the changeset header and diffs for one or more revisions.
2017 Print the changeset header and diffs for one or more revisions.
2019 If no revision is given, the parent of the working directory is used.
2018 If no revision is given, the parent of the working directory is used.
2020
2019
2021 The information shown in the changeset header is: author, date,
2020 The information shown in the changeset header is: author, date,
2022 branch name (if non-default), changeset hash, parent(s) and commit
2021 branch name (if non-default), changeset hash, parent(s) and commit
2023 comment.
2022 comment.
2024
2023
2025 .. note::
2024 .. note::
2026
2025
2027 :hg:`export` may generate unexpected diff output for merge
2026 :hg:`export` may generate unexpected diff output for merge
2028 changesets, as it will compare the merge changeset against its
2027 changesets, as it will compare the merge changeset against its
2029 first parent only.
2028 first parent only.
2030
2029
2031 Output may be to a file, in which case the name of the file is
2030 Output may be to a file, in which case the name of the file is
2032 given using a template string. See :hg:`help templates`. In addition
2031 given using a template string. See :hg:`help templates`. In addition
2033 to the common template keywords, the following formatting rules are
2032 to the common template keywords, the following formatting rules are
2034 supported:
2033 supported:
2035
2034
2036 :``%%``: literal "%" character
2035 :``%%``: literal "%" character
2037 :``%H``: changeset hash (40 hexadecimal digits)
2036 :``%H``: changeset hash (40 hexadecimal digits)
2038 :``%N``: number of patches being generated
2037 :``%N``: number of patches being generated
2039 :``%R``: changeset revision number
2038 :``%R``: changeset revision number
2040 :``%b``: basename of the exporting repository
2039 :``%b``: basename of the exporting repository
2041 :``%h``: short-form changeset hash (12 hexadecimal digits)
2040 :``%h``: short-form changeset hash (12 hexadecimal digits)
2042 :``%m``: first line of the commit message (only alphanumeric characters)
2041 :``%m``: first line of the commit message (only alphanumeric characters)
2043 :``%n``: zero-padded sequence number, starting at 1
2042 :``%n``: zero-padded sequence number, starting at 1
2044 :``%r``: zero-padded changeset revision number
2043 :``%r``: zero-padded changeset revision number
2045 :``\\``: literal "\\" character
2044 :``\\``: literal "\\" character
2046
2045
2047 Without the -a/--text option, export will avoid generating diffs
2046 Without the -a/--text option, export will avoid generating diffs
2048 of files it detects as binary. With -a, export will generate a
2047 of files it detects as binary. With -a, export will generate a
2049 diff anyway, probably with undesirable results.
2048 diff anyway, probably with undesirable results.
2050
2049
2051 With -B/--bookmark changesets reachable by the given bookmark are
2050 With -B/--bookmark changesets reachable by the given bookmark are
2052 selected.
2051 selected.
2053
2052
2054 Use the -g/--git option to generate diffs in the git extended diff
2053 Use the -g/--git option to generate diffs in the git extended diff
2055 format. See :hg:`help diffs` for more information.
2054 format. See :hg:`help diffs` for more information.
2056
2055
2057 With the --switch-parent option, the diff will be against the
2056 With the --switch-parent option, the diff will be against the
2058 second parent. It can be useful to review a merge.
2057 second parent. It can be useful to review a merge.
2059
2058
2060 .. container:: verbose
2059 .. container:: verbose
2061
2060
2062 Template:
2061 Template:
2063
2062
2064 The following keywords are supported in addition to the common template
2063 The following keywords are supported in addition to the common template
2065 keywords and functions. See also :hg:`help templates`.
2064 keywords and functions. See also :hg:`help templates`.
2066
2065
2067 :diff: String. Diff content.
2066 :diff: String. Diff content.
2068 :parents: List of strings. Parent nodes of the changeset.
2067 :parents: List of strings. Parent nodes of the changeset.
2069
2068
2070 Examples:
2069 Examples:
2071
2070
2072 - use export and import to transplant a bugfix to the current
2071 - use export and import to transplant a bugfix to the current
2073 branch::
2072 branch::
2074
2073
2075 hg export -r 9353 | hg import -
2074 hg export -r 9353 | hg import -
2076
2075
2077 - export all the changesets between two revisions to a file with
2076 - export all the changesets between two revisions to a file with
2078 rename information::
2077 rename information::
2079
2078
2080 hg export --git -r 123:150 > changes.txt
2079 hg export --git -r 123:150 > changes.txt
2081
2080
2082 - split outgoing changes into a series of patches with
2081 - split outgoing changes into a series of patches with
2083 descriptive names::
2082 descriptive names::
2084
2083
2085 hg export -r "outgoing()" -o "%n-%m.patch"
2084 hg export -r "outgoing()" -o "%n-%m.patch"
2086
2085
2087 Returns 0 on success.
2086 Returns 0 on success.
2088 """
2087 """
2089 opts = pycompat.byteskwargs(opts)
2088 opts = pycompat.byteskwargs(opts)
2090 bookmark = opts.get('bookmark')
2089 bookmark = opts.get('bookmark')
2091 changesets += tuple(opts.get('rev', []))
2090 changesets += tuple(opts.get('rev', []))
2092
2091
2093 if bookmark and changesets:
2092 if bookmark and changesets:
2094 raise error.Abort(_("-r and -B are mutually exclusive"))
2093 raise error.Abort(_("-r and -B are mutually exclusive"))
2095
2094
2096 if bookmark:
2095 if bookmark:
2097 if bookmark not in repo._bookmarks:
2096 if bookmark not in repo._bookmarks:
2098 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2097 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2099
2098
2100 revs = scmutil.bookmarkrevs(repo, bookmark)
2099 revs = scmutil.bookmarkrevs(repo, bookmark)
2101 else:
2100 else:
2102 if not changesets:
2101 if not changesets:
2103 changesets = ['.']
2102 changesets = ['.']
2104
2103
2105 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2104 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2106 revs = scmutil.revrange(repo, changesets)
2105 revs = scmutil.revrange(repo, changesets)
2107
2106
2108 if not revs:
2107 if not revs:
2109 raise error.Abort(_("export requires at least one changeset"))
2108 raise error.Abort(_("export requires at least one changeset"))
2110 if len(revs) > 1:
2109 if len(revs) > 1:
2111 ui.note(_('exporting patches:\n'))
2110 ui.note(_('exporting patches:\n'))
2112 else:
2111 else:
2113 ui.note(_('exporting patch:\n'))
2112 ui.note(_('exporting patch:\n'))
2114
2113
2115 fntemplate = opts.get('output')
2114 fntemplate = opts.get('output')
2116 if cmdutil.isstdiofilename(fntemplate):
2115 if cmdutil.isstdiofilename(fntemplate):
2117 fntemplate = ''
2116 fntemplate = ''
2118
2117
2119 if fntemplate:
2118 if fntemplate:
2120 fm = formatter.nullformatter(ui, 'export', opts)
2119 fm = formatter.nullformatter(ui, 'export', opts)
2121 else:
2120 else:
2122 ui.pager('export')
2121 ui.pager('export')
2123 fm = ui.formatter('export', opts)
2122 fm = ui.formatter('export', opts)
2124 with fm:
2123 with fm:
2125 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2124 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2126 switch_parent=opts.get('switch_parent'),
2125 switch_parent=opts.get('switch_parent'),
2127 opts=patch.diffallopts(ui, opts))
2126 opts=patch.diffallopts(ui, opts))
2128
2127
2129 @command('files',
2128 @command('files',
2130 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2129 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2131 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2130 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2132 ] + walkopts + formatteropts + subrepoopts,
2131 ] + walkopts + formatteropts + subrepoopts,
2133 _('[OPTION]... [FILE]...'),
2132 _('[OPTION]... [FILE]...'),
2134 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2133 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2135 intents={INTENT_READONLY})
2134 intents={INTENT_READONLY})
2136 def files(ui, repo, *pats, **opts):
2135 def files(ui, repo, *pats, **opts):
2137 """list tracked files
2136 """list tracked files
2138
2137
2139 Print files under Mercurial control in the working directory or
2138 Print files under Mercurial control in the working directory or
2140 specified revision for given files (excluding removed files).
2139 specified revision for given files (excluding removed files).
2141 Files can be specified as filenames or filesets.
2140 Files can be specified as filenames or filesets.
2142
2141
2143 If no files are given to match, this command prints the names
2142 If no files are given to match, this command prints the names
2144 of all files under Mercurial control.
2143 of all files under Mercurial control.
2145
2144
2146 .. container:: verbose
2145 .. container:: verbose
2147
2146
2148 Template:
2147 Template:
2149
2148
2150 The following keywords are supported in addition to the common template
2149 The following keywords are supported in addition to the common template
2151 keywords and functions. See also :hg:`help templates`.
2150 keywords and functions. See also :hg:`help templates`.
2152
2151
2153 :flags: String. Character denoting file's symlink and executable bits.
2152 :flags: String. Character denoting file's symlink and executable bits.
2154 :path: String. Repository-absolute path of the file.
2153 :path: String. Repository-absolute path of the file.
2155 :size: Integer. Size of the file in bytes.
2154 :size: Integer. Size of the file in bytes.
2156
2155
2157 Examples:
2156 Examples:
2158
2157
2159 - list all files under the current directory::
2158 - list all files under the current directory::
2160
2159
2161 hg files .
2160 hg files .
2162
2161
2163 - shows sizes and flags for current revision::
2162 - shows sizes and flags for current revision::
2164
2163
2165 hg files -vr .
2164 hg files -vr .
2166
2165
2167 - list all files named README::
2166 - list all files named README::
2168
2167
2169 hg files -I "**/README"
2168 hg files -I "**/README"
2170
2169
2171 - list all binary files::
2170 - list all binary files::
2172
2171
2173 hg files "set:binary()"
2172 hg files "set:binary()"
2174
2173
2175 - find files containing a regular expression::
2174 - find files containing a regular expression::
2176
2175
2177 hg files "set:grep('bob')"
2176 hg files "set:grep('bob')"
2178
2177
2179 - search tracked file contents with xargs and grep::
2178 - search tracked file contents with xargs and grep::
2180
2179
2181 hg files -0 | xargs -0 grep foo
2180 hg files -0 | xargs -0 grep foo
2182
2181
2183 See :hg:`help patterns` and :hg:`help filesets` for more information
2182 See :hg:`help patterns` and :hg:`help filesets` for more information
2184 on specifying file patterns.
2183 on specifying file patterns.
2185
2184
2186 Returns 0 if a match is found, 1 otherwise.
2185 Returns 0 if a match is found, 1 otherwise.
2187
2186
2188 """
2187 """
2189
2188
2190 opts = pycompat.byteskwargs(opts)
2189 opts = pycompat.byteskwargs(opts)
2191 rev = opts.get('rev')
2190 rev = opts.get('rev')
2192 if rev:
2191 if rev:
2193 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2192 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2194 ctx = scmutil.revsingle(repo, rev, None)
2193 ctx = scmutil.revsingle(repo, rev, None)
2195
2194
2196 end = '\n'
2195 end = '\n'
2197 if opts.get('print0'):
2196 if opts.get('print0'):
2198 end = '\0'
2197 end = '\0'
2199 fmt = '%s' + end
2198 fmt = '%s' + end
2200
2199
2201 m = scmutil.match(ctx, pats, opts)
2200 m = scmutil.match(ctx, pats, opts)
2202 ui.pager('files')
2201 ui.pager('files')
2203 with ui.formatter('files', opts) as fm:
2202 with ui.formatter('files', opts) as fm:
2204 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2203 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2205
2204
2206 @command(
2205 @command(
2207 'forget',
2206 'forget',
2208 [('i', 'interactive', None, _('use interactive mode')),
2207 [('i', 'interactive', None, _('use interactive mode')),
2209 ] + walkopts + dryrunopts,
2208 ] + walkopts + dryrunopts,
2210 _('[OPTION]... FILE...'),
2209 _('[OPTION]... FILE...'),
2211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2212 helpbasic=True, inferrepo=True)
2211 helpbasic=True, inferrepo=True)
2213 def forget(ui, repo, *pats, **opts):
2212 def forget(ui, repo, *pats, **opts):
2214 """forget the specified files on the next commit
2213 """forget the specified files on the next commit
2215
2214
2216 Mark the specified files so they will no longer be tracked
2215 Mark the specified files so they will no longer be tracked
2217 after the next commit.
2216 after the next commit.
2218
2217
2219 This only removes files from the current branch, not from the
2218 This only removes files from the current branch, not from the
2220 entire project history, and it does not delete them from the
2219 entire project history, and it does not delete them from the
2221 working directory.
2220 working directory.
2222
2221
2223 To delete the file from the working directory, see :hg:`remove`.
2222 To delete the file from the working directory, see :hg:`remove`.
2224
2223
2225 To undo a forget before the next commit, see :hg:`add`.
2224 To undo a forget before the next commit, see :hg:`add`.
2226
2225
2227 .. container:: verbose
2226 .. container:: verbose
2228
2227
2229 Examples:
2228 Examples:
2230
2229
2231 - forget newly-added binary files::
2230 - forget newly-added binary files::
2232
2231
2233 hg forget "set:added() and binary()"
2232 hg forget "set:added() and binary()"
2234
2233
2235 - forget files that would be excluded by .hgignore::
2234 - forget files that would be excluded by .hgignore::
2236
2235
2237 hg forget "set:hgignore()"
2236 hg forget "set:hgignore()"
2238
2237
2239 Returns 0 on success.
2238 Returns 0 on success.
2240 """
2239 """
2241
2240
2242 opts = pycompat.byteskwargs(opts)
2241 opts = pycompat.byteskwargs(opts)
2243 if not pats:
2242 if not pats:
2244 raise error.Abort(_('no files specified'))
2243 raise error.Abort(_('no files specified'))
2245
2244
2246 m = scmutil.match(repo[None], pats, opts)
2245 m = scmutil.match(repo[None], pats, opts)
2247 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2246 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2248 rejected = cmdutil.forget(ui, repo, m, prefix="",
2247 rejected = cmdutil.forget(ui, repo, m, prefix="",
2249 explicitonly=False, dryrun=dryrun,
2248 explicitonly=False, dryrun=dryrun,
2250 interactive=interactive)[0]
2249 interactive=interactive)[0]
2251 return rejected and 1 or 0
2250 return rejected and 1 or 0
2252
2251
2253 @command(
2252 @command(
2254 'graft',
2253 'graft',
2255 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2254 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2256 ('', 'base', '',
2255 ('', 'base', '',
2257 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2256 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2258 ('c', 'continue', False, _('resume interrupted graft')),
2257 ('c', 'continue', False, _('resume interrupted graft')),
2259 ('', 'stop', False, _('stop interrupted graft')),
2258 ('', 'stop', False, _('stop interrupted graft')),
2260 ('', 'abort', False, _('abort interrupted graft')),
2259 ('', 'abort', False, _('abort interrupted graft')),
2261 ('e', 'edit', False, _('invoke editor on commit messages')),
2260 ('e', 'edit', False, _('invoke editor on commit messages')),
2262 ('', 'log', None, _('append graft info to log message')),
2261 ('', 'log', None, _('append graft info to log message')),
2263 ('', 'no-commit', None,
2262 ('', 'no-commit', None,
2264 _("don't commit, just apply the changes in working directory")),
2263 _("don't commit, just apply the changes in working directory")),
2265 ('f', 'force', False, _('force graft')),
2264 ('f', 'force', False, _('force graft')),
2266 ('D', 'currentdate', False,
2265 ('D', 'currentdate', False,
2267 _('record the current date as commit date')),
2266 _('record the current date as commit date')),
2268 ('U', 'currentuser', False,
2267 ('U', 'currentuser', False,
2269 _('record the current user as committer'))]
2268 _('record the current user as committer'))]
2270 + commitopts2 + mergetoolopts + dryrunopts,
2269 + commitopts2 + mergetoolopts + dryrunopts,
2271 _('[OPTION]... [-r REV]... REV...'),
2270 _('[OPTION]... [-r REV]... REV...'),
2272 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2271 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2273 def graft(ui, repo, *revs, **opts):
2272 def graft(ui, repo, *revs, **opts):
2274 '''copy changes from other branches onto the current branch
2273 '''copy changes from other branches onto the current branch
2275
2274
2276 This command uses Mercurial's merge logic to copy individual
2275 This command uses Mercurial's merge logic to copy individual
2277 changes from other branches without merging branches in the
2276 changes from other branches without merging branches in the
2278 history graph. This is sometimes known as 'backporting' or
2277 history graph. This is sometimes known as 'backporting' or
2279 'cherry-picking'. By default, graft will copy user, date, and
2278 'cherry-picking'. By default, graft will copy user, date, and
2280 description from the source changesets.
2279 description from the source changesets.
2281
2280
2282 Changesets that are ancestors of the current revision, that have
2281 Changesets that are ancestors of the current revision, that have
2283 already been grafted, or that are merges will be skipped.
2282 already been grafted, or that are merges will be skipped.
2284
2283
2285 If --log is specified, log messages will have a comment appended
2284 If --log is specified, log messages will have a comment appended
2286 of the form::
2285 of the form::
2287
2286
2288 (grafted from CHANGESETHASH)
2287 (grafted from CHANGESETHASH)
2289
2288
2290 If --force is specified, revisions will be grafted even if they
2289 If --force is specified, revisions will be grafted even if they
2291 are already ancestors of, or have been grafted to, the destination.
2290 are already ancestors of, or have been grafted to, the destination.
2292 This is useful when the revisions have since been backed out.
2291 This is useful when the revisions have since been backed out.
2293
2292
2294 If a graft merge results in conflicts, the graft process is
2293 If a graft merge results in conflicts, the graft process is
2295 interrupted so that the current merge can be manually resolved.
2294 interrupted so that the current merge can be manually resolved.
2296 Once all conflicts are addressed, the graft process can be
2295 Once all conflicts are addressed, the graft process can be
2297 continued with the -c/--continue option.
2296 continued with the -c/--continue option.
2298
2297
2299 The -c/--continue option reapplies all the earlier options.
2298 The -c/--continue option reapplies all the earlier options.
2300
2299
2301 .. container:: verbose
2300 .. container:: verbose
2302
2301
2303 The --base option exposes more of how graft internally uses merge with a
2302 The --base option exposes more of how graft internally uses merge with a
2304 custom base revision. --base can be used to specify another ancestor than
2303 custom base revision. --base can be used to specify another ancestor than
2305 the first and only parent.
2304 the first and only parent.
2306
2305
2307 The command::
2306 The command::
2308
2307
2309 hg graft -r 345 --base 234
2308 hg graft -r 345 --base 234
2310
2309
2311 is thus pretty much the same as::
2310 is thus pretty much the same as::
2312
2311
2313 hg diff -r 234 -r 345 | hg import
2312 hg diff -r 234 -r 345 | hg import
2314
2313
2315 but using merge to resolve conflicts and track moved files.
2314 but using merge to resolve conflicts and track moved files.
2316
2315
2317 The result of a merge can thus be backported as a single commit by
2316 The result of a merge can thus be backported as a single commit by
2318 specifying one of the merge parents as base, and thus effectively
2317 specifying one of the merge parents as base, and thus effectively
2319 grafting the changes from the other side.
2318 grafting the changes from the other side.
2320
2319
2321 It is also possible to collapse multiple changesets and clean up history
2320 It is also possible to collapse multiple changesets and clean up history
2322 by specifying another ancestor as base, much like rebase --collapse
2321 by specifying another ancestor as base, much like rebase --collapse
2323 --keep.
2322 --keep.
2324
2323
2325 The commit message can be tweaked after the fact using commit --amend .
2324 The commit message can be tweaked after the fact using commit --amend .
2326
2325
2327 For using non-ancestors as the base to backout changes, see the backout
2326 For using non-ancestors as the base to backout changes, see the backout
2328 command and the hidden --parent option.
2327 command and the hidden --parent option.
2329
2328
2330 .. container:: verbose
2329 .. container:: verbose
2331
2330
2332 Examples:
2331 Examples:
2333
2332
2334 - copy a single change to the stable branch and edit its description::
2333 - copy a single change to the stable branch and edit its description::
2335
2334
2336 hg update stable
2335 hg update stable
2337 hg graft --edit 9393
2336 hg graft --edit 9393
2338
2337
2339 - graft a range of changesets with one exception, updating dates::
2338 - graft a range of changesets with one exception, updating dates::
2340
2339
2341 hg graft -D "2085::2093 and not 2091"
2340 hg graft -D "2085::2093 and not 2091"
2342
2341
2343 - continue a graft after resolving conflicts::
2342 - continue a graft after resolving conflicts::
2344
2343
2345 hg graft -c
2344 hg graft -c
2346
2345
2347 - show the source of a grafted changeset::
2346 - show the source of a grafted changeset::
2348
2347
2349 hg log --debug -r .
2348 hg log --debug -r .
2350
2349
2351 - show revisions sorted by date::
2350 - show revisions sorted by date::
2352
2351
2353 hg log -r "sort(all(), date)"
2352 hg log -r "sort(all(), date)"
2354
2353
2355 - backport the result of a merge as a single commit::
2354 - backport the result of a merge as a single commit::
2356
2355
2357 hg graft -r 123 --base 123^
2356 hg graft -r 123 --base 123^
2358
2357
2359 - land a feature branch as one changeset::
2358 - land a feature branch as one changeset::
2360
2359
2361 hg up -cr default
2360 hg up -cr default
2362 hg graft -r featureX --base "ancestor('featureX', 'default')"
2361 hg graft -r featureX --base "ancestor('featureX', 'default')"
2363
2362
2364 See :hg:`help revisions` for more about specifying revisions.
2363 See :hg:`help revisions` for more about specifying revisions.
2365
2364
2366 Returns 0 on successful completion.
2365 Returns 0 on successful completion.
2367 '''
2366 '''
2368 with repo.wlock():
2367 with repo.wlock():
2369 return _dograft(ui, repo, *revs, **opts)
2368 return _dograft(ui, repo, *revs, **opts)
2370
2369
2371 def _dograft(ui, repo, *revs, **opts):
2370 def _dograft(ui, repo, *revs, **opts):
2372 opts = pycompat.byteskwargs(opts)
2371 opts = pycompat.byteskwargs(opts)
2373 if revs and opts.get('rev'):
2372 if revs and opts.get('rev'):
2374 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2373 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2375 'revision ordering!\n'))
2374 'revision ordering!\n'))
2376
2375
2377 revs = list(revs)
2376 revs = list(revs)
2378 revs.extend(opts.get('rev'))
2377 revs.extend(opts.get('rev'))
2379 basectx = None
2378 basectx = None
2380 if opts.get('base'):
2379 if opts.get('base'):
2381 basectx = scmutil.revsingle(repo, opts['base'], None)
2380 basectx = scmutil.revsingle(repo, opts['base'], None)
2382 # a dict of data to be stored in state file
2381 # a dict of data to be stored in state file
2383 statedata = {}
2382 statedata = {}
2384 # list of new nodes created by ongoing graft
2383 # list of new nodes created by ongoing graft
2385 statedata['newnodes'] = []
2384 statedata['newnodes'] = []
2386
2385
2387 if not opts.get('user') and opts.get('currentuser'):
2386 if not opts.get('user') and opts.get('currentuser'):
2388 opts['user'] = ui.username()
2387 opts['user'] = ui.username()
2389 if not opts.get('date') and opts.get('currentdate'):
2388 if not opts.get('date') and opts.get('currentdate'):
2390 opts['date'] = "%d %d" % dateutil.makedate()
2389 opts['date'] = "%d %d" % dateutil.makedate()
2391
2390
2392 editor = cmdutil.getcommiteditor(editform='graft',
2391 editor = cmdutil.getcommiteditor(editform='graft',
2393 **pycompat.strkwargs(opts))
2392 **pycompat.strkwargs(opts))
2394
2393
2395 cont = False
2394 cont = False
2396 if opts.get('no_commit'):
2395 if opts.get('no_commit'):
2397 if opts.get('edit'):
2396 if opts.get('edit'):
2398 raise error.Abort(_("cannot specify --no-commit and "
2397 raise error.Abort(_("cannot specify --no-commit and "
2399 "--edit together"))
2398 "--edit together"))
2400 if opts.get('currentuser'):
2399 if opts.get('currentuser'):
2401 raise error.Abort(_("cannot specify --no-commit and "
2400 raise error.Abort(_("cannot specify --no-commit and "
2402 "--currentuser together"))
2401 "--currentuser together"))
2403 if opts.get('currentdate'):
2402 if opts.get('currentdate'):
2404 raise error.Abort(_("cannot specify --no-commit and "
2403 raise error.Abort(_("cannot specify --no-commit and "
2405 "--currentdate together"))
2404 "--currentdate together"))
2406 if opts.get('log'):
2405 if opts.get('log'):
2407 raise error.Abort(_("cannot specify --no-commit and "
2406 raise error.Abort(_("cannot specify --no-commit and "
2408 "--log together"))
2407 "--log together"))
2409
2408
2410 graftstate = statemod.cmdstate(repo, 'graftstate')
2409 graftstate = statemod.cmdstate(repo, 'graftstate')
2411
2410
2412 if opts.get('stop'):
2411 if opts.get('stop'):
2413 if opts.get('continue'):
2412 if opts.get('continue'):
2414 raise error.Abort(_("cannot use '--continue' and "
2413 raise error.Abort(_("cannot use '--continue' and "
2415 "'--stop' together"))
2414 "'--stop' together"))
2416 if opts.get('abort'):
2415 if opts.get('abort'):
2417 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2416 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2418
2417
2419 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2418 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2420 opts.get('date'), opts.get('currentdate'),
2419 opts.get('date'), opts.get('currentdate'),
2421 opts.get('currentuser'), opts.get('rev'))):
2420 opts.get('currentuser'), opts.get('rev'))):
2422 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2421 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2423 return _stopgraft(ui, repo, graftstate)
2422 return _stopgraft(ui, repo, graftstate)
2424 elif opts.get('abort'):
2423 elif opts.get('abort'):
2425 if opts.get('continue'):
2424 if opts.get('continue'):
2426 raise error.Abort(_("cannot use '--continue' and "
2425 raise error.Abort(_("cannot use '--continue' and "
2427 "'--abort' together"))
2426 "'--abort' together"))
2428 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2427 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2429 opts.get('date'), opts.get('currentdate'),
2428 opts.get('date'), opts.get('currentdate'),
2430 opts.get('currentuser'), opts.get('rev'))):
2429 opts.get('currentuser'), opts.get('rev'))):
2431 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2430 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2432
2431
2433 return _abortgraft(ui, repo, graftstate)
2432 return _abortgraft(ui, repo, graftstate)
2434 elif opts.get('continue'):
2433 elif opts.get('continue'):
2435 cont = True
2434 cont = True
2436 if revs:
2435 if revs:
2437 raise error.Abort(_("can't specify --continue and revisions"))
2436 raise error.Abort(_("can't specify --continue and revisions"))
2438 # read in unfinished revisions
2437 # read in unfinished revisions
2439 if graftstate.exists():
2438 if graftstate.exists():
2440 statedata = _readgraftstate(repo, graftstate)
2439 statedata = _readgraftstate(repo, graftstate)
2441 if statedata.get('date'):
2440 if statedata.get('date'):
2442 opts['date'] = statedata['date']
2441 opts['date'] = statedata['date']
2443 if statedata.get('user'):
2442 if statedata.get('user'):
2444 opts['user'] = statedata['user']
2443 opts['user'] = statedata['user']
2445 if statedata.get('log'):
2444 if statedata.get('log'):
2446 opts['log'] = True
2445 opts['log'] = True
2447 if statedata.get('no_commit'):
2446 if statedata.get('no_commit'):
2448 opts['no_commit'] = statedata.get('no_commit')
2447 opts['no_commit'] = statedata.get('no_commit')
2449 nodes = statedata['nodes']
2448 nodes = statedata['nodes']
2450 revs = [repo[node].rev() for node in nodes]
2449 revs = [repo[node].rev() for node in nodes]
2451 else:
2450 else:
2452 cmdutil.wrongtooltocontinue(repo, _('graft'))
2451 cmdutil.wrongtooltocontinue(repo, _('graft'))
2453 else:
2452 else:
2454 if not revs:
2453 if not revs:
2455 raise error.Abort(_('no revisions specified'))
2454 raise error.Abort(_('no revisions specified'))
2456 cmdutil.checkunfinished(repo)
2455 cmdutil.checkunfinished(repo)
2457 cmdutil.bailifchanged(repo)
2456 cmdutil.bailifchanged(repo)
2458 revs = scmutil.revrange(repo, revs)
2457 revs = scmutil.revrange(repo, revs)
2459
2458
2460 skipped = set()
2459 skipped = set()
2461 if basectx is None:
2460 if basectx is None:
2462 # check for merges
2461 # check for merges
2463 for rev in repo.revs('%ld and merge()', revs):
2462 for rev in repo.revs('%ld and merge()', revs):
2464 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2463 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2465 skipped.add(rev)
2464 skipped.add(rev)
2466 revs = [r for r in revs if r not in skipped]
2465 revs = [r for r in revs if r not in skipped]
2467 if not revs:
2466 if not revs:
2468 return -1
2467 return -1
2469 if basectx is not None and len(revs) != 1:
2468 if basectx is not None and len(revs) != 1:
2470 raise error.Abort(_('only one revision allowed with --base '))
2469 raise error.Abort(_('only one revision allowed with --base '))
2471
2470
2472 # Don't check in the --continue case, in effect retaining --force across
2471 # Don't check in the --continue case, in effect retaining --force across
2473 # --continues. That's because without --force, any revisions we decided to
2472 # --continues. That's because without --force, any revisions we decided to
2474 # skip would have been filtered out here, so they wouldn't have made their
2473 # skip would have been filtered out here, so they wouldn't have made their
2475 # way to the graftstate. With --force, any revisions we would have otherwise
2474 # way to the graftstate. With --force, any revisions we would have otherwise
2476 # skipped would not have been filtered out, and if they hadn't been applied
2475 # skipped would not have been filtered out, and if they hadn't been applied
2477 # already, they'd have been in the graftstate.
2476 # already, they'd have been in the graftstate.
2478 if not (cont or opts.get('force')) and basectx is None:
2477 if not (cont or opts.get('force')) and basectx is None:
2479 # check for ancestors of dest branch
2478 # check for ancestors of dest branch
2480 crev = repo['.'].rev()
2479 crev = repo['.'].rev()
2481 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2480 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2482 # XXX make this lazy in the future
2481 # XXX make this lazy in the future
2483 # don't mutate while iterating, create a copy
2482 # don't mutate while iterating, create a copy
2484 for rev in list(revs):
2483 for rev in list(revs):
2485 if rev in ancestors:
2484 if rev in ancestors:
2486 ui.warn(_('skipping ancestor revision %d:%s\n') %
2485 ui.warn(_('skipping ancestor revision %d:%s\n') %
2487 (rev, repo[rev]))
2486 (rev, repo[rev]))
2488 # XXX remove on list is slow
2487 # XXX remove on list is slow
2489 revs.remove(rev)
2488 revs.remove(rev)
2490 if not revs:
2489 if not revs:
2491 return -1
2490 return -1
2492
2491
2493 # analyze revs for earlier grafts
2492 # analyze revs for earlier grafts
2494 ids = {}
2493 ids = {}
2495 for ctx in repo.set("%ld", revs):
2494 for ctx in repo.set("%ld", revs):
2496 ids[ctx.hex()] = ctx.rev()
2495 ids[ctx.hex()] = ctx.rev()
2497 n = ctx.extra().get('source')
2496 n = ctx.extra().get('source')
2498 if n:
2497 if n:
2499 ids[n] = ctx.rev()
2498 ids[n] = ctx.rev()
2500
2499
2501 # check ancestors for earlier grafts
2500 # check ancestors for earlier grafts
2502 ui.debug('scanning for duplicate grafts\n')
2501 ui.debug('scanning for duplicate grafts\n')
2503
2502
2504 # The only changesets we can be sure doesn't contain grafts of any
2503 # The only changesets we can be sure doesn't contain grafts of any
2505 # revs, are the ones that are common ancestors of *all* revs:
2504 # revs, are the ones that are common ancestors of *all* revs:
2506 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2505 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2507 ctx = repo[rev]
2506 ctx = repo[rev]
2508 n = ctx.extra().get('source')
2507 n = ctx.extra().get('source')
2509 if n in ids:
2508 if n in ids:
2510 try:
2509 try:
2511 r = repo[n].rev()
2510 r = repo[n].rev()
2512 except error.RepoLookupError:
2511 except error.RepoLookupError:
2513 r = None
2512 r = None
2514 if r in revs:
2513 if r in revs:
2515 ui.warn(_('skipping revision %d:%s '
2514 ui.warn(_('skipping revision %d:%s '
2516 '(already grafted to %d:%s)\n')
2515 '(already grafted to %d:%s)\n')
2517 % (r, repo[r], rev, ctx))
2516 % (r, repo[r], rev, ctx))
2518 revs.remove(r)
2517 revs.remove(r)
2519 elif ids[n] in revs:
2518 elif ids[n] in revs:
2520 if r is None:
2519 if r is None:
2521 ui.warn(_('skipping already grafted revision %d:%s '
2520 ui.warn(_('skipping already grafted revision %d:%s '
2522 '(%d:%s also has unknown origin %s)\n')
2521 '(%d:%s also has unknown origin %s)\n')
2523 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2522 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2524 else:
2523 else:
2525 ui.warn(_('skipping already grafted revision %d:%s '
2524 ui.warn(_('skipping already grafted revision %d:%s '
2526 '(%d:%s also has origin %d:%s)\n')
2525 '(%d:%s also has origin %d:%s)\n')
2527 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2526 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2528 revs.remove(ids[n])
2527 revs.remove(ids[n])
2529 elif ctx.hex() in ids:
2528 elif ctx.hex() in ids:
2530 r = ids[ctx.hex()]
2529 r = ids[ctx.hex()]
2531 if r in revs:
2530 if r in revs:
2532 ui.warn(_('skipping already grafted revision %d:%s '
2531 ui.warn(_('skipping already grafted revision %d:%s '
2533 '(was grafted from %d:%s)\n') %
2532 '(was grafted from %d:%s)\n') %
2534 (r, repo[r], rev, ctx))
2533 (r, repo[r], rev, ctx))
2535 revs.remove(r)
2534 revs.remove(r)
2536 if not revs:
2535 if not revs:
2537 return -1
2536 return -1
2538
2537
2539 if opts.get('no_commit'):
2538 if opts.get('no_commit'):
2540 statedata['no_commit'] = True
2539 statedata['no_commit'] = True
2541 for pos, ctx in enumerate(repo.set("%ld", revs)):
2540 for pos, ctx in enumerate(repo.set("%ld", revs)):
2542 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2541 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2543 ctx.description().split('\n', 1)[0])
2542 ctx.description().split('\n', 1)[0])
2544 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2543 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2545 if names:
2544 if names:
2546 desc += ' (%s)' % ' '.join(names)
2545 desc += ' (%s)' % ' '.join(names)
2547 ui.status(_('grafting %s\n') % desc)
2546 ui.status(_('grafting %s\n') % desc)
2548 if opts.get('dry_run'):
2547 if opts.get('dry_run'):
2549 continue
2548 continue
2550
2549
2551 source = ctx.extra().get('source')
2550 source = ctx.extra().get('source')
2552 extra = {}
2551 extra = {}
2553 if source:
2552 if source:
2554 extra['source'] = source
2553 extra['source'] = source
2555 extra['intermediate-source'] = ctx.hex()
2554 extra['intermediate-source'] = ctx.hex()
2556 else:
2555 else:
2557 extra['source'] = ctx.hex()
2556 extra['source'] = ctx.hex()
2558 user = ctx.user()
2557 user = ctx.user()
2559 if opts.get('user'):
2558 if opts.get('user'):
2560 user = opts['user']
2559 user = opts['user']
2561 statedata['user'] = user
2560 statedata['user'] = user
2562 date = ctx.date()
2561 date = ctx.date()
2563 if opts.get('date'):
2562 if opts.get('date'):
2564 date = opts['date']
2563 date = opts['date']
2565 statedata['date'] = date
2564 statedata['date'] = date
2566 message = ctx.description()
2565 message = ctx.description()
2567 if opts.get('log'):
2566 if opts.get('log'):
2568 message += '\n(grafted from %s)' % ctx.hex()
2567 message += '\n(grafted from %s)' % ctx.hex()
2569 statedata['log'] = True
2568 statedata['log'] = True
2570
2569
2571 # we don't merge the first commit when continuing
2570 # we don't merge the first commit when continuing
2572 if not cont:
2571 if not cont:
2573 # perform the graft merge with p1(rev) as 'ancestor'
2572 # perform the graft merge with p1(rev) as 'ancestor'
2574 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2573 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2575 base = ctx.p1() if basectx is None else basectx
2574 base = ctx.p1() if basectx is None else basectx
2576 with ui.configoverride(overrides, 'graft'):
2575 with ui.configoverride(overrides, 'graft'):
2577 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2576 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2578 # report any conflicts
2577 # report any conflicts
2579 if stats.unresolvedcount > 0:
2578 if stats.unresolvedcount > 0:
2580 # write out state for --continue
2579 # write out state for --continue
2581 nodes = [repo[rev].hex() for rev in revs[pos:]]
2580 nodes = [repo[rev].hex() for rev in revs[pos:]]
2582 statedata['nodes'] = nodes
2581 statedata['nodes'] = nodes
2583 stateversion = 1
2582 stateversion = 1
2584 graftstate.save(stateversion, statedata)
2583 graftstate.save(stateversion, statedata)
2585 hint = _("use 'hg resolve' and 'hg graft --continue'")
2584 hint = _("use 'hg resolve' and 'hg graft --continue'")
2586 raise error.Abort(
2585 raise error.Abort(
2587 _("unresolved conflicts, can't continue"),
2586 _("unresolved conflicts, can't continue"),
2588 hint=hint)
2587 hint=hint)
2589 else:
2588 else:
2590 cont = False
2589 cont = False
2591
2590
2592 # commit if --no-commit is false
2591 # commit if --no-commit is false
2593 if not opts.get('no_commit'):
2592 if not opts.get('no_commit'):
2594 node = repo.commit(text=message, user=user, date=date, extra=extra,
2593 node = repo.commit(text=message, user=user, date=date, extra=extra,
2595 editor=editor)
2594 editor=editor)
2596 if node is None:
2595 if node is None:
2597 ui.warn(
2596 ui.warn(
2598 _('note: graft of %d:%s created no changes to commit\n') %
2597 _('note: graft of %d:%s created no changes to commit\n') %
2599 (ctx.rev(), ctx))
2598 (ctx.rev(), ctx))
2600 # checking that newnodes exist because old state files won't have it
2599 # checking that newnodes exist because old state files won't have it
2601 elif statedata.get('newnodes') is not None:
2600 elif statedata.get('newnodes') is not None:
2602 statedata['newnodes'].append(node)
2601 statedata['newnodes'].append(node)
2603
2602
2604 # remove state when we complete successfully
2603 # remove state when we complete successfully
2605 if not opts.get('dry_run'):
2604 if not opts.get('dry_run'):
2606 graftstate.delete()
2605 graftstate.delete()
2607
2606
2608 return 0
2607 return 0
2609
2608
2610 def _abortgraft(ui, repo, graftstate):
2609 def _abortgraft(ui, repo, graftstate):
2611 """abort the interrupted graft and rollbacks to the state before interrupted
2610 """abort the interrupted graft and rollbacks to the state before interrupted
2612 graft"""
2611 graft"""
2613 if not graftstate.exists():
2612 if not graftstate.exists():
2614 raise error.Abort(_("no interrupted graft to abort"))
2613 raise error.Abort(_("no interrupted graft to abort"))
2615 statedata = _readgraftstate(repo, graftstate)
2614 statedata = _readgraftstate(repo, graftstate)
2616 newnodes = statedata.get('newnodes')
2615 newnodes = statedata.get('newnodes')
2617 if newnodes is None:
2616 if newnodes is None:
2618 # and old graft state which does not have all the data required to abort
2617 # and old graft state which does not have all the data required to abort
2619 # the graft
2618 # the graft
2620 raise error.Abort(_("cannot abort using an old graftstate"))
2619 raise error.Abort(_("cannot abort using an old graftstate"))
2621
2620
2622 # changeset from which graft operation was started
2621 # changeset from which graft operation was started
2623 startctx = None
2622 startctx = None
2624 if len(newnodes) > 0:
2623 if len(newnodes) > 0:
2625 startctx = repo[newnodes[0]].p1()
2624 startctx = repo[newnodes[0]].p1()
2626 else:
2625 else:
2627 startctx = repo['.']
2626 startctx = repo['.']
2628 # whether to strip or not
2627 # whether to strip or not
2629 cleanup = False
2628 cleanup = False
2630 if newnodes:
2629 if newnodes:
2631 newnodes = [repo[r].rev() for r in newnodes]
2630 newnodes = [repo[r].rev() for r in newnodes]
2632 cleanup = True
2631 cleanup = True
2633 # checking that none of the newnodes turned public or is public
2632 # checking that none of the newnodes turned public or is public
2634 immutable = [c for c in newnodes if not repo[c].mutable()]
2633 immutable = [c for c in newnodes if not repo[c].mutable()]
2635 if immutable:
2634 if immutable:
2636 repo.ui.warn(_("cannot clean up public changesets %s\n")
2635 repo.ui.warn(_("cannot clean up public changesets %s\n")
2637 % ', '.join(bytes(repo[r]) for r in immutable),
2636 % ', '.join(bytes(repo[r]) for r in immutable),
2638 hint=_("see 'hg help phases' for details"))
2637 hint=_("see 'hg help phases' for details"))
2639 cleanup = False
2638 cleanup = False
2640
2639
2641 # checking that no new nodes are created on top of grafted revs
2640 # checking that no new nodes are created on top of grafted revs
2642 desc = set(repo.changelog.descendants(newnodes))
2641 desc = set(repo.changelog.descendants(newnodes))
2643 if desc - set(newnodes):
2642 if desc - set(newnodes):
2644 repo.ui.warn(_("new changesets detected on destination "
2643 repo.ui.warn(_("new changesets detected on destination "
2645 "branch, can't strip\n"))
2644 "branch, can't strip\n"))
2646 cleanup = False
2645 cleanup = False
2647
2646
2648 if cleanup:
2647 if cleanup:
2649 with repo.wlock(), repo.lock():
2648 with repo.wlock(), repo.lock():
2650 hg.updaterepo(repo, startctx.node(), overwrite=True)
2649 hg.updaterepo(repo, startctx.node(), overwrite=True)
2651 # stripping the new nodes created
2650 # stripping the new nodes created
2652 strippoints = [c.node() for c in repo.set("roots(%ld)",
2651 strippoints = [c.node() for c in repo.set("roots(%ld)",
2653 newnodes)]
2652 newnodes)]
2654 repair.strip(repo.ui, repo, strippoints, backup=False)
2653 repair.strip(repo.ui, repo, strippoints, backup=False)
2655
2654
2656 if not cleanup:
2655 if not cleanup:
2657 # we don't update to the startnode if we can't strip
2656 # we don't update to the startnode if we can't strip
2658 startctx = repo['.']
2657 startctx = repo['.']
2659 hg.updaterepo(repo, startctx.node(), overwrite=True)
2658 hg.updaterepo(repo, startctx.node(), overwrite=True)
2660
2659
2661 ui.status(_("graft aborted\n"))
2660 ui.status(_("graft aborted\n"))
2662 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2661 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2663 graftstate.delete()
2662 graftstate.delete()
2664 return 0
2663 return 0
2665
2664
2666 def _readgraftstate(repo, graftstate):
2665 def _readgraftstate(repo, graftstate):
2667 """read the graft state file and return a dict of the data stored in it"""
2666 """read the graft state file and return a dict of the data stored in it"""
2668 try:
2667 try:
2669 return graftstate.read()
2668 return graftstate.read()
2670 except error.CorruptedState:
2669 except error.CorruptedState:
2671 nodes = repo.vfs.read('graftstate').splitlines()
2670 nodes = repo.vfs.read('graftstate').splitlines()
2672 return {'nodes': nodes}
2671 return {'nodes': nodes}
2673
2672
2674 def _stopgraft(ui, repo, graftstate):
2673 def _stopgraft(ui, repo, graftstate):
2675 """stop the interrupted graft"""
2674 """stop the interrupted graft"""
2676 if not graftstate.exists():
2675 if not graftstate.exists():
2677 raise error.Abort(_("no interrupted graft found"))
2676 raise error.Abort(_("no interrupted graft found"))
2678 pctx = repo['.']
2677 pctx = repo['.']
2679 hg.updaterepo(repo, pctx.node(), overwrite=True)
2678 hg.updaterepo(repo, pctx.node(), overwrite=True)
2680 graftstate.delete()
2679 graftstate.delete()
2681 ui.status(_("stopped the interrupted graft\n"))
2680 ui.status(_("stopped the interrupted graft\n"))
2682 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2681 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2683 return 0
2682 return 0
2684
2683
2685 @command('grep',
2684 @command('grep',
2686 [('0', 'print0', None, _('end fields with NUL')),
2685 [('0', 'print0', None, _('end fields with NUL')),
2687 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2686 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2688 ('', 'diff', None, _('print all revisions when the term was introduced '
2687 ('', 'diff', None, _('print all revisions when the term was introduced '
2689 'or removed')),
2688 'or removed')),
2690 ('a', 'text', None, _('treat all files as text')),
2689 ('a', 'text', None, _('treat all files as text')),
2691 ('f', 'follow', None,
2690 ('f', 'follow', None,
2692 _('follow changeset history,'
2691 _('follow changeset history,'
2693 ' or file history across copies and renames')),
2692 ' or file history across copies and renames')),
2694 ('i', 'ignore-case', None, _('ignore case when matching')),
2693 ('i', 'ignore-case', None, _('ignore case when matching')),
2695 ('l', 'files-with-matches', None,
2694 ('l', 'files-with-matches', None,
2696 _('print only filenames and revisions that match')),
2695 _('print only filenames and revisions that match')),
2697 ('n', 'line-number', None, _('print matching line numbers')),
2696 ('n', 'line-number', None, _('print matching line numbers')),
2698 ('r', 'rev', [],
2697 ('r', 'rev', [],
2699 _('only search files changed within revision range'), _('REV')),
2698 _('only search files changed within revision range'), _('REV')),
2700 ('', 'all-files', None,
2699 ('', 'all-files', None,
2701 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2700 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2702 ('u', 'user', None, _('list the author (long with -v)')),
2701 ('u', 'user', None, _('list the author (long with -v)')),
2703 ('d', 'date', None, _('list the date (short with -q)')),
2702 ('d', 'date', None, _('list the date (short with -q)')),
2704 ] + formatteropts + walkopts,
2703 ] + formatteropts + walkopts,
2705 _('[OPTION]... PATTERN [FILE]...'),
2704 _('[OPTION]... PATTERN [FILE]...'),
2706 helpcategory=command.CATEGORY_FILE_CONTENTS,
2705 helpcategory=command.CATEGORY_FILE_CONTENTS,
2707 inferrepo=True,
2706 inferrepo=True,
2708 intents={INTENT_READONLY})
2707 intents={INTENT_READONLY})
2709 def grep(ui, repo, pattern, *pats, **opts):
2708 def grep(ui, repo, pattern, *pats, **opts):
2710 """search revision history for a pattern in specified files
2709 """search revision history for a pattern in specified files
2711
2710
2712 Search revision history for a regular expression in the specified
2711 Search revision history for a regular expression in the specified
2713 files or the entire project.
2712 files or the entire project.
2714
2713
2715 By default, grep prints the most recent revision number for each
2714 By default, grep prints the most recent revision number for each
2716 file in which it finds a match. To get it to print every revision
2715 file in which it finds a match. To get it to print every revision
2717 that contains a change in match status ("-" for a match that becomes
2716 that contains a change in match status ("-" for a match that becomes
2718 a non-match, or "+" for a non-match that becomes a match), use the
2717 a non-match, or "+" for a non-match that becomes a match), use the
2719 --diff flag.
2718 --diff flag.
2720
2719
2721 PATTERN can be any Python (roughly Perl-compatible) regular
2720 PATTERN can be any Python (roughly Perl-compatible) regular
2722 expression.
2721 expression.
2723
2722
2724 If no FILEs are specified (and -f/--follow isn't set), all files in
2723 If no FILEs are specified (and -f/--follow isn't set), all files in
2725 the repository are searched, including those that don't exist in the
2724 the repository are searched, including those that don't exist in the
2726 current branch or have been deleted in a prior changeset.
2725 current branch or have been deleted in a prior changeset.
2727
2726
2728 .. container:: verbose
2727 .. container:: verbose
2729
2728
2730 Template:
2729 Template:
2731
2730
2732 The following keywords are supported in addition to the common template
2731 The following keywords are supported in addition to the common template
2733 keywords and functions. See also :hg:`help templates`.
2732 keywords and functions. See also :hg:`help templates`.
2734
2733
2735 :change: String. Character denoting insertion ``+`` or removal ``-``.
2734 :change: String. Character denoting insertion ``+`` or removal ``-``.
2736 Available if ``--diff`` is specified.
2735 Available if ``--diff`` is specified.
2737 :lineno: Integer. Line number of the match.
2736 :lineno: Integer. Line number of the match.
2738 :path: String. Repository-absolute path of the file.
2737 :path: String. Repository-absolute path of the file.
2739 :texts: List of text chunks.
2738 :texts: List of text chunks.
2740
2739
2741 And each entry of ``{texts}`` provides the following sub-keywords.
2740 And each entry of ``{texts}`` provides the following sub-keywords.
2742
2741
2743 :matched: Boolean. True if the chunk matches the specified pattern.
2742 :matched: Boolean. True if the chunk matches the specified pattern.
2744 :text: String. Chunk content.
2743 :text: String. Chunk content.
2745
2744
2746 See :hg:`help templates.operators` for the list expansion syntax.
2745 See :hg:`help templates.operators` for the list expansion syntax.
2747
2746
2748 Returns 0 if a match is found, 1 otherwise.
2747 Returns 0 if a match is found, 1 otherwise.
2749 """
2748 """
2750 opts = pycompat.byteskwargs(opts)
2749 opts = pycompat.byteskwargs(opts)
2751 diff = opts.get('all') or opts.get('diff')
2750 diff = opts.get('all') or opts.get('diff')
2752 all_files = opts.get('all_files')
2751 all_files = opts.get('all_files')
2753 if diff and opts.get('all_files'):
2752 if diff and opts.get('all_files'):
2754 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2753 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2755 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2754 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2756 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2755 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2757 # experimental config: commands.grep.all-files
2756 # experimental config: commands.grep.all-files
2758 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2757 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2759 plaingrep = opts.get('all_files') and not opts.get('rev')
2758 plaingrep = opts.get('all_files') and not opts.get('rev')
2760 if plaingrep:
2759 if plaingrep:
2761 opts['rev'] = ['wdir()']
2760 opts['rev'] = ['wdir()']
2762
2761
2763 reflags = re.M
2762 reflags = re.M
2764 if opts.get('ignore_case'):
2763 if opts.get('ignore_case'):
2765 reflags |= re.I
2764 reflags |= re.I
2766 try:
2765 try:
2767 regexp = util.re.compile(pattern, reflags)
2766 regexp = util.re.compile(pattern, reflags)
2768 except re.error as inst:
2767 except re.error as inst:
2769 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2768 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2770 return 1
2769 return 1
2771 sep, eol = ':', '\n'
2770 sep, eol = ':', '\n'
2772 if opts.get('print0'):
2771 if opts.get('print0'):
2773 sep = eol = '\0'
2772 sep = eol = '\0'
2774
2773
2775 getfile = util.lrucachefunc(repo.file)
2774 getfile = util.lrucachefunc(repo.file)
2776
2775
2777 def matchlines(body):
2776 def matchlines(body):
2778 begin = 0
2777 begin = 0
2779 linenum = 0
2778 linenum = 0
2780 while begin < len(body):
2779 while begin < len(body):
2781 match = regexp.search(body, begin)
2780 match = regexp.search(body, begin)
2782 if not match:
2781 if not match:
2783 break
2782 break
2784 mstart, mend = match.span()
2783 mstart, mend = match.span()
2785 linenum += body.count('\n', begin, mstart) + 1
2784 linenum += body.count('\n', begin, mstart) + 1
2786 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2785 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2787 begin = body.find('\n', mend) + 1 or len(body) + 1
2786 begin = body.find('\n', mend) + 1 or len(body) + 1
2788 lend = begin - 1
2787 lend = begin - 1
2789 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2788 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2790
2789
2791 class linestate(object):
2790 class linestate(object):
2792 def __init__(self, line, linenum, colstart, colend):
2791 def __init__(self, line, linenum, colstart, colend):
2793 self.line = line
2792 self.line = line
2794 self.linenum = linenum
2793 self.linenum = linenum
2795 self.colstart = colstart
2794 self.colstart = colstart
2796 self.colend = colend
2795 self.colend = colend
2797
2796
2798 def __hash__(self):
2797 def __hash__(self):
2799 return hash((self.linenum, self.line))
2798 return hash((self.linenum, self.line))
2800
2799
2801 def __eq__(self, other):
2800 def __eq__(self, other):
2802 return self.line == other.line
2801 return self.line == other.line
2803
2802
2804 def findpos(self):
2803 def findpos(self):
2805 """Iterate all (start, end) indices of matches"""
2804 """Iterate all (start, end) indices of matches"""
2806 yield self.colstart, self.colend
2805 yield self.colstart, self.colend
2807 p = self.colend
2806 p = self.colend
2808 while p < len(self.line):
2807 while p < len(self.line):
2809 m = regexp.search(self.line, p)
2808 m = regexp.search(self.line, p)
2810 if not m:
2809 if not m:
2811 break
2810 break
2812 yield m.span()
2811 yield m.span()
2813 p = m.end()
2812 p = m.end()
2814
2813
2815 matches = {}
2814 matches = {}
2816 copies = {}
2815 copies = {}
2817 def grepbody(fn, rev, body):
2816 def grepbody(fn, rev, body):
2818 matches[rev].setdefault(fn, [])
2817 matches[rev].setdefault(fn, [])
2819 m = matches[rev][fn]
2818 m = matches[rev][fn]
2820 for lnum, cstart, cend, line in matchlines(body):
2819 for lnum, cstart, cend, line in matchlines(body):
2821 s = linestate(line, lnum, cstart, cend)
2820 s = linestate(line, lnum, cstart, cend)
2822 m.append(s)
2821 m.append(s)
2823
2822
2824 def difflinestates(a, b):
2823 def difflinestates(a, b):
2825 sm = difflib.SequenceMatcher(None, a, b)
2824 sm = difflib.SequenceMatcher(None, a, b)
2826 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2825 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2827 if tag == r'insert':
2826 if tag == r'insert':
2828 for i in pycompat.xrange(blo, bhi):
2827 for i in pycompat.xrange(blo, bhi):
2829 yield ('+', b[i])
2828 yield ('+', b[i])
2830 elif tag == r'delete':
2829 elif tag == r'delete':
2831 for i in pycompat.xrange(alo, ahi):
2830 for i in pycompat.xrange(alo, ahi):
2832 yield ('-', a[i])
2831 yield ('-', a[i])
2833 elif tag == r'replace':
2832 elif tag == r'replace':
2834 for i in pycompat.xrange(alo, ahi):
2833 for i in pycompat.xrange(alo, ahi):
2835 yield ('-', a[i])
2834 yield ('-', a[i])
2836 for i in pycompat.xrange(blo, bhi):
2835 for i in pycompat.xrange(blo, bhi):
2837 yield ('+', b[i])
2836 yield ('+', b[i])
2838
2837
2839 def display(fm, fn, ctx, pstates, states):
2838 def display(fm, fn, ctx, pstates, states):
2840 rev = scmutil.intrev(ctx)
2839 rev = scmutil.intrev(ctx)
2841 if fm.isplain():
2840 if fm.isplain():
2842 formatuser = ui.shortuser
2841 formatuser = ui.shortuser
2843 else:
2842 else:
2844 formatuser = pycompat.bytestr
2843 formatuser = pycompat.bytestr
2845 if ui.quiet:
2844 if ui.quiet:
2846 datefmt = '%Y-%m-%d'
2845 datefmt = '%Y-%m-%d'
2847 else:
2846 else:
2848 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2847 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2849 found = False
2848 found = False
2850 @util.cachefunc
2849 @util.cachefunc
2851 def binary():
2850 def binary():
2852 flog = getfile(fn)
2851 flog = getfile(fn)
2853 try:
2852 try:
2854 return stringutil.binary(flog.read(ctx.filenode(fn)))
2853 return stringutil.binary(flog.read(ctx.filenode(fn)))
2855 except error.WdirUnsupported:
2854 except error.WdirUnsupported:
2856 return ctx[fn].isbinary()
2855 return ctx[fn].isbinary()
2857
2856
2858 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2857 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2859 if diff:
2858 if diff:
2860 iter = difflinestates(pstates, states)
2859 iter = difflinestates(pstates, states)
2861 else:
2860 else:
2862 iter = [('', l) for l in states]
2861 iter = [('', l) for l in states]
2863 for change, l in iter:
2862 for change, l in iter:
2864 fm.startitem()
2863 fm.startitem()
2865 fm.context(ctx=ctx)
2864 fm.context(ctx=ctx)
2866 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2865 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2867
2866
2868 cols = [
2867 cols = [
2869 ('filename', '%s', fn, True),
2868 ('filename', '%s', fn, True),
2870 ('rev', '%d', rev, not plaingrep),
2869 ('rev', '%d', rev, not plaingrep),
2871 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2870 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2872 ]
2871 ]
2873 if diff:
2872 if diff:
2874 cols.append(('change', '%s', change, True))
2873 cols.append(('change', '%s', change, True))
2875 cols.extend([
2874 cols.extend([
2876 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2875 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2877 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2876 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2878 opts.get('date')),
2877 opts.get('date')),
2879 ])
2878 ])
2880 lastcol = next(
2879 lastcol = next(
2881 name for name, fmt, data, cond in reversed(cols) if cond)
2880 name for name, fmt, data, cond in reversed(cols) if cond)
2882 for name, fmt, data, cond in cols:
2881 for name, fmt, data, cond in cols:
2883 field = fieldnamemap.get(name, name)
2882 field = fieldnamemap.get(name, name)
2884 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2883 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2885 if cond and name != lastcol:
2884 if cond and name != lastcol:
2886 fm.plain(sep, label='grep.sep')
2885 fm.plain(sep, label='grep.sep')
2887 if not opts.get('files_with_matches'):
2886 if not opts.get('files_with_matches'):
2888 fm.plain(sep, label='grep.sep')
2887 fm.plain(sep, label='grep.sep')
2889 if not opts.get('text') and binary():
2888 if not opts.get('text') and binary():
2890 fm.plain(_(" Binary file matches"))
2889 fm.plain(_(" Binary file matches"))
2891 else:
2890 else:
2892 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2891 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2893 fm.plain(eol)
2892 fm.plain(eol)
2894 found = True
2893 found = True
2895 if opts.get('files_with_matches'):
2894 if opts.get('files_with_matches'):
2896 break
2895 break
2897 return found
2896 return found
2898
2897
2899 def displaymatches(fm, l):
2898 def displaymatches(fm, l):
2900 p = 0
2899 p = 0
2901 for s, e in l.findpos():
2900 for s, e in l.findpos():
2902 if p < s:
2901 if p < s:
2903 fm.startitem()
2902 fm.startitem()
2904 fm.write('text', '%s', l.line[p:s])
2903 fm.write('text', '%s', l.line[p:s])
2905 fm.data(matched=False)
2904 fm.data(matched=False)
2906 fm.startitem()
2905 fm.startitem()
2907 fm.write('text', '%s', l.line[s:e], label='grep.match')
2906 fm.write('text', '%s', l.line[s:e], label='grep.match')
2908 fm.data(matched=True)
2907 fm.data(matched=True)
2909 p = e
2908 p = e
2910 if p < len(l.line):
2909 if p < len(l.line):
2911 fm.startitem()
2910 fm.startitem()
2912 fm.write('text', '%s', l.line[p:])
2911 fm.write('text', '%s', l.line[p:])
2913 fm.data(matched=False)
2912 fm.data(matched=False)
2914 fm.end()
2913 fm.end()
2915
2914
2916 skip = {}
2915 skip = {}
2917 revfiles = {}
2916 revfiles = {}
2918 match = scmutil.match(repo[None], pats, opts)
2917 match = scmutil.match(repo[None], pats, opts)
2919 found = False
2918 found = False
2920 follow = opts.get('follow')
2919 follow = opts.get('follow')
2921
2920
2922 def prep(ctx, fns):
2921 def prep(ctx, fns):
2923 rev = ctx.rev()
2922 rev = ctx.rev()
2924 pctx = ctx.p1()
2923 pctx = ctx.p1()
2925 parent = pctx.rev()
2924 parent = pctx.rev()
2926 matches.setdefault(rev, {})
2925 matches.setdefault(rev, {})
2927 matches.setdefault(parent, {})
2926 matches.setdefault(parent, {})
2928 files = revfiles.setdefault(rev, [])
2927 files = revfiles.setdefault(rev, [])
2929 for fn in fns:
2928 for fn in fns:
2930 flog = getfile(fn)
2929 flog = getfile(fn)
2931 try:
2930 try:
2932 fnode = ctx.filenode(fn)
2931 fnode = ctx.filenode(fn)
2933 except error.LookupError:
2932 except error.LookupError:
2934 continue
2933 continue
2935 try:
2934 try:
2936 copied = flog.renamed(fnode)
2935 copied = flog.renamed(fnode)
2937 except error.WdirUnsupported:
2936 except error.WdirUnsupported:
2938 copied = ctx[fn].renamed()
2937 copied = ctx[fn].renamed()
2939 copy = follow and copied and copied[0]
2938 copy = follow and copied and copied[0]
2940 if copy:
2939 if copy:
2941 copies.setdefault(rev, {})[fn] = copy
2940 copies.setdefault(rev, {})[fn] = copy
2942 if fn in skip:
2941 if fn in skip:
2943 if copy:
2942 if copy:
2944 skip[copy] = True
2943 skip[copy] = True
2945 continue
2944 continue
2946 files.append(fn)
2945 files.append(fn)
2947
2946
2948 if fn not in matches[rev]:
2947 if fn not in matches[rev]:
2949 try:
2948 try:
2950 content = flog.read(fnode)
2949 content = flog.read(fnode)
2951 except error.WdirUnsupported:
2950 except error.WdirUnsupported:
2952 content = ctx[fn].data()
2951 content = ctx[fn].data()
2953 grepbody(fn, rev, content)
2952 grepbody(fn, rev, content)
2954
2953
2955 pfn = copy or fn
2954 pfn = copy or fn
2956 if pfn not in matches[parent]:
2955 if pfn not in matches[parent]:
2957 try:
2956 try:
2958 fnode = pctx.filenode(pfn)
2957 fnode = pctx.filenode(pfn)
2959 grepbody(pfn, parent, flog.read(fnode))
2958 grepbody(pfn, parent, flog.read(fnode))
2960 except error.LookupError:
2959 except error.LookupError:
2961 pass
2960 pass
2962
2961
2963 ui.pager('grep')
2962 ui.pager('grep')
2964 fm = ui.formatter('grep', opts)
2963 fm = ui.formatter('grep', opts)
2965 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2964 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2966 rev = ctx.rev()
2965 rev = ctx.rev()
2967 parent = ctx.p1().rev()
2966 parent = ctx.p1().rev()
2968 for fn in sorted(revfiles.get(rev, [])):
2967 for fn in sorted(revfiles.get(rev, [])):
2969 states = matches[rev][fn]
2968 states = matches[rev][fn]
2970 copy = copies.get(rev, {}).get(fn)
2969 copy = copies.get(rev, {}).get(fn)
2971 if fn in skip:
2970 if fn in skip:
2972 if copy:
2971 if copy:
2973 skip[copy] = True
2972 skip[copy] = True
2974 continue
2973 continue
2975 pstates = matches.get(parent, {}).get(copy or fn, [])
2974 pstates = matches.get(parent, {}).get(copy or fn, [])
2976 if pstates or states:
2975 if pstates or states:
2977 r = display(fm, fn, ctx, pstates, states)
2976 r = display(fm, fn, ctx, pstates, states)
2978 found = found or r
2977 found = found or r
2979 if r and not diff and not all_files:
2978 if r and not diff and not all_files:
2980 skip[fn] = True
2979 skip[fn] = True
2981 if copy:
2980 if copy:
2982 skip[copy] = True
2981 skip[copy] = True
2983 del revfiles[rev]
2982 del revfiles[rev]
2984 # We will keep the matches dict for the duration of the window
2983 # We will keep the matches dict for the duration of the window
2985 # clear the matches dict once the window is over
2984 # clear the matches dict once the window is over
2986 if not revfiles:
2985 if not revfiles:
2987 matches.clear()
2986 matches.clear()
2988 fm.end()
2987 fm.end()
2989
2988
2990 return not found
2989 return not found
2991
2990
2992 @command('heads',
2991 @command('heads',
2993 [('r', 'rev', '',
2992 [('r', 'rev', '',
2994 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2993 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2995 ('t', 'topo', False, _('show topological heads only')),
2994 ('t', 'topo', False, _('show topological heads only')),
2996 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2995 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2997 ('c', 'closed', False, _('show normal and closed branch heads')),
2996 ('c', 'closed', False, _('show normal and closed branch heads')),
2998 ] + templateopts,
2997 ] + templateopts,
2999 _('[-ct] [-r STARTREV] [REV]...'),
2998 _('[-ct] [-r STARTREV] [REV]...'),
3000 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
2999 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3001 intents={INTENT_READONLY})
3000 intents={INTENT_READONLY})
3002 def heads(ui, repo, *branchrevs, **opts):
3001 def heads(ui, repo, *branchrevs, **opts):
3003 """show branch heads
3002 """show branch heads
3004
3003
3005 With no arguments, show all open branch heads in the repository.
3004 With no arguments, show all open branch heads in the repository.
3006 Branch heads are changesets that have no descendants on the
3005 Branch heads are changesets that have no descendants on the
3007 same branch. They are where development generally takes place and
3006 same branch. They are where development generally takes place and
3008 are the usual targets for update and merge operations.
3007 are the usual targets for update and merge operations.
3009
3008
3010 If one or more REVs are given, only open branch heads on the
3009 If one or more REVs are given, only open branch heads on the
3011 branches associated with the specified changesets are shown. This
3010 branches associated with the specified changesets are shown. This
3012 means that you can use :hg:`heads .` to see the heads on the
3011 means that you can use :hg:`heads .` to see the heads on the
3013 currently checked-out branch.
3012 currently checked-out branch.
3014
3013
3015 If -c/--closed is specified, also show branch heads marked closed
3014 If -c/--closed is specified, also show branch heads marked closed
3016 (see :hg:`commit --close-branch`).
3015 (see :hg:`commit --close-branch`).
3017
3016
3018 If STARTREV is specified, only those heads that are descendants of
3017 If STARTREV is specified, only those heads that are descendants of
3019 STARTREV will be displayed.
3018 STARTREV will be displayed.
3020
3019
3021 If -t/--topo is specified, named branch mechanics will be ignored and only
3020 If -t/--topo is specified, named branch mechanics will be ignored and only
3022 topological heads (changesets with no children) will be shown.
3021 topological heads (changesets with no children) will be shown.
3023
3022
3024 Returns 0 if matching heads are found, 1 if not.
3023 Returns 0 if matching heads are found, 1 if not.
3025 """
3024 """
3026
3025
3027 opts = pycompat.byteskwargs(opts)
3026 opts = pycompat.byteskwargs(opts)
3028 start = None
3027 start = None
3029 rev = opts.get('rev')
3028 rev = opts.get('rev')
3030 if rev:
3029 if rev:
3031 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3030 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3032 start = scmutil.revsingle(repo, rev, None).node()
3031 start = scmutil.revsingle(repo, rev, None).node()
3033
3032
3034 if opts.get('topo'):
3033 if opts.get('topo'):
3035 heads = [repo[h] for h in repo.heads(start)]
3034 heads = [repo[h] for h in repo.heads(start)]
3036 else:
3035 else:
3037 heads = []
3036 heads = []
3038 for branch in repo.branchmap():
3037 for branch in repo.branchmap():
3039 heads += repo.branchheads(branch, start, opts.get('closed'))
3038 heads += repo.branchheads(branch, start, opts.get('closed'))
3040 heads = [repo[h] for h in heads]
3039 heads = [repo[h] for h in heads]
3041
3040
3042 if branchrevs:
3041 if branchrevs:
3043 branches = set(repo[r].branch()
3042 branches = set(repo[r].branch()
3044 for r in scmutil.revrange(repo, branchrevs))
3043 for r in scmutil.revrange(repo, branchrevs))
3045 heads = [h for h in heads if h.branch() in branches]
3044 heads = [h for h in heads if h.branch() in branches]
3046
3045
3047 if opts.get('active') and branchrevs:
3046 if opts.get('active') and branchrevs:
3048 dagheads = repo.heads(start)
3047 dagheads = repo.heads(start)
3049 heads = [h for h in heads if h.node() in dagheads]
3048 heads = [h for h in heads if h.node() in dagheads]
3050
3049
3051 if branchrevs:
3050 if branchrevs:
3052 haveheads = set(h.branch() for h in heads)
3051 haveheads = set(h.branch() for h in heads)
3053 if branches - haveheads:
3052 if branches - haveheads:
3054 headless = ', '.join(b for b in branches - haveheads)
3053 headless = ', '.join(b for b in branches - haveheads)
3055 msg = _('no open branch heads found on branches %s')
3054 msg = _('no open branch heads found on branches %s')
3056 if opts.get('rev'):
3055 if opts.get('rev'):
3057 msg += _(' (started at %s)') % opts['rev']
3056 msg += _(' (started at %s)') % opts['rev']
3058 ui.warn((msg + '\n') % headless)
3057 ui.warn((msg + '\n') % headless)
3059
3058
3060 if not heads:
3059 if not heads:
3061 return 1
3060 return 1
3062
3061
3063 ui.pager('heads')
3062 ui.pager('heads')
3064 heads = sorted(heads, key=lambda x: -x.rev())
3063 heads = sorted(heads, key=lambda x: -x.rev())
3065 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3064 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3066 for ctx in heads:
3065 for ctx in heads:
3067 displayer.show(ctx)
3066 displayer.show(ctx)
3068 displayer.close()
3067 displayer.close()
3069
3068
3070 @command('help',
3069 @command('help',
3071 [('e', 'extension', None, _('show only help for extensions')),
3070 [('e', 'extension', None, _('show only help for extensions')),
3072 ('c', 'command', None, _('show only help for commands')),
3071 ('c', 'command', None, _('show only help for commands')),
3073 ('k', 'keyword', None, _('show topics matching keyword')),
3072 ('k', 'keyword', None, _('show topics matching keyword')),
3074 ('s', 'system', [],
3073 ('s', 'system', [],
3075 _('show help for specific platform(s)'), _('PLATFORM')),
3074 _('show help for specific platform(s)'), _('PLATFORM')),
3076 ],
3075 ],
3077 _('[-eck] [-s PLATFORM] [TOPIC]'),
3076 _('[-eck] [-s PLATFORM] [TOPIC]'),
3078 helpcategory=command.CATEGORY_HELP,
3077 helpcategory=command.CATEGORY_HELP,
3079 norepo=True,
3078 norepo=True,
3080 intents={INTENT_READONLY})
3079 intents={INTENT_READONLY})
3081 def help_(ui, name=None, **opts):
3080 def help_(ui, name=None, **opts):
3082 """show help for a given topic or a help overview
3081 """show help for a given topic or a help overview
3083
3082
3084 With no arguments, print a list of commands with short help messages.
3083 With no arguments, print a list of commands with short help messages.
3085
3084
3086 Given a topic, extension, or command name, print help for that
3085 Given a topic, extension, or command name, print help for that
3087 topic.
3086 topic.
3088
3087
3089 Returns 0 if successful.
3088 Returns 0 if successful.
3090 """
3089 """
3091
3090
3092 keep = opts.get(r'system') or []
3091 keep = opts.get(r'system') or []
3093 if len(keep) == 0:
3092 if len(keep) == 0:
3094 if pycompat.sysplatform.startswith('win'):
3093 if pycompat.sysplatform.startswith('win'):
3095 keep.append('windows')
3094 keep.append('windows')
3096 elif pycompat.sysplatform == 'OpenVMS':
3095 elif pycompat.sysplatform == 'OpenVMS':
3097 keep.append('vms')
3096 keep.append('vms')
3098 elif pycompat.sysplatform == 'plan9':
3097 elif pycompat.sysplatform == 'plan9':
3099 keep.append('plan9')
3098 keep.append('plan9')
3100 else:
3099 else:
3101 keep.append('unix')
3100 keep.append('unix')
3102 keep.append(pycompat.sysplatform.lower())
3101 keep.append(pycompat.sysplatform.lower())
3103 if ui.verbose:
3102 if ui.verbose:
3104 keep.append('verbose')
3103 keep.append('verbose')
3105
3104
3106 commands = sys.modules[__name__]
3105 commands = sys.modules[__name__]
3107 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3106 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3108 ui.pager('help')
3107 ui.pager('help')
3109 ui.write(formatted)
3108 ui.write(formatted)
3110
3109
3111
3110
3112 @command('identify|id',
3111 @command('identify|id',
3113 [('r', 'rev', '',
3112 [('r', 'rev', '',
3114 _('identify the specified revision'), _('REV')),
3113 _('identify the specified revision'), _('REV')),
3115 ('n', 'num', None, _('show local revision number')),
3114 ('n', 'num', None, _('show local revision number')),
3116 ('i', 'id', None, _('show global revision id')),
3115 ('i', 'id', None, _('show global revision id')),
3117 ('b', 'branch', None, _('show branch')),
3116 ('b', 'branch', None, _('show branch')),
3118 ('t', 'tags', None, _('show tags')),
3117 ('t', 'tags', None, _('show tags')),
3119 ('B', 'bookmarks', None, _('show bookmarks')),
3118 ('B', 'bookmarks', None, _('show bookmarks')),
3120 ] + remoteopts + formatteropts,
3119 ] + remoteopts + formatteropts,
3121 _('[-nibtB] [-r REV] [SOURCE]'),
3120 _('[-nibtB] [-r REV] [SOURCE]'),
3122 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3121 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3123 optionalrepo=True,
3122 optionalrepo=True,
3124 intents={INTENT_READONLY})
3123 intents={INTENT_READONLY})
3125 def identify(ui, repo, source=None, rev=None,
3124 def identify(ui, repo, source=None, rev=None,
3126 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3125 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3127 """identify the working directory or specified revision
3126 """identify the working directory or specified revision
3128
3127
3129 Print a summary identifying the repository state at REV using one or
3128 Print a summary identifying the repository state at REV using one or
3130 two parent hash identifiers, followed by a "+" if the working
3129 two parent hash identifiers, followed by a "+" if the working
3131 directory has uncommitted changes, the branch name (if not default),
3130 directory has uncommitted changes, the branch name (if not default),
3132 a list of tags, and a list of bookmarks.
3131 a list of tags, and a list of bookmarks.
3133
3132
3134 When REV is not given, print a summary of the current state of the
3133 When REV is not given, print a summary of the current state of the
3135 repository including the working directory. Specify -r. to get information
3134 repository including the working directory. Specify -r. to get information
3136 of the working directory parent without scanning uncommitted changes.
3135 of the working directory parent without scanning uncommitted changes.
3137
3136
3138 Specifying a path to a repository root or Mercurial bundle will
3137 Specifying a path to a repository root or Mercurial bundle will
3139 cause lookup to operate on that repository/bundle.
3138 cause lookup to operate on that repository/bundle.
3140
3139
3141 .. container:: verbose
3140 .. container:: verbose
3142
3141
3143 Template:
3142 Template:
3144
3143
3145 The following keywords are supported in addition to the common template
3144 The following keywords are supported in addition to the common template
3146 keywords and functions. See also :hg:`help templates`.
3145 keywords and functions. See also :hg:`help templates`.
3147
3146
3148 :dirty: String. Character ``+`` denoting if the working directory has
3147 :dirty: String. Character ``+`` denoting if the working directory has
3149 uncommitted changes.
3148 uncommitted changes.
3150 :id: String. One or two nodes, optionally followed by ``+``.
3149 :id: String. One or two nodes, optionally followed by ``+``.
3151 :parents: List of strings. Parent nodes of the changeset.
3150 :parents: List of strings. Parent nodes of the changeset.
3152
3151
3153 Examples:
3152 Examples:
3154
3153
3155 - generate a build identifier for the working directory::
3154 - generate a build identifier for the working directory::
3156
3155
3157 hg id --id > build-id.dat
3156 hg id --id > build-id.dat
3158
3157
3159 - find the revision corresponding to a tag::
3158 - find the revision corresponding to a tag::
3160
3159
3161 hg id -n -r 1.3
3160 hg id -n -r 1.3
3162
3161
3163 - check the most recent revision of a remote repository::
3162 - check the most recent revision of a remote repository::
3164
3163
3165 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3164 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3166
3165
3167 See :hg:`log` for generating more information about specific revisions,
3166 See :hg:`log` for generating more information about specific revisions,
3168 including full hash identifiers.
3167 including full hash identifiers.
3169
3168
3170 Returns 0 if successful.
3169 Returns 0 if successful.
3171 """
3170 """
3172
3171
3173 opts = pycompat.byteskwargs(opts)
3172 opts = pycompat.byteskwargs(opts)
3174 if not repo and not source:
3173 if not repo and not source:
3175 raise error.Abort(_("there is no Mercurial repository here "
3174 raise error.Abort(_("there is no Mercurial repository here "
3176 "(.hg not found)"))
3175 "(.hg not found)"))
3177
3176
3178 default = not (num or id or branch or tags or bookmarks)
3177 default = not (num or id or branch or tags or bookmarks)
3179 output = []
3178 output = []
3180 revs = []
3179 revs = []
3181
3180
3182 if source:
3181 if source:
3183 source, branches = hg.parseurl(ui.expandpath(source))
3182 source, branches = hg.parseurl(ui.expandpath(source))
3184 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3183 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3185 repo = peer.local()
3184 repo = peer.local()
3186 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3185 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3187
3186
3188 fm = ui.formatter('identify', opts)
3187 fm = ui.formatter('identify', opts)
3189 fm.startitem()
3188 fm.startitem()
3190
3189
3191 if not repo:
3190 if not repo:
3192 if num or branch or tags:
3191 if num or branch or tags:
3193 raise error.Abort(
3192 raise error.Abort(
3194 _("can't query remote revision number, branch, or tags"))
3193 _("can't query remote revision number, branch, or tags"))
3195 if not rev and revs:
3194 if not rev and revs:
3196 rev = revs[0]
3195 rev = revs[0]
3197 if not rev:
3196 if not rev:
3198 rev = "tip"
3197 rev = "tip"
3199
3198
3200 remoterev = peer.lookup(rev)
3199 remoterev = peer.lookup(rev)
3201 hexrev = fm.hexfunc(remoterev)
3200 hexrev = fm.hexfunc(remoterev)
3202 if default or id:
3201 if default or id:
3203 output = [hexrev]
3202 output = [hexrev]
3204 fm.data(id=hexrev)
3203 fm.data(id=hexrev)
3205
3204
3206 @util.cachefunc
3205 @util.cachefunc
3207 def getbms():
3206 def getbms():
3208 bms = []
3207 bms = []
3209
3208
3210 if 'bookmarks' in peer.listkeys('namespaces'):
3209 if 'bookmarks' in peer.listkeys('namespaces'):
3211 hexremoterev = hex(remoterev)
3210 hexremoterev = hex(remoterev)
3212 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3211 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3213 if bmr == hexremoterev]
3212 if bmr == hexremoterev]
3214
3213
3215 return sorted(bms)
3214 return sorted(bms)
3216
3215
3217 if fm.isplain():
3216 if fm.isplain():
3218 if bookmarks:
3217 if bookmarks:
3219 output.extend(getbms())
3218 output.extend(getbms())
3220 elif default and not ui.quiet:
3219 elif default and not ui.quiet:
3221 # multiple bookmarks for a single parent separated by '/'
3220 # multiple bookmarks for a single parent separated by '/'
3222 bm = '/'.join(getbms())
3221 bm = '/'.join(getbms())
3223 if bm:
3222 if bm:
3224 output.append(bm)
3223 output.append(bm)
3225 else:
3224 else:
3226 fm.data(node=hex(remoterev))
3225 fm.data(node=hex(remoterev))
3227 if bookmarks or 'bookmarks' in fm.datahint():
3226 if bookmarks or 'bookmarks' in fm.datahint():
3228 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3227 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3229 else:
3228 else:
3230 if rev:
3229 if rev:
3231 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3230 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3232 ctx = scmutil.revsingle(repo, rev, None)
3231 ctx = scmutil.revsingle(repo, rev, None)
3233
3232
3234 if ctx.rev() is None:
3233 if ctx.rev() is None:
3235 ctx = repo[None]
3234 ctx = repo[None]
3236 parents = ctx.parents()
3235 parents = ctx.parents()
3237 taglist = []
3236 taglist = []
3238 for p in parents:
3237 for p in parents:
3239 taglist.extend(p.tags())
3238 taglist.extend(p.tags())
3240
3239
3241 dirty = ""
3240 dirty = ""
3242 if ctx.dirty(missing=True, merge=False, branch=False):
3241 if ctx.dirty(missing=True, merge=False, branch=False):
3243 dirty = '+'
3242 dirty = '+'
3244 fm.data(dirty=dirty)
3243 fm.data(dirty=dirty)
3245
3244
3246 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3245 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3247 if default or id:
3246 if default or id:
3248 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3247 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3249 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3248 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3250
3249
3251 if num:
3250 if num:
3252 numoutput = ["%d" % p.rev() for p in parents]
3251 numoutput = ["%d" % p.rev() for p in parents]
3253 output.append("%s%s" % ('+'.join(numoutput), dirty))
3252 output.append("%s%s" % ('+'.join(numoutput), dirty))
3254
3253
3255 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3254 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3256 for p in parents], name='node'))
3255 for p in parents], name='node'))
3257 else:
3256 else:
3258 hexoutput = fm.hexfunc(ctx.node())
3257 hexoutput = fm.hexfunc(ctx.node())
3259 if default or id:
3258 if default or id:
3260 output = [hexoutput]
3259 output = [hexoutput]
3261 fm.data(id=hexoutput)
3260 fm.data(id=hexoutput)
3262
3261
3263 if num:
3262 if num:
3264 output.append(pycompat.bytestr(ctx.rev()))
3263 output.append(pycompat.bytestr(ctx.rev()))
3265 taglist = ctx.tags()
3264 taglist = ctx.tags()
3266
3265
3267 if default and not ui.quiet:
3266 if default and not ui.quiet:
3268 b = ctx.branch()
3267 b = ctx.branch()
3269 if b != 'default':
3268 if b != 'default':
3270 output.append("(%s)" % b)
3269 output.append("(%s)" % b)
3271
3270
3272 # multiple tags for a single parent separated by '/'
3271 # multiple tags for a single parent separated by '/'
3273 t = '/'.join(taglist)
3272 t = '/'.join(taglist)
3274 if t:
3273 if t:
3275 output.append(t)
3274 output.append(t)
3276
3275
3277 # multiple bookmarks for a single parent separated by '/'
3276 # multiple bookmarks for a single parent separated by '/'
3278 bm = '/'.join(ctx.bookmarks())
3277 bm = '/'.join(ctx.bookmarks())
3279 if bm:
3278 if bm:
3280 output.append(bm)
3279 output.append(bm)
3281 else:
3280 else:
3282 if branch:
3281 if branch:
3283 output.append(ctx.branch())
3282 output.append(ctx.branch())
3284
3283
3285 if tags:
3284 if tags:
3286 output.extend(taglist)
3285 output.extend(taglist)
3287
3286
3288 if bookmarks:
3287 if bookmarks:
3289 output.extend(ctx.bookmarks())
3288 output.extend(ctx.bookmarks())
3290
3289
3291 fm.data(node=ctx.hex())
3290 fm.data(node=ctx.hex())
3292 fm.data(branch=ctx.branch())
3291 fm.data(branch=ctx.branch())
3293 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3292 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3294 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3293 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3295 fm.context(ctx=ctx)
3294 fm.context(ctx=ctx)
3296
3295
3297 fm.plain("%s\n" % ' '.join(output))
3296 fm.plain("%s\n" % ' '.join(output))
3298 fm.end()
3297 fm.end()
3299
3298
3300 @command('import|patch',
3299 @command('import|patch',
3301 [('p', 'strip', 1,
3300 [('p', 'strip', 1,
3302 _('directory strip option for patch. This has the same '
3301 _('directory strip option for patch. This has the same '
3303 'meaning as the corresponding patch option'), _('NUM')),
3302 'meaning as the corresponding patch option'), _('NUM')),
3304 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3303 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3305 ('e', 'edit', False, _('invoke editor on commit messages')),
3304 ('e', 'edit', False, _('invoke editor on commit messages')),
3306 ('f', 'force', None,
3305 ('f', 'force', None,
3307 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3306 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3308 ('', 'no-commit', None,
3307 ('', 'no-commit', None,
3309 _("don't commit, just update the working directory")),
3308 _("don't commit, just update the working directory")),
3310 ('', 'bypass', None,
3309 ('', 'bypass', None,
3311 _("apply patch without touching the working directory")),
3310 _("apply patch without touching the working directory")),
3312 ('', 'partial', None,
3311 ('', 'partial', None,
3313 _('commit even if some hunks fail')),
3312 _('commit even if some hunks fail')),
3314 ('', 'exact', None,
3313 ('', 'exact', None,
3315 _('abort if patch would apply lossily')),
3314 _('abort if patch would apply lossily')),
3316 ('', 'prefix', '',
3315 ('', 'prefix', '',
3317 _('apply patch to subdirectory'), _('DIR')),
3316 _('apply patch to subdirectory'), _('DIR')),
3318 ('', 'import-branch', None,
3317 ('', 'import-branch', None,
3319 _('use any branch information in patch (implied by --exact)'))] +
3318 _('use any branch information in patch (implied by --exact)'))] +
3320 commitopts + commitopts2 + similarityopts,
3319 commitopts + commitopts2 + similarityopts,
3321 _('[OPTION]... PATCH...'),
3320 _('[OPTION]... PATCH...'),
3322 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3321 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3323 def import_(ui, repo, patch1=None, *patches, **opts):
3322 def import_(ui, repo, patch1=None, *patches, **opts):
3324 """import an ordered set of patches
3323 """import an ordered set of patches
3325
3324
3326 Import a list of patches and commit them individually (unless
3325 Import a list of patches and commit them individually (unless
3327 --no-commit is specified).
3326 --no-commit is specified).
3328
3327
3329 To read a patch from standard input (stdin), use "-" as the patch
3328 To read a patch from standard input (stdin), use "-" as the patch
3330 name. If a URL is specified, the patch will be downloaded from
3329 name. If a URL is specified, the patch will be downloaded from
3331 there.
3330 there.
3332
3331
3333 Import first applies changes to the working directory (unless
3332 Import first applies changes to the working directory (unless
3334 --bypass is specified), import will abort if there are outstanding
3333 --bypass is specified), import will abort if there are outstanding
3335 changes.
3334 changes.
3336
3335
3337 Use --bypass to apply and commit patches directly to the
3336 Use --bypass to apply and commit patches directly to the
3338 repository, without affecting the working directory. Without
3337 repository, without affecting the working directory. Without
3339 --exact, patches will be applied on top of the working directory
3338 --exact, patches will be applied on top of the working directory
3340 parent revision.
3339 parent revision.
3341
3340
3342 You can import a patch straight from a mail message. Even patches
3341 You can import a patch straight from a mail message. Even patches
3343 as attachments work (to use the body part, it must have type
3342 as attachments work (to use the body part, it must have type
3344 text/plain or text/x-patch). From and Subject headers of email
3343 text/plain or text/x-patch). From and Subject headers of email
3345 message are used as default committer and commit message. All
3344 message are used as default committer and commit message. All
3346 text/plain body parts before first diff are added to the commit
3345 text/plain body parts before first diff are added to the commit
3347 message.
3346 message.
3348
3347
3349 If the imported patch was generated by :hg:`export`, user and
3348 If the imported patch was generated by :hg:`export`, user and
3350 description from patch override values from message headers and
3349 description from patch override values from message headers and
3351 body. Values given on command line with -m/--message and -u/--user
3350 body. Values given on command line with -m/--message and -u/--user
3352 override these.
3351 override these.
3353
3352
3354 If --exact is specified, import will set the working directory to
3353 If --exact is specified, import will set the working directory to
3355 the parent of each patch before applying it, and will abort if the
3354 the parent of each patch before applying it, and will abort if the
3356 resulting changeset has a different ID than the one recorded in
3355 resulting changeset has a different ID than the one recorded in
3357 the patch. This will guard against various ways that portable
3356 the patch. This will guard against various ways that portable
3358 patch formats and mail systems might fail to transfer Mercurial
3357 patch formats and mail systems might fail to transfer Mercurial
3359 data or metadata. See :hg:`bundle` for lossless transmission.
3358 data or metadata. See :hg:`bundle` for lossless transmission.
3360
3359
3361 Use --partial to ensure a changeset will be created from the patch
3360 Use --partial to ensure a changeset will be created from the patch
3362 even if some hunks fail to apply. Hunks that fail to apply will be
3361 even if some hunks fail to apply. Hunks that fail to apply will be
3363 written to a <target-file>.rej file. Conflicts can then be resolved
3362 written to a <target-file>.rej file. Conflicts can then be resolved
3364 by hand before :hg:`commit --amend` is run to update the created
3363 by hand before :hg:`commit --amend` is run to update the created
3365 changeset. This flag exists to let people import patches that
3364 changeset. This flag exists to let people import patches that
3366 partially apply without losing the associated metadata (author,
3365 partially apply without losing the associated metadata (author,
3367 date, description, ...).
3366 date, description, ...).
3368
3367
3369 .. note::
3368 .. note::
3370
3369
3371 When no hunks apply cleanly, :hg:`import --partial` will create
3370 When no hunks apply cleanly, :hg:`import --partial` will create
3372 an empty changeset, importing only the patch metadata.
3371 an empty changeset, importing only the patch metadata.
3373
3372
3374 With -s/--similarity, hg will attempt to discover renames and
3373 With -s/--similarity, hg will attempt to discover renames and
3375 copies in the patch in the same way as :hg:`addremove`.
3374 copies in the patch in the same way as :hg:`addremove`.
3376
3375
3377 It is possible to use external patch programs to perform the patch
3376 It is possible to use external patch programs to perform the patch
3378 by setting the ``ui.patch`` configuration option. For the default
3377 by setting the ``ui.patch`` configuration option. For the default
3379 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3378 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3380 See :hg:`help config` for more information about configuration
3379 See :hg:`help config` for more information about configuration
3381 files and how to use these options.
3380 files and how to use these options.
3382
3381
3383 See :hg:`help dates` for a list of formats valid for -d/--date.
3382 See :hg:`help dates` for a list of formats valid for -d/--date.
3384
3383
3385 .. container:: verbose
3384 .. container:: verbose
3386
3385
3387 Examples:
3386 Examples:
3388
3387
3389 - import a traditional patch from a website and detect renames::
3388 - import a traditional patch from a website and detect renames::
3390
3389
3391 hg import -s 80 http://example.com/bugfix.patch
3390 hg import -s 80 http://example.com/bugfix.patch
3392
3391
3393 - import a changeset from an hgweb server::
3392 - import a changeset from an hgweb server::
3394
3393
3395 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3394 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3396
3395
3397 - import all the patches in an Unix-style mbox::
3396 - import all the patches in an Unix-style mbox::
3398
3397
3399 hg import incoming-patches.mbox
3398 hg import incoming-patches.mbox
3400
3399
3401 - import patches from stdin::
3400 - import patches from stdin::
3402
3401
3403 hg import -
3402 hg import -
3404
3403
3405 - attempt to exactly restore an exported changeset (not always
3404 - attempt to exactly restore an exported changeset (not always
3406 possible)::
3405 possible)::
3407
3406
3408 hg import --exact proposed-fix.patch
3407 hg import --exact proposed-fix.patch
3409
3408
3410 - use an external tool to apply a patch which is too fuzzy for
3409 - use an external tool to apply a patch which is too fuzzy for
3411 the default internal tool.
3410 the default internal tool.
3412
3411
3413 hg import --config ui.patch="patch --merge" fuzzy.patch
3412 hg import --config ui.patch="patch --merge" fuzzy.patch
3414
3413
3415 - change the default fuzzing from 2 to a less strict 7
3414 - change the default fuzzing from 2 to a less strict 7
3416
3415
3417 hg import --config ui.fuzz=7 fuzz.patch
3416 hg import --config ui.fuzz=7 fuzz.patch
3418
3417
3419 Returns 0 on success, 1 on partial success (see --partial).
3418 Returns 0 on success, 1 on partial success (see --partial).
3420 """
3419 """
3421
3420
3422 opts = pycompat.byteskwargs(opts)
3421 opts = pycompat.byteskwargs(opts)
3423 if not patch1:
3422 if not patch1:
3424 raise error.Abort(_('need at least one patch to import'))
3423 raise error.Abort(_('need at least one patch to import'))
3425
3424
3426 patches = (patch1,) + patches
3425 patches = (patch1,) + patches
3427
3426
3428 date = opts.get('date')
3427 date = opts.get('date')
3429 if date:
3428 if date:
3430 opts['date'] = dateutil.parsedate(date)
3429 opts['date'] = dateutil.parsedate(date)
3431
3430
3432 exact = opts.get('exact')
3431 exact = opts.get('exact')
3433 update = not opts.get('bypass')
3432 update = not opts.get('bypass')
3434 if not update and opts.get('no_commit'):
3433 if not update and opts.get('no_commit'):
3435 raise error.Abort(_('cannot use --no-commit with --bypass'))
3434 raise error.Abort(_('cannot use --no-commit with --bypass'))
3436 try:
3435 try:
3437 sim = float(opts.get('similarity') or 0)
3436 sim = float(opts.get('similarity') or 0)
3438 except ValueError:
3437 except ValueError:
3439 raise error.Abort(_('similarity must be a number'))
3438 raise error.Abort(_('similarity must be a number'))
3440 if sim < 0 or sim > 100:
3439 if sim < 0 or sim > 100:
3441 raise error.Abort(_('similarity must be between 0 and 100'))
3440 raise error.Abort(_('similarity must be between 0 and 100'))
3442 if sim and not update:
3441 if sim and not update:
3443 raise error.Abort(_('cannot use --similarity with --bypass'))
3442 raise error.Abort(_('cannot use --similarity with --bypass'))
3444 if exact:
3443 if exact:
3445 if opts.get('edit'):
3444 if opts.get('edit'):
3446 raise error.Abort(_('cannot use --exact with --edit'))
3445 raise error.Abort(_('cannot use --exact with --edit'))
3447 if opts.get('prefix'):
3446 if opts.get('prefix'):
3448 raise error.Abort(_('cannot use --exact with --prefix'))
3447 raise error.Abort(_('cannot use --exact with --prefix'))
3449
3448
3450 base = opts["base"]
3449 base = opts["base"]
3451 msgs = []
3450 msgs = []
3452 ret = 0
3451 ret = 0
3453
3452
3454 with repo.wlock():
3453 with repo.wlock():
3455 if update:
3454 if update:
3456 cmdutil.checkunfinished(repo)
3455 cmdutil.checkunfinished(repo)
3457 if (exact or not opts.get('force')):
3456 if (exact or not opts.get('force')):
3458 cmdutil.bailifchanged(repo)
3457 cmdutil.bailifchanged(repo)
3459
3458
3460 if not opts.get('no_commit'):
3459 if not opts.get('no_commit'):
3461 lock = repo.lock
3460 lock = repo.lock
3462 tr = lambda: repo.transaction('import')
3461 tr = lambda: repo.transaction('import')
3463 dsguard = util.nullcontextmanager
3462 dsguard = util.nullcontextmanager
3464 else:
3463 else:
3465 lock = util.nullcontextmanager
3464 lock = util.nullcontextmanager
3466 tr = util.nullcontextmanager
3465 tr = util.nullcontextmanager
3467 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3466 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3468 with lock(), tr(), dsguard():
3467 with lock(), tr(), dsguard():
3469 parents = repo[None].parents()
3468 parents = repo[None].parents()
3470 for patchurl in patches:
3469 for patchurl in patches:
3471 if patchurl == '-':
3470 if patchurl == '-':
3472 ui.status(_('applying patch from stdin\n'))
3471 ui.status(_('applying patch from stdin\n'))
3473 patchfile = ui.fin
3472 patchfile = ui.fin
3474 patchurl = 'stdin' # for error message
3473 patchurl = 'stdin' # for error message
3475 else:
3474 else:
3476 patchurl = os.path.join(base, patchurl)
3475 patchurl = os.path.join(base, patchurl)
3477 ui.status(_('applying %s\n') % patchurl)
3476 ui.status(_('applying %s\n') % patchurl)
3478 patchfile = hg.openpath(ui, patchurl)
3477 patchfile = hg.openpath(ui, patchurl)
3479
3478
3480 haspatch = False
3479 haspatch = False
3481 for hunk in patch.split(patchfile):
3480 for hunk in patch.split(patchfile):
3482 with patch.extract(ui, hunk) as patchdata:
3481 with patch.extract(ui, hunk) as patchdata:
3483 msg, node, rej = cmdutil.tryimportone(ui, repo,
3482 msg, node, rej = cmdutil.tryimportone(ui, repo,
3484 patchdata,
3483 patchdata,
3485 parents, opts,
3484 parents, opts,
3486 msgs, hg.clean)
3485 msgs, hg.clean)
3487 if msg:
3486 if msg:
3488 haspatch = True
3487 haspatch = True
3489 ui.note(msg + '\n')
3488 ui.note(msg + '\n')
3490 if update or exact:
3489 if update or exact:
3491 parents = repo[None].parents()
3490 parents = repo[None].parents()
3492 else:
3491 else:
3493 parents = [repo[node]]
3492 parents = [repo[node]]
3494 if rej:
3493 if rej:
3495 ui.write_err(_("patch applied partially\n"))
3494 ui.write_err(_("patch applied partially\n"))
3496 ui.write_err(_("(fix the .rej files and run "
3495 ui.write_err(_("(fix the .rej files and run "
3497 "`hg commit --amend`)\n"))
3496 "`hg commit --amend`)\n"))
3498 ret = 1
3497 ret = 1
3499 break
3498 break
3500
3499
3501 if not haspatch:
3500 if not haspatch:
3502 raise error.Abort(_('%s: no diffs found') % patchurl)
3501 raise error.Abort(_('%s: no diffs found') % patchurl)
3503
3502
3504 if msgs:
3503 if msgs:
3505 repo.savecommitmessage('\n* * *\n'.join(msgs))
3504 repo.savecommitmessage('\n* * *\n'.join(msgs))
3506 return ret
3505 return ret
3507
3506
3508 @command('incoming|in',
3507 @command('incoming|in',
3509 [('f', 'force', None,
3508 [('f', 'force', None,
3510 _('run even if remote repository is unrelated')),
3509 _('run even if remote repository is unrelated')),
3511 ('n', 'newest-first', None, _('show newest record first')),
3510 ('n', 'newest-first', None, _('show newest record first')),
3512 ('', 'bundle', '',
3511 ('', 'bundle', '',
3513 _('file to store the bundles into'), _('FILE')),
3512 _('file to store the bundles into'), _('FILE')),
3514 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3513 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3515 ('B', 'bookmarks', False, _("compare bookmarks")),
3514 ('B', 'bookmarks', False, _("compare bookmarks")),
3516 ('b', 'branch', [],
3515 ('b', 'branch', [],
3517 _('a specific branch you would like to pull'), _('BRANCH')),
3516 _('a specific branch you would like to pull'), _('BRANCH')),
3518 ] + logopts + remoteopts + subrepoopts,
3517 ] + logopts + remoteopts + subrepoopts,
3519 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3518 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3520 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3519 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3521 def incoming(ui, repo, source="default", **opts):
3520 def incoming(ui, repo, source="default", **opts):
3522 """show new changesets found in source
3521 """show new changesets found in source
3523
3522
3524 Show new changesets found in the specified path/URL or the default
3523 Show new changesets found in the specified path/URL or the default
3525 pull location. These are the changesets that would have been pulled
3524 pull location. These are the changesets that would have been pulled
3526 by :hg:`pull` at the time you issued this command.
3525 by :hg:`pull` at the time you issued this command.
3527
3526
3528 See pull for valid source format details.
3527 See pull for valid source format details.
3529
3528
3530 .. container:: verbose
3529 .. container:: verbose
3531
3530
3532 With -B/--bookmarks, the result of bookmark comparison between
3531 With -B/--bookmarks, the result of bookmark comparison between
3533 local and remote repositories is displayed. With -v/--verbose,
3532 local and remote repositories is displayed. With -v/--verbose,
3534 status is also displayed for each bookmark like below::
3533 status is also displayed for each bookmark like below::
3535
3534
3536 BM1 01234567890a added
3535 BM1 01234567890a added
3537 BM2 1234567890ab advanced
3536 BM2 1234567890ab advanced
3538 BM3 234567890abc diverged
3537 BM3 234567890abc diverged
3539 BM4 34567890abcd changed
3538 BM4 34567890abcd changed
3540
3539
3541 The action taken locally when pulling depends on the
3540 The action taken locally when pulling depends on the
3542 status of each bookmark:
3541 status of each bookmark:
3543
3542
3544 :``added``: pull will create it
3543 :``added``: pull will create it
3545 :``advanced``: pull will update it
3544 :``advanced``: pull will update it
3546 :``diverged``: pull will create a divergent bookmark
3545 :``diverged``: pull will create a divergent bookmark
3547 :``changed``: result depends on remote changesets
3546 :``changed``: result depends on remote changesets
3548
3547
3549 From the point of view of pulling behavior, bookmark
3548 From the point of view of pulling behavior, bookmark
3550 existing only in the remote repository are treated as ``added``,
3549 existing only in the remote repository are treated as ``added``,
3551 even if it is in fact locally deleted.
3550 even if it is in fact locally deleted.
3552
3551
3553 .. container:: verbose
3552 .. container:: verbose
3554
3553
3555 For remote repository, using --bundle avoids downloading the
3554 For remote repository, using --bundle avoids downloading the
3556 changesets twice if the incoming is followed by a pull.
3555 changesets twice if the incoming is followed by a pull.
3557
3556
3558 Examples:
3557 Examples:
3559
3558
3560 - show incoming changes with patches and full description::
3559 - show incoming changes with patches and full description::
3561
3560
3562 hg incoming -vp
3561 hg incoming -vp
3563
3562
3564 - show incoming changes excluding merges, store a bundle::
3563 - show incoming changes excluding merges, store a bundle::
3565
3564
3566 hg in -vpM --bundle incoming.hg
3565 hg in -vpM --bundle incoming.hg
3567 hg pull incoming.hg
3566 hg pull incoming.hg
3568
3567
3569 - briefly list changes inside a bundle::
3568 - briefly list changes inside a bundle::
3570
3569
3571 hg in changes.hg -T "{desc|firstline}\\n"
3570 hg in changes.hg -T "{desc|firstline}\\n"
3572
3571
3573 Returns 0 if there are incoming changes, 1 otherwise.
3572 Returns 0 if there are incoming changes, 1 otherwise.
3574 """
3573 """
3575 opts = pycompat.byteskwargs(opts)
3574 opts = pycompat.byteskwargs(opts)
3576 if opts.get('graph'):
3575 if opts.get('graph'):
3577 logcmdutil.checkunsupportedgraphflags([], opts)
3576 logcmdutil.checkunsupportedgraphflags([], opts)
3578 def display(other, chlist, displayer):
3577 def display(other, chlist, displayer):
3579 revdag = logcmdutil.graphrevs(other, chlist, opts)
3578 revdag = logcmdutil.graphrevs(other, chlist, opts)
3580 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3579 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3581 graphmod.asciiedges)
3580 graphmod.asciiedges)
3582
3581
3583 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3582 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3584 return 0
3583 return 0
3585
3584
3586 if opts.get('bundle') and opts.get('subrepos'):
3585 if opts.get('bundle') and opts.get('subrepos'):
3587 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3586 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3588
3587
3589 if opts.get('bookmarks'):
3588 if opts.get('bookmarks'):
3590 source, branches = hg.parseurl(ui.expandpath(source),
3589 source, branches = hg.parseurl(ui.expandpath(source),
3591 opts.get('branch'))
3590 opts.get('branch'))
3592 other = hg.peer(repo, opts, source)
3591 other = hg.peer(repo, opts, source)
3593 if 'bookmarks' not in other.listkeys('namespaces'):
3592 if 'bookmarks' not in other.listkeys('namespaces'):
3594 ui.warn(_("remote doesn't support bookmarks\n"))
3593 ui.warn(_("remote doesn't support bookmarks\n"))
3595 return 0
3594 return 0
3596 ui.pager('incoming')
3595 ui.pager('incoming')
3597 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3596 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3598 return bookmarks.incoming(ui, repo, other)
3597 return bookmarks.incoming(ui, repo, other)
3599
3598
3600 repo._subtoppath = ui.expandpath(source)
3599 repo._subtoppath = ui.expandpath(source)
3601 try:
3600 try:
3602 return hg.incoming(ui, repo, source, opts)
3601 return hg.incoming(ui, repo, source, opts)
3603 finally:
3602 finally:
3604 del repo._subtoppath
3603 del repo._subtoppath
3605
3604
3606
3605
3607 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3606 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3608 helpcategory=command.CATEGORY_REPO_CREATION,
3607 helpcategory=command.CATEGORY_REPO_CREATION,
3609 helpbasic=True, norepo=True)
3608 helpbasic=True, norepo=True)
3610 def init(ui, dest=".", **opts):
3609 def init(ui, dest=".", **opts):
3611 """create a new repository in the given directory
3610 """create a new repository in the given directory
3612
3611
3613 Initialize a new repository in the given directory. If the given
3612 Initialize a new repository in the given directory. If the given
3614 directory does not exist, it will be created.
3613 directory does not exist, it will be created.
3615
3614
3616 If no directory is given, the current directory is used.
3615 If no directory is given, the current directory is used.
3617
3616
3618 It is possible to specify an ``ssh://`` URL as the destination.
3617 It is possible to specify an ``ssh://`` URL as the destination.
3619 See :hg:`help urls` for more information.
3618 See :hg:`help urls` for more information.
3620
3619
3621 Returns 0 on success.
3620 Returns 0 on success.
3622 """
3621 """
3623 opts = pycompat.byteskwargs(opts)
3622 opts = pycompat.byteskwargs(opts)
3624 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3623 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3625
3624
3626 @command('locate',
3625 @command('locate',
3627 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3626 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3628 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3627 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3629 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3628 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3630 ] + walkopts,
3629 ] + walkopts,
3631 _('[OPTION]... [PATTERN]...'),
3630 _('[OPTION]... [PATTERN]...'),
3632 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3631 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3633 def locate(ui, repo, *pats, **opts):
3632 def locate(ui, repo, *pats, **opts):
3634 """locate files matching specific patterns (DEPRECATED)
3633 """locate files matching specific patterns (DEPRECATED)
3635
3634
3636 Print files under Mercurial control in the working directory whose
3635 Print files under Mercurial control in the working directory whose
3637 names match the given patterns.
3636 names match the given patterns.
3638
3637
3639 By default, this command searches all directories in the working
3638 By default, this command searches all directories in the working
3640 directory. To search just the current directory and its
3639 directory. To search just the current directory and its
3641 subdirectories, use "--include .".
3640 subdirectories, use "--include .".
3642
3641
3643 If no patterns are given to match, this command prints the names
3642 If no patterns are given to match, this command prints the names
3644 of all files under Mercurial control in the working directory.
3643 of all files under Mercurial control in the working directory.
3645
3644
3646 If you want to feed the output of this command into the "xargs"
3645 If you want to feed the output of this command into the "xargs"
3647 command, use the -0 option to both this command and "xargs". This
3646 command, use the -0 option to both this command and "xargs". This
3648 will avoid the problem of "xargs" treating single filenames that
3647 will avoid the problem of "xargs" treating single filenames that
3649 contain whitespace as multiple filenames.
3648 contain whitespace as multiple filenames.
3650
3649
3651 See :hg:`help files` for a more versatile command.
3650 See :hg:`help files` for a more versatile command.
3652
3651
3653 Returns 0 if a match is found, 1 otherwise.
3652 Returns 0 if a match is found, 1 otherwise.
3654 """
3653 """
3655 opts = pycompat.byteskwargs(opts)
3654 opts = pycompat.byteskwargs(opts)
3656 if opts.get('print0'):
3655 if opts.get('print0'):
3657 end = '\0'
3656 end = '\0'
3658 else:
3657 else:
3659 end = '\n'
3658 end = '\n'
3660 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3659 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3661
3660
3662 ret = 1
3661 ret = 1
3663 m = scmutil.match(ctx, pats, opts, default='relglob',
3662 m = scmutil.match(ctx, pats, opts, default='relglob',
3664 badfn=lambda x, y: False)
3663 badfn=lambda x, y: False)
3665
3664
3666 ui.pager('locate')
3665 ui.pager('locate')
3667 if ctx.rev() is None:
3666 if ctx.rev() is None:
3668 # When run on the working copy, "locate" includes removed files, so
3667 # When run on the working copy, "locate" includes removed files, so
3669 # we get the list of files from the dirstate.
3668 # we get the list of files from the dirstate.
3670 filesgen = sorted(repo.dirstate.matches(m))
3669 filesgen = sorted(repo.dirstate.matches(m))
3671 else:
3670 else:
3672 filesgen = ctx.matches(m)
3671 filesgen = ctx.matches(m)
3673 for abs in filesgen:
3672 for abs in filesgen:
3674 if opts.get('fullpath'):
3673 if opts.get('fullpath'):
3675 ui.write(repo.wjoin(abs), end)
3674 ui.write(repo.wjoin(abs), end)
3676 else:
3675 else:
3677 ui.write(((pats and m.rel(abs)) or abs), end)
3676 ui.write(((pats and m.rel(abs)) or abs), end)
3678 ret = 0
3677 ret = 0
3679
3678
3680 return ret
3679 return ret
3681
3680
3682 @command('log|history',
3681 @command('log|history',
3683 [('f', 'follow', None,
3682 [('f', 'follow', None,
3684 _('follow changeset history, or file history across copies and renames')),
3683 _('follow changeset history, or file history across copies and renames')),
3685 ('', 'follow-first', None,
3684 ('', 'follow-first', None,
3686 _('only follow the first parent of merge changesets (DEPRECATED)')),
3685 _('only follow the first parent of merge changesets (DEPRECATED)')),
3687 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3686 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3688 ('C', 'copies', None, _('show copied files')),
3687 ('C', 'copies', None, _('show copied files')),
3689 ('k', 'keyword', [],
3688 ('k', 'keyword', [],
3690 _('do case-insensitive search for a given text'), _('TEXT')),
3689 _('do case-insensitive search for a given text'), _('TEXT')),
3691 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3690 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3692 ('L', 'line-range', [],
3691 ('L', 'line-range', [],
3693 _('follow line range of specified file (EXPERIMENTAL)'),
3692 _('follow line range of specified file (EXPERIMENTAL)'),
3694 _('FILE,RANGE')),
3693 _('FILE,RANGE')),
3695 ('', 'removed', None, _('include revisions where files were removed')),
3694 ('', 'removed', None, _('include revisions where files were removed')),
3696 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3695 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3697 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3696 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3698 ('', 'only-branch', [],
3697 ('', 'only-branch', [],
3699 _('show only changesets within the given named branch (DEPRECATED)'),
3698 _('show only changesets within the given named branch (DEPRECATED)'),
3700 _('BRANCH')),
3699 _('BRANCH')),
3701 ('b', 'branch', [],
3700 ('b', 'branch', [],
3702 _('show changesets within the given named branch'), _('BRANCH')),
3701 _('show changesets within the given named branch'), _('BRANCH')),
3703 ('P', 'prune', [],
3702 ('P', 'prune', [],
3704 _('do not display revision or any of its ancestors'), _('REV')),
3703 _('do not display revision or any of its ancestors'), _('REV')),
3705 ] + logopts + walkopts,
3704 ] + logopts + walkopts,
3706 _('[OPTION]... [FILE]'),
3705 _('[OPTION]... [FILE]'),
3707 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3706 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3708 helpbasic=True, inferrepo=True,
3707 helpbasic=True, inferrepo=True,
3709 intents={INTENT_READONLY})
3708 intents={INTENT_READONLY})
3710 def log(ui, repo, *pats, **opts):
3709 def log(ui, repo, *pats, **opts):
3711 """show revision history of entire repository or files
3710 """show revision history of entire repository or files
3712
3711
3713 Print the revision history of the specified files or the entire
3712 Print the revision history of the specified files or the entire
3714 project.
3713 project.
3715
3714
3716 If no revision range is specified, the default is ``tip:0`` unless
3715 If no revision range is specified, the default is ``tip:0`` unless
3717 --follow is set, in which case the working directory parent is
3716 --follow is set, in which case the working directory parent is
3718 used as the starting revision.
3717 used as the starting revision.
3719
3718
3720 File history is shown without following rename or copy history of
3719 File history is shown without following rename or copy history of
3721 files. Use -f/--follow with a filename to follow history across
3720 files. Use -f/--follow with a filename to follow history across
3722 renames and copies. --follow without a filename will only show
3721 renames and copies. --follow without a filename will only show
3723 ancestors of the starting revision.
3722 ancestors of the starting revision.
3724
3723
3725 By default this command prints revision number and changeset id,
3724 By default this command prints revision number and changeset id,
3726 tags, non-trivial parents, user, date and time, and a summary for
3725 tags, non-trivial parents, user, date and time, and a summary for
3727 each commit. When the -v/--verbose switch is used, the list of
3726 each commit. When the -v/--verbose switch is used, the list of
3728 changed files and full commit message are shown.
3727 changed files and full commit message are shown.
3729
3728
3730 With --graph the revisions are shown as an ASCII art DAG with the most
3729 With --graph the revisions are shown as an ASCII art DAG with the most
3731 recent changeset at the top.
3730 recent changeset at the top.
3732 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3731 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3733 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3732 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3734 changeset from the lines below is a parent of the 'o' merge on the same
3733 changeset from the lines below is a parent of the 'o' merge on the same
3735 line.
3734 line.
3736 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3735 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3737 of a '|' indicates one or more revisions in a path are omitted.
3736 of a '|' indicates one or more revisions in a path are omitted.
3738
3737
3739 .. container:: verbose
3738 .. container:: verbose
3740
3739
3741 Use -L/--line-range FILE,M:N options to follow the history of lines
3740 Use -L/--line-range FILE,M:N options to follow the history of lines
3742 from M to N in FILE. With -p/--patch only diff hunks affecting
3741 from M to N in FILE. With -p/--patch only diff hunks affecting
3743 specified line range will be shown. This option requires --follow;
3742 specified line range will be shown. This option requires --follow;
3744 it can be specified multiple times. Currently, this option is not
3743 it can be specified multiple times. Currently, this option is not
3745 compatible with --graph. This option is experimental.
3744 compatible with --graph. This option is experimental.
3746
3745
3747 .. note::
3746 .. note::
3748
3747
3749 :hg:`log --patch` may generate unexpected diff output for merge
3748 :hg:`log --patch` may generate unexpected diff output for merge
3750 changesets, as it will only compare the merge changeset against
3749 changesets, as it will only compare the merge changeset against
3751 its first parent. Also, only files different from BOTH parents
3750 its first parent. Also, only files different from BOTH parents
3752 will appear in files:.
3751 will appear in files:.
3753
3752
3754 .. note::
3753 .. note::
3755
3754
3756 For performance reasons, :hg:`log FILE` may omit duplicate changes
3755 For performance reasons, :hg:`log FILE` may omit duplicate changes
3757 made on branches and will not show removals or mode changes. To
3756 made on branches and will not show removals or mode changes. To
3758 see all such changes, use the --removed switch.
3757 see all such changes, use the --removed switch.
3759
3758
3760 .. container:: verbose
3759 .. container:: verbose
3761
3760
3762 .. note::
3761 .. note::
3763
3762
3764 The history resulting from -L/--line-range options depends on diff
3763 The history resulting from -L/--line-range options depends on diff
3765 options; for instance if white-spaces are ignored, respective changes
3764 options; for instance if white-spaces are ignored, respective changes
3766 with only white-spaces in specified line range will not be listed.
3765 with only white-spaces in specified line range will not be listed.
3767
3766
3768 .. container:: verbose
3767 .. container:: verbose
3769
3768
3770 Some examples:
3769 Some examples:
3771
3770
3772 - changesets with full descriptions and file lists::
3771 - changesets with full descriptions and file lists::
3773
3772
3774 hg log -v
3773 hg log -v
3775
3774
3776 - changesets ancestral to the working directory::
3775 - changesets ancestral to the working directory::
3777
3776
3778 hg log -f
3777 hg log -f
3779
3778
3780 - last 10 commits on the current branch::
3779 - last 10 commits on the current branch::
3781
3780
3782 hg log -l 10 -b .
3781 hg log -l 10 -b .
3783
3782
3784 - changesets showing all modifications of a file, including removals::
3783 - changesets showing all modifications of a file, including removals::
3785
3784
3786 hg log --removed file.c
3785 hg log --removed file.c
3787
3786
3788 - all changesets that touch a directory, with diffs, excluding merges::
3787 - all changesets that touch a directory, with diffs, excluding merges::
3789
3788
3790 hg log -Mp lib/
3789 hg log -Mp lib/
3791
3790
3792 - all revision numbers that match a keyword::
3791 - all revision numbers that match a keyword::
3793
3792
3794 hg log -k bug --template "{rev}\\n"
3793 hg log -k bug --template "{rev}\\n"
3795
3794
3796 - the full hash identifier of the working directory parent::
3795 - the full hash identifier of the working directory parent::
3797
3796
3798 hg log -r . --template "{node}\\n"
3797 hg log -r . --template "{node}\\n"
3799
3798
3800 - list available log templates::
3799 - list available log templates::
3801
3800
3802 hg log -T list
3801 hg log -T list
3803
3802
3804 - check if a given changeset is included in a tagged release::
3803 - check if a given changeset is included in a tagged release::
3805
3804
3806 hg log -r "a21ccf and ancestor(1.9)"
3805 hg log -r "a21ccf and ancestor(1.9)"
3807
3806
3808 - find all changesets by some user in a date range::
3807 - find all changesets by some user in a date range::
3809
3808
3810 hg log -k alice -d "may 2008 to jul 2008"
3809 hg log -k alice -d "may 2008 to jul 2008"
3811
3810
3812 - summary of all changesets after the last tag::
3811 - summary of all changesets after the last tag::
3813
3812
3814 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3813 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3815
3814
3816 - changesets touching lines 13 to 23 for file.c::
3815 - changesets touching lines 13 to 23 for file.c::
3817
3816
3818 hg log -L file.c,13:23
3817 hg log -L file.c,13:23
3819
3818
3820 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3819 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3821 main.c with patch::
3820 main.c with patch::
3822
3821
3823 hg log -L file.c,13:23 -L main.c,2:6 -p
3822 hg log -L file.c,13:23 -L main.c,2:6 -p
3824
3823
3825 See :hg:`help dates` for a list of formats valid for -d/--date.
3824 See :hg:`help dates` for a list of formats valid for -d/--date.
3826
3825
3827 See :hg:`help revisions` for more about specifying and ordering
3826 See :hg:`help revisions` for more about specifying and ordering
3828 revisions.
3827 revisions.
3829
3828
3830 See :hg:`help templates` for more about pre-packaged styles and
3829 See :hg:`help templates` for more about pre-packaged styles and
3831 specifying custom templates. The default template used by the log
3830 specifying custom templates. The default template used by the log
3832 command can be customized via the ``ui.logtemplate`` configuration
3831 command can be customized via the ``ui.logtemplate`` configuration
3833 setting.
3832 setting.
3834
3833
3835 Returns 0 on success.
3834 Returns 0 on success.
3836
3835
3837 """
3836 """
3838 opts = pycompat.byteskwargs(opts)
3837 opts = pycompat.byteskwargs(opts)
3839 linerange = opts.get('line_range')
3838 linerange = opts.get('line_range')
3840
3839
3841 if linerange and not opts.get('follow'):
3840 if linerange and not opts.get('follow'):
3842 raise error.Abort(_('--line-range requires --follow'))
3841 raise error.Abort(_('--line-range requires --follow'))
3843
3842
3844 if linerange and pats:
3843 if linerange and pats:
3845 # TODO: take pats as patterns with no line-range filter
3844 # TODO: take pats as patterns with no line-range filter
3846 raise error.Abort(
3845 raise error.Abort(
3847 _('FILE arguments are not compatible with --line-range option')
3846 _('FILE arguments are not compatible with --line-range option')
3848 )
3847 )
3849
3848
3850 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3849 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3851 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3850 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3852 if linerange:
3851 if linerange:
3853 # TODO: should follow file history from logcmdutil._initialrevs(),
3852 # TODO: should follow file history from logcmdutil._initialrevs(),
3854 # then filter the result by logcmdutil._makerevset() and --limit
3853 # then filter the result by logcmdutil._makerevset() and --limit
3855 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3854 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3856
3855
3857 getrenamed = None
3856 getrenamed = None
3858 if opts.get('copies'):
3857 if opts.get('copies'):
3859 endrev = None
3858 endrev = None
3860 if revs:
3859 if revs:
3861 endrev = revs.max() + 1
3860 endrev = revs.max() + 1
3862 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3861 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3863
3862
3864 ui.pager('log')
3863 ui.pager('log')
3865 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3864 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3866 buffered=True)
3865 buffered=True)
3867 if opts.get('graph'):
3866 if opts.get('graph'):
3868 displayfn = logcmdutil.displaygraphrevs
3867 displayfn = logcmdutil.displaygraphrevs
3869 else:
3868 else:
3870 displayfn = logcmdutil.displayrevs
3869 displayfn = logcmdutil.displayrevs
3871 displayfn(ui, repo, revs, displayer, getrenamed)
3870 displayfn(ui, repo, revs, displayer, getrenamed)
3872
3871
3873 @command('manifest',
3872 @command('manifest',
3874 [('r', 'rev', '', _('revision to display'), _('REV')),
3873 [('r', 'rev', '', _('revision to display'), _('REV')),
3875 ('', 'all', False, _("list files from all revisions"))]
3874 ('', 'all', False, _("list files from all revisions"))]
3876 + formatteropts,
3875 + formatteropts,
3877 _('[-r REV]'),
3876 _('[-r REV]'),
3878 helpcategory=command.CATEGORY_MAINTENANCE,
3877 helpcategory=command.CATEGORY_MAINTENANCE,
3879 intents={INTENT_READONLY})
3878 intents={INTENT_READONLY})
3880 def manifest(ui, repo, node=None, rev=None, **opts):
3879 def manifest(ui, repo, node=None, rev=None, **opts):
3881 """output the current or given revision of the project manifest
3880 """output the current or given revision of the project manifest
3882
3881
3883 Print a list of version controlled files for the given revision.
3882 Print a list of version controlled files for the given revision.
3884 If no revision is given, the first parent of the working directory
3883 If no revision is given, the first parent of the working directory
3885 is used, or the null revision if no revision is checked out.
3884 is used, or the null revision if no revision is checked out.
3886
3885
3887 With -v, print file permissions, symlink and executable bits.
3886 With -v, print file permissions, symlink and executable bits.
3888 With --debug, print file revision hashes.
3887 With --debug, print file revision hashes.
3889
3888
3890 If option --all is specified, the list of all files from all revisions
3889 If option --all is specified, the list of all files from all revisions
3891 is printed. This includes deleted and renamed files.
3890 is printed. This includes deleted and renamed files.
3892
3891
3893 Returns 0 on success.
3892 Returns 0 on success.
3894 """
3893 """
3895 opts = pycompat.byteskwargs(opts)
3894 opts = pycompat.byteskwargs(opts)
3896 fm = ui.formatter('manifest', opts)
3895 fm = ui.formatter('manifest', opts)
3897
3896
3898 if opts.get('all'):
3897 if opts.get('all'):
3899 if rev or node:
3898 if rev or node:
3900 raise error.Abort(_("can't specify a revision with --all"))
3899 raise error.Abort(_("can't specify a revision with --all"))
3901
3900
3902 res = set()
3901 res = set()
3903 for rev in repo:
3902 for rev in repo:
3904 ctx = repo[rev]
3903 ctx = repo[rev]
3905 res |= set(ctx.files())
3904 res |= set(ctx.files())
3906
3905
3907 ui.pager('manifest')
3906 ui.pager('manifest')
3908 for f in sorted(res):
3907 for f in sorted(res):
3909 fm.startitem()
3908 fm.startitem()
3910 fm.write("path", '%s\n', f)
3909 fm.write("path", '%s\n', f)
3911 fm.end()
3910 fm.end()
3912 return
3911 return
3913
3912
3914 if rev and node:
3913 if rev and node:
3915 raise error.Abort(_("please specify just one revision"))
3914 raise error.Abort(_("please specify just one revision"))
3916
3915
3917 if not node:
3916 if not node:
3918 node = rev
3917 node = rev
3919
3918
3920 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3919 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3921 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3920 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3922 if node:
3921 if node:
3923 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3922 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3924 ctx = scmutil.revsingle(repo, node)
3923 ctx = scmutil.revsingle(repo, node)
3925 mf = ctx.manifest()
3924 mf = ctx.manifest()
3926 ui.pager('manifest')
3925 ui.pager('manifest')
3927 for f in ctx:
3926 for f in ctx:
3928 fm.startitem()
3927 fm.startitem()
3929 fm.context(ctx=ctx)
3928 fm.context(ctx=ctx)
3930 fl = ctx[f].flags()
3929 fl = ctx[f].flags()
3931 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3930 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3932 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3931 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3933 fm.write('path', '%s\n', f)
3932 fm.write('path', '%s\n', f)
3934 fm.end()
3933 fm.end()
3935
3934
3936 @command('merge',
3935 @command('merge',
3937 [('f', 'force', None,
3936 [('f', 'force', None,
3938 _('force a merge including outstanding changes (DEPRECATED)')),
3937 _('force a merge including outstanding changes (DEPRECATED)')),
3939 ('r', 'rev', '', _('revision to merge'), _('REV')),
3938 ('r', 'rev', '', _('revision to merge'), _('REV')),
3940 ('P', 'preview', None,
3939 ('P', 'preview', None,
3941 _('review revisions to merge (no merge is performed)')),
3940 _('review revisions to merge (no merge is performed)')),
3942 ('', 'abort', None, _('abort the ongoing merge')),
3941 ('', 'abort', None, _('abort the ongoing merge')),
3943 ] + mergetoolopts,
3942 ] + mergetoolopts,
3944 _('[-P] [[-r] REV]'),
3943 _('[-P] [[-r] REV]'),
3945 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3944 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3946 def merge(ui, repo, node=None, **opts):
3945 def merge(ui, repo, node=None, **opts):
3947 """merge another revision into working directory
3946 """merge another revision into working directory
3948
3947
3949 The current working directory is updated with all changes made in
3948 The current working directory is updated with all changes made in
3950 the requested revision since the last common predecessor revision.
3949 the requested revision since the last common predecessor revision.
3951
3950
3952 Files that changed between either parent are marked as changed for
3951 Files that changed between either parent are marked as changed for
3953 the next commit and a commit must be performed before any further
3952 the next commit and a commit must be performed before any further
3954 updates to the repository are allowed. The next commit will have
3953 updates to the repository are allowed. The next commit will have
3955 two parents.
3954 two parents.
3956
3955
3957 ``--tool`` can be used to specify the merge tool used for file
3956 ``--tool`` can be used to specify the merge tool used for file
3958 merges. It overrides the HGMERGE environment variable and your
3957 merges. It overrides the HGMERGE environment variable and your
3959 configuration files. See :hg:`help merge-tools` for options.
3958 configuration files. See :hg:`help merge-tools` for options.
3960
3959
3961 If no revision is specified, the working directory's parent is a
3960 If no revision is specified, the working directory's parent is a
3962 head revision, and the current branch contains exactly one other
3961 head revision, and the current branch contains exactly one other
3963 head, the other head is merged with by default. Otherwise, an
3962 head, the other head is merged with by default. Otherwise, an
3964 explicit revision with which to merge with must be provided.
3963 explicit revision with which to merge with must be provided.
3965
3964
3966 See :hg:`help resolve` for information on handling file conflicts.
3965 See :hg:`help resolve` for information on handling file conflicts.
3967
3966
3968 To undo an uncommitted merge, use :hg:`merge --abort` which
3967 To undo an uncommitted merge, use :hg:`merge --abort` which
3969 will check out a clean copy of the original merge parent, losing
3968 will check out a clean copy of the original merge parent, losing
3970 all changes.
3969 all changes.
3971
3970
3972 Returns 0 on success, 1 if there are unresolved files.
3971 Returns 0 on success, 1 if there are unresolved files.
3973 """
3972 """
3974
3973
3975 opts = pycompat.byteskwargs(opts)
3974 opts = pycompat.byteskwargs(opts)
3976 abort = opts.get('abort')
3975 abort = opts.get('abort')
3977 if abort and repo.dirstate.p2() == nullid:
3976 if abort and repo.dirstate.p2() == nullid:
3978 cmdutil.wrongtooltocontinue(repo, _('merge'))
3977 cmdutil.wrongtooltocontinue(repo, _('merge'))
3979 if abort:
3978 if abort:
3980 if node:
3979 if node:
3981 raise error.Abort(_("cannot specify a node with --abort"))
3980 raise error.Abort(_("cannot specify a node with --abort"))
3982 if opts.get('rev'):
3981 if opts.get('rev'):
3983 raise error.Abort(_("cannot specify both --rev and --abort"))
3982 raise error.Abort(_("cannot specify both --rev and --abort"))
3984 if opts.get('preview'):
3983 if opts.get('preview'):
3985 raise error.Abort(_("cannot specify --preview with --abort"))
3984 raise error.Abort(_("cannot specify --preview with --abort"))
3986 if opts.get('rev') and node:
3985 if opts.get('rev') and node:
3987 raise error.Abort(_("please specify just one revision"))
3986 raise error.Abort(_("please specify just one revision"))
3988 if not node:
3987 if not node:
3989 node = opts.get('rev')
3988 node = opts.get('rev')
3990
3989
3991 if node:
3990 if node:
3992 node = scmutil.revsingle(repo, node).node()
3991 node = scmutil.revsingle(repo, node).node()
3993
3992
3994 if not node and not abort:
3993 if not node and not abort:
3995 node = repo[destutil.destmerge(repo)].node()
3994 node = repo[destutil.destmerge(repo)].node()
3996
3995
3997 if opts.get('preview'):
3996 if opts.get('preview'):
3998 # find nodes that are ancestors of p2 but not of p1
3997 # find nodes that are ancestors of p2 but not of p1
3999 p1 = repo.lookup('.')
3998 p1 = repo.lookup('.')
4000 p2 = node
3999 p2 = node
4001 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4000 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4002
4001
4003 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4002 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4004 for node in nodes:
4003 for node in nodes:
4005 displayer.show(repo[node])
4004 displayer.show(repo[node])
4006 displayer.close()
4005 displayer.close()
4007 return 0
4006 return 0
4008
4007
4009 # ui.forcemerge is an internal variable, do not document
4008 # ui.forcemerge is an internal variable, do not document
4010 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4009 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4011 with ui.configoverride(overrides, 'merge'):
4010 with ui.configoverride(overrides, 'merge'):
4012 force = opts.get('force')
4011 force = opts.get('force')
4013 labels = ['working copy', 'merge rev']
4012 labels = ['working copy', 'merge rev']
4014 return hg.merge(repo, node, force=force, mergeforce=force,
4013 return hg.merge(repo, node, force=force, mergeforce=force,
4015 labels=labels, abort=abort)
4014 labels=labels, abort=abort)
4016
4015
4017 @command('outgoing|out',
4016 @command('outgoing|out',
4018 [('f', 'force', None, _('run even when the destination is unrelated')),
4017 [('f', 'force', None, _('run even when the destination is unrelated')),
4019 ('r', 'rev', [],
4018 ('r', 'rev', [],
4020 _('a changeset intended to be included in the destination'), _('REV')),
4019 _('a changeset intended to be included in the destination'), _('REV')),
4021 ('n', 'newest-first', None, _('show newest record first')),
4020 ('n', 'newest-first', None, _('show newest record first')),
4022 ('B', 'bookmarks', False, _('compare bookmarks')),
4021 ('B', 'bookmarks', False, _('compare bookmarks')),
4023 ('b', 'branch', [], _('a specific branch you would like to push'),
4022 ('b', 'branch', [], _('a specific branch you would like to push'),
4024 _('BRANCH')),
4023 _('BRANCH')),
4025 ] + logopts + remoteopts + subrepoopts,
4024 ] + logopts + remoteopts + subrepoopts,
4026 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4025 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4027 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4026 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4028 def outgoing(ui, repo, dest=None, **opts):
4027 def outgoing(ui, repo, dest=None, **opts):
4029 """show changesets not found in the destination
4028 """show changesets not found in the destination
4030
4029
4031 Show changesets not found in the specified destination repository
4030 Show changesets not found in the specified destination repository
4032 or the default push location. These are the changesets that would
4031 or the default push location. These are the changesets that would
4033 be pushed if a push was requested.
4032 be pushed if a push was requested.
4034
4033
4035 See pull for details of valid destination formats.
4034 See pull for details of valid destination formats.
4036
4035
4037 .. container:: verbose
4036 .. container:: verbose
4038
4037
4039 With -B/--bookmarks, the result of bookmark comparison between
4038 With -B/--bookmarks, the result of bookmark comparison between
4040 local and remote repositories is displayed. With -v/--verbose,
4039 local and remote repositories is displayed. With -v/--verbose,
4041 status is also displayed for each bookmark like below::
4040 status is also displayed for each bookmark like below::
4042
4041
4043 BM1 01234567890a added
4042 BM1 01234567890a added
4044 BM2 deleted
4043 BM2 deleted
4045 BM3 234567890abc advanced
4044 BM3 234567890abc advanced
4046 BM4 34567890abcd diverged
4045 BM4 34567890abcd diverged
4047 BM5 4567890abcde changed
4046 BM5 4567890abcde changed
4048
4047
4049 The action taken when pushing depends on the
4048 The action taken when pushing depends on the
4050 status of each bookmark:
4049 status of each bookmark:
4051
4050
4052 :``added``: push with ``-B`` will create it
4051 :``added``: push with ``-B`` will create it
4053 :``deleted``: push with ``-B`` will delete it
4052 :``deleted``: push with ``-B`` will delete it
4054 :``advanced``: push will update it
4053 :``advanced``: push will update it
4055 :``diverged``: push with ``-B`` will update it
4054 :``diverged``: push with ``-B`` will update it
4056 :``changed``: push with ``-B`` will update it
4055 :``changed``: push with ``-B`` will update it
4057
4056
4058 From the point of view of pushing behavior, bookmarks
4057 From the point of view of pushing behavior, bookmarks
4059 existing only in the remote repository are treated as
4058 existing only in the remote repository are treated as
4060 ``deleted``, even if it is in fact added remotely.
4059 ``deleted``, even if it is in fact added remotely.
4061
4060
4062 Returns 0 if there are outgoing changes, 1 otherwise.
4061 Returns 0 if there are outgoing changes, 1 otherwise.
4063 """
4062 """
4064 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4063 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4065 # style URLs, so don't overwrite dest.
4064 # style URLs, so don't overwrite dest.
4066 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4065 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4067 if not path:
4066 if not path:
4068 raise error.Abort(_('default repository not configured!'),
4067 raise error.Abort(_('default repository not configured!'),
4069 hint=_("see 'hg help config.paths'"))
4068 hint=_("see 'hg help config.paths'"))
4070
4069
4071 opts = pycompat.byteskwargs(opts)
4070 opts = pycompat.byteskwargs(opts)
4072 if opts.get('graph'):
4071 if opts.get('graph'):
4073 logcmdutil.checkunsupportedgraphflags([], opts)
4072 logcmdutil.checkunsupportedgraphflags([], opts)
4074 o, other = hg._outgoing(ui, repo, dest, opts)
4073 o, other = hg._outgoing(ui, repo, dest, opts)
4075 if not o:
4074 if not o:
4076 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4075 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4077 return
4076 return
4078
4077
4079 revdag = logcmdutil.graphrevs(repo, o, opts)
4078 revdag = logcmdutil.graphrevs(repo, o, opts)
4080 ui.pager('outgoing')
4079 ui.pager('outgoing')
4081 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4080 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4082 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4081 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4083 graphmod.asciiedges)
4082 graphmod.asciiedges)
4084 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4083 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4085 return 0
4084 return 0
4086
4085
4087 if opts.get('bookmarks'):
4086 if opts.get('bookmarks'):
4088 dest = path.pushloc or path.loc
4087 dest = path.pushloc or path.loc
4089 other = hg.peer(repo, opts, dest)
4088 other = hg.peer(repo, opts, dest)
4090 if 'bookmarks' not in other.listkeys('namespaces'):
4089 if 'bookmarks' not in other.listkeys('namespaces'):
4091 ui.warn(_("remote doesn't support bookmarks\n"))
4090 ui.warn(_("remote doesn't support bookmarks\n"))
4092 return 0
4091 return 0
4093 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4092 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4094 ui.pager('outgoing')
4093 ui.pager('outgoing')
4095 return bookmarks.outgoing(ui, repo, other)
4094 return bookmarks.outgoing(ui, repo, other)
4096
4095
4097 repo._subtoppath = path.pushloc or path.loc
4096 repo._subtoppath = path.pushloc or path.loc
4098 try:
4097 try:
4099 return hg.outgoing(ui, repo, dest, opts)
4098 return hg.outgoing(ui, repo, dest, opts)
4100 finally:
4099 finally:
4101 del repo._subtoppath
4100 del repo._subtoppath
4102
4101
4103 @command('parents',
4102 @command('parents',
4104 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4103 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4105 ] + templateopts,
4104 ] + templateopts,
4106 _('[-r REV] [FILE]'),
4105 _('[-r REV] [FILE]'),
4107 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4106 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4108 inferrepo=True)
4107 inferrepo=True)
4109 def parents(ui, repo, file_=None, **opts):
4108 def parents(ui, repo, file_=None, **opts):
4110 """show the parents of the working directory or revision (DEPRECATED)
4109 """show the parents of the working directory or revision (DEPRECATED)
4111
4110
4112 Print the working directory's parent revisions. If a revision is
4111 Print the working directory's parent revisions. If a revision is
4113 given via -r/--rev, the parent of that revision will be printed.
4112 given via -r/--rev, the parent of that revision will be printed.
4114 If a file argument is given, the revision in which the file was
4113 If a file argument is given, the revision in which the file was
4115 last changed (before the working directory revision or the
4114 last changed (before the working directory revision or the
4116 argument to --rev if given) is printed.
4115 argument to --rev if given) is printed.
4117
4116
4118 This command is equivalent to::
4117 This command is equivalent to::
4119
4118
4120 hg log -r "p1()+p2()" or
4119 hg log -r "p1()+p2()" or
4121 hg log -r "p1(REV)+p2(REV)" or
4120 hg log -r "p1(REV)+p2(REV)" or
4122 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4121 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4123 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4122 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4124
4123
4125 See :hg:`summary` and :hg:`help revsets` for related information.
4124 See :hg:`summary` and :hg:`help revsets` for related information.
4126
4125
4127 Returns 0 on success.
4126 Returns 0 on success.
4128 """
4127 """
4129
4128
4130 opts = pycompat.byteskwargs(opts)
4129 opts = pycompat.byteskwargs(opts)
4131 rev = opts.get('rev')
4130 rev = opts.get('rev')
4132 if rev:
4131 if rev:
4133 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4132 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4134 ctx = scmutil.revsingle(repo, rev, None)
4133 ctx = scmutil.revsingle(repo, rev, None)
4135
4134
4136 if file_:
4135 if file_:
4137 m = scmutil.match(ctx, (file_,), opts)
4136 m = scmutil.match(ctx, (file_,), opts)
4138 if m.anypats() or len(m.files()) != 1:
4137 if m.anypats() or len(m.files()) != 1:
4139 raise error.Abort(_('can only specify an explicit filename'))
4138 raise error.Abort(_('can only specify an explicit filename'))
4140 file_ = m.files()[0]
4139 file_ = m.files()[0]
4141 filenodes = []
4140 filenodes = []
4142 for cp in ctx.parents():
4141 for cp in ctx.parents():
4143 if not cp:
4142 if not cp:
4144 continue
4143 continue
4145 try:
4144 try:
4146 filenodes.append(cp.filenode(file_))
4145 filenodes.append(cp.filenode(file_))
4147 except error.LookupError:
4146 except error.LookupError:
4148 pass
4147 pass
4149 if not filenodes:
4148 if not filenodes:
4150 raise error.Abort(_("'%s' not found in manifest!") % file_)
4149 raise error.Abort(_("'%s' not found in manifest!") % file_)
4151 p = []
4150 p = []
4152 for fn in filenodes:
4151 for fn in filenodes:
4153 fctx = repo.filectx(file_, fileid=fn)
4152 fctx = repo.filectx(file_, fileid=fn)
4154 p.append(fctx.node())
4153 p.append(fctx.node())
4155 else:
4154 else:
4156 p = [cp.node() for cp in ctx.parents()]
4155 p = [cp.node() for cp in ctx.parents()]
4157
4156
4158 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4157 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4159 for n in p:
4158 for n in p:
4160 if n != nullid:
4159 if n != nullid:
4161 displayer.show(repo[n])
4160 displayer.show(repo[n])
4162 displayer.close()
4161 displayer.close()
4163
4162
4164 @command('paths', formatteropts, _('[NAME]'),
4163 @command('paths', formatteropts, _('[NAME]'),
4165 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4164 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4166 optionalrepo=True, intents={INTENT_READONLY})
4165 optionalrepo=True, intents={INTENT_READONLY})
4167 def paths(ui, repo, search=None, **opts):
4166 def paths(ui, repo, search=None, **opts):
4168 """show aliases for remote repositories
4167 """show aliases for remote repositories
4169
4168
4170 Show definition of symbolic path name NAME. If no name is given,
4169 Show definition of symbolic path name NAME. If no name is given,
4171 show definition of all available names.
4170 show definition of all available names.
4172
4171
4173 Option -q/--quiet suppresses all output when searching for NAME
4172 Option -q/--quiet suppresses all output when searching for NAME
4174 and shows only the path names when listing all definitions.
4173 and shows only the path names when listing all definitions.
4175
4174
4176 Path names are defined in the [paths] section of your
4175 Path names are defined in the [paths] section of your
4177 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4176 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4178 repository, ``.hg/hgrc`` is used, too.
4177 repository, ``.hg/hgrc`` is used, too.
4179
4178
4180 The path names ``default`` and ``default-push`` have a special
4179 The path names ``default`` and ``default-push`` have a special
4181 meaning. When performing a push or pull operation, they are used
4180 meaning. When performing a push or pull operation, they are used
4182 as fallbacks if no location is specified on the command-line.
4181 as fallbacks if no location is specified on the command-line.
4183 When ``default-push`` is set, it will be used for push and
4182 When ``default-push`` is set, it will be used for push and
4184 ``default`` will be used for pull; otherwise ``default`` is used
4183 ``default`` will be used for pull; otherwise ``default`` is used
4185 as the fallback for both. When cloning a repository, the clone
4184 as the fallback for both. When cloning a repository, the clone
4186 source is written as ``default`` in ``.hg/hgrc``.
4185 source is written as ``default`` in ``.hg/hgrc``.
4187
4186
4188 .. note::
4187 .. note::
4189
4188
4190 ``default`` and ``default-push`` apply to all inbound (e.g.
4189 ``default`` and ``default-push`` apply to all inbound (e.g.
4191 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4190 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4192 and :hg:`bundle`) operations.
4191 and :hg:`bundle`) operations.
4193
4192
4194 See :hg:`help urls` for more information.
4193 See :hg:`help urls` for more information.
4195
4194
4196 .. container:: verbose
4195 .. container:: verbose
4197
4196
4198 Template:
4197 Template:
4199
4198
4200 The following keywords are supported. See also :hg:`help templates`.
4199 The following keywords are supported. See also :hg:`help templates`.
4201
4200
4202 :name: String. Symbolic name of the path alias.
4201 :name: String. Symbolic name of the path alias.
4203 :pushurl: String. URL for push operations.
4202 :pushurl: String. URL for push operations.
4204 :url: String. URL or directory path for the other operations.
4203 :url: String. URL or directory path for the other operations.
4205
4204
4206 Returns 0 on success.
4205 Returns 0 on success.
4207 """
4206 """
4208
4207
4209 opts = pycompat.byteskwargs(opts)
4208 opts = pycompat.byteskwargs(opts)
4210 ui.pager('paths')
4209 ui.pager('paths')
4211 if search:
4210 if search:
4212 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4211 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4213 if name == search]
4212 if name == search]
4214 else:
4213 else:
4215 pathitems = sorted(ui.paths.iteritems())
4214 pathitems = sorted(ui.paths.iteritems())
4216
4215
4217 fm = ui.formatter('paths', opts)
4216 fm = ui.formatter('paths', opts)
4218 if fm.isplain():
4217 if fm.isplain():
4219 hidepassword = util.hidepassword
4218 hidepassword = util.hidepassword
4220 else:
4219 else:
4221 hidepassword = bytes
4220 hidepassword = bytes
4222 if ui.quiet:
4221 if ui.quiet:
4223 namefmt = '%s\n'
4222 namefmt = '%s\n'
4224 else:
4223 else:
4225 namefmt = '%s = '
4224 namefmt = '%s = '
4226 showsubopts = not search and not ui.quiet
4225 showsubopts = not search and not ui.quiet
4227
4226
4228 for name, path in pathitems:
4227 for name, path in pathitems:
4229 fm.startitem()
4228 fm.startitem()
4230 fm.condwrite(not search, 'name', namefmt, name)
4229 fm.condwrite(not search, 'name', namefmt, name)
4231 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4230 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4232 for subopt, value in sorted(path.suboptions.items()):
4231 for subopt, value in sorted(path.suboptions.items()):
4233 assert subopt not in ('name', 'url')
4232 assert subopt not in ('name', 'url')
4234 if showsubopts:
4233 if showsubopts:
4235 fm.plain('%s:%s = ' % (name, subopt))
4234 fm.plain('%s:%s = ' % (name, subopt))
4236 fm.condwrite(showsubopts, subopt, '%s\n', value)
4235 fm.condwrite(showsubopts, subopt, '%s\n', value)
4237
4236
4238 fm.end()
4237 fm.end()
4239
4238
4240 if search and not pathitems:
4239 if search and not pathitems:
4241 if not ui.quiet:
4240 if not ui.quiet:
4242 ui.warn(_("not found!\n"))
4241 ui.warn(_("not found!\n"))
4243 return 1
4242 return 1
4244 else:
4243 else:
4245 return 0
4244 return 0
4246
4245
4247 @command('phase',
4246 @command('phase',
4248 [('p', 'public', False, _('set changeset phase to public')),
4247 [('p', 'public', False, _('set changeset phase to public')),
4249 ('d', 'draft', False, _('set changeset phase to draft')),
4248 ('d', 'draft', False, _('set changeset phase to draft')),
4250 ('s', 'secret', False, _('set changeset phase to secret')),
4249 ('s', 'secret', False, _('set changeset phase to secret')),
4251 ('f', 'force', False, _('allow to move boundary backward')),
4250 ('f', 'force', False, _('allow to move boundary backward')),
4252 ('r', 'rev', [], _('target revision'), _('REV')),
4251 ('r', 'rev', [], _('target revision'), _('REV')),
4253 ],
4252 ],
4254 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4253 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4255 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4254 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4256 def phase(ui, repo, *revs, **opts):
4255 def phase(ui, repo, *revs, **opts):
4257 """set or show the current phase name
4256 """set or show the current phase name
4258
4257
4259 With no argument, show the phase name of the current revision(s).
4258 With no argument, show the phase name of the current revision(s).
4260
4259
4261 With one of -p/--public, -d/--draft or -s/--secret, change the
4260 With one of -p/--public, -d/--draft or -s/--secret, change the
4262 phase value of the specified revisions.
4261 phase value of the specified revisions.
4263
4262
4264 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4263 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4265 lower phase to a higher phase. Phases are ordered as follows::
4264 lower phase to a higher phase. Phases are ordered as follows::
4266
4265
4267 public < draft < secret
4266 public < draft < secret
4268
4267
4269 Returns 0 on success, 1 if some phases could not be changed.
4268 Returns 0 on success, 1 if some phases could not be changed.
4270
4269
4271 (For more information about the phases concept, see :hg:`help phases`.)
4270 (For more information about the phases concept, see :hg:`help phases`.)
4272 """
4271 """
4273 opts = pycompat.byteskwargs(opts)
4272 opts = pycompat.byteskwargs(opts)
4274 # search for a unique phase argument
4273 # search for a unique phase argument
4275 targetphase = None
4274 targetphase = None
4276 for idx, name in enumerate(phases.cmdphasenames):
4275 for idx, name in enumerate(phases.cmdphasenames):
4277 if opts[name]:
4276 if opts[name]:
4278 if targetphase is not None:
4277 if targetphase is not None:
4279 raise error.Abort(_('only one phase can be specified'))
4278 raise error.Abort(_('only one phase can be specified'))
4280 targetphase = idx
4279 targetphase = idx
4281
4280
4282 # look for specified revision
4281 # look for specified revision
4283 revs = list(revs)
4282 revs = list(revs)
4284 revs.extend(opts['rev'])
4283 revs.extend(opts['rev'])
4285 if not revs:
4284 if not revs:
4286 # display both parents as the second parent phase can influence
4285 # display both parents as the second parent phase can influence
4287 # the phase of a merge commit
4286 # the phase of a merge commit
4288 revs = [c.rev() for c in repo[None].parents()]
4287 revs = [c.rev() for c in repo[None].parents()]
4289
4288
4290 revs = scmutil.revrange(repo, revs)
4289 revs = scmutil.revrange(repo, revs)
4291
4290
4292 ret = 0
4291 ret = 0
4293 if targetphase is None:
4292 if targetphase is None:
4294 # display
4293 # display
4295 for r in revs:
4294 for r in revs:
4296 ctx = repo[r]
4295 ctx = repo[r]
4297 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4296 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4298 else:
4297 else:
4299 with repo.lock(), repo.transaction("phase") as tr:
4298 with repo.lock(), repo.transaction("phase") as tr:
4300 # set phase
4299 # set phase
4301 if not revs:
4300 if not revs:
4302 raise error.Abort(_('empty revision set'))
4301 raise error.Abort(_('empty revision set'))
4303 nodes = [repo[r].node() for r in revs]
4302 nodes = [repo[r].node() for r in revs]
4304 # moving revision from public to draft may hide them
4303 # moving revision from public to draft may hide them
4305 # We have to check result on an unfiltered repository
4304 # We have to check result on an unfiltered repository
4306 unfi = repo.unfiltered()
4305 unfi = repo.unfiltered()
4307 getphase = unfi._phasecache.phase
4306 getphase = unfi._phasecache.phase
4308 olddata = [getphase(unfi, r) for r in unfi]
4307 olddata = [getphase(unfi, r) for r in unfi]
4309 phases.advanceboundary(repo, tr, targetphase, nodes)
4308 phases.advanceboundary(repo, tr, targetphase, nodes)
4310 if opts['force']:
4309 if opts['force']:
4311 phases.retractboundary(repo, tr, targetphase, nodes)
4310 phases.retractboundary(repo, tr, targetphase, nodes)
4312 getphase = unfi._phasecache.phase
4311 getphase = unfi._phasecache.phase
4313 newdata = [getphase(unfi, r) for r in unfi]
4312 newdata = [getphase(unfi, r) for r in unfi]
4314 changes = sum(newdata[r] != olddata[r] for r in unfi)
4313 changes = sum(newdata[r] != olddata[r] for r in unfi)
4315 cl = unfi.changelog
4314 cl = unfi.changelog
4316 rejected = [n for n in nodes
4315 rejected = [n for n in nodes
4317 if newdata[cl.rev(n)] < targetphase]
4316 if newdata[cl.rev(n)] < targetphase]
4318 if rejected:
4317 if rejected:
4319 ui.warn(_('cannot move %i changesets to a higher '
4318 ui.warn(_('cannot move %i changesets to a higher '
4320 'phase, use --force\n') % len(rejected))
4319 'phase, use --force\n') % len(rejected))
4321 ret = 1
4320 ret = 1
4322 if changes:
4321 if changes:
4323 msg = _('phase changed for %i changesets\n') % changes
4322 msg = _('phase changed for %i changesets\n') % changes
4324 if ret:
4323 if ret:
4325 ui.status(msg)
4324 ui.status(msg)
4326 else:
4325 else:
4327 ui.note(msg)
4326 ui.note(msg)
4328 else:
4327 else:
4329 ui.warn(_('no phases changed\n'))
4328 ui.warn(_('no phases changed\n'))
4330 return ret
4329 return ret
4331
4330
4332 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4331 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4333 """Run after a changegroup has been added via pull/unbundle
4332 """Run after a changegroup has been added via pull/unbundle
4334
4333
4335 This takes arguments below:
4334 This takes arguments below:
4336
4335
4337 :modheads: change of heads by pull/unbundle
4336 :modheads: change of heads by pull/unbundle
4338 :optupdate: updating working directory is needed or not
4337 :optupdate: updating working directory is needed or not
4339 :checkout: update destination revision (or None to default destination)
4338 :checkout: update destination revision (or None to default destination)
4340 :brev: a name, which might be a bookmark to be activated after updating
4339 :brev: a name, which might be a bookmark to be activated after updating
4341 """
4340 """
4342 if modheads == 0:
4341 if modheads == 0:
4343 return
4342 return
4344 if optupdate:
4343 if optupdate:
4345 try:
4344 try:
4346 return hg.updatetotally(ui, repo, checkout, brev)
4345 return hg.updatetotally(ui, repo, checkout, brev)
4347 except error.UpdateAbort as inst:
4346 except error.UpdateAbort as inst:
4348 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4347 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4349 hint = inst.hint
4348 hint = inst.hint
4350 raise error.UpdateAbort(msg, hint=hint)
4349 raise error.UpdateAbort(msg, hint=hint)
4351 if modheads > 1:
4350 if modheads > 1:
4352 currentbranchheads = len(repo.branchheads())
4351 currentbranchheads = len(repo.branchheads())
4353 if currentbranchheads == modheads:
4352 if currentbranchheads == modheads:
4354 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4353 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4355 elif currentbranchheads > 1:
4354 elif currentbranchheads > 1:
4356 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4355 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4357 "merge)\n"))
4356 "merge)\n"))
4358 else:
4357 else:
4359 ui.status(_("(run 'hg heads' to see heads)\n"))
4358 ui.status(_("(run 'hg heads' to see heads)\n"))
4360 elif not ui.configbool('commands', 'update.requiredest'):
4359 elif not ui.configbool('commands', 'update.requiredest'):
4361 ui.status(_("(run 'hg update' to get a working copy)\n"))
4360 ui.status(_("(run 'hg update' to get a working copy)\n"))
4362
4361
4363 @command('pull',
4362 @command('pull',
4364 [('u', 'update', None,
4363 [('u', 'update', None,
4365 _('update to new branch head if new descendants were pulled')),
4364 _('update to new branch head if new descendants were pulled')),
4366 ('f', 'force', None, _('run even when remote repository is unrelated')),
4365 ('f', 'force', None, _('run even when remote repository is unrelated')),
4367 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4366 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4368 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4367 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4369 ('b', 'branch', [], _('a specific branch you would like to pull'),
4368 ('b', 'branch', [], _('a specific branch you would like to pull'),
4370 _('BRANCH')),
4369 _('BRANCH')),
4371 ] + remoteopts,
4370 ] + remoteopts,
4372 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4371 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4373 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4372 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4374 helpbasic=True)
4373 helpbasic=True)
4375 def pull(ui, repo, source="default", **opts):
4374 def pull(ui, repo, source="default", **opts):
4376 """pull changes from the specified source
4375 """pull changes from the specified source
4377
4376
4378 Pull changes from a remote repository to a local one.
4377 Pull changes from a remote repository to a local one.
4379
4378
4380 This finds all changes from the repository at the specified path
4379 This finds all changes from the repository at the specified path
4381 or URL and adds them to a local repository (the current one unless
4380 or URL and adds them to a local repository (the current one unless
4382 -R is specified). By default, this does not update the copy of the
4381 -R is specified). By default, this does not update the copy of the
4383 project in the working directory.
4382 project in the working directory.
4384
4383
4385 When cloning from servers that support it, Mercurial may fetch
4384 When cloning from servers that support it, Mercurial may fetch
4386 pre-generated data. When this is done, hooks operating on incoming
4385 pre-generated data. When this is done, hooks operating on incoming
4387 changesets and changegroups may fire more than once, once for each
4386 changesets and changegroups may fire more than once, once for each
4388 pre-generated bundle and as well as for any additional remaining
4387 pre-generated bundle and as well as for any additional remaining
4389 data. See :hg:`help -e clonebundles` for more.
4388 data. See :hg:`help -e clonebundles` for more.
4390
4389
4391 Use :hg:`incoming` if you want to see what would have been added
4390 Use :hg:`incoming` if you want to see what would have been added
4392 by a pull at the time you issued this command. If you then decide
4391 by a pull at the time you issued this command. If you then decide
4393 to add those changes to the repository, you should use :hg:`pull
4392 to add those changes to the repository, you should use :hg:`pull
4394 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4393 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4395
4394
4396 If SOURCE is omitted, the 'default' path will be used.
4395 If SOURCE is omitted, the 'default' path will be used.
4397 See :hg:`help urls` for more information.
4396 See :hg:`help urls` for more information.
4398
4397
4399 Specifying bookmark as ``.`` is equivalent to specifying the active
4398 Specifying bookmark as ``.`` is equivalent to specifying the active
4400 bookmark's name.
4399 bookmark's name.
4401
4400
4402 Returns 0 on success, 1 if an update had unresolved files.
4401 Returns 0 on success, 1 if an update had unresolved files.
4403 """
4402 """
4404
4403
4405 opts = pycompat.byteskwargs(opts)
4404 opts = pycompat.byteskwargs(opts)
4406 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4405 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4407 msg = _('update destination required by configuration')
4406 msg = _('update destination required by configuration')
4408 hint = _('use hg pull followed by hg update DEST')
4407 hint = _('use hg pull followed by hg update DEST')
4409 raise error.Abort(msg, hint=hint)
4408 raise error.Abort(msg, hint=hint)
4410
4409
4411 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4410 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4412 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4411 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4413 other = hg.peer(repo, opts, source)
4412 other = hg.peer(repo, opts, source)
4414 try:
4413 try:
4415 revs, checkout = hg.addbranchrevs(repo, other, branches,
4414 revs, checkout = hg.addbranchrevs(repo, other, branches,
4416 opts.get('rev'))
4415 opts.get('rev'))
4417
4416
4418
4417
4419 pullopargs = {}
4418 pullopargs = {}
4420 if opts.get('bookmark'):
4419 if opts.get('bookmark'):
4421 if not revs:
4420 if not revs:
4422 revs = []
4421 revs = []
4423 # The list of bookmark used here is not the one used to actually
4422 # The list of bookmark used here is not the one used to actually
4424 # update the bookmark name. This can result in the revision pulled
4423 # update the bookmark name. This can result in the revision pulled
4425 # not ending up with the name of the bookmark because of a race
4424 # not ending up with the name of the bookmark because of a race
4426 # condition on the server. (See issue 4689 for details)
4425 # condition on the server. (See issue 4689 for details)
4427 remotebookmarks = other.listkeys('bookmarks')
4426 remotebookmarks = other.listkeys('bookmarks')
4428 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4427 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4429 pullopargs['remotebookmarks'] = remotebookmarks
4428 pullopargs['remotebookmarks'] = remotebookmarks
4430 for b in opts['bookmark']:
4429 for b in opts['bookmark']:
4431 b = repo._bookmarks.expandname(b)
4430 b = repo._bookmarks.expandname(b)
4432 if b not in remotebookmarks:
4431 if b not in remotebookmarks:
4433 raise error.Abort(_('remote bookmark %s not found!') % b)
4432 raise error.Abort(_('remote bookmark %s not found!') % b)
4434 revs.append(hex(remotebookmarks[b]))
4433 revs.append(hex(remotebookmarks[b]))
4435
4434
4436 if revs:
4435 if revs:
4437 try:
4436 try:
4438 # When 'rev' is a bookmark name, we cannot guarantee that it
4437 # When 'rev' is a bookmark name, we cannot guarantee that it
4439 # will be updated with that name because of a race condition
4438 # will be updated with that name because of a race condition
4440 # server side. (See issue 4689 for details)
4439 # server side. (See issue 4689 for details)
4441 oldrevs = revs
4440 oldrevs = revs
4442 revs = [] # actually, nodes
4441 revs = [] # actually, nodes
4443 for r in oldrevs:
4442 for r in oldrevs:
4444 with other.commandexecutor() as e:
4443 with other.commandexecutor() as e:
4445 node = e.callcommand('lookup', {'key': r}).result()
4444 node = e.callcommand('lookup', {'key': r}).result()
4446
4445
4447 revs.append(node)
4446 revs.append(node)
4448 if r == checkout:
4447 if r == checkout:
4449 checkout = node
4448 checkout = node
4450 except error.CapabilityError:
4449 except error.CapabilityError:
4451 err = _("other repository doesn't support revision lookup, "
4450 err = _("other repository doesn't support revision lookup, "
4452 "so a rev cannot be specified.")
4451 "so a rev cannot be specified.")
4453 raise error.Abort(err)
4452 raise error.Abort(err)
4454
4453
4455 wlock = util.nullcontextmanager()
4454 wlock = util.nullcontextmanager()
4456 if opts.get('update'):
4455 if opts.get('update'):
4457 wlock = repo.wlock()
4456 wlock = repo.wlock()
4458 with wlock:
4457 with wlock:
4459 pullopargs.update(opts.get('opargs', {}))
4458 pullopargs.update(opts.get('opargs', {}))
4460 modheads = exchange.pull(repo, other, heads=revs,
4459 modheads = exchange.pull(repo, other, heads=revs,
4461 force=opts.get('force'),
4460 force=opts.get('force'),
4462 bookmarks=opts.get('bookmark', ()),
4461 bookmarks=opts.get('bookmark', ()),
4463 opargs=pullopargs).cgresult
4462 opargs=pullopargs).cgresult
4464
4463
4465 # brev is a name, which might be a bookmark to be activated at
4464 # brev is a name, which might be a bookmark to be activated at
4466 # the end of the update. In other words, it is an explicit
4465 # the end of the update. In other words, it is an explicit
4467 # destination of the update
4466 # destination of the update
4468 brev = None
4467 brev = None
4469
4468
4470 if checkout:
4469 if checkout:
4471 checkout = repo.changelog.rev(checkout)
4470 checkout = repo.changelog.rev(checkout)
4472
4471
4473 # order below depends on implementation of
4472 # order below depends on implementation of
4474 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4473 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4475 # because 'checkout' is determined without it.
4474 # because 'checkout' is determined without it.
4476 if opts.get('rev'):
4475 if opts.get('rev'):
4477 brev = opts['rev'][0]
4476 brev = opts['rev'][0]
4478 elif opts.get('branch'):
4477 elif opts.get('branch'):
4479 brev = opts['branch'][0]
4478 brev = opts['branch'][0]
4480 else:
4479 else:
4481 brev = branches[0]
4480 brev = branches[0]
4482 repo._subtoppath = source
4481 repo._subtoppath = source
4483 try:
4482 try:
4484 ret = postincoming(ui, repo, modheads, opts.get('update'),
4483 ret = postincoming(ui, repo, modheads, opts.get('update'),
4485 checkout, brev)
4484 checkout, brev)
4486
4485
4487 finally:
4486 finally:
4488 del repo._subtoppath
4487 del repo._subtoppath
4489
4488
4490 finally:
4489 finally:
4491 other.close()
4490 other.close()
4492 return ret
4491 return ret
4493
4492
4494 @command('push',
4493 @command('push',
4495 [('f', 'force', None, _('force push')),
4494 [('f', 'force', None, _('force push')),
4496 ('r', 'rev', [],
4495 ('r', 'rev', [],
4497 _('a changeset intended to be included in the destination'),
4496 _('a changeset intended to be included in the destination'),
4498 _('REV')),
4497 _('REV')),
4499 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4498 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4500 ('b', 'branch', [],
4499 ('b', 'branch', [],
4501 _('a specific branch you would like to push'), _('BRANCH')),
4500 _('a specific branch you would like to push'), _('BRANCH')),
4502 ('', 'new-branch', False, _('allow pushing a new branch')),
4501 ('', 'new-branch', False, _('allow pushing a new branch')),
4503 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4502 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4504 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4503 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4505 ] + remoteopts,
4504 ] + remoteopts,
4506 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4505 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4507 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4506 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4508 helpbasic=True)
4507 helpbasic=True)
4509 def push(ui, repo, dest=None, **opts):
4508 def push(ui, repo, dest=None, **opts):
4510 """push changes to the specified destination
4509 """push changes to the specified destination
4511
4510
4512 Push changesets from the local repository to the specified
4511 Push changesets from the local repository to the specified
4513 destination.
4512 destination.
4514
4513
4515 This operation is symmetrical to pull: it is identical to a pull
4514 This operation is symmetrical to pull: it is identical to a pull
4516 in the destination repository from the current one.
4515 in the destination repository from the current one.
4517
4516
4518 By default, push will not allow creation of new heads at the
4517 By default, push will not allow creation of new heads at the
4519 destination, since multiple heads would make it unclear which head
4518 destination, since multiple heads would make it unclear which head
4520 to use. In this situation, it is recommended to pull and merge
4519 to use. In this situation, it is recommended to pull and merge
4521 before pushing.
4520 before pushing.
4522
4521
4523 Use --new-branch if you want to allow push to create a new named
4522 Use --new-branch if you want to allow push to create a new named
4524 branch that is not present at the destination. This allows you to
4523 branch that is not present at the destination. This allows you to
4525 only create a new branch without forcing other changes.
4524 only create a new branch without forcing other changes.
4526
4525
4527 .. note::
4526 .. note::
4528
4527
4529 Extra care should be taken with the -f/--force option,
4528 Extra care should be taken with the -f/--force option,
4530 which will push all new heads on all branches, an action which will
4529 which will push all new heads on all branches, an action which will
4531 almost always cause confusion for collaborators.
4530 almost always cause confusion for collaborators.
4532
4531
4533 If -r/--rev is used, the specified revision and all its ancestors
4532 If -r/--rev is used, the specified revision and all its ancestors
4534 will be pushed to the remote repository.
4533 will be pushed to the remote repository.
4535
4534
4536 If -B/--bookmark is used, the specified bookmarked revision, its
4535 If -B/--bookmark is used, the specified bookmarked revision, its
4537 ancestors, and the bookmark will be pushed to the remote
4536 ancestors, and the bookmark will be pushed to the remote
4538 repository. Specifying ``.`` is equivalent to specifying the active
4537 repository. Specifying ``.`` is equivalent to specifying the active
4539 bookmark's name.
4538 bookmark's name.
4540
4539
4541 Please see :hg:`help urls` for important details about ``ssh://``
4540 Please see :hg:`help urls` for important details about ``ssh://``
4542 URLs. If DESTINATION is omitted, a default path will be used.
4541 URLs. If DESTINATION is omitted, a default path will be used.
4543
4542
4544 .. container:: verbose
4543 .. container:: verbose
4545
4544
4546 The --pushvars option sends strings to the server that become
4545 The --pushvars option sends strings to the server that become
4547 environment variables prepended with ``HG_USERVAR_``. For example,
4546 environment variables prepended with ``HG_USERVAR_``. For example,
4548 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4547 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4549 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4548 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4550
4549
4551 pushvars can provide for user-overridable hooks as well as set debug
4550 pushvars can provide for user-overridable hooks as well as set debug
4552 levels. One example is having a hook that blocks commits containing
4551 levels. One example is having a hook that blocks commits containing
4553 conflict markers, but enables the user to override the hook if the file
4552 conflict markers, but enables the user to override the hook if the file
4554 is using conflict markers for testing purposes or the file format has
4553 is using conflict markers for testing purposes or the file format has
4555 strings that look like conflict markers.
4554 strings that look like conflict markers.
4556
4555
4557 By default, servers will ignore `--pushvars`. To enable it add the
4556 By default, servers will ignore `--pushvars`. To enable it add the
4558 following to your configuration file::
4557 following to your configuration file::
4559
4558
4560 [push]
4559 [push]
4561 pushvars.server = true
4560 pushvars.server = true
4562
4561
4563 Returns 0 if push was successful, 1 if nothing to push.
4562 Returns 0 if push was successful, 1 if nothing to push.
4564 """
4563 """
4565
4564
4566 opts = pycompat.byteskwargs(opts)
4565 opts = pycompat.byteskwargs(opts)
4567 if opts.get('bookmark'):
4566 if opts.get('bookmark'):
4568 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4567 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4569 for b in opts['bookmark']:
4568 for b in opts['bookmark']:
4570 # translate -B options to -r so changesets get pushed
4569 # translate -B options to -r so changesets get pushed
4571 b = repo._bookmarks.expandname(b)
4570 b = repo._bookmarks.expandname(b)
4572 if b in repo._bookmarks:
4571 if b in repo._bookmarks:
4573 opts.setdefault('rev', []).append(b)
4572 opts.setdefault('rev', []).append(b)
4574 else:
4573 else:
4575 # if we try to push a deleted bookmark, translate it to null
4574 # if we try to push a deleted bookmark, translate it to null
4576 # this lets simultaneous -r, -b options continue working
4575 # this lets simultaneous -r, -b options continue working
4577 opts.setdefault('rev', []).append("null")
4576 opts.setdefault('rev', []).append("null")
4578
4577
4579 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4578 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4580 if not path:
4579 if not path:
4581 raise error.Abort(_('default repository not configured!'),
4580 raise error.Abort(_('default repository not configured!'),
4582 hint=_("see 'hg help config.paths'"))
4581 hint=_("see 'hg help config.paths'"))
4583 dest = path.pushloc or path.loc
4582 dest = path.pushloc or path.loc
4584 branches = (path.branch, opts.get('branch') or [])
4583 branches = (path.branch, opts.get('branch') or [])
4585 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4584 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4586 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4585 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4587 other = hg.peer(repo, opts, dest)
4586 other = hg.peer(repo, opts, dest)
4588
4587
4589 if revs:
4588 if revs:
4590 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4589 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4591 if not revs:
4590 if not revs:
4592 raise error.Abort(_("specified revisions evaluate to an empty set"),
4591 raise error.Abort(_("specified revisions evaluate to an empty set"),
4593 hint=_("use different revision arguments"))
4592 hint=_("use different revision arguments"))
4594 elif path.pushrev:
4593 elif path.pushrev:
4595 # It doesn't make any sense to specify ancestor revisions. So limit
4594 # It doesn't make any sense to specify ancestor revisions. So limit
4596 # to DAG heads to make discovery simpler.
4595 # to DAG heads to make discovery simpler.
4597 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4596 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4598 revs = scmutil.revrange(repo, [expr])
4597 revs = scmutil.revrange(repo, [expr])
4599 revs = [repo[rev].node() for rev in revs]
4598 revs = [repo[rev].node() for rev in revs]
4600 if not revs:
4599 if not revs:
4601 raise error.Abort(_('default push revset for path evaluates to an '
4600 raise error.Abort(_('default push revset for path evaluates to an '
4602 'empty set'))
4601 'empty set'))
4603
4602
4604 repo._subtoppath = dest
4603 repo._subtoppath = dest
4605 try:
4604 try:
4606 # push subrepos depth-first for coherent ordering
4605 # push subrepos depth-first for coherent ordering
4607 c = repo['.']
4606 c = repo['.']
4608 subs = c.substate # only repos that are committed
4607 subs = c.substate # only repos that are committed
4609 for s in sorted(subs):
4608 for s in sorted(subs):
4610 result = c.sub(s).push(opts)
4609 result = c.sub(s).push(opts)
4611 if result == 0:
4610 if result == 0:
4612 return not result
4611 return not result
4613 finally:
4612 finally:
4614 del repo._subtoppath
4613 del repo._subtoppath
4615
4614
4616 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4615 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4617 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4616 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4618
4617
4619 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4618 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4620 newbranch=opts.get('new_branch'),
4619 newbranch=opts.get('new_branch'),
4621 bookmarks=opts.get('bookmark', ()),
4620 bookmarks=opts.get('bookmark', ()),
4622 publish=opts.get('publish'),
4621 publish=opts.get('publish'),
4623 opargs=opargs)
4622 opargs=opargs)
4624
4623
4625 result = not pushop.cgresult
4624 result = not pushop.cgresult
4626
4625
4627 if pushop.bkresult is not None:
4626 if pushop.bkresult is not None:
4628 if pushop.bkresult == 2:
4627 if pushop.bkresult == 2:
4629 result = 2
4628 result = 2
4630 elif not result and pushop.bkresult:
4629 elif not result and pushop.bkresult:
4631 result = 2
4630 result = 2
4632
4631
4633 return result
4632 return result
4634
4633
4635 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4634 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4636 def recover(ui, repo):
4635 def recover(ui, repo):
4637 """roll back an interrupted transaction
4636 """roll back an interrupted transaction
4638
4637
4639 Recover from an interrupted commit or pull.
4638 Recover from an interrupted commit or pull.
4640
4639
4641 This command tries to fix the repository status after an
4640 This command tries to fix the repository status after an
4642 interrupted operation. It should only be necessary when Mercurial
4641 interrupted operation. It should only be necessary when Mercurial
4643 suggests it.
4642 suggests it.
4644
4643
4645 Returns 0 if successful, 1 if nothing to recover or verify fails.
4644 Returns 0 if successful, 1 if nothing to recover or verify fails.
4646 """
4645 """
4647 if repo.recover():
4646 if repo.recover():
4648 return hg.verify(repo)
4647 return hg.verify(repo)
4649 return 1
4648 return 1
4650
4649
4651 @command('remove|rm',
4650 @command('remove|rm',
4652 [('A', 'after', None, _('record delete for missing files')),
4651 [('A', 'after', None, _('record delete for missing files')),
4653 ('f', 'force', None,
4652 ('f', 'force', None,
4654 _('forget added files, delete modified files')),
4653 _('forget added files, delete modified files')),
4655 ] + subrepoopts + walkopts + dryrunopts,
4654 ] + subrepoopts + walkopts + dryrunopts,
4656 _('[OPTION]... FILE...'),
4655 _('[OPTION]... FILE...'),
4657 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4656 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4658 helpbasic=True, inferrepo=True)
4657 helpbasic=True, inferrepo=True)
4659 def remove(ui, repo, *pats, **opts):
4658 def remove(ui, repo, *pats, **opts):
4660 """remove the specified files on the next commit
4659 """remove the specified files on the next commit
4661
4660
4662 Schedule the indicated files for removal from the current branch.
4661 Schedule the indicated files for removal from the current branch.
4663
4662
4664 This command schedules the files to be removed at the next commit.
4663 This command schedules the files to be removed at the next commit.
4665 To undo a remove before that, see :hg:`revert`. To undo added
4664 To undo a remove before that, see :hg:`revert`. To undo added
4666 files, see :hg:`forget`.
4665 files, see :hg:`forget`.
4667
4666
4668 .. container:: verbose
4667 .. container:: verbose
4669
4668
4670 -A/--after can be used to remove only files that have already
4669 -A/--after can be used to remove only files that have already
4671 been deleted, -f/--force can be used to force deletion, and -Af
4670 been deleted, -f/--force can be used to force deletion, and -Af
4672 can be used to remove files from the next revision without
4671 can be used to remove files from the next revision without
4673 deleting them from the working directory.
4672 deleting them from the working directory.
4674
4673
4675 The following table details the behavior of remove for different
4674 The following table details the behavior of remove for different
4676 file states (columns) and option combinations (rows). The file
4675 file states (columns) and option combinations (rows). The file
4677 states are Added [A], Clean [C], Modified [M] and Missing [!]
4676 states are Added [A], Clean [C], Modified [M] and Missing [!]
4678 (as reported by :hg:`status`). The actions are Warn, Remove
4677 (as reported by :hg:`status`). The actions are Warn, Remove
4679 (from branch) and Delete (from disk):
4678 (from branch) and Delete (from disk):
4680
4679
4681 ========= == == == ==
4680 ========= == == == ==
4682 opt/state A C M !
4681 opt/state A C M !
4683 ========= == == == ==
4682 ========= == == == ==
4684 none W RD W R
4683 none W RD W R
4685 -f R RD RD R
4684 -f R RD RD R
4686 -A W W W R
4685 -A W W W R
4687 -Af R R R R
4686 -Af R R R R
4688 ========= == == == ==
4687 ========= == == == ==
4689
4688
4690 .. note::
4689 .. note::
4691
4690
4692 :hg:`remove` never deletes files in Added [A] state from the
4691 :hg:`remove` never deletes files in Added [A] state from the
4693 working directory, not even if ``--force`` is specified.
4692 working directory, not even if ``--force`` is specified.
4694
4693
4695 Returns 0 on success, 1 if any warnings encountered.
4694 Returns 0 on success, 1 if any warnings encountered.
4696 """
4695 """
4697
4696
4698 opts = pycompat.byteskwargs(opts)
4697 opts = pycompat.byteskwargs(opts)
4699 after, force = opts.get('after'), opts.get('force')
4698 after, force = opts.get('after'), opts.get('force')
4700 dryrun = opts.get('dry_run')
4699 dryrun = opts.get('dry_run')
4701 if not pats and not after:
4700 if not pats and not after:
4702 raise error.Abort(_('no files specified'))
4701 raise error.Abort(_('no files specified'))
4703
4702
4704 m = scmutil.match(repo[None], pats, opts)
4703 m = scmutil.match(repo[None], pats, opts)
4705 subrepos = opts.get('subrepos')
4704 subrepos = opts.get('subrepos')
4706 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4705 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4707 dryrun=dryrun)
4706 dryrun=dryrun)
4708
4707
4709 @command('rename|move|mv',
4708 @command('rename|move|mv',
4710 [('A', 'after', None, _('record a rename that has already occurred')),
4709 [('A', 'after', None, _('record a rename that has already occurred')),
4711 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4710 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4712 ] + walkopts + dryrunopts,
4711 ] + walkopts + dryrunopts,
4713 _('[OPTION]... SOURCE... DEST'),
4712 _('[OPTION]... SOURCE... DEST'),
4714 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4713 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4715 def rename(ui, repo, *pats, **opts):
4714 def rename(ui, repo, *pats, **opts):
4716 """rename files; equivalent of copy + remove
4715 """rename files; equivalent of copy + remove
4717
4716
4718 Mark dest as copies of sources; mark sources for deletion. If dest
4717 Mark dest as copies of sources; mark sources for deletion. If dest
4719 is a directory, copies are put in that directory. If dest is a
4718 is a directory, copies are put in that directory. If dest is a
4720 file, there can only be one source.
4719 file, there can only be one source.
4721
4720
4722 By default, this command copies the contents of files as they
4721 By default, this command copies the contents of files as they
4723 exist in the working directory. If invoked with -A/--after, the
4722 exist in the working directory. If invoked with -A/--after, the
4724 operation is recorded, but no copying is performed.
4723 operation is recorded, but no copying is performed.
4725
4724
4726 This command takes effect at the next commit. To undo a rename
4725 This command takes effect at the next commit. To undo a rename
4727 before that, see :hg:`revert`.
4726 before that, see :hg:`revert`.
4728
4727
4729 Returns 0 on success, 1 if errors are encountered.
4728 Returns 0 on success, 1 if errors are encountered.
4730 """
4729 """
4731 opts = pycompat.byteskwargs(opts)
4730 opts = pycompat.byteskwargs(opts)
4732 with repo.wlock(False):
4731 with repo.wlock(False):
4733 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4732 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4734
4733
4735 @command('resolve',
4734 @command('resolve',
4736 [('a', 'all', None, _('select all unresolved files')),
4735 [('a', 'all', None, _('select all unresolved files')),
4737 ('l', 'list', None, _('list state of files needing merge')),
4736 ('l', 'list', None, _('list state of files needing merge')),
4738 ('m', 'mark', None, _('mark files as resolved')),
4737 ('m', 'mark', None, _('mark files as resolved')),
4739 ('u', 'unmark', None, _('mark files as unresolved')),
4738 ('u', 'unmark', None, _('mark files as unresolved')),
4740 ('n', 'no-status', None, _('hide status prefix')),
4739 ('n', 'no-status', None, _('hide status prefix')),
4741 ('', 're-merge', None, _('re-merge files'))]
4740 ('', 're-merge', None, _('re-merge files'))]
4742 + mergetoolopts + walkopts + formatteropts,
4741 + mergetoolopts + walkopts + formatteropts,
4743 _('[OPTION]... [FILE]...'),
4742 _('[OPTION]... [FILE]...'),
4744 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4743 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4745 inferrepo=True)
4744 inferrepo=True)
4746 def resolve(ui, repo, *pats, **opts):
4745 def resolve(ui, repo, *pats, **opts):
4747 """redo merges or set/view the merge status of files
4746 """redo merges or set/view the merge status of files
4748
4747
4749 Merges with unresolved conflicts are often the result of
4748 Merges with unresolved conflicts are often the result of
4750 non-interactive merging using the ``internal:merge`` configuration
4749 non-interactive merging using the ``internal:merge`` configuration
4751 setting, or a command-line merge tool like ``diff3``. The resolve
4750 setting, or a command-line merge tool like ``diff3``. The resolve
4752 command is used to manage the files involved in a merge, after
4751 command is used to manage the files involved in a merge, after
4753 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4752 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4754 working directory must have two parents). See :hg:`help
4753 working directory must have two parents). See :hg:`help
4755 merge-tools` for information on configuring merge tools.
4754 merge-tools` for information on configuring merge tools.
4756
4755
4757 The resolve command can be used in the following ways:
4756 The resolve command can be used in the following ways:
4758
4757
4759 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4758 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4760 the specified files, discarding any previous merge attempts. Re-merging
4759 the specified files, discarding any previous merge attempts. Re-merging
4761 is not performed for files already marked as resolved. Use ``--all/-a``
4760 is not performed for files already marked as resolved. Use ``--all/-a``
4762 to select all unresolved files. ``--tool`` can be used to specify
4761 to select all unresolved files. ``--tool`` can be used to specify
4763 the merge tool used for the given files. It overrides the HGMERGE
4762 the merge tool used for the given files. It overrides the HGMERGE
4764 environment variable and your configuration files. Previous file
4763 environment variable and your configuration files. Previous file
4765 contents are saved with a ``.orig`` suffix.
4764 contents are saved with a ``.orig`` suffix.
4766
4765
4767 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4766 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4768 (e.g. after having manually fixed-up the files). The default is
4767 (e.g. after having manually fixed-up the files). The default is
4769 to mark all unresolved files.
4768 to mark all unresolved files.
4770
4769
4771 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4770 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4772 default is to mark all resolved files.
4771 default is to mark all resolved files.
4773
4772
4774 - :hg:`resolve -l`: list files which had or still have conflicts.
4773 - :hg:`resolve -l`: list files which had or still have conflicts.
4775 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4774 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4776 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4775 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4777 the list. See :hg:`help filesets` for details.
4776 the list. See :hg:`help filesets` for details.
4778
4777
4779 .. note::
4778 .. note::
4780
4779
4781 Mercurial will not let you commit files with unresolved merge
4780 Mercurial will not let you commit files with unresolved merge
4782 conflicts. You must use :hg:`resolve -m ...` before you can
4781 conflicts. You must use :hg:`resolve -m ...` before you can
4783 commit after a conflicting merge.
4782 commit after a conflicting merge.
4784
4783
4785 .. container:: verbose
4784 .. container:: verbose
4786
4785
4787 Template:
4786 Template:
4788
4787
4789 The following keywords are supported in addition to the common template
4788 The following keywords are supported in addition to the common template
4790 keywords and functions. See also :hg:`help templates`.
4789 keywords and functions. See also :hg:`help templates`.
4791
4790
4792 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4791 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4793 :path: String. Repository-absolute path of the file.
4792 :path: String. Repository-absolute path of the file.
4794
4793
4795 Returns 0 on success, 1 if any files fail a resolve attempt.
4794 Returns 0 on success, 1 if any files fail a resolve attempt.
4796 """
4795 """
4797
4796
4798 opts = pycompat.byteskwargs(opts)
4797 opts = pycompat.byteskwargs(opts)
4799 confirm = ui.configbool('commands', 'resolve.confirm')
4798 confirm = ui.configbool('commands', 'resolve.confirm')
4800 flaglist = 'all mark unmark list no_status re_merge'.split()
4799 flaglist = 'all mark unmark list no_status re_merge'.split()
4801 all, mark, unmark, show, nostatus, remerge = \
4800 all, mark, unmark, show, nostatus, remerge = \
4802 [opts.get(o) for o in flaglist]
4801 [opts.get(o) for o in flaglist]
4803
4802
4804 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4803 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4805 if actioncount > 1:
4804 if actioncount > 1:
4806 raise error.Abort(_("too many actions specified"))
4805 raise error.Abort(_("too many actions specified"))
4807 elif (actioncount == 0
4806 elif (actioncount == 0
4808 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4807 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4809 hint = _('use --mark, --unmark, --list or --re-merge')
4808 hint = _('use --mark, --unmark, --list or --re-merge')
4810 raise error.Abort(_('no action specified'), hint=hint)
4809 raise error.Abort(_('no action specified'), hint=hint)
4811 if pats and all:
4810 if pats and all:
4812 raise error.Abort(_("can't specify --all and patterns"))
4811 raise error.Abort(_("can't specify --all and patterns"))
4813 if not (all or pats or show or mark or unmark):
4812 if not (all or pats or show or mark or unmark):
4814 raise error.Abort(_('no files or directories specified'),
4813 raise error.Abort(_('no files or directories specified'),
4815 hint=('use --all to re-merge all unresolved files'))
4814 hint=('use --all to re-merge all unresolved files'))
4816
4815
4817 if confirm:
4816 if confirm:
4818 if all:
4817 if all:
4819 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4818 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4820 b'$$ &Yes $$ &No')):
4819 b'$$ &Yes $$ &No')):
4821 raise error.Abort(_('user quit'))
4820 raise error.Abort(_('user quit'))
4822 if mark and not pats:
4821 if mark and not pats:
4823 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4822 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4824 b'$$ &Yes $$ &No')):
4823 b'$$ &Yes $$ &No')):
4825 raise error.Abort(_('user quit'))
4824 raise error.Abort(_('user quit'))
4826 if unmark and not pats:
4825 if unmark and not pats:
4827 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4826 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4828 b'$$ &Yes $$ &No')):
4827 b'$$ &Yes $$ &No')):
4829 raise error.Abort(_('user quit'))
4828 raise error.Abort(_('user quit'))
4830
4829
4831 if show:
4830 if show:
4832 ui.pager('resolve')
4831 ui.pager('resolve')
4833 fm = ui.formatter('resolve', opts)
4832 fm = ui.formatter('resolve', opts)
4834 ms = mergemod.mergestate.read(repo)
4833 ms = mergemod.mergestate.read(repo)
4835 wctx = repo[None]
4834 wctx = repo[None]
4836 m = scmutil.match(wctx, pats, opts)
4835 m = scmutil.match(wctx, pats, opts)
4837
4836
4838 # Labels and keys based on merge state. Unresolved path conflicts show
4837 # Labels and keys based on merge state. Unresolved path conflicts show
4839 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4838 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4840 # resolved conflicts.
4839 # resolved conflicts.
4841 mergestateinfo = {
4840 mergestateinfo = {
4842 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4841 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4843 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4842 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4844 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4843 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4845 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4844 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4846 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4845 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4847 'D'),
4846 'D'),
4848 }
4847 }
4849
4848
4850 for f in ms:
4849 for f in ms:
4851 if not m(f):
4850 if not m(f):
4852 continue
4851 continue
4853
4852
4854 label, key = mergestateinfo[ms[f]]
4853 label, key = mergestateinfo[ms[f]]
4855 fm.startitem()
4854 fm.startitem()
4856 fm.context(ctx=wctx)
4855 fm.context(ctx=wctx)
4857 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4856 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4858 fm.write('path', '%s\n', f, label=label)
4857 fm.write('path', '%s\n', f, label=label)
4859 fm.end()
4858 fm.end()
4860 return 0
4859 return 0
4861
4860
4862 with repo.wlock():
4861 with repo.wlock():
4863 ms = mergemod.mergestate.read(repo)
4862 ms = mergemod.mergestate.read(repo)
4864
4863
4865 if not (ms.active() or repo.dirstate.p2() != nullid):
4864 if not (ms.active() or repo.dirstate.p2() != nullid):
4866 raise error.Abort(
4865 raise error.Abort(
4867 _('resolve command not applicable when not merging'))
4866 _('resolve command not applicable when not merging'))
4868
4867
4869 wctx = repo[None]
4868 wctx = repo[None]
4870
4869
4871 if (ms.mergedriver
4870 if (ms.mergedriver
4872 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4871 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4873 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4872 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4874 ms.commit()
4873 ms.commit()
4875 # allow mark and unmark to go through
4874 # allow mark and unmark to go through
4876 if not mark and not unmark and not proceed:
4875 if not mark and not unmark and not proceed:
4877 return 1
4876 return 1
4878
4877
4879 m = scmutil.match(wctx, pats, opts)
4878 m = scmutil.match(wctx, pats, opts)
4880 ret = 0
4879 ret = 0
4881 didwork = False
4880 didwork = False
4882 runconclude = False
4881 runconclude = False
4883
4882
4884 tocomplete = []
4883 tocomplete = []
4885 hasconflictmarkers = []
4884 hasconflictmarkers = []
4886 if mark:
4885 if mark:
4887 markcheck = ui.config('commands', 'resolve.mark-check')
4886 markcheck = ui.config('commands', 'resolve.mark-check')
4888 if markcheck not in ['warn', 'abort']:
4887 if markcheck not in ['warn', 'abort']:
4889 # Treat all invalid / unrecognized values as 'none'.
4888 # Treat all invalid / unrecognized values as 'none'.
4890 markcheck = False
4889 markcheck = False
4891 for f in ms:
4890 for f in ms:
4892 if not m(f):
4891 if not m(f):
4893 continue
4892 continue
4894
4893
4895 didwork = True
4894 didwork = True
4896
4895
4897 # don't let driver-resolved files be marked, and run the conclude
4896 # don't let driver-resolved files be marked, and run the conclude
4898 # step if asked to resolve
4897 # step if asked to resolve
4899 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4898 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4900 exact = m.exact(f)
4899 exact = m.exact(f)
4901 if mark:
4900 if mark:
4902 if exact:
4901 if exact:
4903 ui.warn(_('not marking %s as it is driver-resolved\n')
4902 ui.warn(_('not marking %s as it is driver-resolved\n')
4904 % f)
4903 % f)
4905 elif unmark:
4904 elif unmark:
4906 if exact:
4905 if exact:
4907 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4906 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4908 % f)
4907 % f)
4909 else:
4908 else:
4910 runconclude = True
4909 runconclude = True
4911 continue
4910 continue
4912
4911
4913 # path conflicts must be resolved manually
4912 # path conflicts must be resolved manually
4914 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4913 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4915 mergemod.MERGE_RECORD_RESOLVED_PATH):
4914 mergemod.MERGE_RECORD_RESOLVED_PATH):
4916 if mark:
4915 if mark:
4917 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4916 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4918 elif unmark:
4917 elif unmark:
4919 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4918 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4920 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4919 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4921 ui.warn(_('%s: path conflict must be resolved manually\n')
4920 ui.warn(_('%s: path conflict must be resolved manually\n')
4922 % f)
4921 % f)
4923 continue
4922 continue
4924
4923
4925 if mark:
4924 if mark:
4926 if markcheck:
4925 if markcheck:
4927 with repo.wvfs(f) as fobj:
4926 with repo.wvfs(f) as fobj:
4928 fdata = fobj.read()
4927 fdata = fobj.read()
4929 if filemerge.hasconflictmarkers(fdata) and \
4928 if filemerge.hasconflictmarkers(fdata) and \
4930 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4929 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4931 hasconflictmarkers.append(f)
4930 hasconflictmarkers.append(f)
4932 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4931 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4933 elif unmark:
4932 elif unmark:
4934 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4933 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4935 else:
4934 else:
4936 # backup pre-resolve (merge uses .orig for its own purposes)
4935 # backup pre-resolve (merge uses .orig for its own purposes)
4937 a = repo.wjoin(f)
4936 a = repo.wjoin(f)
4938 try:
4937 try:
4939 util.copyfile(a, a + ".resolve")
4938 util.copyfile(a, a + ".resolve")
4940 except (IOError, OSError) as inst:
4939 except (IOError, OSError) as inst:
4941 if inst.errno != errno.ENOENT:
4940 if inst.errno != errno.ENOENT:
4942 raise
4941 raise
4943
4942
4944 try:
4943 try:
4945 # preresolve file
4944 # preresolve file
4946 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4945 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4947 with ui.configoverride(overrides, 'resolve'):
4946 with ui.configoverride(overrides, 'resolve'):
4948 complete, r = ms.preresolve(f, wctx)
4947 complete, r = ms.preresolve(f, wctx)
4949 if not complete:
4948 if not complete:
4950 tocomplete.append(f)
4949 tocomplete.append(f)
4951 elif r:
4950 elif r:
4952 ret = 1
4951 ret = 1
4953 finally:
4952 finally:
4954 ms.commit()
4953 ms.commit()
4955
4954
4956 # replace filemerge's .orig file with our resolve file, but only
4955 # replace filemerge's .orig file with our resolve file, but only
4957 # for merges that are complete
4956 # for merges that are complete
4958 if complete:
4957 if complete:
4959 try:
4958 try:
4960 util.rename(a + ".resolve",
4959 util.rename(a + ".resolve",
4961 scmutil.origpath(ui, repo, a))
4960 scmutil.origpath(ui, repo, a))
4962 except OSError as inst:
4961 except OSError as inst:
4963 if inst.errno != errno.ENOENT:
4962 if inst.errno != errno.ENOENT:
4964 raise
4963 raise
4965
4964
4966 if hasconflictmarkers:
4965 if hasconflictmarkers:
4967 ui.warn(_('warning: the following files still have conflict '
4966 ui.warn(_('warning: the following files still have conflict '
4968 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4967 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4969 if markcheck == 'abort' and not all and not pats:
4968 if markcheck == 'abort' and not all and not pats:
4970 raise error.Abort(_('conflict markers detected'),
4969 raise error.Abort(_('conflict markers detected'),
4971 hint=_('use --all to mark anyway'))
4970 hint=_('use --all to mark anyway'))
4972
4971
4973 for f in tocomplete:
4972 for f in tocomplete:
4974 try:
4973 try:
4975 # resolve file
4974 # resolve file
4976 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4975 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4977 with ui.configoverride(overrides, 'resolve'):
4976 with ui.configoverride(overrides, 'resolve'):
4978 r = ms.resolve(f, wctx)
4977 r = ms.resolve(f, wctx)
4979 if r:
4978 if r:
4980 ret = 1
4979 ret = 1
4981 finally:
4980 finally:
4982 ms.commit()
4981 ms.commit()
4983
4982
4984 # replace filemerge's .orig file with our resolve file
4983 # replace filemerge's .orig file with our resolve file
4985 a = repo.wjoin(f)
4984 a = repo.wjoin(f)
4986 try:
4985 try:
4987 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4986 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4988 except OSError as inst:
4987 except OSError as inst:
4989 if inst.errno != errno.ENOENT:
4988 if inst.errno != errno.ENOENT:
4990 raise
4989 raise
4991
4990
4992 ms.commit()
4991 ms.commit()
4993 ms.recordactions()
4992 ms.recordactions()
4994
4993
4995 if not didwork and pats:
4994 if not didwork and pats:
4996 hint = None
4995 hint = None
4997 if not any([p for p in pats if p.find(':') >= 0]):
4996 if not any([p for p in pats if p.find(':') >= 0]):
4998 pats = ['path:%s' % p for p in pats]
4997 pats = ['path:%s' % p for p in pats]
4999 m = scmutil.match(wctx, pats, opts)
4998 m = scmutil.match(wctx, pats, opts)
5000 for f in ms:
4999 for f in ms:
5001 if not m(f):
5000 if not m(f):
5002 continue
5001 continue
5003 def flag(o):
5002 def flag(o):
5004 if o == 're_merge':
5003 if o == 're_merge':
5005 return '--re-merge '
5004 return '--re-merge '
5006 return '-%s ' % o[0:1]
5005 return '-%s ' % o[0:1]
5007 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5006 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5008 hint = _("(try: hg resolve %s%s)\n") % (
5007 hint = _("(try: hg resolve %s%s)\n") % (
5009 flags,
5008 flags,
5010 ' '.join(pats))
5009 ' '.join(pats))
5011 break
5010 break
5012 ui.warn(_("arguments do not match paths that need resolving\n"))
5011 ui.warn(_("arguments do not match paths that need resolving\n"))
5013 if hint:
5012 if hint:
5014 ui.warn(hint)
5013 ui.warn(hint)
5015 elif ms.mergedriver and ms.mdstate() != 's':
5014 elif ms.mergedriver and ms.mdstate() != 's':
5016 # run conclude step when either a driver-resolved file is requested
5015 # run conclude step when either a driver-resolved file is requested
5017 # or there are no driver-resolved files
5016 # or there are no driver-resolved files
5018 # we can't use 'ret' to determine whether any files are unresolved
5017 # we can't use 'ret' to determine whether any files are unresolved
5019 # because we might not have tried to resolve some
5018 # because we might not have tried to resolve some
5020 if ((runconclude or not list(ms.driverresolved()))
5019 if ((runconclude or not list(ms.driverresolved()))
5021 and not list(ms.unresolved())):
5020 and not list(ms.unresolved())):
5022 proceed = mergemod.driverconclude(repo, ms, wctx)
5021 proceed = mergemod.driverconclude(repo, ms, wctx)
5023 ms.commit()
5022 ms.commit()
5024 if not proceed:
5023 if not proceed:
5025 return 1
5024 return 1
5026
5025
5027 # Nudge users into finishing an unfinished operation
5026 # Nudge users into finishing an unfinished operation
5028 unresolvedf = list(ms.unresolved())
5027 unresolvedf = list(ms.unresolved())
5029 driverresolvedf = list(ms.driverresolved())
5028 driverresolvedf = list(ms.driverresolved())
5030 if not unresolvedf and not driverresolvedf:
5029 if not unresolvedf and not driverresolvedf:
5031 ui.status(_('(no more unresolved files)\n'))
5030 ui.status(_('(no more unresolved files)\n'))
5032 cmdutil.checkafterresolved(repo)
5031 cmdutil.checkafterresolved(repo)
5033 elif not unresolvedf:
5032 elif not unresolvedf:
5034 ui.status(_('(no more unresolved files -- '
5033 ui.status(_('(no more unresolved files -- '
5035 'run "hg resolve --all" to conclude)\n'))
5034 'run "hg resolve --all" to conclude)\n'))
5036
5035
5037 return ret
5036 return ret
5038
5037
5039 @command('revert',
5038 @command('revert',
5040 [('a', 'all', None, _('revert all changes when no arguments given')),
5039 [('a', 'all', None, _('revert all changes when no arguments given')),
5041 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5040 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5042 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5041 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5043 ('C', 'no-backup', None, _('do not save backup copies of files')),
5042 ('C', 'no-backup', None, _('do not save backup copies of files')),
5044 ('i', 'interactive', None, _('interactively select the changes')),
5043 ('i', 'interactive', None, _('interactively select the changes')),
5045 ] + walkopts + dryrunopts,
5044 ] + walkopts + dryrunopts,
5046 _('[OPTION]... [-r REV] [NAME]...'),
5045 _('[OPTION]... [-r REV] [NAME]...'),
5047 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5046 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5048 def revert(ui, repo, *pats, **opts):
5047 def revert(ui, repo, *pats, **opts):
5049 """restore files to their checkout state
5048 """restore files to their checkout state
5050
5049
5051 .. note::
5050 .. note::
5052
5051
5053 To check out earlier revisions, you should use :hg:`update REV`.
5052 To check out earlier revisions, you should use :hg:`update REV`.
5054 To cancel an uncommitted merge (and lose your changes),
5053 To cancel an uncommitted merge (and lose your changes),
5055 use :hg:`merge --abort`.
5054 use :hg:`merge --abort`.
5056
5055
5057 With no revision specified, revert the specified files or directories
5056 With no revision specified, revert the specified files or directories
5058 to the contents they had in the parent of the working directory.
5057 to the contents they had in the parent of the working directory.
5059 This restores the contents of files to an unmodified
5058 This restores the contents of files to an unmodified
5060 state and unschedules adds, removes, copies, and renames. If the
5059 state and unschedules adds, removes, copies, and renames. If the
5061 working directory has two parents, you must explicitly specify a
5060 working directory has two parents, you must explicitly specify a
5062 revision.
5061 revision.
5063
5062
5064 Using the -r/--rev or -d/--date options, revert the given files or
5063 Using the -r/--rev or -d/--date options, revert the given files or
5065 directories to their states as of a specific revision. Because
5064 directories to their states as of a specific revision. Because
5066 revert does not change the working directory parents, this will
5065 revert does not change the working directory parents, this will
5067 cause these files to appear modified. This can be helpful to "back
5066 cause these files to appear modified. This can be helpful to "back
5068 out" some or all of an earlier change. See :hg:`backout` for a
5067 out" some or all of an earlier change. See :hg:`backout` for a
5069 related method.
5068 related method.
5070
5069
5071 Modified files are saved with a .orig suffix before reverting.
5070 Modified files are saved with a .orig suffix before reverting.
5072 To disable these backups, use --no-backup. It is possible to store
5071 To disable these backups, use --no-backup. It is possible to store
5073 the backup files in a custom directory relative to the root of the
5072 the backup files in a custom directory relative to the root of the
5074 repository by setting the ``ui.origbackuppath`` configuration
5073 repository by setting the ``ui.origbackuppath`` configuration
5075 option.
5074 option.
5076
5075
5077 See :hg:`help dates` for a list of formats valid for -d/--date.
5076 See :hg:`help dates` for a list of formats valid for -d/--date.
5078
5077
5079 See :hg:`help backout` for a way to reverse the effect of an
5078 See :hg:`help backout` for a way to reverse the effect of an
5080 earlier changeset.
5079 earlier changeset.
5081
5080
5082 Returns 0 on success.
5081 Returns 0 on success.
5083 """
5082 """
5084
5083
5085 opts = pycompat.byteskwargs(opts)
5084 opts = pycompat.byteskwargs(opts)
5086 if opts.get("date"):
5085 if opts.get("date"):
5087 if opts.get("rev"):
5086 if opts.get("rev"):
5088 raise error.Abort(_("you can't specify a revision and a date"))
5087 raise error.Abort(_("you can't specify a revision and a date"))
5089 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5088 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5090
5089
5091 parent, p2 = repo.dirstate.parents()
5090 parent, p2 = repo.dirstate.parents()
5092 if not opts.get('rev') and p2 != nullid:
5091 if not opts.get('rev') and p2 != nullid:
5093 # revert after merge is a trap for new users (issue2915)
5092 # revert after merge is a trap for new users (issue2915)
5094 raise error.Abort(_('uncommitted merge with no revision specified'),
5093 raise error.Abort(_('uncommitted merge with no revision specified'),
5095 hint=_("use 'hg update' or see 'hg help revert'"))
5094 hint=_("use 'hg update' or see 'hg help revert'"))
5096
5095
5097 rev = opts.get('rev')
5096 rev = opts.get('rev')
5098 if rev:
5097 if rev:
5099 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5098 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5100 ctx = scmutil.revsingle(repo, rev)
5099 ctx = scmutil.revsingle(repo, rev)
5101
5100
5102 if (not (pats or opts.get('include') or opts.get('exclude') or
5101 if (not (pats or opts.get('include') or opts.get('exclude') or
5103 opts.get('all') or opts.get('interactive'))):
5102 opts.get('all') or opts.get('interactive'))):
5104 msg = _("no files or directories specified")
5103 msg = _("no files or directories specified")
5105 if p2 != nullid:
5104 if p2 != nullid:
5106 hint = _("uncommitted merge, use --all to discard all changes,"
5105 hint = _("uncommitted merge, use --all to discard all changes,"
5107 " or 'hg update -C .' to abort the merge")
5106 " or 'hg update -C .' to abort the merge")
5108 raise error.Abort(msg, hint=hint)
5107 raise error.Abort(msg, hint=hint)
5109 dirty = any(repo.status())
5108 dirty = any(repo.status())
5110 node = ctx.node()
5109 node = ctx.node()
5111 if node != parent:
5110 if node != parent:
5112 if dirty:
5111 if dirty:
5113 hint = _("uncommitted changes, use --all to discard all"
5112 hint = _("uncommitted changes, use --all to discard all"
5114 " changes, or 'hg update %d' to update") % ctx.rev()
5113 " changes, or 'hg update %d' to update") % ctx.rev()
5115 else:
5114 else:
5116 hint = _("use --all to revert all files,"
5115 hint = _("use --all to revert all files,"
5117 " or 'hg update %d' to update") % ctx.rev()
5116 " or 'hg update %d' to update") % ctx.rev()
5118 elif dirty:
5117 elif dirty:
5119 hint = _("uncommitted changes, use --all to discard all changes")
5118 hint = _("uncommitted changes, use --all to discard all changes")
5120 else:
5119 else:
5121 hint = _("use --all to revert all files")
5120 hint = _("use --all to revert all files")
5122 raise error.Abort(msg, hint=hint)
5121 raise error.Abort(msg, hint=hint)
5123
5122
5124 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5123 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5125 **pycompat.strkwargs(opts))
5124 **pycompat.strkwargs(opts))
5126
5125
5127 @command(
5126 @command(
5128 'rollback',
5127 'rollback',
5129 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5128 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5130 helpcategory=command.CATEGORY_MAINTENANCE)
5129 helpcategory=command.CATEGORY_MAINTENANCE)
5131 def rollback(ui, repo, **opts):
5130 def rollback(ui, repo, **opts):
5132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5131 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5133
5132
5134 Please use :hg:`commit --amend` instead of rollback to correct
5133 Please use :hg:`commit --amend` instead of rollback to correct
5135 mistakes in the last commit.
5134 mistakes in the last commit.
5136
5135
5137 This command should be used with care. There is only one level of
5136 This command should be used with care. There is only one level of
5138 rollback, and there is no way to undo a rollback. It will also
5137 rollback, and there is no way to undo a rollback. It will also
5139 restore the dirstate at the time of the last transaction, losing
5138 restore the dirstate at the time of the last transaction, losing
5140 any dirstate changes since that time. This command does not alter
5139 any dirstate changes since that time. This command does not alter
5141 the working directory.
5140 the working directory.
5142
5141
5143 Transactions are used to encapsulate the effects of all commands
5142 Transactions are used to encapsulate the effects of all commands
5144 that create new changesets or propagate existing changesets into a
5143 that create new changesets or propagate existing changesets into a
5145 repository.
5144 repository.
5146
5145
5147 .. container:: verbose
5146 .. container:: verbose
5148
5147
5149 For example, the following commands are transactional, and their
5148 For example, the following commands are transactional, and their
5150 effects can be rolled back:
5149 effects can be rolled back:
5151
5150
5152 - commit
5151 - commit
5153 - import
5152 - import
5154 - pull
5153 - pull
5155 - push (with this repository as the destination)
5154 - push (with this repository as the destination)
5156 - unbundle
5155 - unbundle
5157
5156
5158 To avoid permanent data loss, rollback will refuse to rollback a
5157 To avoid permanent data loss, rollback will refuse to rollback a
5159 commit transaction if it isn't checked out. Use --force to
5158 commit transaction if it isn't checked out. Use --force to
5160 override this protection.
5159 override this protection.
5161
5160
5162 The rollback command can be entirely disabled by setting the
5161 The rollback command can be entirely disabled by setting the
5163 ``ui.rollback`` configuration setting to false. If you're here
5162 ``ui.rollback`` configuration setting to false. If you're here
5164 because you want to use rollback and it's disabled, you can
5163 because you want to use rollback and it's disabled, you can
5165 re-enable the command by setting ``ui.rollback`` to true.
5164 re-enable the command by setting ``ui.rollback`` to true.
5166
5165
5167 This command is not intended for use on public repositories. Once
5166 This command is not intended for use on public repositories. Once
5168 changes are visible for pull by other users, rolling a transaction
5167 changes are visible for pull by other users, rolling a transaction
5169 back locally is ineffective (someone else may already have pulled
5168 back locally is ineffective (someone else may already have pulled
5170 the changes). Furthermore, a race is possible with readers of the
5169 the changes). Furthermore, a race is possible with readers of the
5171 repository; for example an in-progress pull from the repository
5170 repository; for example an in-progress pull from the repository
5172 may fail if a rollback is performed.
5171 may fail if a rollback is performed.
5173
5172
5174 Returns 0 on success, 1 if no rollback data is available.
5173 Returns 0 on success, 1 if no rollback data is available.
5175 """
5174 """
5176 if not ui.configbool('ui', 'rollback'):
5175 if not ui.configbool('ui', 'rollback'):
5177 raise error.Abort(_('rollback is disabled because it is unsafe'),
5176 raise error.Abort(_('rollback is disabled because it is unsafe'),
5178 hint=('see `hg help -v rollback` for information'))
5177 hint=('see `hg help -v rollback` for information'))
5179 return repo.rollback(dryrun=opts.get(r'dry_run'),
5178 return repo.rollback(dryrun=opts.get(r'dry_run'),
5180 force=opts.get(r'force'))
5179 force=opts.get(r'force'))
5181
5180
5182 @command(
5181 @command(
5183 'root', [], intents={INTENT_READONLY},
5182 'root', [], intents={INTENT_READONLY},
5184 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5183 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5185 def root(ui, repo):
5184 def root(ui, repo):
5186 """print the root (top) of the current working directory
5185 """print the root (top) of the current working directory
5187
5186
5188 Print the root directory of the current repository.
5187 Print the root directory of the current repository.
5189
5188
5190 Returns 0 on success.
5189 Returns 0 on success.
5191 """
5190 """
5192 ui.write(repo.root + "\n")
5191 ui.write(repo.root + "\n")
5193
5192
5194 @command('serve',
5193 @command('serve',
5195 [('A', 'accesslog', '', _('name of access log file to write to'),
5194 [('A', 'accesslog', '', _('name of access log file to write to'),
5196 _('FILE')),
5195 _('FILE')),
5197 ('d', 'daemon', None, _('run server in background')),
5196 ('d', 'daemon', None, _('run server in background')),
5198 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5197 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5199 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5198 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5200 # use string type, then we can check if something was passed
5199 # use string type, then we can check if something was passed
5201 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5200 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5202 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5201 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5203 _('ADDR')),
5202 _('ADDR')),
5204 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5203 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5205 _('PREFIX')),
5204 _('PREFIX')),
5206 ('n', 'name', '',
5205 ('n', 'name', '',
5207 _('name to show in web pages (default: working directory)'), _('NAME')),
5206 _('name to show in web pages (default: working directory)'), _('NAME')),
5208 ('', 'web-conf', '',
5207 ('', 'web-conf', '',
5209 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5208 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5210 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5209 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5211 _('FILE')),
5210 _('FILE')),
5212 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5211 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5213 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5212 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5214 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5213 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5215 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5214 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5216 ('', 'style', '', _('template style to use'), _('STYLE')),
5215 ('', 'style', '', _('template style to use'), _('STYLE')),
5217 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5216 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5218 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5217 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5219 ('', 'print-url', None, _('start and print only the URL'))]
5218 ('', 'print-url', None, _('start and print only the URL'))]
5220 + subrepoopts,
5219 + subrepoopts,
5221 _('[OPTION]...'),
5220 _('[OPTION]...'),
5222 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5221 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5223 helpbasic=True, optionalrepo=True)
5222 helpbasic=True, optionalrepo=True)
5224 def serve(ui, repo, **opts):
5223 def serve(ui, repo, **opts):
5225 """start stand-alone webserver
5224 """start stand-alone webserver
5226
5225
5227 Start a local HTTP repository browser and pull server. You can use
5226 Start a local HTTP repository browser and pull server. You can use
5228 this for ad-hoc sharing and browsing of repositories. It is
5227 this for ad-hoc sharing and browsing of repositories. It is
5229 recommended to use a real web server to serve a repository for
5228 recommended to use a real web server to serve a repository for
5230 longer periods of time.
5229 longer periods of time.
5231
5230
5232 Please note that the server does not implement access control.
5231 Please note that the server does not implement access control.
5233 This means that, by default, anybody can read from the server and
5232 This means that, by default, anybody can read from the server and
5234 nobody can write to it by default. Set the ``web.allow-push``
5233 nobody can write to it by default. Set the ``web.allow-push``
5235 option to ``*`` to allow everybody to push to the server. You
5234 option to ``*`` to allow everybody to push to the server. You
5236 should use a real web server if you need to authenticate users.
5235 should use a real web server if you need to authenticate users.
5237
5236
5238 By default, the server logs accesses to stdout and errors to
5237 By default, the server logs accesses to stdout and errors to
5239 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5238 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5240 files.
5239 files.
5241
5240
5242 To have the server choose a free port number to listen on, specify
5241 To have the server choose a free port number to listen on, specify
5243 a port number of 0; in this case, the server will print the port
5242 a port number of 0; in this case, the server will print the port
5244 number it uses.
5243 number it uses.
5245
5244
5246 Returns 0 on success.
5245 Returns 0 on success.
5247 """
5246 """
5248
5247
5249 opts = pycompat.byteskwargs(opts)
5248 opts = pycompat.byteskwargs(opts)
5250 if opts["stdio"] and opts["cmdserver"]:
5249 if opts["stdio"] and opts["cmdserver"]:
5251 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5250 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5252 if opts["print_url"] and ui.verbose:
5251 if opts["print_url"] and ui.verbose:
5253 raise error.Abort(_("cannot use --print-url with --verbose"))
5252 raise error.Abort(_("cannot use --print-url with --verbose"))
5254
5253
5255 if opts["stdio"]:
5254 if opts["stdio"]:
5256 if repo is None:
5255 if repo is None:
5257 raise error.RepoError(_("there is no Mercurial repository here"
5256 raise error.RepoError(_("there is no Mercurial repository here"
5258 " (.hg not found)"))
5257 " (.hg not found)"))
5259 s = wireprotoserver.sshserver(ui, repo)
5258 s = wireprotoserver.sshserver(ui, repo)
5260 s.serve_forever()
5259 s.serve_forever()
5261
5260
5262 service = server.createservice(ui, repo, opts)
5261 service = server.createservice(ui, repo, opts)
5263 return server.runservice(opts, initfn=service.init, runfn=service.run)
5262 return server.runservice(opts, initfn=service.init, runfn=service.run)
5264
5263
5265 _NOTTERSE = 'nothing'
5264 _NOTTERSE = 'nothing'
5266
5265
5267 @command('status|st',
5266 @command('status|st',
5268 [('A', 'all', None, _('show status of all files')),
5267 [('A', 'all', None, _('show status of all files')),
5269 ('m', 'modified', None, _('show only modified files')),
5268 ('m', 'modified', None, _('show only modified files')),
5270 ('a', 'added', None, _('show only added files')),
5269 ('a', 'added', None, _('show only added files')),
5271 ('r', 'removed', None, _('show only removed files')),
5270 ('r', 'removed', None, _('show only removed files')),
5272 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5271 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5273 ('c', 'clean', None, _('show only files without changes')),
5272 ('c', 'clean', None, _('show only files without changes')),
5274 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5273 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5275 ('i', 'ignored', None, _('show only ignored files')),
5274 ('i', 'ignored', None, _('show only ignored files')),
5276 ('n', 'no-status', None, _('hide status prefix')),
5275 ('n', 'no-status', None, _('hide status prefix')),
5277 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5276 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5278 ('C', 'copies', None, _('show source of copied files')),
5277 ('C', 'copies', None, _('show source of copied files')),
5279 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5278 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5280 ('', 'rev', [], _('show difference from revision'), _('REV')),
5279 ('', 'rev', [], _('show difference from revision'), _('REV')),
5281 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5280 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5282 ] + walkopts + subrepoopts + formatteropts,
5281 ] + walkopts + subrepoopts + formatteropts,
5283 _('[OPTION]... [FILE]...'),
5282 _('[OPTION]... [FILE]...'),
5284 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5283 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5285 helpbasic=True, inferrepo=True,
5284 helpbasic=True, inferrepo=True,
5286 intents={INTENT_READONLY})
5285 intents={INTENT_READONLY})
5287 def status(ui, repo, *pats, **opts):
5286 def status(ui, repo, *pats, **opts):
5288 """show changed files in the working directory
5287 """show changed files in the working directory
5289
5288
5290 Show status of files in the repository. If names are given, only
5289 Show status of files in the repository. If names are given, only
5291 files that match are shown. Files that are clean or ignored or
5290 files that match are shown. Files that are clean or ignored or
5292 the source of a copy/move operation, are not listed unless
5291 the source of a copy/move operation, are not listed unless
5293 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5292 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5294 Unless options described with "show only ..." are given, the
5293 Unless options described with "show only ..." are given, the
5295 options -mardu are used.
5294 options -mardu are used.
5296
5295
5297 Option -q/--quiet hides untracked (unknown and ignored) files
5296 Option -q/--quiet hides untracked (unknown and ignored) files
5298 unless explicitly requested with -u/--unknown or -i/--ignored.
5297 unless explicitly requested with -u/--unknown or -i/--ignored.
5299
5298
5300 .. note::
5299 .. note::
5301
5300
5302 :hg:`status` may appear to disagree with diff if permissions have
5301 :hg:`status` may appear to disagree with diff if permissions have
5303 changed or a merge has occurred. The standard diff format does
5302 changed or a merge has occurred. The standard diff format does
5304 not report permission changes and diff only reports changes
5303 not report permission changes and diff only reports changes
5305 relative to one merge parent.
5304 relative to one merge parent.
5306
5305
5307 If one revision is given, it is used as the base revision.
5306 If one revision is given, it is used as the base revision.
5308 If two revisions are given, the differences between them are
5307 If two revisions are given, the differences between them are
5309 shown. The --change option can also be used as a shortcut to list
5308 shown. The --change option can also be used as a shortcut to list
5310 the changed files of a revision from its first parent.
5309 the changed files of a revision from its first parent.
5311
5310
5312 The codes used to show the status of files are::
5311 The codes used to show the status of files are::
5313
5312
5314 M = modified
5313 M = modified
5315 A = added
5314 A = added
5316 R = removed
5315 R = removed
5317 C = clean
5316 C = clean
5318 ! = missing (deleted by non-hg command, but still tracked)
5317 ! = missing (deleted by non-hg command, but still tracked)
5319 ? = not tracked
5318 ? = not tracked
5320 I = ignored
5319 I = ignored
5321 = origin of the previous file (with --copies)
5320 = origin of the previous file (with --copies)
5322
5321
5323 .. container:: verbose
5322 .. container:: verbose
5324
5323
5325 The -t/--terse option abbreviates the output by showing only the directory
5324 The -t/--terse option abbreviates the output by showing only the directory
5326 name if all the files in it share the same status. The option takes an
5325 name if all the files in it share the same status. The option takes an
5327 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5326 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5328 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5327 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5329 for 'ignored' and 'c' for clean.
5328 for 'ignored' and 'c' for clean.
5330
5329
5331 It abbreviates only those statuses which are passed. Note that clean and
5330 It abbreviates only those statuses which are passed. Note that clean and
5332 ignored files are not displayed with '--terse ic' unless the -c/--clean
5331 ignored files are not displayed with '--terse ic' unless the -c/--clean
5333 and -i/--ignored options are also used.
5332 and -i/--ignored options are also used.
5334
5333
5335 The -v/--verbose option shows information when the repository is in an
5334 The -v/--verbose option shows information when the repository is in an
5336 unfinished merge, shelve, rebase state etc. You can have this behavior
5335 unfinished merge, shelve, rebase state etc. You can have this behavior
5337 turned on by default by enabling the ``commands.status.verbose`` option.
5336 turned on by default by enabling the ``commands.status.verbose`` option.
5338
5337
5339 You can skip displaying some of these states by setting
5338 You can skip displaying some of these states by setting
5340 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5339 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5341 'histedit', 'merge', 'rebase', or 'unshelve'.
5340 'histedit', 'merge', 'rebase', or 'unshelve'.
5342
5341
5343 Template:
5342 Template:
5344
5343
5345 The following keywords are supported in addition to the common template
5344 The following keywords are supported in addition to the common template
5346 keywords and functions. See also :hg:`help templates`.
5345 keywords and functions. See also :hg:`help templates`.
5347
5346
5348 :path: String. Repository-absolute path of the file.
5347 :path: String. Repository-absolute path of the file.
5349 :source: String. Repository-absolute path of the file originated from.
5348 :source: String. Repository-absolute path of the file originated from.
5350 Available if ``--copies`` is specified.
5349 Available if ``--copies`` is specified.
5351 :status: String. Character denoting file's status.
5350 :status: String. Character denoting file's status.
5352
5351
5353 Examples:
5352 Examples:
5354
5353
5355 - show changes in the working directory relative to a
5354 - show changes in the working directory relative to a
5356 changeset::
5355 changeset::
5357
5356
5358 hg status --rev 9353
5357 hg status --rev 9353
5359
5358
5360 - show changes in the working directory relative to the
5359 - show changes in the working directory relative to the
5361 current directory (see :hg:`help patterns` for more information)::
5360 current directory (see :hg:`help patterns` for more information)::
5362
5361
5363 hg status re:
5362 hg status re:
5364
5363
5365 - show all changes including copies in an existing changeset::
5364 - show all changes including copies in an existing changeset::
5366
5365
5367 hg status --copies --change 9353
5366 hg status --copies --change 9353
5368
5367
5369 - get a NUL separated list of added files, suitable for xargs::
5368 - get a NUL separated list of added files, suitable for xargs::
5370
5369
5371 hg status -an0
5370 hg status -an0
5372
5371
5373 - show more information about the repository status, abbreviating
5372 - show more information about the repository status, abbreviating
5374 added, removed, modified, deleted, and untracked paths::
5373 added, removed, modified, deleted, and untracked paths::
5375
5374
5376 hg status -v -t mardu
5375 hg status -v -t mardu
5377
5376
5378 Returns 0 on success.
5377 Returns 0 on success.
5379
5378
5380 """
5379 """
5381
5380
5382 opts = pycompat.byteskwargs(opts)
5381 opts = pycompat.byteskwargs(opts)
5383 revs = opts.get('rev')
5382 revs = opts.get('rev')
5384 change = opts.get('change')
5383 change = opts.get('change')
5385 terse = opts.get('terse')
5384 terse = opts.get('terse')
5386 if terse is _NOTTERSE:
5385 if terse is _NOTTERSE:
5387 if revs:
5386 if revs:
5388 terse = ''
5387 terse = ''
5389 else:
5388 else:
5390 terse = ui.config('commands', 'status.terse')
5389 terse = ui.config('commands', 'status.terse')
5391
5390
5392 if revs and change:
5391 if revs and change:
5393 msg = _('cannot specify --rev and --change at the same time')
5392 msg = _('cannot specify --rev and --change at the same time')
5394 raise error.Abort(msg)
5393 raise error.Abort(msg)
5395 elif revs and terse:
5394 elif revs and terse:
5396 msg = _('cannot use --terse with --rev')
5395 msg = _('cannot use --terse with --rev')
5397 raise error.Abort(msg)
5396 raise error.Abort(msg)
5398 elif change:
5397 elif change:
5399 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5398 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5400 ctx2 = scmutil.revsingle(repo, change, None)
5399 ctx2 = scmutil.revsingle(repo, change, None)
5401 ctx1 = ctx2.p1()
5400 ctx1 = ctx2.p1()
5402 else:
5401 else:
5403 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5402 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5404 ctx1, ctx2 = scmutil.revpair(repo, revs)
5403 ctx1, ctx2 = scmutil.revpair(repo, revs)
5405
5404
5406 if pats or ui.configbool('commands', 'status.relative'):
5405 if pats or ui.configbool('commands', 'status.relative'):
5407 cwd = repo.getcwd()
5406 cwd = repo.getcwd()
5408 else:
5407 else:
5409 cwd = ''
5408 cwd = ''
5410
5409
5411 if opts.get('print0'):
5410 if opts.get('print0'):
5412 end = '\0'
5411 end = '\0'
5413 else:
5412 else:
5414 end = '\n'
5413 end = '\n'
5415 copy = {}
5414 copy = {}
5416 states = 'modified added removed deleted unknown ignored clean'.split()
5415 states = 'modified added removed deleted unknown ignored clean'.split()
5417 show = [k for k in states if opts.get(k)]
5416 show = [k for k in states if opts.get(k)]
5418 if opts.get('all'):
5417 if opts.get('all'):
5419 show += ui.quiet and (states[:4] + ['clean']) or states
5418 show += ui.quiet and (states[:4] + ['clean']) or states
5420
5419
5421 if not show:
5420 if not show:
5422 if ui.quiet:
5421 if ui.quiet:
5423 show = states[:4]
5422 show = states[:4]
5424 else:
5423 else:
5425 show = states[:5]
5424 show = states[:5]
5426
5425
5427 m = scmutil.match(ctx2, pats, opts)
5426 m = scmutil.match(ctx2, pats, opts)
5428 if terse:
5427 if terse:
5429 # we need to compute clean and unknown to terse
5428 # we need to compute clean and unknown to terse
5430 stat = repo.status(ctx1.node(), ctx2.node(), m,
5429 stat = repo.status(ctx1.node(), ctx2.node(), m,
5431 'ignored' in show or 'i' in terse,
5430 'ignored' in show or 'i' in terse,
5432 clean=True, unknown=True,
5431 clean=True, unknown=True,
5433 listsubrepos=opts.get('subrepos'))
5432 listsubrepos=opts.get('subrepos'))
5434
5433
5435 stat = cmdutil.tersedir(stat, terse)
5434 stat = cmdutil.tersedir(stat, terse)
5436 else:
5435 else:
5437 stat = repo.status(ctx1.node(), ctx2.node(), m,
5436 stat = repo.status(ctx1.node(), ctx2.node(), m,
5438 'ignored' in show, 'clean' in show,
5437 'ignored' in show, 'clean' in show,
5439 'unknown' in show, opts.get('subrepos'))
5438 'unknown' in show, opts.get('subrepos'))
5440
5439
5441 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5440 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5442
5441
5443 if (opts.get('all') or opts.get('copies')
5442 if (opts.get('all') or opts.get('copies')
5444 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5443 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5445 copy = copies.pathcopies(ctx1, ctx2, m)
5444 copy = copies.pathcopies(ctx1, ctx2, m)
5446
5445
5447 ui.pager('status')
5446 ui.pager('status')
5448 fm = ui.formatter('status', opts)
5447 fm = ui.formatter('status', opts)
5449 fmt = '%s' + end
5448 fmt = '%s' + end
5450 showchar = not opts.get('no_status')
5449 showchar = not opts.get('no_status')
5451
5450
5452 for state, char, files in changestates:
5451 for state, char, files in changestates:
5453 if state in show:
5452 if state in show:
5454 label = 'status.' + state
5453 label = 'status.' + state
5455 for f in files:
5454 for f in files:
5456 fm.startitem()
5455 fm.startitem()
5457 fm.context(ctx=ctx2)
5456 fm.context(ctx=ctx2)
5458 fm.data(path=f)
5457 fm.data(path=f)
5459 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5458 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5460 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5459 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5461 if f in copy:
5460 if f in copy:
5462 fm.data(source=copy[f])
5461 fm.data(source=copy[f])
5463 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5462 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5464 label='status.copied')
5463 label='status.copied')
5465
5464
5466 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5465 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5467 and not ui.plain()):
5466 and not ui.plain()):
5468 cmdutil.morestatus(repo, fm)
5467 cmdutil.morestatus(repo, fm)
5469 fm.end()
5468 fm.end()
5470
5469
5471 @command('summary|sum',
5470 @command('summary|sum',
5472 [('', 'remote', None, _('check for push and pull'))],
5471 [('', 'remote', None, _('check for push and pull'))],
5473 '[--remote]',
5472 '[--remote]',
5474 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5473 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5475 helpbasic=True,
5474 helpbasic=True,
5476 intents={INTENT_READONLY})
5475 intents={INTENT_READONLY})
5477 def summary(ui, repo, **opts):
5476 def summary(ui, repo, **opts):
5478 """summarize working directory state
5477 """summarize working directory state
5479
5478
5480 This generates a brief summary of the working directory state,
5479 This generates a brief summary of the working directory state,
5481 including parents, branch, commit status, phase and available updates.
5480 including parents, branch, commit status, phase and available updates.
5482
5481
5483 With the --remote option, this will check the default paths for
5482 With the --remote option, this will check the default paths for
5484 incoming and outgoing changes. This can be time-consuming.
5483 incoming and outgoing changes. This can be time-consuming.
5485
5484
5486 Returns 0 on success.
5485 Returns 0 on success.
5487 """
5486 """
5488
5487
5489 opts = pycompat.byteskwargs(opts)
5488 opts = pycompat.byteskwargs(opts)
5490 ui.pager('summary')
5489 ui.pager('summary')
5491 ctx = repo[None]
5490 ctx = repo[None]
5492 parents = ctx.parents()
5491 parents = ctx.parents()
5493 pnode = parents[0].node()
5492 pnode = parents[0].node()
5494 marks = []
5493 marks = []
5495
5494
5496 ms = None
5495 ms = None
5497 try:
5496 try:
5498 ms = mergemod.mergestate.read(repo)
5497 ms = mergemod.mergestate.read(repo)
5499 except error.UnsupportedMergeRecords as e:
5498 except error.UnsupportedMergeRecords as e:
5500 s = ' '.join(e.recordtypes)
5499 s = ' '.join(e.recordtypes)
5501 ui.warn(
5500 ui.warn(
5502 _('warning: merge state has unsupported record types: %s\n') % s)
5501 _('warning: merge state has unsupported record types: %s\n') % s)
5503 unresolved = []
5502 unresolved = []
5504 else:
5503 else:
5505 unresolved = list(ms.unresolved())
5504 unresolved = list(ms.unresolved())
5506
5505
5507 for p in parents:
5506 for p in parents:
5508 # label with log.changeset (instead of log.parent) since this
5507 # label with log.changeset (instead of log.parent) since this
5509 # shows a working directory parent *changeset*:
5508 # shows a working directory parent *changeset*:
5510 # i18n: column positioning for "hg summary"
5509 # i18n: column positioning for "hg summary"
5511 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5510 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5512 label=logcmdutil.changesetlabels(p))
5511 label=logcmdutil.changesetlabels(p))
5513 ui.write(' '.join(p.tags()), label='log.tag')
5512 ui.write(' '.join(p.tags()), label='log.tag')
5514 if p.bookmarks():
5513 if p.bookmarks():
5515 marks.extend(p.bookmarks())
5514 marks.extend(p.bookmarks())
5516 if p.rev() == -1:
5515 if p.rev() == -1:
5517 if not len(repo):
5516 if not len(repo):
5518 ui.write(_(' (empty repository)'))
5517 ui.write(_(' (empty repository)'))
5519 else:
5518 else:
5520 ui.write(_(' (no revision checked out)'))
5519 ui.write(_(' (no revision checked out)'))
5521 if p.obsolete():
5520 if p.obsolete():
5522 ui.write(_(' (obsolete)'))
5521 ui.write(_(' (obsolete)'))
5523 if p.isunstable():
5522 if p.isunstable():
5524 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5523 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5525 for instability in p.instabilities())
5524 for instability in p.instabilities())
5526 ui.write(' ('
5525 ui.write(' ('
5527 + ', '.join(instabilities)
5526 + ', '.join(instabilities)
5528 + ')')
5527 + ')')
5529 ui.write('\n')
5528 ui.write('\n')
5530 if p.description():
5529 if p.description():
5531 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5530 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5532 label='log.summary')
5531 label='log.summary')
5533
5532
5534 branch = ctx.branch()
5533 branch = ctx.branch()
5535 bheads = repo.branchheads(branch)
5534 bheads = repo.branchheads(branch)
5536 # i18n: column positioning for "hg summary"
5535 # i18n: column positioning for "hg summary"
5537 m = _('branch: %s\n') % branch
5536 m = _('branch: %s\n') % branch
5538 if branch != 'default':
5537 if branch != 'default':
5539 ui.write(m, label='log.branch')
5538 ui.write(m, label='log.branch')
5540 else:
5539 else:
5541 ui.status(m, label='log.branch')
5540 ui.status(m, label='log.branch')
5542
5541
5543 if marks:
5542 if marks:
5544 active = repo._activebookmark
5543 active = repo._activebookmark
5545 # i18n: column positioning for "hg summary"
5544 # i18n: column positioning for "hg summary"
5546 ui.write(_('bookmarks:'), label='log.bookmark')
5545 ui.write(_('bookmarks:'), label='log.bookmark')
5547 if active is not None:
5546 if active is not None:
5548 if active in marks:
5547 if active in marks:
5549 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5548 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5550 marks.remove(active)
5549 marks.remove(active)
5551 else:
5550 else:
5552 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5551 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5553 for m in marks:
5552 for m in marks:
5554 ui.write(' ' + m, label='log.bookmark')
5553 ui.write(' ' + m, label='log.bookmark')
5555 ui.write('\n', label='log.bookmark')
5554 ui.write('\n', label='log.bookmark')
5556
5555
5557 status = repo.status(unknown=True)
5556 status = repo.status(unknown=True)
5558
5557
5559 c = repo.dirstate.copies()
5558 c = repo.dirstate.copies()
5560 copied, renamed = [], []
5559 copied, renamed = [], []
5561 for d, s in c.iteritems():
5560 for d, s in c.iteritems():
5562 if s in status.removed:
5561 if s in status.removed:
5563 status.removed.remove(s)
5562 status.removed.remove(s)
5564 renamed.append(d)
5563 renamed.append(d)
5565 else:
5564 else:
5566 copied.append(d)
5565 copied.append(d)
5567 if d in status.added:
5566 if d in status.added:
5568 status.added.remove(d)
5567 status.added.remove(d)
5569
5568
5570 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5569 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5571
5570
5572 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5571 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5573 (ui.label(_('%d added'), 'status.added'), status.added),
5572 (ui.label(_('%d added'), 'status.added'), status.added),
5574 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5573 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5575 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5574 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5576 (ui.label(_('%d copied'), 'status.copied'), copied),
5575 (ui.label(_('%d copied'), 'status.copied'), copied),
5577 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5576 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5578 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5577 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5579 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5578 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5580 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5579 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5581 t = []
5580 t = []
5582 for l, s in labels:
5581 for l, s in labels:
5583 if s:
5582 if s:
5584 t.append(l % len(s))
5583 t.append(l % len(s))
5585
5584
5586 t = ', '.join(t)
5585 t = ', '.join(t)
5587 cleanworkdir = False
5586 cleanworkdir = False
5588
5587
5589 if repo.vfs.exists('graftstate'):
5588 if repo.vfs.exists('graftstate'):
5590 t += _(' (graft in progress)')
5589 t += _(' (graft in progress)')
5591 if repo.vfs.exists('updatestate'):
5590 if repo.vfs.exists('updatestate'):
5592 t += _(' (interrupted update)')
5591 t += _(' (interrupted update)')
5593 elif len(parents) > 1:
5592 elif len(parents) > 1:
5594 t += _(' (merge)')
5593 t += _(' (merge)')
5595 elif branch != parents[0].branch():
5594 elif branch != parents[0].branch():
5596 t += _(' (new branch)')
5595 t += _(' (new branch)')
5597 elif (parents[0].closesbranch() and
5596 elif (parents[0].closesbranch() and
5598 pnode in repo.branchheads(branch, closed=True)):
5597 pnode in repo.branchheads(branch, closed=True)):
5599 t += _(' (head closed)')
5598 t += _(' (head closed)')
5600 elif not (status.modified or status.added or status.removed or renamed or
5599 elif not (status.modified or status.added or status.removed or renamed or
5601 copied or subs):
5600 copied or subs):
5602 t += _(' (clean)')
5601 t += _(' (clean)')
5603 cleanworkdir = True
5602 cleanworkdir = True
5604 elif pnode not in bheads:
5603 elif pnode not in bheads:
5605 t += _(' (new branch head)')
5604 t += _(' (new branch head)')
5606
5605
5607 if parents:
5606 if parents:
5608 pendingphase = max(p.phase() for p in parents)
5607 pendingphase = max(p.phase() for p in parents)
5609 else:
5608 else:
5610 pendingphase = phases.public
5609 pendingphase = phases.public
5611
5610
5612 if pendingphase > phases.newcommitphase(ui):
5611 if pendingphase > phases.newcommitphase(ui):
5613 t += ' (%s)' % phases.phasenames[pendingphase]
5612 t += ' (%s)' % phases.phasenames[pendingphase]
5614
5613
5615 if cleanworkdir:
5614 if cleanworkdir:
5616 # i18n: column positioning for "hg summary"
5615 # i18n: column positioning for "hg summary"
5617 ui.status(_('commit: %s\n') % t.strip())
5616 ui.status(_('commit: %s\n') % t.strip())
5618 else:
5617 else:
5619 # i18n: column positioning for "hg summary"
5618 # i18n: column positioning for "hg summary"
5620 ui.write(_('commit: %s\n') % t.strip())
5619 ui.write(_('commit: %s\n') % t.strip())
5621
5620
5622 # all ancestors of branch heads - all ancestors of parent = new csets
5621 # all ancestors of branch heads - all ancestors of parent = new csets
5623 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5622 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5624 bheads))
5623 bheads))
5625
5624
5626 if new == 0:
5625 if new == 0:
5627 # i18n: column positioning for "hg summary"
5626 # i18n: column positioning for "hg summary"
5628 ui.status(_('update: (current)\n'))
5627 ui.status(_('update: (current)\n'))
5629 elif pnode not in bheads:
5628 elif pnode not in bheads:
5630 # i18n: column positioning for "hg summary"
5629 # i18n: column positioning for "hg summary"
5631 ui.write(_('update: %d new changesets (update)\n') % new)
5630 ui.write(_('update: %d new changesets (update)\n') % new)
5632 else:
5631 else:
5633 # i18n: column positioning for "hg summary"
5632 # i18n: column positioning for "hg summary"
5634 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5633 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5635 (new, len(bheads)))
5634 (new, len(bheads)))
5636
5635
5637 t = []
5636 t = []
5638 draft = len(repo.revs('draft()'))
5637 draft = len(repo.revs('draft()'))
5639 if draft:
5638 if draft:
5640 t.append(_('%d draft') % draft)
5639 t.append(_('%d draft') % draft)
5641 secret = len(repo.revs('secret()'))
5640 secret = len(repo.revs('secret()'))
5642 if secret:
5641 if secret:
5643 t.append(_('%d secret') % secret)
5642 t.append(_('%d secret') % secret)
5644
5643
5645 if draft or secret:
5644 if draft or secret:
5646 ui.status(_('phases: %s\n') % ', '.join(t))
5645 ui.status(_('phases: %s\n') % ', '.join(t))
5647
5646
5648 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5647 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5649 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5648 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5650 numtrouble = len(repo.revs(trouble + "()"))
5649 numtrouble = len(repo.revs(trouble + "()"))
5651 # We write all the possibilities to ease translation
5650 # We write all the possibilities to ease translation
5652 troublemsg = {
5651 troublemsg = {
5653 "orphan": _("orphan: %d changesets"),
5652 "orphan": _("orphan: %d changesets"),
5654 "contentdivergent": _("content-divergent: %d changesets"),
5653 "contentdivergent": _("content-divergent: %d changesets"),
5655 "phasedivergent": _("phase-divergent: %d changesets"),
5654 "phasedivergent": _("phase-divergent: %d changesets"),
5656 }
5655 }
5657 if numtrouble > 0:
5656 if numtrouble > 0:
5658 ui.status(troublemsg[trouble] % numtrouble + "\n")
5657 ui.status(troublemsg[trouble] % numtrouble + "\n")
5659
5658
5660 cmdutil.summaryhooks(ui, repo)
5659 cmdutil.summaryhooks(ui, repo)
5661
5660
5662 if opts.get('remote'):
5661 if opts.get('remote'):
5663 needsincoming, needsoutgoing = True, True
5662 needsincoming, needsoutgoing = True, True
5664 else:
5663 else:
5665 needsincoming, needsoutgoing = False, False
5664 needsincoming, needsoutgoing = False, False
5666 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5665 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5667 if i:
5666 if i:
5668 needsincoming = True
5667 needsincoming = True
5669 if o:
5668 if o:
5670 needsoutgoing = True
5669 needsoutgoing = True
5671 if not needsincoming and not needsoutgoing:
5670 if not needsincoming and not needsoutgoing:
5672 return
5671 return
5673
5672
5674 def getincoming():
5673 def getincoming():
5675 source, branches = hg.parseurl(ui.expandpath('default'))
5674 source, branches = hg.parseurl(ui.expandpath('default'))
5676 sbranch = branches[0]
5675 sbranch = branches[0]
5677 try:
5676 try:
5678 other = hg.peer(repo, {}, source)
5677 other = hg.peer(repo, {}, source)
5679 except error.RepoError:
5678 except error.RepoError:
5680 if opts.get('remote'):
5679 if opts.get('remote'):
5681 raise
5680 raise
5682 return source, sbranch, None, None, None
5681 return source, sbranch, None, None, None
5683 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5682 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5684 if revs:
5683 if revs:
5685 revs = [other.lookup(rev) for rev in revs]
5684 revs = [other.lookup(rev) for rev in revs]
5686 ui.debug('comparing with %s\n' % util.hidepassword(source))
5685 ui.debug('comparing with %s\n' % util.hidepassword(source))
5687 repo.ui.pushbuffer()
5686 repo.ui.pushbuffer()
5688 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5687 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5689 repo.ui.popbuffer()
5688 repo.ui.popbuffer()
5690 return source, sbranch, other, commoninc, commoninc[1]
5689 return source, sbranch, other, commoninc, commoninc[1]
5691
5690
5692 if needsincoming:
5691 if needsincoming:
5693 source, sbranch, sother, commoninc, incoming = getincoming()
5692 source, sbranch, sother, commoninc, incoming = getincoming()
5694 else:
5693 else:
5695 source = sbranch = sother = commoninc = incoming = None
5694 source = sbranch = sother = commoninc = incoming = None
5696
5695
5697 def getoutgoing():
5696 def getoutgoing():
5698 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5697 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5699 dbranch = branches[0]
5698 dbranch = branches[0]
5700 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5699 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5701 if source != dest:
5700 if source != dest:
5702 try:
5701 try:
5703 dother = hg.peer(repo, {}, dest)
5702 dother = hg.peer(repo, {}, dest)
5704 except error.RepoError:
5703 except error.RepoError:
5705 if opts.get('remote'):
5704 if opts.get('remote'):
5706 raise
5705 raise
5707 return dest, dbranch, None, None
5706 return dest, dbranch, None, None
5708 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5707 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5709 elif sother is None:
5708 elif sother is None:
5710 # there is no explicit destination peer, but source one is invalid
5709 # there is no explicit destination peer, but source one is invalid
5711 return dest, dbranch, None, None
5710 return dest, dbranch, None, None
5712 else:
5711 else:
5713 dother = sother
5712 dother = sother
5714 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5713 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5715 common = None
5714 common = None
5716 else:
5715 else:
5717 common = commoninc
5716 common = commoninc
5718 if revs:
5717 if revs:
5719 revs = [repo.lookup(rev) for rev in revs]
5718 revs = [repo.lookup(rev) for rev in revs]
5720 repo.ui.pushbuffer()
5719 repo.ui.pushbuffer()
5721 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5720 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5722 commoninc=common)
5721 commoninc=common)
5723 repo.ui.popbuffer()
5722 repo.ui.popbuffer()
5724 return dest, dbranch, dother, outgoing
5723 return dest, dbranch, dother, outgoing
5725
5724
5726 if needsoutgoing:
5725 if needsoutgoing:
5727 dest, dbranch, dother, outgoing = getoutgoing()
5726 dest, dbranch, dother, outgoing = getoutgoing()
5728 else:
5727 else:
5729 dest = dbranch = dother = outgoing = None
5728 dest = dbranch = dother = outgoing = None
5730
5729
5731 if opts.get('remote'):
5730 if opts.get('remote'):
5732 t = []
5731 t = []
5733 if incoming:
5732 if incoming:
5734 t.append(_('1 or more incoming'))
5733 t.append(_('1 or more incoming'))
5735 o = outgoing.missing
5734 o = outgoing.missing
5736 if o:
5735 if o:
5737 t.append(_('%d outgoing') % len(o))
5736 t.append(_('%d outgoing') % len(o))
5738 other = dother or sother
5737 other = dother or sother
5739 if 'bookmarks' in other.listkeys('namespaces'):
5738 if 'bookmarks' in other.listkeys('namespaces'):
5740 counts = bookmarks.summary(repo, other)
5739 counts = bookmarks.summary(repo, other)
5741 if counts[0] > 0:
5740 if counts[0] > 0:
5742 t.append(_('%d incoming bookmarks') % counts[0])
5741 t.append(_('%d incoming bookmarks') % counts[0])
5743 if counts[1] > 0:
5742 if counts[1] > 0:
5744 t.append(_('%d outgoing bookmarks') % counts[1])
5743 t.append(_('%d outgoing bookmarks') % counts[1])
5745
5744
5746 if t:
5745 if t:
5747 # i18n: column positioning for "hg summary"
5746 # i18n: column positioning for "hg summary"
5748 ui.write(_('remote: %s\n') % (', '.join(t)))
5747 ui.write(_('remote: %s\n') % (', '.join(t)))
5749 else:
5748 else:
5750 # i18n: column positioning for "hg summary"
5749 # i18n: column positioning for "hg summary"
5751 ui.status(_('remote: (synced)\n'))
5750 ui.status(_('remote: (synced)\n'))
5752
5751
5753 cmdutil.summaryremotehooks(ui, repo, opts,
5752 cmdutil.summaryremotehooks(ui, repo, opts,
5754 ((source, sbranch, sother, commoninc),
5753 ((source, sbranch, sother, commoninc),
5755 (dest, dbranch, dother, outgoing)))
5754 (dest, dbranch, dother, outgoing)))
5756
5755
5757 @command('tag',
5756 @command('tag',
5758 [('f', 'force', None, _('force tag')),
5757 [('f', 'force', None, _('force tag')),
5759 ('l', 'local', None, _('make the tag local')),
5758 ('l', 'local', None, _('make the tag local')),
5760 ('r', 'rev', '', _('revision to tag'), _('REV')),
5759 ('r', 'rev', '', _('revision to tag'), _('REV')),
5761 ('', 'remove', None, _('remove a tag')),
5760 ('', 'remove', None, _('remove a tag')),
5762 # -l/--local is already there, commitopts cannot be used
5761 # -l/--local is already there, commitopts cannot be used
5763 ('e', 'edit', None, _('invoke editor on commit messages')),
5762 ('e', 'edit', None, _('invoke editor on commit messages')),
5764 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5763 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5765 ] + commitopts2,
5764 ] + commitopts2,
5766 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5765 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5767 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5766 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5768 def tag(ui, repo, name1, *names, **opts):
5767 def tag(ui, repo, name1, *names, **opts):
5769 """add one or more tags for the current or given revision
5768 """add one or more tags for the current or given revision
5770
5769
5771 Name a particular revision using <name>.
5770 Name a particular revision using <name>.
5772
5771
5773 Tags are used to name particular revisions of the repository and are
5772 Tags are used to name particular revisions of the repository and are
5774 very useful to compare different revisions, to go back to significant
5773 very useful to compare different revisions, to go back to significant
5775 earlier versions or to mark branch points as releases, etc. Changing
5774 earlier versions or to mark branch points as releases, etc. Changing
5776 an existing tag is normally disallowed; use -f/--force to override.
5775 an existing tag is normally disallowed; use -f/--force to override.
5777
5776
5778 If no revision is given, the parent of the working directory is
5777 If no revision is given, the parent of the working directory is
5779 used.
5778 used.
5780
5779
5781 To facilitate version control, distribution, and merging of tags,
5780 To facilitate version control, distribution, and merging of tags,
5782 they are stored as a file named ".hgtags" which is managed similarly
5781 they are stored as a file named ".hgtags" which is managed similarly
5783 to other project files and can be hand-edited if necessary. This
5782 to other project files and can be hand-edited if necessary. This
5784 also means that tagging creates a new commit. The file
5783 also means that tagging creates a new commit. The file
5785 ".hg/localtags" is used for local tags (not shared among
5784 ".hg/localtags" is used for local tags (not shared among
5786 repositories).
5785 repositories).
5787
5786
5788 Tag commits are usually made at the head of a branch. If the parent
5787 Tag commits are usually made at the head of a branch. If the parent
5789 of the working directory is not a branch head, :hg:`tag` aborts; use
5788 of the working directory is not a branch head, :hg:`tag` aborts; use
5790 -f/--force to force the tag commit to be based on a non-head
5789 -f/--force to force the tag commit to be based on a non-head
5791 changeset.
5790 changeset.
5792
5791
5793 See :hg:`help dates` for a list of formats valid for -d/--date.
5792 See :hg:`help dates` for a list of formats valid for -d/--date.
5794
5793
5795 Since tag names have priority over branch names during revision
5794 Since tag names have priority over branch names during revision
5796 lookup, using an existing branch name as a tag name is discouraged.
5795 lookup, using an existing branch name as a tag name is discouraged.
5797
5796
5798 Returns 0 on success.
5797 Returns 0 on success.
5799 """
5798 """
5800 opts = pycompat.byteskwargs(opts)
5799 opts = pycompat.byteskwargs(opts)
5801 with repo.wlock(), repo.lock():
5800 with repo.wlock(), repo.lock():
5802 rev_ = "."
5801 rev_ = "."
5803 names = [t.strip() for t in (name1,) + names]
5802 names = [t.strip() for t in (name1,) + names]
5804 if len(names) != len(set(names)):
5803 if len(names) != len(set(names)):
5805 raise error.Abort(_('tag names must be unique'))
5804 raise error.Abort(_('tag names must be unique'))
5806 for n in names:
5805 for n in names:
5807 scmutil.checknewlabel(repo, n, 'tag')
5806 scmutil.checknewlabel(repo, n, 'tag')
5808 if not n:
5807 if not n:
5809 raise error.Abort(_('tag names cannot consist entirely of '
5808 raise error.Abort(_('tag names cannot consist entirely of '
5810 'whitespace'))
5809 'whitespace'))
5811 if opts.get('rev') and opts.get('remove'):
5810 if opts.get('rev') and opts.get('remove'):
5812 raise error.Abort(_("--rev and --remove are incompatible"))
5811 raise error.Abort(_("--rev and --remove are incompatible"))
5813 if opts.get('rev'):
5812 if opts.get('rev'):
5814 rev_ = opts['rev']
5813 rev_ = opts['rev']
5815 message = opts.get('message')
5814 message = opts.get('message')
5816 if opts.get('remove'):
5815 if opts.get('remove'):
5817 if opts.get('local'):
5816 if opts.get('local'):
5818 expectedtype = 'local'
5817 expectedtype = 'local'
5819 else:
5818 else:
5820 expectedtype = 'global'
5819 expectedtype = 'global'
5821
5820
5822 for n in names:
5821 for n in names:
5823 if not repo.tagtype(n):
5822 if not repo.tagtype(n):
5824 raise error.Abort(_("tag '%s' does not exist") % n)
5823 raise error.Abort(_("tag '%s' does not exist") % n)
5825 if repo.tagtype(n) != expectedtype:
5824 if repo.tagtype(n) != expectedtype:
5826 if expectedtype == 'global':
5825 if expectedtype == 'global':
5827 raise error.Abort(_("tag '%s' is not a global tag") % n)
5826 raise error.Abort(_("tag '%s' is not a global tag") % n)
5828 else:
5827 else:
5829 raise error.Abort(_("tag '%s' is not a local tag") % n)
5828 raise error.Abort(_("tag '%s' is not a local tag") % n)
5830 rev_ = 'null'
5829 rev_ = 'null'
5831 if not message:
5830 if not message:
5832 # we don't translate commit messages
5831 # we don't translate commit messages
5833 message = 'Removed tag %s' % ', '.join(names)
5832 message = 'Removed tag %s' % ', '.join(names)
5834 elif not opts.get('force'):
5833 elif not opts.get('force'):
5835 for n in names:
5834 for n in names:
5836 if n in repo.tags():
5835 if n in repo.tags():
5837 raise error.Abort(_("tag '%s' already exists "
5836 raise error.Abort(_("tag '%s' already exists "
5838 "(use -f to force)") % n)
5837 "(use -f to force)") % n)
5839 if not opts.get('local'):
5838 if not opts.get('local'):
5840 p1, p2 = repo.dirstate.parents()
5839 p1, p2 = repo.dirstate.parents()
5841 if p2 != nullid:
5840 if p2 != nullid:
5842 raise error.Abort(_('uncommitted merge'))
5841 raise error.Abort(_('uncommitted merge'))
5843 bheads = repo.branchheads()
5842 bheads = repo.branchheads()
5844 if not opts.get('force') and bheads and p1 not in bheads:
5843 if not opts.get('force') and bheads and p1 not in bheads:
5845 raise error.Abort(_('working directory is not at a branch head '
5844 raise error.Abort(_('working directory is not at a branch head '
5846 '(use -f to force)'))
5845 '(use -f to force)'))
5847 node = scmutil.revsingle(repo, rev_).node()
5846 node = scmutil.revsingle(repo, rev_).node()
5848
5847
5849 if not message:
5848 if not message:
5850 # we don't translate commit messages
5849 # we don't translate commit messages
5851 message = ('Added tag %s for changeset %s' %
5850 message = ('Added tag %s for changeset %s' %
5852 (', '.join(names), short(node)))
5851 (', '.join(names), short(node)))
5853
5852
5854 date = opts.get('date')
5853 date = opts.get('date')
5855 if date:
5854 if date:
5856 date = dateutil.parsedate(date)
5855 date = dateutil.parsedate(date)
5857
5856
5858 if opts.get('remove'):
5857 if opts.get('remove'):
5859 editform = 'tag.remove'
5858 editform = 'tag.remove'
5860 else:
5859 else:
5861 editform = 'tag.add'
5860 editform = 'tag.add'
5862 editor = cmdutil.getcommiteditor(editform=editform,
5861 editor = cmdutil.getcommiteditor(editform=editform,
5863 **pycompat.strkwargs(opts))
5862 **pycompat.strkwargs(opts))
5864
5863
5865 # don't allow tagging the null rev
5864 # don't allow tagging the null rev
5866 if (not opts.get('remove') and
5865 if (not opts.get('remove') and
5867 scmutil.revsingle(repo, rev_).rev() == nullrev):
5866 scmutil.revsingle(repo, rev_).rev() == nullrev):
5868 raise error.Abort(_("cannot tag null revision"))
5867 raise error.Abort(_("cannot tag null revision"))
5869
5868
5870 tagsmod.tag(repo, names, node, message, opts.get('local'),
5869 tagsmod.tag(repo, names, node, message, opts.get('local'),
5871 opts.get('user'), date, editor=editor)
5870 opts.get('user'), date, editor=editor)
5872
5871
5873 @command(
5872 @command(
5874 'tags', formatteropts, '',
5873 'tags', formatteropts, '',
5875 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5874 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5876 intents={INTENT_READONLY})
5875 intents={INTENT_READONLY})
5877 def tags(ui, repo, **opts):
5876 def tags(ui, repo, **opts):
5878 """list repository tags
5877 """list repository tags
5879
5878
5880 This lists both regular and local tags. When the -v/--verbose
5879 This lists both regular and local tags. When the -v/--verbose
5881 switch is used, a third column "local" is printed for local tags.
5880 switch is used, a third column "local" is printed for local tags.
5882 When the -q/--quiet switch is used, only the tag name is printed.
5881 When the -q/--quiet switch is used, only the tag name is printed.
5883
5882
5884 .. container:: verbose
5883 .. container:: verbose
5885
5884
5886 Template:
5885 Template:
5887
5886
5888 The following keywords are supported in addition to the common template
5887 The following keywords are supported in addition to the common template
5889 keywords and functions such as ``{tag}``. See also
5888 keywords and functions such as ``{tag}``. See also
5890 :hg:`help templates`.
5889 :hg:`help templates`.
5891
5890
5892 :type: String. ``local`` for local tags.
5891 :type: String. ``local`` for local tags.
5893
5892
5894 Returns 0 on success.
5893 Returns 0 on success.
5895 """
5894 """
5896
5895
5897 opts = pycompat.byteskwargs(opts)
5896 opts = pycompat.byteskwargs(opts)
5898 ui.pager('tags')
5897 ui.pager('tags')
5899 fm = ui.formatter('tags', opts)
5898 fm = ui.formatter('tags', opts)
5900 hexfunc = fm.hexfunc
5899 hexfunc = fm.hexfunc
5901 tagtype = ""
5900 tagtype = ""
5902
5901
5903 for t, n in reversed(repo.tagslist()):
5902 for t, n in reversed(repo.tagslist()):
5904 hn = hexfunc(n)
5903 hn = hexfunc(n)
5905 label = 'tags.normal'
5904 label = 'tags.normal'
5906 tagtype = ''
5905 tagtype = ''
5907 if repo.tagtype(t) == 'local':
5906 if repo.tagtype(t) == 'local':
5908 label = 'tags.local'
5907 label = 'tags.local'
5909 tagtype = 'local'
5908 tagtype = 'local'
5910
5909
5911 fm.startitem()
5910 fm.startitem()
5912 fm.context(repo=repo)
5911 fm.context(repo=repo)
5913 fm.write('tag', '%s', t, label=label)
5912 fm.write('tag', '%s', t, label=label)
5914 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5913 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5915 fm.condwrite(not ui.quiet, 'rev node', fmt,
5914 fm.condwrite(not ui.quiet, 'rev node', fmt,
5916 repo.changelog.rev(n), hn, label=label)
5915 repo.changelog.rev(n), hn, label=label)
5917 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5916 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5918 tagtype, label=label)
5917 tagtype, label=label)
5919 fm.plain('\n')
5918 fm.plain('\n')
5920 fm.end()
5919 fm.end()
5921
5920
5922 @command('tip',
5921 @command('tip',
5923 [('p', 'patch', None, _('show patch')),
5922 [('p', 'patch', None, _('show patch')),
5924 ('g', 'git', None, _('use git extended diff format')),
5923 ('g', 'git', None, _('use git extended diff format')),
5925 ] + templateopts,
5924 ] + templateopts,
5926 _('[-p] [-g]'),
5925 _('[-p] [-g]'),
5927 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5926 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5928 def tip(ui, repo, **opts):
5927 def tip(ui, repo, **opts):
5929 """show the tip revision (DEPRECATED)
5928 """show the tip revision (DEPRECATED)
5930
5929
5931 The tip revision (usually just called the tip) is the changeset
5930 The tip revision (usually just called the tip) is the changeset
5932 most recently added to the repository (and therefore the most
5931 most recently added to the repository (and therefore the most
5933 recently changed head).
5932 recently changed head).
5934
5933
5935 If you have just made a commit, that commit will be the tip. If
5934 If you have just made a commit, that commit will be the tip. If
5936 you have just pulled changes from another repository, the tip of
5935 you have just pulled changes from another repository, the tip of
5937 that repository becomes the current tip. The "tip" tag is special
5936 that repository becomes the current tip. The "tip" tag is special
5938 and cannot be renamed or assigned to a different changeset.
5937 and cannot be renamed or assigned to a different changeset.
5939
5938
5940 This command is deprecated, please use :hg:`heads` instead.
5939 This command is deprecated, please use :hg:`heads` instead.
5941
5940
5942 Returns 0 on success.
5941 Returns 0 on success.
5943 """
5942 """
5944 opts = pycompat.byteskwargs(opts)
5943 opts = pycompat.byteskwargs(opts)
5945 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5944 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5946 displayer.show(repo['tip'])
5945 displayer.show(repo['tip'])
5947 displayer.close()
5946 displayer.close()
5948
5947
5949 @command('unbundle',
5948 @command('unbundle',
5950 [('u', 'update', None,
5949 [('u', 'update', None,
5951 _('update to new branch head if changesets were unbundled'))],
5950 _('update to new branch head if changesets were unbundled'))],
5952 _('[-u] FILE...'),
5951 _('[-u] FILE...'),
5953 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5952 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5954 def unbundle(ui, repo, fname1, *fnames, **opts):
5953 def unbundle(ui, repo, fname1, *fnames, **opts):
5955 """apply one or more bundle files
5954 """apply one or more bundle files
5956
5955
5957 Apply one or more bundle files generated by :hg:`bundle`.
5956 Apply one or more bundle files generated by :hg:`bundle`.
5958
5957
5959 Returns 0 on success, 1 if an update has unresolved files.
5958 Returns 0 on success, 1 if an update has unresolved files.
5960 """
5959 """
5961 fnames = (fname1,) + fnames
5960 fnames = (fname1,) + fnames
5962
5961
5963 with repo.lock():
5962 with repo.lock():
5964 for fname in fnames:
5963 for fname in fnames:
5965 f = hg.openpath(ui, fname)
5964 f = hg.openpath(ui, fname)
5966 gen = exchange.readbundle(ui, f, fname)
5965 gen = exchange.readbundle(ui, f, fname)
5967 if isinstance(gen, streamclone.streamcloneapplier):
5966 if isinstance(gen, streamclone.streamcloneapplier):
5968 raise error.Abort(
5967 raise error.Abort(
5969 _('packed bundles cannot be applied with '
5968 _('packed bundles cannot be applied with '
5970 '"hg unbundle"'),
5969 '"hg unbundle"'),
5971 hint=_('use "hg debugapplystreamclonebundle"'))
5970 hint=_('use "hg debugapplystreamclonebundle"'))
5972 url = 'bundle:' + fname
5971 url = 'bundle:' + fname
5973 try:
5972 try:
5974 txnname = 'unbundle'
5973 txnname = 'unbundle'
5975 if not isinstance(gen, bundle2.unbundle20):
5974 if not isinstance(gen, bundle2.unbundle20):
5976 txnname = 'unbundle\n%s' % util.hidepassword(url)
5975 txnname = 'unbundle\n%s' % util.hidepassword(url)
5977 with repo.transaction(txnname) as tr:
5976 with repo.transaction(txnname) as tr:
5978 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5977 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5979 url=url)
5978 url=url)
5980 except error.BundleUnknownFeatureError as exc:
5979 except error.BundleUnknownFeatureError as exc:
5981 raise error.Abort(
5980 raise error.Abort(
5982 _('%s: unknown bundle feature, %s') % (fname, exc),
5981 _('%s: unknown bundle feature, %s') % (fname, exc),
5983 hint=_("see https://mercurial-scm.org/"
5982 hint=_("see https://mercurial-scm.org/"
5984 "wiki/BundleFeature for more "
5983 "wiki/BundleFeature for more "
5985 "information"))
5984 "information"))
5986 modheads = bundle2.combinechangegroupresults(op)
5985 modheads = bundle2.combinechangegroupresults(op)
5987
5986
5988 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5987 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5989
5988
5990 @command('update|up|checkout|co',
5989 @command('update|up|checkout|co',
5991 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5990 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5992 ('c', 'check', None, _('require clean working directory')),
5991 ('c', 'check', None, _('require clean working directory')),
5993 ('m', 'merge', None, _('merge uncommitted changes')),
5992 ('m', 'merge', None, _('merge uncommitted changes')),
5994 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5993 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5995 ('r', 'rev', '', _('revision'), _('REV'))
5994 ('r', 'rev', '', _('revision'), _('REV'))
5996 ] + mergetoolopts,
5995 ] + mergetoolopts,
5997 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5996 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5998 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5997 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5999 helpbasic=True)
5998 helpbasic=True)
6000 def update(ui, repo, node=None, **opts):
5999 def update(ui, repo, node=None, **opts):
6001 """update working directory (or switch revisions)
6000 """update working directory (or switch revisions)
6002
6001
6003 Update the repository's working directory to the specified
6002 Update the repository's working directory to the specified
6004 changeset. If no changeset is specified, update to the tip of the
6003 changeset. If no changeset is specified, update to the tip of the
6005 current named branch and move the active bookmark (see :hg:`help
6004 current named branch and move the active bookmark (see :hg:`help
6006 bookmarks`).
6005 bookmarks`).
6007
6006
6008 Update sets the working directory's parent revision to the specified
6007 Update sets the working directory's parent revision to the specified
6009 changeset (see :hg:`help parents`).
6008 changeset (see :hg:`help parents`).
6010
6009
6011 If the changeset is not a descendant or ancestor of the working
6010 If the changeset is not a descendant or ancestor of the working
6012 directory's parent and there are uncommitted changes, the update is
6011 directory's parent and there are uncommitted changes, the update is
6013 aborted. With the -c/--check option, the working directory is checked
6012 aborted. With the -c/--check option, the working directory is checked
6014 for uncommitted changes; if none are found, the working directory is
6013 for uncommitted changes; if none are found, the working directory is
6015 updated to the specified changeset.
6014 updated to the specified changeset.
6016
6015
6017 .. container:: verbose
6016 .. container:: verbose
6018
6017
6019 The -C/--clean, -c/--check, and -m/--merge options control what
6018 The -C/--clean, -c/--check, and -m/--merge options control what
6020 happens if the working directory contains uncommitted changes.
6019 happens if the working directory contains uncommitted changes.
6021 At most of one of them can be specified.
6020 At most of one of them can be specified.
6022
6021
6023 1. If no option is specified, and if
6022 1. If no option is specified, and if
6024 the requested changeset is an ancestor or descendant of
6023 the requested changeset is an ancestor or descendant of
6025 the working directory's parent, the uncommitted changes
6024 the working directory's parent, the uncommitted changes
6026 are merged into the requested changeset and the merged
6025 are merged into the requested changeset and the merged
6027 result is left uncommitted. If the requested changeset is
6026 result is left uncommitted. If the requested changeset is
6028 not an ancestor or descendant (that is, it is on another
6027 not an ancestor or descendant (that is, it is on another
6029 branch), the update is aborted and the uncommitted changes
6028 branch), the update is aborted and the uncommitted changes
6030 are preserved.
6029 are preserved.
6031
6030
6032 2. With the -m/--merge option, the update is allowed even if the
6031 2. With the -m/--merge option, the update is allowed even if the
6033 requested changeset is not an ancestor or descendant of
6032 requested changeset is not an ancestor or descendant of
6034 the working directory's parent.
6033 the working directory's parent.
6035
6034
6036 3. With the -c/--check option, the update is aborted and the
6035 3. With the -c/--check option, the update is aborted and the
6037 uncommitted changes are preserved.
6036 uncommitted changes are preserved.
6038
6037
6039 4. With the -C/--clean option, uncommitted changes are discarded and
6038 4. With the -C/--clean option, uncommitted changes are discarded and
6040 the working directory is updated to the requested changeset.
6039 the working directory is updated to the requested changeset.
6041
6040
6042 To cancel an uncommitted merge (and lose your changes), use
6041 To cancel an uncommitted merge (and lose your changes), use
6043 :hg:`merge --abort`.
6042 :hg:`merge --abort`.
6044
6043
6045 Use null as the changeset to remove the working directory (like
6044 Use null as the changeset to remove the working directory (like
6046 :hg:`clone -U`).
6045 :hg:`clone -U`).
6047
6046
6048 If you want to revert just one file to an older revision, use
6047 If you want to revert just one file to an older revision, use
6049 :hg:`revert [-r REV] NAME`.
6048 :hg:`revert [-r REV] NAME`.
6050
6049
6051 See :hg:`help dates` for a list of formats valid for -d/--date.
6050 See :hg:`help dates` for a list of formats valid for -d/--date.
6052
6051
6053 Returns 0 on success, 1 if there are unresolved files.
6052 Returns 0 on success, 1 if there are unresolved files.
6054 """
6053 """
6055 rev = opts.get(r'rev')
6054 rev = opts.get(r'rev')
6056 date = opts.get(r'date')
6055 date = opts.get(r'date')
6057 clean = opts.get(r'clean')
6056 clean = opts.get(r'clean')
6058 check = opts.get(r'check')
6057 check = opts.get(r'check')
6059 merge = opts.get(r'merge')
6058 merge = opts.get(r'merge')
6060 if rev and node:
6059 if rev and node:
6061 raise error.Abort(_("please specify just one revision"))
6060 raise error.Abort(_("please specify just one revision"))
6062
6061
6063 if ui.configbool('commands', 'update.requiredest'):
6062 if ui.configbool('commands', 'update.requiredest'):
6064 if not node and not rev and not date:
6063 if not node and not rev and not date:
6065 raise error.Abort(_('you must specify a destination'),
6064 raise error.Abort(_('you must specify a destination'),
6066 hint=_('for example: hg update ".::"'))
6065 hint=_('for example: hg update ".::"'))
6067
6066
6068 if rev is None or rev == '':
6067 if rev is None or rev == '':
6069 rev = node
6068 rev = node
6070
6069
6071 if date and rev is not None:
6070 if date and rev is not None:
6072 raise error.Abort(_("you can't specify a revision and a date"))
6071 raise error.Abort(_("you can't specify a revision and a date"))
6073
6072
6074 if len([x for x in (clean, check, merge) if x]) > 1:
6073 if len([x for x in (clean, check, merge) if x]) > 1:
6075 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6074 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6076 "or -m/--merge"))
6075 "or -m/--merge"))
6077
6076
6078 updatecheck = None
6077 updatecheck = None
6079 if check:
6078 if check:
6080 updatecheck = 'abort'
6079 updatecheck = 'abort'
6081 elif merge:
6080 elif merge:
6082 updatecheck = 'none'
6081 updatecheck = 'none'
6083
6082
6084 with repo.wlock():
6083 with repo.wlock():
6085 cmdutil.clearunfinished(repo)
6084 cmdutil.clearunfinished(repo)
6086
6085
6087 if date:
6086 if date:
6088 rev = cmdutil.finddate(ui, repo, date)
6087 rev = cmdutil.finddate(ui, repo, date)
6089
6088
6090 # if we defined a bookmark, we have to remember the original name
6089 # if we defined a bookmark, we have to remember the original name
6091 brev = rev
6090 brev = rev
6092 if rev:
6091 if rev:
6093 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6092 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6094 ctx = scmutil.revsingle(repo, rev, rev)
6093 ctx = scmutil.revsingle(repo, rev, rev)
6095 rev = ctx.rev()
6094 rev = ctx.rev()
6096 hidden = ctx.hidden()
6095 hidden = ctx.hidden()
6097 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6096 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6098 with ui.configoverride(overrides, 'update'):
6097 with ui.configoverride(overrides, 'update'):
6099 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6098 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6100 updatecheck=updatecheck)
6099 updatecheck=updatecheck)
6101 if hidden:
6100 if hidden:
6102 ctxstr = ctx.hex()[:12]
6101 ctxstr = ctx.hex()[:12]
6103 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6102 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6104
6103
6105 if ctx.obsolete():
6104 if ctx.obsolete():
6106 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6105 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6107 ui.warn("(%s)\n" % obsfatemsg)
6106 ui.warn("(%s)\n" % obsfatemsg)
6108 return ret
6107 return ret
6109
6108
6110 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6109 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6111 def verify(ui, repo):
6110 def verify(ui, repo):
6112 """verify the integrity of the repository
6111 """verify the integrity of the repository
6113
6112
6114 Verify the integrity of the current repository.
6113 Verify the integrity of the current repository.
6115
6114
6116 This will perform an extensive check of the repository's
6115 This will perform an extensive check of the repository's
6117 integrity, validating the hashes and checksums of each entry in
6116 integrity, validating the hashes and checksums of each entry in
6118 the changelog, manifest, and tracked files, as well as the
6117 the changelog, manifest, and tracked files, as well as the
6119 integrity of their crosslinks and indices.
6118 integrity of their crosslinks and indices.
6120
6119
6121 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6120 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6122 for more information about recovery from corruption of the
6121 for more information about recovery from corruption of the
6123 repository.
6122 repository.
6124
6123
6125 Returns 0 on success, 1 if errors are encountered.
6124 Returns 0 on success, 1 if errors are encountered.
6126 """
6125 """
6127 return hg.verify(repo)
6126 return hg.verify(repo)
6128
6127
6129 @command(
6128 @command(
6130 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6129 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6131 norepo=True, intents={INTENT_READONLY})
6130 norepo=True, intents={INTENT_READONLY})
6132 def version_(ui, **opts):
6131 def version_(ui, **opts):
6133 """output version and copyright information
6132 """output version and copyright information
6134
6133
6135 .. container:: verbose
6134 .. container:: verbose
6136
6135
6137 Template:
6136 Template:
6138
6137
6139 The following keywords are supported. See also :hg:`help templates`.
6138 The following keywords are supported. See also :hg:`help templates`.
6140
6139
6141 :extensions: List of extensions.
6140 :extensions: List of extensions.
6142 :ver: String. Version number.
6141 :ver: String. Version number.
6143
6142
6144 And each entry of ``{extensions}`` provides the following sub-keywords
6143 And each entry of ``{extensions}`` provides the following sub-keywords
6145 in addition to ``{ver}``.
6144 in addition to ``{ver}``.
6146
6145
6147 :bundled: Boolean. True if included in the release.
6146 :bundled: Boolean. True if included in the release.
6148 :name: String. Extension name.
6147 :name: String. Extension name.
6149 """
6148 """
6150 opts = pycompat.byteskwargs(opts)
6149 opts = pycompat.byteskwargs(opts)
6151 if ui.verbose:
6150 if ui.verbose:
6152 ui.pager('version')
6151 ui.pager('version')
6153 fm = ui.formatter("version", opts)
6152 fm = ui.formatter("version", opts)
6154 fm.startitem()
6153 fm.startitem()
6155 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6154 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6156 util.version())
6155 util.version())
6157 license = _(
6156 license = _(
6158 "(see https://mercurial-scm.org for more information)\n"
6157 "(see https://mercurial-scm.org for more information)\n"
6159 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6158 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6160 "This is free software; see the source for copying conditions. "
6159 "This is free software; see the source for copying conditions. "
6161 "There is NO\nwarranty; "
6160 "There is NO\nwarranty; "
6162 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6161 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6163 )
6162 )
6164 if not ui.quiet:
6163 if not ui.quiet:
6165 fm.plain(license)
6164 fm.plain(license)
6166
6165
6167 if ui.verbose:
6166 if ui.verbose:
6168 fm.plain(_("\nEnabled extensions:\n\n"))
6167 fm.plain(_("\nEnabled extensions:\n\n"))
6169 # format names and versions into columns
6168 # format names and versions into columns
6170 names = []
6169 names = []
6171 vers = []
6170 vers = []
6172 isinternals = []
6171 isinternals = []
6173 for name, module in extensions.extensions():
6172 for name, module in extensions.extensions():
6174 names.append(name)
6173 names.append(name)
6175 vers.append(extensions.moduleversion(module) or None)
6174 vers.append(extensions.moduleversion(module) or None)
6176 isinternals.append(extensions.ismoduleinternal(module))
6175 isinternals.append(extensions.ismoduleinternal(module))
6177 fn = fm.nested("extensions", tmpl='{name}\n')
6176 fn = fm.nested("extensions", tmpl='{name}\n')
6178 if names:
6177 if names:
6179 namefmt = " %%-%ds " % max(len(n) for n in names)
6178 namefmt = " %%-%ds " % max(len(n) for n in names)
6180 places = [_("external"), _("internal")]
6179 places = [_("external"), _("internal")]
6181 for n, v, p in zip(names, vers, isinternals):
6180 for n, v, p in zip(names, vers, isinternals):
6182 fn.startitem()
6181 fn.startitem()
6183 fn.condwrite(ui.verbose, "name", namefmt, n)
6182 fn.condwrite(ui.verbose, "name", namefmt, n)
6184 if ui.verbose:
6183 if ui.verbose:
6185 fn.plain("%s " % places[p])
6184 fn.plain("%s " % places[p])
6186 fn.data(bundled=p)
6185 fn.data(bundled=p)
6187 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6186 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6188 if ui.verbose:
6187 if ui.verbose:
6189 fn.plain("\n")
6188 fn.plain("\n")
6190 fn.end()
6189 fn.end()
6191 fm.end()
6190 fm.end()
6192
6191
6193 def loadcmdtable(ui, name, cmdtable):
6192 def loadcmdtable(ui, name, cmdtable):
6194 """Load command functions from specified cmdtable
6193 """Load command functions from specified cmdtable
6195 """
6194 """
6196 cmdtable = cmdtable.copy()
6195 cmdtable = cmdtable.copy()
6197 for cmd in list(cmdtable):
6196 for cmd in list(cmdtable):
6198 if not cmd.startswith('^'):
6197 if not cmd.startswith('^'):
6199 continue
6198 continue
6200 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6199 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6201 % (cmd, name), '4.8')
6200 % (cmd, name), '4.8')
6202 entry = cmdtable.pop(cmd)
6201 entry = cmdtable.pop(cmd)
6203 entry[0].helpbasic = True
6202 entry[0].helpbasic = True
6204 cmdtable[cmd[1:]] = entry
6203 cmdtable[cmd[1:]] = entry
6205
6204
6206 overrides = [cmd for cmd in cmdtable if cmd in table]
6205 overrides = [cmd for cmd in cmdtable if cmd in table]
6207 if overrides:
6206 if overrides:
6208 ui.warn(_("extension '%s' overrides commands: %s\n")
6207 ui.warn(_("extension '%s' overrides commands: %s\n")
6209 % (name, " ".join(overrides)))
6208 % (name, " ".join(overrides)))
6210 table.update(cmdtable)
6209 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now