##// END OF EJS Templates
py3: use "%d" % val for int rather than pycompat.bytestr...
Pulkit Goyal -
r33015:f66be4ca default
parent child Browse files
Show More
@@ -1,5401 +1,5400 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 rcutil,
49 rcutil,
50 registrar,
50 registrar,
51 revsetlang,
51 revsetlang,
52 scmutil,
52 scmutil,
53 server,
53 server,
54 sshserver,
54 sshserver,
55 streamclone,
55 streamclone,
56 tags as tagsmod,
56 tags as tagsmod,
57 templatekw,
57 templatekw,
58 ui as uimod,
58 ui as uimod,
59 util,
59 util,
60 )
60 )
61
61
62 release = lockmod.release
62 release = lockmod.release
63
63
64 table = {}
64 table = {}
65 table.update(debugcommandsmod.command._table)
65 table.update(debugcommandsmod.command._table)
66
66
67 command = registrar.command(table)
67 command = registrar.command(table)
68
68
69 # common command options
69 # common command options
70
70
71 globalopts = [
71 globalopts = [
72 ('R', 'repository', '',
72 ('R', 'repository', '',
73 _('repository root directory or name of overlay bundle file'),
73 _('repository root directory or name of overlay bundle file'),
74 _('REPO')),
74 _('REPO')),
75 ('', 'cwd', '',
75 ('', 'cwd', '',
76 _('change working directory'), _('DIR')),
76 _('change working directory'), _('DIR')),
77 ('y', 'noninteractive', None,
77 ('y', 'noninteractive', None,
78 _('do not prompt, automatically pick the first choice for all prompts')),
78 _('do not prompt, automatically pick the first choice for all prompts')),
79 ('q', 'quiet', None, _('suppress output')),
79 ('q', 'quiet', None, _('suppress output')),
80 ('v', 'verbose', None, _('enable additional output')),
80 ('v', 'verbose', None, _('enable additional output')),
81 ('', 'color', '',
81 ('', 'color', '',
82 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
82 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
83 # and should not be translated
83 # and should not be translated
84 _("when to colorize (boolean, always, auto, never, or debug)"),
84 _("when to colorize (boolean, always, auto, never, or debug)"),
85 _('TYPE')),
85 _('TYPE')),
86 ('', 'config', [],
86 ('', 'config', [],
87 _('set/override config option (use \'section.name=value\')'),
87 _('set/override config option (use \'section.name=value\')'),
88 _('CONFIG')),
88 _('CONFIG')),
89 ('', 'debug', None, _('enable debugging output')),
89 ('', 'debug', None, _('enable debugging output')),
90 ('', 'debugger', None, _('start debugger')),
90 ('', 'debugger', None, _('start debugger')),
91 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
91 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
92 _('ENCODE')),
92 _('ENCODE')),
93 ('', 'encodingmode', encoding.encodingmode,
93 ('', 'encodingmode', encoding.encodingmode,
94 _('set the charset encoding mode'), _('MODE')),
94 _('set the charset encoding mode'), _('MODE')),
95 ('', 'traceback', None, _('always print a traceback on exception')),
95 ('', 'traceback', None, _('always print a traceback on exception')),
96 ('', 'time', None, _('time how long the command takes')),
96 ('', 'time', None, _('time how long the command takes')),
97 ('', 'profile', None, _('print command execution profile')),
97 ('', 'profile', None, _('print command execution profile')),
98 ('', 'version', None, _('output version information and exit')),
98 ('', 'version', None, _('output version information and exit')),
99 ('h', 'help', None, _('display help and exit')),
99 ('h', 'help', None, _('display help and exit')),
100 ('', 'hidden', False, _('consider hidden changesets')),
100 ('', 'hidden', False, _('consider hidden changesets')),
101 ('', 'pager', 'auto',
101 ('', 'pager', 'auto',
102 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
102 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
103 ]
103 ]
104
104
105 dryrunopts = cmdutil.dryrunopts
105 dryrunopts = cmdutil.dryrunopts
106 remoteopts = cmdutil.remoteopts
106 remoteopts = cmdutil.remoteopts
107 walkopts = cmdutil.walkopts
107 walkopts = cmdutil.walkopts
108 commitopts = cmdutil.commitopts
108 commitopts = cmdutil.commitopts
109 commitopts2 = cmdutil.commitopts2
109 commitopts2 = cmdutil.commitopts2
110 formatteropts = cmdutil.formatteropts
110 formatteropts = cmdutil.formatteropts
111 templateopts = cmdutil.templateopts
111 templateopts = cmdutil.templateopts
112 logopts = cmdutil.logopts
112 logopts = cmdutil.logopts
113 diffopts = cmdutil.diffopts
113 diffopts = cmdutil.diffopts
114 diffwsopts = cmdutil.diffwsopts
114 diffwsopts = cmdutil.diffwsopts
115 diffopts2 = cmdutil.diffopts2
115 diffopts2 = cmdutil.diffopts2
116 mergetoolopts = cmdutil.mergetoolopts
116 mergetoolopts = cmdutil.mergetoolopts
117 similarityopts = cmdutil.similarityopts
117 similarityopts = cmdutil.similarityopts
118 subrepoopts = cmdutil.subrepoopts
118 subrepoopts = cmdutil.subrepoopts
119 debugrevlogopts = cmdutil.debugrevlogopts
119 debugrevlogopts = cmdutil.debugrevlogopts
120
120
121 # Commands start here, listed alphabetically
121 # Commands start here, listed alphabetically
122
122
123 @command('^add',
123 @command('^add',
124 walkopts + subrepoopts + dryrunopts,
124 walkopts + subrepoopts + dryrunopts,
125 _('[OPTION]... [FILE]...'),
125 _('[OPTION]... [FILE]...'),
126 inferrepo=True)
126 inferrepo=True)
127 def add(ui, repo, *pats, **opts):
127 def add(ui, repo, *pats, **opts):
128 """add the specified files on the next commit
128 """add the specified files on the next commit
129
129
130 Schedule files to be version controlled and added to the
130 Schedule files to be version controlled and added to the
131 repository.
131 repository.
132
132
133 The files will be added to the repository at the next commit. To
133 The files will be added to the repository at the next commit. To
134 undo an add before that, see :hg:`forget`.
134 undo an add before that, see :hg:`forget`.
135
135
136 If no names are given, add all files to the repository (except
136 If no names are given, add all files to the repository (except
137 files matching ``.hgignore``).
137 files matching ``.hgignore``).
138
138
139 .. container:: verbose
139 .. container:: verbose
140
140
141 Examples:
141 Examples:
142
142
143 - New (unknown) files are added
143 - New (unknown) files are added
144 automatically by :hg:`add`::
144 automatically by :hg:`add`::
145
145
146 $ ls
146 $ ls
147 foo.c
147 foo.c
148 $ hg status
148 $ hg status
149 ? foo.c
149 ? foo.c
150 $ hg add
150 $ hg add
151 adding foo.c
151 adding foo.c
152 $ hg status
152 $ hg status
153 A foo.c
153 A foo.c
154
154
155 - Specific files to be added can be specified::
155 - Specific files to be added can be specified::
156
156
157 $ ls
157 $ ls
158 bar.c foo.c
158 bar.c foo.c
159 $ hg status
159 $ hg status
160 ? bar.c
160 ? bar.c
161 ? foo.c
161 ? foo.c
162 $ hg add bar.c
162 $ hg add bar.c
163 $ hg status
163 $ hg status
164 A bar.c
164 A bar.c
165 ? foo.c
165 ? foo.c
166
166
167 Returns 0 if all files are successfully added.
167 Returns 0 if all files are successfully added.
168 """
168 """
169
169
170 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
170 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
171 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
171 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + subrepoopts + walkopts + dryrunopts,
175 similarityopts + subrepoopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'),
176 _('[OPTION]... [FILE]...'),
177 inferrepo=True)
177 inferrepo=True)
178 def addremove(ui, repo, *pats, **opts):
178 def addremove(ui, repo, *pats, **opts):
179 """add all new files, delete all missing files
179 """add all new files, delete all missing files
180
180
181 Add all new files and remove all missing files from the
181 Add all new files and remove all missing files from the
182 repository.
182 repository.
183
183
184 Unless names are given, new files are ignored if they match any of
184 Unless names are given, new files are ignored if they match any of
185 the patterns in ``.hgignore``. As with add, these changes take
185 the patterns in ``.hgignore``. As with add, these changes take
186 effect at the next commit.
186 effect at the next commit.
187
187
188 Use the -s/--similarity option to detect renamed files. This
188 Use the -s/--similarity option to detect renamed files. This
189 option takes a percentage between 0 (disabled) and 100 (files must
189 option takes a percentage between 0 (disabled) and 100 (files must
190 be identical) as its parameter. With a parameter greater than 0,
190 be identical) as its parameter. With a parameter greater than 0,
191 this compares every removed file with every added file and records
191 this compares every removed file with every added file and records
192 those similar enough as renames. Detecting renamed files this way
192 those similar enough as renames. Detecting renamed files this way
193 can be expensive. After using this option, :hg:`status -C` can be
193 can be expensive. After using this option, :hg:`status -C` can be
194 used to check which files were identified as moved or renamed. If
194 used to check which files were identified as moved or renamed. If
195 not specified, -s/--similarity defaults to 100 and only renames of
195 not specified, -s/--similarity defaults to 100 and only renames of
196 identical files are detected.
196 identical files are detected.
197
197
198 .. container:: verbose
198 .. container:: verbose
199
199
200 Examples:
200 Examples:
201
201
202 - A number of files (bar.c and foo.c) are new,
202 - A number of files (bar.c and foo.c) are new,
203 while foobar.c has been removed (without using :hg:`remove`)
203 while foobar.c has been removed (without using :hg:`remove`)
204 from the repository::
204 from the repository::
205
205
206 $ ls
206 $ ls
207 bar.c foo.c
207 bar.c foo.c
208 $ hg status
208 $ hg status
209 ! foobar.c
209 ! foobar.c
210 ? bar.c
210 ? bar.c
211 ? foo.c
211 ? foo.c
212 $ hg addremove
212 $ hg addremove
213 adding bar.c
213 adding bar.c
214 adding foo.c
214 adding foo.c
215 removing foobar.c
215 removing foobar.c
216 $ hg status
216 $ hg status
217 A bar.c
217 A bar.c
218 A foo.c
218 A foo.c
219 R foobar.c
219 R foobar.c
220
220
221 - A file foobar.c was moved to foo.c without using :hg:`rename`.
221 - A file foobar.c was moved to foo.c without using :hg:`rename`.
222 Afterwards, it was edited slightly::
222 Afterwards, it was edited slightly::
223
223
224 $ ls
224 $ ls
225 foo.c
225 foo.c
226 $ hg status
226 $ hg status
227 ! foobar.c
227 ! foobar.c
228 ? foo.c
228 ? foo.c
229 $ hg addremove --similarity 90
229 $ hg addremove --similarity 90
230 removing foobar.c
230 removing foobar.c
231 adding foo.c
231 adding foo.c
232 recording removal of foobar.c as rename to foo.c (94% similar)
232 recording removal of foobar.c as rename to foo.c (94% similar)
233 $ hg status -C
233 $ hg status -C
234 A foo.c
234 A foo.c
235 foobar.c
235 foobar.c
236 R foobar.c
236 R foobar.c
237
237
238 Returns 0 if all files are successfully added.
238 Returns 0 if all files are successfully added.
239 """
239 """
240 opts = pycompat.byteskwargs(opts)
240 opts = pycompat.byteskwargs(opts)
241 try:
241 try:
242 sim = float(opts.get('similarity') or 100)
242 sim = float(opts.get('similarity') or 100)
243 except ValueError:
243 except ValueError:
244 raise error.Abort(_('similarity must be a number'))
244 raise error.Abort(_('similarity must be a number'))
245 if sim < 0 or sim > 100:
245 if sim < 0 or sim > 100:
246 raise error.Abort(_('similarity must be between 0 and 100'))
246 raise error.Abort(_('similarity must be between 0 and 100'))
247 matcher = scmutil.match(repo[None], pats, opts)
247 matcher = scmutil.match(repo[None], pats, opts)
248 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
248 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
249
249
250 @command('^annotate|blame',
250 @command('^annotate|blame',
251 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
251 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
252 ('', 'follow', None,
252 ('', 'follow', None,
253 _('follow copies/renames and list the filename (DEPRECATED)')),
253 _('follow copies/renames and list the filename (DEPRECATED)')),
254 ('', 'no-follow', None, _("don't follow copies and renames")),
254 ('', 'no-follow', None, _("don't follow copies and renames")),
255 ('a', 'text', None, _('treat all files as text')),
255 ('a', 'text', None, _('treat all files as text')),
256 ('u', 'user', None, _('list the author (long with -v)')),
256 ('u', 'user', None, _('list the author (long with -v)')),
257 ('f', 'file', None, _('list the filename')),
257 ('f', 'file', None, _('list the filename')),
258 ('d', 'date', None, _('list the date (short with -q)')),
258 ('d', 'date', None, _('list the date (short with -q)')),
259 ('n', 'number', None, _('list the revision number (default)')),
259 ('n', 'number', None, _('list the revision number (default)')),
260 ('c', 'changeset', None, _('list the changeset')),
260 ('c', 'changeset', None, _('list the changeset')),
261 ('l', 'line-number', None, _('show line number at the first appearance')),
261 ('l', 'line-number', None, _('show line number at the first appearance')),
262 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
262 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
263 ] + diffwsopts + walkopts + formatteropts,
263 ] + diffwsopts + walkopts + formatteropts,
264 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
264 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
265 inferrepo=True)
265 inferrepo=True)
266 def annotate(ui, repo, *pats, **opts):
266 def annotate(ui, repo, *pats, **opts):
267 """show changeset information by line for each file
267 """show changeset information by line for each file
268
268
269 List changes in files, showing the revision id responsible for
269 List changes in files, showing the revision id responsible for
270 each line.
270 each line.
271
271
272 This command is useful for discovering when a change was made and
272 This command is useful for discovering when a change was made and
273 by whom.
273 by whom.
274
274
275 If you include --file, --user, or --date, the revision number is
275 If you include --file, --user, or --date, the revision number is
276 suppressed unless you also include --number.
276 suppressed unless you also include --number.
277
277
278 Without the -a/--text option, annotate will avoid processing files
278 Without the -a/--text option, annotate will avoid processing files
279 it detects as binary. With -a, annotate will annotate the file
279 it detects as binary. With -a, annotate will annotate the file
280 anyway, although the results will probably be neither useful
280 anyway, although the results will probably be neither useful
281 nor desirable.
281 nor desirable.
282
282
283 Returns 0 on success.
283 Returns 0 on success.
284 """
284 """
285 opts = pycompat.byteskwargs(opts)
285 opts = pycompat.byteskwargs(opts)
286 if not pats:
286 if not pats:
287 raise error.Abort(_('at least one filename or pattern is required'))
287 raise error.Abort(_('at least one filename or pattern is required'))
288
288
289 if opts.get('follow'):
289 if opts.get('follow'):
290 # --follow is deprecated and now just an alias for -f/--file
290 # --follow is deprecated and now just an alias for -f/--file
291 # to mimic the behavior of Mercurial before version 1.5
291 # to mimic the behavior of Mercurial before version 1.5
292 opts['file'] = True
292 opts['file'] = True
293
293
294 ctx = scmutil.revsingle(repo, opts.get('rev'))
294 ctx = scmutil.revsingle(repo, opts.get('rev'))
295
295
296 rootfm = ui.formatter('annotate', opts)
296 rootfm = ui.formatter('annotate', opts)
297 if ui.quiet:
297 if ui.quiet:
298 datefunc = util.shortdate
298 datefunc = util.shortdate
299 else:
299 else:
300 datefunc = util.datestr
300 datefunc = util.datestr
301 if ctx.rev() is None:
301 if ctx.rev() is None:
302 def hexfn(node):
302 def hexfn(node):
303 if node is None:
303 if node is None:
304 return None
304 return None
305 else:
305 else:
306 return rootfm.hexfunc(node)
306 return rootfm.hexfunc(node)
307 if opts.get('changeset'):
307 if opts.get('changeset'):
308 # omit "+" suffix which is appended to node hex
308 # omit "+" suffix which is appended to node hex
309 def formatrev(rev):
309 def formatrev(rev):
310 if rev is None:
310 if rev is None:
311 return '%d' % ctx.p1().rev()
311 return '%d' % ctx.p1().rev()
312 else:
312 else:
313 return '%d' % rev
313 return '%d' % rev
314 else:
314 else:
315 def formatrev(rev):
315 def formatrev(rev):
316 if rev is None:
316 if rev is None:
317 return '%d+' % ctx.p1().rev()
317 return '%d+' % ctx.p1().rev()
318 else:
318 else:
319 return '%d ' % rev
319 return '%d ' % rev
320 def formathex(hex):
320 def formathex(hex):
321 if hex is None:
321 if hex is None:
322 return '%s+' % rootfm.hexfunc(ctx.p1().node())
322 return '%s+' % rootfm.hexfunc(ctx.p1().node())
323 else:
323 else:
324 return '%s ' % hex
324 return '%s ' % hex
325 else:
325 else:
326 hexfn = rootfm.hexfunc
326 hexfn = rootfm.hexfunc
327 formatrev = formathex = str
327 formatrev = formathex = str
328
328
329 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
329 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
330 ('number', ' ', lambda x: x[0].rev(), formatrev),
330 ('number', ' ', lambda x: x[0].rev(), formatrev),
331 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
331 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
332 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
332 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
333 ('file', ' ', lambda x: x[0].path(), str),
333 ('file', ' ', lambda x: x[0].path(), str),
334 ('line_number', ':', lambda x: x[1], str),
334 ('line_number', ':', lambda x: x[1], str),
335 ]
335 ]
336 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
336 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
337
337
338 if (not opts.get('user') and not opts.get('changeset')
338 if (not opts.get('user') and not opts.get('changeset')
339 and not opts.get('date') and not opts.get('file')):
339 and not opts.get('date') and not opts.get('file')):
340 opts['number'] = True
340 opts['number'] = True
341
341
342 linenumber = opts.get('line_number') is not None
342 linenumber = opts.get('line_number') is not None
343 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
343 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
344 raise error.Abort(_('at least one of -n/-c is required for -l'))
344 raise error.Abort(_('at least one of -n/-c is required for -l'))
345
345
346 ui.pager('annotate')
346 ui.pager('annotate')
347
347
348 if rootfm.isplain():
348 if rootfm.isplain():
349 def makefunc(get, fmt):
349 def makefunc(get, fmt):
350 return lambda x: fmt(get(x))
350 return lambda x: fmt(get(x))
351 else:
351 else:
352 def makefunc(get, fmt):
352 def makefunc(get, fmt):
353 return get
353 return get
354 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
354 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
355 if opts.get(op)]
355 if opts.get(op)]
356 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
356 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
357 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
357 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
358 if opts.get(op))
358 if opts.get(op))
359
359
360 def bad(x, y):
360 def bad(x, y):
361 raise error.Abort("%s: %s" % (x, y))
361 raise error.Abort("%s: %s" % (x, y))
362
362
363 m = scmutil.match(ctx, pats, opts, badfn=bad)
363 m = scmutil.match(ctx, pats, opts, badfn=bad)
364
364
365 follow = not opts.get('no_follow')
365 follow = not opts.get('no_follow')
366 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
366 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
367 whitespace=True)
367 whitespace=True)
368 skiprevs = opts.get('skip')
368 skiprevs = opts.get('skip')
369 if skiprevs:
369 if skiprevs:
370 skiprevs = scmutil.revrange(repo, skiprevs)
370 skiprevs = scmutil.revrange(repo, skiprevs)
371
371
372 for abs in ctx.walk(m):
372 for abs in ctx.walk(m):
373 fctx = ctx[abs]
373 fctx = ctx[abs]
374 rootfm.startitem()
374 rootfm.startitem()
375 rootfm.data(abspath=abs, path=m.rel(abs))
375 rootfm.data(abspath=abs, path=m.rel(abs))
376 if not opts.get('text') and fctx.isbinary():
376 if not opts.get('text') and fctx.isbinary():
377 rootfm.plain(_("%s: binary file\n")
377 rootfm.plain(_("%s: binary file\n")
378 % ((pats and m.rel(abs)) or abs))
378 % ((pats and m.rel(abs)) or abs))
379 continue
379 continue
380
380
381 fm = rootfm.nested('lines')
381 fm = rootfm.nested('lines')
382 lines = fctx.annotate(follow=follow, linenumber=linenumber,
382 lines = fctx.annotate(follow=follow, linenumber=linenumber,
383 skiprevs=skiprevs, diffopts=diffopts)
383 skiprevs=skiprevs, diffopts=diffopts)
384 if not lines:
384 if not lines:
385 fm.end()
385 fm.end()
386 continue
386 continue
387 formats = []
387 formats = []
388 pieces = []
388 pieces = []
389
389
390 for f, sep in funcmap:
390 for f, sep in funcmap:
391 l = [f(n) for n, dummy in lines]
391 l = [f(n) for n, dummy in lines]
392 if fm.isplain():
392 if fm.isplain():
393 sizes = [encoding.colwidth(x) for x in l]
393 sizes = [encoding.colwidth(x) for x in l]
394 ml = max(sizes)
394 ml = max(sizes)
395 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
395 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
396 else:
396 else:
397 formats.append(['%s' for x in l])
397 formats.append(['%s' for x in l])
398 pieces.append(l)
398 pieces.append(l)
399
399
400 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
400 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
401 fm.startitem()
401 fm.startitem()
402 fm.write(fields, "".join(f), *p)
402 fm.write(fields, "".join(f), *p)
403 fm.write('line', ": %s", l[1])
403 fm.write('line', ": %s", l[1])
404
404
405 if not lines[-1][1].endswith('\n'):
405 if not lines[-1][1].endswith('\n'):
406 fm.plain('\n')
406 fm.plain('\n')
407 fm.end()
407 fm.end()
408
408
409 rootfm.end()
409 rootfm.end()
410
410
411 @command('archive',
411 @command('archive',
412 [('', 'no-decode', None, _('do not pass files through decoders')),
412 [('', 'no-decode', None, _('do not pass files through decoders')),
413 ('p', 'prefix', '', _('directory prefix for files in archive'),
413 ('p', 'prefix', '', _('directory prefix for files in archive'),
414 _('PREFIX')),
414 _('PREFIX')),
415 ('r', 'rev', '', _('revision to distribute'), _('REV')),
415 ('r', 'rev', '', _('revision to distribute'), _('REV')),
416 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
416 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
417 ] + subrepoopts + walkopts,
417 ] + subrepoopts + walkopts,
418 _('[OPTION]... DEST'))
418 _('[OPTION]... DEST'))
419 def archive(ui, repo, dest, **opts):
419 def archive(ui, repo, dest, **opts):
420 '''create an unversioned archive of a repository revision
420 '''create an unversioned archive of a repository revision
421
421
422 By default, the revision used is the parent of the working
422 By default, the revision used is the parent of the working
423 directory; use -r/--rev to specify a different revision.
423 directory; use -r/--rev to specify a different revision.
424
424
425 The archive type is automatically detected based on file
425 The archive type is automatically detected based on file
426 extension (to override, use -t/--type).
426 extension (to override, use -t/--type).
427
427
428 .. container:: verbose
428 .. container:: verbose
429
429
430 Examples:
430 Examples:
431
431
432 - create a zip file containing the 1.0 release::
432 - create a zip file containing the 1.0 release::
433
433
434 hg archive -r 1.0 project-1.0.zip
434 hg archive -r 1.0 project-1.0.zip
435
435
436 - create a tarball excluding .hg files::
436 - create a tarball excluding .hg files::
437
437
438 hg archive project.tar.gz -X ".hg*"
438 hg archive project.tar.gz -X ".hg*"
439
439
440 Valid types are:
440 Valid types are:
441
441
442 :``files``: a directory full of files (default)
442 :``files``: a directory full of files (default)
443 :``tar``: tar archive, uncompressed
443 :``tar``: tar archive, uncompressed
444 :``tbz2``: tar archive, compressed using bzip2
444 :``tbz2``: tar archive, compressed using bzip2
445 :``tgz``: tar archive, compressed using gzip
445 :``tgz``: tar archive, compressed using gzip
446 :``uzip``: zip archive, uncompressed
446 :``uzip``: zip archive, uncompressed
447 :``zip``: zip archive, compressed using deflate
447 :``zip``: zip archive, compressed using deflate
448
448
449 The exact name of the destination archive or directory is given
449 The exact name of the destination archive or directory is given
450 using a format string; see :hg:`help export` for details.
450 using a format string; see :hg:`help export` for details.
451
451
452 Each member added to an archive file has a directory prefix
452 Each member added to an archive file has a directory prefix
453 prepended. Use -p/--prefix to specify a format string for the
453 prepended. Use -p/--prefix to specify a format string for the
454 prefix. The default is the basename of the archive, with suffixes
454 prefix. The default is the basename of the archive, with suffixes
455 removed.
455 removed.
456
456
457 Returns 0 on success.
457 Returns 0 on success.
458 '''
458 '''
459
459
460 opts = pycompat.byteskwargs(opts)
460 opts = pycompat.byteskwargs(opts)
461 ctx = scmutil.revsingle(repo, opts.get('rev'))
461 ctx = scmutil.revsingle(repo, opts.get('rev'))
462 if not ctx:
462 if not ctx:
463 raise error.Abort(_('no working directory: please specify a revision'))
463 raise error.Abort(_('no working directory: please specify a revision'))
464 node = ctx.node()
464 node = ctx.node()
465 dest = cmdutil.makefilename(repo, dest, node)
465 dest = cmdutil.makefilename(repo, dest, node)
466 if os.path.realpath(dest) == repo.root:
466 if os.path.realpath(dest) == repo.root:
467 raise error.Abort(_('repository root cannot be destination'))
467 raise error.Abort(_('repository root cannot be destination'))
468
468
469 kind = opts.get('type') or archival.guesskind(dest) or 'files'
469 kind = opts.get('type') or archival.guesskind(dest) or 'files'
470 prefix = opts.get('prefix')
470 prefix = opts.get('prefix')
471
471
472 if dest == '-':
472 if dest == '-':
473 if kind == 'files':
473 if kind == 'files':
474 raise error.Abort(_('cannot archive plain files to stdout'))
474 raise error.Abort(_('cannot archive plain files to stdout'))
475 dest = cmdutil.makefileobj(repo, dest)
475 dest = cmdutil.makefileobj(repo, dest)
476 if not prefix:
476 if not prefix:
477 prefix = os.path.basename(repo.root) + '-%h'
477 prefix = os.path.basename(repo.root) + '-%h'
478
478
479 prefix = cmdutil.makefilename(repo, prefix, node)
479 prefix = cmdutil.makefilename(repo, prefix, node)
480 matchfn = scmutil.match(ctx, [], opts)
480 matchfn = scmutil.match(ctx, [], opts)
481 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
481 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
482 matchfn, prefix, subrepos=opts.get('subrepos'))
482 matchfn, prefix, subrepos=opts.get('subrepos'))
483
483
484 @command('backout',
484 @command('backout',
485 [('', 'merge', None, _('merge with old dirstate parent after backout')),
485 [('', 'merge', None, _('merge with old dirstate parent after backout')),
486 ('', 'commit', None,
486 ('', 'commit', None,
487 _('commit if no conflicts were encountered (DEPRECATED)')),
487 _('commit if no conflicts were encountered (DEPRECATED)')),
488 ('', 'no-commit', None, _('do not commit')),
488 ('', 'no-commit', None, _('do not commit')),
489 ('', 'parent', '',
489 ('', 'parent', '',
490 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
490 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
491 ('r', 'rev', '', _('revision to backout'), _('REV')),
491 ('r', 'rev', '', _('revision to backout'), _('REV')),
492 ('e', 'edit', False, _('invoke editor on commit messages')),
492 ('e', 'edit', False, _('invoke editor on commit messages')),
493 ] + mergetoolopts + walkopts + commitopts + commitopts2,
493 ] + mergetoolopts + walkopts + commitopts + commitopts2,
494 _('[OPTION]... [-r] REV'))
494 _('[OPTION]... [-r] REV'))
495 def backout(ui, repo, node=None, rev=None, **opts):
495 def backout(ui, repo, node=None, rev=None, **opts):
496 '''reverse effect of earlier changeset
496 '''reverse effect of earlier changeset
497
497
498 Prepare a new changeset with the effect of REV undone in the
498 Prepare a new changeset with the effect of REV undone in the
499 current working directory. If no conflicts were encountered,
499 current working directory. If no conflicts were encountered,
500 it will be committed immediately.
500 it will be committed immediately.
501
501
502 If REV is the parent of the working directory, then this new changeset
502 If REV is the parent of the working directory, then this new changeset
503 is committed automatically (unless --no-commit is specified).
503 is committed automatically (unless --no-commit is specified).
504
504
505 .. note::
505 .. note::
506
506
507 :hg:`backout` cannot be used to fix either an unwanted or
507 :hg:`backout` cannot be used to fix either an unwanted or
508 incorrect merge.
508 incorrect merge.
509
509
510 .. container:: verbose
510 .. container:: verbose
511
511
512 Examples:
512 Examples:
513
513
514 - Reverse the effect of the parent of the working directory.
514 - Reverse the effect of the parent of the working directory.
515 This backout will be committed immediately::
515 This backout will be committed immediately::
516
516
517 hg backout -r .
517 hg backout -r .
518
518
519 - Reverse the effect of previous bad revision 23::
519 - Reverse the effect of previous bad revision 23::
520
520
521 hg backout -r 23
521 hg backout -r 23
522
522
523 - Reverse the effect of previous bad revision 23 and
523 - Reverse the effect of previous bad revision 23 and
524 leave changes uncommitted::
524 leave changes uncommitted::
525
525
526 hg backout -r 23 --no-commit
526 hg backout -r 23 --no-commit
527 hg commit -m "Backout revision 23"
527 hg commit -m "Backout revision 23"
528
528
529 By default, the pending changeset will have one parent,
529 By default, the pending changeset will have one parent,
530 maintaining a linear history. With --merge, the pending
530 maintaining a linear history. With --merge, the pending
531 changeset will instead have two parents: the old parent of the
531 changeset will instead have two parents: the old parent of the
532 working directory and a new child of REV that simply undoes REV.
532 working directory and a new child of REV that simply undoes REV.
533
533
534 Before version 1.7, the behavior without --merge was equivalent
534 Before version 1.7, the behavior without --merge was equivalent
535 to specifying --merge followed by :hg:`update --clean .` to
535 to specifying --merge followed by :hg:`update --clean .` to
536 cancel the merge and leave the child of REV as a head to be
536 cancel the merge and leave the child of REV as a head to be
537 merged separately.
537 merged separately.
538
538
539 See :hg:`help dates` for a list of formats valid for -d/--date.
539 See :hg:`help dates` for a list of formats valid for -d/--date.
540
540
541 See :hg:`help revert` for a way to restore files to the state
541 See :hg:`help revert` for a way to restore files to the state
542 of another revision.
542 of another revision.
543
543
544 Returns 0 on success, 1 if nothing to backout or there are unresolved
544 Returns 0 on success, 1 if nothing to backout or there are unresolved
545 files.
545 files.
546 '''
546 '''
547 wlock = lock = None
547 wlock = lock = None
548 try:
548 try:
549 wlock = repo.wlock()
549 wlock = repo.wlock()
550 lock = repo.lock()
550 lock = repo.lock()
551 return _dobackout(ui, repo, node, rev, **opts)
551 return _dobackout(ui, repo, node, rev, **opts)
552 finally:
552 finally:
553 release(lock, wlock)
553 release(lock, wlock)
554
554
555 def _dobackout(ui, repo, node=None, rev=None, **opts):
555 def _dobackout(ui, repo, node=None, rev=None, **opts):
556 opts = pycompat.byteskwargs(opts)
556 opts = pycompat.byteskwargs(opts)
557 if opts.get('commit') and opts.get('no_commit'):
557 if opts.get('commit') and opts.get('no_commit'):
558 raise error.Abort(_("cannot use --commit with --no-commit"))
558 raise error.Abort(_("cannot use --commit with --no-commit"))
559 if opts.get('merge') and opts.get('no_commit'):
559 if opts.get('merge') and opts.get('no_commit'):
560 raise error.Abort(_("cannot use --merge with --no-commit"))
560 raise error.Abort(_("cannot use --merge with --no-commit"))
561
561
562 if rev and node:
562 if rev and node:
563 raise error.Abort(_("please specify just one revision"))
563 raise error.Abort(_("please specify just one revision"))
564
564
565 if not rev:
565 if not rev:
566 rev = node
566 rev = node
567
567
568 if not rev:
568 if not rev:
569 raise error.Abort(_("please specify a revision to backout"))
569 raise error.Abort(_("please specify a revision to backout"))
570
570
571 date = opts.get('date')
571 date = opts.get('date')
572 if date:
572 if date:
573 opts['date'] = util.parsedate(date)
573 opts['date'] = util.parsedate(date)
574
574
575 cmdutil.checkunfinished(repo)
575 cmdutil.checkunfinished(repo)
576 cmdutil.bailifchanged(repo)
576 cmdutil.bailifchanged(repo)
577 node = scmutil.revsingle(repo, rev).node()
577 node = scmutil.revsingle(repo, rev).node()
578
578
579 op1, op2 = repo.dirstate.parents()
579 op1, op2 = repo.dirstate.parents()
580 if not repo.changelog.isancestor(node, op1):
580 if not repo.changelog.isancestor(node, op1):
581 raise error.Abort(_('cannot backout change that is not an ancestor'))
581 raise error.Abort(_('cannot backout change that is not an ancestor'))
582
582
583 p1, p2 = repo.changelog.parents(node)
583 p1, p2 = repo.changelog.parents(node)
584 if p1 == nullid:
584 if p1 == nullid:
585 raise error.Abort(_('cannot backout a change with no parents'))
585 raise error.Abort(_('cannot backout a change with no parents'))
586 if p2 != nullid:
586 if p2 != nullid:
587 if not opts.get('parent'):
587 if not opts.get('parent'):
588 raise error.Abort(_('cannot backout a merge changeset'))
588 raise error.Abort(_('cannot backout a merge changeset'))
589 p = repo.lookup(opts['parent'])
589 p = repo.lookup(opts['parent'])
590 if p not in (p1, p2):
590 if p not in (p1, p2):
591 raise error.Abort(_('%s is not a parent of %s') %
591 raise error.Abort(_('%s is not a parent of %s') %
592 (short(p), short(node)))
592 (short(p), short(node)))
593 parent = p
593 parent = p
594 else:
594 else:
595 if opts.get('parent'):
595 if opts.get('parent'):
596 raise error.Abort(_('cannot use --parent on non-merge changeset'))
596 raise error.Abort(_('cannot use --parent on non-merge changeset'))
597 parent = p1
597 parent = p1
598
598
599 # the backout should appear on the same branch
599 # the backout should appear on the same branch
600 branch = repo.dirstate.branch()
600 branch = repo.dirstate.branch()
601 bheads = repo.branchheads(branch)
601 bheads = repo.branchheads(branch)
602 rctx = scmutil.revsingle(repo, hex(parent))
602 rctx = scmutil.revsingle(repo, hex(parent))
603 if not opts.get('merge') and op1 != node:
603 if not opts.get('merge') and op1 != node:
604 dsguard = dirstateguard.dirstateguard(repo, 'backout')
604 dsguard = dirstateguard.dirstateguard(repo, 'backout')
605 try:
605 try:
606 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
606 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
607 'backout')
607 'backout')
608 stats = mergemod.update(repo, parent, True, True, node, False)
608 stats = mergemod.update(repo, parent, True, True, node, False)
609 repo.setparents(op1, op2)
609 repo.setparents(op1, op2)
610 dsguard.close()
610 dsguard.close()
611 hg._showstats(repo, stats)
611 hg._showstats(repo, stats)
612 if stats[3]:
612 if stats[3]:
613 repo.ui.status(_("use 'hg resolve' to retry unresolved "
613 repo.ui.status(_("use 'hg resolve' to retry unresolved "
614 "file merges\n"))
614 "file merges\n"))
615 return 1
615 return 1
616 finally:
616 finally:
617 ui.setconfig('ui', 'forcemerge', '', '')
617 ui.setconfig('ui', 'forcemerge', '', '')
618 lockmod.release(dsguard)
618 lockmod.release(dsguard)
619 else:
619 else:
620 hg.clean(repo, node, show_stats=False)
620 hg.clean(repo, node, show_stats=False)
621 repo.dirstate.setbranch(branch)
621 repo.dirstate.setbranch(branch)
622 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
622 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
623
623
624 if opts.get('no_commit'):
624 if opts.get('no_commit'):
625 msg = _("changeset %s backed out, "
625 msg = _("changeset %s backed out, "
626 "don't forget to commit.\n")
626 "don't forget to commit.\n")
627 ui.status(msg % short(node))
627 ui.status(msg % short(node))
628 return 0
628 return 0
629
629
630 def commitfunc(ui, repo, message, match, opts):
630 def commitfunc(ui, repo, message, match, opts):
631 editform = 'backout'
631 editform = 'backout'
632 e = cmdutil.getcommiteditor(editform=editform,
632 e = cmdutil.getcommiteditor(editform=editform,
633 **pycompat.strkwargs(opts))
633 **pycompat.strkwargs(opts))
634 if not message:
634 if not message:
635 # we don't translate commit messages
635 # we don't translate commit messages
636 message = "Backed out changeset %s" % short(node)
636 message = "Backed out changeset %s" % short(node)
637 e = cmdutil.getcommiteditor(edit=True, editform=editform)
637 e = cmdutil.getcommiteditor(edit=True, editform=editform)
638 return repo.commit(message, opts.get('user'), opts.get('date'),
638 return repo.commit(message, opts.get('user'), opts.get('date'),
639 match, editor=e)
639 match, editor=e)
640 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
640 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
641 if not newnode:
641 if not newnode:
642 ui.status(_("nothing changed\n"))
642 ui.status(_("nothing changed\n"))
643 return 1
643 return 1
644 cmdutil.commitstatus(repo, newnode, branch, bheads)
644 cmdutil.commitstatus(repo, newnode, branch, bheads)
645
645
646 def nice(node):
646 def nice(node):
647 return '%d:%s' % (repo.changelog.rev(node), short(node))
647 return '%d:%s' % (repo.changelog.rev(node), short(node))
648 ui.status(_('changeset %s backs out changeset %s\n') %
648 ui.status(_('changeset %s backs out changeset %s\n') %
649 (nice(repo.changelog.tip()), nice(node)))
649 (nice(repo.changelog.tip()), nice(node)))
650 if opts.get('merge') and op1 != node:
650 if opts.get('merge') and op1 != node:
651 hg.clean(repo, op1, show_stats=False)
651 hg.clean(repo, op1, show_stats=False)
652 ui.status(_('merging with changeset %s\n')
652 ui.status(_('merging with changeset %s\n')
653 % nice(repo.changelog.tip()))
653 % nice(repo.changelog.tip()))
654 try:
654 try:
655 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
655 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
656 'backout')
656 'backout')
657 return hg.merge(repo, hex(repo.changelog.tip()))
657 return hg.merge(repo, hex(repo.changelog.tip()))
658 finally:
658 finally:
659 ui.setconfig('ui', 'forcemerge', '', '')
659 ui.setconfig('ui', 'forcemerge', '', '')
660 return 0
660 return 0
661
661
662 @command('bisect',
662 @command('bisect',
663 [('r', 'reset', False, _('reset bisect state')),
663 [('r', 'reset', False, _('reset bisect state')),
664 ('g', 'good', False, _('mark changeset good')),
664 ('g', 'good', False, _('mark changeset good')),
665 ('b', 'bad', False, _('mark changeset bad')),
665 ('b', 'bad', False, _('mark changeset bad')),
666 ('s', 'skip', False, _('skip testing changeset')),
666 ('s', 'skip', False, _('skip testing changeset')),
667 ('e', 'extend', False, _('extend the bisect range')),
667 ('e', 'extend', False, _('extend the bisect range')),
668 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
668 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
669 ('U', 'noupdate', False, _('do not update to target'))],
669 ('U', 'noupdate', False, _('do not update to target'))],
670 _("[-gbsr] [-U] [-c CMD] [REV]"))
670 _("[-gbsr] [-U] [-c CMD] [REV]"))
671 def bisect(ui, repo, rev=None, extra=None, command=None,
671 def bisect(ui, repo, rev=None, extra=None, command=None,
672 reset=None, good=None, bad=None, skip=None, extend=None,
672 reset=None, good=None, bad=None, skip=None, extend=None,
673 noupdate=None):
673 noupdate=None):
674 """subdivision search of changesets
674 """subdivision search of changesets
675
675
676 This command helps to find changesets which introduce problems. To
676 This command helps to find changesets which introduce problems. To
677 use, mark the earliest changeset you know exhibits the problem as
677 use, mark the earliest changeset you know exhibits the problem as
678 bad, then mark the latest changeset which is free from the problem
678 bad, then mark the latest changeset which is free from the problem
679 as good. Bisect will update your working directory to a revision
679 as good. Bisect will update your working directory to a revision
680 for testing (unless the -U/--noupdate option is specified). Once
680 for testing (unless the -U/--noupdate option is specified). Once
681 you have performed tests, mark the working directory as good or
681 you have performed tests, mark the working directory as good or
682 bad, and bisect will either update to another candidate changeset
682 bad, and bisect will either update to another candidate changeset
683 or announce that it has found the bad revision.
683 or announce that it has found the bad revision.
684
684
685 As a shortcut, you can also use the revision argument to mark a
685 As a shortcut, you can also use the revision argument to mark a
686 revision as good or bad without checking it out first.
686 revision as good or bad without checking it out first.
687
687
688 If you supply a command, it will be used for automatic bisection.
688 If you supply a command, it will be used for automatic bisection.
689 The environment variable HG_NODE will contain the ID of the
689 The environment variable HG_NODE will contain the ID of the
690 changeset being tested. The exit status of the command will be
690 changeset being tested. The exit status of the command will be
691 used to mark revisions as good or bad: status 0 means good, 125
691 used to mark revisions as good or bad: status 0 means good, 125
692 means to skip the revision, 127 (command not found) will abort the
692 means to skip the revision, 127 (command not found) will abort the
693 bisection, and any other non-zero exit status means the revision
693 bisection, and any other non-zero exit status means the revision
694 is bad.
694 is bad.
695
695
696 .. container:: verbose
696 .. container:: verbose
697
697
698 Some examples:
698 Some examples:
699
699
700 - start a bisection with known bad revision 34, and good revision 12::
700 - start a bisection with known bad revision 34, and good revision 12::
701
701
702 hg bisect --bad 34
702 hg bisect --bad 34
703 hg bisect --good 12
703 hg bisect --good 12
704
704
705 - advance the current bisection by marking current revision as good or
705 - advance the current bisection by marking current revision as good or
706 bad::
706 bad::
707
707
708 hg bisect --good
708 hg bisect --good
709 hg bisect --bad
709 hg bisect --bad
710
710
711 - mark the current revision, or a known revision, to be skipped (e.g. if
711 - mark the current revision, or a known revision, to be skipped (e.g. if
712 that revision is not usable because of another issue)::
712 that revision is not usable because of another issue)::
713
713
714 hg bisect --skip
714 hg bisect --skip
715 hg bisect --skip 23
715 hg bisect --skip 23
716
716
717 - skip all revisions that do not touch directories ``foo`` or ``bar``::
717 - skip all revisions that do not touch directories ``foo`` or ``bar``::
718
718
719 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
719 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
720
720
721 - forget the current bisection::
721 - forget the current bisection::
722
722
723 hg bisect --reset
723 hg bisect --reset
724
724
725 - use 'make && make tests' to automatically find the first broken
725 - use 'make && make tests' to automatically find the first broken
726 revision::
726 revision::
727
727
728 hg bisect --reset
728 hg bisect --reset
729 hg bisect --bad 34
729 hg bisect --bad 34
730 hg bisect --good 12
730 hg bisect --good 12
731 hg bisect --command "make && make tests"
731 hg bisect --command "make && make tests"
732
732
733 - see all changesets whose states are already known in the current
733 - see all changesets whose states are already known in the current
734 bisection::
734 bisection::
735
735
736 hg log -r "bisect(pruned)"
736 hg log -r "bisect(pruned)"
737
737
738 - see the changeset currently being bisected (especially useful
738 - see the changeset currently being bisected (especially useful
739 if running with -U/--noupdate)::
739 if running with -U/--noupdate)::
740
740
741 hg log -r "bisect(current)"
741 hg log -r "bisect(current)"
742
742
743 - see all changesets that took part in the current bisection::
743 - see all changesets that took part in the current bisection::
744
744
745 hg log -r "bisect(range)"
745 hg log -r "bisect(range)"
746
746
747 - you can even get a nice graph::
747 - you can even get a nice graph::
748
748
749 hg log --graph -r "bisect(range)"
749 hg log --graph -r "bisect(range)"
750
750
751 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
751 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
752
752
753 Returns 0 on success.
753 Returns 0 on success.
754 """
754 """
755 # backward compatibility
755 # backward compatibility
756 if rev in "good bad reset init".split():
756 if rev in "good bad reset init".split():
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
758 cmd, rev, extra = rev, extra, None
758 cmd, rev, extra = rev, extra, None
759 if cmd == "good":
759 if cmd == "good":
760 good = True
760 good = True
761 elif cmd == "bad":
761 elif cmd == "bad":
762 bad = True
762 bad = True
763 else:
763 else:
764 reset = True
764 reset = True
765 elif extra:
765 elif extra:
766 raise error.Abort(_('incompatible arguments'))
766 raise error.Abort(_('incompatible arguments'))
767
767
768 incompatibles = {
768 incompatibles = {
769 '--bad': bad,
769 '--bad': bad,
770 '--command': bool(command),
770 '--command': bool(command),
771 '--extend': extend,
771 '--extend': extend,
772 '--good': good,
772 '--good': good,
773 '--reset': reset,
773 '--reset': reset,
774 '--skip': skip,
774 '--skip': skip,
775 }
775 }
776
776
777 enabled = [x for x in incompatibles if incompatibles[x]]
777 enabled = [x for x in incompatibles if incompatibles[x]]
778
778
779 if len(enabled) > 1:
779 if len(enabled) > 1:
780 raise error.Abort(_('%s and %s are incompatible') %
780 raise error.Abort(_('%s and %s are incompatible') %
781 tuple(sorted(enabled)[0:2]))
781 tuple(sorted(enabled)[0:2]))
782
782
783 if reset:
783 if reset:
784 hbisect.resetstate(repo)
784 hbisect.resetstate(repo)
785 return
785 return
786
786
787 state = hbisect.load_state(repo)
787 state = hbisect.load_state(repo)
788
788
789 # update state
789 # update state
790 if good or bad or skip:
790 if good or bad or skip:
791 if rev:
791 if rev:
792 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
792 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
793 else:
793 else:
794 nodes = [repo.lookup('.')]
794 nodes = [repo.lookup('.')]
795 if good:
795 if good:
796 state['good'] += nodes
796 state['good'] += nodes
797 elif bad:
797 elif bad:
798 state['bad'] += nodes
798 state['bad'] += nodes
799 elif skip:
799 elif skip:
800 state['skip'] += nodes
800 state['skip'] += nodes
801 hbisect.save_state(repo, state)
801 hbisect.save_state(repo, state)
802 if not (state['good'] and state['bad']):
802 if not (state['good'] and state['bad']):
803 return
803 return
804
804
805 def mayupdate(repo, node, show_stats=True):
805 def mayupdate(repo, node, show_stats=True):
806 """common used update sequence"""
806 """common used update sequence"""
807 if noupdate:
807 if noupdate:
808 return
808 return
809 cmdutil.checkunfinished(repo)
809 cmdutil.checkunfinished(repo)
810 cmdutil.bailifchanged(repo)
810 cmdutil.bailifchanged(repo)
811 return hg.clean(repo, node, show_stats=show_stats)
811 return hg.clean(repo, node, show_stats=show_stats)
812
812
813 displayer = cmdutil.show_changeset(ui, repo, {})
813 displayer = cmdutil.show_changeset(ui, repo, {})
814
814
815 if command:
815 if command:
816 changesets = 1
816 changesets = 1
817 if noupdate:
817 if noupdate:
818 try:
818 try:
819 node = state['current'][0]
819 node = state['current'][0]
820 except LookupError:
820 except LookupError:
821 raise error.Abort(_('current bisect revision is unknown - '
821 raise error.Abort(_('current bisect revision is unknown - '
822 'start a new bisect to fix'))
822 'start a new bisect to fix'))
823 else:
823 else:
824 node, p2 = repo.dirstate.parents()
824 node, p2 = repo.dirstate.parents()
825 if p2 != nullid:
825 if p2 != nullid:
826 raise error.Abort(_('current bisect revision is a merge'))
826 raise error.Abort(_('current bisect revision is a merge'))
827 if rev:
827 if rev:
828 node = repo[scmutil.revsingle(repo, rev, node)].node()
828 node = repo[scmutil.revsingle(repo, rev, node)].node()
829 try:
829 try:
830 while changesets:
830 while changesets:
831 # update state
831 # update state
832 state['current'] = [node]
832 state['current'] = [node]
833 hbisect.save_state(repo, state)
833 hbisect.save_state(repo, state)
834 status = ui.system(command, environ={'HG_NODE': hex(node)},
834 status = ui.system(command, environ={'HG_NODE': hex(node)},
835 blockedtag='bisect_check')
835 blockedtag='bisect_check')
836 if status == 125:
836 if status == 125:
837 transition = "skip"
837 transition = "skip"
838 elif status == 0:
838 elif status == 0:
839 transition = "good"
839 transition = "good"
840 # status < 0 means process was killed
840 # status < 0 means process was killed
841 elif status == 127:
841 elif status == 127:
842 raise error.Abort(_("failed to execute %s") % command)
842 raise error.Abort(_("failed to execute %s") % command)
843 elif status < 0:
843 elif status < 0:
844 raise error.Abort(_("%s killed") % command)
844 raise error.Abort(_("%s killed") % command)
845 else:
845 else:
846 transition = "bad"
846 transition = "bad"
847 state[transition].append(node)
847 state[transition].append(node)
848 ctx = repo[node]
848 ctx = repo[node]
849 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
849 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
850 hbisect.checkstate(state)
850 hbisect.checkstate(state)
851 # bisect
851 # bisect
852 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
852 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
853 # update to next check
853 # update to next check
854 node = nodes[0]
854 node = nodes[0]
855 mayupdate(repo, node, show_stats=False)
855 mayupdate(repo, node, show_stats=False)
856 finally:
856 finally:
857 state['current'] = [node]
857 state['current'] = [node]
858 hbisect.save_state(repo, state)
858 hbisect.save_state(repo, state)
859 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
859 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
860 return
860 return
861
861
862 hbisect.checkstate(state)
862 hbisect.checkstate(state)
863
863
864 # actually bisect
864 # actually bisect
865 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
865 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
866 if extend:
866 if extend:
867 if not changesets:
867 if not changesets:
868 extendnode = hbisect.extendrange(repo, state, nodes, good)
868 extendnode = hbisect.extendrange(repo, state, nodes, good)
869 if extendnode is not None:
869 if extendnode is not None:
870 ui.write(_("Extending search to changeset %d:%s\n")
870 ui.write(_("Extending search to changeset %d:%s\n")
871 % (extendnode.rev(), extendnode))
871 % (extendnode.rev(), extendnode))
872 state['current'] = [extendnode.node()]
872 state['current'] = [extendnode.node()]
873 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
874 return mayupdate(repo, extendnode.node())
874 return mayupdate(repo, extendnode.node())
875 raise error.Abort(_("nothing to extend"))
875 raise error.Abort(_("nothing to extend"))
876
876
877 if changesets == 0:
877 if changesets == 0:
878 hbisect.printresult(ui, repo, state, displayer, nodes, good)
878 hbisect.printresult(ui, repo, state, displayer, nodes, good)
879 else:
879 else:
880 assert len(nodes) == 1 # only a single node can be tested next
880 assert len(nodes) == 1 # only a single node can be tested next
881 node = nodes[0]
881 node = nodes[0]
882 # compute the approximate number of remaining tests
882 # compute the approximate number of remaining tests
883 tests, size = 0, 2
883 tests, size = 0, 2
884 while size <= changesets:
884 while size <= changesets:
885 tests, size = tests + 1, size * 2
885 tests, size = tests + 1, size * 2
886 rev = repo.changelog.rev(node)
886 rev = repo.changelog.rev(node)
887 ui.write(_("Testing changeset %d:%s "
887 ui.write(_("Testing changeset %d:%s "
888 "(%d changesets remaining, ~%d tests)\n")
888 "(%d changesets remaining, ~%d tests)\n")
889 % (rev, short(node), changesets, tests))
889 % (rev, short(node), changesets, tests))
890 state['current'] = [node]
890 state['current'] = [node]
891 hbisect.save_state(repo, state)
891 hbisect.save_state(repo, state)
892 return mayupdate(repo, node)
892 return mayupdate(repo, node)
893
893
894 @command('bookmarks|bookmark',
894 @command('bookmarks|bookmark',
895 [('f', 'force', False, _('force')),
895 [('f', 'force', False, _('force')),
896 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
896 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
897 ('d', 'delete', False, _('delete a given bookmark')),
897 ('d', 'delete', False, _('delete a given bookmark')),
898 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
898 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
899 ('i', 'inactive', False, _('mark a bookmark inactive')),
899 ('i', 'inactive', False, _('mark a bookmark inactive')),
900 ] + formatteropts,
900 ] + formatteropts,
901 _('hg bookmarks [OPTIONS]... [NAME]...'))
901 _('hg bookmarks [OPTIONS]... [NAME]...'))
902 def bookmark(ui, repo, *names, **opts):
902 def bookmark(ui, repo, *names, **opts):
903 '''create a new bookmark or list existing bookmarks
903 '''create a new bookmark or list existing bookmarks
904
904
905 Bookmarks are labels on changesets to help track lines of development.
905 Bookmarks are labels on changesets to help track lines of development.
906 Bookmarks are unversioned and can be moved, renamed and deleted.
906 Bookmarks are unversioned and can be moved, renamed and deleted.
907 Deleting or moving a bookmark has no effect on the associated changesets.
907 Deleting or moving a bookmark has no effect on the associated changesets.
908
908
909 Creating or updating to a bookmark causes it to be marked as 'active'.
909 Creating or updating to a bookmark causes it to be marked as 'active'.
910 The active bookmark is indicated with a '*'.
910 The active bookmark is indicated with a '*'.
911 When a commit is made, the active bookmark will advance to the new commit.
911 When a commit is made, the active bookmark will advance to the new commit.
912 A plain :hg:`update` will also advance an active bookmark, if possible.
912 A plain :hg:`update` will also advance an active bookmark, if possible.
913 Updating away from a bookmark will cause it to be deactivated.
913 Updating away from a bookmark will cause it to be deactivated.
914
914
915 Bookmarks can be pushed and pulled between repositories (see
915 Bookmarks can be pushed and pulled between repositories (see
916 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
916 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
917 diverged, a new 'divergent bookmark' of the form 'name@path' will
917 diverged, a new 'divergent bookmark' of the form 'name@path' will
918 be created. Using :hg:`merge` will resolve the divergence.
918 be created. Using :hg:`merge` will resolve the divergence.
919
919
920 A bookmark named '@' has the special property that :hg:`clone` will
920 A bookmark named '@' has the special property that :hg:`clone` will
921 check it out by default if it exists.
921 check it out by default if it exists.
922
922
923 .. container:: verbose
923 .. container:: verbose
924
924
925 Examples:
925 Examples:
926
926
927 - create an active bookmark for a new line of development::
927 - create an active bookmark for a new line of development::
928
928
929 hg book new-feature
929 hg book new-feature
930
930
931 - create an inactive bookmark as a place marker::
931 - create an inactive bookmark as a place marker::
932
932
933 hg book -i reviewed
933 hg book -i reviewed
934
934
935 - create an inactive bookmark on another changeset::
935 - create an inactive bookmark on another changeset::
936
936
937 hg book -r .^ tested
937 hg book -r .^ tested
938
938
939 - rename bookmark turkey to dinner::
939 - rename bookmark turkey to dinner::
940
940
941 hg book -m turkey dinner
941 hg book -m turkey dinner
942
942
943 - move the '@' bookmark from another branch::
943 - move the '@' bookmark from another branch::
944
944
945 hg book -f @
945 hg book -f @
946 '''
946 '''
947 opts = pycompat.byteskwargs(opts)
947 opts = pycompat.byteskwargs(opts)
948 force = opts.get('force')
948 force = opts.get('force')
949 rev = opts.get('rev')
949 rev = opts.get('rev')
950 delete = opts.get('delete')
950 delete = opts.get('delete')
951 rename = opts.get('rename')
951 rename = opts.get('rename')
952 inactive = opts.get('inactive')
952 inactive = opts.get('inactive')
953
953
954 if delete and rename:
954 if delete and rename:
955 raise error.Abort(_("--delete and --rename are incompatible"))
955 raise error.Abort(_("--delete and --rename are incompatible"))
956 if delete and rev:
956 if delete and rev:
957 raise error.Abort(_("--rev is incompatible with --delete"))
957 raise error.Abort(_("--rev is incompatible with --delete"))
958 if rename and rev:
958 if rename and rev:
959 raise error.Abort(_("--rev is incompatible with --rename"))
959 raise error.Abort(_("--rev is incompatible with --rename"))
960 if not names and (delete or rev):
960 if not names and (delete or rev):
961 raise error.Abort(_("bookmark name required"))
961 raise error.Abort(_("bookmark name required"))
962
962
963 if delete or rename or names or inactive:
963 if delete or rename or names or inactive:
964 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
964 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
965 if delete:
965 if delete:
966 bookmarks.delete(repo, tr, names)
966 bookmarks.delete(repo, tr, names)
967 elif rename:
967 elif rename:
968 if not names:
968 if not names:
969 raise error.Abort(_("new bookmark name required"))
969 raise error.Abort(_("new bookmark name required"))
970 elif len(names) > 1:
970 elif len(names) > 1:
971 raise error.Abort(_("only one new bookmark name allowed"))
971 raise error.Abort(_("only one new bookmark name allowed"))
972 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
972 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
973 elif names:
973 elif names:
974 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
974 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
975 elif inactive:
975 elif inactive:
976 if len(repo._bookmarks) == 0:
976 if len(repo._bookmarks) == 0:
977 ui.status(_("no bookmarks set\n"))
977 ui.status(_("no bookmarks set\n"))
978 elif not repo._activebookmark:
978 elif not repo._activebookmark:
979 ui.status(_("no active bookmark\n"))
979 ui.status(_("no active bookmark\n"))
980 else:
980 else:
981 bookmarks.deactivate(repo)
981 bookmarks.deactivate(repo)
982 else: # show bookmarks
982 else: # show bookmarks
983 bookmarks.printbookmarks(ui, repo, **opts)
983 bookmarks.printbookmarks(ui, repo, **opts)
984
984
985 @command('branch',
985 @command('branch',
986 [('f', 'force', None,
986 [('f', 'force', None,
987 _('set branch name even if it shadows an existing branch')),
987 _('set branch name even if it shadows an existing branch')),
988 ('C', 'clean', None, _('reset branch name to parent branch name'))],
988 ('C', 'clean', None, _('reset branch name to parent branch name'))],
989 _('[-fC] [NAME]'))
989 _('[-fC] [NAME]'))
990 def branch(ui, repo, label=None, **opts):
990 def branch(ui, repo, label=None, **opts):
991 """set or show the current branch name
991 """set or show the current branch name
992
992
993 .. note::
993 .. note::
994
994
995 Branch names are permanent and global. Use :hg:`bookmark` to create a
995 Branch names are permanent and global. Use :hg:`bookmark` to create a
996 light-weight bookmark instead. See :hg:`help glossary` for more
996 light-weight bookmark instead. See :hg:`help glossary` for more
997 information about named branches and bookmarks.
997 information about named branches and bookmarks.
998
998
999 With no argument, show the current branch name. With one argument,
999 With no argument, show the current branch name. With one argument,
1000 set the working directory branch name (the branch will not exist
1000 set the working directory branch name (the branch will not exist
1001 in the repository until the next commit). Standard practice
1001 in the repository until the next commit). Standard practice
1002 recommends that primary development take place on the 'default'
1002 recommends that primary development take place on the 'default'
1003 branch.
1003 branch.
1004
1004
1005 Unless -f/--force is specified, branch will not let you set a
1005 Unless -f/--force is specified, branch will not let you set a
1006 branch name that already exists.
1006 branch name that already exists.
1007
1007
1008 Use -C/--clean to reset the working directory branch to that of
1008 Use -C/--clean to reset the working directory branch to that of
1009 the parent of the working directory, negating a previous branch
1009 the parent of the working directory, negating a previous branch
1010 change.
1010 change.
1011
1011
1012 Use the command :hg:`update` to switch to an existing branch. Use
1012 Use the command :hg:`update` to switch to an existing branch. Use
1013 :hg:`commit --close-branch` to mark this branch head as closed.
1013 :hg:`commit --close-branch` to mark this branch head as closed.
1014 When all heads of a branch are closed, the branch will be
1014 When all heads of a branch are closed, the branch will be
1015 considered closed.
1015 considered closed.
1016
1016
1017 Returns 0 on success.
1017 Returns 0 on success.
1018 """
1018 """
1019 opts = pycompat.byteskwargs(opts)
1019 opts = pycompat.byteskwargs(opts)
1020 if label:
1020 if label:
1021 label = label.strip()
1021 label = label.strip()
1022
1022
1023 if not opts.get('clean') and not label:
1023 if not opts.get('clean') and not label:
1024 ui.write("%s\n" % repo.dirstate.branch())
1024 ui.write("%s\n" % repo.dirstate.branch())
1025 return
1025 return
1026
1026
1027 with repo.wlock():
1027 with repo.wlock():
1028 if opts.get('clean'):
1028 if opts.get('clean'):
1029 label = repo[None].p1().branch()
1029 label = repo[None].p1().branch()
1030 repo.dirstate.setbranch(label)
1030 repo.dirstate.setbranch(label)
1031 ui.status(_('reset working directory to branch %s\n') % label)
1031 ui.status(_('reset working directory to branch %s\n') % label)
1032 elif label:
1032 elif label:
1033 if not opts.get('force') and label in repo.branchmap():
1033 if not opts.get('force') and label in repo.branchmap():
1034 if label not in [p.branch() for p in repo[None].parents()]:
1034 if label not in [p.branch() for p in repo[None].parents()]:
1035 raise error.Abort(_('a branch of the same name already'
1035 raise error.Abort(_('a branch of the same name already'
1036 ' exists'),
1036 ' exists'),
1037 # i18n: "it" refers to an existing branch
1037 # i18n: "it" refers to an existing branch
1038 hint=_("use 'hg update' to switch to it"))
1038 hint=_("use 'hg update' to switch to it"))
1039 scmutil.checknewlabel(repo, label, 'branch')
1039 scmutil.checknewlabel(repo, label, 'branch')
1040 repo.dirstate.setbranch(label)
1040 repo.dirstate.setbranch(label)
1041 ui.status(_('marked working directory as branch %s\n') % label)
1041 ui.status(_('marked working directory as branch %s\n') % label)
1042
1042
1043 # find any open named branches aside from default
1043 # find any open named branches aside from default
1044 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1044 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1045 if n != "default" and not c]
1045 if n != "default" and not c]
1046 if not others:
1046 if not others:
1047 ui.status(_('(branches are permanent and global, '
1047 ui.status(_('(branches are permanent and global, '
1048 'did you want a bookmark?)\n'))
1048 'did you want a bookmark?)\n'))
1049
1049
1050 @command('branches',
1050 @command('branches',
1051 [('a', 'active', False,
1051 [('a', 'active', False,
1052 _('show only branches that have unmerged heads (DEPRECATED)')),
1052 _('show only branches that have unmerged heads (DEPRECATED)')),
1053 ('c', 'closed', False, _('show normal and closed branches')),
1053 ('c', 'closed', False, _('show normal and closed branches')),
1054 ] + formatteropts,
1054 ] + formatteropts,
1055 _('[-c]'))
1055 _('[-c]'))
1056 def branches(ui, repo, active=False, closed=False, **opts):
1056 def branches(ui, repo, active=False, closed=False, **opts):
1057 """list repository named branches
1057 """list repository named branches
1058
1058
1059 List the repository's named branches, indicating which ones are
1059 List the repository's named branches, indicating which ones are
1060 inactive. If -c/--closed is specified, also list branches which have
1060 inactive. If -c/--closed is specified, also list branches which have
1061 been marked closed (see :hg:`commit --close-branch`).
1061 been marked closed (see :hg:`commit --close-branch`).
1062
1062
1063 Use the command :hg:`update` to switch to an existing branch.
1063 Use the command :hg:`update` to switch to an existing branch.
1064
1064
1065 Returns 0.
1065 Returns 0.
1066 """
1066 """
1067
1067
1068 opts = pycompat.byteskwargs(opts)
1068 opts = pycompat.byteskwargs(opts)
1069 ui.pager('branches')
1069 ui.pager('branches')
1070 fm = ui.formatter('branches', opts)
1070 fm = ui.formatter('branches', opts)
1071 hexfunc = fm.hexfunc
1071 hexfunc = fm.hexfunc
1072
1072
1073 allheads = set(repo.heads())
1073 allheads = set(repo.heads())
1074 branches = []
1074 branches = []
1075 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1075 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1076 isactive = not isclosed and bool(set(heads) & allheads)
1076 isactive = not isclosed and bool(set(heads) & allheads)
1077 branches.append((tag, repo[tip], isactive, not isclosed))
1077 branches.append((tag, repo[tip], isactive, not isclosed))
1078 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1078 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1079 reverse=True)
1079 reverse=True)
1080
1080
1081 for tag, ctx, isactive, isopen in branches:
1081 for tag, ctx, isactive, isopen in branches:
1082 if active and not isactive:
1082 if active and not isactive:
1083 continue
1083 continue
1084 if isactive:
1084 if isactive:
1085 label = 'branches.active'
1085 label = 'branches.active'
1086 notice = ''
1086 notice = ''
1087 elif not isopen:
1087 elif not isopen:
1088 if not closed:
1088 if not closed:
1089 continue
1089 continue
1090 label = 'branches.closed'
1090 label = 'branches.closed'
1091 notice = _(' (closed)')
1091 notice = _(' (closed)')
1092 else:
1092 else:
1093 label = 'branches.inactive'
1093 label = 'branches.inactive'
1094 notice = _(' (inactive)')
1094 notice = _(' (inactive)')
1095 current = (tag == repo.dirstate.branch())
1095 current = (tag == repo.dirstate.branch())
1096 if current:
1096 if current:
1097 label = 'branches.current'
1097 label = 'branches.current'
1098
1098
1099 fm.startitem()
1099 fm.startitem()
1100 fm.write('branch', '%s', tag, label=label)
1100 fm.write('branch', '%s', tag, label=label)
1101 rev = ctx.rev()
1101 rev = ctx.rev()
1102 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1102 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1103 fmt = ' ' * padsize + ' %d:%s'
1103 fmt = ' ' * padsize + ' %d:%s'
1104 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1104 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1105 label='log.changeset changeset.%s' % ctx.phasestr())
1105 label='log.changeset changeset.%s' % ctx.phasestr())
1106 fm.context(ctx=ctx)
1106 fm.context(ctx=ctx)
1107 fm.data(active=isactive, closed=not isopen, current=current)
1107 fm.data(active=isactive, closed=not isopen, current=current)
1108 if not ui.quiet:
1108 if not ui.quiet:
1109 fm.plain(notice)
1109 fm.plain(notice)
1110 fm.plain('\n')
1110 fm.plain('\n')
1111 fm.end()
1111 fm.end()
1112
1112
1113 @command('bundle',
1113 @command('bundle',
1114 [('f', 'force', None, _('run even when the destination is unrelated')),
1114 [('f', 'force', None, _('run even when the destination is unrelated')),
1115 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1115 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1116 _('REV')),
1116 _('REV')),
1117 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1117 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1118 _('BRANCH')),
1118 _('BRANCH')),
1119 ('', 'base', [],
1119 ('', 'base', [],
1120 _('a base changeset assumed to be available at the destination'),
1120 _('a base changeset assumed to be available at the destination'),
1121 _('REV')),
1121 _('REV')),
1122 ('a', 'all', None, _('bundle all changesets in the repository')),
1122 ('a', 'all', None, _('bundle all changesets in the repository')),
1123 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1123 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1124 ] + remoteopts,
1124 ] + remoteopts,
1125 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1125 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1126 def bundle(ui, repo, fname, dest=None, **opts):
1126 def bundle(ui, repo, fname, dest=None, **opts):
1127 """create a bundle file
1127 """create a bundle file
1128
1128
1129 Generate a bundle file containing data to be added to a repository.
1129 Generate a bundle file containing data to be added to a repository.
1130
1130
1131 To create a bundle containing all changesets, use -a/--all
1131 To create a bundle containing all changesets, use -a/--all
1132 (or --base null). Otherwise, hg assumes the destination will have
1132 (or --base null). Otherwise, hg assumes the destination will have
1133 all the nodes you specify with --base parameters. Otherwise, hg
1133 all the nodes you specify with --base parameters. Otherwise, hg
1134 will assume the repository has all the nodes in destination, or
1134 will assume the repository has all the nodes in destination, or
1135 default-push/default if no destination is specified.
1135 default-push/default if no destination is specified.
1136
1136
1137 You can change bundle format with the -t/--type option. See
1137 You can change bundle format with the -t/--type option. See
1138 :hg:`help bundlespec` for documentation on this format. By default,
1138 :hg:`help bundlespec` for documentation on this format. By default,
1139 the most appropriate format is used and compression defaults to
1139 the most appropriate format is used and compression defaults to
1140 bzip2.
1140 bzip2.
1141
1141
1142 The bundle file can then be transferred using conventional means
1142 The bundle file can then be transferred using conventional means
1143 and applied to another repository with the unbundle or pull
1143 and applied to another repository with the unbundle or pull
1144 command. This is useful when direct push and pull are not
1144 command. This is useful when direct push and pull are not
1145 available or when exporting an entire repository is undesirable.
1145 available or when exporting an entire repository is undesirable.
1146
1146
1147 Applying bundles preserves all changeset contents including
1147 Applying bundles preserves all changeset contents including
1148 permissions, copy/rename information, and revision history.
1148 permissions, copy/rename information, and revision history.
1149
1149
1150 Returns 0 on success, 1 if no changes found.
1150 Returns 0 on success, 1 if no changes found.
1151 """
1151 """
1152 opts = pycompat.byteskwargs(opts)
1152 opts = pycompat.byteskwargs(opts)
1153 revs = None
1153 revs = None
1154 if 'rev' in opts:
1154 if 'rev' in opts:
1155 revstrings = opts['rev']
1155 revstrings = opts['rev']
1156 revs = scmutil.revrange(repo, revstrings)
1156 revs = scmutil.revrange(repo, revstrings)
1157 if revstrings and not revs:
1157 if revstrings and not revs:
1158 raise error.Abort(_('no commits to bundle'))
1158 raise error.Abort(_('no commits to bundle'))
1159
1159
1160 bundletype = opts.get('type', 'bzip2').lower()
1160 bundletype = opts.get('type', 'bzip2').lower()
1161 try:
1161 try:
1162 bcompression, cgversion, params = exchange.parsebundlespec(
1162 bcompression, cgversion, params = exchange.parsebundlespec(
1163 repo, bundletype, strict=False)
1163 repo, bundletype, strict=False)
1164 except error.UnsupportedBundleSpecification as e:
1164 except error.UnsupportedBundleSpecification as e:
1165 raise error.Abort(str(e),
1165 raise error.Abort(str(e),
1166 hint=_("see 'hg help bundlespec' for supported "
1166 hint=_("see 'hg help bundlespec' for supported "
1167 "values for --type"))
1167 "values for --type"))
1168
1168
1169 # Packed bundles are a pseudo bundle format for now.
1169 # Packed bundles are a pseudo bundle format for now.
1170 if cgversion == 's1':
1170 if cgversion == 's1':
1171 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1171 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1172 hint=_("use 'hg debugcreatestreamclonebundle'"))
1172 hint=_("use 'hg debugcreatestreamclonebundle'"))
1173
1173
1174 if opts.get('all'):
1174 if opts.get('all'):
1175 if dest:
1175 if dest:
1176 raise error.Abort(_("--all is incompatible with specifying "
1176 raise error.Abort(_("--all is incompatible with specifying "
1177 "a destination"))
1177 "a destination"))
1178 if opts.get('base'):
1178 if opts.get('base'):
1179 ui.warn(_("ignoring --base because --all was specified\n"))
1179 ui.warn(_("ignoring --base because --all was specified\n"))
1180 base = ['null']
1180 base = ['null']
1181 else:
1181 else:
1182 base = scmutil.revrange(repo, opts.get('base'))
1182 base = scmutil.revrange(repo, opts.get('base'))
1183 if cgversion not in changegroup.supportedoutgoingversions(repo):
1183 if cgversion not in changegroup.supportedoutgoingversions(repo):
1184 raise error.Abort(_("repository does not support bundle version %s") %
1184 raise error.Abort(_("repository does not support bundle version %s") %
1185 cgversion)
1185 cgversion)
1186
1186
1187 if base:
1187 if base:
1188 if dest:
1188 if dest:
1189 raise error.Abort(_("--base is incompatible with specifying "
1189 raise error.Abort(_("--base is incompatible with specifying "
1190 "a destination"))
1190 "a destination"))
1191 common = [repo.lookup(rev) for rev in base]
1191 common = [repo.lookup(rev) for rev in base]
1192 heads = revs and map(repo.lookup, revs) or None
1192 heads = revs and map(repo.lookup, revs) or None
1193 outgoing = discovery.outgoing(repo, common, heads)
1193 outgoing = discovery.outgoing(repo, common, heads)
1194 else:
1194 else:
1195 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1195 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1196 dest, branches = hg.parseurl(dest, opts.get('branch'))
1196 dest, branches = hg.parseurl(dest, opts.get('branch'))
1197 other = hg.peer(repo, opts, dest)
1197 other = hg.peer(repo, opts, dest)
1198 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1198 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1199 heads = revs and map(repo.lookup, revs) or revs
1199 heads = revs and map(repo.lookup, revs) or revs
1200 outgoing = discovery.findcommonoutgoing(repo, other,
1200 outgoing = discovery.findcommonoutgoing(repo, other,
1201 onlyheads=heads,
1201 onlyheads=heads,
1202 force=opts.get('force'),
1202 force=opts.get('force'),
1203 portable=True)
1203 portable=True)
1204
1204
1205 if not outgoing.missing:
1205 if not outgoing.missing:
1206 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1206 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1207 return 1
1207 return 1
1208
1208
1209 if cgversion == '01': #bundle1
1209 if cgversion == '01': #bundle1
1210 if bcompression is None:
1210 if bcompression is None:
1211 bcompression = 'UN'
1211 bcompression = 'UN'
1212 bversion = 'HG10' + bcompression
1212 bversion = 'HG10' + bcompression
1213 bcompression = None
1213 bcompression = None
1214 elif cgversion in ('02', '03'):
1214 elif cgversion in ('02', '03'):
1215 bversion = 'HG20'
1215 bversion = 'HG20'
1216 else:
1216 else:
1217 raise error.ProgrammingError(
1217 raise error.ProgrammingError(
1218 'bundle: unexpected changegroup version %s' % cgversion)
1218 'bundle: unexpected changegroup version %s' % cgversion)
1219
1219
1220 # TODO compression options should be derived from bundlespec parsing.
1220 # TODO compression options should be derived from bundlespec parsing.
1221 # This is a temporary hack to allow adjusting bundle compression
1221 # This is a temporary hack to allow adjusting bundle compression
1222 # level without a) formalizing the bundlespec changes to declare it
1222 # level without a) formalizing the bundlespec changes to declare it
1223 # b) introducing a command flag.
1223 # b) introducing a command flag.
1224 compopts = {}
1224 compopts = {}
1225 complevel = ui.configint('experimental', 'bundlecomplevel')
1225 complevel = ui.configint('experimental', 'bundlecomplevel')
1226 if complevel is not None:
1226 if complevel is not None:
1227 compopts['level'] = complevel
1227 compopts['level'] = complevel
1228
1228
1229
1229
1230 contentopts = {'cg.version': cgversion}
1230 contentopts = {'cg.version': cgversion}
1231 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1231 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1232 contentopts['obsolescence'] = True
1232 contentopts['obsolescence'] = True
1233 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1233 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1234 contentopts, compression=bcompression,
1234 contentopts, compression=bcompression,
1235 compopts=compopts)
1235 compopts=compopts)
1236
1236
1237 @command('cat',
1237 @command('cat',
1238 [('o', 'output', '',
1238 [('o', 'output', '',
1239 _('print output to file with formatted name'), _('FORMAT')),
1239 _('print output to file with formatted name'), _('FORMAT')),
1240 ('r', 'rev', '', _('print the given revision'), _('REV')),
1240 ('r', 'rev', '', _('print the given revision'), _('REV')),
1241 ('', 'decode', None, _('apply any matching decode filter')),
1241 ('', 'decode', None, _('apply any matching decode filter')),
1242 ] + walkopts + formatteropts,
1242 ] + walkopts + formatteropts,
1243 _('[OPTION]... FILE...'),
1243 _('[OPTION]... FILE...'),
1244 inferrepo=True)
1244 inferrepo=True)
1245 def cat(ui, repo, file1, *pats, **opts):
1245 def cat(ui, repo, file1, *pats, **opts):
1246 """output the current or given revision of files
1246 """output the current or given revision of files
1247
1247
1248 Print the specified files as they were at the given revision. If
1248 Print the specified files as they were at the given revision. If
1249 no revision is given, the parent of the working directory is used.
1249 no revision is given, the parent of the working directory is used.
1250
1250
1251 Output may be to a file, in which case the name of the file is
1251 Output may be to a file, in which case the name of the file is
1252 given using a format string. The formatting rules as follows:
1252 given using a format string. The formatting rules as follows:
1253
1253
1254 :``%%``: literal "%" character
1254 :``%%``: literal "%" character
1255 :``%s``: basename of file being printed
1255 :``%s``: basename of file being printed
1256 :``%d``: dirname of file being printed, or '.' if in repository root
1256 :``%d``: dirname of file being printed, or '.' if in repository root
1257 :``%p``: root-relative path name of file being printed
1257 :``%p``: root-relative path name of file being printed
1258 :``%H``: changeset hash (40 hexadecimal digits)
1258 :``%H``: changeset hash (40 hexadecimal digits)
1259 :``%R``: changeset revision number
1259 :``%R``: changeset revision number
1260 :``%h``: short-form changeset hash (12 hexadecimal digits)
1260 :``%h``: short-form changeset hash (12 hexadecimal digits)
1261 :``%r``: zero-padded changeset revision number
1261 :``%r``: zero-padded changeset revision number
1262 :``%b``: basename of the exporting repository
1262 :``%b``: basename of the exporting repository
1263
1263
1264 Returns 0 on success.
1264 Returns 0 on success.
1265 """
1265 """
1266 ctx = scmutil.revsingle(repo, opts.get('rev'))
1266 ctx = scmutil.revsingle(repo, opts.get('rev'))
1267 m = scmutil.match(ctx, (file1,) + pats, opts)
1267 m = scmutil.match(ctx, (file1,) + pats, opts)
1268 fntemplate = opts.pop('output', '')
1268 fntemplate = opts.pop('output', '')
1269 if cmdutil.isstdiofilename(fntemplate):
1269 if cmdutil.isstdiofilename(fntemplate):
1270 fntemplate = ''
1270 fntemplate = ''
1271
1271
1272 if fntemplate:
1272 if fntemplate:
1273 fm = formatter.nullformatter(ui, 'cat')
1273 fm = formatter.nullformatter(ui, 'cat')
1274 else:
1274 else:
1275 ui.pager('cat')
1275 ui.pager('cat')
1276 fm = ui.formatter('cat', opts)
1276 fm = ui.formatter('cat', opts)
1277 with fm:
1277 with fm:
1278 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1278 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1279
1279
1280 @command('^clone',
1280 @command('^clone',
1281 [('U', 'noupdate', None, _('the clone will include an empty working '
1281 [('U', 'noupdate', None, _('the clone will include an empty working '
1282 'directory (only a repository)')),
1282 'directory (only a repository)')),
1283 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1283 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1284 _('REV')),
1284 _('REV')),
1285 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1285 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1286 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1286 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1287 ('', 'pull', None, _('use pull protocol to copy metadata')),
1287 ('', 'pull', None, _('use pull protocol to copy metadata')),
1288 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1288 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1289 ] + remoteopts,
1289 ] + remoteopts,
1290 _('[OPTION]... SOURCE [DEST]'),
1290 _('[OPTION]... SOURCE [DEST]'),
1291 norepo=True)
1291 norepo=True)
1292 def clone(ui, source, dest=None, **opts):
1292 def clone(ui, source, dest=None, **opts):
1293 """make a copy of an existing repository
1293 """make a copy of an existing repository
1294
1294
1295 Create a copy of an existing repository in a new directory.
1295 Create a copy of an existing repository in a new directory.
1296
1296
1297 If no destination directory name is specified, it defaults to the
1297 If no destination directory name is specified, it defaults to the
1298 basename of the source.
1298 basename of the source.
1299
1299
1300 The location of the source is added to the new repository's
1300 The location of the source is added to the new repository's
1301 ``.hg/hgrc`` file, as the default to be used for future pulls.
1301 ``.hg/hgrc`` file, as the default to be used for future pulls.
1302
1302
1303 Only local paths and ``ssh://`` URLs are supported as
1303 Only local paths and ``ssh://`` URLs are supported as
1304 destinations. For ``ssh://`` destinations, no working directory or
1304 destinations. For ``ssh://`` destinations, no working directory or
1305 ``.hg/hgrc`` will be created on the remote side.
1305 ``.hg/hgrc`` will be created on the remote side.
1306
1306
1307 If the source repository has a bookmark called '@' set, that
1307 If the source repository has a bookmark called '@' set, that
1308 revision will be checked out in the new repository by default.
1308 revision will be checked out in the new repository by default.
1309
1309
1310 To check out a particular version, use -u/--update, or
1310 To check out a particular version, use -u/--update, or
1311 -U/--noupdate to create a clone with no working directory.
1311 -U/--noupdate to create a clone with no working directory.
1312
1312
1313 To pull only a subset of changesets, specify one or more revisions
1313 To pull only a subset of changesets, specify one or more revisions
1314 identifiers with -r/--rev or branches with -b/--branch. The
1314 identifiers with -r/--rev or branches with -b/--branch. The
1315 resulting clone will contain only the specified changesets and
1315 resulting clone will contain only the specified changesets and
1316 their ancestors. These options (or 'clone src#rev dest') imply
1316 their ancestors. These options (or 'clone src#rev dest') imply
1317 --pull, even for local source repositories.
1317 --pull, even for local source repositories.
1318
1318
1319 .. note::
1319 .. note::
1320
1320
1321 Specifying a tag will include the tagged changeset but not the
1321 Specifying a tag will include the tagged changeset but not the
1322 changeset containing the tag.
1322 changeset containing the tag.
1323
1323
1324 .. container:: verbose
1324 .. container:: verbose
1325
1325
1326 For efficiency, hardlinks are used for cloning whenever the
1326 For efficiency, hardlinks are used for cloning whenever the
1327 source and destination are on the same filesystem (note this
1327 source and destination are on the same filesystem (note this
1328 applies only to the repository data, not to the working
1328 applies only to the repository data, not to the working
1329 directory). Some filesystems, such as AFS, implement hardlinking
1329 directory). Some filesystems, such as AFS, implement hardlinking
1330 incorrectly, but do not report errors. In these cases, use the
1330 incorrectly, but do not report errors. In these cases, use the
1331 --pull option to avoid hardlinking.
1331 --pull option to avoid hardlinking.
1332
1332
1333 In some cases, you can clone repositories and the working
1333 In some cases, you can clone repositories and the working
1334 directory using full hardlinks with ::
1334 directory using full hardlinks with ::
1335
1335
1336 $ cp -al REPO REPOCLONE
1336 $ cp -al REPO REPOCLONE
1337
1337
1338 This is the fastest way to clone, but it is not always safe. The
1338 This is the fastest way to clone, but it is not always safe. The
1339 operation is not atomic (making sure REPO is not modified during
1339 operation is not atomic (making sure REPO is not modified during
1340 the operation is up to you) and you have to make sure your
1340 the operation is up to you) and you have to make sure your
1341 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1341 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1342 so). Also, this is not compatible with certain extensions that
1342 so). Also, this is not compatible with certain extensions that
1343 place their metadata under the .hg directory, such as mq.
1343 place their metadata under the .hg directory, such as mq.
1344
1344
1345 Mercurial will update the working directory to the first applicable
1345 Mercurial will update the working directory to the first applicable
1346 revision from this list:
1346 revision from this list:
1347
1347
1348 a) null if -U or the source repository has no changesets
1348 a) null if -U or the source repository has no changesets
1349 b) if -u . and the source repository is local, the first parent of
1349 b) if -u . and the source repository is local, the first parent of
1350 the source repository's working directory
1350 the source repository's working directory
1351 c) the changeset specified with -u (if a branch name, this means the
1351 c) the changeset specified with -u (if a branch name, this means the
1352 latest head of that branch)
1352 latest head of that branch)
1353 d) the changeset specified with -r
1353 d) the changeset specified with -r
1354 e) the tipmost head specified with -b
1354 e) the tipmost head specified with -b
1355 f) the tipmost head specified with the url#branch source syntax
1355 f) the tipmost head specified with the url#branch source syntax
1356 g) the revision marked with the '@' bookmark, if present
1356 g) the revision marked with the '@' bookmark, if present
1357 h) the tipmost head of the default branch
1357 h) the tipmost head of the default branch
1358 i) tip
1358 i) tip
1359
1359
1360 When cloning from servers that support it, Mercurial may fetch
1360 When cloning from servers that support it, Mercurial may fetch
1361 pre-generated data from a server-advertised URL. When this is done,
1361 pre-generated data from a server-advertised URL. When this is done,
1362 hooks operating on incoming changesets and changegroups may fire twice,
1362 hooks operating on incoming changesets and changegroups may fire twice,
1363 once for the bundle fetched from the URL and another for any additional
1363 once for the bundle fetched from the URL and another for any additional
1364 data not fetched from this URL. In addition, if an error occurs, the
1364 data not fetched from this URL. In addition, if an error occurs, the
1365 repository may be rolled back to a partial clone. This behavior may
1365 repository may be rolled back to a partial clone. This behavior may
1366 change in future releases. See :hg:`help -e clonebundles` for more.
1366 change in future releases. See :hg:`help -e clonebundles` for more.
1367
1367
1368 Examples:
1368 Examples:
1369
1369
1370 - clone a remote repository to a new directory named hg/::
1370 - clone a remote repository to a new directory named hg/::
1371
1371
1372 hg clone https://www.mercurial-scm.org/repo/hg/
1372 hg clone https://www.mercurial-scm.org/repo/hg/
1373
1373
1374 - create a lightweight local clone::
1374 - create a lightweight local clone::
1375
1375
1376 hg clone project/ project-feature/
1376 hg clone project/ project-feature/
1377
1377
1378 - clone from an absolute path on an ssh server (note double-slash)::
1378 - clone from an absolute path on an ssh server (note double-slash)::
1379
1379
1380 hg clone ssh://user@server//home/projects/alpha/
1380 hg clone ssh://user@server//home/projects/alpha/
1381
1381
1382 - do a high-speed clone over a LAN while checking out a
1382 - do a high-speed clone over a LAN while checking out a
1383 specified version::
1383 specified version::
1384
1384
1385 hg clone --uncompressed http://server/repo -u 1.5
1385 hg clone --uncompressed http://server/repo -u 1.5
1386
1386
1387 - create a repository without changesets after a particular revision::
1387 - create a repository without changesets after a particular revision::
1388
1388
1389 hg clone -r 04e544 experimental/ good/
1389 hg clone -r 04e544 experimental/ good/
1390
1390
1391 - clone (and track) a particular named branch::
1391 - clone (and track) a particular named branch::
1392
1392
1393 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1393 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1394
1394
1395 See :hg:`help urls` for details on specifying URLs.
1395 See :hg:`help urls` for details on specifying URLs.
1396
1396
1397 Returns 0 on success.
1397 Returns 0 on success.
1398 """
1398 """
1399 opts = pycompat.byteskwargs(opts)
1399 opts = pycompat.byteskwargs(opts)
1400 if opts.get('noupdate') and opts.get('updaterev'):
1400 if opts.get('noupdate') and opts.get('updaterev'):
1401 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1401 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1402
1402
1403 r = hg.clone(ui, opts, source, dest,
1403 r = hg.clone(ui, opts, source, dest,
1404 pull=opts.get('pull'),
1404 pull=opts.get('pull'),
1405 stream=opts.get('uncompressed'),
1405 stream=opts.get('uncompressed'),
1406 rev=opts.get('rev'),
1406 rev=opts.get('rev'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1408 branch=opts.get('branch'),
1408 branch=opts.get('branch'),
1409 shareopts=opts.get('shareopts'))
1409 shareopts=opts.get('shareopts'))
1410
1410
1411 return r is None
1411 return r is None
1412
1412
1413 @command('^commit|ci',
1413 @command('^commit|ci',
1414 [('A', 'addremove', None,
1414 [('A', 'addremove', None,
1415 _('mark new/missing files as added/removed before committing')),
1415 _('mark new/missing files as added/removed before committing')),
1416 ('', 'close-branch', None,
1416 ('', 'close-branch', None,
1417 _('mark a branch head as closed')),
1417 _('mark a branch head as closed')),
1418 ('', 'amend', None, _('amend the parent of the working directory')),
1418 ('', 'amend', None, _('amend the parent of the working directory')),
1419 ('s', 'secret', None, _('use the secret phase for committing')),
1419 ('s', 'secret', None, _('use the secret phase for committing')),
1420 ('e', 'edit', None, _('invoke editor on commit messages')),
1420 ('e', 'edit', None, _('invoke editor on commit messages')),
1421 ('i', 'interactive', None, _('use interactive mode')),
1421 ('i', 'interactive', None, _('use interactive mode')),
1422 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1422 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1423 _('[OPTION]... [FILE]...'),
1423 _('[OPTION]... [FILE]...'),
1424 inferrepo=True)
1424 inferrepo=True)
1425 def commit(ui, repo, *pats, **opts):
1425 def commit(ui, repo, *pats, **opts):
1426 """commit the specified files or all outstanding changes
1426 """commit the specified files or all outstanding changes
1427
1427
1428 Commit changes to the given files into the repository. Unlike a
1428 Commit changes to the given files into the repository. Unlike a
1429 centralized SCM, this operation is a local operation. See
1429 centralized SCM, this operation is a local operation. See
1430 :hg:`push` for a way to actively distribute your changes.
1430 :hg:`push` for a way to actively distribute your changes.
1431
1431
1432 If a list of files is omitted, all changes reported by :hg:`status`
1432 If a list of files is omitted, all changes reported by :hg:`status`
1433 will be committed.
1433 will be committed.
1434
1434
1435 If you are committing the result of a merge, do not provide any
1435 If you are committing the result of a merge, do not provide any
1436 filenames or -I/-X filters.
1436 filenames or -I/-X filters.
1437
1437
1438 If no commit message is specified, Mercurial starts your
1438 If no commit message is specified, Mercurial starts your
1439 configured editor where you can enter a message. In case your
1439 configured editor where you can enter a message. In case your
1440 commit fails, you will find a backup of your message in
1440 commit fails, you will find a backup of your message in
1441 ``.hg/last-message.txt``.
1441 ``.hg/last-message.txt``.
1442
1442
1443 The --close-branch flag can be used to mark the current branch
1443 The --close-branch flag can be used to mark the current branch
1444 head closed. When all heads of a branch are closed, the branch
1444 head closed. When all heads of a branch are closed, the branch
1445 will be considered closed and no longer listed.
1445 will be considered closed and no longer listed.
1446
1446
1447 The --amend flag can be used to amend the parent of the
1447 The --amend flag can be used to amend the parent of the
1448 working directory with a new commit that contains the changes
1448 working directory with a new commit that contains the changes
1449 in the parent in addition to those currently reported by :hg:`status`,
1449 in the parent in addition to those currently reported by :hg:`status`,
1450 if there are any. The old commit is stored in a backup bundle in
1450 if there are any. The old commit is stored in a backup bundle in
1451 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1451 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1452 on how to restore it).
1452 on how to restore it).
1453
1453
1454 Message, user and date are taken from the amended commit unless
1454 Message, user and date are taken from the amended commit unless
1455 specified. When a message isn't specified on the command line,
1455 specified. When a message isn't specified on the command line,
1456 the editor will open with the message of the amended commit.
1456 the editor will open with the message of the amended commit.
1457
1457
1458 It is not possible to amend public changesets (see :hg:`help phases`)
1458 It is not possible to amend public changesets (see :hg:`help phases`)
1459 or changesets that have children.
1459 or changesets that have children.
1460
1460
1461 See :hg:`help dates` for a list of formats valid for -d/--date.
1461 See :hg:`help dates` for a list of formats valid for -d/--date.
1462
1462
1463 Returns 0 on success, 1 if nothing changed.
1463 Returns 0 on success, 1 if nothing changed.
1464
1464
1465 .. container:: verbose
1465 .. container:: verbose
1466
1466
1467 Examples:
1467 Examples:
1468
1468
1469 - commit all files ending in .py::
1469 - commit all files ending in .py::
1470
1470
1471 hg commit --include "set:**.py"
1471 hg commit --include "set:**.py"
1472
1472
1473 - commit all non-binary files::
1473 - commit all non-binary files::
1474
1474
1475 hg commit --exclude "set:binary()"
1475 hg commit --exclude "set:binary()"
1476
1476
1477 - amend the current commit and set the date to now::
1477 - amend the current commit and set the date to now::
1478
1478
1479 hg commit --amend --date now
1479 hg commit --amend --date now
1480 """
1480 """
1481 wlock = lock = None
1481 wlock = lock = None
1482 try:
1482 try:
1483 wlock = repo.wlock()
1483 wlock = repo.wlock()
1484 lock = repo.lock()
1484 lock = repo.lock()
1485 return _docommit(ui, repo, *pats, **opts)
1485 return _docommit(ui, repo, *pats, **opts)
1486 finally:
1486 finally:
1487 release(lock, wlock)
1487 release(lock, wlock)
1488
1488
1489 def _docommit(ui, repo, *pats, **opts):
1489 def _docommit(ui, repo, *pats, **opts):
1490 if opts.get(r'interactive'):
1490 if opts.get(r'interactive'):
1491 opts.pop(r'interactive')
1491 opts.pop(r'interactive')
1492 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1492 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1493 cmdutil.recordfilter, *pats,
1493 cmdutil.recordfilter, *pats,
1494 **opts)
1494 **opts)
1495 # ret can be 0 (no changes to record) or the value returned by
1495 # ret can be 0 (no changes to record) or the value returned by
1496 # commit(), 1 if nothing changed or None on success.
1496 # commit(), 1 if nothing changed or None on success.
1497 return 1 if ret == 0 else ret
1497 return 1 if ret == 0 else ret
1498
1498
1499 opts = pycompat.byteskwargs(opts)
1499 opts = pycompat.byteskwargs(opts)
1500 if opts.get('subrepos'):
1500 if opts.get('subrepos'):
1501 if opts.get('amend'):
1501 if opts.get('amend'):
1502 raise error.Abort(_('cannot amend with --subrepos'))
1502 raise error.Abort(_('cannot amend with --subrepos'))
1503 # Let --subrepos on the command line override config setting.
1503 # Let --subrepos on the command line override config setting.
1504 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1504 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1505
1505
1506 cmdutil.checkunfinished(repo, commit=True)
1506 cmdutil.checkunfinished(repo, commit=True)
1507
1507
1508 branch = repo[None].branch()
1508 branch = repo[None].branch()
1509 bheads = repo.branchheads(branch)
1509 bheads = repo.branchheads(branch)
1510
1510
1511 extra = {}
1511 extra = {}
1512 if opts.get('close_branch'):
1512 if opts.get('close_branch'):
1513 extra['close'] = 1
1513 extra['close'] = 1
1514
1514
1515 if not bheads:
1515 if not bheads:
1516 raise error.Abort(_('can only close branch heads'))
1516 raise error.Abort(_('can only close branch heads'))
1517 elif opts.get('amend'):
1517 elif opts.get('amend'):
1518 if repo[None].parents()[0].p1().branch() != branch and \
1518 if repo[None].parents()[0].p1().branch() != branch and \
1519 repo[None].parents()[0].p2().branch() != branch:
1519 repo[None].parents()[0].p2().branch() != branch:
1520 raise error.Abort(_('can only close branch heads'))
1520 raise error.Abort(_('can only close branch heads'))
1521
1521
1522 if opts.get('amend'):
1522 if opts.get('amend'):
1523 if ui.configbool('ui', 'commitsubrepos'):
1523 if ui.configbool('ui', 'commitsubrepos'):
1524 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1524 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1525
1525
1526 old = repo['.']
1526 old = repo['.']
1527 if not old.mutable():
1527 if not old.mutable():
1528 raise error.Abort(_('cannot amend public changesets'))
1528 raise error.Abort(_('cannot amend public changesets'))
1529 if len(repo[None].parents()) > 1:
1529 if len(repo[None].parents()) > 1:
1530 raise error.Abort(_('cannot amend while merging'))
1530 raise error.Abort(_('cannot amend while merging'))
1531 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1531 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1532 if not allowunstable and old.children():
1532 if not allowunstable and old.children():
1533 raise error.Abort(_('cannot amend changeset with children'))
1533 raise error.Abort(_('cannot amend changeset with children'))
1534
1534
1535 # Currently histedit gets confused if an amend happens while histedit
1535 # Currently histedit gets confused if an amend happens while histedit
1536 # is in progress. Since we have a checkunfinished command, we are
1536 # is in progress. Since we have a checkunfinished command, we are
1537 # temporarily honoring it.
1537 # temporarily honoring it.
1538 #
1538 #
1539 # Note: eventually this guard will be removed. Please do not expect
1539 # Note: eventually this guard will be removed. Please do not expect
1540 # this behavior to remain.
1540 # this behavior to remain.
1541 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1541 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1542 cmdutil.checkunfinished(repo)
1542 cmdutil.checkunfinished(repo)
1543
1543
1544 # commitfunc is used only for temporary amend commit by cmdutil.amend
1544 # commitfunc is used only for temporary amend commit by cmdutil.amend
1545 def commitfunc(ui, repo, message, match, opts):
1545 def commitfunc(ui, repo, message, match, opts):
1546 return repo.commit(message,
1546 return repo.commit(message,
1547 opts.get('user') or old.user(),
1547 opts.get('user') or old.user(),
1548 opts.get('date') or old.date(),
1548 opts.get('date') or old.date(),
1549 match,
1549 match,
1550 extra=extra)
1550 extra=extra)
1551
1551
1552 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1552 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1553 if node == old.node():
1553 if node == old.node():
1554 ui.status(_("nothing changed\n"))
1554 ui.status(_("nothing changed\n"))
1555 return 1
1555 return 1
1556 else:
1556 else:
1557 def commitfunc(ui, repo, message, match, opts):
1557 def commitfunc(ui, repo, message, match, opts):
1558 overrides = {}
1558 overrides = {}
1559 if opts.get('secret'):
1559 if opts.get('secret'):
1560 overrides[('phases', 'new-commit')] = 'secret'
1560 overrides[('phases', 'new-commit')] = 'secret'
1561
1561
1562 baseui = repo.baseui
1562 baseui = repo.baseui
1563 with baseui.configoverride(overrides, 'commit'):
1563 with baseui.configoverride(overrides, 'commit'):
1564 with ui.configoverride(overrides, 'commit'):
1564 with ui.configoverride(overrides, 'commit'):
1565 editform = cmdutil.mergeeditform(repo[None],
1565 editform = cmdutil.mergeeditform(repo[None],
1566 'commit.normal')
1566 'commit.normal')
1567 editor = cmdutil.getcommiteditor(
1567 editor = cmdutil.getcommiteditor(
1568 editform=editform, **pycompat.strkwargs(opts))
1568 editform=editform, **pycompat.strkwargs(opts))
1569 return repo.commit(message,
1569 return repo.commit(message,
1570 opts.get('user'),
1570 opts.get('user'),
1571 opts.get('date'),
1571 opts.get('date'),
1572 match,
1572 match,
1573 editor=editor,
1573 editor=editor,
1574 extra=extra)
1574 extra=extra)
1575
1575
1576 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1576 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1577
1577
1578 if not node:
1578 if not node:
1579 stat = cmdutil.postcommitstatus(repo, pats, opts)
1579 stat = cmdutil.postcommitstatus(repo, pats, opts)
1580 if stat[3]:
1580 if stat[3]:
1581 ui.status(_("nothing changed (%d missing files, see "
1581 ui.status(_("nothing changed (%d missing files, see "
1582 "'hg status')\n") % len(stat[3]))
1582 "'hg status')\n") % len(stat[3]))
1583 else:
1583 else:
1584 ui.status(_("nothing changed\n"))
1584 ui.status(_("nothing changed\n"))
1585 return 1
1585 return 1
1586
1586
1587 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1587 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1588
1588
1589 @command('config|showconfig|debugconfig',
1589 @command('config|showconfig|debugconfig',
1590 [('u', 'untrusted', None, _('show untrusted configuration options')),
1590 [('u', 'untrusted', None, _('show untrusted configuration options')),
1591 ('e', 'edit', None, _('edit user config')),
1591 ('e', 'edit', None, _('edit user config')),
1592 ('l', 'local', None, _('edit repository config')),
1592 ('l', 'local', None, _('edit repository config')),
1593 ('g', 'global', None, _('edit global config'))] + formatteropts,
1593 ('g', 'global', None, _('edit global config'))] + formatteropts,
1594 _('[-u] [NAME]...'),
1594 _('[-u] [NAME]...'),
1595 optionalrepo=True)
1595 optionalrepo=True)
1596 def config(ui, repo, *values, **opts):
1596 def config(ui, repo, *values, **opts):
1597 """show combined config settings from all hgrc files
1597 """show combined config settings from all hgrc files
1598
1598
1599 With no arguments, print names and values of all config items.
1599 With no arguments, print names and values of all config items.
1600
1600
1601 With one argument of the form section.name, print just the value
1601 With one argument of the form section.name, print just the value
1602 of that config item.
1602 of that config item.
1603
1603
1604 With multiple arguments, print names and values of all config
1604 With multiple arguments, print names and values of all config
1605 items with matching section names.
1605 items with matching section names.
1606
1606
1607 With --edit, start an editor on the user-level config file. With
1607 With --edit, start an editor on the user-level config file. With
1608 --global, edit the system-wide config file. With --local, edit the
1608 --global, edit the system-wide config file. With --local, edit the
1609 repository-level config file.
1609 repository-level config file.
1610
1610
1611 With --debug, the source (filename and line number) is printed
1611 With --debug, the source (filename and line number) is printed
1612 for each config item.
1612 for each config item.
1613
1613
1614 See :hg:`help config` for more information about config files.
1614 See :hg:`help config` for more information about config files.
1615
1615
1616 Returns 0 on success, 1 if NAME does not exist.
1616 Returns 0 on success, 1 if NAME does not exist.
1617
1617
1618 """
1618 """
1619
1619
1620 opts = pycompat.byteskwargs(opts)
1620 opts = pycompat.byteskwargs(opts)
1621 if opts.get('edit') or opts.get('local') or opts.get('global'):
1621 if opts.get('edit') or opts.get('local') or opts.get('global'):
1622 if opts.get('local') and opts.get('global'):
1622 if opts.get('local') and opts.get('global'):
1623 raise error.Abort(_("can't use --local and --global together"))
1623 raise error.Abort(_("can't use --local and --global together"))
1624
1624
1625 if opts.get('local'):
1625 if opts.get('local'):
1626 if not repo:
1626 if not repo:
1627 raise error.Abort(_("can't use --local outside a repository"))
1627 raise error.Abort(_("can't use --local outside a repository"))
1628 paths = [repo.vfs.join('hgrc')]
1628 paths = [repo.vfs.join('hgrc')]
1629 elif opts.get('global'):
1629 elif opts.get('global'):
1630 paths = rcutil.systemrcpath()
1630 paths = rcutil.systemrcpath()
1631 else:
1631 else:
1632 paths = rcutil.userrcpath()
1632 paths = rcutil.userrcpath()
1633
1633
1634 for f in paths:
1634 for f in paths:
1635 if os.path.exists(f):
1635 if os.path.exists(f):
1636 break
1636 break
1637 else:
1637 else:
1638 if opts.get('global'):
1638 if opts.get('global'):
1639 samplehgrc = uimod.samplehgrcs['global']
1639 samplehgrc = uimod.samplehgrcs['global']
1640 elif opts.get('local'):
1640 elif opts.get('local'):
1641 samplehgrc = uimod.samplehgrcs['local']
1641 samplehgrc = uimod.samplehgrcs['local']
1642 else:
1642 else:
1643 samplehgrc = uimod.samplehgrcs['user']
1643 samplehgrc = uimod.samplehgrcs['user']
1644
1644
1645 f = paths[0]
1645 f = paths[0]
1646 fp = open(f, "w")
1646 fp = open(f, "w")
1647 fp.write(samplehgrc)
1647 fp.write(samplehgrc)
1648 fp.close()
1648 fp.close()
1649
1649
1650 editor = ui.geteditor()
1650 editor = ui.geteditor()
1651 ui.system("%s \"%s\"" % (editor, f),
1651 ui.system("%s \"%s\"" % (editor, f),
1652 onerr=error.Abort, errprefix=_("edit failed"),
1652 onerr=error.Abort, errprefix=_("edit failed"),
1653 blockedtag='config_edit')
1653 blockedtag='config_edit')
1654 return
1654 return
1655 ui.pager('config')
1655 ui.pager('config')
1656 fm = ui.formatter('config', opts)
1656 fm = ui.formatter('config', opts)
1657 for t, f in rcutil.rccomponents():
1657 for t, f in rcutil.rccomponents():
1658 if t == 'path':
1658 if t == 'path':
1659 ui.debug('read config from: %s\n' % f)
1659 ui.debug('read config from: %s\n' % f)
1660 elif t == 'items':
1660 elif t == 'items':
1661 for section, name, value, source in f:
1661 for section, name, value, source in f:
1662 ui.debug('set config by: %s\n' % source)
1662 ui.debug('set config by: %s\n' % source)
1663 else:
1663 else:
1664 raise error.ProgrammingError('unknown rctype: %s' % t)
1664 raise error.ProgrammingError('unknown rctype: %s' % t)
1665 untrusted = bool(opts.get('untrusted'))
1665 untrusted = bool(opts.get('untrusted'))
1666 if values:
1666 if values:
1667 sections = [v for v in values if '.' not in v]
1667 sections = [v for v in values if '.' not in v]
1668 items = [v for v in values if '.' in v]
1668 items = [v for v in values if '.' in v]
1669 if len(items) > 1 or items and sections:
1669 if len(items) > 1 or items and sections:
1670 raise error.Abort(_('only one config item permitted'))
1670 raise error.Abort(_('only one config item permitted'))
1671 matched = False
1671 matched = False
1672 for section, name, value in ui.walkconfig(untrusted=untrusted):
1672 for section, name, value in ui.walkconfig(untrusted=untrusted):
1673 source = ui.configsource(section, name, untrusted)
1673 source = ui.configsource(section, name, untrusted)
1674 value = pycompat.bytestr(value)
1674 value = pycompat.bytestr(value)
1675 if fm.isplain():
1675 if fm.isplain():
1676 source = source or 'none'
1676 source = source or 'none'
1677 value = value.replace('\n', '\\n')
1677 value = value.replace('\n', '\\n')
1678 entryname = section + '.' + name
1678 entryname = section + '.' + name
1679 if values:
1679 if values:
1680 for v in values:
1680 for v in values:
1681 if v == section:
1681 if v == section:
1682 fm.startitem()
1682 fm.startitem()
1683 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1683 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1684 fm.write('name value', '%s=%s\n', entryname, value)
1684 fm.write('name value', '%s=%s\n', entryname, value)
1685 matched = True
1685 matched = True
1686 elif v == entryname:
1686 elif v == entryname:
1687 fm.startitem()
1687 fm.startitem()
1688 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1688 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1689 fm.write('value', '%s\n', value)
1689 fm.write('value', '%s\n', value)
1690 fm.data(name=entryname)
1690 fm.data(name=entryname)
1691 matched = True
1691 matched = True
1692 else:
1692 else:
1693 fm.startitem()
1693 fm.startitem()
1694 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1694 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1695 fm.write('name value', '%s=%s\n', entryname, value)
1695 fm.write('name value', '%s=%s\n', entryname, value)
1696 matched = True
1696 matched = True
1697 fm.end()
1697 fm.end()
1698 if matched:
1698 if matched:
1699 return 0
1699 return 0
1700 return 1
1700 return 1
1701
1701
1702 @command('copy|cp',
1702 @command('copy|cp',
1703 [('A', 'after', None, _('record a copy that has already occurred')),
1703 [('A', 'after', None, _('record a copy that has already occurred')),
1704 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1704 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1705 ] + walkopts + dryrunopts,
1705 ] + walkopts + dryrunopts,
1706 _('[OPTION]... [SOURCE]... DEST'))
1706 _('[OPTION]... [SOURCE]... DEST'))
1707 def copy(ui, repo, *pats, **opts):
1707 def copy(ui, repo, *pats, **opts):
1708 """mark files as copied for the next commit
1708 """mark files as copied for the next commit
1709
1709
1710 Mark dest as having copies of source files. If dest is a
1710 Mark dest as having copies of source files. If dest is a
1711 directory, copies are put in that directory. If dest is a file,
1711 directory, copies are put in that directory. If dest is a file,
1712 the source must be a single file.
1712 the source must be a single file.
1713
1713
1714 By default, this command copies the contents of files as they
1714 By default, this command copies the contents of files as they
1715 exist in the working directory. If invoked with -A/--after, the
1715 exist in the working directory. If invoked with -A/--after, the
1716 operation is recorded, but no copying is performed.
1716 operation is recorded, but no copying is performed.
1717
1717
1718 This command takes effect with the next commit. To undo a copy
1718 This command takes effect with the next commit. To undo a copy
1719 before that, see :hg:`revert`.
1719 before that, see :hg:`revert`.
1720
1720
1721 Returns 0 on success, 1 if errors are encountered.
1721 Returns 0 on success, 1 if errors are encountered.
1722 """
1722 """
1723 opts = pycompat.byteskwargs(opts)
1723 opts = pycompat.byteskwargs(opts)
1724 with repo.wlock(False):
1724 with repo.wlock(False):
1725 return cmdutil.copy(ui, repo, pats, opts)
1725 return cmdutil.copy(ui, repo, pats, opts)
1726
1726
1727 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1727 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1728 def debugcommands(ui, cmd='', *args):
1728 def debugcommands(ui, cmd='', *args):
1729 """list all available commands and options"""
1729 """list all available commands and options"""
1730 for cmd, vals in sorted(table.iteritems()):
1730 for cmd, vals in sorted(table.iteritems()):
1731 cmd = cmd.split('|')[0].strip('^')
1731 cmd = cmd.split('|')[0].strip('^')
1732 opts = ', '.join([i[1] for i in vals[1]])
1732 opts = ', '.join([i[1] for i in vals[1]])
1733 ui.write('%s: %s\n' % (cmd, opts))
1733 ui.write('%s: %s\n' % (cmd, opts))
1734
1734
1735 @command('debugcomplete',
1735 @command('debugcomplete',
1736 [('o', 'options', None, _('show the command options'))],
1736 [('o', 'options', None, _('show the command options'))],
1737 _('[-o] CMD'),
1737 _('[-o] CMD'),
1738 norepo=True)
1738 norepo=True)
1739 def debugcomplete(ui, cmd='', **opts):
1739 def debugcomplete(ui, cmd='', **opts):
1740 """returns the completion list associated with the given command"""
1740 """returns the completion list associated with the given command"""
1741
1741
1742 if opts.get('options'):
1742 if opts.get('options'):
1743 options = []
1743 options = []
1744 otables = [globalopts]
1744 otables = [globalopts]
1745 if cmd:
1745 if cmd:
1746 aliases, entry = cmdutil.findcmd(cmd, table, False)
1746 aliases, entry = cmdutil.findcmd(cmd, table, False)
1747 otables.append(entry[1])
1747 otables.append(entry[1])
1748 for t in otables:
1748 for t in otables:
1749 for o in t:
1749 for o in t:
1750 if "(DEPRECATED)" in o[3]:
1750 if "(DEPRECATED)" in o[3]:
1751 continue
1751 continue
1752 if o[0]:
1752 if o[0]:
1753 options.append('-%s' % o[0])
1753 options.append('-%s' % o[0])
1754 options.append('--%s' % o[1])
1754 options.append('--%s' % o[1])
1755 ui.write("%s\n" % "\n".join(options))
1755 ui.write("%s\n" % "\n".join(options))
1756 return
1756 return
1757
1757
1758 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1758 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1759 if ui.verbose:
1759 if ui.verbose:
1760 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1760 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1761 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1761 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1762
1762
1763 @command('^diff',
1763 @command('^diff',
1764 [('r', 'rev', [], _('revision'), _('REV')),
1764 [('r', 'rev', [], _('revision'), _('REV')),
1765 ('c', 'change', '', _('change made by revision'), _('REV'))
1765 ('c', 'change', '', _('change made by revision'), _('REV'))
1766 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1766 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1767 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1767 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1768 inferrepo=True)
1768 inferrepo=True)
1769 def diff(ui, repo, *pats, **opts):
1769 def diff(ui, repo, *pats, **opts):
1770 """diff repository (or selected files)
1770 """diff repository (or selected files)
1771
1771
1772 Show differences between revisions for the specified files.
1772 Show differences between revisions for the specified files.
1773
1773
1774 Differences between files are shown using the unified diff format.
1774 Differences between files are shown using the unified diff format.
1775
1775
1776 .. note::
1776 .. note::
1777
1777
1778 :hg:`diff` may generate unexpected results for merges, as it will
1778 :hg:`diff` may generate unexpected results for merges, as it will
1779 default to comparing against the working directory's first
1779 default to comparing against the working directory's first
1780 parent changeset if no revisions are specified.
1780 parent changeset if no revisions are specified.
1781
1781
1782 When two revision arguments are given, then changes are shown
1782 When two revision arguments are given, then changes are shown
1783 between those revisions. If only one revision is specified then
1783 between those revisions. If only one revision is specified then
1784 that revision is compared to the working directory, and, when no
1784 that revision is compared to the working directory, and, when no
1785 revisions are specified, the working directory files are compared
1785 revisions are specified, the working directory files are compared
1786 to its first parent.
1786 to its first parent.
1787
1787
1788 Alternatively you can specify -c/--change with a revision to see
1788 Alternatively you can specify -c/--change with a revision to see
1789 the changes in that changeset relative to its first parent.
1789 the changes in that changeset relative to its first parent.
1790
1790
1791 Without the -a/--text option, diff will avoid generating diffs of
1791 Without the -a/--text option, diff will avoid generating diffs of
1792 files it detects as binary. With -a, diff will generate a diff
1792 files it detects as binary. With -a, diff will generate a diff
1793 anyway, probably with undesirable results.
1793 anyway, probably with undesirable results.
1794
1794
1795 Use the -g/--git option to generate diffs in the git extended diff
1795 Use the -g/--git option to generate diffs in the git extended diff
1796 format. For more information, read :hg:`help diffs`.
1796 format. For more information, read :hg:`help diffs`.
1797
1797
1798 .. container:: verbose
1798 .. container:: verbose
1799
1799
1800 Examples:
1800 Examples:
1801
1801
1802 - compare a file in the current working directory to its parent::
1802 - compare a file in the current working directory to its parent::
1803
1803
1804 hg diff foo.c
1804 hg diff foo.c
1805
1805
1806 - compare two historical versions of a directory, with rename info::
1806 - compare two historical versions of a directory, with rename info::
1807
1807
1808 hg diff --git -r 1.0:1.2 lib/
1808 hg diff --git -r 1.0:1.2 lib/
1809
1809
1810 - get change stats relative to the last change on some date::
1810 - get change stats relative to the last change on some date::
1811
1811
1812 hg diff --stat -r "date('may 2')"
1812 hg diff --stat -r "date('may 2')"
1813
1813
1814 - diff all newly-added files that contain a keyword::
1814 - diff all newly-added files that contain a keyword::
1815
1815
1816 hg diff "set:added() and grep(GNU)"
1816 hg diff "set:added() and grep(GNU)"
1817
1817
1818 - compare a revision and its parents::
1818 - compare a revision and its parents::
1819
1819
1820 hg diff -c 9353 # compare against first parent
1820 hg diff -c 9353 # compare against first parent
1821 hg diff -r 9353^:9353 # same using revset syntax
1821 hg diff -r 9353^:9353 # same using revset syntax
1822 hg diff -r 9353^2:9353 # compare against the second parent
1822 hg diff -r 9353^2:9353 # compare against the second parent
1823
1823
1824 Returns 0 on success.
1824 Returns 0 on success.
1825 """
1825 """
1826
1826
1827 opts = pycompat.byteskwargs(opts)
1827 opts = pycompat.byteskwargs(opts)
1828 revs = opts.get('rev')
1828 revs = opts.get('rev')
1829 change = opts.get('change')
1829 change = opts.get('change')
1830 stat = opts.get('stat')
1830 stat = opts.get('stat')
1831 reverse = opts.get('reverse')
1831 reverse = opts.get('reverse')
1832
1832
1833 if revs and change:
1833 if revs and change:
1834 msg = _('cannot specify --rev and --change at the same time')
1834 msg = _('cannot specify --rev and --change at the same time')
1835 raise error.Abort(msg)
1835 raise error.Abort(msg)
1836 elif change:
1836 elif change:
1837 node2 = scmutil.revsingle(repo, change, None).node()
1837 node2 = scmutil.revsingle(repo, change, None).node()
1838 node1 = repo[node2].p1().node()
1838 node1 = repo[node2].p1().node()
1839 else:
1839 else:
1840 node1, node2 = scmutil.revpair(repo, revs)
1840 node1, node2 = scmutil.revpair(repo, revs)
1841
1841
1842 if reverse:
1842 if reverse:
1843 node1, node2 = node2, node1
1843 node1, node2 = node2, node1
1844
1844
1845 diffopts = patch.diffallopts(ui, opts)
1845 diffopts = patch.diffallopts(ui, opts)
1846 m = scmutil.match(repo[node2], pats, opts)
1846 m = scmutil.match(repo[node2], pats, opts)
1847 ui.pager('diff')
1847 ui.pager('diff')
1848 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1848 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1849 listsubrepos=opts.get('subrepos'),
1849 listsubrepos=opts.get('subrepos'),
1850 root=opts.get('root'))
1850 root=opts.get('root'))
1851
1851
1852 @command('^export',
1852 @command('^export',
1853 [('o', 'output', '',
1853 [('o', 'output', '',
1854 _('print output to file with formatted name'), _('FORMAT')),
1854 _('print output to file with formatted name'), _('FORMAT')),
1855 ('', 'switch-parent', None, _('diff against the second parent')),
1855 ('', 'switch-parent', None, _('diff against the second parent')),
1856 ('r', 'rev', [], _('revisions to export'), _('REV')),
1856 ('r', 'rev', [], _('revisions to export'), _('REV')),
1857 ] + diffopts,
1857 ] + diffopts,
1858 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1858 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1859 def export(ui, repo, *changesets, **opts):
1859 def export(ui, repo, *changesets, **opts):
1860 """dump the header and diffs for one or more changesets
1860 """dump the header and diffs for one or more changesets
1861
1861
1862 Print the changeset header and diffs for one or more revisions.
1862 Print the changeset header and diffs for one or more revisions.
1863 If no revision is given, the parent of the working directory is used.
1863 If no revision is given, the parent of the working directory is used.
1864
1864
1865 The information shown in the changeset header is: author, date,
1865 The information shown in the changeset header is: author, date,
1866 branch name (if non-default), changeset hash, parent(s) and commit
1866 branch name (if non-default), changeset hash, parent(s) and commit
1867 comment.
1867 comment.
1868
1868
1869 .. note::
1869 .. note::
1870
1870
1871 :hg:`export` may generate unexpected diff output for merge
1871 :hg:`export` may generate unexpected diff output for merge
1872 changesets, as it will compare the merge changeset against its
1872 changesets, as it will compare the merge changeset against its
1873 first parent only.
1873 first parent only.
1874
1874
1875 Output may be to a file, in which case the name of the file is
1875 Output may be to a file, in which case the name of the file is
1876 given using a format string. The formatting rules are as follows:
1876 given using a format string. The formatting rules are as follows:
1877
1877
1878 :``%%``: literal "%" character
1878 :``%%``: literal "%" character
1879 :``%H``: changeset hash (40 hexadecimal digits)
1879 :``%H``: changeset hash (40 hexadecimal digits)
1880 :``%N``: number of patches being generated
1880 :``%N``: number of patches being generated
1881 :``%R``: changeset revision number
1881 :``%R``: changeset revision number
1882 :``%b``: basename of the exporting repository
1882 :``%b``: basename of the exporting repository
1883 :``%h``: short-form changeset hash (12 hexadecimal digits)
1883 :``%h``: short-form changeset hash (12 hexadecimal digits)
1884 :``%m``: first line of the commit message (only alphanumeric characters)
1884 :``%m``: first line of the commit message (only alphanumeric characters)
1885 :``%n``: zero-padded sequence number, starting at 1
1885 :``%n``: zero-padded sequence number, starting at 1
1886 :``%r``: zero-padded changeset revision number
1886 :``%r``: zero-padded changeset revision number
1887
1887
1888 Without the -a/--text option, export will avoid generating diffs
1888 Without the -a/--text option, export will avoid generating diffs
1889 of files it detects as binary. With -a, export will generate a
1889 of files it detects as binary. With -a, export will generate a
1890 diff anyway, probably with undesirable results.
1890 diff anyway, probably with undesirable results.
1891
1891
1892 Use the -g/--git option to generate diffs in the git extended diff
1892 Use the -g/--git option to generate diffs in the git extended diff
1893 format. See :hg:`help diffs` for more information.
1893 format. See :hg:`help diffs` for more information.
1894
1894
1895 With the --switch-parent option, the diff will be against the
1895 With the --switch-parent option, the diff will be against the
1896 second parent. It can be useful to review a merge.
1896 second parent. It can be useful to review a merge.
1897
1897
1898 .. container:: verbose
1898 .. container:: verbose
1899
1899
1900 Examples:
1900 Examples:
1901
1901
1902 - use export and import to transplant a bugfix to the current
1902 - use export and import to transplant a bugfix to the current
1903 branch::
1903 branch::
1904
1904
1905 hg export -r 9353 | hg import -
1905 hg export -r 9353 | hg import -
1906
1906
1907 - export all the changesets between two revisions to a file with
1907 - export all the changesets between two revisions to a file with
1908 rename information::
1908 rename information::
1909
1909
1910 hg export --git -r 123:150 > changes.txt
1910 hg export --git -r 123:150 > changes.txt
1911
1911
1912 - split outgoing changes into a series of patches with
1912 - split outgoing changes into a series of patches with
1913 descriptive names::
1913 descriptive names::
1914
1914
1915 hg export -r "outgoing()" -o "%n-%m.patch"
1915 hg export -r "outgoing()" -o "%n-%m.patch"
1916
1916
1917 Returns 0 on success.
1917 Returns 0 on success.
1918 """
1918 """
1919 opts = pycompat.byteskwargs(opts)
1919 opts = pycompat.byteskwargs(opts)
1920 changesets += tuple(opts.get('rev', []))
1920 changesets += tuple(opts.get('rev', []))
1921 if not changesets:
1921 if not changesets:
1922 changesets = ['.']
1922 changesets = ['.']
1923 revs = scmutil.revrange(repo, changesets)
1923 revs = scmutil.revrange(repo, changesets)
1924 if not revs:
1924 if not revs:
1925 raise error.Abort(_("export requires at least one changeset"))
1925 raise error.Abort(_("export requires at least one changeset"))
1926 if len(revs) > 1:
1926 if len(revs) > 1:
1927 ui.note(_('exporting patches:\n'))
1927 ui.note(_('exporting patches:\n'))
1928 else:
1928 else:
1929 ui.note(_('exporting patch:\n'))
1929 ui.note(_('exporting patch:\n'))
1930 ui.pager('export')
1930 ui.pager('export')
1931 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1931 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1932 switch_parent=opts.get('switch_parent'),
1932 switch_parent=opts.get('switch_parent'),
1933 opts=patch.diffallopts(ui, opts))
1933 opts=patch.diffallopts(ui, opts))
1934
1934
1935 @command('files',
1935 @command('files',
1936 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1936 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1937 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1937 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1938 ] + walkopts + formatteropts + subrepoopts,
1938 ] + walkopts + formatteropts + subrepoopts,
1939 _('[OPTION]... [FILE]...'))
1939 _('[OPTION]... [FILE]...'))
1940 def files(ui, repo, *pats, **opts):
1940 def files(ui, repo, *pats, **opts):
1941 """list tracked files
1941 """list tracked files
1942
1942
1943 Print files under Mercurial control in the working directory or
1943 Print files under Mercurial control in the working directory or
1944 specified revision for given files (excluding removed files).
1944 specified revision for given files (excluding removed files).
1945 Files can be specified as filenames or filesets.
1945 Files can be specified as filenames or filesets.
1946
1946
1947 If no files are given to match, this command prints the names
1947 If no files are given to match, this command prints the names
1948 of all files under Mercurial control.
1948 of all files under Mercurial control.
1949
1949
1950 .. container:: verbose
1950 .. container:: verbose
1951
1951
1952 Examples:
1952 Examples:
1953
1953
1954 - list all files under the current directory::
1954 - list all files under the current directory::
1955
1955
1956 hg files .
1956 hg files .
1957
1957
1958 - shows sizes and flags for current revision::
1958 - shows sizes and flags for current revision::
1959
1959
1960 hg files -vr .
1960 hg files -vr .
1961
1961
1962 - list all files named README::
1962 - list all files named README::
1963
1963
1964 hg files -I "**/README"
1964 hg files -I "**/README"
1965
1965
1966 - list all binary files::
1966 - list all binary files::
1967
1967
1968 hg files "set:binary()"
1968 hg files "set:binary()"
1969
1969
1970 - find files containing a regular expression::
1970 - find files containing a regular expression::
1971
1971
1972 hg files "set:grep('bob')"
1972 hg files "set:grep('bob')"
1973
1973
1974 - search tracked file contents with xargs and grep::
1974 - search tracked file contents with xargs and grep::
1975
1975
1976 hg files -0 | xargs -0 grep foo
1976 hg files -0 | xargs -0 grep foo
1977
1977
1978 See :hg:`help patterns` and :hg:`help filesets` for more information
1978 See :hg:`help patterns` and :hg:`help filesets` for more information
1979 on specifying file patterns.
1979 on specifying file patterns.
1980
1980
1981 Returns 0 if a match is found, 1 otherwise.
1981 Returns 0 if a match is found, 1 otherwise.
1982
1982
1983 """
1983 """
1984
1984
1985 opts = pycompat.byteskwargs(opts)
1985 opts = pycompat.byteskwargs(opts)
1986 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1986 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1987
1987
1988 end = '\n'
1988 end = '\n'
1989 if opts.get('print0'):
1989 if opts.get('print0'):
1990 end = '\0'
1990 end = '\0'
1991 fmt = '%s' + end
1991 fmt = '%s' + end
1992
1992
1993 m = scmutil.match(ctx, pats, opts)
1993 m = scmutil.match(ctx, pats, opts)
1994 ui.pager('files')
1994 ui.pager('files')
1995 with ui.formatter('files', opts) as fm:
1995 with ui.formatter('files', opts) as fm:
1996 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
1996 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
1997
1997
1998 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
1998 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
1999 def forget(ui, repo, *pats, **opts):
1999 def forget(ui, repo, *pats, **opts):
2000 """forget the specified files on the next commit
2000 """forget the specified files on the next commit
2001
2001
2002 Mark the specified files so they will no longer be tracked
2002 Mark the specified files so they will no longer be tracked
2003 after the next commit.
2003 after the next commit.
2004
2004
2005 This only removes files from the current branch, not from the
2005 This only removes files from the current branch, not from the
2006 entire project history, and it does not delete them from the
2006 entire project history, and it does not delete them from the
2007 working directory.
2007 working directory.
2008
2008
2009 To delete the file from the working directory, see :hg:`remove`.
2009 To delete the file from the working directory, see :hg:`remove`.
2010
2010
2011 To undo a forget before the next commit, see :hg:`add`.
2011 To undo a forget before the next commit, see :hg:`add`.
2012
2012
2013 .. container:: verbose
2013 .. container:: verbose
2014
2014
2015 Examples:
2015 Examples:
2016
2016
2017 - forget newly-added binary files::
2017 - forget newly-added binary files::
2018
2018
2019 hg forget "set:added() and binary()"
2019 hg forget "set:added() and binary()"
2020
2020
2021 - forget files that would be excluded by .hgignore::
2021 - forget files that would be excluded by .hgignore::
2022
2022
2023 hg forget "set:hgignore()"
2023 hg forget "set:hgignore()"
2024
2024
2025 Returns 0 on success.
2025 Returns 0 on success.
2026 """
2026 """
2027
2027
2028 opts = pycompat.byteskwargs(opts)
2028 opts = pycompat.byteskwargs(opts)
2029 if not pats:
2029 if not pats:
2030 raise error.Abort(_('no files specified'))
2030 raise error.Abort(_('no files specified'))
2031
2031
2032 m = scmutil.match(repo[None], pats, opts)
2032 m = scmutil.match(repo[None], pats, opts)
2033 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2033 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2034 return rejected and 1 or 0
2034 return rejected and 1 or 0
2035
2035
2036 @command(
2036 @command(
2037 'graft',
2037 'graft',
2038 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2038 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2039 ('c', 'continue', False, _('resume interrupted graft')),
2039 ('c', 'continue', False, _('resume interrupted graft')),
2040 ('e', 'edit', False, _('invoke editor on commit messages')),
2040 ('e', 'edit', False, _('invoke editor on commit messages')),
2041 ('', 'log', None, _('append graft info to log message')),
2041 ('', 'log', None, _('append graft info to log message')),
2042 ('f', 'force', False, _('force graft')),
2042 ('f', 'force', False, _('force graft')),
2043 ('D', 'currentdate', False,
2043 ('D', 'currentdate', False,
2044 _('record the current date as commit date')),
2044 _('record the current date as commit date')),
2045 ('U', 'currentuser', False,
2045 ('U', 'currentuser', False,
2046 _('record the current user as committer'), _('DATE'))]
2046 _('record the current user as committer'), _('DATE'))]
2047 + commitopts2 + mergetoolopts + dryrunopts,
2047 + commitopts2 + mergetoolopts + dryrunopts,
2048 _('[OPTION]... [-r REV]... REV...'))
2048 _('[OPTION]... [-r REV]... REV...'))
2049 def graft(ui, repo, *revs, **opts):
2049 def graft(ui, repo, *revs, **opts):
2050 '''copy changes from other branches onto the current branch
2050 '''copy changes from other branches onto the current branch
2051
2051
2052 This command uses Mercurial's merge logic to copy individual
2052 This command uses Mercurial's merge logic to copy individual
2053 changes from other branches without merging branches in the
2053 changes from other branches without merging branches in the
2054 history graph. This is sometimes known as 'backporting' or
2054 history graph. This is sometimes known as 'backporting' or
2055 'cherry-picking'. By default, graft will copy user, date, and
2055 'cherry-picking'. By default, graft will copy user, date, and
2056 description from the source changesets.
2056 description from the source changesets.
2057
2057
2058 Changesets that are ancestors of the current revision, that have
2058 Changesets that are ancestors of the current revision, that have
2059 already been grafted, or that are merges will be skipped.
2059 already been grafted, or that are merges will be skipped.
2060
2060
2061 If --log is specified, log messages will have a comment appended
2061 If --log is specified, log messages will have a comment appended
2062 of the form::
2062 of the form::
2063
2063
2064 (grafted from CHANGESETHASH)
2064 (grafted from CHANGESETHASH)
2065
2065
2066 If --force is specified, revisions will be grafted even if they
2066 If --force is specified, revisions will be grafted even if they
2067 are already ancestors of or have been grafted to the destination.
2067 are already ancestors of or have been grafted to the destination.
2068 This is useful when the revisions have since been backed out.
2068 This is useful when the revisions have since been backed out.
2069
2069
2070 If a graft merge results in conflicts, the graft process is
2070 If a graft merge results in conflicts, the graft process is
2071 interrupted so that the current merge can be manually resolved.
2071 interrupted so that the current merge can be manually resolved.
2072 Once all conflicts are addressed, the graft process can be
2072 Once all conflicts are addressed, the graft process can be
2073 continued with the -c/--continue option.
2073 continued with the -c/--continue option.
2074
2074
2075 .. note::
2075 .. note::
2076
2076
2077 The -c/--continue option does not reapply earlier options, except
2077 The -c/--continue option does not reapply earlier options, except
2078 for --force.
2078 for --force.
2079
2079
2080 .. container:: verbose
2080 .. container:: verbose
2081
2081
2082 Examples:
2082 Examples:
2083
2083
2084 - copy a single change to the stable branch and edit its description::
2084 - copy a single change to the stable branch and edit its description::
2085
2085
2086 hg update stable
2086 hg update stable
2087 hg graft --edit 9393
2087 hg graft --edit 9393
2088
2088
2089 - graft a range of changesets with one exception, updating dates::
2089 - graft a range of changesets with one exception, updating dates::
2090
2090
2091 hg graft -D "2085::2093 and not 2091"
2091 hg graft -D "2085::2093 and not 2091"
2092
2092
2093 - continue a graft after resolving conflicts::
2093 - continue a graft after resolving conflicts::
2094
2094
2095 hg graft -c
2095 hg graft -c
2096
2096
2097 - show the source of a grafted changeset::
2097 - show the source of a grafted changeset::
2098
2098
2099 hg log --debug -r .
2099 hg log --debug -r .
2100
2100
2101 - show revisions sorted by date::
2101 - show revisions sorted by date::
2102
2102
2103 hg log -r "sort(all(), date)"
2103 hg log -r "sort(all(), date)"
2104
2104
2105 See :hg:`help revisions` for more about specifying revisions.
2105 See :hg:`help revisions` for more about specifying revisions.
2106
2106
2107 Returns 0 on successful completion.
2107 Returns 0 on successful completion.
2108 '''
2108 '''
2109 with repo.wlock():
2109 with repo.wlock():
2110 return _dograft(ui, repo, *revs, **opts)
2110 return _dograft(ui, repo, *revs, **opts)
2111
2111
2112 def _dograft(ui, repo, *revs, **opts):
2112 def _dograft(ui, repo, *revs, **opts):
2113 opts = pycompat.byteskwargs(opts)
2113 opts = pycompat.byteskwargs(opts)
2114 if revs and opts.get('rev'):
2114 if revs and opts.get('rev'):
2115 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2115 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2116 'revision ordering!\n'))
2116 'revision ordering!\n'))
2117
2117
2118 revs = list(revs)
2118 revs = list(revs)
2119 revs.extend(opts.get('rev'))
2119 revs.extend(opts.get('rev'))
2120
2120
2121 if not opts.get('user') and opts.get('currentuser'):
2121 if not opts.get('user') and opts.get('currentuser'):
2122 opts['user'] = ui.username()
2122 opts['user'] = ui.username()
2123 if not opts.get('date') and opts.get('currentdate'):
2123 if not opts.get('date') and opts.get('currentdate'):
2124 opts['date'] = "%d %d" % util.makedate()
2124 opts['date'] = "%d %d" % util.makedate()
2125
2125
2126 editor = cmdutil.getcommiteditor(editform='graft',
2126 editor = cmdutil.getcommiteditor(editform='graft',
2127 **pycompat.strkwargs(opts))
2127 **pycompat.strkwargs(opts))
2128
2128
2129 cont = False
2129 cont = False
2130 if opts.get('continue'):
2130 if opts.get('continue'):
2131 cont = True
2131 cont = True
2132 if revs:
2132 if revs:
2133 raise error.Abort(_("can't specify --continue and revisions"))
2133 raise error.Abort(_("can't specify --continue and revisions"))
2134 # read in unfinished revisions
2134 # read in unfinished revisions
2135 try:
2135 try:
2136 nodes = repo.vfs.read('graftstate').splitlines()
2136 nodes = repo.vfs.read('graftstate').splitlines()
2137 revs = [repo[node].rev() for node in nodes]
2137 revs = [repo[node].rev() for node in nodes]
2138 except IOError as inst:
2138 except IOError as inst:
2139 if inst.errno != errno.ENOENT:
2139 if inst.errno != errno.ENOENT:
2140 raise
2140 raise
2141 cmdutil.wrongtooltocontinue(repo, _('graft'))
2141 cmdutil.wrongtooltocontinue(repo, _('graft'))
2142 else:
2142 else:
2143 cmdutil.checkunfinished(repo)
2143 cmdutil.checkunfinished(repo)
2144 cmdutil.bailifchanged(repo)
2144 cmdutil.bailifchanged(repo)
2145 if not revs:
2145 if not revs:
2146 raise error.Abort(_('no revisions specified'))
2146 raise error.Abort(_('no revisions specified'))
2147 revs = scmutil.revrange(repo, revs)
2147 revs = scmutil.revrange(repo, revs)
2148
2148
2149 skipped = set()
2149 skipped = set()
2150 # check for merges
2150 # check for merges
2151 for rev in repo.revs('%ld and merge()', revs):
2151 for rev in repo.revs('%ld and merge()', revs):
2152 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2152 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2153 skipped.add(rev)
2153 skipped.add(rev)
2154 revs = [r for r in revs if r not in skipped]
2154 revs = [r for r in revs if r not in skipped]
2155 if not revs:
2155 if not revs:
2156 return -1
2156 return -1
2157
2157
2158 # Don't check in the --continue case, in effect retaining --force across
2158 # Don't check in the --continue case, in effect retaining --force across
2159 # --continues. That's because without --force, any revisions we decided to
2159 # --continues. That's because without --force, any revisions we decided to
2160 # skip would have been filtered out here, so they wouldn't have made their
2160 # skip would have been filtered out here, so they wouldn't have made their
2161 # way to the graftstate. With --force, any revisions we would have otherwise
2161 # way to the graftstate. With --force, any revisions we would have otherwise
2162 # skipped would not have been filtered out, and if they hadn't been applied
2162 # skipped would not have been filtered out, and if they hadn't been applied
2163 # already, they'd have been in the graftstate.
2163 # already, they'd have been in the graftstate.
2164 if not (cont or opts.get('force')):
2164 if not (cont or opts.get('force')):
2165 # check for ancestors of dest branch
2165 # check for ancestors of dest branch
2166 crev = repo['.'].rev()
2166 crev = repo['.'].rev()
2167 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2167 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2168 # XXX make this lazy in the future
2168 # XXX make this lazy in the future
2169 # don't mutate while iterating, create a copy
2169 # don't mutate while iterating, create a copy
2170 for rev in list(revs):
2170 for rev in list(revs):
2171 if rev in ancestors:
2171 if rev in ancestors:
2172 ui.warn(_('skipping ancestor revision %d:%s\n') %
2172 ui.warn(_('skipping ancestor revision %d:%s\n') %
2173 (rev, repo[rev]))
2173 (rev, repo[rev]))
2174 # XXX remove on list is slow
2174 # XXX remove on list is slow
2175 revs.remove(rev)
2175 revs.remove(rev)
2176 if not revs:
2176 if not revs:
2177 return -1
2177 return -1
2178
2178
2179 # analyze revs for earlier grafts
2179 # analyze revs for earlier grafts
2180 ids = {}
2180 ids = {}
2181 for ctx in repo.set("%ld", revs):
2181 for ctx in repo.set("%ld", revs):
2182 ids[ctx.hex()] = ctx.rev()
2182 ids[ctx.hex()] = ctx.rev()
2183 n = ctx.extra().get('source')
2183 n = ctx.extra().get('source')
2184 if n:
2184 if n:
2185 ids[n] = ctx.rev()
2185 ids[n] = ctx.rev()
2186
2186
2187 # check ancestors for earlier grafts
2187 # check ancestors for earlier grafts
2188 ui.debug('scanning for duplicate grafts\n')
2188 ui.debug('scanning for duplicate grafts\n')
2189
2189
2190 # The only changesets we can be sure doesn't contain grafts of any
2190 # The only changesets we can be sure doesn't contain grafts of any
2191 # revs, are the ones that are common ancestors of *all* revs:
2191 # revs, are the ones that are common ancestors of *all* revs:
2192 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2192 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2193 ctx = repo[rev]
2193 ctx = repo[rev]
2194 n = ctx.extra().get('source')
2194 n = ctx.extra().get('source')
2195 if n in ids:
2195 if n in ids:
2196 try:
2196 try:
2197 r = repo[n].rev()
2197 r = repo[n].rev()
2198 except error.RepoLookupError:
2198 except error.RepoLookupError:
2199 r = None
2199 r = None
2200 if r in revs:
2200 if r in revs:
2201 ui.warn(_('skipping revision %d:%s '
2201 ui.warn(_('skipping revision %d:%s '
2202 '(already grafted to %d:%s)\n')
2202 '(already grafted to %d:%s)\n')
2203 % (r, repo[r], rev, ctx))
2203 % (r, repo[r], rev, ctx))
2204 revs.remove(r)
2204 revs.remove(r)
2205 elif ids[n] in revs:
2205 elif ids[n] in revs:
2206 if r is None:
2206 if r is None:
2207 ui.warn(_('skipping already grafted revision %d:%s '
2207 ui.warn(_('skipping already grafted revision %d:%s '
2208 '(%d:%s also has unknown origin %s)\n')
2208 '(%d:%s also has unknown origin %s)\n')
2209 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2209 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2210 else:
2210 else:
2211 ui.warn(_('skipping already grafted revision %d:%s '
2211 ui.warn(_('skipping already grafted revision %d:%s '
2212 '(%d:%s also has origin %d:%s)\n')
2212 '(%d:%s also has origin %d:%s)\n')
2213 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2213 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2214 revs.remove(ids[n])
2214 revs.remove(ids[n])
2215 elif ctx.hex() in ids:
2215 elif ctx.hex() in ids:
2216 r = ids[ctx.hex()]
2216 r = ids[ctx.hex()]
2217 ui.warn(_('skipping already grafted revision %d:%s '
2217 ui.warn(_('skipping already grafted revision %d:%s '
2218 '(was grafted from %d:%s)\n') %
2218 '(was grafted from %d:%s)\n') %
2219 (r, repo[r], rev, ctx))
2219 (r, repo[r], rev, ctx))
2220 revs.remove(r)
2220 revs.remove(r)
2221 if not revs:
2221 if not revs:
2222 return -1
2222 return -1
2223
2223
2224 for pos, ctx in enumerate(repo.set("%ld", revs)):
2224 for pos, ctx in enumerate(repo.set("%ld", revs)):
2225 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2225 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2226 ctx.description().split('\n', 1)[0])
2226 ctx.description().split('\n', 1)[0])
2227 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2227 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2228 if names:
2228 if names:
2229 desc += ' (%s)' % ' '.join(names)
2229 desc += ' (%s)' % ' '.join(names)
2230 ui.status(_('grafting %s\n') % desc)
2230 ui.status(_('grafting %s\n') % desc)
2231 if opts.get('dry_run'):
2231 if opts.get('dry_run'):
2232 continue
2232 continue
2233
2233
2234 source = ctx.extra().get('source')
2234 source = ctx.extra().get('source')
2235 extra = {}
2235 extra = {}
2236 if source:
2236 if source:
2237 extra['source'] = source
2237 extra['source'] = source
2238 extra['intermediate-source'] = ctx.hex()
2238 extra['intermediate-source'] = ctx.hex()
2239 else:
2239 else:
2240 extra['source'] = ctx.hex()
2240 extra['source'] = ctx.hex()
2241 user = ctx.user()
2241 user = ctx.user()
2242 if opts.get('user'):
2242 if opts.get('user'):
2243 user = opts['user']
2243 user = opts['user']
2244 date = ctx.date()
2244 date = ctx.date()
2245 if opts.get('date'):
2245 if opts.get('date'):
2246 date = opts['date']
2246 date = opts['date']
2247 message = ctx.description()
2247 message = ctx.description()
2248 if opts.get('log'):
2248 if opts.get('log'):
2249 message += '\n(grafted from %s)' % ctx.hex()
2249 message += '\n(grafted from %s)' % ctx.hex()
2250
2250
2251 # we don't merge the first commit when continuing
2251 # we don't merge the first commit when continuing
2252 if not cont:
2252 if not cont:
2253 # perform the graft merge with p1(rev) as 'ancestor'
2253 # perform the graft merge with p1(rev) as 'ancestor'
2254 try:
2254 try:
2255 # ui.forcemerge is an internal variable, do not document
2255 # ui.forcemerge is an internal variable, do not document
2256 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2256 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2257 'graft')
2257 'graft')
2258 stats = mergemod.graft(repo, ctx, ctx.p1(),
2258 stats = mergemod.graft(repo, ctx, ctx.p1(),
2259 ['local', 'graft'])
2259 ['local', 'graft'])
2260 finally:
2260 finally:
2261 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2261 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2262 # report any conflicts
2262 # report any conflicts
2263 if stats and stats[3] > 0:
2263 if stats and stats[3] > 0:
2264 # write out state for --continue
2264 # write out state for --continue
2265 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2265 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2266 repo.vfs.write('graftstate', ''.join(nodelines))
2266 repo.vfs.write('graftstate', ''.join(nodelines))
2267 extra = ''
2267 extra = ''
2268 if opts.get('user'):
2268 if opts.get('user'):
2269 extra += ' --user %s' % util.shellquote(opts['user'])
2269 extra += ' --user %s' % util.shellquote(opts['user'])
2270 if opts.get('date'):
2270 if opts.get('date'):
2271 extra += ' --date %s' % util.shellquote(opts['date'])
2271 extra += ' --date %s' % util.shellquote(opts['date'])
2272 if opts.get('log'):
2272 if opts.get('log'):
2273 extra += ' --log'
2273 extra += ' --log'
2274 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2274 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2275 raise error.Abort(
2275 raise error.Abort(
2276 _("unresolved conflicts, can't continue"),
2276 _("unresolved conflicts, can't continue"),
2277 hint=hint)
2277 hint=hint)
2278 else:
2278 else:
2279 cont = False
2279 cont = False
2280
2280
2281 # commit
2281 # commit
2282 node = repo.commit(text=message, user=user,
2282 node = repo.commit(text=message, user=user,
2283 date=date, extra=extra, editor=editor)
2283 date=date, extra=extra, editor=editor)
2284 if node is None:
2284 if node is None:
2285 ui.warn(
2285 ui.warn(
2286 _('note: graft of %d:%s created no changes to commit\n') %
2286 _('note: graft of %d:%s created no changes to commit\n') %
2287 (ctx.rev(), ctx))
2287 (ctx.rev(), ctx))
2288
2288
2289 # remove state when we complete successfully
2289 # remove state when we complete successfully
2290 if not opts.get('dry_run'):
2290 if not opts.get('dry_run'):
2291 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2291 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2292
2292
2293 return 0
2293 return 0
2294
2294
2295 @command('grep',
2295 @command('grep',
2296 [('0', 'print0', None, _('end fields with NUL')),
2296 [('0', 'print0', None, _('end fields with NUL')),
2297 ('', 'all', None, _('print all revisions that match')),
2297 ('', 'all', None, _('print all revisions that match')),
2298 ('a', 'text', None, _('treat all files as text')),
2298 ('a', 'text', None, _('treat all files as text')),
2299 ('f', 'follow', None,
2299 ('f', 'follow', None,
2300 _('follow changeset history,'
2300 _('follow changeset history,'
2301 ' or file history across copies and renames')),
2301 ' or file history across copies and renames')),
2302 ('i', 'ignore-case', None, _('ignore case when matching')),
2302 ('i', 'ignore-case', None, _('ignore case when matching')),
2303 ('l', 'files-with-matches', None,
2303 ('l', 'files-with-matches', None,
2304 _('print only filenames and revisions that match')),
2304 _('print only filenames and revisions that match')),
2305 ('n', 'line-number', None, _('print matching line numbers')),
2305 ('n', 'line-number', None, _('print matching line numbers')),
2306 ('r', 'rev', [],
2306 ('r', 'rev', [],
2307 _('only search files changed within revision range'), _('REV')),
2307 _('only search files changed within revision range'), _('REV')),
2308 ('u', 'user', None, _('list the author (long with -v)')),
2308 ('u', 'user', None, _('list the author (long with -v)')),
2309 ('d', 'date', None, _('list the date (short with -q)')),
2309 ('d', 'date', None, _('list the date (short with -q)')),
2310 ] + formatteropts + walkopts,
2310 ] + formatteropts + walkopts,
2311 _('[OPTION]... PATTERN [FILE]...'),
2311 _('[OPTION]... PATTERN [FILE]...'),
2312 inferrepo=True)
2312 inferrepo=True)
2313 def grep(ui, repo, pattern, *pats, **opts):
2313 def grep(ui, repo, pattern, *pats, **opts):
2314 """search revision history for a pattern in specified files
2314 """search revision history for a pattern in specified files
2315
2315
2316 Search revision history for a regular expression in the specified
2316 Search revision history for a regular expression in the specified
2317 files or the entire project.
2317 files or the entire project.
2318
2318
2319 By default, grep prints the most recent revision number for each
2319 By default, grep prints the most recent revision number for each
2320 file in which it finds a match. To get it to print every revision
2320 file in which it finds a match. To get it to print every revision
2321 that contains a change in match status ("-" for a match that becomes
2321 that contains a change in match status ("-" for a match that becomes
2322 a non-match, or "+" for a non-match that becomes a match), use the
2322 a non-match, or "+" for a non-match that becomes a match), use the
2323 --all flag.
2323 --all flag.
2324
2324
2325 PATTERN can be any Python (roughly Perl-compatible) regular
2325 PATTERN can be any Python (roughly Perl-compatible) regular
2326 expression.
2326 expression.
2327
2327
2328 If no FILEs are specified (and -f/--follow isn't set), all files in
2328 If no FILEs are specified (and -f/--follow isn't set), all files in
2329 the repository are searched, including those that don't exist in the
2329 the repository are searched, including those that don't exist in the
2330 current branch or have been deleted in a prior changeset.
2330 current branch or have been deleted in a prior changeset.
2331
2331
2332 Returns 0 if a match is found, 1 otherwise.
2332 Returns 0 if a match is found, 1 otherwise.
2333 """
2333 """
2334 opts = pycompat.byteskwargs(opts)
2334 opts = pycompat.byteskwargs(opts)
2335 reflags = re.M
2335 reflags = re.M
2336 if opts.get('ignore_case'):
2336 if opts.get('ignore_case'):
2337 reflags |= re.I
2337 reflags |= re.I
2338 try:
2338 try:
2339 regexp = util.re.compile(pattern, reflags)
2339 regexp = util.re.compile(pattern, reflags)
2340 except re.error as inst:
2340 except re.error as inst:
2341 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2341 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2342 return 1
2342 return 1
2343 sep, eol = ':', '\n'
2343 sep, eol = ':', '\n'
2344 if opts.get('print0'):
2344 if opts.get('print0'):
2345 sep = eol = '\0'
2345 sep = eol = '\0'
2346
2346
2347 getfile = util.lrucachefunc(repo.file)
2347 getfile = util.lrucachefunc(repo.file)
2348
2348
2349 def matchlines(body):
2349 def matchlines(body):
2350 begin = 0
2350 begin = 0
2351 linenum = 0
2351 linenum = 0
2352 while begin < len(body):
2352 while begin < len(body):
2353 match = regexp.search(body, begin)
2353 match = regexp.search(body, begin)
2354 if not match:
2354 if not match:
2355 break
2355 break
2356 mstart, mend = match.span()
2356 mstart, mend = match.span()
2357 linenum += body.count('\n', begin, mstart) + 1
2357 linenum += body.count('\n', begin, mstart) + 1
2358 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2358 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2359 begin = body.find('\n', mend) + 1 or len(body) + 1
2359 begin = body.find('\n', mend) + 1 or len(body) + 1
2360 lend = begin - 1
2360 lend = begin - 1
2361 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2361 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2362
2362
2363 class linestate(object):
2363 class linestate(object):
2364 def __init__(self, line, linenum, colstart, colend):
2364 def __init__(self, line, linenum, colstart, colend):
2365 self.line = line
2365 self.line = line
2366 self.linenum = linenum
2366 self.linenum = linenum
2367 self.colstart = colstart
2367 self.colstart = colstart
2368 self.colend = colend
2368 self.colend = colend
2369
2369
2370 def __hash__(self):
2370 def __hash__(self):
2371 return hash((self.linenum, self.line))
2371 return hash((self.linenum, self.line))
2372
2372
2373 def __eq__(self, other):
2373 def __eq__(self, other):
2374 return self.line == other.line
2374 return self.line == other.line
2375
2375
2376 def findpos(self):
2376 def findpos(self):
2377 """Iterate all (start, end) indices of matches"""
2377 """Iterate all (start, end) indices of matches"""
2378 yield self.colstart, self.colend
2378 yield self.colstart, self.colend
2379 p = self.colend
2379 p = self.colend
2380 while p < len(self.line):
2380 while p < len(self.line):
2381 m = regexp.search(self.line, p)
2381 m = regexp.search(self.line, p)
2382 if not m:
2382 if not m:
2383 break
2383 break
2384 yield m.span()
2384 yield m.span()
2385 p = m.end()
2385 p = m.end()
2386
2386
2387 matches = {}
2387 matches = {}
2388 copies = {}
2388 copies = {}
2389 def grepbody(fn, rev, body):
2389 def grepbody(fn, rev, body):
2390 matches[rev].setdefault(fn, [])
2390 matches[rev].setdefault(fn, [])
2391 m = matches[rev][fn]
2391 m = matches[rev][fn]
2392 for lnum, cstart, cend, line in matchlines(body):
2392 for lnum, cstart, cend, line in matchlines(body):
2393 s = linestate(line, lnum, cstart, cend)
2393 s = linestate(line, lnum, cstart, cend)
2394 m.append(s)
2394 m.append(s)
2395
2395
2396 def difflinestates(a, b):
2396 def difflinestates(a, b):
2397 sm = difflib.SequenceMatcher(None, a, b)
2397 sm = difflib.SequenceMatcher(None, a, b)
2398 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2398 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2399 if tag == 'insert':
2399 if tag == 'insert':
2400 for i in xrange(blo, bhi):
2400 for i in xrange(blo, bhi):
2401 yield ('+', b[i])
2401 yield ('+', b[i])
2402 elif tag == 'delete':
2402 elif tag == 'delete':
2403 for i in xrange(alo, ahi):
2403 for i in xrange(alo, ahi):
2404 yield ('-', a[i])
2404 yield ('-', a[i])
2405 elif tag == 'replace':
2405 elif tag == 'replace':
2406 for i in xrange(alo, ahi):
2406 for i in xrange(alo, ahi):
2407 yield ('-', a[i])
2407 yield ('-', a[i])
2408 for i in xrange(blo, bhi):
2408 for i in xrange(blo, bhi):
2409 yield ('+', b[i])
2409 yield ('+', b[i])
2410
2410
2411 def display(fm, fn, ctx, pstates, states):
2411 def display(fm, fn, ctx, pstates, states):
2412 rev = ctx.rev()
2412 rev = ctx.rev()
2413 if fm.isplain():
2413 if fm.isplain():
2414 formatuser = ui.shortuser
2414 formatuser = ui.shortuser
2415 else:
2415 else:
2416 formatuser = str
2416 formatuser = str
2417 if ui.quiet:
2417 if ui.quiet:
2418 datefmt = '%Y-%m-%d'
2418 datefmt = '%Y-%m-%d'
2419 else:
2419 else:
2420 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2420 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2421 found = False
2421 found = False
2422 @util.cachefunc
2422 @util.cachefunc
2423 def binary():
2423 def binary():
2424 flog = getfile(fn)
2424 flog = getfile(fn)
2425 return util.binary(flog.read(ctx.filenode(fn)))
2425 return util.binary(flog.read(ctx.filenode(fn)))
2426
2426
2427 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2427 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2428 if opts.get('all'):
2428 if opts.get('all'):
2429 iter = difflinestates(pstates, states)
2429 iter = difflinestates(pstates, states)
2430 else:
2430 else:
2431 iter = [('', l) for l in states]
2431 iter = [('', l) for l in states]
2432 for change, l in iter:
2432 for change, l in iter:
2433 fm.startitem()
2433 fm.startitem()
2434 fm.data(node=fm.hexfunc(ctx.node()))
2434 fm.data(node=fm.hexfunc(ctx.node()))
2435 cols = [
2435 cols = [
2436 ('filename', fn, True),
2436 ('filename', fn, True),
2437 ('rev', rev, True),
2437 ('rev', rev, True),
2438 ('linenumber', l.linenum, opts.get('line_number')),
2438 ('linenumber', l.linenum, opts.get('line_number')),
2439 ]
2439 ]
2440 if opts.get('all'):
2440 if opts.get('all'):
2441 cols.append(('change', change, True))
2441 cols.append(('change', change, True))
2442 cols.extend([
2442 cols.extend([
2443 ('user', formatuser(ctx.user()), opts.get('user')),
2443 ('user', formatuser(ctx.user()), opts.get('user')),
2444 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2444 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2445 ])
2445 ])
2446 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2446 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2447 for name, data, cond in cols:
2447 for name, data, cond in cols:
2448 field = fieldnamemap.get(name, name)
2448 field = fieldnamemap.get(name, name)
2449 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2449 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2450 if cond and name != lastcol:
2450 if cond and name != lastcol:
2451 fm.plain(sep, label='grep.sep')
2451 fm.plain(sep, label='grep.sep')
2452 if not opts.get('files_with_matches'):
2452 if not opts.get('files_with_matches'):
2453 fm.plain(sep, label='grep.sep')
2453 fm.plain(sep, label='grep.sep')
2454 if not opts.get('text') and binary():
2454 if not opts.get('text') and binary():
2455 fm.plain(_(" Binary file matches"))
2455 fm.plain(_(" Binary file matches"))
2456 else:
2456 else:
2457 displaymatches(fm.nested('texts'), l)
2457 displaymatches(fm.nested('texts'), l)
2458 fm.plain(eol)
2458 fm.plain(eol)
2459 found = True
2459 found = True
2460 if opts.get('files_with_matches'):
2460 if opts.get('files_with_matches'):
2461 break
2461 break
2462 return found
2462 return found
2463
2463
2464 def displaymatches(fm, l):
2464 def displaymatches(fm, l):
2465 p = 0
2465 p = 0
2466 for s, e in l.findpos():
2466 for s, e in l.findpos():
2467 if p < s:
2467 if p < s:
2468 fm.startitem()
2468 fm.startitem()
2469 fm.write('text', '%s', l.line[p:s])
2469 fm.write('text', '%s', l.line[p:s])
2470 fm.data(matched=False)
2470 fm.data(matched=False)
2471 fm.startitem()
2471 fm.startitem()
2472 fm.write('text', '%s', l.line[s:e], label='grep.match')
2472 fm.write('text', '%s', l.line[s:e], label='grep.match')
2473 fm.data(matched=True)
2473 fm.data(matched=True)
2474 p = e
2474 p = e
2475 if p < len(l.line):
2475 if p < len(l.line):
2476 fm.startitem()
2476 fm.startitem()
2477 fm.write('text', '%s', l.line[p:])
2477 fm.write('text', '%s', l.line[p:])
2478 fm.data(matched=False)
2478 fm.data(matched=False)
2479 fm.end()
2479 fm.end()
2480
2480
2481 skip = {}
2481 skip = {}
2482 revfiles = {}
2482 revfiles = {}
2483 matchfn = scmutil.match(repo[None], pats, opts)
2483 matchfn = scmutil.match(repo[None], pats, opts)
2484 found = False
2484 found = False
2485 follow = opts.get('follow')
2485 follow = opts.get('follow')
2486
2486
2487 def prep(ctx, fns):
2487 def prep(ctx, fns):
2488 rev = ctx.rev()
2488 rev = ctx.rev()
2489 pctx = ctx.p1()
2489 pctx = ctx.p1()
2490 parent = pctx.rev()
2490 parent = pctx.rev()
2491 matches.setdefault(rev, {})
2491 matches.setdefault(rev, {})
2492 matches.setdefault(parent, {})
2492 matches.setdefault(parent, {})
2493 files = revfiles.setdefault(rev, [])
2493 files = revfiles.setdefault(rev, [])
2494 for fn in fns:
2494 for fn in fns:
2495 flog = getfile(fn)
2495 flog = getfile(fn)
2496 try:
2496 try:
2497 fnode = ctx.filenode(fn)
2497 fnode = ctx.filenode(fn)
2498 except error.LookupError:
2498 except error.LookupError:
2499 continue
2499 continue
2500
2500
2501 copied = flog.renamed(fnode)
2501 copied = flog.renamed(fnode)
2502 copy = follow and copied and copied[0]
2502 copy = follow and copied and copied[0]
2503 if copy:
2503 if copy:
2504 copies.setdefault(rev, {})[fn] = copy
2504 copies.setdefault(rev, {})[fn] = copy
2505 if fn in skip:
2505 if fn in skip:
2506 if copy:
2506 if copy:
2507 skip[copy] = True
2507 skip[copy] = True
2508 continue
2508 continue
2509 files.append(fn)
2509 files.append(fn)
2510
2510
2511 if fn not in matches[rev]:
2511 if fn not in matches[rev]:
2512 grepbody(fn, rev, flog.read(fnode))
2512 grepbody(fn, rev, flog.read(fnode))
2513
2513
2514 pfn = copy or fn
2514 pfn = copy or fn
2515 if pfn not in matches[parent]:
2515 if pfn not in matches[parent]:
2516 try:
2516 try:
2517 fnode = pctx.filenode(pfn)
2517 fnode = pctx.filenode(pfn)
2518 grepbody(pfn, parent, flog.read(fnode))
2518 grepbody(pfn, parent, flog.read(fnode))
2519 except error.LookupError:
2519 except error.LookupError:
2520 pass
2520 pass
2521
2521
2522 ui.pager('grep')
2522 ui.pager('grep')
2523 fm = ui.formatter('grep', opts)
2523 fm = ui.formatter('grep', opts)
2524 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2524 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2525 rev = ctx.rev()
2525 rev = ctx.rev()
2526 parent = ctx.p1().rev()
2526 parent = ctx.p1().rev()
2527 for fn in sorted(revfiles.get(rev, [])):
2527 for fn in sorted(revfiles.get(rev, [])):
2528 states = matches[rev][fn]
2528 states = matches[rev][fn]
2529 copy = copies.get(rev, {}).get(fn)
2529 copy = copies.get(rev, {}).get(fn)
2530 if fn in skip:
2530 if fn in skip:
2531 if copy:
2531 if copy:
2532 skip[copy] = True
2532 skip[copy] = True
2533 continue
2533 continue
2534 pstates = matches.get(parent, {}).get(copy or fn, [])
2534 pstates = matches.get(parent, {}).get(copy or fn, [])
2535 if pstates or states:
2535 if pstates or states:
2536 r = display(fm, fn, ctx, pstates, states)
2536 r = display(fm, fn, ctx, pstates, states)
2537 found = found or r
2537 found = found or r
2538 if r and not opts.get('all'):
2538 if r and not opts.get('all'):
2539 skip[fn] = True
2539 skip[fn] = True
2540 if copy:
2540 if copy:
2541 skip[copy] = True
2541 skip[copy] = True
2542 del matches[rev]
2542 del matches[rev]
2543 del revfiles[rev]
2543 del revfiles[rev]
2544 fm.end()
2544 fm.end()
2545
2545
2546 return not found
2546 return not found
2547
2547
2548 @command('heads',
2548 @command('heads',
2549 [('r', 'rev', '',
2549 [('r', 'rev', '',
2550 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2550 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2551 ('t', 'topo', False, _('show topological heads only')),
2551 ('t', 'topo', False, _('show topological heads only')),
2552 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2552 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2553 ('c', 'closed', False, _('show normal and closed branch heads')),
2553 ('c', 'closed', False, _('show normal and closed branch heads')),
2554 ] + templateopts,
2554 ] + templateopts,
2555 _('[-ct] [-r STARTREV] [REV]...'))
2555 _('[-ct] [-r STARTREV] [REV]...'))
2556 def heads(ui, repo, *branchrevs, **opts):
2556 def heads(ui, repo, *branchrevs, **opts):
2557 """show branch heads
2557 """show branch heads
2558
2558
2559 With no arguments, show all open branch heads in the repository.
2559 With no arguments, show all open branch heads in the repository.
2560 Branch heads are changesets that have no descendants on the
2560 Branch heads are changesets that have no descendants on the
2561 same branch. They are where development generally takes place and
2561 same branch. They are where development generally takes place and
2562 are the usual targets for update and merge operations.
2562 are the usual targets for update and merge operations.
2563
2563
2564 If one or more REVs are given, only open branch heads on the
2564 If one or more REVs are given, only open branch heads on the
2565 branches associated with the specified changesets are shown. This
2565 branches associated with the specified changesets are shown. This
2566 means that you can use :hg:`heads .` to see the heads on the
2566 means that you can use :hg:`heads .` to see the heads on the
2567 currently checked-out branch.
2567 currently checked-out branch.
2568
2568
2569 If -c/--closed is specified, also show branch heads marked closed
2569 If -c/--closed is specified, also show branch heads marked closed
2570 (see :hg:`commit --close-branch`).
2570 (see :hg:`commit --close-branch`).
2571
2571
2572 If STARTREV is specified, only those heads that are descendants of
2572 If STARTREV is specified, only those heads that are descendants of
2573 STARTREV will be displayed.
2573 STARTREV will be displayed.
2574
2574
2575 If -t/--topo is specified, named branch mechanics will be ignored and only
2575 If -t/--topo is specified, named branch mechanics will be ignored and only
2576 topological heads (changesets with no children) will be shown.
2576 topological heads (changesets with no children) will be shown.
2577
2577
2578 Returns 0 if matching heads are found, 1 if not.
2578 Returns 0 if matching heads are found, 1 if not.
2579 """
2579 """
2580
2580
2581 opts = pycompat.byteskwargs(opts)
2581 opts = pycompat.byteskwargs(opts)
2582 start = None
2582 start = None
2583 if 'rev' in opts:
2583 if 'rev' in opts:
2584 start = scmutil.revsingle(repo, opts['rev'], None).node()
2584 start = scmutil.revsingle(repo, opts['rev'], None).node()
2585
2585
2586 if opts.get('topo'):
2586 if opts.get('topo'):
2587 heads = [repo[h] for h in repo.heads(start)]
2587 heads = [repo[h] for h in repo.heads(start)]
2588 else:
2588 else:
2589 heads = []
2589 heads = []
2590 for branch in repo.branchmap():
2590 for branch in repo.branchmap():
2591 heads += repo.branchheads(branch, start, opts.get('closed'))
2591 heads += repo.branchheads(branch, start, opts.get('closed'))
2592 heads = [repo[h] for h in heads]
2592 heads = [repo[h] for h in heads]
2593
2593
2594 if branchrevs:
2594 if branchrevs:
2595 branches = set(repo[br].branch() for br in branchrevs)
2595 branches = set(repo[br].branch() for br in branchrevs)
2596 heads = [h for h in heads if h.branch() in branches]
2596 heads = [h for h in heads if h.branch() in branches]
2597
2597
2598 if opts.get('active') and branchrevs:
2598 if opts.get('active') and branchrevs:
2599 dagheads = repo.heads(start)
2599 dagheads = repo.heads(start)
2600 heads = [h for h in heads if h.node() in dagheads]
2600 heads = [h for h in heads if h.node() in dagheads]
2601
2601
2602 if branchrevs:
2602 if branchrevs:
2603 haveheads = set(h.branch() for h in heads)
2603 haveheads = set(h.branch() for h in heads)
2604 if branches - haveheads:
2604 if branches - haveheads:
2605 headless = ', '.join(b for b in branches - haveheads)
2605 headless = ', '.join(b for b in branches - haveheads)
2606 msg = _('no open branch heads found on branches %s')
2606 msg = _('no open branch heads found on branches %s')
2607 if opts.get('rev'):
2607 if opts.get('rev'):
2608 msg += _(' (started at %s)') % opts['rev']
2608 msg += _(' (started at %s)') % opts['rev']
2609 ui.warn((msg + '\n') % headless)
2609 ui.warn((msg + '\n') % headless)
2610
2610
2611 if not heads:
2611 if not heads:
2612 return 1
2612 return 1
2613
2613
2614 ui.pager('heads')
2614 ui.pager('heads')
2615 heads = sorted(heads, key=lambda x: -x.rev())
2615 heads = sorted(heads, key=lambda x: -x.rev())
2616 displayer = cmdutil.show_changeset(ui, repo, opts)
2616 displayer = cmdutil.show_changeset(ui, repo, opts)
2617 for ctx in heads:
2617 for ctx in heads:
2618 displayer.show(ctx)
2618 displayer.show(ctx)
2619 displayer.close()
2619 displayer.close()
2620
2620
2621 @command('help',
2621 @command('help',
2622 [('e', 'extension', None, _('show only help for extensions')),
2622 [('e', 'extension', None, _('show only help for extensions')),
2623 ('c', 'command', None, _('show only help for commands')),
2623 ('c', 'command', None, _('show only help for commands')),
2624 ('k', 'keyword', None, _('show topics matching keyword')),
2624 ('k', 'keyword', None, _('show topics matching keyword')),
2625 ('s', 'system', [], _('show help for specific platform(s)')),
2625 ('s', 'system', [], _('show help for specific platform(s)')),
2626 ],
2626 ],
2627 _('[-ecks] [TOPIC]'),
2627 _('[-ecks] [TOPIC]'),
2628 norepo=True)
2628 norepo=True)
2629 def help_(ui, name=None, **opts):
2629 def help_(ui, name=None, **opts):
2630 """show help for a given topic or a help overview
2630 """show help for a given topic or a help overview
2631
2631
2632 With no arguments, print a list of commands with short help messages.
2632 With no arguments, print a list of commands with short help messages.
2633
2633
2634 Given a topic, extension, or command name, print help for that
2634 Given a topic, extension, or command name, print help for that
2635 topic.
2635 topic.
2636
2636
2637 Returns 0 if successful.
2637 Returns 0 if successful.
2638 """
2638 """
2639
2639
2640 keep = opts.get(r'system') or []
2640 keep = opts.get(r'system') or []
2641 if len(keep) == 0:
2641 if len(keep) == 0:
2642 if pycompat.sysplatform.startswith('win'):
2642 if pycompat.sysplatform.startswith('win'):
2643 keep.append('windows')
2643 keep.append('windows')
2644 elif pycompat.sysplatform == 'OpenVMS':
2644 elif pycompat.sysplatform == 'OpenVMS':
2645 keep.append('vms')
2645 keep.append('vms')
2646 elif pycompat.sysplatform == 'plan9':
2646 elif pycompat.sysplatform == 'plan9':
2647 keep.append('plan9')
2647 keep.append('plan9')
2648 else:
2648 else:
2649 keep.append('unix')
2649 keep.append('unix')
2650 keep.append(pycompat.sysplatform.lower())
2650 keep.append(pycompat.sysplatform.lower())
2651 if ui.verbose:
2651 if ui.verbose:
2652 keep.append('verbose')
2652 keep.append('verbose')
2653
2653
2654 commands = sys.modules[__name__]
2654 commands = sys.modules[__name__]
2655 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2655 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2656 ui.pager('help')
2656 ui.pager('help')
2657 ui.write(formatted)
2657 ui.write(formatted)
2658
2658
2659
2659
2660 @command('identify|id',
2660 @command('identify|id',
2661 [('r', 'rev', '',
2661 [('r', 'rev', '',
2662 _('identify the specified revision'), _('REV')),
2662 _('identify the specified revision'), _('REV')),
2663 ('n', 'num', None, _('show local revision number')),
2663 ('n', 'num', None, _('show local revision number')),
2664 ('i', 'id', None, _('show global revision id')),
2664 ('i', 'id', None, _('show global revision id')),
2665 ('b', 'branch', None, _('show branch')),
2665 ('b', 'branch', None, _('show branch')),
2666 ('t', 'tags', None, _('show tags')),
2666 ('t', 'tags', None, _('show tags')),
2667 ('B', 'bookmarks', None, _('show bookmarks')),
2667 ('B', 'bookmarks', None, _('show bookmarks')),
2668 ] + remoteopts,
2668 ] + remoteopts,
2669 _('[-nibtB] [-r REV] [SOURCE]'),
2669 _('[-nibtB] [-r REV] [SOURCE]'),
2670 optionalrepo=True)
2670 optionalrepo=True)
2671 def identify(ui, repo, source=None, rev=None,
2671 def identify(ui, repo, source=None, rev=None,
2672 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2672 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2673 """identify the working directory or specified revision
2673 """identify the working directory or specified revision
2674
2674
2675 Print a summary identifying the repository state at REV using one or
2675 Print a summary identifying the repository state at REV using one or
2676 two parent hash identifiers, followed by a "+" if the working
2676 two parent hash identifiers, followed by a "+" if the working
2677 directory has uncommitted changes, the branch name (if not default),
2677 directory has uncommitted changes, the branch name (if not default),
2678 a list of tags, and a list of bookmarks.
2678 a list of tags, and a list of bookmarks.
2679
2679
2680 When REV is not given, print a summary of the current state of the
2680 When REV is not given, print a summary of the current state of the
2681 repository.
2681 repository.
2682
2682
2683 Specifying a path to a repository root or Mercurial bundle will
2683 Specifying a path to a repository root or Mercurial bundle will
2684 cause lookup to operate on that repository/bundle.
2684 cause lookup to operate on that repository/bundle.
2685
2685
2686 .. container:: verbose
2686 .. container:: verbose
2687
2687
2688 Examples:
2688 Examples:
2689
2689
2690 - generate a build identifier for the working directory::
2690 - generate a build identifier for the working directory::
2691
2691
2692 hg id --id > build-id.dat
2692 hg id --id > build-id.dat
2693
2693
2694 - find the revision corresponding to a tag::
2694 - find the revision corresponding to a tag::
2695
2695
2696 hg id -n -r 1.3
2696 hg id -n -r 1.3
2697
2697
2698 - check the most recent revision of a remote repository::
2698 - check the most recent revision of a remote repository::
2699
2699
2700 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2700 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2701
2701
2702 See :hg:`log` for generating more information about specific revisions,
2702 See :hg:`log` for generating more information about specific revisions,
2703 including full hash identifiers.
2703 including full hash identifiers.
2704
2704
2705 Returns 0 if successful.
2705 Returns 0 if successful.
2706 """
2706 """
2707
2707
2708 opts = pycompat.byteskwargs(opts)
2708 opts = pycompat.byteskwargs(opts)
2709 if not repo and not source:
2709 if not repo and not source:
2710 raise error.Abort(_("there is no Mercurial repository here "
2710 raise error.Abort(_("there is no Mercurial repository here "
2711 "(.hg not found)"))
2711 "(.hg not found)"))
2712
2712
2713 if ui.debugflag:
2713 if ui.debugflag:
2714 hexfunc = hex
2714 hexfunc = hex
2715 else:
2715 else:
2716 hexfunc = short
2716 hexfunc = short
2717 default = not (num or id or branch or tags or bookmarks)
2717 default = not (num or id or branch or tags or bookmarks)
2718 output = []
2718 output = []
2719 revs = []
2719 revs = []
2720
2720
2721 if source:
2721 if source:
2722 source, branches = hg.parseurl(ui.expandpath(source))
2722 source, branches = hg.parseurl(ui.expandpath(source))
2723 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2723 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2724 repo = peer.local()
2724 repo = peer.local()
2725 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2725 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2726
2726
2727 if not repo:
2727 if not repo:
2728 if num or branch or tags:
2728 if num or branch or tags:
2729 raise error.Abort(
2729 raise error.Abort(
2730 _("can't query remote revision number, branch, or tags"))
2730 _("can't query remote revision number, branch, or tags"))
2731 if not rev and revs:
2731 if not rev and revs:
2732 rev = revs[0]
2732 rev = revs[0]
2733 if not rev:
2733 if not rev:
2734 rev = "tip"
2734 rev = "tip"
2735
2735
2736 remoterev = peer.lookup(rev)
2736 remoterev = peer.lookup(rev)
2737 if default or id:
2737 if default or id:
2738 output = [hexfunc(remoterev)]
2738 output = [hexfunc(remoterev)]
2739
2739
2740 def getbms():
2740 def getbms():
2741 bms = []
2741 bms = []
2742
2742
2743 if 'bookmarks' in peer.listkeys('namespaces'):
2743 if 'bookmarks' in peer.listkeys('namespaces'):
2744 hexremoterev = hex(remoterev)
2744 hexremoterev = hex(remoterev)
2745 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2745 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2746 if bmr == hexremoterev]
2746 if bmr == hexremoterev]
2747
2747
2748 return sorted(bms)
2748 return sorted(bms)
2749
2749
2750 if bookmarks:
2750 if bookmarks:
2751 output.extend(getbms())
2751 output.extend(getbms())
2752 elif default and not ui.quiet:
2752 elif default and not ui.quiet:
2753 # multiple bookmarks for a single parent separated by '/'
2753 # multiple bookmarks for a single parent separated by '/'
2754 bm = '/'.join(getbms())
2754 bm = '/'.join(getbms())
2755 if bm:
2755 if bm:
2756 output.append(bm)
2756 output.append(bm)
2757 else:
2757 else:
2758 ctx = scmutil.revsingle(repo, rev, None)
2758 ctx = scmutil.revsingle(repo, rev, None)
2759
2759
2760 if ctx.rev() is None:
2760 if ctx.rev() is None:
2761 ctx = repo[None]
2761 ctx = repo[None]
2762 parents = ctx.parents()
2762 parents = ctx.parents()
2763 taglist = []
2763 taglist = []
2764 for p in parents:
2764 for p in parents:
2765 taglist.extend(p.tags())
2765 taglist.extend(p.tags())
2766
2766
2767 changed = ""
2767 changed = ""
2768 if default or id or num:
2768 if default or id or num:
2769 if (any(repo.status())
2769 if (any(repo.status())
2770 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2770 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2771 changed = '+'
2771 changed = '+'
2772 if default or id:
2772 if default or id:
2773 output = ["%s%s" %
2773 output = ["%s%s" %
2774 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2774 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2775 if num:
2775 if num:
2776 output.append("%s%s" %
2776 output.append("%s%s" %
2777 ('+'.join([pycompat.bytestr(p.rev()) for p in parents]),
2777 ('+'.join(["%d" % p.rev() for p in parents]), changed))
2778 changed))
2779 else:
2778 else:
2780 if default or id:
2779 if default or id:
2781 output = [hexfunc(ctx.node())]
2780 output = [hexfunc(ctx.node())]
2782 if num:
2781 if num:
2783 output.append(pycompat.bytestr(ctx.rev()))
2782 output.append(pycompat.bytestr(ctx.rev()))
2784 taglist = ctx.tags()
2783 taglist = ctx.tags()
2785
2784
2786 if default and not ui.quiet:
2785 if default and not ui.quiet:
2787 b = ctx.branch()
2786 b = ctx.branch()
2788 if b != 'default':
2787 if b != 'default':
2789 output.append("(%s)" % b)
2788 output.append("(%s)" % b)
2790
2789
2791 # multiple tags for a single parent separated by '/'
2790 # multiple tags for a single parent separated by '/'
2792 t = '/'.join(taglist)
2791 t = '/'.join(taglist)
2793 if t:
2792 if t:
2794 output.append(t)
2793 output.append(t)
2795
2794
2796 # multiple bookmarks for a single parent separated by '/'
2795 # multiple bookmarks for a single parent separated by '/'
2797 bm = '/'.join(ctx.bookmarks())
2796 bm = '/'.join(ctx.bookmarks())
2798 if bm:
2797 if bm:
2799 output.append(bm)
2798 output.append(bm)
2800 else:
2799 else:
2801 if branch:
2800 if branch:
2802 output.append(ctx.branch())
2801 output.append(ctx.branch())
2803
2802
2804 if tags:
2803 if tags:
2805 output.extend(taglist)
2804 output.extend(taglist)
2806
2805
2807 if bookmarks:
2806 if bookmarks:
2808 output.extend(ctx.bookmarks())
2807 output.extend(ctx.bookmarks())
2809
2808
2810 ui.write("%s\n" % ' '.join(output))
2809 ui.write("%s\n" % ' '.join(output))
2811
2810
2812 @command('import|patch',
2811 @command('import|patch',
2813 [('p', 'strip', 1,
2812 [('p', 'strip', 1,
2814 _('directory strip option for patch. This has the same '
2813 _('directory strip option for patch. This has the same '
2815 'meaning as the corresponding patch option'), _('NUM')),
2814 'meaning as the corresponding patch option'), _('NUM')),
2816 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2815 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2817 ('e', 'edit', False, _('invoke editor on commit messages')),
2816 ('e', 'edit', False, _('invoke editor on commit messages')),
2818 ('f', 'force', None,
2817 ('f', 'force', None,
2819 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2818 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2820 ('', 'no-commit', None,
2819 ('', 'no-commit', None,
2821 _("don't commit, just update the working directory")),
2820 _("don't commit, just update the working directory")),
2822 ('', 'bypass', None,
2821 ('', 'bypass', None,
2823 _("apply patch without touching the working directory")),
2822 _("apply patch without touching the working directory")),
2824 ('', 'partial', None,
2823 ('', 'partial', None,
2825 _('commit even if some hunks fail')),
2824 _('commit even if some hunks fail')),
2826 ('', 'exact', None,
2825 ('', 'exact', None,
2827 _('abort if patch would apply lossily')),
2826 _('abort if patch would apply lossily')),
2828 ('', 'prefix', '',
2827 ('', 'prefix', '',
2829 _('apply patch to subdirectory'), _('DIR')),
2828 _('apply patch to subdirectory'), _('DIR')),
2830 ('', 'import-branch', None,
2829 ('', 'import-branch', None,
2831 _('use any branch information in patch (implied by --exact)'))] +
2830 _('use any branch information in patch (implied by --exact)'))] +
2832 commitopts + commitopts2 + similarityopts,
2831 commitopts + commitopts2 + similarityopts,
2833 _('[OPTION]... PATCH...'))
2832 _('[OPTION]... PATCH...'))
2834 def import_(ui, repo, patch1=None, *patches, **opts):
2833 def import_(ui, repo, patch1=None, *patches, **opts):
2835 """import an ordered set of patches
2834 """import an ordered set of patches
2836
2835
2837 Import a list of patches and commit them individually (unless
2836 Import a list of patches and commit them individually (unless
2838 --no-commit is specified).
2837 --no-commit is specified).
2839
2838
2840 To read a patch from standard input (stdin), use "-" as the patch
2839 To read a patch from standard input (stdin), use "-" as the patch
2841 name. If a URL is specified, the patch will be downloaded from
2840 name. If a URL is specified, the patch will be downloaded from
2842 there.
2841 there.
2843
2842
2844 Import first applies changes to the working directory (unless
2843 Import first applies changes to the working directory (unless
2845 --bypass is specified), import will abort if there are outstanding
2844 --bypass is specified), import will abort if there are outstanding
2846 changes.
2845 changes.
2847
2846
2848 Use --bypass to apply and commit patches directly to the
2847 Use --bypass to apply and commit patches directly to the
2849 repository, without affecting the working directory. Without
2848 repository, without affecting the working directory. Without
2850 --exact, patches will be applied on top of the working directory
2849 --exact, patches will be applied on top of the working directory
2851 parent revision.
2850 parent revision.
2852
2851
2853 You can import a patch straight from a mail message. Even patches
2852 You can import a patch straight from a mail message. Even patches
2854 as attachments work (to use the body part, it must have type
2853 as attachments work (to use the body part, it must have type
2855 text/plain or text/x-patch). From and Subject headers of email
2854 text/plain or text/x-patch). From and Subject headers of email
2856 message are used as default committer and commit message. All
2855 message are used as default committer and commit message. All
2857 text/plain body parts before first diff are added to the commit
2856 text/plain body parts before first diff are added to the commit
2858 message.
2857 message.
2859
2858
2860 If the imported patch was generated by :hg:`export`, user and
2859 If the imported patch was generated by :hg:`export`, user and
2861 description from patch override values from message headers and
2860 description from patch override values from message headers and
2862 body. Values given on command line with -m/--message and -u/--user
2861 body. Values given on command line with -m/--message and -u/--user
2863 override these.
2862 override these.
2864
2863
2865 If --exact is specified, import will set the working directory to
2864 If --exact is specified, import will set the working directory to
2866 the parent of each patch before applying it, and will abort if the
2865 the parent of each patch before applying it, and will abort if the
2867 resulting changeset has a different ID than the one recorded in
2866 resulting changeset has a different ID than the one recorded in
2868 the patch. This will guard against various ways that portable
2867 the patch. This will guard against various ways that portable
2869 patch formats and mail systems might fail to transfer Mercurial
2868 patch formats and mail systems might fail to transfer Mercurial
2870 data or metadata. See :hg:`bundle` for lossless transmission.
2869 data or metadata. See :hg:`bundle` for lossless transmission.
2871
2870
2872 Use --partial to ensure a changeset will be created from the patch
2871 Use --partial to ensure a changeset will be created from the patch
2873 even if some hunks fail to apply. Hunks that fail to apply will be
2872 even if some hunks fail to apply. Hunks that fail to apply will be
2874 written to a <target-file>.rej file. Conflicts can then be resolved
2873 written to a <target-file>.rej file. Conflicts can then be resolved
2875 by hand before :hg:`commit --amend` is run to update the created
2874 by hand before :hg:`commit --amend` is run to update the created
2876 changeset. This flag exists to let people import patches that
2875 changeset. This flag exists to let people import patches that
2877 partially apply without losing the associated metadata (author,
2876 partially apply without losing the associated metadata (author,
2878 date, description, ...).
2877 date, description, ...).
2879
2878
2880 .. note::
2879 .. note::
2881
2880
2882 When no hunks apply cleanly, :hg:`import --partial` will create
2881 When no hunks apply cleanly, :hg:`import --partial` will create
2883 an empty changeset, importing only the patch metadata.
2882 an empty changeset, importing only the patch metadata.
2884
2883
2885 With -s/--similarity, hg will attempt to discover renames and
2884 With -s/--similarity, hg will attempt to discover renames and
2886 copies in the patch in the same way as :hg:`addremove`.
2885 copies in the patch in the same way as :hg:`addremove`.
2887
2886
2888 It is possible to use external patch programs to perform the patch
2887 It is possible to use external patch programs to perform the patch
2889 by setting the ``ui.patch`` configuration option. For the default
2888 by setting the ``ui.patch`` configuration option. For the default
2890 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2889 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2891 See :hg:`help config` for more information about configuration
2890 See :hg:`help config` for more information about configuration
2892 files and how to use these options.
2891 files and how to use these options.
2893
2892
2894 See :hg:`help dates` for a list of formats valid for -d/--date.
2893 See :hg:`help dates` for a list of formats valid for -d/--date.
2895
2894
2896 .. container:: verbose
2895 .. container:: verbose
2897
2896
2898 Examples:
2897 Examples:
2899
2898
2900 - import a traditional patch from a website and detect renames::
2899 - import a traditional patch from a website and detect renames::
2901
2900
2902 hg import -s 80 http://example.com/bugfix.patch
2901 hg import -s 80 http://example.com/bugfix.patch
2903
2902
2904 - import a changeset from an hgweb server::
2903 - import a changeset from an hgweb server::
2905
2904
2906 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2905 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2907
2906
2908 - import all the patches in an Unix-style mbox::
2907 - import all the patches in an Unix-style mbox::
2909
2908
2910 hg import incoming-patches.mbox
2909 hg import incoming-patches.mbox
2911
2910
2912 - import patches from stdin::
2911 - import patches from stdin::
2913
2912
2914 hg import -
2913 hg import -
2915
2914
2916 - attempt to exactly restore an exported changeset (not always
2915 - attempt to exactly restore an exported changeset (not always
2917 possible)::
2916 possible)::
2918
2917
2919 hg import --exact proposed-fix.patch
2918 hg import --exact proposed-fix.patch
2920
2919
2921 - use an external tool to apply a patch which is too fuzzy for
2920 - use an external tool to apply a patch which is too fuzzy for
2922 the default internal tool.
2921 the default internal tool.
2923
2922
2924 hg import --config ui.patch="patch --merge" fuzzy.patch
2923 hg import --config ui.patch="patch --merge" fuzzy.patch
2925
2924
2926 - change the default fuzzing from 2 to a less strict 7
2925 - change the default fuzzing from 2 to a less strict 7
2927
2926
2928 hg import --config ui.fuzz=7 fuzz.patch
2927 hg import --config ui.fuzz=7 fuzz.patch
2929
2928
2930 Returns 0 on success, 1 on partial success (see --partial).
2929 Returns 0 on success, 1 on partial success (see --partial).
2931 """
2930 """
2932
2931
2933 opts = pycompat.byteskwargs(opts)
2932 opts = pycompat.byteskwargs(opts)
2934 if not patch1:
2933 if not patch1:
2935 raise error.Abort(_('need at least one patch to import'))
2934 raise error.Abort(_('need at least one patch to import'))
2936
2935
2937 patches = (patch1,) + patches
2936 patches = (patch1,) + patches
2938
2937
2939 date = opts.get('date')
2938 date = opts.get('date')
2940 if date:
2939 if date:
2941 opts['date'] = util.parsedate(date)
2940 opts['date'] = util.parsedate(date)
2942
2941
2943 exact = opts.get('exact')
2942 exact = opts.get('exact')
2944 update = not opts.get('bypass')
2943 update = not opts.get('bypass')
2945 if not update and opts.get('no_commit'):
2944 if not update and opts.get('no_commit'):
2946 raise error.Abort(_('cannot use --no-commit with --bypass'))
2945 raise error.Abort(_('cannot use --no-commit with --bypass'))
2947 try:
2946 try:
2948 sim = float(opts.get('similarity') or 0)
2947 sim = float(opts.get('similarity') or 0)
2949 except ValueError:
2948 except ValueError:
2950 raise error.Abort(_('similarity must be a number'))
2949 raise error.Abort(_('similarity must be a number'))
2951 if sim < 0 or sim > 100:
2950 if sim < 0 or sim > 100:
2952 raise error.Abort(_('similarity must be between 0 and 100'))
2951 raise error.Abort(_('similarity must be between 0 and 100'))
2953 if sim and not update:
2952 if sim and not update:
2954 raise error.Abort(_('cannot use --similarity with --bypass'))
2953 raise error.Abort(_('cannot use --similarity with --bypass'))
2955 if exact:
2954 if exact:
2956 if opts.get('edit'):
2955 if opts.get('edit'):
2957 raise error.Abort(_('cannot use --exact with --edit'))
2956 raise error.Abort(_('cannot use --exact with --edit'))
2958 if opts.get('prefix'):
2957 if opts.get('prefix'):
2959 raise error.Abort(_('cannot use --exact with --prefix'))
2958 raise error.Abort(_('cannot use --exact with --prefix'))
2960
2959
2961 base = opts["base"]
2960 base = opts["base"]
2962 wlock = dsguard = lock = tr = None
2961 wlock = dsguard = lock = tr = None
2963 msgs = []
2962 msgs = []
2964 ret = 0
2963 ret = 0
2965
2964
2966
2965
2967 try:
2966 try:
2968 wlock = repo.wlock()
2967 wlock = repo.wlock()
2969
2968
2970 if update:
2969 if update:
2971 cmdutil.checkunfinished(repo)
2970 cmdutil.checkunfinished(repo)
2972 if (exact or not opts.get('force')):
2971 if (exact or not opts.get('force')):
2973 cmdutil.bailifchanged(repo)
2972 cmdutil.bailifchanged(repo)
2974
2973
2975 if not opts.get('no_commit'):
2974 if not opts.get('no_commit'):
2976 lock = repo.lock()
2975 lock = repo.lock()
2977 tr = repo.transaction('import')
2976 tr = repo.transaction('import')
2978 else:
2977 else:
2979 dsguard = dirstateguard.dirstateguard(repo, 'import')
2978 dsguard = dirstateguard.dirstateguard(repo, 'import')
2980 parents = repo[None].parents()
2979 parents = repo[None].parents()
2981 for patchurl in patches:
2980 for patchurl in patches:
2982 if patchurl == '-':
2981 if patchurl == '-':
2983 ui.status(_('applying patch from stdin\n'))
2982 ui.status(_('applying patch from stdin\n'))
2984 patchfile = ui.fin
2983 patchfile = ui.fin
2985 patchurl = 'stdin' # for error message
2984 patchurl = 'stdin' # for error message
2986 else:
2985 else:
2987 patchurl = os.path.join(base, patchurl)
2986 patchurl = os.path.join(base, patchurl)
2988 ui.status(_('applying %s\n') % patchurl)
2987 ui.status(_('applying %s\n') % patchurl)
2989 patchfile = hg.openpath(ui, patchurl)
2988 patchfile = hg.openpath(ui, patchurl)
2990
2989
2991 haspatch = False
2990 haspatch = False
2992 for hunk in patch.split(patchfile):
2991 for hunk in patch.split(patchfile):
2993 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
2992 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
2994 parents, opts,
2993 parents, opts,
2995 msgs, hg.clean)
2994 msgs, hg.clean)
2996 if msg:
2995 if msg:
2997 haspatch = True
2996 haspatch = True
2998 ui.note(msg + '\n')
2997 ui.note(msg + '\n')
2999 if update or exact:
2998 if update or exact:
3000 parents = repo[None].parents()
2999 parents = repo[None].parents()
3001 else:
3000 else:
3002 parents = [repo[node]]
3001 parents = [repo[node]]
3003 if rej:
3002 if rej:
3004 ui.write_err(_("patch applied partially\n"))
3003 ui.write_err(_("patch applied partially\n"))
3005 ui.write_err(_("(fix the .rej files and run "
3004 ui.write_err(_("(fix the .rej files and run "
3006 "`hg commit --amend`)\n"))
3005 "`hg commit --amend`)\n"))
3007 ret = 1
3006 ret = 1
3008 break
3007 break
3009
3008
3010 if not haspatch:
3009 if not haspatch:
3011 raise error.Abort(_('%s: no diffs found') % patchurl)
3010 raise error.Abort(_('%s: no diffs found') % patchurl)
3012
3011
3013 if tr:
3012 if tr:
3014 tr.close()
3013 tr.close()
3015 if msgs:
3014 if msgs:
3016 repo.savecommitmessage('\n* * *\n'.join(msgs))
3015 repo.savecommitmessage('\n* * *\n'.join(msgs))
3017 if dsguard:
3016 if dsguard:
3018 dsguard.close()
3017 dsguard.close()
3019 return ret
3018 return ret
3020 finally:
3019 finally:
3021 if tr:
3020 if tr:
3022 tr.release()
3021 tr.release()
3023 release(lock, dsguard, wlock)
3022 release(lock, dsguard, wlock)
3024
3023
3025 @command('incoming|in',
3024 @command('incoming|in',
3026 [('f', 'force', None,
3025 [('f', 'force', None,
3027 _('run even if remote repository is unrelated')),
3026 _('run even if remote repository is unrelated')),
3028 ('n', 'newest-first', None, _('show newest record first')),
3027 ('n', 'newest-first', None, _('show newest record first')),
3029 ('', 'bundle', '',
3028 ('', 'bundle', '',
3030 _('file to store the bundles into'), _('FILE')),
3029 _('file to store the bundles into'), _('FILE')),
3031 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3030 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3032 ('B', 'bookmarks', False, _("compare bookmarks")),
3031 ('B', 'bookmarks', False, _("compare bookmarks")),
3033 ('b', 'branch', [],
3032 ('b', 'branch', [],
3034 _('a specific branch you would like to pull'), _('BRANCH')),
3033 _('a specific branch you would like to pull'), _('BRANCH')),
3035 ] + logopts + remoteopts + subrepoopts,
3034 ] + logopts + remoteopts + subrepoopts,
3036 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3035 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3037 def incoming(ui, repo, source="default", **opts):
3036 def incoming(ui, repo, source="default", **opts):
3038 """show new changesets found in source
3037 """show new changesets found in source
3039
3038
3040 Show new changesets found in the specified path/URL or the default
3039 Show new changesets found in the specified path/URL or the default
3041 pull location. These are the changesets that would have been pulled
3040 pull location. These are the changesets that would have been pulled
3042 if a pull at the time you issued this command.
3041 if a pull at the time you issued this command.
3043
3042
3044 See pull for valid source format details.
3043 See pull for valid source format details.
3045
3044
3046 .. container:: verbose
3045 .. container:: verbose
3047
3046
3048 With -B/--bookmarks, the result of bookmark comparison between
3047 With -B/--bookmarks, the result of bookmark comparison between
3049 local and remote repositories is displayed. With -v/--verbose,
3048 local and remote repositories is displayed. With -v/--verbose,
3050 status is also displayed for each bookmark like below::
3049 status is also displayed for each bookmark like below::
3051
3050
3052 BM1 01234567890a added
3051 BM1 01234567890a added
3053 BM2 1234567890ab advanced
3052 BM2 1234567890ab advanced
3054 BM3 234567890abc diverged
3053 BM3 234567890abc diverged
3055 BM4 34567890abcd changed
3054 BM4 34567890abcd changed
3056
3055
3057 The action taken locally when pulling depends on the
3056 The action taken locally when pulling depends on the
3058 status of each bookmark:
3057 status of each bookmark:
3059
3058
3060 :``added``: pull will create it
3059 :``added``: pull will create it
3061 :``advanced``: pull will update it
3060 :``advanced``: pull will update it
3062 :``diverged``: pull will create a divergent bookmark
3061 :``diverged``: pull will create a divergent bookmark
3063 :``changed``: result depends on remote changesets
3062 :``changed``: result depends on remote changesets
3064
3063
3065 From the point of view of pulling behavior, bookmark
3064 From the point of view of pulling behavior, bookmark
3066 existing only in the remote repository are treated as ``added``,
3065 existing only in the remote repository are treated as ``added``,
3067 even if it is in fact locally deleted.
3066 even if it is in fact locally deleted.
3068
3067
3069 .. container:: verbose
3068 .. container:: verbose
3070
3069
3071 For remote repository, using --bundle avoids downloading the
3070 For remote repository, using --bundle avoids downloading the
3072 changesets twice if the incoming is followed by a pull.
3071 changesets twice if the incoming is followed by a pull.
3073
3072
3074 Examples:
3073 Examples:
3075
3074
3076 - show incoming changes with patches and full description::
3075 - show incoming changes with patches and full description::
3077
3076
3078 hg incoming -vp
3077 hg incoming -vp
3079
3078
3080 - show incoming changes excluding merges, store a bundle::
3079 - show incoming changes excluding merges, store a bundle::
3081
3080
3082 hg in -vpM --bundle incoming.hg
3081 hg in -vpM --bundle incoming.hg
3083 hg pull incoming.hg
3082 hg pull incoming.hg
3084
3083
3085 - briefly list changes inside a bundle::
3084 - briefly list changes inside a bundle::
3086
3085
3087 hg in changes.hg -T "{desc|firstline}\\n"
3086 hg in changes.hg -T "{desc|firstline}\\n"
3088
3087
3089 Returns 0 if there are incoming changes, 1 otherwise.
3088 Returns 0 if there are incoming changes, 1 otherwise.
3090 """
3089 """
3091 opts = pycompat.byteskwargs(opts)
3090 opts = pycompat.byteskwargs(opts)
3092 if opts.get('graph'):
3091 if opts.get('graph'):
3093 cmdutil.checkunsupportedgraphflags([], opts)
3092 cmdutil.checkunsupportedgraphflags([], opts)
3094 def display(other, chlist, displayer):
3093 def display(other, chlist, displayer):
3095 revdag = cmdutil.graphrevs(other, chlist, opts)
3094 revdag = cmdutil.graphrevs(other, chlist, opts)
3096 cmdutil.displaygraph(ui, repo, revdag, displayer,
3095 cmdutil.displaygraph(ui, repo, revdag, displayer,
3097 graphmod.asciiedges)
3096 graphmod.asciiedges)
3098
3097
3099 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3098 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3100 return 0
3099 return 0
3101
3100
3102 if opts.get('bundle') and opts.get('subrepos'):
3101 if opts.get('bundle') and opts.get('subrepos'):
3103 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3102 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3104
3103
3105 if opts.get('bookmarks'):
3104 if opts.get('bookmarks'):
3106 source, branches = hg.parseurl(ui.expandpath(source),
3105 source, branches = hg.parseurl(ui.expandpath(source),
3107 opts.get('branch'))
3106 opts.get('branch'))
3108 other = hg.peer(repo, opts, source)
3107 other = hg.peer(repo, opts, source)
3109 if 'bookmarks' not in other.listkeys('namespaces'):
3108 if 'bookmarks' not in other.listkeys('namespaces'):
3110 ui.warn(_("remote doesn't support bookmarks\n"))
3109 ui.warn(_("remote doesn't support bookmarks\n"))
3111 return 0
3110 return 0
3112 ui.pager('incoming')
3111 ui.pager('incoming')
3113 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3112 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3114 return bookmarks.incoming(ui, repo, other)
3113 return bookmarks.incoming(ui, repo, other)
3115
3114
3116 repo._subtoppath = ui.expandpath(source)
3115 repo._subtoppath = ui.expandpath(source)
3117 try:
3116 try:
3118 return hg.incoming(ui, repo, source, opts)
3117 return hg.incoming(ui, repo, source, opts)
3119 finally:
3118 finally:
3120 del repo._subtoppath
3119 del repo._subtoppath
3121
3120
3122
3121
3123 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3122 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3124 norepo=True)
3123 norepo=True)
3125 def init(ui, dest=".", **opts):
3124 def init(ui, dest=".", **opts):
3126 """create a new repository in the given directory
3125 """create a new repository in the given directory
3127
3126
3128 Initialize a new repository in the given directory. If the given
3127 Initialize a new repository in the given directory. If the given
3129 directory does not exist, it will be created.
3128 directory does not exist, it will be created.
3130
3129
3131 If no directory is given, the current directory is used.
3130 If no directory is given, the current directory is used.
3132
3131
3133 It is possible to specify an ``ssh://`` URL as the destination.
3132 It is possible to specify an ``ssh://`` URL as the destination.
3134 See :hg:`help urls` for more information.
3133 See :hg:`help urls` for more information.
3135
3134
3136 Returns 0 on success.
3135 Returns 0 on success.
3137 """
3136 """
3138 opts = pycompat.byteskwargs(opts)
3137 opts = pycompat.byteskwargs(opts)
3139 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3138 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3140
3139
3141 @command('locate',
3140 @command('locate',
3142 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3141 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3143 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3142 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3144 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3143 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3145 ] + walkopts,
3144 ] + walkopts,
3146 _('[OPTION]... [PATTERN]...'))
3145 _('[OPTION]... [PATTERN]...'))
3147 def locate(ui, repo, *pats, **opts):
3146 def locate(ui, repo, *pats, **opts):
3148 """locate files matching specific patterns (DEPRECATED)
3147 """locate files matching specific patterns (DEPRECATED)
3149
3148
3150 Print files under Mercurial control in the working directory whose
3149 Print files under Mercurial control in the working directory whose
3151 names match the given patterns.
3150 names match the given patterns.
3152
3151
3153 By default, this command searches all directories in the working
3152 By default, this command searches all directories in the working
3154 directory. To search just the current directory and its
3153 directory. To search just the current directory and its
3155 subdirectories, use "--include .".
3154 subdirectories, use "--include .".
3156
3155
3157 If no patterns are given to match, this command prints the names
3156 If no patterns are given to match, this command prints the names
3158 of all files under Mercurial control in the working directory.
3157 of all files under Mercurial control in the working directory.
3159
3158
3160 If you want to feed the output of this command into the "xargs"
3159 If you want to feed the output of this command into the "xargs"
3161 command, use the -0 option to both this command and "xargs". This
3160 command, use the -0 option to both this command and "xargs". This
3162 will avoid the problem of "xargs" treating single filenames that
3161 will avoid the problem of "xargs" treating single filenames that
3163 contain whitespace as multiple filenames.
3162 contain whitespace as multiple filenames.
3164
3163
3165 See :hg:`help files` for a more versatile command.
3164 See :hg:`help files` for a more versatile command.
3166
3165
3167 Returns 0 if a match is found, 1 otherwise.
3166 Returns 0 if a match is found, 1 otherwise.
3168 """
3167 """
3169 opts = pycompat.byteskwargs(opts)
3168 opts = pycompat.byteskwargs(opts)
3170 if opts.get('print0'):
3169 if opts.get('print0'):
3171 end = '\0'
3170 end = '\0'
3172 else:
3171 else:
3173 end = '\n'
3172 end = '\n'
3174 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3173 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3175
3174
3176 ret = 1
3175 ret = 1
3177 ctx = repo[rev]
3176 ctx = repo[rev]
3178 m = scmutil.match(ctx, pats, opts, default='relglob',
3177 m = scmutil.match(ctx, pats, opts, default='relglob',
3179 badfn=lambda x, y: False)
3178 badfn=lambda x, y: False)
3180
3179
3181 ui.pager('locate')
3180 ui.pager('locate')
3182 for abs in ctx.matches(m):
3181 for abs in ctx.matches(m):
3183 if opts.get('fullpath'):
3182 if opts.get('fullpath'):
3184 ui.write(repo.wjoin(abs), end)
3183 ui.write(repo.wjoin(abs), end)
3185 else:
3184 else:
3186 ui.write(((pats and m.rel(abs)) or abs), end)
3185 ui.write(((pats and m.rel(abs)) or abs), end)
3187 ret = 0
3186 ret = 0
3188
3187
3189 return ret
3188 return ret
3190
3189
3191 @command('^log|history',
3190 @command('^log|history',
3192 [('f', 'follow', None,
3191 [('f', 'follow', None,
3193 _('follow changeset history, or file history across copies and renames')),
3192 _('follow changeset history, or file history across copies and renames')),
3194 ('', 'follow-first', None,
3193 ('', 'follow-first', None,
3195 _('only follow the first parent of merge changesets (DEPRECATED)')),
3194 _('only follow the first parent of merge changesets (DEPRECATED)')),
3196 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3195 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3197 ('C', 'copies', None, _('show copied files')),
3196 ('C', 'copies', None, _('show copied files')),
3198 ('k', 'keyword', [],
3197 ('k', 'keyword', [],
3199 _('do case-insensitive search for a given text'), _('TEXT')),
3198 _('do case-insensitive search for a given text'), _('TEXT')),
3200 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3199 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3201 ('', 'removed', None, _('include revisions where files were removed')),
3200 ('', 'removed', None, _('include revisions where files were removed')),
3202 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3201 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3203 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3202 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3204 ('', 'only-branch', [],
3203 ('', 'only-branch', [],
3205 _('show only changesets within the given named branch (DEPRECATED)'),
3204 _('show only changesets within the given named branch (DEPRECATED)'),
3206 _('BRANCH')),
3205 _('BRANCH')),
3207 ('b', 'branch', [],
3206 ('b', 'branch', [],
3208 _('show changesets within the given named branch'), _('BRANCH')),
3207 _('show changesets within the given named branch'), _('BRANCH')),
3209 ('P', 'prune', [],
3208 ('P', 'prune', [],
3210 _('do not display revision or any of its ancestors'), _('REV')),
3209 _('do not display revision or any of its ancestors'), _('REV')),
3211 ] + logopts + walkopts,
3210 ] + logopts + walkopts,
3212 _('[OPTION]... [FILE]'),
3211 _('[OPTION]... [FILE]'),
3213 inferrepo=True)
3212 inferrepo=True)
3214 def log(ui, repo, *pats, **opts):
3213 def log(ui, repo, *pats, **opts):
3215 """show revision history of entire repository or files
3214 """show revision history of entire repository or files
3216
3215
3217 Print the revision history of the specified files or the entire
3216 Print the revision history of the specified files or the entire
3218 project.
3217 project.
3219
3218
3220 If no revision range is specified, the default is ``tip:0`` unless
3219 If no revision range is specified, the default is ``tip:0`` unless
3221 --follow is set, in which case the working directory parent is
3220 --follow is set, in which case the working directory parent is
3222 used as the starting revision.
3221 used as the starting revision.
3223
3222
3224 File history is shown without following rename or copy history of
3223 File history is shown without following rename or copy history of
3225 files. Use -f/--follow with a filename to follow history across
3224 files. Use -f/--follow with a filename to follow history across
3226 renames and copies. --follow without a filename will only show
3225 renames and copies. --follow without a filename will only show
3227 ancestors or descendants of the starting revision.
3226 ancestors or descendants of the starting revision.
3228
3227
3229 By default this command prints revision number and changeset id,
3228 By default this command prints revision number and changeset id,
3230 tags, non-trivial parents, user, date and time, and a summary for
3229 tags, non-trivial parents, user, date and time, and a summary for
3231 each commit. When the -v/--verbose switch is used, the list of
3230 each commit. When the -v/--verbose switch is used, the list of
3232 changed files and full commit message are shown.
3231 changed files and full commit message are shown.
3233
3232
3234 With --graph the revisions are shown as an ASCII art DAG with the most
3233 With --graph the revisions are shown as an ASCII art DAG with the most
3235 recent changeset at the top.
3234 recent changeset at the top.
3236 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3235 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3237 and '+' represents a fork where the changeset from the lines below is a
3236 and '+' represents a fork where the changeset from the lines below is a
3238 parent of the 'o' merge on the same line.
3237 parent of the 'o' merge on the same line.
3239 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3238 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3240 of a '|' indicates one or more revisions in a path are omitted.
3239 of a '|' indicates one or more revisions in a path are omitted.
3241
3240
3242 .. note::
3241 .. note::
3243
3242
3244 :hg:`log --patch` may generate unexpected diff output for merge
3243 :hg:`log --patch` may generate unexpected diff output for merge
3245 changesets, as it will only compare the merge changeset against
3244 changesets, as it will only compare the merge changeset against
3246 its first parent. Also, only files different from BOTH parents
3245 its first parent. Also, only files different from BOTH parents
3247 will appear in files:.
3246 will appear in files:.
3248
3247
3249 .. note::
3248 .. note::
3250
3249
3251 For performance reasons, :hg:`log FILE` may omit duplicate changes
3250 For performance reasons, :hg:`log FILE` may omit duplicate changes
3252 made on branches and will not show removals or mode changes. To
3251 made on branches and will not show removals or mode changes. To
3253 see all such changes, use the --removed switch.
3252 see all such changes, use the --removed switch.
3254
3253
3255 .. container:: verbose
3254 .. container:: verbose
3256
3255
3257 Some examples:
3256 Some examples:
3258
3257
3259 - changesets with full descriptions and file lists::
3258 - changesets with full descriptions and file lists::
3260
3259
3261 hg log -v
3260 hg log -v
3262
3261
3263 - changesets ancestral to the working directory::
3262 - changesets ancestral to the working directory::
3264
3263
3265 hg log -f
3264 hg log -f
3266
3265
3267 - last 10 commits on the current branch::
3266 - last 10 commits on the current branch::
3268
3267
3269 hg log -l 10 -b .
3268 hg log -l 10 -b .
3270
3269
3271 - changesets showing all modifications of a file, including removals::
3270 - changesets showing all modifications of a file, including removals::
3272
3271
3273 hg log --removed file.c
3272 hg log --removed file.c
3274
3273
3275 - all changesets that touch a directory, with diffs, excluding merges::
3274 - all changesets that touch a directory, with diffs, excluding merges::
3276
3275
3277 hg log -Mp lib/
3276 hg log -Mp lib/
3278
3277
3279 - all revision numbers that match a keyword::
3278 - all revision numbers that match a keyword::
3280
3279
3281 hg log -k bug --template "{rev}\\n"
3280 hg log -k bug --template "{rev}\\n"
3282
3281
3283 - the full hash identifier of the working directory parent::
3282 - the full hash identifier of the working directory parent::
3284
3283
3285 hg log -r . --template "{node}\\n"
3284 hg log -r . --template "{node}\\n"
3286
3285
3287 - list available log templates::
3286 - list available log templates::
3288
3287
3289 hg log -T list
3288 hg log -T list
3290
3289
3291 - check if a given changeset is included in a tagged release::
3290 - check if a given changeset is included in a tagged release::
3292
3291
3293 hg log -r "a21ccf and ancestor(1.9)"
3292 hg log -r "a21ccf and ancestor(1.9)"
3294
3293
3295 - find all changesets by some user in a date range::
3294 - find all changesets by some user in a date range::
3296
3295
3297 hg log -k alice -d "may 2008 to jul 2008"
3296 hg log -k alice -d "may 2008 to jul 2008"
3298
3297
3299 - summary of all changesets after the last tag::
3298 - summary of all changesets after the last tag::
3300
3299
3301 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3300 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3302
3301
3303 See :hg:`help dates` for a list of formats valid for -d/--date.
3302 See :hg:`help dates` for a list of formats valid for -d/--date.
3304
3303
3305 See :hg:`help revisions` for more about specifying and ordering
3304 See :hg:`help revisions` for more about specifying and ordering
3306 revisions.
3305 revisions.
3307
3306
3308 See :hg:`help templates` for more about pre-packaged styles and
3307 See :hg:`help templates` for more about pre-packaged styles and
3309 specifying custom templates.
3308 specifying custom templates.
3310
3309
3311 Returns 0 on success.
3310 Returns 0 on success.
3312
3311
3313 """
3312 """
3314 opts = pycompat.byteskwargs(opts)
3313 opts = pycompat.byteskwargs(opts)
3315 if opts.get('follow') and opts.get('rev'):
3314 if opts.get('follow') and opts.get('rev'):
3316 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3315 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3317 del opts['follow']
3316 del opts['follow']
3318
3317
3319 if opts.get('graph'):
3318 if opts.get('graph'):
3320 return cmdutil.graphlog(ui, repo, pats, opts)
3319 return cmdutil.graphlog(ui, repo, pats, opts)
3321
3320
3322 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3321 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3323 limit = cmdutil.loglimit(opts)
3322 limit = cmdutil.loglimit(opts)
3324 count = 0
3323 count = 0
3325
3324
3326 getrenamed = None
3325 getrenamed = None
3327 if opts.get('copies'):
3326 if opts.get('copies'):
3328 endrev = None
3327 endrev = None
3329 if opts.get('rev'):
3328 if opts.get('rev'):
3330 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3329 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3331 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3330 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3332
3331
3333 ui.pager('log')
3332 ui.pager('log')
3334 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3333 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3335 for rev in revs:
3334 for rev in revs:
3336 if count == limit:
3335 if count == limit:
3337 break
3336 break
3338 ctx = repo[rev]
3337 ctx = repo[rev]
3339 copies = None
3338 copies = None
3340 if getrenamed is not None and rev:
3339 if getrenamed is not None and rev:
3341 copies = []
3340 copies = []
3342 for fn in ctx.files():
3341 for fn in ctx.files():
3343 rename = getrenamed(fn, rev)
3342 rename = getrenamed(fn, rev)
3344 if rename:
3343 if rename:
3345 copies.append((fn, rename[0]))
3344 copies.append((fn, rename[0]))
3346 if filematcher:
3345 if filematcher:
3347 revmatchfn = filematcher(ctx.rev())
3346 revmatchfn = filematcher(ctx.rev())
3348 else:
3347 else:
3349 revmatchfn = None
3348 revmatchfn = None
3350 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3349 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3351 if displayer.flush(ctx):
3350 if displayer.flush(ctx):
3352 count += 1
3351 count += 1
3353
3352
3354 displayer.close()
3353 displayer.close()
3355
3354
3356 @command('manifest',
3355 @command('manifest',
3357 [('r', 'rev', '', _('revision to display'), _('REV')),
3356 [('r', 'rev', '', _('revision to display'), _('REV')),
3358 ('', 'all', False, _("list files from all revisions"))]
3357 ('', 'all', False, _("list files from all revisions"))]
3359 + formatteropts,
3358 + formatteropts,
3360 _('[-r REV]'))
3359 _('[-r REV]'))
3361 def manifest(ui, repo, node=None, rev=None, **opts):
3360 def manifest(ui, repo, node=None, rev=None, **opts):
3362 """output the current or given revision of the project manifest
3361 """output the current or given revision of the project manifest
3363
3362
3364 Print a list of version controlled files for the given revision.
3363 Print a list of version controlled files for the given revision.
3365 If no revision is given, the first parent of the working directory
3364 If no revision is given, the first parent of the working directory
3366 is used, or the null revision if no revision is checked out.
3365 is used, or the null revision if no revision is checked out.
3367
3366
3368 With -v, print file permissions, symlink and executable bits.
3367 With -v, print file permissions, symlink and executable bits.
3369 With --debug, print file revision hashes.
3368 With --debug, print file revision hashes.
3370
3369
3371 If option --all is specified, the list of all files from all revisions
3370 If option --all is specified, the list of all files from all revisions
3372 is printed. This includes deleted and renamed files.
3371 is printed. This includes deleted and renamed files.
3373
3372
3374 Returns 0 on success.
3373 Returns 0 on success.
3375 """
3374 """
3376 opts = pycompat.byteskwargs(opts)
3375 opts = pycompat.byteskwargs(opts)
3377 fm = ui.formatter('manifest', opts)
3376 fm = ui.formatter('manifest', opts)
3378
3377
3379 if opts.get('all'):
3378 if opts.get('all'):
3380 if rev or node:
3379 if rev or node:
3381 raise error.Abort(_("can't specify a revision with --all"))
3380 raise error.Abort(_("can't specify a revision with --all"))
3382
3381
3383 res = []
3382 res = []
3384 prefix = "data/"
3383 prefix = "data/"
3385 suffix = ".i"
3384 suffix = ".i"
3386 plen = len(prefix)
3385 plen = len(prefix)
3387 slen = len(suffix)
3386 slen = len(suffix)
3388 with repo.lock():
3387 with repo.lock():
3389 for fn, b, size in repo.store.datafiles():
3388 for fn, b, size in repo.store.datafiles():
3390 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3389 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3391 res.append(fn[plen:-slen])
3390 res.append(fn[plen:-slen])
3392 ui.pager('manifest')
3391 ui.pager('manifest')
3393 for f in res:
3392 for f in res:
3394 fm.startitem()
3393 fm.startitem()
3395 fm.write("path", '%s\n', f)
3394 fm.write("path", '%s\n', f)
3396 fm.end()
3395 fm.end()
3397 return
3396 return
3398
3397
3399 if rev and node:
3398 if rev and node:
3400 raise error.Abort(_("please specify just one revision"))
3399 raise error.Abort(_("please specify just one revision"))
3401
3400
3402 if not node:
3401 if not node:
3403 node = rev
3402 node = rev
3404
3403
3405 char = {'l': '@', 'x': '*', '': ''}
3404 char = {'l': '@', 'x': '*', '': ''}
3406 mode = {'l': '644', 'x': '755', '': '644'}
3405 mode = {'l': '644', 'x': '755', '': '644'}
3407 ctx = scmutil.revsingle(repo, node)
3406 ctx = scmutil.revsingle(repo, node)
3408 mf = ctx.manifest()
3407 mf = ctx.manifest()
3409 ui.pager('manifest')
3408 ui.pager('manifest')
3410 for f in ctx:
3409 for f in ctx:
3411 fm.startitem()
3410 fm.startitem()
3412 fl = ctx[f].flags()
3411 fl = ctx[f].flags()
3413 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3412 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3414 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3413 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3415 fm.write('path', '%s\n', f)
3414 fm.write('path', '%s\n', f)
3416 fm.end()
3415 fm.end()
3417
3416
3418 @command('^merge',
3417 @command('^merge',
3419 [('f', 'force', None,
3418 [('f', 'force', None,
3420 _('force a merge including outstanding changes (DEPRECATED)')),
3419 _('force a merge including outstanding changes (DEPRECATED)')),
3421 ('r', 'rev', '', _('revision to merge'), _('REV')),
3420 ('r', 'rev', '', _('revision to merge'), _('REV')),
3422 ('P', 'preview', None,
3421 ('P', 'preview', None,
3423 _('review revisions to merge (no merge is performed)'))
3422 _('review revisions to merge (no merge is performed)'))
3424 ] + mergetoolopts,
3423 ] + mergetoolopts,
3425 _('[-P] [[-r] REV]'))
3424 _('[-P] [[-r] REV]'))
3426 def merge(ui, repo, node=None, **opts):
3425 def merge(ui, repo, node=None, **opts):
3427 """merge another revision into working directory
3426 """merge another revision into working directory
3428
3427
3429 The current working directory is updated with all changes made in
3428 The current working directory is updated with all changes made in
3430 the requested revision since the last common predecessor revision.
3429 the requested revision since the last common predecessor revision.
3431
3430
3432 Files that changed between either parent are marked as changed for
3431 Files that changed between either parent are marked as changed for
3433 the next commit and a commit must be performed before any further
3432 the next commit and a commit must be performed before any further
3434 updates to the repository are allowed. The next commit will have
3433 updates to the repository are allowed. The next commit will have
3435 two parents.
3434 two parents.
3436
3435
3437 ``--tool`` can be used to specify the merge tool used for file
3436 ``--tool`` can be used to specify the merge tool used for file
3438 merges. It overrides the HGMERGE environment variable and your
3437 merges. It overrides the HGMERGE environment variable and your
3439 configuration files. See :hg:`help merge-tools` for options.
3438 configuration files. See :hg:`help merge-tools` for options.
3440
3439
3441 If no revision is specified, the working directory's parent is a
3440 If no revision is specified, the working directory's parent is a
3442 head revision, and the current branch contains exactly one other
3441 head revision, and the current branch contains exactly one other
3443 head, the other head is merged with by default. Otherwise, an
3442 head, the other head is merged with by default. Otherwise, an
3444 explicit revision with which to merge with must be provided.
3443 explicit revision with which to merge with must be provided.
3445
3444
3446 See :hg:`help resolve` for information on handling file conflicts.
3445 See :hg:`help resolve` for information on handling file conflicts.
3447
3446
3448 To undo an uncommitted merge, use :hg:`update --clean .` which
3447 To undo an uncommitted merge, use :hg:`update --clean .` which
3449 will check out a clean copy of the original merge parent, losing
3448 will check out a clean copy of the original merge parent, losing
3450 all changes.
3449 all changes.
3451
3450
3452 Returns 0 on success, 1 if there are unresolved files.
3451 Returns 0 on success, 1 if there are unresolved files.
3453 """
3452 """
3454
3453
3455 opts = pycompat.byteskwargs(opts)
3454 opts = pycompat.byteskwargs(opts)
3456 if opts.get('rev') and node:
3455 if opts.get('rev') and node:
3457 raise error.Abort(_("please specify just one revision"))
3456 raise error.Abort(_("please specify just one revision"))
3458 if not node:
3457 if not node:
3459 node = opts.get('rev')
3458 node = opts.get('rev')
3460
3459
3461 if node:
3460 if node:
3462 node = scmutil.revsingle(repo, node).node()
3461 node = scmutil.revsingle(repo, node).node()
3463
3462
3464 if not node:
3463 if not node:
3465 node = repo[destutil.destmerge(repo)].node()
3464 node = repo[destutil.destmerge(repo)].node()
3466
3465
3467 if opts.get('preview'):
3466 if opts.get('preview'):
3468 # find nodes that are ancestors of p2 but not of p1
3467 # find nodes that are ancestors of p2 but not of p1
3469 p1 = repo.lookup('.')
3468 p1 = repo.lookup('.')
3470 p2 = repo.lookup(node)
3469 p2 = repo.lookup(node)
3471 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3470 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3472
3471
3473 displayer = cmdutil.show_changeset(ui, repo, opts)
3472 displayer = cmdutil.show_changeset(ui, repo, opts)
3474 for node in nodes:
3473 for node in nodes:
3475 displayer.show(repo[node])
3474 displayer.show(repo[node])
3476 displayer.close()
3475 displayer.close()
3477 return 0
3476 return 0
3478
3477
3479 try:
3478 try:
3480 # ui.forcemerge is an internal variable, do not document
3479 # ui.forcemerge is an internal variable, do not document
3481 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3480 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3482 force = opts.get('force')
3481 force = opts.get('force')
3483 labels = ['working copy', 'merge rev']
3482 labels = ['working copy', 'merge rev']
3484 return hg.merge(repo, node, force=force, mergeforce=force,
3483 return hg.merge(repo, node, force=force, mergeforce=force,
3485 labels=labels)
3484 labels=labels)
3486 finally:
3485 finally:
3487 ui.setconfig('ui', 'forcemerge', '', 'merge')
3486 ui.setconfig('ui', 'forcemerge', '', 'merge')
3488
3487
3489 @command('outgoing|out',
3488 @command('outgoing|out',
3490 [('f', 'force', None, _('run even when the destination is unrelated')),
3489 [('f', 'force', None, _('run even when the destination is unrelated')),
3491 ('r', 'rev', [],
3490 ('r', 'rev', [],
3492 _('a changeset intended to be included in the destination'), _('REV')),
3491 _('a changeset intended to be included in the destination'), _('REV')),
3493 ('n', 'newest-first', None, _('show newest record first')),
3492 ('n', 'newest-first', None, _('show newest record first')),
3494 ('B', 'bookmarks', False, _('compare bookmarks')),
3493 ('B', 'bookmarks', False, _('compare bookmarks')),
3495 ('b', 'branch', [], _('a specific branch you would like to push'),
3494 ('b', 'branch', [], _('a specific branch you would like to push'),
3496 _('BRANCH')),
3495 _('BRANCH')),
3497 ] + logopts + remoteopts + subrepoopts,
3496 ] + logopts + remoteopts + subrepoopts,
3498 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3497 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3499 def outgoing(ui, repo, dest=None, **opts):
3498 def outgoing(ui, repo, dest=None, **opts):
3500 """show changesets not found in the destination
3499 """show changesets not found in the destination
3501
3500
3502 Show changesets not found in the specified destination repository
3501 Show changesets not found in the specified destination repository
3503 or the default push location. These are the changesets that would
3502 or the default push location. These are the changesets that would
3504 be pushed if a push was requested.
3503 be pushed if a push was requested.
3505
3504
3506 See pull for details of valid destination formats.
3505 See pull for details of valid destination formats.
3507
3506
3508 .. container:: verbose
3507 .. container:: verbose
3509
3508
3510 With -B/--bookmarks, the result of bookmark comparison between
3509 With -B/--bookmarks, the result of bookmark comparison between
3511 local and remote repositories is displayed. With -v/--verbose,
3510 local and remote repositories is displayed. With -v/--verbose,
3512 status is also displayed for each bookmark like below::
3511 status is also displayed for each bookmark like below::
3513
3512
3514 BM1 01234567890a added
3513 BM1 01234567890a added
3515 BM2 deleted
3514 BM2 deleted
3516 BM3 234567890abc advanced
3515 BM3 234567890abc advanced
3517 BM4 34567890abcd diverged
3516 BM4 34567890abcd diverged
3518 BM5 4567890abcde changed
3517 BM5 4567890abcde changed
3519
3518
3520 The action taken when pushing depends on the
3519 The action taken when pushing depends on the
3521 status of each bookmark:
3520 status of each bookmark:
3522
3521
3523 :``added``: push with ``-B`` will create it
3522 :``added``: push with ``-B`` will create it
3524 :``deleted``: push with ``-B`` will delete it
3523 :``deleted``: push with ``-B`` will delete it
3525 :``advanced``: push will update it
3524 :``advanced``: push will update it
3526 :``diverged``: push with ``-B`` will update it
3525 :``diverged``: push with ``-B`` will update it
3527 :``changed``: push with ``-B`` will update it
3526 :``changed``: push with ``-B`` will update it
3528
3527
3529 From the point of view of pushing behavior, bookmarks
3528 From the point of view of pushing behavior, bookmarks
3530 existing only in the remote repository are treated as
3529 existing only in the remote repository are treated as
3531 ``deleted``, even if it is in fact added remotely.
3530 ``deleted``, even if it is in fact added remotely.
3532
3531
3533 Returns 0 if there are outgoing changes, 1 otherwise.
3532 Returns 0 if there are outgoing changes, 1 otherwise.
3534 """
3533 """
3535 opts = pycompat.byteskwargs(opts)
3534 opts = pycompat.byteskwargs(opts)
3536 if opts.get('graph'):
3535 if opts.get('graph'):
3537 cmdutil.checkunsupportedgraphflags([], opts)
3536 cmdutil.checkunsupportedgraphflags([], opts)
3538 o, other = hg._outgoing(ui, repo, dest, opts)
3537 o, other = hg._outgoing(ui, repo, dest, opts)
3539 if not o:
3538 if not o:
3540 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3539 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3541 return
3540 return
3542
3541
3543 revdag = cmdutil.graphrevs(repo, o, opts)
3542 revdag = cmdutil.graphrevs(repo, o, opts)
3544 ui.pager('outgoing')
3543 ui.pager('outgoing')
3545 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3544 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3546 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3545 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3547 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3546 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3548 return 0
3547 return 0
3549
3548
3550 if opts.get('bookmarks'):
3549 if opts.get('bookmarks'):
3551 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3550 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3552 dest, branches = hg.parseurl(dest, opts.get('branch'))
3551 dest, branches = hg.parseurl(dest, opts.get('branch'))
3553 other = hg.peer(repo, opts, dest)
3552 other = hg.peer(repo, opts, dest)
3554 if 'bookmarks' not in other.listkeys('namespaces'):
3553 if 'bookmarks' not in other.listkeys('namespaces'):
3555 ui.warn(_("remote doesn't support bookmarks\n"))
3554 ui.warn(_("remote doesn't support bookmarks\n"))
3556 return 0
3555 return 0
3557 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3556 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3558 ui.pager('outgoing')
3557 ui.pager('outgoing')
3559 return bookmarks.outgoing(ui, repo, other)
3558 return bookmarks.outgoing(ui, repo, other)
3560
3559
3561 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3560 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3562 try:
3561 try:
3563 return hg.outgoing(ui, repo, dest, opts)
3562 return hg.outgoing(ui, repo, dest, opts)
3564 finally:
3563 finally:
3565 del repo._subtoppath
3564 del repo._subtoppath
3566
3565
3567 @command('parents',
3566 @command('parents',
3568 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3567 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3569 ] + templateopts,
3568 ] + templateopts,
3570 _('[-r REV] [FILE]'),
3569 _('[-r REV] [FILE]'),
3571 inferrepo=True)
3570 inferrepo=True)
3572 def parents(ui, repo, file_=None, **opts):
3571 def parents(ui, repo, file_=None, **opts):
3573 """show the parents of the working directory or revision (DEPRECATED)
3572 """show the parents of the working directory or revision (DEPRECATED)
3574
3573
3575 Print the working directory's parent revisions. If a revision is
3574 Print the working directory's parent revisions. If a revision is
3576 given via -r/--rev, the parent of that revision will be printed.
3575 given via -r/--rev, the parent of that revision will be printed.
3577 If a file argument is given, the revision in which the file was
3576 If a file argument is given, the revision in which the file was
3578 last changed (before the working directory revision or the
3577 last changed (before the working directory revision or the
3579 argument to --rev if given) is printed.
3578 argument to --rev if given) is printed.
3580
3579
3581 This command is equivalent to::
3580 This command is equivalent to::
3582
3581
3583 hg log -r "p1()+p2()" or
3582 hg log -r "p1()+p2()" or
3584 hg log -r "p1(REV)+p2(REV)" or
3583 hg log -r "p1(REV)+p2(REV)" or
3585 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3584 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3586 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3585 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3587
3586
3588 See :hg:`summary` and :hg:`help revsets` for related information.
3587 See :hg:`summary` and :hg:`help revsets` for related information.
3589
3588
3590 Returns 0 on success.
3589 Returns 0 on success.
3591 """
3590 """
3592
3591
3593 opts = pycompat.byteskwargs(opts)
3592 opts = pycompat.byteskwargs(opts)
3594 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3593 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3595
3594
3596 if file_:
3595 if file_:
3597 m = scmutil.match(ctx, (file_,), opts)
3596 m = scmutil.match(ctx, (file_,), opts)
3598 if m.anypats() or len(m.files()) != 1:
3597 if m.anypats() or len(m.files()) != 1:
3599 raise error.Abort(_('can only specify an explicit filename'))
3598 raise error.Abort(_('can only specify an explicit filename'))
3600 file_ = m.files()[0]
3599 file_ = m.files()[0]
3601 filenodes = []
3600 filenodes = []
3602 for cp in ctx.parents():
3601 for cp in ctx.parents():
3603 if not cp:
3602 if not cp:
3604 continue
3603 continue
3605 try:
3604 try:
3606 filenodes.append(cp.filenode(file_))
3605 filenodes.append(cp.filenode(file_))
3607 except error.LookupError:
3606 except error.LookupError:
3608 pass
3607 pass
3609 if not filenodes:
3608 if not filenodes:
3610 raise error.Abort(_("'%s' not found in manifest!") % file_)
3609 raise error.Abort(_("'%s' not found in manifest!") % file_)
3611 p = []
3610 p = []
3612 for fn in filenodes:
3611 for fn in filenodes:
3613 fctx = repo.filectx(file_, fileid=fn)
3612 fctx = repo.filectx(file_, fileid=fn)
3614 p.append(fctx.node())
3613 p.append(fctx.node())
3615 else:
3614 else:
3616 p = [cp.node() for cp in ctx.parents()]
3615 p = [cp.node() for cp in ctx.parents()]
3617
3616
3618 displayer = cmdutil.show_changeset(ui, repo, opts)
3617 displayer = cmdutil.show_changeset(ui, repo, opts)
3619 for n in p:
3618 for n in p:
3620 if n != nullid:
3619 if n != nullid:
3621 displayer.show(repo[n])
3620 displayer.show(repo[n])
3622 displayer.close()
3621 displayer.close()
3623
3622
3624 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3623 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3625 def paths(ui, repo, search=None, **opts):
3624 def paths(ui, repo, search=None, **opts):
3626 """show aliases for remote repositories
3625 """show aliases for remote repositories
3627
3626
3628 Show definition of symbolic path name NAME. If no name is given,
3627 Show definition of symbolic path name NAME. If no name is given,
3629 show definition of all available names.
3628 show definition of all available names.
3630
3629
3631 Option -q/--quiet suppresses all output when searching for NAME
3630 Option -q/--quiet suppresses all output when searching for NAME
3632 and shows only the path names when listing all definitions.
3631 and shows only the path names when listing all definitions.
3633
3632
3634 Path names are defined in the [paths] section of your
3633 Path names are defined in the [paths] section of your
3635 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3634 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3636 repository, ``.hg/hgrc`` is used, too.
3635 repository, ``.hg/hgrc`` is used, too.
3637
3636
3638 The path names ``default`` and ``default-push`` have a special
3637 The path names ``default`` and ``default-push`` have a special
3639 meaning. When performing a push or pull operation, they are used
3638 meaning. When performing a push or pull operation, they are used
3640 as fallbacks if no location is specified on the command-line.
3639 as fallbacks if no location is specified on the command-line.
3641 When ``default-push`` is set, it will be used for push and
3640 When ``default-push`` is set, it will be used for push and
3642 ``default`` will be used for pull; otherwise ``default`` is used
3641 ``default`` will be used for pull; otherwise ``default`` is used
3643 as the fallback for both. When cloning a repository, the clone
3642 as the fallback for both. When cloning a repository, the clone
3644 source is written as ``default`` in ``.hg/hgrc``.
3643 source is written as ``default`` in ``.hg/hgrc``.
3645
3644
3646 .. note::
3645 .. note::
3647
3646
3648 ``default`` and ``default-push`` apply to all inbound (e.g.
3647 ``default`` and ``default-push`` apply to all inbound (e.g.
3649 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3648 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3650 and :hg:`bundle`) operations.
3649 and :hg:`bundle`) operations.
3651
3650
3652 See :hg:`help urls` for more information.
3651 See :hg:`help urls` for more information.
3653
3652
3654 Returns 0 on success.
3653 Returns 0 on success.
3655 """
3654 """
3656
3655
3657 opts = pycompat.byteskwargs(opts)
3656 opts = pycompat.byteskwargs(opts)
3658 ui.pager('paths')
3657 ui.pager('paths')
3659 if search:
3658 if search:
3660 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3659 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3661 if name == search]
3660 if name == search]
3662 else:
3661 else:
3663 pathitems = sorted(ui.paths.iteritems())
3662 pathitems = sorted(ui.paths.iteritems())
3664
3663
3665 fm = ui.formatter('paths', opts)
3664 fm = ui.formatter('paths', opts)
3666 if fm.isplain():
3665 if fm.isplain():
3667 hidepassword = util.hidepassword
3666 hidepassword = util.hidepassword
3668 else:
3667 else:
3669 hidepassword = str
3668 hidepassword = str
3670 if ui.quiet:
3669 if ui.quiet:
3671 namefmt = '%s\n'
3670 namefmt = '%s\n'
3672 else:
3671 else:
3673 namefmt = '%s = '
3672 namefmt = '%s = '
3674 showsubopts = not search and not ui.quiet
3673 showsubopts = not search and not ui.quiet
3675
3674
3676 for name, path in pathitems:
3675 for name, path in pathitems:
3677 fm.startitem()
3676 fm.startitem()
3678 fm.condwrite(not search, 'name', namefmt, name)
3677 fm.condwrite(not search, 'name', namefmt, name)
3679 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3678 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3680 for subopt, value in sorted(path.suboptions.items()):
3679 for subopt, value in sorted(path.suboptions.items()):
3681 assert subopt not in ('name', 'url')
3680 assert subopt not in ('name', 'url')
3682 if showsubopts:
3681 if showsubopts:
3683 fm.plain('%s:%s = ' % (name, subopt))
3682 fm.plain('%s:%s = ' % (name, subopt))
3684 fm.condwrite(showsubopts, subopt, '%s\n', value)
3683 fm.condwrite(showsubopts, subopt, '%s\n', value)
3685
3684
3686 fm.end()
3685 fm.end()
3687
3686
3688 if search and not pathitems:
3687 if search and not pathitems:
3689 if not ui.quiet:
3688 if not ui.quiet:
3690 ui.warn(_("not found!\n"))
3689 ui.warn(_("not found!\n"))
3691 return 1
3690 return 1
3692 else:
3691 else:
3693 return 0
3692 return 0
3694
3693
3695 @command('phase',
3694 @command('phase',
3696 [('p', 'public', False, _('set changeset phase to public')),
3695 [('p', 'public', False, _('set changeset phase to public')),
3697 ('d', 'draft', False, _('set changeset phase to draft')),
3696 ('d', 'draft', False, _('set changeset phase to draft')),
3698 ('s', 'secret', False, _('set changeset phase to secret')),
3697 ('s', 'secret', False, _('set changeset phase to secret')),
3699 ('f', 'force', False, _('allow to move boundary backward')),
3698 ('f', 'force', False, _('allow to move boundary backward')),
3700 ('r', 'rev', [], _('target revision'), _('REV')),
3699 ('r', 'rev', [], _('target revision'), _('REV')),
3701 ],
3700 ],
3702 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3701 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3703 def phase(ui, repo, *revs, **opts):
3702 def phase(ui, repo, *revs, **opts):
3704 """set or show the current phase name
3703 """set or show the current phase name
3705
3704
3706 With no argument, show the phase name of the current revision(s).
3705 With no argument, show the phase name of the current revision(s).
3707
3706
3708 With one of -p/--public, -d/--draft or -s/--secret, change the
3707 With one of -p/--public, -d/--draft or -s/--secret, change the
3709 phase value of the specified revisions.
3708 phase value of the specified revisions.
3710
3709
3711 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3710 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3712 lower phase to an higher phase. Phases are ordered as follows::
3711 lower phase to an higher phase. Phases are ordered as follows::
3713
3712
3714 public < draft < secret
3713 public < draft < secret
3715
3714
3716 Returns 0 on success, 1 if some phases could not be changed.
3715 Returns 0 on success, 1 if some phases could not be changed.
3717
3716
3718 (For more information about the phases concept, see :hg:`help phases`.)
3717 (For more information about the phases concept, see :hg:`help phases`.)
3719 """
3718 """
3720 opts = pycompat.byteskwargs(opts)
3719 opts = pycompat.byteskwargs(opts)
3721 # search for a unique phase argument
3720 # search for a unique phase argument
3722 targetphase = None
3721 targetphase = None
3723 for idx, name in enumerate(phases.phasenames):
3722 for idx, name in enumerate(phases.phasenames):
3724 if opts[name]:
3723 if opts[name]:
3725 if targetphase is not None:
3724 if targetphase is not None:
3726 raise error.Abort(_('only one phase can be specified'))
3725 raise error.Abort(_('only one phase can be specified'))
3727 targetphase = idx
3726 targetphase = idx
3728
3727
3729 # look for specified revision
3728 # look for specified revision
3730 revs = list(revs)
3729 revs = list(revs)
3731 revs.extend(opts['rev'])
3730 revs.extend(opts['rev'])
3732 if not revs:
3731 if not revs:
3733 # display both parents as the second parent phase can influence
3732 # display both parents as the second parent phase can influence
3734 # the phase of a merge commit
3733 # the phase of a merge commit
3735 revs = [c.rev() for c in repo[None].parents()]
3734 revs = [c.rev() for c in repo[None].parents()]
3736
3735
3737 revs = scmutil.revrange(repo, revs)
3736 revs = scmutil.revrange(repo, revs)
3738
3737
3739 lock = None
3738 lock = None
3740 ret = 0
3739 ret = 0
3741 if targetphase is None:
3740 if targetphase is None:
3742 # display
3741 # display
3743 for r in revs:
3742 for r in revs:
3744 ctx = repo[r]
3743 ctx = repo[r]
3745 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3744 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3746 else:
3745 else:
3747 tr = None
3746 tr = None
3748 lock = repo.lock()
3747 lock = repo.lock()
3749 try:
3748 try:
3750 tr = repo.transaction("phase")
3749 tr = repo.transaction("phase")
3751 # set phase
3750 # set phase
3752 if not revs:
3751 if not revs:
3753 raise error.Abort(_('empty revision set'))
3752 raise error.Abort(_('empty revision set'))
3754 nodes = [repo[r].node() for r in revs]
3753 nodes = [repo[r].node() for r in revs]
3755 # moving revision from public to draft may hide them
3754 # moving revision from public to draft may hide them
3756 # We have to check result on an unfiltered repository
3755 # We have to check result on an unfiltered repository
3757 unfi = repo.unfiltered()
3756 unfi = repo.unfiltered()
3758 getphase = unfi._phasecache.phase
3757 getphase = unfi._phasecache.phase
3759 olddata = [getphase(unfi, r) for r in unfi]
3758 olddata = [getphase(unfi, r) for r in unfi]
3760 phases.advanceboundary(repo, tr, targetphase, nodes)
3759 phases.advanceboundary(repo, tr, targetphase, nodes)
3761 if opts['force']:
3760 if opts['force']:
3762 phases.retractboundary(repo, tr, targetphase, nodes)
3761 phases.retractboundary(repo, tr, targetphase, nodes)
3763 tr.close()
3762 tr.close()
3764 finally:
3763 finally:
3765 if tr is not None:
3764 if tr is not None:
3766 tr.release()
3765 tr.release()
3767 lock.release()
3766 lock.release()
3768 getphase = unfi._phasecache.phase
3767 getphase = unfi._phasecache.phase
3769 newdata = [getphase(unfi, r) for r in unfi]
3768 newdata = [getphase(unfi, r) for r in unfi]
3770 changes = sum(newdata[r] != olddata[r] for r in unfi)
3769 changes = sum(newdata[r] != olddata[r] for r in unfi)
3771 cl = unfi.changelog
3770 cl = unfi.changelog
3772 rejected = [n for n in nodes
3771 rejected = [n for n in nodes
3773 if newdata[cl.rev(n)] < targetphase]
3772 if newdata[cl.rev(n)] < targetphase]
3774 if rejected:
3773 if rejected:
3775 ui.warn(_('cannot move %i changesets to a higher '
3774 ui.warn(_('cannot move %i changesets to a higher '
3776 'phase, use --force\n') % len(rejected))
3775 'phase, use --force\n') % len(rejected))
3777 ret = 1
3776 ret = 1
3778 if changes:
3777 if changes:
3779 msg = _('phase changed for %i changesets\n') % changes
3778 msg = _('phase changed for %i changesets\n') % changes
3780 if ret:
3779 if ret:
3781 ui.status(msg)
3780 ui.status(msg)
3782 else:
3781 else:
3783 ui.note(msg)
3782 ui.note(msg)
3784 else:
3783 else:
3785 ui.warn(_('no phases changed\n'))
3784 ui.warn(_('no phases changed\n'))
3786 return ret
3785 return ret
3787
3786
3788 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3787 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3789 """Run after a changegroup has been added via pull/unbundle
3788 """Run after a changegroup has been added via pull/unbundle
3790
3789
3791 This takes arguments below:
3790 This takes arguments below:
3792
3791
3793 :modheads: change of heads by pull/unbundle
3792 :modheads: change of heads by pull/unbundle
3794 :optupdate: updating working directory is needed or not
3793 :optupdate: updating working directory is needed or not
3795 :checkout: update destination revision (or None to default destination)
3794 :checkout: update destination revision (or None to default destination)
3796 :brev: a name, which might be a bookmark to be activated after updating
3795 :brev: a name, which might be a bookmark to be activated after updating
3797 """
3796 """
3798 if modheads == 0:
3797 if modheads == 0:
3799 return
3798 return
3800 if optupdate:
3799 if optupdate:
3801 try:
3800 try:
3802 return hg.updatetotally(ui, repo, checkout, brev)
3801 return hg.updatetotally(ui, repo, checkout, brev)
3803 except error.UpdateAbort as inst:
3802 except error.UpdateAbort as inst:
3804 msg = _("not updating: %s") % str(inst)
3803 msg = _("not updating: %s") % str(inst)
3805 hint = inst.hint
3804 hint = inst.hint
3806 raise error.UpdateAbort(msg, hint=hint)
3805 raise error.UpdateAbort(msg, hint=hint)
3807 if modheads > 1:
3806 if modheads > 1:
3808 currentbranchheads = len(repo.branchheads())
3807 currentbranchheads = len(repo.branchheads())
3809 if currentbranchheads == modheads:
3808 if currentbranchheads == modheads:
3810 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3809 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3811 elif currentbranchheads > 1:
3810 elif currentbranchheads > 1:
3812 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3811 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3813 "merge)\n"))
3812 "merge)\n"))
3814 else:
3813 else:
3815 ui.status(_("(run 'hg heads' to see heads)\n"))
3814 ui.status(_("(run 'hg heads' to see heads)\n"))
3816 else:
3815 else:
3817 ui.status(_("(run 'hg update' to get a working copy)\n"))
3816 ui.status(_("(run 'hg update' to get a working copy)\n"))
3818
3817
3819 @command('^pull',
3818 @command('^pull',
3820 [('u', 'update', None,
3819 [('u', 'update', None,
3821 _('update to new branch head if changesets were pulled')),
3820 _('update to new branch head if changesets were pulled')),
3822 ('f', 'force', None, _('run even when remote repository is unrelated')),
3821 ('f', 'force', None, _('run even when remote repository is unrelated')),
3823 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3822 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3824 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3823 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3825 ('b', 'branch', [], _('a specific branch you would like to pull'),
3824 ('b', 'branch', [], _('a specific branch you would like to pull'),
3826 _('BRANCH')),
3825 _('BRANCH')),
3827 ] + remoteopts,
3826 ] + remoteopts,
3828 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3827 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3829 def pull(ui, repo, source="default", **opts):
3828 def pull(ui, repo, source="default", **opts):
3830 """pull changes from the specified source
3829 """pull changes from the specified source
3831
3830
3832 Pull changes from a remote repository to a local one.
3831 Pull changes from a remote repository to a local one.
3833
3832
3834 This finds all changes from the repository at the specified path
3833 This finds all changes from the repository at the specified path
3835 or URL and adds them to a local repository (the current one unless
3834 or URL and adds them to a local repository (the current one unless
3836 -R is specified). By default, this does not update the copy of the
3835 -R is specified). By default, this does not update the copy of the
3837 project in the working directory.
3836 project in the working directory.
3838
3837
3839 Use :hg:`incoming` if you want to see what would have been added
3838 Use :hg:`incoming` if you want to see what would have been added
3840 by a pull at the time you issued this command. If you then decide
3839 by a pull at the time you issued this command. If you then decide
3841 to add those changes to the repository, you should use :hg:`pull
3840 to add those changes to the repository, you should use :hg:`pull
3842 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3841 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3843
3842
3844 If SOURCE is omitted, the 'default' path will be used.
3843 If SOURCE is omitted, the 'default' path will be used.
3845 See :hg:`help urls` for more information.
3844 See :hg:`help urls` for more information.
3846
3845
3847 Specifying bookmark as ``.`` is equivalent to specifying the active
3846 Specifying bookmark as ``.`` is equivalent to specifying the active
3848 bookmark's name.
3847 bookmark's name.
3849
3848
3850 Returns 0 on success, 1 if an update had unresolved files.
3849 Returns 0 on success, 1 if an update had unresolved files.
3851 """
3850 """
3852
3851
3853 opts = pycompat.byteskwargs(opts)
3852 opts = pycompat.byteskwargs(opts)
3854 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3853 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3855 msg = _('update destination required by configuration')
3854 msg = _('update destination required by configuration')
3856 hint = _('use hg pull followed by hg update DEST')
3855 hint = _('use hg pull followed by hg update DEST')
3857 raise error.Abort(msg, hint=hint)
3856 raise error.Abort(msg, hint=hint)
3858
3857
3859 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3858 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3860 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3859 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3861 other = hg.peer(repo, opts, source)
3860 other = hg.peer(repo, opts, source)
3862 try:
3861 try:
3863 revs, checkout = hg.addbranchrevs(repo, other, branches,
3862 revs, checkout = hg.addbranchrevs(repo, other, branches,
3864 opts.get('rev'))
3863 opts.get('rev'))
3865
3864
3866
3865
3867 pullopargs = {}
3866 pullopargs = {}
3868 if opts.get('bookmark'):
3867 if opts.get('bookmark'):
3869 if not revs:
3868 if not revs:
3870 revs = []
3869 revs = []
3871 # The list of bookmark used here is not the one used to actually
3870 # The list of bookmark used here is not the one used to actually
3872 # update the bookmark name. This can result in the revision pulled
3871 # update the bookmark name. This can result in the revision pulled
3873 # not ending up with the name of the bookmark because of a race
3872 # not ending up with the name of the bookmark because of a race
3874 # condition on the server. (See issue 4689 for details)
3873 # condition on the server. (See issue 4689 for details)
3875 remotebookmarks = other.listkeys('bookmarks')
3874 remotebookmarks = other.listkeys('bookmarks')
3876 pullopargs['remotebookmarks'] = remotebookmarks
3875 pullopargs['remotebookmarks'] = remotebookmarks
3877 for b in opts['bookmark']:
3876 for b in opts['bookmark']:
3878 b = repo._bookmarks.expandname(b)
3877 b = repo._bookmarks.expandname(b)
3879 if b not in remotebookmarks:
3878 if b not in remotebookmarks:
3880 raise error.Abort(_('remote bookmark %s not found!') % b)
3879 raise error.Abort(_('remote bookmark %s not found!') % b)
3881 revs.append(remotebookmarks[b])
3880 revs.append(remotebookmarks[b])
3882
3881
3883 if revs:
3882 if revs:
3884 try:
3883 try:
3885 # When 'rev' is a bookmark name, we cannot guarantee that it
3884 # When 'rev' is a bookmark name, we cannot guarantee that it
3886 # will be updated with that name because of a race condition
3885 # will be updated with that name because of a race condition
3887 # server side. (See issue 4689 for details)
3886 # server side. (See issue 4689 for details)
3888 oldrevs = revs
3887 oldrevs = revs
3889 revs = [] # actually, nodes
3888 revs = [] # actually, nodes
3890 for r in oldrevs:
3889 for r in oldrevs:
3891 node = other.lookup(r)
3890 node = other.lookup(r)
3892 revs.append(node)
3891 revs.append(node)
3893 if r == checkout:
3892 if r == checkout:
3894 checkout = node
3893 checkout = node
3895 except error.CapabilityError:
3894 except error.CapabilityError:
3896 err = _("other repository doesn't support revision lookup, "
3895 err = _("other repository doesn't support revision lookup, "
3897 "so a rev cannot be specified.")
3896 "so a rev cannot be specified.")
3898 raise error.Abort(err)
3897 raise error.Abort(err)
3899
3898
3900 pullopargs.update(opts.get('opargs', {}))
3899 pullopargs.update(opts.get('opargs', {}))
3901 modheads = exchange.pull(repo, other, heads=revs,
3900 modheads = exchange.pull(repo, other, heads=revs,
3902 force=opts.get('force'),
3901 force=opts.get('force'),
3903 bookmarks=opts.get('bookmark', ()),
3902 bookmarks=opts.get('bookmark', ()),
3904 opargs=pullopargs).cgresult
3903 opargs=pullopargs).cgresult
3905
3904
3906 # brev is a name, which might be a bookmark to be activated at
3905 # brev is a name, which might be a bookmark to be activated at
3907 # the end of the update. In other words, it is an explicit
3906 # the end of the update. In other words, it is an explicit
3908 # destination of the update
3907 # destination of the update
3909 brev = None
3908 brev = None
3910
3909
3911 if checkout:
3910 if checkout:
3912 checkout = str(repo.changelog.rev(checkout))
3911 checkout = str(repo.changelog.rev(checkout))
3913
3912
3914 # order below depends on implementation of
3913 # order below depends on implementation of
3915 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3914 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3916 # because 'checkout' is determined without it.
3915 # because 'checkout' is determined without it.
3917 if opts.get('rev'):
3916 if opts.get('rev'):
3918 brev = opts['rev'][0]
3917 brev = opts['rev'][0]
3919 elif opts.get('branch'):
3918 elif opts.get('branch'):
3920 brev = opts['branch'][0]
3919 brev = opts['branch'][0]
3921 else:
3920 else:
3922 brev = branches[0]
3921 brev = branches[0]
3923 repo._subtoppath = source
3922 repo._subtoppath = source
3924 try:
3923 try:
3925 ret = postincoming(ui, repo, modheads, opts.get('update'),
3924 ret = postincoming(ui, repo, modheads, opts.get('update'),
3926 checkout, brev)
3925 checkout, brev)
3927
3926
3928 finally:
3927 finally:
3929 del repo._subtoppath
3928 del repo._subtoppath
3930
3929
3931 finally:
3930 finally:
3932 other.close()
3931 other.close()
3933 return ret
3932 return ret
3934
3933
3935 @command('^push',
3934 @command('^push',
3936 [('f', 'force', None, _('force push')),
3935 [('f', 'force', None, _('force push')),
3937 ('r', 'rev', [],
3936 ('r', 'rev', [],
3938 _('a changeset intended to be included in the destination'),
3937 _('a changeset intended to be included in the destination'),
3939 _('REV')),
3938 _('REV')),
3940 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3939 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3941 ('b', 'branch', [],
3940 ('b', 'branch', [],
3942 _('a specific branch you would like to push'), _('BRANCH')),
3941 _('a specific branch you would like to push'), _('BRANCH')),
3943 ('', 'new-branch', False, _('allow pushing a new branch')),
3942 ('', 'new-branch', False, _('allow pushing a new branch')),
3944 ] + remoteopts,
3943 ] + remoteopts,
3945 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3944 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3946 def push(ui, repo, dest=None, **opts):
3945 def push(ui, repo, dest=None, **opts):
3947 """push changes to the specified destination
3946 """push changes to the specified destination
3948
3947
3949 Push changesets from the local repository to the specified
3948 Push changesets from the local repository to the specified
3950 destination.
3949 destination.
3951
3950
3952 This operation is symmetrical to pull: it is identical to a pull
3951 This operation is symmetrical to pull: it is identical to a pull
3953 in the destination repository from the current one.
3952 in the destination repository from the current one.
3954
3953
3955 By default, push will not allow creation of new heads at the
3954 By default, push will not allow creation of new heads at the
3956 destination, since multiple heads would make it unclear which head
3955 destination, since multiple heads would make it unclear which head
3957 to use. In this situation, it is recommended to pull and merge
3956 to use. In this situation, it is recommended to pull and merge
3958 before pushing.
3957 before pushing.
3959
3958
3960 Use --new-branch if you want to allow push to create a new named
3959 Use --new-branch if you want to allow push to create a new named
3961 branch that is not present at the destination. This allows you to
3960 branch that is not present at the destination. This allows you to
3962 only create a new branch without forcing other changes.
3961 only create a new branch without forcing other changes.
3963
3962
3964 .. note::
3963 .. note::
3965
3964
3966 Extra care should be taken with the -f/--force option,
3965 Extra care should be taken with the -f/--force option,
3967 which will push all new heads on all branches, an action which will
3966 which will push all new heads on all branches, an action which will
3968 almost always cause confusion for collaborators.
3967 almost always cause confusion for collaborators.
3969
3968
3970 If -r/--rev is used, the specified revision and all its ancestors
3969 If -r/--rev is used, the specified revision and all its ancestors
3971 will be pushed to the remote repository.
3970 will be pushed to the remote repository.
3972
3971
3973 If -B/--bookmark is used, the specified bookmarked revision, its
3972 If -B/--bookmark is used, the specified bookmarked revision, its
3974 ancestors, and the bookmark will be pushed to the remote
3973 ancestors, and the bookmark will be pushed to the remote
3975 repository. Specifying ``.`` is equivalent to specifying the active
3974 repository. Specifying ``.`` is equivalent to specifying the active
3976 bookmark's name.
3975 bookmark's name.
3977
3976
3978 Please see :hg:`help urls` for important details about ``ssh://``
3977 Please see :hg:`help urls` for important details about ``ssh://``
3979 URLs. If DESTINATION is omitted, a default path will be used.
3978 URLs. If DESTINATION is omitted, a default path will be used.
3980
3979
3981 Returns 0 if push was successful, 1 if nothing to push.
3980 Returns 0 if push was successful, 1 if nothing to push.
3982 """
3981 """
3983
3982
3984 opts = pycompat.byteskwargs(opts)
3983 opts = pycompat.byteskwargs(opts)
3985 if opts.get('bookmark'):
3984 if opts.get('bookmark'):
3986 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
3985 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
3987 for b in opts['bookmark']:
3986 for b in opts['bookmark']:
3988 # translate -B options to -r so changesets get pushed
3987 # translate -B options to -r so changesets get pushed
3989 b = repo._bookmarks.expandname(b)
3988 b = repo._bookmarks.expandname(b)
3990 if b in repo._bookmarks:
3989 if b in repo._bookmarks:
3991 opts.setdefault('rev', []).append(b)
3990 opts.setdefault('rev', []).append(b)
3992 else:
3991 else:
3993 # if we try to push a deleted bookmark, translate it to null
3992 # if we try to push a deleted bookmark, translate it to null
3994 # this lets simultaneous -r, -b options continue working
3993 # this lets simultaneous -r, -b options continue working
3995 opts.setdefault('rev', []).append("null")
3994 opts.setdefault('rev', []).append("null")
3996
3995
3997 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3996 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3998 if not path:
3997 if not path:
3999 raise error.Abort(_('default repository not configured!'),
3998 raise error.Abort(_('default repository not configured!'),
4000 hint=_("see 'hg help config.paths'"))
3999 hint=_("see 'hg help config.paths'"))
4001 dest = path.pushloc or path.loc
4000 dest = path.pushloc or path.loc
4002 branches = (path.branch, opts.get('branch') or [])
4001 branches = (path.branch, opts.get('branch') or [])
4003 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4002 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4004 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4003 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4005 other = hg.peer(repo, opts, dest)
4004 other = hg.peer(repo, opts, dest)
4006
4005
4007 if revs:
4006 if revs:
4008 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4007 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4009 if not revs:
4008 if not revs:
4010 raise error.Abort(_("specified revisions evaluate to an empty set"),
4009 raise error.Abort(_("specified revisions evaluate to an empty set"),
4011 hint=_("use different revision arguments"))
4010 hint=_("use different revision arguments"))
4012 elif path.pushrev:
4011 elif path.pushrev:
4013 # It doesn't make any sense to specify ancestor revisions. So limit
4012 # It doesn't make any sense to specify ancestor revisions. So limit
4014 # to DAG heads to make discovery simpler.
4013 # to DAG heads to make discovery simpler.
4015 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4014 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4016 revs = scmutil.revrange(repo, [expr])
4015 revs = scmutil.revrange(repo, [expr])
4017 revs = [repo[rev].node() for rev in revs]
4016 revs = [repo[rev].node() for rev in revs]
4018 if not revs:
4017 if not revs:
4019 raise error.Abort(_('default push revset for path evaluates to an '
4018 raise error.Abort(_('default push revset for path evaluates to an '
4020 'empty set'))
4019 'empty set'))
4021
4020
4022 repo._subtoppath = dest
4021 repo._subtoppath = dest
4023 try:
4022 try:
4024 # push subrepos depth-first for coherent ordering
4023 # push subrepos depth-first for coherent ordering
4025 c = repo['']
4024 c = repo['']
4026 subs = c.substate # only repos that are committed
4025 subs = c.substate # only repos that are committed
4027 for s in sorted(subs):
4026 for s in sorted(subs):
4028 result = c.sub(s).push(opts)
4027 result = c.sub(s).push(opts)
4029 if result == 0:
4028 if result == 0:
4030 return not result
4029 return not result
4031 finally:
4030 finally:
4032 del repo._subtoppath
4031 del repo._subtoppath
4033 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4032 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4034 newbranch=opts.get('new_branch'),
4033 newbranch=opts.get('new_branch'),
4035 bookmarks=opts.get('bookmark', ()),
4034 bookmarks=opts.get('bookmark', ()),
4036 opargs=opts.get('opargs'))
4035 opargs=opts.get('opargs'))
4037
4036
4038 result = not pushop.cgresult
4037 result = not pushop.cgresult
4039
4038
4040 if pushop.bkresult is not None:
4039 if pushop.bkresult is not None:
4041 if pushop.bkresult == 2:
4040 if pushop.bkresult == 2:
4042 result = 2
4041 result = 2
4043 elif not result and pushop.bkresult:
4042 elif not result and pushop.bkresult:
4044 result = 2
4043 result = 2
4045
4044
4046 return result
4045 return result
4047
4046
4048 @command('recover', [])
4047 @command('recover', [])
4049 def recover(ui, repo):
4048 def recover(ui, repo):
4050 """roll back an interrupted transaction
4049 """roll back an interrupted transaction
4051
4050
4052 Recover from an interrupted commit or pull.
4051 Recover from an interrupted commit or pull.
4053
4052
4054 This command tries to fix the repository status after an
4053 This command tries to fix the repository status after an
4055 interrupted operation. It should only be necessary when Mercurial
4054 interrupted operation. It should only be necessary when Mercurial
4056 suggests it.
4055 suggests it.
4057
4056
4058 Returns 0 if successful, 1 if nothing to recover or verify fails.
4057 Returns 0 if successful, 1 if nothing to recover or verify fails.
4059 """
4058 """
4060 if repo.recover():
4059 if repo.recover():
4061 return hg.verify(repo)
4060 return hg.verify(repo)
4062 return 1
4061 return 1
4063
4062
4064 @command('^remove|rm',
4063 @command('^remove|rm',
4065 [('A', 'after', None, _('record delete for missing files')),
4064 [('A', 'after', None, _('record delete for missing files')),
4066 ('f', 'force', None,
4065 ('f', 'force', None,
4067 _('forget added files, delete modified files')),
4066 _('forget added files, delete modified files')),
4068 ] + subrepoopts + walkopts,
4067 ] + subrepoopts + walkopts,
4069 _('[OPTION]... FILE...'),
4068 _('[OPTION]... FILE...'),
4070 inferrepo=True)
4069 inferrepo=True)
4071 def remove(ui, repo, *pats, **opts):
4070 def remove(ui, repo, *pats, **opts):
4072 """remove the specified files on the next commit
4071 """remove the specified files on the next commit
4073
4072
4074 Schedule the indicated files for removal from the current branch.
4073 Schedule the indicated files for removal from the current branch.
4075
4074
4076 This command schedules the files to be removed at the next commit.
4075 This command schedules the files to be removed at the next commit.
4077 To undo a remove before that, see :hg:`revert`. To undo added
4076 To undo a remove before that, see :hg:`revert`. To undo added
4078 files, see :hg:`forget`.
4077 files, see :hg:`forget`.
4079
4078
4080 .. container:: verbose
4079 .. container:: verbose
4081
4080
4082 -A/--after can be used to remove only files that have already
4081 -A/--after can be used to remove only files that have already
4083 been deleted, -f/--force can be used to force deletion, and -Af
4082 been deleted, -f/--force can be used to force deletion, and -Af
4084 can be used to remove files from the next revision without
4083 can be used to remove files from the next revision without
4085 deleting them from the working directory.
4084 deleting them from the working directory.
4086
4085
4087 The following table details the behavior of remove for different
4086 The following table details the behavior of remove for different
4088 file states (columns) and option combinations (rows). The file
4087 file states (columns) and option combinations (rows). The file
4089 states are Added [A], Clean [C], Modified [M] and Missing [!]
4088 states are Added [A], Clean [C], Modified [M] and Missing [!]
4090 (as reported by :hg:`status`). The actions are Warn, Remove
4089 (as reported by :hg:`status`). The actions are Warn, Remove
4091 (from branch) and Delete (from disk):
4090 (from branch) and Delete (from disk):
4092
4091
4093 ========= == == == ==
4092 ========= == == == ==
4094 opt/state A C M !
4093 opt/state A C M !
4095 ========= == == == ==
4094 ========= == == == ==
4096 none W RD W R
4095 none W RD W R
4097 -f R RD RD R
4096 -f R RD RD R
4098 -A W W W R
4097 -A W W W R
4099 -Af R R R R
4098 -Af R R R R
4100 ========= == == == ==
4099 ========= == == == ==
4101
4100
4102 .. note::
4101 .. note::
4103
4102
4104 :hg:`remove` never deletes files in Added [A] state from the
4103 :hg:`remove` never deletes files in Added [A] state from the
4105 working directory, not even if ``--force`` is specified.
4104 working directory, not even if ``--force`` is specified.
4106
4105
4107 Returns 0 on success, 1 if any warnings encountered.
4106 Returns 0 on success, 1 if any warnings encountered.
4108 """
4107 """
4109
4108
4110 opts = pycompat.byteskwargs(opts)
4109 opts = pycompat.byteskwargs(opts)
4111 after, force = opts.get('after'), opts.get('force')
4110 after, force = opts.get('after'), opts.get('force')
4112 if not pats and not after:
4111 if not pats and not after:
4113 raise error.Abort(_('no files specified'))
4112 raise error.Abort(_('no files specified'))
4114
4113
4115 m = scmutil.match(repo[None], pats, opts)
4114 m = scmutil.match(repo[None], pats, opts)
4116 subrepos = opts.get('subrepos')
4115 subrepos = opts.get('subrepos')
4117 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4116 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4118
4117
4119 @command('rename|move|mv',
4118 @command('rename|move|mv',
4120 [('A', 'after', None, _('record a rename that has already occurred')),
4119 [('A', 'after', None, _('record a rename that has already occurred')),
4121 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4120 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4122 ] + walkopts + dryrunopts,
4121 ] + walkopts + dryrunopts,
4123 _('[OPTION]... SOURCE... DEST'))
4122 _('[OPTION]... SOURCE... DEST'))
4124 def rename(ui, repo, *pats, **opts):
4123 def rename(ui, repo, *pats, **opts):
4125 """rename files; equivalent of copy + remove
4124 """rename files; equivalent of copy + remove
4126
4125
4127 Mark dest as copies of sources; mark sources for deletion. If dest
4126 Mark dest as copies of sources; mark sources for deletion. If dest
4128 is a directory, copies are put in that directory. If dest is a
4127 is a directory, copies are put in that directory. If dest is a
4129 file, there can only be one source.
4128 file, there can only be one source.
4130
4129
4131 By default, this command copies the contents of files as they
4130 By default, this command copies the contents of files as they
4132 exist in the working directory. If invoked with -A/--after, the
4131 exist in the working directory. If invoked with -A/--after, the
4133 operation is recorded, but no copying is performed.
4132 operation is recorded, but no copying is performed.
4134
4133
4135 This command takes effect at the next commit. To undo a rename
4134 This command takes effect at the next commit. To undo a rename
4136 before that, see :hg:`revert`.
4135 before that, see :hg:`revert`.
4137
4136
4138 Returns 0 on success, 1 if errors are encountered.
4137 Returns 0 on success, 1 if errors are encountered.
4139 """
4138 """
4140 opts = pycompat.byteskwargs(opts)
4139 opts = pycompat.byteskwargs(opts)
4141 with repo.wlock(False):
4140 with repo.wlock(False):
4142 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4141 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4143
4142
4144 @command('resolve',
4143 @command('resolve',
4145 [('a', 'all', None, _('select all unresolved files')),
4144 [('a', 'all', None, _('select all unresolved files')),
4146 ('l', 'list', None, _('list state of files needing merge')),
4145 ('l', 'list', None, _('list state of files needing merge')),
4147 ('m', 'mark', None, _('mark files as resolved')),
4146 ('m', 'mark', None, _('mark files as resolved')),
4148 ('u', 'unmark', None, _('mark files as unresolved')),
4147 ('u', 'unmark', None, _('mark files as unresolved')),
4149 ('n', 'no-status', None, _('hide status prefix'))]
4148 ('n', 'no-status', None, _('hide status prefix'))]
4150 + mergetoolopts + walkopts + formatteropts,
4149 + mergetoolopts + walkopts + formatteropts,
4151 _('[OPTION]... [FILE]...'),
4150 _('[OPTION]... [FILE]...'),
4152 inferrepo=True)
4151 inferrepo=True)
4153 def resolve(ui, repo, *pats, **opts):
4152 def resolve(ui, repo, *pats, **opts):
4154 """redo merges or set/view the merge status of files
4153 """redo merges or set/view the merge status of files
4155
4154
4156 Merges with unresolved conflicts are often the result of
4155 Merges with unresolved conflicts are often the result of
4157 non-interactive merging using the ``internal:merge`` configuration
4156 non-interactive merging using the ``internal:merge`` configuration
4158 setting, or a command-line merge tool like ``diff3``. The resolve
4157 setting, or a command-line merge tool like ``diff3``. The resolve
4159 command is used to manage the files involved in a merge, after
4158 command is used to manage the files involved in a merge, after
4160 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4159 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4161 working directory must have two parents). See :hg:`help
4160 working directory must have two parents). See :hg:`help
4162 merge-tools` for information on configuring merge tools.
4161 merge-tools` for information on configuring merge tools.
4163
4162
4164 The resolve command can be used in the following ways:
4163 The resolve command can be used in the following ways:
4165
4164
4166 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4165 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4167 files, discarding any previous merge attempts. Re-merging is not
4166 files, discarding any previous merge attempts. Re-merging is not
4168 performed for files already marked as resolved. Use ``--all/-a``
4167 performed for files already marked as resolved. Use ``--all/-a``
4169 to select all unresolved files. ``--tool`` can be used to specify
4168 to select all unresolved files. ``--tool`` can be used to specify
4170 the merge tool used for the given files. It overrides the HGMERGE
4169 the merge tool used for the given files. It overrides the HGMERGE
4171 environment variable and your configuration files. Previous file
4170 environment variable and your configuration files. Previous file
4172 contents are saved with a ``.orig`` suffix.
4171 contents are saved with a ``.orig`` suffix.
4173
4172
4174 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4173 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4175 (e.g. after having manually fixed-up the files). The default is
4174 (e.g. after having manually fixed-up the files). The default is
4176 to mark all unresolved files.
4175 to mark all unresolved files.
4177
4176
4178 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4177 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4179 default is to mark all resolved files.
4178 default is to mark all resolved files.
4180
4179
4181 - :hg:`resolve -l`: list files which had or still have conflicts.
4180 - :hg:`resolve -l`: list files which had or still have conflicts.
4182 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4181 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4183 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4182 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4184 the list. See :hg:`help filesets` for details.
4183 the list. See :hg:`help filesets` for details.
4185
4184
4186 .. note::
4185 .. note::
4187
4186
4188 Mercurial will not let you commit files with unresolved merge
4187 Mercurial will not let you commit files with unresolved merge
4189 conflicts. You must use :hg:`resolve -m ...` before you can
4188 conflicts. You must use :hg:`resolve -m ...` before you can
4190 commit after a conflicting merge.
4189 commit after a conflicting merge.
4191
4190
4192 Returns 0 on success, 1 if any files fail a resolve attempt.
4191 Returns 0 on success, 1 if any files fail a resolve attempt.
4193 """
4192 """
4194
4193
4195 opts = pycompat.byteskwargs(opts)
4194 opts = pycompat.byteskwargs(opts)
4196 flaglist = 'all mark unmark list no_status'.split()
4195 flaglist = 'all mark unmark list no_status'.split()
4197 all, mark, unmark, show, nostatus = \
4196 all, mark, unmark, show, nostatus = \
4198 [opts.get(o) for o in flaglist]
4197 [opts.get(o) for o in flaglist]
4199
4198
4200 if (show and (mark or unmark)) or (mark and unmark):
4199 if (show and (mark or unmark)) or (mark and unmark):
4201 raise error.Abort(_("too many options specified"))
4200 raise error.Abort(_("too many options specified"))
4202 if pats and all:
4201 if pats and all:
4203 raise error.Abort(_("can't specify --all and patterns"))
4202 raise error.Abort(_("can't specify --all and patterns"))
4204 if not (all or pats or show or mark or unmark):
4203 if not (all or pats or show or mark or unmark):
4205 raise error.Abort(_('no files or directories specified'),
4204 raise error.Abort(_('no files or directories specified'),
4206 hint=('use --all to re-merge all unresolved files'))
4205 hint=('use --all to re-merge all unresolved files'))
4207
4206
4208 if show:
4207 if show:
4209 ui.pager('resolve')
4208 ui.pager('resolve')
4210 fm = ui.formatter('resolve', opts)
4209 fm = ui.formatter('resolve', opts)
4211 ms = mergemod.mergestate.read(repo)
4210 ms = mergemod.mergestate.read(repo)
4212 m = scmutil.match(repo[None], pats, opts)
4211 m = scmutil.match(repo[None], pats, opts)
4213 for f in ms:
4212 for f in ms:
4214 if not m(f):
4213 if not m(f):
4215 continue
4214 continue
4216 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4215 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4217 'd': 'driverresolved'}[ms[f]]
4216 'd': 'driverresolved'}[ms[f]]
4218 fm.startitem()
4217 fm.startitem()
4219 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4218 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4220 fm.write('path', '%s\n', f, label=l)
4219 fm.write('path', '%s\n', f, label=l)
4221 fm.end()
4220 fm.end()
4222 return 0
4221 return 0
4223
4222
4224 with repo.wlock():
4223 with repo.wlock():
4225 ms = mergemod.mergestate.read(repo)
4224 ms = mergemod.mergestate.read(repo)
4226
4225
4227 if not (ms.active() or repo.dirstate.p2() != nullid):
4226 if not (ms.active() or repo.dirstate.p2() != nullid):
4228 raise error.Abort(
4227 raise error.Abort(
4229 _('resolve command not applicable when not merging'))
4228 _('resolve command not applicable when not merging'))
4230
4229
4231 wctx = repo[None]
4230 wctx = repo[None]
4232
4231
4233 if ms.mergedriver and ms.mdstate() == 'u':
4232 if ms.mergedriver and ms.mdstate() == 'u':
4234 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4233 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4235 ms.commit()
4234 ms.commit()
4236 # allow mark and unmark to go through
4235 # allow mark and unmark to go through
4237 if not mark and not unmark and not proceed:
4236 if not mark and not unmark and not proceed:
4238 return 1
4237 return 1
4239
4238
4240 m = scmutil.match(wctx, pats, opts)
4239 m = scmutil.match(wctx, pats, opts)
4241 ret = 0
4240 ret = 0
4242 didwork = False
4241 didwork = False
4243 runconclude = False
4242 runconclude = False
4244
4243
4245 tocomplete = []
4244 tocomplete = []
4246 for f in ms:
4245 for f in ms:
4247 if not m(f):
4246 if not m(f):
4248 continue
4247 continue
4249
4248
4250 didwork = True
4249 didwork = True
4251
4250
4252 # don't let driver-resolved files be marked, and run the conclude
4251 # don't let driver-resolved files be marked, and run the conclude
4253 # step if asked to resolve
4252 # step if asked to resolve
4254 if ms[f] == "d":
4253 if ms[f] == "d":
4255 exact = m.exact(f)
4254 exact = m.exact(f)
4256 if mark:
4255 if mark:
4257 if exact:
4256 if exact:
4258 ui.warn(_('not marking %s as it is driver-resolved\n')
4257 ui.warn(_('not marking %s as it is driver-resolved\n')
4259 % f)
4258 % f)
4260 elif unmark:
4259 elif unmark:
4261 if exact:
4260 if exact:
4262 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4261 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4263 % f)
4262 % f)
4264 else:
4263 else:
4265 runconclude = True
4264 runconclude = True
4266 continue
4265 continue
4267
4266
4268 if mark:
4267 if mark:
4269 ms.mark(f, "r")
4268 ms.mark(f, "r")
4270 elif unmark:
4269 elif unmark:
4271 ms.mark(f, "u")
4270 ms.mark(f, "u")
4272 else:
4271 else:
4273 # backup pre-resolve (merge uses .orig for its own purposes)
4272 # backup pre-resolve (merge uses .orig for its own purposes)
4274 a = repo.wjoin(f)
4273 a = repo.wjoin(f)
4275 try:
4274 try:
4276 util.copyfile(a, a + ".resolve")
4275 util.copyfile(a, a + ".resolve")
4277 except (IOError, OSError) as inst:
4276 except (IOError, OSError) as inst:
4278 if inst.errno != errno.ENOENT:
4277 if inst.errno != errno.ENOENT:
4279 raise
4278 raise
4280
4279
4281 try:
4280 try:
4282 # preresolve file
4281 # preresolve file
4283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4284 'resolve')
4283 'resolve')
4285 complete, r = ms.preresolve(f, wctx)
4284 complete, r = ms.preresolve(f, wctx)
4286 if not complete:
4285 if not complete:
4287 tocomplete.append(f)
4286 tocomplete.append(f)
4288 elif r:
4287 elif r:
4289 ret = 1
4288 ret = 1
4290 finally:
4289 finally:
4291 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4290 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4292 ms.commit()
4291 ms.commit()
4293
4292
4294 # replace filemerge's .orig file with our resolve file, but only
4293 # replace filemerge's .orig file with our resolve file, but only
4295 # for merges that are complete
4294 # for merges that are complete
4296 if complete:
4295 if complete:
4297 try:
4296 try:
4298 util.rename(a + ".resolve",
4297 util.rename(a + ".resolve",
4299 scmutil.origpath(ui, repo, a))
4298 scmutil.origpath(ui, repo, a))
4300 except OSError as inst:
4299 except OSError as inst:
4301 if inst.errno != errno.ENOENT:
4300 if inst.errno != errno.ENOENT:
4302 raise
4301 raise
4303
4302
4304 for f in tocomplete:
4303 for f in tocomplete:
4305 try:
4304 try:
4306 # resolve file
4305 # resolve file
4307 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4306 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4308 'resolve')
4307 'resolve')
4309 r = ms.resolve(f, wctx)
4308 r = ms.resolve(f, wctx)
4310 if r:
4309 if r:
4311 ret = 1
4310 ret = 1
4312 finally:
4311 finally:
4313 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4312 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4314 ms.commit()
4313 ms.commit()
4315
4314
4316 # replace filemerge's .orig file with our resolve file
4315 # replace filemerge's .orig file with our resolve file
4317 a = repo.wjoin(f)
4316 a = repo.wjoin(f)
4318 try:
4317 try:
4319 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4318 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4320 except OSError as inst:
4319 except OSError as inst:
4321 if inst.errno != errno.ENOENT:
4320 if inst.errno != errno.ENOENT:
4322 raise
4321 raise
4323
4322
4324 ms.commit()
4323 ms.commit()
4325 ms.recordactions()
4324 ms.recordactions()
4326
4325
4327 if not didwork and pats:
4326 if not didwork and pats:
4328 hint = None
4327 hint = None
4329 if not any([p for p in pats if p.find(':') >= 0]):
4328 if not any([p for p in pats if p.find(':') >= 0]):
4330 pats = ['path:%s' % p for p in pats]
4329 pats = ['path:%s' % p for p in pats]
4331 m = scmutil.match(wctx, pats, opts)
4330 m = scmutil.match(wctx, pats, opts)
4332 for f in ms:
4331 for f in ms:
4333 if not m(f):
4332 if not m(f):
4334 continue
4333 continue
4335 flags = ''.join(['-%s ' % o[0] for o in flaglist
4334 flags = ''.join(['-%s ' % o[0] for o in flaglist
4336 if opts.get(o)])
4335 if opts.get(o)])
4337 hint = _("(try: hg resolve %s%s)\n") % (
4336 hint = _("(try: hg resolve %s%s)\n") % (
4338 flags,
4337 flags,
4339 ' '.join(pats))
4338 ' '.join(pats))
4340 break
4339 break
4341 ui.warn(_("arguments do not match paths that need resolving\n"))
4340 ui.warn(_("arguments do not match paths that need resolving\n"))
4342 if hint:
4341 if hint:
4343 ui.warn(hint)
4342 ui.warn(hint)
4344 elif ms.mergedriver and ms.mdstate() != 's':
4343 elif ms.mergedriver and ms.mdstate() != 's':
4345 # run conclude step when either a driver-resolved file is requested
4344 # run conclude step when either a driver-resolved file is requested
4346 # or there are no driver-resolved files
4345 # or there are no driver-resolved files
4347 # we can't use 'ret' to determine whether any files are unresolved
4346 # we can't use 'ret' to determine whether any files are unresolved
4348 # because we might not have tried to resolve some
4347 # because we might not have tried to resolve some
4349 if ((runconclude or not list(ms.driverresolved()))
4348 if ((runconclude or not list(ms.driverresolved()))
4350 and not list(ms.unresolved())):
4349 and not list(ms.unresolved())):
4351 proceed = mergemod.driverconclude(repo, ms, wctx)
4350 proceed = mergemod.driverconclude(repo, ms, wctx)
4352 ms.commit()
4351 ms.commit()
4353 if not proceed:
4352 if not proceed:
4354 return 1
4353 return 1
4355
4354
4356 # Nudge users into finishing an unfinished operation
4355 # Nudge users into finishing an unfinished operation
4357 unresolvedf = list(ms.unresolved())
4356 unresolvedf = list(ms.unresolved())
4358 driverresolvedf = list(ms.driverresolved())
4357 driverresolvedf = list(ms.driverresolved())
4359 if not unresolvedf and not driverresolvedf:
4358 if not unresolvedf and not driverresolvedf:
4360 ui.status(_('(no more unresolved files)\n'))
4359 ui.status(_('(no more unresolved files)\n'))
4361 cmdutil.checkafterresolved(repo)
4360 cmdutil.checkafterresolved(repo)
4362 elif not unresolvedf:
4361 elif not unresolvedf:
4363 ui.status(_('(no more unresolved files -- '
4362 ui.status(_('(no more unresolved files -- '
4364 'run "hg resolve --all" to conclude)\n'))
4363 'run "hg resolve --all" to conclude)\n'))
4365
4364
4366 return ret
4365 return ret
4367
4366
4368 @command('revert',
4367 @command('revert',
4369 [('a', 'all', None, _('revert all changes when no arguments given')),
4368 [('a', 'all', None, _('revert all changes when no arguments given')),
4370 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4369 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4371 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4370 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4372 ('C', 'no-backup', None, _('do not save backup copies of files')),
4371 ('C', 'no-backup', None, _('do not save backup copies of files')),
4373 ('i', 'interactive', None,
4372 ('i', 'interactive', None,
4374 _('interactively select the changes (EXPERIMENTAL)')),
4373 _('interactively select the changes (EXPERIMENTAL)')),
4375 ] + walkopts + dryrunopts,
4374 ] + walkopts + dryrunopts,
4376 _('[OPTION]... [-r REV] [NAME]...'))
4375 _('[OPTION]... [-r REV] [NAME]...'))
4377 def revert(ui, repo, *pats, **opts):
4376 def revert(ui, repo, *pats, **opts):
4378 """restore files to their checkout state
4377 """restore files to their checkout state
4379
4378
4380 .. note::
4379 .. note::
4381
4380
4382 To check out earlier revisions, you should use :hg:`update REV`.
4381 To check out earlier revisions, you should use :hg:`update REV`.
4383 To cancel an uncommitted merge (and lose your changes),
4382 To cancel an uncommitted merge (and lose your changes),
4384 use :hg:`update --clean .`.
4383 use :hg:`update --clean .`.
4385
4384
4386 With no revision specified, revert the specified files or directories
4385 With no revision specified, revert the specified files or directories
4387 to the contents they had in the parent of the working directory.
4386 to the contents they had in the parent of the working directory.
4388 This restores the contents of files to an unmodified
4387 This restores the contents of files to an unmodified
4389 state and unschedules adds, removes, copies, and renames. If the
4388 state and unschedules adds, removes, copies, and renames. If the
4390 working directory has two parents, you must explicitly specify a
4389 working directory has two parents, you must explicitly specify a
4391 revision.
4390 revision.
4392
4391
4393 Using the -r/--rev or -d/--date options, revert the given files or
4392 Using the -r/--rev or -d/--date options, revert the given files or
4394 directories to their states as of a specific revision. Because
4393 directories to their states as of a specific revision. Because
4395 revert does not change the working directory parents, this will
4394 revert does not change the working directory parents, this will
4396 cause these files to appear modified. This can be helpful to "back
4395 cause these files to appear modified. This can be helpful to "back
4397 out" some or all of an earlier change. See :hg:`backout` for a
4396 out" some or all of an earlier change. See :hg:`backout` for a
4398 related method.
4397 related method.
4399
4398
4400 Modified files are saved with a .orig suffix before reverting.
4399 Modified files are saved with a .orig suffix before reverting.
4401 To disable these backups, use --no-backup. It is possible to store
4400 To disable these backups, use --no-backup. It is possible to store
4402 the backup files in a custom directory relative to the root of the
4401 the backup files in a custom directory relative to the root of the
4403 repository by setting the ``ui.origbackuppath`` configuration
4402 repository by setting the ``ui.origbackuppath`` configuration
4404 option.
4403 option.
4405
4404
4406 See :hg:`help dates` for a list of formats valid for -d/--date.
4405 See :hg:`help dates` for a list of formats valid for -d/--date.
4407
4406
4408 See :hg:`help backout` for a way to reverse the effect of an
4407 See :hg:`help backout` for a way to reverse the effect of an
4409 earlier changeset.
4408 earlier changeset.
4410
4409
4411 Returns 0 on success.
4410 Returns 0 on success.
4412 """
4411 """
4413
4412
4414 if opts.get("date"):
4413 if opts.get("date"):
4415 if opts.get("rev"):
4414 if opts.get("rev"):
4416 raise error.Abort(_("you can't specify a revision and a date"))
4415 raise error.Abort(_("you can't specify a revision and a date"))
4417 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4416 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4418
4417
4419 parent, p2 = repo.dirstate.parents()
4418 parent, p2 = repo.dirstate.parents()
4420 if not opts.get('rev') and p2 != nullid:
4419 if not opts.get('rev') and p2 != nullid:
4421 # revert after merge is a trap for new users (issue2915)
4420 # revert after merge is a trap for new users (issue2915)
4422 raise error.Abort(_('uncommitted merge with no revision specified'),
4421 raise error.Abort(_('uncommitted merge with no revision specified'),
4423 hint=_("use 'hg update' or see 'hg help revert'"))
4422 hint=_("use 'hg update' or see 'hg help revert'"))
4424
4423
4425 ctx = scmutil.revsingle(repo, opts.get('rev'))
4424 ctx = scmutil.revsingle(repo, opts.get('rev'))
4426
4425
4427 if (not (pats or opts.get('include') or opts.get('exclude') or
4426 if (not (pats or opts.get('include') or opts.get('exclude') or
4428 opts.get('all') or opts.get('interactive'))):
4427 opts.get('all') or opts.get('interactive'))):
4429 msg = _("no files or directories specified")
4428 msg = _("no files or directories specified")
4430 if p2 != nullid:
4429 if p2 != nullid:
4431 hint = _("uncommitted merge, use --all to discard all changes,"
4430 hint = _("uncommitted merge, use --all to discard all changes,"
4432 " or 'hg update -C .' to abort the merge")
4431 " or 'hg update -C .' to abort the merge")
4433 raise error.Abort(msg, hint=hint)
4432 raise error.Abort(msg, hint=hint)
4434 dirty = any(repo.status())
4433 dirty = any(repo.status())
4435 node = ctx.node()
4434 node = ctx.node()
4436 if node != parent:
4435 if node != parent:
4437 if dirty:
4436 if dirty:
4438 hint = _("uncommitted changes, use --all to discard all"
4437 hint = _("uncommitted changes, use --all to discard all"
4439 " changes, or 'hg update %s' to update") % ctx.rev()
4438 " changes, or 'hg update %s' to update") % ctx.rev()
4440 else:
4439 else:
4441 hint = _("use --all to revert all files,"
4440 hint = _("use --all to revert all files,"
4442 " or 'hg update %s' to update") % ctx.rev()
4441 " or 'hg update %s' to update") % ctx.rev()
4443 elif dirty:
4442 elif dirty:
4444 hint = _("uncommitted changes, use --all to discard all changes")
4443 hint = _("uncommitted changes, use --all to discard all changes")
4445 else:
4444 else:
4446 hint = _("use --all to revert all files")
4445 hint = _("use --all to revert all files")
4447 raise error.Abort(msg, hint=hint)
4446 raise error.Abort(msg, hint=hint)
4448
4447
4449 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4448 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4450
4449
4451 @command('rollback', dryrunopts +
4450 @command('rollback', dryrunopts +
4452 [('f', 'force', False, _('ignore safety measures'))])
4451 [('f', 'force', False, _('ignore safety measures'))])
4453 def rollback(ui, repo, **opts):
4452 def rollback(ui, repo, **opts):
4454 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4453 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4455
4454
4456 Please use :hg:`commit --amend` instead of rollback to correct
4455 Please use :hg:`commit --amend` instead of rollback to correct
4457 mistakes in the last commit.
4456 mistakes in the last commit.
4458
4457
4459 This command should be used with care. There is only one level of
4458 This command should be used with care. There is only one level of
4460 rollback, and there is no way to undo a rollback. It will also
4459 rollback, and there is no way to undo a rollback. It will also
4461 restore the dirstate at the time of the last transaction, losing
4460 restore the dirstate at the time of the last transaction, losing
4462 any dirstate changes since that time. This command does not alter
4461 any dirstate changes since that time. This command does not alter
4463 the working directory.
4462 the working directory.
4464
4463
4465 Transactions are used to encapsulate the effects of all commands
4464 Transactions are used to encapsulate the effects of all commands
4466 that create new changesets or propagate existing changesets into a
4465 that create new changesets or propagate existing changesets into a
4467 repository.
4466 repository.
4468
4467
4469 .. container:: verbose
4468 .. container:: verbose
4470
4469
4471 For example, the following commands are transactional, and their
4470 For example, the following commands are transactional, and their
4472 effects can be rolled back:
4471 effects can be rolled back:
4473
4472
4474 - commit
4473 - commit
4475 - import
4474 - import
4476 - pull
4475 - pull
4477 - push (with this repository as the destination)
4476 - push (with this repository as the destination)
4478 - unbundle
4477 - unbundle
4479
4478
4480 To avoid permanent data loss, rollback will refuse to rollback a
4479 To avoid permanent data loss, rollback will refuse to rollback a
4481 commit transaction if it isn't checked out. Use --force to
4480 commit transaction if it isn't checked out. Use --force to
4482 override this protection.
4481 override this protection.
4483
4482
4484 The rollback command can be entirely disabled by setting the
4483 The rollback command can be entirely disabled by setting the
4485 ``ui.rollback`` configuration setting to false. If you're here
4484 ``ui.rollback`` configuration setting to false. If you're here
4486 because you want to use rollback and it's disabled, you can
4485 because you want to use rollback and it's disabled, you can
4487 re-enable the command by setting ``ui.rollback`` to true.
4486 re-enable the command by setting ``ui.rollback`` to true.
4488
4487
4489 This command is not intended for use on public repositories. Once
4488 This command is not intended for use on public repositories. Once
4490 changes are visible for pull by other users, rolling a transaction
4489 changes are visible for pull by other users, rolling a transaction
4491 back locally is ineffective (someone else may already have pulled
4490 back locally is ineffective (someone else may already have pulled
4492 the changes). Furthermore, a race is possible with readers of the
4491 the changes). Furthermore, a race is possible with readers of the
4493 repository; for example an in-progress pull from the repository
4492 repository; for example an in-progress pull from the repository
4494 may fail if a rollback is performed.
4493 may fail if a rollback is performed.
4495
4494
4496 Returns 0 on success, 1 if no rollback data is available.
4495 Returns 0 on success, 1 if no rollback data is available.
4497 """
4496 """
4498 if not ui.configbool('ui', 'rollback', True):
4497 if not ui.configbool('ui', 'rollback', True):
4499 raise error.Abort(_('rollback is disabled because it is unsafe'),
4498 raise error.Abort(_('rollback is disabled because it is unsafe'),
4500 hint=('see `hg help -v rollback` for information'))
4499 hint=('see `hg help -v rollback` for information'))
4501 return repo.rollback(dryrun=opts.get(r'dry_run'),
4500 return repo.rollback(dryrun=opts.get(r'dry_run'),
4502 force=opts.get(r'force'))
4501 force=opts.get(r'force'))
4503
4502
4504 @command('root', [])
4503 @command('root', [])
4505 def root(ui, repo):
4504 def root(ui, repo):
4506 """print the root (top) of the current working directory
4505 """print the root (top) of the current working directory
4507
4506
4508 Print the root directory of the current repository.
4507 Print the root directory of the current repository.
4509
4508
4510 Returns 0 on success.
4509 Returns 0 on success.
4511 """
4510 """
4512 ui.write(repo.root + "\n")
4511 ui.write(repo.root + "\n")
4513
4512
4514 @command('^serve',
4513 @command('^serve',
4515 [('A', 'accesslog', '', _('name of access log file to write to'),
4514 [('A', 'accesslog', '', _('name of access log file to write to'),
4516 _('FILE')),
4515 _('FILE')),
4517 ('d', 'daemon', None, _('run server in background')),
4516 ('d', 'daemon', None, _('run server in background')),
4518 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4517 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4519 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4518 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4520 # use string type, then we can check if something was passed
4519 # use string type, then we can check if something was passed
4521 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4520 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4522 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4521 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4523 _('ADDR')),
4522 _('ADDR')),
4524 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4523 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4525 _('PREFIX')),
4524 _('PREFIX')),
4526 ('n', 'name', '',
4525 ('n', 'name', '',
4527 _('name to show in web pages (default: working directory)'), _('NAME')),
4526 _('name to show in web pages (default: working directory)'), _('NAME')),
4528 ('', 'web-conf', '',
4527 ('', 'web-conf', '',
4529 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4528 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4530 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4529 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4531 _('FILE')),
4530 _('FILE')),
4532 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4531 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4533 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4532 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4534 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4533 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4535 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4534 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4536 ('', 'style', '', _('template style to use'), _('STYLE')),
4535 ('', 'style', '', _('template style to use'), _('STYLE')),
4537 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4536 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4538 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4537 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4539 + subrepoopts,
4538 + subrepoopts,
4540 _('[OPTION]...'),
4539 _('[OPTION]...'),
4541 optionalrepo=True)
4540 optionalrepo=True)
4542 def serve(ui, repo, **opts):
4541 def serve(ui, repo, **opts):
4543 """start stand-alone webserver
4542 """start stand-alone webserver
4544
4543
4545 Start a local HTTP repository browser and pull server. You can use
4544 Start a local HTTP repository browser and pull server. You can use
4546 this for ad-hoc sharing and browsing of repositories. It is
4545 this for ad-hoc sharing and browsing of repositories. It is
4547 recommended to use a real web server to serve a repository for
4546 recommended to use a real web server to serve a repository for
4548 longer periods of time.
4547 longer periods of time.
4549
4548
4550 Please note that the server does not implement access control.
4549 Please note that the server does not implement access control.
4551 This means that, by default, anybody can read from the server and
4550 This means that, by default, anybody can read from the server and
4552 nobody can write to it by default. Set the ``web.allow_push``
4551 nobody can write to it by default. Set the ``web.allow_push``
4553 option to ``*`` to allow everybody to push to the server. You
4552 option to ``*`` to allow everybody to push to the server. You
4554 should use a real web server if you need to authenticate users.
4553 should use a real web server if you need to authenticate users.
4555
4554
4556 By default, the server logs accesses to stdout and errors to
4555 By default, the server logs accesses to stdout and errors to
4557 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4556 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4558 files.
4557 files.
4559
4558
4560 To have the server choose a free port number to listen on, specify
4559 To have the server choose a free port number to listen on, specify
4561 a port number of 0; in this case, the server will print the port
4560 a port number of 0; in this case, the server will print the port
4562 number it uses.
4561 number it uses.
4563
4562
4564 Returns 0 on success.
4563 Returns 0 on success.
4565 """
4564 """
4566
4565
4567 opts = pycompat.byteskwargs(opts)
4566 opts = pycompat.byteskwargs(opts)
4568 if opts["stdio"] and opts["cmdserver"]:
4567 if opts["stdio"] and opts["cmdserver"]:
4569 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4568 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4570
4569
4571 if opts["stdio"]:
4570 if opts["stdio"]:
4572 if repo is None:
4571 if repo is None:
4573 raise error.RepoError(_("there is no Mercurial repository here"
4572 raise error.RepoError(_("there is no Mercurial repository here"
4574 " (.hg not found)"))
4573 " (.hg not found)"))
4575 s = sshserver.sshserver(ui, repo)
4574 s = sshserver.sshserver(ui, repo)
4576 s.serve_forever()
4575 s.serve_forever()
4577
4576
4578 service = server.createservice(ui, repo, opts)
4577 service = server.createservice(ui, repo, opts)
4579 return server.runservice(opts, initfn=service.init, runfn=service.run)
4578 return server.runservice(opts, initfn=service.init, runfn=service.run)
4580
4579
4581 @command('^status|st',
4580 @command('^status|st',
4582 [('A', 'all', None, _('show status of all files')),
4581 [('A', 'all', None, _('show status of all files')),
4583 ('m', 'modified', None, _('show only modified files')),
4582 ('m', 'modified', None, _('show only modified files')),
4584 ('a', 'added', None, _('show only added files')),
4583 ('a', 'added', None, _('show only added files')),
4585 ('r', 'removed', None, _('show only removed files')),
4584 ('r', 'removed', None, _('show only removed files')),
4586 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4585 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4587 ('c', 'clean', None, _('show only files without changes')),
4586 ('c', 'clean', None, _('show only files without changes')),
4588 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4587 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4589 ('i', 'ignored', None, _('show only ignored files')),
4588 ('i', 'ignored', None, _('show only ignored files')),
4590 ('n', 'no-status', None, _('hide status prefix')),
4589 ('n', 'no-status', None, _('hide status prefix')),
4591 ('C', 'copies', None, _('show source of copied files')),
4590 ('C', 'copies', None, _('show source of copied files')),
4592 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4591 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4593 ('', 'rev', [], _('show difference from revision'), _('REV')),
4592 ('', 'rev', [], _('show difference from revision'), _('REV')),
4594 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4593 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4595 ] + walkopts + subrepoopts + formatteropts,
4594 ] + walkopts + subrepoopts + formatteropts,
4596 _('[OPTION]... [FILE]...'),
4595 _('[OPTION]... [FILE]...'),
4597 inferrepo=True)
4596 inferrepo=True)
4598 def status(ui, repo, *pats, **opts):
4597 def status(ui, repo, *pats, **opts):
4599 """show changed files in the working directory
4598 """show changed files in the working directory
4600
4599
4601 Show status of files in the repository. If names are given, only
4600 Show status of files in the repository. If names are given, only
4602 files that match are shown. Files that are clean or ignored or
4601 files that match are shown. Files that are clean or ignored or
4603 the source of a copy/move operation, are not listed unless
4602 the source of a copy/move operation, are not listed unless
4604 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4603 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4605 Unless options described with "show only ..." are given, the
4604 Unless options described with "show only ..." are given, the
4606 options -mardu are used.
4605 options -mardu are used.
4607
4606
4608 Option -q/--quiet hides untracked (unknown and ignored) files
4607 Option -q/--quiet hides untracked (unknown and ignored) files
4609 unless explicitly requested with -u/--unknown or -i/--ignored.
4608 unless explicitly requested with -u/--unknown or -i/--ignored.
4610
4609
4611 .. note::
4610 .. note::
4612
4611
4613 :hg:`status` may appear to disagree with diff if permissions have
4612 :hg:`status` may appear to disagree with diff if permissions have
4614 changed or a merge has occurred. The standard diff format does
4613 changed or a merge has occurred. The standard diff format does
4615 not report permission changes and diff only reports changes
4614 not report permission changes and diff only reports changes
4616 relative to one merge parent.
4615 relative to one merge parent.
4617
4616
4618 If one revision is given, it is used as the base revision.
4617 If one revision is given, it is used as the base revision.
4619 If two revisions are given, the differences between them are
4618 If two revisions are given, the differences between them are
4620 shown. The --change option can also be used as a shortcut to list
4619 shown. The --change option can also be used as a shortcut to list
4621 the changed files of a revision from its first parent.
4620 the changed files of a revision from its first parent.
4622
4621
4623 The codes used to show the status of files are::
4622 The codes used to show the status of files are::
4624
4623
4625 M = modified
4624 M = modified
4626 A = added
4625 A = added
4627 R = removed
4626 R = removed
4628 C = clean
4627 C = clean
4629 ! = missing (deleted by non-hg command, but still tracked)
4628 ! = missing (deleted by non-hg command, but still tracked)
4630 ? = not tracked
4629 ? = not tracked
4631 I = ignored
4630 I = ignored
4632 = origin of the previous file (with --copies)
4631 = origin of the previous file (with --copies)
4633
4632
4634 .. container:: verbose
4633 .. container:: verbose
4635
4634
4636 Examples:
4635 Examples:
4637
4636
4638 - show changes in the working directory relative to a
4637 - show changes in the working directory relative to a
4639 changeset::
4638 changeset::
4640
4639
4641 hg status --rev 9353
4640 hg status --rev 9353
4642
4641
4643 - show changes in the working directory relative to the
4642 - show changes in the working directory relative to the
4644 current directory (see :hg:`help patterns` for more information)::
4643 current directory (see :hg:`help patterns` for more information)::
4645
4644
4646 hg status re:
4645 hg status re:
4647
4646
4648 - show all changes including copies in an existing changeset::
4647 - show all changes including copies in an existing changeset::
4649
4648
4650 hg status --copies --change 9353
4649 hg status --copies --change 9353
4651
4650
4652 - get a NUL separated list of added files, suitable for xargs::
4651 - get a NUL separated list of added files, suitable for xargs::
4653
4652
4654 hg status -an0
4653 hg status -an0
4655
4654
4656 Returns 0 on success.
4655 Returns 0 on success.
4657 """
4656 """
4658
4657
4659 opts = pycompat.byteskwargs(opts)
4658 opts = pycompat.byteskwargs(opts)
4660 revs = opts.get('rev')
4659 revs = opts.get('rev')
4661 change = opts.get('change')
4660 change = opts.get('change')
4662
4661
4663 if revs and change:
4662 if revs and change:
4664 msg = _('cannot specify --rev and --change at the same time')
4663 msg = _('cannot specify --rev and --change at the same time')
4665 raise error.Abort(msg)
4664 raise error.Abort(msg)
4666 elif change:
4665 elif change:
4667 node2 = scmutil.revsingle(repo, change, None).node()
4666 node2 = scmutil.revsingle(repo, change, None).node()
4668 node1 = repo[node2].p1().node()
4667 node1 = repo[node2].p1().node()
4669 else:
4668 else:
4670 node1, node2 = scmutil.revpair(repo, revs)
4669 node1, node2 = scmutil.revpair(repo, revs)
4671
4670
4672 if pats or ui.configbool('commands', 'status.relative'):
4671 if pats or ui.configbool('commands', 'status.relative'):
4673 cwd = repo.getcwd()
4672 cwd = repo.getcwd()
4674 else:
4673 else:
4675 cwd = ''
4674 cwd = ''
4676
4675
4677 if opts.get('print0'):
4676 if opts.get('print0'):
4678 end = '\0'
4677 end = '\0'
4679 else:
4678 else:
4680 end = '\n'
4679 end = '\n'
4681 copy = {}
4680 copy = {}
4682 states = 'modified added removed deleted unknown ignored clean'.split()
4681 states = 'modified added removed deleted unknown ignored clean'.split()
4683 show = [k for k in states if opts.get(k)]
4682 show = [k for k in states if opts.get(k)]
4684 if opts.get('all'):
4683 if opts.get('all'):
4685 show += ui.quiet and (states[:4] + ['clean']) or states
4684 show += ui.quiet and (states[:4] + ['clean']) or states
4686 if not show:
4685 if not show:
4687 if ui.quiet:
4686 if ui.quiet:
4688 show = states[:4]
4687 show = states[:4]
4689 else:
4688 else:
4690 show = states[:5]
4689 show = states[:5]
4691
4690
4692 m = scmutil.match(repo[node2], pats, opts)
4691 m = scmutil.match(repo[node2], pats, opts)
4693 stat = repo.status(node1, node2, m,
4692 stat = repo.status(node1, node2, m,
4694 'ignored' in show, 'clean' in show, 'unknown' in show,
4693 'ignored' in show, 'clean' in show, 'unknown' in show,
4695 opts.get('subrepos'))
4694 opts.get('subrepos'))
4696 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4695 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4697
4696
4698 if (opts.get('all') or opts.get('copies')
4697 if (opts.get('all') or opts.get('copies')
4699 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4698 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4700 copy = copies.pathcopies(repo[node1], repo[node2], m)
4699 copy = copies.pathcopies(repo[node1], repo[node2], m)
4701
4700
4702 ui.pager('status')
4701 ui.pager('status')
4703 fm = ui.formatter('status', opts)
4702 fm = ui.formatter('status', opts)
4704 fmt = '%s' + end
4703 fmt = '%s' + end
4705 showchar = not opts.get('no_status')
4704 showchar = not opts.get('no_status')
4706
4705
4707 for state, char, files in changestates:
4706 for state, char, files in changestates:
4708 if state in show:
4707 if state in show:
4709 label = 'status.' + state
4708 label = 'status.' + state
4710 for f in files:
4709 for f in files:
4711 fm.startitem()
4710 fm.startitem()
4712 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4711 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4713 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4712 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4714 if f in copy:
4713 if f in copy:
4715 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4714 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4716 label='status.copied')
4715 label='status.copied')
4717 fm.end()
4716 fm.end()
4718
4717
4719 @command('^summary|sum',
4718 @command('^summary|sum',
4720 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4719 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4721 def summary(ui, repo, **opts):
4720 def summary(ui, repo, **opts):
4722 """summarize working directory state
4721 """summarize working directory state
4723
4722
4724 This generates a brief summary of the working directory state,
4723 This generates a brief summary of the working directory state,
4725 including parents, branch, commit status, phase and available updates.
4724 including parents, branch, commit status, phase and available updates.
4726
4725
4727 With the --remote option, this will check the default paths for
4726 With the --remote option, this will check the default paths for
4728 incoming and outgoing changes. This can be time-consuming.
4727 incoming and outgoing changes. This can be time-consuming.
4729
4728
4730 Returns 0 on success.
4729 Returns 0 on success.
4731 """
4730 """
4732
4731
4733 opts = pycompat.byteskwargs(opts)
4732 opts = pycompat.byteskwargs(opts)
4734 ui.pager('summary')
4733 ui.pager('summary')
4735 ctx = repo[None]
4734 ctx = repo[None]
4736 parents = ctx.parents()
4735 parents = ctx.parents()
4737 pnode = parents[0].node()
4736 pnode = parents[0].node()
4738 marks = []
4737 marks = []
4739
4738
4740 ms = None
4739 ms = None
4741 try:
4740 try:
4742 ms = mergemod.mergestate.read(repo)
4741 ms = mergemod.mergestate.read(repo)
4743 except error.UnsupportedMergeRecords as e:
4742 except error.UnsupportedMergeRecords as e:
4744 s = ' '.join(e.recordtypes)
4743 s = ' '.join(e.recordtypes)
4745 ui.warn(
4744 ui.warn(
4746 _('warning: merge state has unsupported record types: %s\n') % s)
4745 _('warning: merge state has unsupported record types: %s\n') % s)
4747 unresolved = 0
4746 unresolved = 0
4748 else:
4747 else:
4749 unresolved = [f for f in ms if ms[f] == 'u']
4748 unresolved = [f for f in ms if ms[f] == 'u']
4750
4749
4751 for p in parents:
4750 for p in parents:
4752 # label with log.changeset (instead of log.parent) since this
4751 # label with log.changeset (instead of log.parent) since this
4753 # shows a working directory parent *changeset*:
4752 # shows a working directory parent *changeset*:
4754 # i18n: column positioning for "hg summary"
4753 # i18n: column positioning for "hg summary"
4755 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4754 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4756 label=cmdutil._changesetlabels(p))
4755 label=cmdutil._changesetlabels(p))
4757 ui.write(' '.join(p.tags()), label='log.tag')
4756 ui.write(' '.join(p.tags()), label='log.tag')
4758 if p.bookmarks():
4757 if p.bookmarks():
4759 marks.extend(p.bookmarks())
4758 marks.extend(p.bookmarks())
4760 if p.rev() == -1:
4759 if p.rev() == -1:
4761 if not len(repo):
4760 if not len(repo):
4762 ui.write(_(' (empty repository)'))
4761 ui.write(_(' (empty repository)'))
4763 else:
4762 else:
4764 ui.write(_(' (no revision checked out)'))
4763 ui.write(_(' (no revision checked out)'))
4765 if p.obsolete():
4764 if p.obsolete():
4766 ui.write(_(' (obsolete)'))
4765 ui.write(_(' (obsolete)'))
4767 if p.troubled():
4766 if p.troubled():
4768 ui.write(' ('
4767 ui.write(' ('
4769 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4768 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4770 for trouble in p.troubles())
4769 for trouble in p.troubles())
4771 + ')')
4770 + ')')
4772 ui.write('\n')
4771 ui.write('\n')
4773 if p.description():
4772 if p.description():
4774 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4773 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4775 label='log.summary')
4774 label='log.summary')
4776
4775
4777 branch = ctx.branch()
4776 branch = ctx.branch()
4778 bheads = repo.branchheads(branch)
4777 bheads = repo.branchheads(branch)
4779 # i18n: column positioning for "hg summary"
4778 # i18n: column positioning for "hg summary"
4780 m = _('branch: %s\n') % branch
4779 m = _('branch: %s\n') % branch
4781 if branch != 'default':
4780 if branch != 'default':
4782 ui.write(m, label='log.branch')
4781 ui.write(m, label='log.branch')
4783 else:
4782 else:
4784 ui.status(m, label='log.branch')
4783 ui.status(m, label='log.branch')
4785
4784
4786 if marks:
4785 if marks:
4787 active = repo._activebookmark
4786 active = repo._activebookmark
4788 # i18n: column positioning for "hg summary"
4787 # i18n: column positioning for "hg summary"
4789 ui.write(_('bookmarks:'), label='log.bookmark')
4788 ui.write(_('bookmarks:'), label='log.bookmark')
4790 if active is not None:
4789 if active is not None:
4791 if active in marks:
4790 if active in marks:
4792 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4791 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4793 marks.remove(active)
4792 marks.remove(active)
4794 else:
4793 else:
4795 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4794 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4796 for m in marks:
4795 for m in marks:
4797 ui.write(' ' + m, label='log.bookmark')
4796 ui.write(' ' + m, label='log.bookmark')
4798 ui.write('\n', label='log.bookmark')
4797 ui.write('\n', label='log.bookmark')
4799
4798
4800 status = repo.status(unknown=True)
4799 status = repo.status(unknown=True)
4801
4800
4802 c = repo.dirstate.copies()
4801 c = repo.dirstate.copies()
4803 copied, renamed = [], []
4802 copied, renamed = [], []
4804 for d, s in c.iteritems():
4803 for d, s in c.iteritems():
4805 if s in status.removed:
4804 if s in status.removed:
4806 status.removed.remove(s)
4805 status.removed.remove(s)
4807 renamed.append(d)
4806 renamed.append(d)
4808 else:
4807 else:
4809 copied.append(d)
4808 copied.append(d)
4810 if d in status.added:
4809 if d in status.added:
4811 status.added.remove(d)
4810 status.added.remove(d)
4812
4811
4813 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4812 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4814
4813
4815 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4814 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4816 (ui.label(_('%d added'), 'status.added'), status.added),
4815 (ui.label(_('%d added'), 'status.added'), status.added),
4817 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4816 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4818 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4817 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4819 (ui.label(_('%d copied'), 'status.copied'), copied),
4818 (ui.label(_('%d copied'), 'status.copied'), copied),
4820 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4819 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4821 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4820 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4822 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4821 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4823 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4822 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4824 t = []
4823 t = []
4825 for l, s in labels:
4824 for l, s in labels:
4826 if s:
4825 if s:
4827 t.append(l % len(s))
4826 t.append(l % len(s))
4828
4827
4829 t = ', '.join(t)
4828 t = ', '.join(t)
4830 cleanworkdir = False
4829 cleanworkdir = False
4831
4830
4832 if repo.vfs.exists('graftstate'):
4831 if repo.vfs.exists('graftstate'):
4833 t += _(' (graft in progress)')
4832 t += _(' (graft in progress)')
4834 if repo.vfs.exists('updatestate'):
4833 if repo.vfs.exists('updatestate'):
4835 t += _(' (interrupted update)')
4834 t += _(' (interrupted update)')
4836 elif len(parents) > 1:
4835 elif len(parents) > 1:
4837 t += _(' (merge)')
4836 t += _(' (merge)')
4838 elif branch != parents[0].branch():
4837 elif branch != parents[0].branch():
4839 t += _(' (new branch)')
4838 t += _(' (new branch)')
4840 elif (parents[0].closesbranch() and
4839 elif (parents[0].closesbranch() and
4841 pnode in repo.branchheads(branch, closed=True)):
4840 pnode in repo.branchheads(branch, closed=True)):
4842 t += _(' (head closed)')
4841 t += _(' (head closed)')
4843 elif not (status.modified or status.added or status.removed or renamed or
4842 elif not (status.modified or status.added or status.removed or renamed or
4844 copied or subs):
4843 copied or subs):
4845 t += _(' (clean)')
4844 t += _(' (clean)')
4846 cleanworkdir = True
4845 cleanworkdir = True
4847 elif pnode not in bheads:
4846 elif pnode not in bheads:
4848 t += _(' (new branch head)')
4847 t += _(' (new branch head)')
4849
4848
4850 if parents:
4849 if parents:
4851 pendingphase = max(p.phase() for p in parents)
4850 pendingphase = max(p.phase() for p in parents)
4852 else:
4851 else:
4853 pendingphase = phases.public
4852 pendingphase = phases.public
4854
4853
4855 if pendingphase > phases.newcommitphase(ui):
4854 if pendingphase > phases.newcommitphase(ui):
4856 t += ' (%s)' % phases.phasenames[pendingphase]
4855 t += ' (%s)' % phases.phasenames[pendingphase]
4857
4856
4858 if cleanworkdir:
4857 if cleanworkdir:
4859 # i18n: column positioning for "hg summary"
4858 # i18n: column positioning for "hg summary"
4860 ui.status(_('commit: %s\n') % t.strip())
4859 ui.status(_('commit: %s\n') % t.strip())
4861 else:
4860 else:
4862 # i18n: column positioning for "hg summary"
4861 # i18n: column positioning for "hg summary"
4863 ui.write(_('commit: %s\n') % t.strip())
4862 ui.write(_('commit: %s\n') % t.strip())
4864
4863
4865 # all ancestors of branch heads - all ancestors of parent = new csets
4864 # all ancestors of branch heads - all ancestors of parent = new csets
4866 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4865 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4867 bheads))
4866 bheads))
4868
4867
4869 if new == 0:
4868 if new == 0:
4870 # i18n: column positioning for "hg summary"
4869 # i18n: column positioning for "hg summary"
4871 ui.status(_('update: (current)\n'))
4870 ui.status(_('update: (current)\n'))
4872 elif pnode not in bheads:
4871 elif pnode not in bheads:
4873 # i18n: column positioning for "hg summary"
4872 # i18n: column positioning for "hg summary"
4874 ui.write(_('update: %d new changesets (update)\n') % new)
4873 ui.write(_('update: %d new changesets (update)\n') % new)
4875 else:
4874 else:
4876 # i18n: column positioning for "hg summary"
4875 # i18n: column positioning for "hg summary"
4877 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4876 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4878 (new, len(bheads)))
4877 (new, len(bheads)))
4879
4878
4880 t = []
4879 t = []
4881 draft = len(repo.revs('draft()'))
4880 draft = len(repo.revs('draft()'))
4882 if draft:
4881 if draft:
4883 t.append(_('%d draft') % draft)
4882 t.append(_('%d draft') % draft)
4884 secret = len(repo.revs('secret()'))
4883 secret = len(repo.revs('secret()'))
4885 if secret:
4884 if secret:
4886 t.append(_('%d secret') % secret)
4885 t.append(_('%d secret') % secret)
4887
4886
4888 if draft or secret:
4887 if draft or secret:
4889 ui.status(_('phases: %s\n') % ', '.join(t))
4888 ui.status(_('phases: %s\n') % ', '.join(t))
4890
4889
4891 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4890 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4892 for trouble in ("unstable", "divergent", "bumped"):
4891 for trouble in ("unstable", "divergent", "bumped"):
4893 numtrouble = len(repo.revs(trouble + "()"))
4892 numtrouble = len(repo.revs(trouble + "()"))
4894 # We write all the possibilities to ease translation
4893 # We write all the possibilities to ease translation
4895 troublemsg = {
4894 troublemsg = {
4896 "unstable": _("unstable: %d changesets"),
4895 "unstable": _("unstable: %d changesets"),
4897 "divergent": _("divergent: %d changesets"),
4896 "divergent": _("divergent: %d changesets"),
4898 "bumped": _("bumped: %d changesets"),
4897 "bumped": _("bumped: %d changesets"),
4899 }
4898 }
4900 if numtrouble > 0:
4899 if numtrouble > 0:
4901 ui.status(troublemsg[trouble] % numtrouble + "\n")
4900 ui.status(troublemsg[trouble] % numtrouble + "\n")
4902
4901
4903 cmdutil.summaryhooks(ui, repo)
4902 cmdutil.summaryhooks(ui, repo)
4904
4903
4905 if opts.get('remote'):
4904 if opts.get('remote'):
4906 needsincoming, needsoutgoing = True, True
4905 needsincoming, needsoutgoing = True, True
4907 else:
4906 else:
4908 needsincoming, needsoutgoing = False, False
4907 needsincoming, needsoutgoing = False, False
4909 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4908 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4910 if i:
4909 if i:
4911 needsincoming = True
4910 needsincoming = True
4912 if o:
4911 if o:
4913 needsoutgoing = True
4912 needsoutgoing = True
4914 if not needsincoming and not needsoutgoing:
4913 if not needsincoming and not needsoutgoing:
4915 return
4914 return
4916
4915
4917 def getincoming():
4916 def getincoming():
4918 source, branches = hg.parseurl(ui.expandpath('default'))
4917 source, branches = hg.parseurl(ui.expandpath('default'))
4919 sbranch = branches[0]
4918 sbranch = branches[0]
4920 try:
4919 try:
4921 other = hg.peer(repo, {}, source)
4920 other = hg.peer(repo, {}, source)
4922 except error.RepoError:
4921 except error.RepoError:
4923 if opts.get('remote'):
4922 if opts.get('remote'):
4924 raise
4923 raise
4925 return source, sbranch, None, None, None
4924 return source, sbranch, None, None, None
4926 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4925 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4927 if revs:
4926 if revs:
4928 revs = [other.lookup(rev) for rev in revs]
4927 revs = [other.lookup(rev) for rev in revs]
4929 ui.debug('comparing with %s\n' % util.hidepassword(source))
4928 ui.debug('comparing with %s\n' % util.hidepassword(source))
4930 repo.ui.pushbuffer()
4929 repo.ui.pushbuffer()
4931 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4930 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4932 repo.ui.popbuffer()
4931 repo.ui.popbuffer()
4933 return source, sbranch, other, commoninc, commoninc[1]
4932 return source, sbranch, other, commoninc, commoninc[1]
4934
4933
4935 if needsincoming:
4934 if needsincoming:
4936 source, sbranch, sother, commoninc, incoming = getincoming()
4935 source, sbranch, sother, commoninc, incoming = getincoming()
4937 else:
4936 else:
4938 source = sbranch = sother = commoninc = incoming = None
4937 source = sbranch = sother = commoninc = incoming = None
4939
4938
4940 def getoutgoing():
4939 def getoutgoing():
4941 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4940 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4942 dbranch = branches[0]
4941 dbranch = branches[0]
4943 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4942 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4944 if source != dest:
4943 if source != dest:
4945 try:
4944 try:
4946 dother = hg.peer(repo, {}, dest)
4945 dother = hg.peer(repo, {}, dest)
4947 except error.RepoError:
4946 except error.RepoError:
4948 if opts.get('remote'):
4947 if opts.get('remote'):
4949 raise
4948 raise
4950 return dest, dbranch, None, None
4949 return dest, dbranch, None, None
4951 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4950 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4952 elif sother is None:
4951 elif sother is None:
4953 # there is no explicit destination peer, but source one is invalid
4952 # there is no explicit destination peer, but source one is invalid
4954 return dest, dbranch, None, None
4953 return dest, dbranch, None, None
4955 else:
4954 else:
4956 dother = sother
4955 dother = sother
4957 if (source != dest or (sbranch is not None and sbranch != dbranch)):
4956 if (source != dest or (sbranch is not None and sbranch != dbranch)):
4958 common = None
4957 common = None
4959 else:
4958 else:
4960 common = commoninc
4959 common = commoninc
4961 if revs:
4960 if revs:
4962 revs = [repo.lookup(rev) for rev in revs]
4961 revs = [repo.lookup(rev) for rev in revs]
4963 repo.ui.pushbuffer()
4962 repo.ui.pushbuffer()
4964 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
4963 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
4965 commoninc=common)
4964 commoninc=common)
4966 repo.ui.popbuffer()
4965 repo.ui.popbuffer()
4967 return dest, dbranch, dother, outgoing
4966 return dest, dbranch, dother, outgoing
4968
4967
4969 if needsoutgoing:
4968 if needsoutgoing:
4970 dest, dbranch, dother, outgoing = getoutgoing()
4969 dest, dbranch, dother, outgoing = getoutgoing()
4971 else:
4970 else:
4972 dest = dbranch = dother = outgoing = None
4971 dest = dbranch = dother = outgoing = None
4973
4972
4974 if opts.get('remote'):
4973 if opts.get('remote'):
4975 t = []
4974 t = []
4976 if incoming:
4975 if incoming:
4977 t.append(_('1 or more incoming'))
4976 t.append(_('1 or more incoming'))
4978 o = outgoing.missing
4977 o = outgoing.missing
4979 if o:
4978 if o:
4980 t.append(_('%d outgoing') % len(o))
4979 t.append(_('%d outgoing') % len(o))
4981 other = dother or sother
4980 other = dother or sother
4982 if 'bookmarks' in other.listkeys('namespaces'):
4981 if 'bookmarks' in other.listkeys('namespaces'):
4983 counts = bookmarks.summary(repo, other)
4982 counts = bookmarks.summary(repo, other)
4984 if counts[0] > 0:
4983 if counts[0] > 0:
4985 t.append(_('%d incoming bookmarks') % counts[0])
4984 t.append(_('%d incoming bookmarks') % counts[0])
4986 if counts[1] > 0:
4985 if counts[1] > 0:
4987 t.append(_('%d outgoing bookmarks') % counts[1])
4986 t.append(_('%d outgoing bookmarks') % counts[1])
4988
4987
4989 if t:
4988 if t:
4990 # i18n: column positioning for "hg summary"
4989 # i18n: column positioning for "hg summary"
4991 ui.write(_('remote: %s\n') % (', '.join(t)))
4990 ui.write(_('remote: %s\n') % (', '.join(t)))
4992 else:
4991 else:
4993 # i18n: column positioning for "hg summary"
4992 # i18n: column positioning for "hg summary"
4994 ui.status(_('remote: (synced)\n'))
4993 ui.status(_('remote: (synced)\n'))
4995
4994
4996 cmdutil.summaryremotehooks(ui, repo, opts,
4995 cmdutil.summaryremotehooks(ui, repo, opts,
4997 ((source, sbranch, sother, commoninc),
4996 ((source, sbranch, sother, commoninc),
4998 (dest, dbranch, dother, outgoing)))
4997 (dest, dbranch, dother, outgoing)))
4999
4998
5000 @command('tag',
4999 @command('tag',
5001 [('f', 'force', None, _('force tag')),
5000 [('f', 'force', None, _('force tag')),
5002 ('l', 'local', None, _('make the tag local')),
5001 ('l', 'local', None, _('make the tag local')),
5003 ('r', 'rev', '', _('revision to tag'), _('REV')),
5002 ('r', 'rev', '', _('revision to tag'), _('REV')),
5004 ('', 'remove', None, _('remove a tag')),
5003 ('', 'remove', None, _('remove a tag')),
5005 # -l/--local is already there, commitopts cannot be used
5004 # -l/--local is already there, commitopts cannot be used
5006 ('e', 'edit', None, _('invoke editor on commit messages')),
5005 ('e', 'edit', None, _('invoke editor on commit messages')),
5007 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5006 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5008 ] + commitopts2,
5007 ] + commitopts2,
5009 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5008 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5010 def tag(ui, repo, name1, *names, **opts):
5009 def tag(ui, repo, name1, *names, **opts):
5011 """add one or more tags for the current or given revision
5010 """add one or more tags for the current or given revision
5012
5011
5013 Name a particular revision using <name>.
5012 Name a particular revision using <name>.
5014
5013
5015 Tags are used to name particular revisions of the repository and are
5014 Tags are used to name particular revisions of the repository and are
5016 very useful to compare different revisions, to go back to significant
5015 very useful to compare different revisions, to go back to significant
5017 earlier versions or to mark branch points as releases, etc. Changing
5016 earlier versions or to mark branch points as releases, etc. Changing
5018 an existing tag is normally disallowed; use -f/--force to override.
5017 an existing tag is normally disallowed; use -f/--force to override.
5019
5018
5020 If no revision is given, the parent of the working directory is
5019 If no revision is given, the parent of the working directory is
5021 used.
5020 used.
5022
5021
5023 To facilitate version control, distribution, and merging of tags,
5022 To facilitate version control, distribution, and merging of tags,
5024 they are stored as a file named ".hgtags" which is managed similarly
5023 they are stored as a file named ".hgtags" which is managed similarly
5025 to other project files and can be hand-edited if necessary. This
5024 to other project files and can be hand-edited if necessary. This
5026 also means that tagging creates a new commit. The file
5025 also means that tagging creates a new commit. The file
5027 ".hg/localtags" is used for local tags (not shared among
5026 ".hg/localtags" is used for local tags (not shared among
5028 repositories).
5027 repositories).
5029
5028
5030 Tag commits are usually made at the head of a branch. If the parent
5029 Tag commits are usually made at the head of a branch. If the parent
5031 of the working directory is not a branch head, :hg:`tag` aborts; use
5030 of the working directory is not a branch head, :hg:`tag` aborts; use
5032 -f/--force to force the tag commit to be based on a non-head
5031 -f/--force to force the tag commit to be based on a non-head
5033 changeset.
5032 changeset.
5034
5033
5035 See :hg:`help dates` for a list of formats valid for -d/--date.
5034 See :hg:`help dates` for a list of formats valid for -d/--date.
5036
5035
5037 Since tag names have priority over branch names during revision
5036 Since tag names have priority over branch names during revision
5038 lookup, using an existing branch name as a tag name is discouraged.
5037 lookup, using an existing branch name as a tag name is discouraged.
5039
5038
5040 Returns 0 on success.
5039 Returns 0 on success.
5041 """
5040 """
5042 opts = pycompat.byteskwargs(opts)
5041 opts = pycompat.byteskwargs(opts)
5043 wlock = lock = None
5042 wlock = lock = None
5044 try:
5043 try:
5045 wlock = repo.wlock()
5044 wlock = repo.wlock()
5046 lock = repo.lock()
5045 lock = repo.lock()
5047 rev_ = "."
5046 rev_ = "."
5048 names = [t.strip() for t in (name1,) + names]
5047 names = [t.strip() for t in (name1,) + names]
5049 if len(names) != len(set(names)):
5048 if len(names) != len(set(names)):
5050 raise error.Abort(_('tag names must be unique'))
5049 raise error.Abort(_('tag names must be unique'))
5051 for n in names:
5050 for n in names:
5052 scmutil.checknewlabel(repo, n, 'tag')
5051 scmutil.checknewlabel(repo, n, 'tag')
5053 if not n:
5052 if not n:
5054 raise error.Abort(_('tag names cannot consist entirely of '
5053 raise error.Abort(_('tag names cannot consist entirely of '
5055 'whitespace'))
5054 'whitespace'))
5056 if opts.get('rev') and opts.get('remove'):
5055 if opts.get('rev') and opts.get('remove'):
5057 raise error.Abort(_("--rev and --remove are incompatible"))
5056 raise error.Abort(_("--rev and --remove are incompatible"))
5058 if opts.get('rev'):
5057 if opts.get('rev'):
5059 rev_ = opts['rev']
5058 rev_ = opts['rev']
5060 message = opts.get('message')
5059 message = opts.get('message')
5061 if opts.get('remove'):
5060 if opts.get('remove'):
5062 if opts.get('local'):
5061 if opts.get('local'):
5063 expectedtype = 'local'
5062 expectedtype = 'local'
5064 else:
5063 else:
5065 expectedtype = 'global'
5064 expectedtype = 'global'
5066
5065
5067 for n in names:
5066 for n in names:
5068 if not repo.tagtype(n):
5067 if not repo.tagtype(n):
5069 raise error.Abort(_("tag '%s' does not exist") % n)
5068 raise error.Abort(_("tag '%s' does not exist") % n)
5070 if repo.tagtype(n) != expectedtype:
5069 if repo.tagtype(n) != expectedtype:
5071 if expectedtype == 'global':
5070 if expectedtype == 'global':
5072 raise error.Abort(_("tag '%s' is not a global tag") % n)
5071 raise error.Abort(_("tag '%s' is not a global tag") % n)
5073 else:
5072 else:
5074 raise error.Abort(_("tag '%s' is not a local tag") % n)
5073 raise error.Abort(_("tag '%s' is not a local tag") % n)
5075 rev_ = 'null'
5074 rev_ = 'null'
5076 if not message:
5075 if not message:
5077 # we don't translate commit messages
5076 # we don't translate commit messages
5078 message = 'Removed tag %s' % ', '.join(names)
5077 message = 'Removed tag %s' % ', '.join(names)
5079 elif not opts.get('force'):
5078 elif not opts.get('force'):
5080 for n in names:
5079 for n in names:
5081 if n in repo.tags():
5080 if n in repo.tags():
5082 raise error.Abort(_("tag '%s' already exists "
5081 raise error.Abort(_("tag '%s' already exists "
5083 "(use -f to force)") % n)
5082 "(use -f to force)") % n)
5084 if not opts.get('local'):
5083 if not opts.get('local'):
5085 p1, p2 = repo.dirstate.parents()
5084 p1, p2 = repo.dirstate.parents()
5086 if p2 != nullid:
5085 if p2 != nullid:
5087 raise error.Abort(_('uncommitted merge'))
5086 raise error.Abort(_('uncommitted merge'))
5088 bheads = repo.branchheads()
5087 bheads = repo.branchheads()
5089 if not opts.get('force') and bheads and p1 not in bheads:
5088 if not opts.get('force') and bheads and p1 not in bheads:
5090 raise error.Abort(_('working directory is not at a branch head '
5089 raise error.Abort(_('working directory is not at a branch head '
5091 '(use -f to force)'))
5090 '(use -f to force)'))
5092 r = scmutil.revsingle(repo, rev_).node()
5091 r = scmutil.revsingle(repo, rev_).node()
5093
5092
5094 if not message:
5093 if not message:
5095 # we don't translate commit messages
5094 # we don't translate commit messages
5096 message = ('Added tag %s for changeset %s' %
5095 message = ('Added tag %s for changeset %s' %
5097 (', '.join(names), short(r)))
5096 (', '.join(names), short(r)))
5098
5097
5099 date = opts.get('date')
5098 date = opts.get('date')
5100 if date:
5099 if date:
5101 date = util.parsedate(date)
5100 date = util.parsedate(date)
5102
5101
5103 if opts.get('remove'):
5102 if opts.get('remove'):
5104 editform = 'tag.remove'
5103 editform = 'tag.remove'
5105 else:
5104 else:
5106 editform = 'tag.add'
5105 editform = 'tag.add'
5107 editor = cmdutil.getcommiteditor(editform=editform,
5106 editor = cmdutil.getcommiteditor(editform=editform,
5108 **pycompat.strkwargs(opts))
5107 **pycompat.strkwargs(opts))
5109
5108
5110 # don't allow tagging the null rev
5109 # don't allow tagging the null rev
5111 if (not opts.get('remove') and
5110 if (not opts.get('remove') and
5112 scmutil.revsingle(repo, rev_).rev() == nullrev):
5111 scmutil.revsingle(repo, rev_).rev() == nullrev):
5113 raise error.Abort(_("cannot tag null revision"))
5112 raise error.Abort(_("cannot tag null revision"))
5114
5113
5115 tagsmod.tag(repo, names, r, message, opts.get('local'),
5114 tagsmod.tag(repo, names, r, message, opts.get('local'),
5116 opts.get('user'), date, editor=editor)
5115 opts.get('user'), date, editor=editor)
5117 finally:
5116 finally:
5118 release(lock, wlock)
5117 release(lock, wlock)
5119
5118
5120 @command('tags', formatteropts, '')
5119 @command('tags', formatteropts, '')
5121 def tags(ui, repo, **opts):
5120 def tags(ui, repo, **opts):
5122 """list repository tags
5121 """list repository tags
5123
5122
5124 This lists both regular and local tags. When the -v/--verbose
5123 This lists both regular and local tags. When the -v/--verbose
5125 switch is used, a third column "local" is printed for local tags.
5124 switch is used, a third column "local" is printed for local tags.
5126 When the -q/--quiet switch is used, only the tag name is printed.
5125 When the -q/--quiet switch is used, only the tag name is printed.
5127
5126
5128 Returns 0 on success.
5127 Returns 0 on success.
5129 """
5128 """
5130
5129
5131 opts = pycompat.byteskwargs(opts)
5130 opts = pycompat.byteskwargs(opts)
5132 ui.pager('tags')
5131 ui.pager('tags')
5133 fm = ui.formatter('tags', opts)
5132 fm = ui.formatter('tags', opts)
5134 hexfunc = fm.hexfunc
5133 hexfunc = fm.hexfunc
5135 tagtype = ""
5134 tagtype = ""
5136
5135
5137 for t, n in reversed(repo.tagslist()):
5136 for t, n in reversed(repo.tagslist()):
5138 hn = hexfunc(n)
5137 hn = hexfunc(n)
5139 label = 'tags.normal'
5138 label = 'tags.normal'
5140 tagtype = ''
5139 tagtype = ''
5141 if repo.tagtype(t) == 'local':
5140 if repo.tagtype(t) == 'local':
5142 label = 'tags.local'
5141 label = 'tags.local'
5143 tagtype = 'local'
5142 tagtype = 'local'
5144
5143
5145 fm.startitem()
5144 fm.startitem()
5146 fm.write('tag', '%s', t, label=label)
5145 fm.write('tag', '%s', t, label=label)
5147 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5146 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5148 fm.condwrite(not ui.quiet, 'rev node', fmt,
5147 fm.condwrite(not ui.quiet, 'rev node', fmt,
5149 repo.changelog.rev(n), hn, label=label)
5148 repo.changelog.rev(n), hn, label=label)
5150 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5149 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5151 tagtype, label=label)
5150 tagtype, label=label)
5152 fm.plain('\n')
5151 fm.plain('\n')
5153 fm.end()
5152 fm.end()
5154
5153
5155 @command('tip',
5154 @command('tip',
5156 [('p', 'patch', None, _('show patch')),
5155 [('p', 'patch', None, _('show patch')),
5157 ('g', 'git', None, _('use git extended diff format')),
5156 ('g', 'git', None, _('use git extended diff format')),
5158 ] + templateopts,
5157 ] + templateopts,
5159 _('[-p] [-g]'))
5158 _('[-p] [-g]'))
5160 def tip(ui, repo, **opts):
5159 def tip(ui, repo, **opts):
5161 """show the tip revision (DEPRECATED)
5160 """show the tip revision (DEPRECATED)
5162
5161
5163 The tip revision (usually just called the tip) is the changeset
5162 The tip revision (usually just called the tip) is the changeset
5164 most recently added to the repository (and therefore the most
5163 most recently added to the repository (and therefore the most
5165 recently changed head).
5164 recently changed head).
5166
5165
5167 If you have just made a commit, that commit will be the tip. If
5166 If you have just made a commit, that commit will be the tip. If
5168 you have just pulled changes from another repository, the tip of
5167 you have just pulled changes from another repository, the tip of
5169 that repository becomes the current tip. The "tip" tag is special
5168 that repository becomes the current tip. The "tip" tag is special
5170 and cannot be renamed or assigned to a different changeset.
5169 and cannot be renamed or assigned to a different changeset.
5171
5170
5172 This command is deprecated, please use :hg:`heads` instead.
5171 This command is deprecated, please use :hg:`heads` instead.
5173
5172
5174 Returns 0 on success.
5173 Returns 0 on success.
5175 """
5174 """
5176 opts = pycompat.byteskwargs(opts)
5175 opts = pycompat.byteskwargs(opts)
5177 displayer = cmdutil.show_changeset(ui, repo, opts)
5176 displayer = cmdutil.show_changeset(ui, repo, opts)
5178 displayer.show(repo['tip'])
5177 displayer.show(repo['tip'])
5179 displayer.close()
5178 displayer.close()
5180
5179
5181 @command('unbundle',
5180 @command('unbundle',
5182 [('u', 'update', None,
5181 [('u', 'update', None,
5183 _('update to new branch head if changesets were unbundled'))],
5182 _('update to new branch head if changesets were unbundled'))],
5184 _('[-u] FILE...'))
5183 _('[-u] FILE...'))
5185 def unbundle(ui, repo, fname1, *fnames, **opts):
5184 def unbundle(ui, repo, fname1, *fnames, **opts):
5186 """apply one or more bundle files
5185 """apply one or more bundle files
5187
5186
5188 Apply one or more bundle files generated by :hg:`bundle`.
5187 Apply one or more bundle files generated by :hg:`bundle`.
5189
5188
5190 Returns 0 on success, 1 if an update has unresolved files.
5189 Returns 0 on success, 1 if an update has unresolved files.
5191 """
5190 """
5192 fnames = (fname1,) + fnames
5191 fnames = (fname1,) + fnames
5193
5192
5194 with repo.lock():
5193 with repo.lock():
5195 for fname in fnames:
5194 for fname in fnames:
5196 f = hg.openpath(ui, fname)
5195 f = hg.openpath(ui, fname)
5197 gen = exchange.readbundle(ui, f, fname)
5196 gen = exchange.readbundle(ui, f, fname)
5198 if isinstance(gen, streamclone.streamcloneapplier):
5197 if isinstance(gen, streamclone.streamcloneapplier):
5199 raise error.Abort(
5198 raise error.Abort(
5200 _('packed bundles cannot be applied with '
5199 _('packed bundles cannot be applied with '
5201 '"hg unbundle"'),
5200 '"hg unbundle"'),
5202 hint=_('use "hg debugapplystreamclonebundle"'))
5201 hint=_('use "hg debugapplystreamclonebundle"'))
5203 url = 'bundle:' + fname
5202 url = 'bundle:' + fname
5204 if isinstance(gen, bundle2.unbundle20):
5203 if isinstance(gen, bundle2.unbundle20):
5205 with repo.transaction('unbundle') as tr:
5204 with repo.transaction('unbundle') as tr:
5206 try:
5205 try:
5207 op = bundle2.applybundle(repo, gen, tr,
5206 op = bundle2.applybundle(repo, gen, tr,
5208 source='unbundle',
5207 source='unbundle',
5209 url=url)
5208 url=url)
5210 except error.BundleUnknownFeatureError as exc:
5209 except error.BundleUnknownFeatureError as exc:
5211 raise error.Abort(
5210 raise error.Abort(
5212 _('%s: unknown bundle feature, %s') % (fname, exc),
5211 _('%s: unknown bundle feature, %s') % (fname, exc),
5213 hint=_("see https://mercurial-scm.org/"
5212 hint=_("see https://mercurial-scm.org/"
5214 "wiki/BundleFeature for more "
5213 "wiki/BundleFeature for more "
5215 "information"))
5214 "information"))
5216 changes = [r.get('return', 0)
5215 changes = [r.get('return', 0)
5217 for r in op.records['changegroup']]
5216 for r in op.records['changegroup']]
5218 modheads = changegroup.combineresults(changes)
5217 modheads = changegroup.combineresults(changes)
5219 else:
5218 else:
5220 txnname = 'unbundle\n%s' % util.hidepassword(url)
5219 txnname = 'unbundle\n%s' % util.hidepassword(url)
5221 with repo.transaction(txnname) as tr:
5220 with repo.transaction(txnname) as tr:
5222 modheads = gen.apply(repo, tr, 'unbundle', url)
5221 modheads = gen.apply(repo, tr, 'unbundle', url)
5223
5222
5224 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5223 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5225
5224
5226 @command('^update|up|checkout|co',
5225 @command('^update|up|checkout|co',
5227 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5226 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5228 ('c', 'check', None, _('require clean working directory')),
5227 ('c', 'check', None, _('require clean working directory')),
5229 ('m', 'merge', None, _('merge uncommitted changes')),
5228 ('m', 'merge', None, _('merge uncommitted changes')),
5230 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5229 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5231 ('r', 'rev', '', _('revision'), _('REV'))
5230 ('r', 'rev', '', _('revision'), _('REV'))
5232 ] + mergetoolopts,
5231 ] + mergetoolopts,
5233 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5232 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5234 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5233 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5235 merge=None, tool=None):
5234 merge=None, tool=None):
5236 """update working directory (or switch revisions)
5235 """update working directory (or switch revisions)
5237
5236
5238 Update the repository's working directory to the specified
5237 Update the repository's working directory to the specified
5239 changeset. If no changeset is specified, update to the tip of the
5238 changeset. If no changeset is specified, update to the tip of the
5240 current named branch and move the active bookmark (see :hg:`help
5239 current named branch and move the active bookmark (see :hg:`help
5241 bookmarks`).
5240 bookmarks`).
5242
5241
5243 Update sets the working directory's parent revision to the specified
5242 Update sets the working directory's parent revision to the specified
5244 changeset (see :hg:`help parents`).
5243 changeset (see :hg:`help parents`).
5245
5244
5246 If the changeset is not a descendant or ancestor of the working
5245 If the changeset is not a descendant or ancestor of the working
5247 directory's parent and there are uncommitted changes, the update is
5246 directory's parent and there are uncommitted changes, the update is
5248 aborted. With the -c/--check option, the working directory is checked
5247 aborted. With the -c/--check option, the working directory is checked
5249 for uncommitted changes; if none are found, the working directory is
5248 for uncommitted changes; if none are found, the working directory is
5250 updated to the specified changeset.
5249 updated to the specified changeset.
5251
5250
5252 .. container:: verbose
5251 .. container:: verbose
5253
5252
5254 The -C/--clean, -c/--check, and -m/--merge options control what
5253 The -C/--clean, -c/--check, and -m/--merge options control what
5255 happens if the working directory contains uncommitted changes.
5254 happens if the working directory contains uncommitted changes.
5256 At most of one of them can be specified.
5255 At most of one of them can be specified.
5257
5256
5258 1. If no option is specified, and if
5257 1. If no option is specified, and if
5259 the requested changeset is an ancestor or descendant of
5258 the requested changeset is an ancestor or descendant of
5260 the working directory's parent, the uncommitted changes
5259 the working directory's parent, the uncommitted changes
5261 are merged into the requested changeset and the merged
5260 are merged into the requested changeset and the merged
5262 result is left uncommitted. If the requested changeset is
5261 result is left uncommitted. If the requested changeset is
5263 not an ancestor or descendant (that is, it is on another
5262 not an ancestor or descendant (that is, it is on another
5264 branch), the update is aborted and the uncommitted changes
5263 branch), the update is aborted and the uncommitted changes
5265 are preserved.
5264 are preserved.
5266
5265
5267 2. With the -m/--merge option, the update is allowed even if the
5266 2. With the -m/--merge option, the update is allowed even if the
5268 requested changeset is not an ancestor or descendant of
5267 requested changeset is not an ancestor or descendant of
5269 the working directory's parent.
5268 the working directory's parent.
5270
5269
5271 3. With the -c/--check option, the update is aborted and the
5270 3. With the -c/--check option, the update is aborted and the
5272 uncommitted changes are preserved.
5271 uncommitted changes are preserved.
5273
5272
5274 4. With the -C/--clean option, uncommitted changes are discarded and
5273 4. With the -C/--clean option, uncommitted changes are discarded and
5275 the working directory is updated to the requested changeset.
5274 the working directory is updated to the requested changeset.
5276
5275
5277 To cancel an uncommitted merge (and lose your changes), use
5276 To cancel an uncommitted merge (and lose your changes), use
5278 :hg:`update --clean .`.
5277 :hg:`update --clean .`.
5279
5278
5280 Use null as the changeset to remove the working directory (like
5279 Use null as the changeset to remove the working directory (like
5281 :hg:`clone -U`).
5280 :hg:`clone -U`).
5282
5281
5283 If you want to revert just one file to an older revision, use
5282 If you want to revert just one file to an older revision, use
5284 :hg:`revert [-r REV] NAME`.
5283 :hg:`revert [-r REV] NAME`.
5285
5284
5286 See :hg:`help dates` for a list of formats valid for -d/--date.
5285 See :hg:`help dates` for a list of formats valid for -d/--date.
5287
5286
5288 Returns 0 on success, 1 if there are unresolved files.
5287 Returns 0 on success, 1 if there are unresolved files.
5289 """
5288 """
5290 if rev and node:
5289 if rev and node:
5291 raise error.Abort(_("please specify just one revision"))
5290 raise error.Abort(_("please specify just one revision"))
5292
5291
5293 if ui.configbool('commands', 'update.requiredest'):
5292 if ui.configbool('commands', 'update.requiredest'):
5294 if not node and not rev and not date:
5293 if not node and not rev and not date:
5295 raise error.Abort(_('you must specify a destination'),
5294 raise error.Abort(_('you must specify a destination'),
5296 hint=_('for example: hg update ".::"'))
5295 hint=_('for example: hg update ".::"'))
5297
5296
5298 if rev is None or rev == '':
5297 if rev is None or rev == '':
5299 rev = node
5298 rev = node
5300
5299
5301 if date and rev is not None:
5300 if date and rev is not None:
5302 raise error.Abort(_("you can't specify a revision and a date"))
5301 raise error.Abort(_("you can't specify a revision and a date"))
5303
5302
5304 if len([x for x in (clean, check, merge) if x]) > 1:
5303 if len([x for x in (clean, check, merge) if x]) > 1:
5305 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5304 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5306 "or -m/merge"))
5305 "or -m/merge"))
5307
5306
5308 updatecheck = None
5307 updatecheck = None
5309 if check:
5308 if check:
5310 updatecheck = 'abort'
5309 updatecheck = 'abort'
5311 elif merge:
5310 elif merge:
5312 updatecheck = 'none'
5311 updatecheck = 'none'
5313
5312
5314 with repo.wlock():
5313 with repo.wlock():
5315 cmdutil.clearunfinished(repo)
5314 cmdutil.clearunfinished(repo)
5316
5315
5317 if date:
5316 if date:
5318 rev = cmdutil.finddate(ui, repo, date)
5317 rev = cmdutil.finddate(ui, repo, date)
5319
5318
5320 # if we defined a bookmark, we have to remember the original name
5319 # if we defined a bookmark, we have to remember the original name
5321 brev = rev
5320 brev = rev
5322 rev = scmutil.revsingle(repo, rev, rev).rev()
5321 rev = scmutil.revsingle(repo, rev, rev).rev()
5323
5322
5324 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5323 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5325
5324
5326 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5325 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5327 updatecheck=updatecheck)
5326 updatecheck=updatecheck)
5328
5327
5329 @command('verify', [])
5328 @command('verify', [])
5330 def verify(ui, repo):
5329 def verify(ui, repo):
5331 """verify the integrity of the repository
5330 """verify the integrity of the repository
5332
5331
5333 Verify the integrity of the current repository.
5332 Verify the integrity of the current repository.
5334
5333
5335 This will perform an extensive check of the repository's
5334 This will perform an extensive check of the repository's
5336 integrity, validating the hashes and checksums of each entry in
5335 integrity, validating the hashes and checksums of each entry in
5337 the changelog, manifest, and tracked files, as well as the
5336 the changelog, manifest, and tracked files, as well as the
5338 integrity of their crosslinks and indices.
5337 integrity of their crosslinks and indices.
5339
5338
5340 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5339 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5341 for more information about recovery from corruption of the
5340 for more information about recovery from corruption of the
5342 repository.
5341 repository.
5343
5342
5344 Returns 0 on success, 1 if errors are encountered.
5343 Returns 0 on success, 1 if errors are encountered.
5345 """
5344 """
5346 return hg.verify(repo)
5345 return hg.verify(repo)
5347
5346
5348 @command('version', [] + formatteropts, norepo=True)
5347 @command('version', [] + formatteropts, norepo=True)
5349 def version_(ui, **opts):
5348 def version_(ui, **opts):
5350 """output version and copyright information"""
5349 """output version and copyright information"""
5351 opts = pycompat.byteskwargs(opts)
5350 opts = pycompat.byteskwargs(opts)
5352 if ui.verbose:
5351 if ui.verbose:
5353 ui.pager('version')
5352 ui.pager('version')
5354 fm = ui.formatter("version", opts)
5353 fm = ui.formatter("version", opts)
5355 fm.startitem()
5354 fm.startitem()
5356 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5355 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5357 util.version())
5356 util.version())
5358 license = _(
5357 license = _(
5359 "(see https://mercurial-scm.org for more information)\n"
5358 "(see https://mercurial-scm.org for more information)\n"
5360 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5359 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5361 "This is free software; see the source for copying conditions. "
5360 "This is free software; see the source for copying conditions. "
5362 "There is NO\nwarranty; "
5361 "There is NO\nwarranty; "
5363 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5362 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5364 )
5363 )
5365 if not ui.quiet:
5364 if not ui.quiet:
5366 fm.plain(license)
5365 fm.plain(license)
5367
5366
5368 if ui.verbose:
5367 if ui.verbose:
5369 fm.plain(_("\nEnabled extensions:\n\n"))
5368 fm.plain(_("\nEnabled extensions:\n\n"))
5370 # format names and versions into columns
5369 # format names and versions into columns
5371 names = []
5370 names = []
5372 vers = []
5371 vers = []
5373 isinternals = []
5372 isinternals = []
5374 for name, module in extensions.extensions():
5373 for name, module in extensions.extensions():
5375 names.append(name)
5374 names.append(name)
5376 vers.append(extensions.moduleversion(module) or None)
5375 vers.append(extensions.moduleversion(module) or None)
5377 isinternals.append(extensions.ismoduleinternal(module))
5376 isinternals.append(extensions.ismoduleinternal(module))
5378 fn = fm.nested("extensions")
5377 fn = fm.nested("extensions")
5379 if names:
5378 if names:
5380 namefmt = " %%-%ds " % max(len(n) for n in names)
5379 namefmt = " %%-%ds " % max(len(n) for n in names)
5381 places = [_("external"), _("internal")]
5380 places = [_("external"), _("internal")]
5382 for n, v, p in zip(names, vers, isinternals):
5381 for n, v, p in zip(names, vers, isinternals):
5383 fn.startitem()
5382 fn.startitem()
5384 fn.condwrite(ui.verbose, "name", namefmt, n)
5383 fn.condwrite(ui.verbose, "name", namefmt, n)
5385 if ui.verbose:
5384 if ui.verbose:
5386 fn.plain("%s " % places[p])
5385 fn.plain("%s " % places[p])
5387 fn.data(bundled=p)
5386 fn.data(bundled=p)
5388 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5387 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5389 if ui.verbose:
5388 if ui.verbose:
5390 fn.plain("\n")
5389 fn.plain("\n")
5391 fn.end()
5390 fn.end()
5392 fm.end()
5391 fm.end()
5393
5392
5394 def loadcmdtable(ui, name, cmdtable):
5393 def loadcmdtable(ui, name, cmdtable):
5395 """Load command functions from specified cmdtable
5394 """Load command functions from specified cmdtable
5396 """
5395 """
5397 overrides = [cmd for cmd in cmdtable if cmd in table]
5396 overrides = [cmd for cmd in cmdtable if cmd in table]
5398 if overrides:
5397 if overrides:
5399 ui.warn(_("extension '%s' overrides commands: %s\n")
5398 ui.warn(_("extension '%s' overrides commands: %s\n")
5400 % (name, " ".join(overrides)))
5399 % (name, " ".join(overrides)))
5401 table.update(cmdtable)
5400 table.update(cmdtable)
@@ -1,709 +1,709 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 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 from .i18n import _
10 from .i18n import _
11 from .node import (
11 from .node import (
12 hex,
12 hex,
13 nullid,
13 nullid,
14 short,
14 short,
15 )
15 )
16
16
17 from . import (
17 from . import (
18 encoding,
18 encoding,
19 error,
19 error,
20 hbisect,
20 hbisect,
21 obsutil,
21 obsutil,
22 patch,
22 patch,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 scmutil,
25 scmutil,
26 util,
26 util,
27 )
27 )
28
28
29 class _hybrid(object):
29 class _hybrid(object):
30 """Wrapper for list or dict to support legacy template
30 """Wrapper for list or dict to support legacy template
31
31
32 This class allows us to handle both:
32 This class allows us to handle both:
33 - "{files}" (legacy command-line-specific list hack) and
33 - "{files}" (legacy command-line-specific list hack) and
34 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
34 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
35 and to access raw values:
35 and to access raw values:
36 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
36 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
37 - "{get(extras, key)}"
37 - "{get(extras, key)}"
38 - "{files|json}"
38 - "{files|json}"
39 """
39 """
40
40
41 def __init__(self, gen, values, makemap, joinfmt):
41 def __init__(self, gen, values, makemap, joinfmt):
42 if gen is not None:
42 if gen is not None:
43 self.gen = gen
43 self.gen = gen
44 self._values = values
44 self._values = values
45 self._makemap = makemap
45 self._makemap = makemap
46 self.joinfmt = joinfmt
46 self.joinfmt = joinfmt
47 @util.propertycache
47 @util.propertycache
48 def gen(self):
48 def gen(self):
49 return self._defaultgen()
49 return self._defaultgen()
50 def _defaultgen(self):
50 def _defaultgen(self):
51 """Generator to stringify this as {join(self, ' ')}"""
51 """Generator to stringify this as {join(self, ' ')}"""
52 for i, d in enumerate(self.itermaps()):
52 for i, d in enumerate(self.itermaps()):
53 if i > 0:
53 if i > 0:
54 yield ' '
54 yield ' '
55 yield self.joinfmt(d)
55 yield self.joinfmt(d)
56 def itermaps(self):
56 def itermaps(self):
57 makemap = self._makemap
57 makemap = self._makemap
58 for x in self._values:
58 for x in self._values:
59 yield makemap(x)
59 yield makemap(x)
60 def __contains__(self, x):
60 def __contains__(self, x):
61 return x in self._values
61 return x in self._values
62 def __len__(self):
62 def __len__(self):
63 return len(self._values)
63 return len(self._values)
64 def __iter__(self):
64 def __iter__(self):
65 return iter(self._values)
65 return iter(self._values)
66 def __getattr__(self, name):
66 def __getattr__(self, name):
67 if name not in ('get', 'items', 'iteritems', 'iterkeys', 'itervalues',
67 if name not in ('get', 'items', 'iteritems', 'iterkeys', 'itervalues',
68 'keys', 'values'):
68 'keys', 'values'):
69 raise AttributeError(name)
69 raise AttributeError(name)
70 return getattr(self._values, name)
70 return getattr(self._values, name)
71
71
72 def hybriddict(data, key='key', value='value', fmt='%s=%s', gen=None):
72 def hybriddict(data, key='key', value='value', fmt='%s=%s', gen=None):
73 """Wrap data to support both dict-like and string-like operations"""
73 """Wrap data to support both dict-like and string-like operations"""
74 return _hybrid(gen, data, lambda k: {key: k, value: data[k]},
74 return _hybrid(gen, data, lambda k: {key: k, value: data[k]},
75 lambda d: fmt % (d[key], d[value]))
75 lambda d: fmt % (d[key], d[value]))
76
76
77 def hybridlist(data, name, fmt='%s', gen=None):
77 def hybridlist(data, name, fmt='%s', gen=None):
78 """Wrap data to support both list-like and string-like operations"""
78 """Wrap data to support both list-like and string-like operations"""
79 return _hybrid(gen, data, lambda x: {name: x}, lambda d: fmt % d[name])
79 return _hybrid(gen, data, lambda x: {name: x}, lambda d: fmt % d[name])
80
80
81 def unwraphybrid(thing):
81 def unwraphybrid(thing):
82 """Return an object which can be stringified possibly by using a legacy
82 """Return an object which can be stringified possibly by using a legacy
83 template"""
83 template"""
84 if not util.safehasattr(thing, 'gen'):
84 if not util.safehasattr(thing, 'gen'):
85 return thing
85 return thing
86 return thing.gen
86 return thing.gen
87
87
88 def showdict(name, data, mapping, plural=None, key='key', value='value',
88 def showdict(name, data, mapping, plural=None, key='key', value='value',
89 fmt='%s=%s', separator=' '):
89 fmt='%s=%s', separator=' '):
90 c = [{key: k, value: v} for k, v in data.iteritems()]
90 c = [{key: k, value: v} for k, v in data.iteritems()]
91 f = _showlist(name, c, mapping, plural, separator)
91 f = _showlist(name, c, mapping, plural, separator)
92 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
92 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
93
93
94 def showlist(name, values, mapping, plural=None, element=None, separator=' '):
94 def showlist(name, values, mapping, plural=None, element=None, separator=' '):
95 if not element:
95 if not element:
96 element = name
96 element = name
97 f = _showlist(name, values, mapping, plural, separator)
97 f = _showlist(name, values, mapping, plural, separator)
98 return hybridlist(values, name=element, gen=f)
98 return hybridlist(values, name=element, gen=f)
99
99
100 def _showlist(name, values, mapping, plural=None, separator=' '):
100 def _showlist(name, values, mapping, plural=None, separator=' '):
101 '''expand set of values.
101 '''expand set of values.
102 name is name of key in template map.
102 name is name of key in template map.
103 values is list of strings or dicts.
103 values is list of strings or dicts.
104 plural is plural of name, if not simply name + 's'.
104 plural is plural of name, if not simply name + 's'.
105 separator is used to join values as a string
105 separator is used to join values as a string
106
106
107 expansion works like this, given name 'foo'.
107 expansion works like this, given name 'foo'.
108
108
109 if values is empty, expand 'no_foos'.
109 if values is empty, expand 'no_foos'.
110
110
111 if 'foo' not in template map, return values as a string,
111 if 'foo' not in template map, return values as a string,
112 joined by 'separator'.
112 joined by 'separator'.
113
113
114 expand 'start_foos'.
114 expand 'start_foos'.
115
115
116 for each value, expand 'foo'. if 'last_foo' in template
116 for each value, expand 'foo'. if 'last_foo' in template
117 map, expand it instead of 'foo' for last key.
117 map, expand it instead of 'foo' for last key.
118
118
119 expand 'end_foos'.
119 expand 'end_foos'.
120 '''
120 '''
121 templ = mapping['templ']
121 templ = mapping['templ']
122 if not plural:
122 if not plural:
123 plural = name + 's'
123 plural = name + 's'
124 if not values:
124 if not values:
125 noname = 'no_' + plural
125 noname = 'no_' + plural
126 if noname in templ:
126 if noname in templ:
127 yield templ(noname, **mapping)
127 yield templ(noname, **mapping)
128 return
128 return
129 if name not in templ:
129 if name not in templ:
130 if isinstance(values[0], bytes):
130 if isinstance(values[0], bytes):
131 yield separator.join(values)
131 yield separator.join(values)
132 else:
132 else:
133 for v in values:
133 for v in values:
134 yield dict(v, **mapping)
134 yield dict(v, **mapping)
135 return
135 return
136 startname = 'start_' + plural
136 startname = 'start_' + plural
137 if startname in templ:
137 if startname in templ:
138 yield templ(startname, **mapping)
138 yield templ(startname, **mapping)
139 vmapping = mapping.copy()
139 vmapping = mapping.copy()
140 def one(v, tag=name):
140 def one(v, tag=name):
141 try:
141 try:
142 vmapping.update(v)
142 vmapping.update(v)
143 except (AttributeError, ValueError):
143 except (AttributeError, ValueError):
144 try:
144 try:
145 for a, b in v:
145 for a, b in v:
146 vmapping[a] = b
146 vmapping[a] = b
147 except ValueError:
147 except ValueError:
148 vmapping[name] = v
148 vmapping[name] = v
149 return templ(tag, **vmapping)
149 return templ(tag, **vmapping)
150 lastname = 'last_' + name
150 lastname = 'last_' + name
151 if lastname in templ:
151 if lastname in templ:
152 last = values.pop()
152 last = values.pop()
153 else:
153 else:
154 last = None
154 last = None
155 for v in values:
155 for v in values:
156 yield one(v)
156 yield one(v)
157 if last is not None:
157 if last is not None:
158 yield one(last, tag=lastname)
158 yield one(last, tag=lastname)
159 endname = 'end_' + plural
159 endname = 'end_' + plural
160 if endname in templ:
160 if endname in templ:
161 yield templ(endname, **mapping)
161 yield templ(endname, **mapping)
162
162
163 def _formatrevnode(ctx):
163 def _formatrevnode(ctx):
164 """Format changeset as '{rev}:{node|formatnode}', which is the default
164 """Format changeset as '{rev}:{node|formatnode}', which is the default
165 template provided by cmdutil.changeset_templater"""
165 template provided by cmdutil.changeset_templater"""
166 repo = ctx.repo()
166 repo = ctx.repo()
167 if repo.ui.debugflag:
167 if repo.ui.debugflag:
168 hexfunc = hex
168 hexfunc = hex
169 else:
169 else:
170 hexfunc = short
170 hexfunc = short
171 return '%d:%s' % (scmutil.intrev(ctx), hexfunc(scmutil.binnode(ctx)))
171 return '%d:%s' % (scmutil.intrev(ctx), hexfunc(scmutil.binnode(ctx)))
172
172
173 def getfiles(repo, ctx, revcache):
173 def getfiles(repo, ctx, revcache):
174 if 'files' not in revcache:
174 if 'files' not in revcache:
175 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
175 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
176 return revcache['files']
176 return revcache['files']
177
177
178 def getlatesttags(repo, ctx, cache, pattern=None):
178 def getlatesttags(repo, ctx, cache, pattern=None):
179 '''return date, distance and name for the latest tag of rev'''
179 '''return date, distance and name for the latest tag of rev'''
180
180
181 cachename = 'latesttags'
181 cachename = 'latesttags'
182 if pattern is not None:
182 if pattern is not None:
183 cachename += '-' + pattern
183 cachename += '-' + pattern
184 match = util.stringmatcher(pattern)[2]
184 match = util.stringmatcher(pattern)[2]
185 else:
185 else:
186 match = util.always
186 match = util.always
187
187
188 if cachename not in cache:
188 if cachename not in cache:
189 # Cache mapping from rev to a tuple with tag date, tag
189 # Cache mapping from rev to a tuple with tag date, tag
190 # distance and tag name
190 # distance and tag name
191 cache[cachename] = {-1: (0, 0, ['null'])}
191 cache[cachename] = {-1: (0, 0, ['null'])}
192 latesttags = cache[cachename]
192 latesttags = cache[cachename]
193
193
194 rev = ctx.rev()
194 rev = ctx.rev()
195 todo = [rev]
195 todo = [rev]
196 while todo:
196 while todo:
197 rev = todo.pop()
197 rev = todo.pop()
198 if rev in latesttags:
198 if rev in latesttags:
199 continue
199 continue
200 ctx = repo[rev]
200 ctx = repo[rev]
201 tags = [t for t in ctx.tags()
201 tags = [t for t in ctx.tags()
202 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
202 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
203 and match(t))]
203 and match(t))]
204 if tags:
204 if tags:
205 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
205 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
206 continue
206 continue
207 try:
207 try:
208 # The tuples are laid out so the right one can be found by
208 # The tuples are laid out so the right one can be found by
209 # comparison.
209 # comparison.
210 pdate, pdist, ptag = max(
210 pdate, pdist, ptag = max(
211 latesttags[p.rev()] for p in ctx.parents())
211 latesttags[p.rev()] for p in ctx.parents())
212 except KeyError:
212 except KeyError:
213 # Cache miss - recurse
213 # Cache miss - recurse
214 todo.append(rev)
214 todo.append(rev)
215 todo.extend(p.rev() for p in ctx.parents())
215 todo.extend(p.rev() for p in ctx.parents())
216 continue
216 continue
217 latesttags[rev] = pdate, pdist + 1, ptag
217 latesttags[rev] = pdate, pdist + 1, ptag
218 return latesttags[rev]
218 return latesttags[rev]
219
219
220 def getrenamedfn(repo, endrev=None):
220 def getrenamedfn(repo, endrev=None):
221 rcache = {}
221 rcache = {}
222 if endrev is None:
222 if endrev is None:
223 endrev = len(repo)
223 endrev = len(repo)
224
224
225 def getrenamed(fn, rev):
225 def getrenamed(fn, rev):
226 '''looks up all renames for a file (up to endrev) the first
226 '''looks up all renames for a file (up to endrev) the first
227 time the file is given. It indexes on the changerev and only
227 time the file is given. It indexes on the changerev and only
228 parses the manifest if linkrev != changerev.
228 parses the manifest if linkrev != changerev.
229 Returns rename info for fn at changerev rev.'''
229 Returns rename info for fn at changerev rev.'''
230 if fn not in rcache:
230 if fn not in rcache:
231 rcache[fn] = {}
231 rcache[fn] = {}
232 fl = repo.file(fn)
232 fl = repo.file(fn)
233 for i in fl:
233 for i in fl:
234 lr = fl.linkrev(i)
234 lr = fl.linkrev(i)
235 renamed = fl.renamed(fl.node(i))
235 renamed = fl.renamed(fl.node(i))
236 rcache[fn][lr] = renamed
236 rcache[fn][lr] = renamed
237 if lr >= endrev:
237 if lr >= endrev:
238 break
238 break
239 if rev in rcache[fn]:
239 if rev in rcache[fn]:
240 return rcache[fn][rev]
240 return rcache[fn][rev]
241
241
242 # If linkrev != rev (i.e. rev not found in rcache) fallback to
242 # If linkrev != rev (i.e. rev not found in rcache) fallback to
243 # filectx logic.
243 # filectx logic.
244 try:
244 try:
245 return repo[rev][fn].renamed()
245 return repo[rev][fn].renamed()
246 except error.LookupError:
246 except error.LookupError:
247 return None
247 return None
248
248
249 return getrenamed
249 return getrenamed
250
250
251 # default templates internally used for rendering of lists
251 # default templates internally used for rendering of lists
252 defaulttempl = {
252 defaulttempl = {
253 'parent': '{rev}:{node|formatnode} ',
253 'parent': '{rev}:{node|formatnode} ',
254 'manifest': '{rev}:{node|formatnode}',
254 'manifest': '{rev}:{node|formatnode}',
255 'file_copy': '{name} ({source})',
255 'file_copy': '{name} ({source})',
256 'envvar': '{key}={value}',
256 'envvar': '{key}={value}',
257 'extra': '{key}={value|stringescape}'
257 'extra': '{key}={value|stringescape}'
258 }
258 }
259 # filecopy is preserved for compatibility reasons
259 # filecopy is preserved for compatibility reasons
260 defaulttempl['filecopy'] = defaulttempl['file_copy']
260 defaulttempl['filecopy'] = defaulttempl['file_copy']
261
261
262 # keywords are callables like:
262 # keywords are callables like:
263 # fn(repo, ctx, templ, cache, revcache, **args)
263 # fn(repo, ctx, templ, cache, revcache, **args)
264 # with:
264 # with:
265 # repo - current repository instance
265 # repo - current repository instance
266 # ctx - the changectx being displayed
266 # ctx - the changectx being displayed
267 # templ - the templater instance
267 # templ - the templater instance
268 # cache - a cache dictionary for the whole templater run
268 # cache - a cache dictionary for the whole templater run
269 # revcache - a cache dictionary for the current revision
269 # revcache - a cache dictionary for the current revision
270 keywords = {}
270 keywords = {}
271
271
272 templatekeyword = registrar.templatekeyword(keywords)
272 templatekeyword = registrar.templatekeyword(keywords)
273
273
274 @templatekeyword('author')
274 @templatekeyword('author')
275 def showauthor(repo, ctx, templ, **args):
275 def showauthor(repo, ctx, templ, **args):
276 """String. The unmodified author of the changeset."""
276 """String. The unmodified author of the changeset."""
277 return ctx.user()
277 return ctx.user()
278
278
279 @templatekeyword('bisect')
279 @templatekeyword('bisect')
280 def showbisect(repo, ctx, templ, **args):
280 def showbisect(repo, ctx, templ, **args):
281 """String. The changeset bisection status."""
281 """String. The changeset bisection status."""
282 return hbisect.label(repo, ctx.node())
282 return hbisect.label(repo, ctx.node())
283
283
284 @templatekeyword('branch')
284 @templatekeyword('branch')
285 def showbranch(**args):
285 def showbranch(**args):
286 """String. The name of the branch on which the changeset was
286 """String. The name of the branch on which the changeset was
287 committed.
287 committed.
288 """
288 """
289 return args[r'ctx'].branch()
289 return args[r'ctx'].branch()
290
290
291 @templatekeyword('branches')
291 @templatekeyword('branches')
292 def showbranches(**args):
292 def showbranches(**args):
293 """List of strings. The name of the branch on which the
293 """List of strings. The name of the branch on which the
294 changeset was committed. Will be empty if the branch name was
294 changeset was committed. Will be empty if the branch name was
295 default. (DEPRECATED)
295 default. (DEPRECATED)
296 """
296 """
297 args = pycompat.byteskwargs(args)
297 args = pycompat.byteskwargs(args)
298 branch = args['ctx'].branch()
298 branch = args['ctx'].branch()
299 if branch != 'default':
299 if branch != 'default':
300 return showlist('branch', [branch], args, plural='branches')
300 return showlist('branch', [branch], args, plural='branches')
301 return showlist('branch', [], args, plural='branches')
301 return showlist('branch', [], args, plural='branches')
302
302
303 @templatekeyword('bookmarks')
303 @templatekeyword('bookmarks')
304 def showbookmarks(**args):
304 def showbookmarks(**args):
305 """List of strings. Any bookmarks associated with the
305 """List of strings. Any bookmarks associated with the
306 changeset. Also sets 'active', the name of the active bookmark.
306 changeset. Also sets 'active', the name of the active bookmark.
307 """
307 """
308 args = pycompat.byteskwargs(args)
308 args = pycompat.byteskwargs(args)
309 repo = args['ctx']._repo
309 repo = args['ctx']._repo
310 bookmarks = args['ctx'].bookmarks()
310 bookmarks = args['ctx'].bookmarks()
311 active = repo._activebookmark
311 active = repo._activebookmark
312 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
312 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
313 f = _showlist('bookmark', bookmarks, args)
313 f = _showlist('bookmark', bookmarks, args)
314 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
314 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
315
315
316 @templatekeyword('children')
316 @templatekeyword('children')
317 def showchildren(**args):
317 def showchildren(**args):
318 """List of strings. The children of the changeset."""
318 """List of strings. The children of the changeset."""
319 args = pycompat.byteskwargs(args)
319 args = pycompat.byteskwargs(args)
320 ctx = args['ctx']
320 ctx = args['ctx']
321 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
321 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
322 return showlist('children', childrevs, args, element='child')
322 return showlist('children', childrevs, args, element='child')
323
323
324 # Deprecated, but kept alive for help generation a purpose.
324 # Deprecated, but kept alive for help generation a purpose.
325 @templatekeyword('currentbookmark')
325 @templatekeyword('currentbookmark')
326 def showcurrentbookmark(**args):
326 def showcurrentbookmark(**args):
327 """String. The active bookmark, if it is
327 """String. The active bookmark, if it is
328 associated with the changeset (DEPRECATED)"""
328 associated with the changeset (DEPRECATED)"""
329 return showactivebookmark(**args)
329 return showactivebookmark(**args)
330
330
331 @templatekeyword('activebookmark')
331 @templatekeyword('activebookmark')
332 def showactivebookmark(**args):
332 def showactivebookmark(**args):
333 """String. The active bookmark, if it is
333 """String. The active bookmark, if it is
334 associated with the changeset"""
334 associated with the changeset"""
335 active = args[r'repo']._activebookmark
335 active = args[r'repo']._activebookmark
336 if active and active in args[r'ctx'].bookmarks():
336 if active and active in args[r'ctx'].bookmarks():
337 return active
337 return active
338 return ''
338 return ''
339
339
340 @templatekeyword('date')
340 @templatekeyword('date')
341 def showdate(repo, ctx, templ, **args):
341 def showdate(repo, ctx, templ, **args):
342 """Date information. The date when the changeset was committed."""
342 """Date information. The date when the changeset was committed."""
343 return ctx.date()
343 return ctx.date()
344
344
345 @templatekeyword('desc')
345 @templatekeyword('desc')
346 def showdescription(repo, ctx, templ, **args):
346 def showdescription(repo, ctx, templ, **args):
347 """String. The text of the changeset description."""
347 """String. The text of the changeset description."""
348 s = ctx.description()
348 s = ctx.description()
349 if isinstance(s, encoding.localstr):
349 if isinstance(s, encoding.localstr):
350 # try hard to preserve utf-8 bytes
350 # try hard to preserve utf-8 bytes
351 return encoding.tolocal(encoding.fromlocal(s).strip())
351 return encoding.tolocal(encoding.fromlocal(s).strip())
352 else:
352 else:
353 return s.strip()
353 return s.strip()
354
354
355 @templatekeyword('diffstat')
355 @templatekeyword('diffstat')
356 def showdiffstat(repo, ctx, templ, **args):
356 def showdiffstat(repo, ctx, templ, **args):
357 """String. Statistics of changes with the following format:
357 """String. Statistics of changes with the following format:
358 "modified files: +added/-removed lines"
358 "modified files: +added/-removed lines"
359 """
359 """
360 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
360 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
361 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
361 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
362 return '%s: +%s/-%s' % (len(stats), adds, removes)
362 return '%s: +%s/-%s' % (len(stats), adds, removes)
363
363
364 @templatekeyword('envvars')
364 @templatekeyword('envvars')
365 def showenvvars(repo, **args):
365 def showenvvars(repo, **args):
366 """A dictionary of environment variables. (EXPERIMENTAL)"""
366 """A dictionary of environment variables. (EXPERIMENTAL)"""
367 args = pycompat.byteskwargs(args)
367 args = pycompat.byteskwargs(args)
368 env = repo.ui.exportableenviron()
368 env = repo.ui.exportableenviron()
369 env = util.sortdict((k, env[k]) for k in sorted(env))
369 env = util.sortdict((k, env[k]) for k in sorted(env))
370 return showdict('envvar', env, args, plural='envvars')
370 return showdict('envvar', env, args, plural='envvars')
371
371
372 @templatekeyword('extras')
372 @templatekeyword('extras')
373 def showextras(**args):
373 def showextras(**args):
374 """List of dicts with key, value entries of the 'extras'
374 """List of dicts with key, value entries of the 'extras'
375 field of this changeset."""
375 field of this changeset."""
376 args = pycompat.byteskwargs(args)
376 args = pycompat.byteskwargs(args)
377 extras = args['ctx'].extra()
377 extras = args['ctx'].extra()
378 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
378 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
379 makemap = lambda k: {'key': k, 'value': extras[k]}
379 makemap = lambda k: {'key': k, 'value': extras[k]}
380 c = [makemap(k) for k in extras]
380 c = [makemap(k) for k in extras]
381 f = _showlist('extra', c, args, plural='extras')
381 f = _showlist('extra', c, args, plural='extras')
382 return _hybrid(f, extras, makemap,
382 return _hybrid(f, extras, makemap,
383 lambda x: '%s=%s' % (x['key'], util.escapestr(x['value'])))
383 lambda x: '%s=%s' % (x['key'], util.escapestr(x['value'])))
384
384
385 @templatekeyword('file_adds')
385 @templatekeyword('file_adds')
386 def showfileadds(**args):
386 def showfileadds(**args):
387 """List of strings. Files added by this changeset."""
387 """List of strings. Files added by this changeset."""
388 args = pycompat.byteskwargs(args)
388 args = pycompat.byteskwargs(args)
389 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
389 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
390 return showlist('file_add', getfiles(repo, ctx, revcache)[1], args,
390 return showlist('file_add', getfiles(repo, ctx, revcache)[1], args,
391 element='file')
391 element='file')
392
392
393 @templatekeyword('file_copies')
393 @templatekeyword('file_copies')
394 def showfilecopies(**args):
394 def showfilecopies(**args):
395 """List of strings. Files copied in this changeset with
395 """List of strings. Files copied in this changeset with
396 their sources.
396 their sources.
397 """
397 """
398 args = pycompat.byteskwargs(args)
398 args = pycompat.byteskwargs(args)
399 cache, ctx = args['cache'], args['ctx']
399 cache, ctx = args['cache'], args['ctx']
400 copies = args['revcache'].get('copies')
400 copies = args['revcache'].get('copies')
401 if copies is None:
401 if copies is None:
402 if 'getrenamed' not in cache:
402 if 'getrenamed' not in cache:
403 cache['getrenamed'] = getrenamedfn(args['repo'])
403 cache['getrenamed'] = getrenamedfn(args['repo'])
404 copies = []
404 copies = []
405 getrenamed = cache['getrenamed']
405 getrenamed = cache['getrenamed']
406 for fn in ctx.files():
406 for fn in ctx.files():
407 rename = getrenamed(fn, ctx.rev())
407 rename = getrenamed(fn, ctx.rev())
408 if rename:
408 if rename:
409 copies.append((fn, rename[0]))
409 copies.append((fn, rename[0]))
410
410
411 copies = util.sortdict(copies)
411 copies = util.sortdict(copies)
412 return showdict('file_copy', copies, args, plural='file_copies',
412 return showdict('file_copy', copies, args, plural='file_copies',
413 key='name', value='source', fmt='%s (%s)')
413 key='name', value='source', fmt='%s (%s)')
414
414
415 # showfilecopiesswitch() displays file copies only if copy records are
415 # showfilecopiesswitch() displays file copies only if copy records are
416 # provided before calling the templater, usually with a --copies
416 # provided before calling the templater, usually with a --copies
417 # command line switch.
417 # command line switch.
418 @templatekeyword('file_copies_switch')
418 @templatekeyword('file_copies_switch')
419 def showfilecopiesswitch(**args):
419 def showfilecopiesswitch(**args):
420 """List of strings. Like "file_copies" but displayed
420 """List of strings. Like "file_copies" but displayed
421 only if the --copied switch is set.
421 only if the --copied switch is set.
422 """
422 """
423 args = pycompat.byteskwargs(args)
423 args = pycompat.byteskwargs(args)
424 copies = args['revcache'].get('copies') or []
424 copies = args['revcache'].get('copies') or []
425 copies = util.sortdict(copies)
425 copies = util.sortdict(copies)
426 return showdict('file_copy', copies, args, plural='file_copies',
426 return showdict('file_copy', copies, args, plural='file_copies',
427 key='name', value='source', fmt='%s (%s)')
427 key='name', value='source', fmt='%s (%s)')
428
428
429 @templatekeyword('file_dels')
429 @templatekeyword('file_dels')
430 def showfiledels(**args):
430 def showfiledels(**args):
431 """List of strings. Files removed by this changeset."""
431 """List of strings. Files removed by this changeset."""
432 args = pycompat.byteskwargs(args)
432 args = pycompat.byteskwargs(args)
433 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
433 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
434 return showlist('file_del', getfiles(repo, ctx, revcache)[2], args,
434 return showlist('file_del', getfiles(repo, ctx, revcache)[2], args,
435 element='file')
435 element='file')
436
436
437 @templatekeyword('file_mods')
437 @templatekeyword('file_mods')
438 def showfilemods(**args):
438 def showfilemods(**args):
439 """List of strings. Files modified by this changeset."""
439 """List of strings. Files modified by this changeset."""
440 args = pycompat.byteskwargs(args)
440 args = pycompat.byteskwargs(args)
441 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
441 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
442 return showlist('file_mod', getfiles(repo, ctx, revcache)[0], args,
442 return showlist('file_mod', getfiles(repo, ctx, revcache)[0], args,
443 element='file')
443 element='file')
444
444
445 @templatekeyword('files')
445 @templatekeyword('files')
446 def showfiles(**args):
446 def showfiles(**args):
447 """List of strings. All files modified, added, or removed by this
447 """List of strings. All files modified, added, or removed by this
448 changeset.
448 changeset.
449 """
449 """
450 args = pycompat.byteskwargs(args)
450 args = pycompat.byteskwargs(args)
451 return showlist('file', args['ctx'].files(), args)
451 return showlist('file', args['ctx'].files(), args)
452
452
453 @templatekeyword('graphnode')
453 @templatekeyword('graphnode')
454 def showgraphnode(repo, ctx, **args):
454 def showgraphnode(repo, ctx, **args):
455 """String. The character representing the changeset node in
455 """String. The character representing the changeset node in
456 an ASCII revision graph"""
456 an ASCII revision graph"""
457 wpnodes = repo.dirstate.parents()
457 wpnodes = repo.dirstate.parents()
458 if wpnodes[1] == nullid:
458 if wpnodes[1] == nullid:
459 wpnodes = wpnodes[:1]
459 wpnodes = wpnodes[:1]
460 if ctx.node() in wpnodes:
460 if ctx.node() in wpnodes:
461 return '@'
461 return '@'
462 elif ctx.obsolete():
462 elif ctx.obsolete():
463 return 'x'
463 return 'x'
464 elif ctx.closesbranch():
464 elif ctx.closesbranch():
465 return '_'
465 return '_'
466 else:
466 else:
467 return 'o'
467 return 'o'
468
468
469 @templatekeyword('index')
469 @templatekeyword('index')
470 def showindex(**args):
470 def showindex(**args):
471 """Integer. The current iteration of the loop. (0 indexed)"""
471 """Integer. The current iteration of the loop. (0 indexed)"""
472 # just hosts documentation; should be overridden by template mapping
472 # just hosts documentation; should be overridden by template mapping
473 raise error.Abort(_("can't use index in this context"))
473 raise error.Abort(_("can't use index in this context"))
474
474
475 @templatekeyword('latesttag')
475 @templatekeyword('latesttag')
476 def showlatesttag(**args):
476 def showlatesttag(**args):
477 """List of strings. The global tags on the most recent globally
477 """List of strings. The global tags on the most recent globally
478 tagged ancestor of this changeset. If no such tags exist, the list
478 tagged ancestor of this changeset. If no such tags exist, the list
479 consists of the single string "null".
479 consists of the single string "null".
480 """
480 """
481 return showlatesttags(None, **args)
481 return showlatesttags(None, **args)
482
482
483 def showlatesttags(pattern, **args):
483 def showlatesttags(pattern, **args):
484 """helper method for the latesttag keyword and function"""
484 """helper method for the latesttag keyword and function"""
485 args = pycompat.byteskwargs(args)
485 args = pycompat.byteskwargs(args)
486 repo, ctx = args['repo'], args['ctx']
486 repo, ctx = args['repo'], args['ctx']
487 cache = args['cache']
487 cache = args['cache']
488 latesttags = getlatesttags(repo, ctx, cache, pattern)
488 latesttags = getlatesttags(repo, ctx, cache, pattern)
489
489
490 # latesttag[0] is an implementation detail for sorting csets on different
490 # latesttag[0] is an implementation detail for sorting csets on different
491 # branches in a stable manner- it is the date the tagged cset was created,
491 # branches in a stable manner- it is the date the tagged cset was created,
492 # not the date the tag was created. Therefore it isn't made visible here.
492 # not the date the tag was created. Therefore it isn't made visible here.
493 makemap = lambda v: {
493 makemap = lambda v: {
494 'changes': _showchangessincetag,
494 'changes': _showchangessincetag,
495 'distance': latesttags[1],
495 'distance': latesttags[1],
496 'latesttag': v, # BC with {latesttag % '{latesttag}'}
496 'latesttag': v, # BC with {latesttag % '{latesttag}'}
497 'tag': v
497 'tag': v
498 }
498 }
499
499
500 tags = latesttags[2]
500 tags = latesttags[2]
501 f = _showlist('latesttag', tags, args, separator=':')
501 f = _showlist('latesttag', tags, args, separator=':')
502 return _hybrid(f, tags, makemap, lambda x: x['latesttag'])
502 return _hybrid(f, tags, makemap, lambda x: x['latesttag'])
503
503
504 @templatekeyword('latesttagdistance')
504 @templatekeyword('latesttagdistance')
505 def showlatesttagdistance(repo, ctx, templ, cache, **args):
505 def showlatesttagdistance(repo, ctx, templ, cache, **args):
506 """Integer. Longest path to the latest tag."""
506 """Integer. Longest path to the latest tag."""
507 return getlatesttags(repo, ctx, cache)[1]
507 return getlatesttags(repo, ctx, cache)[1]
508
508
509 @templatekeyword('changessincelatesttag')
509 @templatekeyword('changessincelatesttag')
510 def showchangessincelatesttag(repo, ctx, templ, cache, **args):
510 def showchangessincelatesttag(repo, ctx, templ, cache, **args):
511 """Integer. All ancestors not in the latest tag."""
511 """Integer. All ancestors not in the latest tag."""
512 latesttag = getlatesttags(repo, ctx, cache)[2][0]
512 latesttag = getlatesttags(repo, ctx, cache)[2][0]
513
513
514 return _showchangessincetag(repo, ctx, tag=latesttag, **args)
514 return _showchangessincetag(repo, ctx, tag=latesttag, **args)
515
515
516 def _showchangessincetag(repo, ctx, **args):
516 def _showchangessincetag(repo, ctx, **args):
517 offset = 0
517 offset = 0
518 revs = [ctx.rev()]
518 revs = [ctx.rev()]
519 tag = args[r'tag']
519 tag = args[r'tag']
520
520
521 # The only() revset doesn't currently support wdir()
521 # The only() revset doesn't currently support wdir()
522 if ctx.rev() is None:
522 if ctx.rev() is None:
523 offset = 1
523 offset = 1
524 revs = [p.rev() for p in ctx.parents()]
524 revs = [p.rev() for p in ctx.parents()]
525
525
526 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
526 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
527
527
528 @templatekeyword('manifest')
528 @templatekeyword('manifest')
529 def showmanifest(**args):
529 def showmanifest(**args):
530 repo, ctx, templ = args[r'repo'], args[r'ctx'], args[r'templ']
530 repo, ctx, templ = args[r'repo'], args[r'ctx'], args[r'templ']
531 mnode = ctx.manifestnode()
531 mnode = ctx.manifestnode()
532 if mnode is None:
532 if mnode is None:
533 # just avoid crash, we might want to use the 'ff...' hash in future
533 # just avoid crash, we might want to use the 'ff...' hash in future
534 return
534 return
535 args = args.copy()
535 args = args.copy()
536 args.update({r'rev': repo.manifestlog._revlog.rev(mnode),
536 args.update({r'rev': repo.manifestlog._revlog.rev(mnode),
537 r'node': hex(mnode)})
537 r'node': hex(mnode)})
538 return templ('manifest', **args)
538 return templ('manifest', **args)
539
539
540 def shownames(namespace, **args):
540 def shownames(namespace, **args):
541 """helper method to generate a template keyword for a namespace"""
541 """helper method to generate a template keyword for a namespace"""
542 args = pycompat.byteskwargs(args)
542 args = pycompat.byteskwargs(args)
543 ctx = args['ctx']
543 ctx = args['ctx']
544 repo = ctx.repo()
544 repo = ctx.repo()
545 ns = repo.names[namespace]
545 ns = repo.names[namespace]
546 names = ns.names(repo, ctx.node())
546 names = ns.names(repo, ctx.node())
547 return showlist(ns.templatename, names, args, plural=namespace)
547 return showlist(ns.templatename, names, args, plural=namespace)
548
548
549 @templatekeyword('namespaces')
549 @templatekeyword('namespaces')
550 def shownamespaces(**args):
550 def shownamespaces(**args):
551 """Dict of lists. Names attached to this changeset per
551 """Dict of lists. Names attached to this changeset per
552 namespace."""
552 namespace."""
553 args = pycompat.byteskwargs(args)
553 args = pycompat.byteskwargs(args)
554 ctx = args['ctx']
554 ctx = args['ctx']
555 repo = ctx.repo()
555 repo = ctx.repo()
556 namespaces = util.sortdict((k, showlist('name', ns.names(repo, ctx.node()),
556 namespaces = util.sortdict((k, showlist('name', ns.names(repo, ctx.node()),
557 args))
557 args))
558 for k, ns in repo.names.iteritems())
558 for k, ns in repo.names.iteritems())
559 f = _showlist('namespace', list(namespaces), args)
559 f = _showlist('namespace', list(namespaces), args)
560 return _hybrid(f, namespaces,
560 return _hybrid(f, namespaces,
561 lambda k: {'namespace': k, 'names': namespaces[k]},
561 lambda k: {'namespace': k, 'names': namespaces[k]},
562 lambda x: x['namespace'])
562 lambda x: x['namespace'])
563
563
564 @templatekeyword('node')
564 @templatekeyword('node')
565 def shownode(repo, ctx, templ, **args):
565 def shownode(repo, ctx, templ, **args):
566 """String. The changeset identification hash, as a 40 hexadecimal
566 """String. The changeset identification hash, as a 40 hexadecimal
567 digit string.
567 digit string.
568 """
568 """
569 return ctx.hex()
569 return ctx.hex()
570
570
571 @templatekeyword('obsolete')
571 @templatekeyword('obsolete')
572 def showobsolete(repo, ctx, templ, **args):
572 def showobsolete(repo, ctx, templ, **args):
573 """String. Whether the changeset is obsolete.
573 """String. Whether the changeset is obsolete.
574 """
574 """
575 if ctx.obsolete():
575 if ctx.obsolete():
576 return 'obsolete'
576 return 'obsolete'
577 return ''
577 return ''
578
578
579 @templatekeyword("predecessors")
579 @templatekeyword("predecessors")
580 def showpredecessors(repo, ctx, **args):
580 def showpredecessors(repo, ctx, **args):
581 """Returns the list if the closest visible successors
581 """Returns the list if the closest visible successors
582 """
582 """
583 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
583 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
584 predecessors = map(hex, predecessors)
584 predecessors = map(hex, predecessors)
585
585
586 return _hybrid(None, predecessors,
586 return _hybrid(None, predecessors,
587 lambda x: {'ctx': repo[x], 'revcache': {}},
587 lambda x: {'ctx': repo[x], 'revcache': {}},
588 lambda d: _formatrevnode(d['ctx']))
588 lambda d: _formatrevnode(d['ctx']))
589
589
590 @templatekeyword('p1rev')
590 @templatekeyword('p1rev')
591 def showp1rev(repo, ctx, templ, **args):
591 def showp1rev(repo, ctx, templ, **args):
592 """Integer. The repository-local revision number of the changeset's
592 """Integer. The repository-local revision number of the changeset's
593 first parent, or -1 if the changeset has no parents."""
593 first parent, or -1 if the changeset has no parents."""
594 return ctx.p1().rev()
594 return ctx.p1().rev()
595
595
596 @templatekeyword('p2rev')
596 @templatekeyword('p2rev')
597 def showp2rev(repo, ctx, templ, **args):
597 def showp2rev(repo, ctx, templ, **args):
598 """Integer. The repository-local revision number of the changeset's
598 """Integer. The repository-local revision number of the changeset's
599 second parent, or -1 if the changeset has no second parent."""
599 second parent, or -1 if the changeset has no second parent."""
600 return ctx.p2().rev()
600 return ctx.p2().rev()
601
601
602 @templatekeyword('p1node')
602 @templatekeyword('p1node')
603 def showp1node(repo, ctx, templ, **args):
603 def showp1node(repo, ctx, templ, **args):
604 """String. The identification hash of the changeset's first parent,
604 """String. The identification hash of the changeset's first parent,
605 as a 40 digit hexadecimal string. If the changeset has no parents, all
605 as a 40 digit hexadecimal string. If the changeset has no parents, all
606 digits are 0."""
606 digits are 0."""
607 return ctx.p1().hex()
607 return ctx.p1().hex()
608
608
609 @templatekeyword('p2node')
609 @templatekeyword('p2node')
610 def showp2node(repo, ctx, templ, **args):
610 def showp2node(repo, ctx, templ, **args):
611 """String. The identification hash of the changeset's second
611 """String. The identification hash of the changeset's second
612 parent, as a 40 digit hexadecimal string. If the changeset has no second
612 parent, as a 40 digit hexadecimal string. If the changeset has no second
613 parent, all digits are 0."""
613 parent, all digits are 0."""
614 return ctx.p2().hex()
614 return ctx.p2().hex()
615
615
616 @templatekeyword('parents')
616 @templatekeyword('parents')
617 def showparents(**args):
617 def showparents(**args):
618 """List of strings. The parents of the changeset in "rev:node"
618 """List of strings. The parents of the changeset in "rev:node"
619 format. If the changeset has only one "natural" parent (the predecessor
619 format. If the changeset has only one "natural" parent (the predecessor
620 revision) nothing is shown."""
620 revision) nothing is shown."""
621 args = pycompat.byteskwargs(args)
621 args = pycompat.byteskwargs(args)
622 repo = args['repo']
622 repo = args['repo']
623 ctx = args['ctx']
623 ctx = args['ctx']
624 pctxs = scmutil.meaningfulparents(repo, ctx)
624 pctxs = scmutil.meaningfulparents(repo, ctx)
625 # ifcontains() needs a list of str
625 # ifcontains() needs a list of str
626 prevs = [pycompat.bytestr(p.rev()) for p in pctxs]
626 prevs = ["%d" % p.rev() for p in pctxs]
627 parents = [[('rev', p.rev()),
627 parents = [[('rev', p.rev()),
628 ('node', p.hex()),
628 ('node', p.hex()),
629 ('phase', p.phasestr())]
629 ('phase', p.phasestr())]
630 for p in pctxs]
630 for p in pctxs]
631 f = _showlist('parent', parents, args)
631 f = _showlist('parent', parents, args)
632 return _hybrid(f, prevs, lambda x: {'ctx': repo[int(x)], 'revcache': {}},
632 return _hybrid(f, prevs, lambda x: {'ctx': repo[int(x)], 'revcache': {}},
633 lambda d: _formatrevnode(d['ctx']))
633 lambda d: _formatrevnode(d['ctx']))
634
634
635 @templatekeyword('phase')
635 @templatekeyword('phase')
636 def showphase(repo, ctx, templ, **args):
636 def showphase(repo, ctx, templ, **args):
637 """String. The changeset phase name."""
637 """String. The changeset phase name."""
638 return ctx.phasestr()
638 return ctx.phasestr()
639
639
640 @templatekeyword('phaseidx')
640 @templatekeyword('phaseidx')
641 def showphaseidx(repo, ctx, templ, **args):
641 def showphaseidx(repo, ctx, templ, **args):
642 """Integer. The changeset phase index."""
642 """Integer. The changeset phase index."""
643 return ctx.phase()
643 return ctx.phase()
644
644
645 @templatekeyword('rev')
645 @templatekeyword('rev')
646 def showrev(repo, ctx, templ, **args):
646 def showrev(repo, ctx, templ, **args):
647 """Integer. The repository-local changeset revision number."""
647 """Integer. The repository-local changeset revision number."""
648 return scmutil.intrev(ctx)
648 return scmutil.intrev(ctx)
649
649
650 def showrevslist(name, revs, **args):
650 def showrevslist(name, revs, **args):
651 """helper to generate a list of revisions in which a mapped template will
651 """helper to generate a list of revisions in which a mapped template will
652 be evaluated"""
652 be evaluated"""
653 args = pycompat.byteskwargs(args)
653 args = pycompat.byteskwargs(args)
654 repo = args['ctx'].repo()
654 repo = args['ctx'].repo()
655 # ifcontains() needs a list of str
655 # ifcontains() needs a list of str
656 revs = [pycompat.bytestr(r) for r in revs]
656 revs = ["%d" % r for r in revs]
657 f = _showlist(name, revs, args)
657 f = _showlist(name, revs, args)
658 return _hybrid(f, revs,
658 return _hybrid(f, revs,
659 lambda x: {name: x, 'ctx': repo[int(x)], 'revcache': {}},
659 lambda x: {name: x, 'ctx': repo[int(x)], 'revcache': {}},
660 lambda d: d[name])
660 lambda d: d[name])
661
661
662 @templatekeyword('subrepos')
662 @templatekeyword('subrepos')
663 def showsubrepos(**args):
663 def showsubrepos(**args):
664 """List of strings. Updated subrepositories in the changeset."""
664 """List of strings. Updated subrepositories in the changeset."""
665 args = pycompat.byteskwargs(args)
665 args = pycompat.byteskwargs(args)
666 ctx = args['ctx']
666 ctx = args['ctx']
667 substate = ctx.substate
667 substate = ctx.substate
668 if not substate:
668 if not substate:
669 return showlist('subrepo', [], args)
669 return showlist('subrepo', [], args)
670 psubstate = ctx.parents()[0].substate or {}
670 psubstate = ctx.parents()[0].substate or {}
671 subrepos = []
671 subrepos = []
672 for sub in substate:
672 for sub in substate:
673 if sub not in psubstate or substate[sub] != psubstate[sub]:
673 if sub not in psubstate or substate[sub] != psubstate[sub]:
674 subrepos.append(sub) # modified or newly added in ctx
674 subrepos.append(sub) # modified or newly added in ctx
675 for sub in psubstate:
675 for sub in psubstate:
676 if sub not in substate:
676 if sub not in substate:
677 subrepos.append(sub) # removed in ctx
677 subrepos.append(sub) # removed in ctx
678 return showlist('subrepo', sorted(subrepos), args)
678 return showlist('subrepo', sorted(subrepos), args)
679
679
680 # don't remove "showtags" definition, even though namespaces will put
680 # don't remove "showtags" definition, even though namespaces will put
681 # a helper function for "tags" keyword into "keywords" map automatically,
681 # a helper function for "tags" keyword into "keywords" map automatically,
682 # because online help text is built without namespaces initialization
682 # because online help text is built without namespaces initialization
683 @templatekeyword('tags')
683 @templatekeyword('tags')
684 def showtags(**args):
684 def showtags(**args):
685 """List of strings. Any tags associated with the changeset."""
685 """List of strings. Any tags associated with the changeset."""
686 return shownames('tags', **args)
686 return shownames('tags', **args)
687
687
688 def loadkeyword(ui, extname, registrarobj):
688 def loadkeyword(ui, extname, registrarobj):
689 """Load template keyword from specified registrarobj
689 """Load template keyword from specified registrarobj
690 """
690 """
691 for name, func in registrarobj._table.iteritems():
691 for name, func in registrarobj._table.iteritems():
692 keywords[name] = func
692 keywords[name] = func
693
693
694 @templatekeyword('termwidth')
694 @templatekeyword('termwidth')
695 def termwidth(repo, ctx, templ, **args):
695 def termwidth(repo, ctx, templ, **args):
696 """Integer. The width of the current terminal."""
696 """Integer. The width of the current terminal."""
697 return repo.ui.termwidth()
697 return repo.ui.termwidth()
698
698
699 @templatekeyword('troubles')
699 @templatekeyword('troubles')
700 def showtroubles(**args):
700 def showtroubles(**args):
701 """List of strings. Evolution troubles affecting the changeset.
701 """List of strings. Evolution troubles affecting the changeset.
702
702
703 (EXPERIMENTAL)
703 (EXPERIMENTAL)
704 """
704 """
705 args = pycompat.byteskwargs(args)
705 args = pycompat.byteskwargs(args)
706 return showlist('trouble', args['ctx'].troubles(), args)
706 return showlist('trouble', args['ctx'].troubles(), args)
707
707
708 # tell hggettext to extract docstrings from these functions:
708 # tell hggettext to extract docstrings from these functions:
709 i18nfunctions = keywords.values()
709 i18nfunctions = keywords.values()
General Comments 0
You need to be logged in to leave comments. Login now