##// END OF EJS Templates
graft: check for missing revision first before scanning working copy...
Joerg Sonnenberger -
r36860:ff541b8c default
parent child Browse files
Show More
@@ -1,5616 +1,5616 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 logcmdutil,
44 logcmdutil,
45 merge as mergemod,
45 merge as mergemod,
46 obsolete,
46 obsolete,
47 obsutil,
47 obsutil,
48 patch,
48 patch,
49 phases,
49 phases,
50 pycompat,
50 pycompat,
51 rcutil,
51 rcutil,
52 registrar,
52 registrar,
53 revsetlang,
53 revsetlang,
54 rewriteutil,
54 rewriteutil,
55 scmutil,
55 scmutil,
56 server,
56 server,
57 streamclone,
57 streamclone,
58 tags as tagsmod,
58 tags as tagsmod,
59 templatekw,
59 templatekw,
60 ui as uimod,
60 ui as uimod,
61 util,
61 util,
62 wireprotoserver,
62 wireprotoserver,
63 )
63 )
64 from .utils import dateutil
64 from .utils import dateutil
65
65
66 release = lockmod.release
66 release = lockmod.release
67
67
68 table = {}
68 table = {}
69 table.update(debugcommandsmod.command._table)
69 table.update(debugcommandsmod.command._table)
70
70
71 command = registrar.command(table)
71 command = registrar.command(table)
72 readonly = registrar.command.readonly
72 readonly = registrar.command.readonly
73
73
74 # common command options
74 # common command options
75
75
76 globalopts = [
76 globalopts = [
77 ('R', 'repository', '',
77 ('R', 'repository', '',
78 _('repository root directory or name of overlay bundle file'),
78 _('repository root directory or name of overlay bundle file'),
79 _('REPO')),
79 _('REPO')),
80 ('', 'cwd', '',
80 ('', 'cwd', '',
81 _('change working directory'), _('DIR')),
81 _('change working directory'), _('DIR')),
82 ('y', 'noninteractive', None,
82 ('y', 'noninteractive', None,
83 _('do not prompt, automatically pick the first choice for all prompts')),
83 _('do not prompt, automatically pick the first choice for all prompts')),
84 ('q', 'quiet', None, _('suppress output')),
84 ('q', 'quiet', None, _('suppress output')),
85 ('v', 'verbose', None, _('enable additional output')),
85 ('v', 'verbose', None, _('enable additional output')),
86 ('', 'color', '',
86 ('', 'color', '',
87 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
87 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
88 # and should not be translated
88 # and should not be translated
89 _("when to colorize (boolean, always, auto, never, or debug)"),
89 _("when to colorize (boolean, always, auto, never, or debug)"),
90 _('TYPE')),
90 _('TYPE')),
91 ('', 'config', [],
91 ('', 'config', [],
92 _('set/override config option (use \'section.name=value\')'),
92 _('set/override config option (use \'section.name=value\')'),
93 _('CONFIG')),
93 _('CONFIG')),
94 ('', 'debug', None, _('enable debugging output')),
94 ('', 'debug', None, _('enable debugging output')),
95 ('', 'debugger', None, _('start debugger')),
95 ('', 'debugger', None, _('start debugger')),
96 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
96 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
97 _('ENCODE')),
97 _('ENCODE')),
98 ('', 'encodingmode', encoding.encodingmode,
98 ('', 'encodingmode', encoding.encodingmode,
99 _('set the charset encoding mode'), _('MODE')),
99 _('set the charset encoding mode'), _('MODE')),
100 ('', 'traceback', None, _('always print a traceback on exception')),
100 ('', 'traceback', None, _('always print a traceback on exception')),
101 ('', 'time', None, _('time how long the command takes')),
101 ('', 'time', None, _('time how long the command takes')),
102 ('', 'profile', None, _('print command execution profile')),
102 ('', 'profile', None, _('print command execution profile')),
103 ('', 'version', None, _('output version information and exit')),
103 ('', 'version', None, _('output version information and exit')),
104 ('h', 'help', None, _('display help and exit')),
104 ('h', 'help', None, _('display help and exit')),
105 ('', 'hidden', False, _('consider hidden changesets')),
105 ('', 'hidden', False, _('consider hidden changesets')),
106 ('', 'pager', 'auto',
106 ('', 'pager', 'auto',
107 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
107 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
108 ]
108 ]
109
109
110 dryrunopts = cmdutil.dryrunopts
110 dryrunopts = cmdutil.dryrunopts
111 remoteopts = cmdutil.remoteopts
111 remoteopts = cmdutil.remoteopts
112 walkopts = cmdutil.walkopts
112 walkopts = cmdutil.walkopts
113 commitopts = cmdutil.commitopts
113 commitopts = cmdutil.commitopts
114 commitopts2 = cmdutil.commitopts2
114 commitopts2 = cmdutil.commitopts2
115 formatteropts = cmdutil.formatteropts
115 formatteropts = cmdutil.formatteropts
116 templateopts = cmdutil.templateopts
116 templateopts = cmdutil.templateopts
117 logopts = cmdutil.logopts
117 logopts = cmdutil.logopts
118 diffopts = cmdutil.diffopts
118 diffopts = cmdutil.diffopts
119 diffwsopts = cmdutil.diffwsopts
119 diffwsopts = cmdutil.diffwsopts
120 diffopts2 = cmdutil.diffopts2
120 diffopts2 = cmdutil.diffopts2
121 mergetoolopts = cmdutil.mergetoolopts
121 mergetoolopts = cmdutil.mergetoolopts
122 similarityopts = cmdutil.similarityopts
122 similarityopts = cmdutil.similarityopts
123 subrepoopts = cmdutil.subrepoopts
123 subrepoopts = cmdutil.subrepoopts
124 debugrevlogopts = cmdutil.debugrevlogopts
124 debugrevlogopts = cmdutil.debugrevlogopts
125
125
126 # Commands start here, listed alphabetically
126 # Commands start here, listed alphabetically
127
127
128 @command('^add',
128 @command('^add',
129 walkopts + subrepoopts + dryrunopts,
129 walkopts + subrepoopts + dryrunopts,
130 _('[OPTION]... [FILE]...'),
130 _('[OPTION]... [FILE]...'),
131 inferrepo=True)
131 inferrepo=True)
132 def add(ui, repo, *pats, **opts):
132 def add(ui, repo, *pats, **opts):
133 """add the specified files on the next commit
133 """add the specified files on the next commit
134
134
135 Schedule files to be version controlled and added to the
135 Schedule files to be version controlled and added to the
136 repository.
136 repository.
137
137
138 The files will be added to the repository at the next commit. To
138 The files will be added to the repository at the next commit. To
139 undo an add before that, see :hg:`forget`.
139 undo an add before that, see :hg:`forget`.
140
140
141 If no names are given, add all files to the repository (except
141 If no names are given, add all files to the repository (except
142 files matching ``.hgignore``).
142 files matching ``.hgignore``).
143
143
144 .. container:: verbose
144 .. container:: verbose
145
145
146 Examples:
146 Examples:
147
147
148 - New (unknown) files are added
148 - New (unknown) files are added
149 automatically by :hg:`add`::
149 automatically by :hg:`add`::
150
150
151 $ ls
151 $ ls
152 foo.c
152 foo.c
153 $ hg status
153 $ hg status
154 ? foo.c
154 ? foo.c
155 $ hg add
155 $ hg add
156 adding foo.c
156 adding foo.c
157 $ hg status
157 $ hg status
158 A foo.c
158 A foo.c
159
159
160 - Specific files to be added can be specified::
160 - Specific files to be added can be specified::
161
161
162 $ ls
162 $ ls
163 bar.c foo.c
163 bar.c foo.c
164 $ hg status
164 $ hg status
165 ? bar.c
165 ? bar.c
166 ? foo.c
166 ? foo.c
167 $ hg add bar.c
167 $ hg add bar.c
168 $ hg status
168 $ hg status
169 A bar.c
169 A bar.c
170 ? foo.c
170 ? foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
175 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
176 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
176 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
177 return rejected and 1 or 0
177 return rejected and 1 or 0
178
178
179 @command('addremove',
179 @command('addremove',
180 similarityopts + subrepoopts + walkopts + dryrunopts,
180 similarityopts + subrepoopts + walkopts + dryrunopts,
181 _('[OPTION]... [FILE]...'),
181 _('[OPTION]... [FILE]...'),
182 inferrepo=True)
182 inferrepo=True)
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 Unless names are given, new files are ignored if they match any of
189 Unless names are given, new files are ignored if they match any of
190 the patterns in ``.hgignore``. As with add, these changes take
190 the patterns in ``.hgignore``. As with add, these changes take
191 effect at the next commit.
191 effect at the next commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 .. container:: verbose
203 .. container:: verbose
204
204
205 Examples:
205 Examples:
206
206
207 - A number of files (bar.c and foo.c) are new,
207 - A number of files (bar.c and foo.c) are new,
208 while foobar.c has been removed (without using :hg:`remove`)
208 while foobar.c has been removed (without using :hg:`remove`)
209 from the repository::
209 from the repository::
210
210
211 $ ls
211 $ ls
212 bar.c foo.c
212 bar.c foo.c
213 $ hg status
213 $ hg status
214 ! foobar.c
214 ! foobar.c
215 ? bar.c
215 ? bar.c
216 ? foo.c
216 ? foo.c
217 $ hg addremove
217 $ hg addremove
218 adding bar.c
218 adding bar.c
219 adding foo.c
219 adding foo.c
220 removing foobar.c
220 removing foobar.c
221 $ hg status
221 $ hg status
222 A bar.c
222 A bar.c
223 A foo.c
223 A foo.c
224 R foobar.c
224 R foobar.c
225
225
226 - A file foobar.c was moved to foo.c without using :hg:`rename`.
226 - A file foobar.c was moved to foo.c without using :hg:`rename`.
227 Afterwards, it was edited slightly::
227 Afterwards, it was edited slightly::
228
228
229 $ ls
229 $ ls
230 foo.c
230 foo.c
231 $ hg status
231 $ hg status
232 ! foobar.c
232 ! foobar.c
233 ? foo.c
233 ? foo.c
234 $ hg addremove --similarity 90
234 $ hg addremove --similarity 90
235 removing foobar.c
235 removing foobar.c
236 adding foo.c
236 adding foo.c
237 recording removal of foobar.c as rename to foo.c (94% similar)
237 recording removal of foobar.c as rename to foo.c (94% similar)
238 $ hg status -C
238 $ hg status -C
239 A foo.c
239 A foo.c
240 foobar.c
240 foobar.c
241 R foobar.c
241 R foobar.c
242
242
243 Returns 0 if all files are successfully added.
243 Returns 0 if all files are successfully added.
244 """
244 """
245 opts = pycompat.byteskwargs(opts)
245 opts = pycompat.byteskwargs(opts)
246 try:
246 try:
247 sim = float(opts.get('similarity') or 100)
247 sim = float(opts.get('similarity') or 100)
248 except ValueError:
248 except ValueError:
249 raise error.Abort(_('similarity must be a number'))
249 raise error.Abort(_('similarity must be a number'))
250 if sim < 0 or sim > 100:
250 if sim < 0 or sim > 100:
251 raise error.Abort(_('similarity must be between 0 and 100'))
251 raise error.Abort(_('similarity must be between 0 and 100'))
252 matcher = scmutil.match(repo[None], pats, opts)
252 matcher = scmutil.match(repo[None], pats, opts)
253 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
253 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
254
254
255 @command('^annotate|blame',
255 @command('^annotate|blame',
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
256 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
257 ('', 'follow', None,
257 ('', 'follow', None,
258 _('follow copies/renames and list the filename (DEPRECATED)')),
258 _('follow copies/renames and list the filename (DEPRECATED)')),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
259 ('', 'no-follow', None, _("don't follow copies and renames")),
260 ('a', 'text', None, _('treat all files as text')),
260 ('a', 'text', None, _('treat all files as text')),
261 ('u', 'user', None, _('list the author (long with -v)')),
261 ('u', 'user', None, _('list the author (long with -v)')),
262 ('f', 'file', None, _('list the filename')),
262 ('f', 'file', None, _('list the filename')),
263 ('d', 'date', None, _('list the date (short with -q)')),
263 ('d', 'date', None, _('list the date (short with -q)')),
264 ('n', 'number', None, _('list the revision number (default)')),
264 ('n', 'number', None, _('list the revision number (default)')),
265 ('c', 'changeset', None, _('list the changeset')),
265 ('c', 'changeset', None, _('list the changeset')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
266 ('l', 'line-number', None, _('show line number at the first appearance')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
267 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
268 ] + diffwsopts + walkopts + formatteropts,
268 ] + diffwsopts + walkopts + formatteropts,
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
269 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
270 inferrepo=True)
270 inferrepo=True)
271 def annotate(ui, repo, *pats, **opts):
271 def annotate(ui, repo, *pats, **opts):
272 """show changeset information by line for each file
272 """show changeset information by line for each file
273
273
274 List changes in files, showing the revision id responsible for
274 List changes in files, showing the revision id responsible for
275 each line.
275 each line.
276
276
277 This command is useful for discovering when a change was made and
277 This command is useful for discovering when a change was made and
278 by whom.
278 by whom.
279
279
280 If you include --file, --user, or --date, the revision number is
280 If you include --file, --user, or --date, the revision number is
281 suppressed unless you also include --number.
281 suppressed unless you also include --number.
282
282
283 Without the -a/--text option, annotate will avoid processing files
283 Without the -a/--text option, annotate will avoid processing files
284 it detects as binary. With -a, annotate will annotate the file
284 it detects as binary. With -a, annotate will annotate the file
285 anyway, although the results will probably be neither useful
285 anyway, although the results will probably be neither useful
286 nor desirable.
286 nor desirable.
287
287
288 Returns 0 on success.
288 Returns 0 on success.
289 """
289 """
290 opts = pycompat.byteskwargs(opts)
290 opts = pycompat.byteskwargs(opts)
291 if not pats:
291 if not pats:
292 raise error.Abort(_('at least one filename or pattern is required'))
292 raise error.Abort(_('at least one filename or pattern is required'))
293
293
294 if opts.get('follow'):
294 if opts.get('follow'):
295 # --follow is deprecated and now just an alias for -f/--file
295 # --follow is deprecated and now just an alias for -f/--file
296 # to mimic the behavior of Mercurial before version 1.5
296 # to mimic the behavior of Mercurial before version 1.5
297 opts['file'] = True
297 opts['file'] = True
298
298
299 rev = opts.get('rev')
299 rev = opts.get('rev')
300 if rev:
300 if rev:
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
301 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
302 ctx = scmutil.revsingle(repo, rev)
302 ctx = scmutil.revsingle(repo, rev)
303
303
304 rootfm = ui.formatter('annotate', opts)
304 rootfm = ui.formatter('annotate', opts)
305 if ui.quiet:
305 if ui.quiet:
306 datefunc = dateutil.shortdate
306 datefunc = dateutil.shortdate
307 else:
307 else:
308 datefunc = dateutil.datestr
308 datefunc = dateutil.datestr
309 if ctx.rev() is None:
309 if ctx.rev() is None:
310 def hexfn(node):
310 def hexfn(node):
311 if node is None:
311 if node is None:
312 return None
312 return None
313 else:
313 else:
314 return rootfm.hexfunc(node)
314 return rootfm.hexfunc(node)
315 if opts.get('changeset'):
315 if opts.get('changeset'):
316 # omit "+" suffix which is appended to node hex
316 # omit "+" suffix which is appended to node hex
317 def formatrev(rev):
317 def formatrev(rev):
318 if rev is None:
318 if rev is None:
319 return '%d' % ctx.p1().rev()
319 return '%d' % ctx.p1().rev()
320 else:
320 else:
321 return '%d' % rev
321 return '%d' % rev
322 else:
322 else:
323 def formatrev(rev):
323 def formatrev(rev):
324 if rev is None:
324 if rev is None:
325 return '%d+' % ctx.p1().rev()
325 return '%d+' % ctx.p1().rev()
326 else:
326 else:
327 return '%d ' % rev
327 return '%d ' % rev
328 def formathex(hex):
328 def formathex(hex):
329 if hex is None:
329 if hex is None:
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
330 return '%s+' % rootfm.hexfunc(ctx.p1().node())
331 else:
331 else:
332 return '%s ' % hex
332 return '%s ' % hex
333 else:
333 else:
334 hexfn = rootfm.hexfunc
334 hexfn = rootfm.hexfunc
335 formatrev = formathex = pycompat.bytestr
335 formatrev = formathex = pycompat.bytestr
336
336
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
337 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
338 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
339 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
340 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
341 ('file', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
342 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
343 ]
343 ]
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
344 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
345
345
346 if (not opts.get('user') and not opts.get('changeset')
346 if (not opts.get('user') and not opts.get('changeset')
347 and not opts.get('date') and not opts.get('file')):
347 and not opts.get('date') and not opts.get('file')):
348 opts['number'] = True
348 opts['number'] = True
349
349
350 linenumber = opts.get('line_number') is not None
350 linenumber = opts.get('line_number') is not None
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
351 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
352 raise error.Abort(_('at least one of -n/-c is required for -l'))
353
353
354 ui.pager('annotate')
354 ui.pager('annotate')
355
355
356 if rootfm.isplain():
356 if rootfm.isplain():
357 def makefunc(get, fmt):
357 def makefunc(get, fmt):
358 return lambda x: fmt(get(x))
358 return lambda x: fmt(get(x))
359 else:
359 else:
360 def makefunc(get, fmt):
360 def makefunc(get, fmt):
361 return get
361 return get
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
362 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
363 if opts.get(op)]
363 if opts.get(op)]
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
364 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
365 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
366 if opts.get(op))
366 if opts.get(op))
367
367
368 def bad(x, y):
368 def bad(x, y):
369 raise error.Abort("%s: %s" % (x, y))
369 raise error.Abort("%s: %s" % (x, y))
370
370
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
371 m = scmutil.match(ctx, pats, opts, badfn=bad)
372
372
373 follow = not opts.get('no_follow')
373 follow = not opts.get('no_follow')
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
374 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
375 whitespace=True)
375 whitespace=True)
376 skiprevs = opts.get('skip')
376 skiprevs = opts.get('skip')
377 if skiprevs:
377 if skiprevs:
378 skiprevs = scmutil.revrange(repo, skiprevs)
378 skiprevs = scmutil.revrange(repo, skiprevs)
379
379
380 for abs in ctx.walk(m):
380 for abs in ctx.walk(m):
381 fctx = ctx[abs]
381 fctx = ctx[abs]
382 rootfm.startitem()
382 rootfm.startitem()
383 rootfm.data(abspath=abs, path=m.rel(abs))
383 rootfm.data(abspath=abs, path=m.rel(abs))
384 if not opts.get('text') and fctx.isbinary():
384 if not opts.get('text') and fctx.isbinary():
385 rootfm.plain(_("%s: binary file\n")
385 rootfm.plain(_("%s: binary file\n")
386 % ((pats and m.rel(abs)) or abs))
386 % ((pats and m.rel(abs)) or abs))
387 continue
387 continue
388
388
389 fm = rootfm.nested('lines')
389 fm = rootfm.nested('lines')
390 lines = fctx.annotate(follow=follow, linenumber=linenumber,
390 lines = fctx.annotate(follow=follow, linenumber=linenumber,
391 skiprevs=skiprevs, diffopts=diffopts)
391 skiprevs=skiprevs, diffopts=diffopts)
392 if not lines:
392 if not lines:
393 fm.end()
393 fm.end()
394 continue
394 continue
395 formats = []
395 formats = []
396 pieces = []
396 pieces = []
397
397
398 for f, sep in funcmap:
398 for f, sep in funcmap:
399 l = [f(n) for n, dummy in lines]
399 l = [f(n) for n, dummy in lines]
400 if fm.isplain():
400 if fm.isplain():
401 sizes = [encoding.colwidth(x) for x in l]
401 sizes = [encoding.colwidth(x) for x in l]
402 ml = max(sizes)
402 ml = max(sizes)
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
403 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
404 else:
404 else:
405 formats.append(['%s' for x in l])
405 formats.append(['%s' for x in l])
406 pieces.append(l)
406 pieces.append(l)
407
407
408 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
408 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
409 fm.startitem()
409 fm.startitem()
410 fm.write(fields, "".join(f), *p)
410 fm.write(fields, "".join(f), *p)
411 if l[0].skip:
411 if l[0].skip:
412 fmt = "* %s"
412 fmt = "* %s"
413 else:
413 else:
414 fmt = ": %s"
414 fmt = ": %s"
415 fm.write('line', fmt, l[1])
415 fm.write('line', fmt, l[1])
416
416
417 if not lines[-1][1].endswith('\n'):
417 if not lines[-1][1].endswith('\n'):
418 fm.plain('\n')
418 fm.plain('\n')
419 fm.end()
419 fm.end()
420
420
421 rootfm.end()
421 rootfm.end()
422
422
423 @command('archive',
423 @command('archive',
424 [('', 'no-decode', None, _('do not pass files through decoders')),
424 [('', 'no-decode', None, _('do not pass files through decoders')),
425 ('p', 'prefix', '', _('directory prefix for files in archive'),
425 ('p', 'prefix', '', _('directory prefix for files in archive'),
426 _('PREFIX')),
426 _('PREFIX')),
427 ('r', 'rev', '', _('revision to distribute'), _('REV')),
427 ('r', 'rev', '', _('revision to distribute'), _('REV')),
428 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
428 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
429 ] + subrepoopts + walkopts,
429 ] + subrepoopts + walkopts,
430 _('[OPTION]... DEST'))
430 _('[OPTION]... DEST'))
431 def archive(ui, repo, dest, **opts):
431 def archive(ui, repo, dest, **opts):
432 '''create an unversioned archive of a repository revision
432 '''create an unversioned archive of a repository revision
433
433
434 By default, the revision used is the parent of the working
434 By default, the revision used is the parent of the working
435 directory; use -r/--rev to specify a different revision.
435 directory; use -r/--rev to specify a different revision.
436
436
437 The archive type is automatically detected based on file
437 The archive type is automatically detected based on file
438 extension (to override, use -t/--type).
438 extension (to override, use -t/--type).
439
439
440 .. container:: verbose
440 .. container:: verbose
441
441
442 Examples:
442 Examples:
443
443
444 - create a zip file containing the 1.0 release::
444 - create a zip file containing the 1.0 release::
445
445
446 hg archive -r 1.0 project-1.0.zip
446 hg archive -r 1.0 project-1.0.zip
447
447
448 - create a tarball excluding .hg files::
448 - create a tarball excluding .hg files::
449
449
450 hg archive project.tar.gz -X ".hg*"
450 hg archive project.tar.gz -X ".hg*"
451
451
452 Valid types are:
452 Valid types are:
453
453
454 :``files``: a directory full of files (default)
454 :``files``: a directory full of files (default)
455 :``tar``: tar archive, uncompressed
455 :``tar``: tar archive, uncompressed
456 :``tbz2``: tar archive, compressed using bzip2
456 :``tbz2``: tar archive, compressed using bzip2
457 :``tgz``: tar archive, compressed using gzip
457 :``tgz``: tar archive, compressed using gzip
458 :``uzip``: zip archive, uncompressed
458 :``uzip``: zip archive, uncompressed
459 :``zip``: zip archive, compressed using deflate
459 :``zip``: zip archive, compressed using deflate
460
460
461 The exact name of the destination archive or directory is given
461 The exact name of the destination archive or directory is given
462 using a format string; see :hg:`help export` for details.
462 using a format string; see :hg:`help export` for details.
463
463
464 Each member added to an archive file has a directory prefix
464 Each member added to an archive file has a directory prefix
465 prepended. Use -p/--prefix to specify a format string for the
465 prepended. Use -p/--prefix to specify a format string for the
466 prefix. The default is the basename of the archive, with suffixes
466 prefix. The default is the basename of the archive, with suffixes
467 removed.
467 removed.
468
468
469 Returns 0 on success.
469 Returns 0 on success.
470 '''
470 '''
471
471
472 opts = pycompat.byteskwargs(opts)
472 opts = pycompat.byteskwargs(opts)
473 rev = opts.get('rev')
473 rev = opts.get('rev')
474 if rev:
474 if rev:
475 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
475 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
476 ctx = scmutil.revsingle(repo, rev)
476 ctx = scmutil.revsingle(repo, rev)
477 if not ctx:
477 if not ctx:
478 raise error.Abort(_('no working directory: please specify a revision'))
478 raise error.Abort(_('no working directory: please specify a revision'))
479 node = ctx.node()
479 node = ctx.node()
480 dest = cmdutil.makefilename(ctx, dest)
480 dest = cmdutil.makefilename(ctx, dest)
481 if os.path.realpath(dest) == repo.root:
481 if os.path.realpath(dest) == repo.root:
482 raise error.Abort(_('repository root cannot be destination'))
482 raise error.Abort(_('repository root cannot be destination'))
483
483
484 kind = opts.get('type') or archival.guesskind(dest) or 'files'
484 kind = opts.get('type') or archival.guesskind(dest) or 'files'
485 prefix = opts.get('prefix')
485 prefix = opts.get('prefix')
486
486
487 if dest == '-':
487 if dest == '-':
488 if kind == 'files':
488 if kind == 'files':
489 raise error.Abort(_('cannot archive plain files to stdout'))
489 raise error.Abort(_('cannot archive plain files to stdout'))
490 dest = cmdutil.makefileobj(ctx, dest)
490 dest = cmdutil.makefileobj(ctx, dest)
491 if not prefix:
491 if not prefix:
492 prefix = os.path.basename(repo.root) + '-%h'
492 prefix = os.path.basename(repo.root) + '-%h'
493
493
494 prefix = cmdutil.makefilename(ctx, prefix)
494 prefix = cmdutil.makefilename(ctx, prefix)
495 match = scmutil.match(ctx, [], opts)
495 match = scmutil.match(ctx, [], opts)
496 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
496 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
497 match, prefix, subrepos=opts.get('subrepos'))
497 match, prefix, subrepos=opts.get('subrepos'))
498
498
499 @command('backout',
499 @command('backout',
500 [('', 'merge', None, _('merge with old dirstate parent after backout')),
500 [('', 'merge', None, _('merge with old dirstate parent after backout')),
501 ('', 'commit', None,
501 ('', 'commit', None,
502 _('commit if no conflicts were encountered (DEPRECATED)')),
502 _('commit if no conflicts were encountered (DEPRECATED)')),
503 ('', 'no-commit', None, _('do not commit')),
503 ('', 'no-commit', None, _('do not commit')),
504 ('', 'parent', '',
504 ('', 'parent', '',
505 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
505 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
506 ('r', 'rev', '', _('revision to backout'), _('REV')),
506 ('r', 'rev', '', _('revision to backout'), _('REV')),
507 ('e', 'edit', False, _('invoke editor on commit messages')),
507 ('e', 'edit', False, _('invoke editor on commit messages')),
508 ] + mergetoolopts + walkopts + commitopts + commitopts2,
508 ] + mergetoolopts + walkopts + commitopts + commitopts2,
509 _('[OPTION]... [-r] REV'))
509 _('[OPTION]... [-r] REV'))
510 def backout(ui, repo, node=None, rev=None, **opts):
510 def backout(ui, repo, node=None, rev=None, **opts):
511 '''reverse effect of earlier changeset
511 '''reverse effect of earlier changeset
512
512
513 Prepare a new changeset with the effect of REV undone in the
513 Prepare a new changeset with the effect of REV undone in the
514 current working directory. If no conflicts were encountered,
514 current working directory. If no conflicts were encountered,
515 it will be committed immediately.
515 it will be committed immediately.
516
516
517 If REV is the parent of the working directory, then this new changeset
517 If REV is the parent of the working directory, then this new changeset
518 is committed automatically (unless --no-commit is specified).
518 is committed automatically (unless --no-commit is specified).
519
519
520 .. note::
520 .. note::
521
521
522 :hg:`backout` cannot be used to fix either an unwanted or
522 :hg:`backout` cannot be used to fix either an unwanted or
523 incorrect merge.
523 incorrect merge.
524
524
525 .. container:: verbose
525 .. container:: verbose
526
526
527 Examples:
527 Examples:
528
528
529 - Reverse the effect of the parent of the working directory.
529 - Reverse the effect of the parent of the working directory.
530 This backout will be committed immediately::
530 This backout will be committed immediately::
531
531
532 hg backout -r .
532 hg backout -r .
533
533
534 - Reverse the effect of previous bad revision 23::
534 - Reverse the effect of previous bad revision 23::
535
535
536 hg backout -r 23
536 hg backout -r 23
537
537
538 - Reverse the effect of previous bad revision 23 and
538 - Reverse the effect of previous bad revision 23 and
539 leave changes uncommitted::
539 leave changes uncommitted::
540
540
541 hg backout -r 23 --no-commit
541 hg backout -r 23 --no-commit
542 hg commit -m "Backout revision 23"
542 hg commit -m "Backout revision 23"
543
543
544 By default, the pending changeset will have one parent,
544 By default, the pending changeset will have one parent,
545 maintaining a linear history. With --merge, the pending
545 maintaining a linear history. With --merge, the pending
546 changeset will instead have two parents: the old parent of the
546 changeset will instead have two parents: the old parent of the
547 working directory and a new child of REV that simply undoes REV.
547 working directory and a new child of REV that simply undoes REV.
548
548
549 Before version 1.7, the behavior without --merge was equivalent
549 Before version 1.7, the behavior without --merge was equivalent
550 to specifying --merge followed by :hg:`update --clean .` to
550 to specifying --merge followed by :hg:`update --clean .` to
551 cancel the merge and leave the child of REV as a head to be
551 cancel the merge and leave the child of REV as a head to be
552 merged separately.
552 merged separately.
553
553
554 See :hg:`help dates` for a list of formats valid for -d/--date.
554 See :hg:`help dates` for a list of formats valid for -d/--date.
555
555
556 See :hg:`help revert` for a way to restore files to the state
556 See :hg:`help revert` for a way to restore files to the state
557 of another revision.
557 of another revision.
558
558
559 Returns 0 on success, 1 if nothing to backout or there are unresolved
559 Returns 0 on success, 1 if nothing to backout or there are unresolved
560 files.
560 files.
561 '''
561 '''
562 wlock = lock = None
562 wlock = lock = None
563 try:
563 try:
564 wlock = repo.wlock()
564 wlock = repo.wlock()
565 lock = repo.lock()
565 lock = repo.lock()
566 return _dobackout(ui, repo, node, rev, **opts)
566 return _dobackout(ui, repo, node, rev, **opts)
567 finally:
567 finally:
568 release(lock, wlock)
568 release(lock, wlock)
569
569
570 def _dobackout(ui, repo, node=None, rev=None, **opts):
570 def _dobackout(ui, repo, node=None, rev=None, **opts):
571 opts = pycompat.byteskwargs(opts)
571 opts = pycompat.byteskwargs(opts)
572 if opts.get('commit') and opts.get('no_commit'):
572 if opts.get('commit') and opts.get('no_commit'):
573 raise error.Abort(_("cannot use --commit with --no-commit"))
573 raise error.Abort(_("cannot use --commit with --no-commit"))
574 if opts.get('merge') and opts.get('no_commit'):
574 if opts.get('merge') and opts.get('no_commit'):
575 raise error.Abort(_("cannot use --merge with --no-commit"))
575 raise error.Abort(_("cannot use --merge with --no-commit"))
576
576
577 if rev and node:
577 if rev and node:
578 raise error.Abort(_("please specify just one revision"))
578 raise error.Abort(_("please specify just one revision"))
579
579
580 if not rev:
580 if not rev:
581 rev = node
581 rev = node
582
582
583 if not rev:
583 if not rev:
584 raise error.Abort(_("please specify a revision to backout"))
584 raise error.Abort(_("please specify a revision to backout"))
585
585
586 date = opts.get('date')
586 date = opts.get('date')
587 if date:
587 if date:
588 opts['date'] = dateutil.parsedate(date)
588 opts['date'] = dateutil.parsedate(date)
589
589
590 cmdutil.checkunfinished(repo)
590 cmdutil.checkunfinished(repo)
591 cmdutil.bailifchanged(repo)
591 cmdutil.bailifchanged(repo)
592 node = scmutil.revsingle(repo, rev).node()
592 node = scmutil.revsingle(repo, rev).node()
593
593
594 op1, op2 = repo.dirstate.parents()
594 op1, op2 = repo.dirstate.parents()
595 if not repo.changelog.isancestor(node, op1):
595 if not repo.changelog.isancestor(node, op1):
596 raise error.Abort(_('cannot backout change that is not an ancestor'))
596 raise error.Abort(_('cannot backout change that is not an ancestor'))
597
597
598 p1, p2 = repo.changelog.parents(node)
598 p1, p2 = repo.changelog.parents(node)
599 if p1 == nullid:
599 if p1 == nullid:
600 raise error.Abort(_('cannot backout a change with no parents'))
600 raise error.Abort(_('cannot backout a change with no parents'))
601 if p2 != nullid:
601 if p2 != nullid:
602 if not opts.get('parent'):
602 if not opts.get('parent'):
603 raise error.Abort(_('cannot backout a merge changeset'))
603 raise error.Abort(_('cannot backout a merge changeset'))
604 p = repo.lookup(opts['parent'])
604 p = repo.lookup(opts['parent'])
605 if p not in (p1, p2):
605 if p not in (p1, p2):
606 raise error.Abort(_('%s is not a parent of %s') %
606 raise error.Abort(_('%s is not a parent of %s') %
607 (short(p), short(node)))
607 (short(p), short(node)))
608 parent = p
608 parent = p
609 else:
609 else:
610 if opts.get('parent'):
610 if opts.get('parent'):
611 raise error.Abort(_('cannot use --parent on non-merge changeset'))
611 raise error.Abort(_('cannot use --parent on non-merge changeset'))
612 parent = p1
612 parent = p1
613
613
614 # the backout should appear on the same branch
614 # the backout should appear on the same branch
615 branch = repo.dirstate.branch()
615 branch = repo.dirstate.branch()
616 bheads = repo.branchheads(branch)
616 bheads = repo.branchheads(branch)
617 rctx = scmutil.revsingle(repo, hex(parent))
617 rctx = scmutil.revsingle(repo, hex(parent))
618 if not opts.get('merge') and op1 != node:
618 if not opts.get('merge') and op1 != node:
619 dsguard = dirstateguard.dirstateguard(repo, 'backout')
619 dsguard = dirstateguard.dirstateguard(repo, 'backout')
620 try:
620 try:
621 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
621 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
622 'backout')
622 'backout')
623 stats = mergemod.update(repo, parent, True, True, node, False)
623 stats = mergemod.update(repo, parent, True, True, node, False)
624 repo.setparents(op1, op2)
624 repo.setparents(op1, op2)
625 dsguard.close()
625 dsguard.close()
626 hg._showstats(repo, stats)
626 hg._showstats(repo, stats)
627 if stats[3]:
627 if stats[3]:
628 repo.ui.status(_("use 'hg resolve' to retry unresolved "
628 repo.ui.status(_("use 'hg resolve' to retry unresolved "
629 "file merges\n"))
629 "file merges\n"))
630 return 1
630 return 1
631 finally:
631 finally:
632 ui.setconfig('ui', 'forcemerge', '', '')
632 ui.setconfig('ui', 'forcemerge', '', '')
633 lockmod.release(dsguard)
633 lockmod.release(dsguard)
634 else:
634 else:
635 hg.clean(repo, node, show_stats=False)
635 hg.clean(repo, node, show_stats=False)
636 repo.dirstate.setbranch(branch)
636 repo.dirstate.setbranch(branch)
637 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
637 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
638
638
639 if opts.get('no_commit'):
639 if opts.get('no_commit'):
640 msg = _("changeset %s backed out, "
640 msg = _("changeset %s backed out, "
641 "don't forget to commit.\n")
641 "don't forget to commit.\n")
642 ui.status(msg % short(node))
642 ui.status(msg % short(node))
643 return 0
643 return 0
644
644
645 def commitfunc(ui, repo, message, match, opts):
645 def commitfunc(ui, repo, message, match, opts):
646 editform = 'backout'
646 editform = 'backout'
647 e = cmdutil.getcommiteditor(editform=editform,
647 e = cmdutil.getcommiteditor(editform=editform,
648 **pycompat.strkwargs(opts))
648 **pycompat.strkwargs(opts))
649 if not message:
649 if not message:
650 # we don't translate commit messages
650 # we don't translate commit messages
651 message = "Backed out changeset %s" % short(node)
651 message = "Backed out changeset %s" % short(node)
652 e = cmdutil.getcommiteditor(edit=True, editform=editform)
652 e = cmdutil.getcommiteditor(edit=True, editform=editform)
653 return repo.commit(message, opts.get('user'), opts.get('date'),
653 return repo.commit(message, opts.get('user'), opts.get('date'),
654 match, editor=e)
654 match, editor=e)
655 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
655 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
656 if not newnode:
656 if not newnode:
657 ui.status(_("nothing changed\n"))
657 ui.status(_("nothing changed\n"))
658 return 1
658 return 1
659 cmdutil.commitstatus(repo, newnode, branch, bheads)
659 cmdutil.commitstatus(repo, newnode, branch, bheads)
660
660
661 def nice(node):
661 def nice(node):
662 return '%d:%s' % (repo.changelog.rev(node), short(node))
662 return '%d:%s' % (repo.changelog.rev(node), short(node))
663 ui.status(_('changeset %s backs out changeset %s\n') %
663 ui.status(_('changeset %s backs out changeset %s\n') %
664 (nice(repo.changelog.tip()), nice(node)))
664 (nice(repo.changelog.tip()), nice(node)))
665 if opts.get('merge') and op1 != node:
665 if opts.get('merge') and op1 != node:
666 hg.clean(repo, op1, show_stats=False)
666 hg.clean(repo, op1, show_stats=False)
667 ui.status(_('merging with changeset %s\n')
667 ui.status(_('merging with changeset %s\n')
668 % nice(repo.changelog.tip()))
668 % nice(repo.changelog.tip()))
669 try:
669 try:
670 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
670 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
671 'backout')
671 'backout')
672 return hg.merge(repo, hex(repo.changelog.tip()))
672 return hg.merge(repo, hex(repo.changelog.tip()))
673 finally:
673 finally:
674 ui.setconfig('ui', 'forcemerge', '', '')
674 ui.setconfig('ui', 'forcemerge', '', '')
675 return 0
675 return 0
676
676
677 @command('bisect',
677 @command('bisect',
678 [('r', 'reset', False, _('reset bisect state')),
678 [('r', 'reset', False, _('reset bisect state')),
679 ('g', 'good', False, _('mark changeset good')),
679 ('g', 'good', False, _('mark changeset good')),
680 ('b', 'bad', False, _('mark changeset bad')),
680 ('b', 'bad', False, _('mark changeset bad')),
681 ('s', 'skip', False, _('skip testing changeset')),
681 ('s', 'skip', False, _('skip testing changeset')),
682 ('e', 'extend', False, _('extend the bisect range')),
682 ('e', 'extend', False, _('extend the bisect range')),
683 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
683 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
684 ('U', 'noupdate', False, _('do not update to target'))],
684 ('U', 'noupdate', False, _('do not update to target'))],
685 _("[-gbsr] [-U] [-c CMD] [REV]"))
685 _("[-gbsr] [-U] [-c CMD] [REV]"))
686 def bisect(ui, repo, rev=None, extra=None, command=None,
686 def bisect(ui, repo, rev=None, extra=None, command=None,
687 reset=None, good=None, bad=None, skip=None, extend=None,
687 reset=None, good=None, bad=None, skip=None, extend=None,
688 noupdate=None):
688 noupdate=None):
689 """subdivision search of changesets
689 """subdivision search of changesets
690
690
691 This command helps to find changesets which introduce problems. To
691 This command helps to find changesets which introduce problems. To
692 use, mark the earliest changeset you know exhibits the problem as
692 use, mark the earliest changeset you know exhibits the problem as
693 bad, then mark the latest changeset which is free from the problem
693 bad, then mark the latest changeset which is free from the problem
694 as good. Bisect will update your working directory to a revision
694 as good. Bisect will update your working directory to a revision
695 for testing (unless the -U/--noupdate option is specified). Once
695 for testing (unless the -U/--noupdate option is specified). Once
696 you have performed tests, mark the working directory as good or
696 you have performed tests, mark the working directory as good or
697 bad, and bisect will either update to another candidate changeset
697 bad, and bisect will either update to another candidate changeset
698 or announce that it has found the bad revision.
698 or announce that it has found the bad revision.
699
699
700 As a shortcut, you can also use the revision argument to mark a
700 As a shortcut, you can also use the revision argument to mark a
701 revision as good or bad without checking it out first.
701 revision as good or bad without checking it out first.
702
702
703 If you supply a command, it will be used for automatic bisection.
703 If you supply a command, it will be used for automatic bisection.
704 The environment variable HG_NODE will contain the ID of the
704 The environment variable HG_NODE will contain the ID of the
705 changeset being tested. The exit status of the command will be
705 changeset being tested. The exit status of the command will be
706 used to mark revisions as good or bad: status 0 means good, 125
706 used to mark revisions as good or bad: status 0 means good, 125
707 means to skip the revision, 127 (command not found) will abort the
707 means to skip the revision, 127 (command not found) will abort the
708 bisection, and any other non-zero exit status means the revision
708 bisection, and any other non-zero exit status means the revision
709 is bad.
709 is bad.
710
710
711 .. container:: verbose
711 .. container:: verbose
712
712
713 Some examples:
713 Some examples:
714
714
715 - start a bisection with known bad revision 34, and good revision 12::
715 - start a bisection with known bad revision 34, and good revision 12::
716
716
717 hg bisect --bad 34
717 hg bisect --bad 34
718 hg bisect --good 12
718 hg bisect --good 12
719
719
720 - advance the current bisection by marking current revision as good or
720 - advance the current bisection by marking current revision as good or
721 bad::
721 bad::
722
722
723 hg bisect --good
723 hg bisect --good
724 hg bisect --bad
724 hg bisect --bad
725
725
726 - mark the current revision, or a known revision, to be skipped (e.g. if
726 - mark the current revision, or a known revision, to be skipped (e.g. if
727 that revision is not usable because of another issue)::
727 that revision is not usable because of another issue)::
728
728
729 hg bisect --skip
729 hg bisect --skip
730 hg bisect --skip 23
730 hg bisect --skip 23
731
731
732 - skip all revisions that do not touch directories ``foo`` or ``bar``::
732 - skip all revisions that do not touch directories ``foo`` or ``bar``::
733
733
734 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
734 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
735
735
736 - forget the current bisection::
736 - forget the current bisection::
737
737
738 hg bisect --reset
738 hg bisect --reset
739
739
740 - use 'make && make tests' to automatically find the first broken
740 - use 'make && make tests' to automatically find the first broken
741 revision::
741 revision::
742
742
743 hg bisect --reset
743 hg bisect --reset
744 hg bisect --bad 34
744 hg bisect --bad 34
745 hg bisect --good 12
745 hg bisect --good 12
746 hg bisect --command "make && make tests"
746 hg bisect --command "make && make tests"
747
747
748 - see all changesets whose states are already known in the current
748 - see all changesets whose states are already known in the current
749 bisection::
749 bisection::
750
750
751 hg log -r "bisect(pruned)"
751 hg log -r "bisect(pruned)"
752
752
753 - see the changeset currently being bisected (especially useful
753 - see the changeset currently being bisected (especially useful
754 if running with -U/--noupdate)::
754 if running with -U/--noupdate)::
755
755
756 hg log -r "bisect(current)"
756 hg log -r "bisect(current)"
757
757
758 - see all changesets that took part in the current bisection::
758 - see all changesets that took part in the current bisection::
759
759
760 hg log -r "bisect(range)"
760 hg log -r "bisect(range)"
761
761
762 - you can even get a nice graph::
762 - you can even get a nice graph::
763
763
764 hg log --graph -r "bisect(range)"
764 hg log --graph -r "bisect(range)"
765
765
766 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
766 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
767
767
768 Returns 0 on success.
768 Returns 0 on success.
769 """
769 """
770 # backward compatibility
770 # backward compatibility
771 if rev in "good bad reset init".split():
771 if rev in "good bad reset init".split():
772 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
772 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
773 cmd, rev, extra = rev, extra, None
773 cmd, rev, extra = rev, extra, None
774 if cmd == "good":
774 if cmd == "good":
775 good = True
775 good = True
776 elif cmd == "bad":
776 elif cmd == "bad":
777 bad = True
777 bad = True
778 else:
778 else:
779 reset = True
779 reset = True
780 elif extra:
780 elif extra:
781 raise error.Abort(_('incompatible arguments'))
781 raise error.Abort(_('incompatible arguments'))
782
782
783 incompatibles = {
783 incompatibles = {
784 '--bad': bad,
784 '--bad': bad,
785 '--command': bool(command),
785 '--command': bool(command),
786 '--extend': extend,
786 '--extend': extend,
787 '--good': good,
787 '--good': good,
788 '--reset': reset,
788 '--reset': reset,
789 '--skip': skip,
789 '--skip': skip,
790 }
790 }
791
791
792 enabled = [x for x in incompatibles if incompatibles[x]]
792 enabled = [x for x in incompatibles if incompatibles[x]]
793
793
794 if len(enabled) > 1:
794 if len(enabled) > 1:
795 raise error.Abort(_('%s and %s are incompatible') %
795 raise error.Abort(_('%s and %s are incompatible') %
796 tuple(sorted(enabled)[0:2]))
796 tuple(sorted(enabled)[0:2]))
797
797
798 if reset:
798 if reset:
799 hbisect.resetstate(repo)
799 hbisect.resetstate(repo)
800 return
800 return
801
801
802 state = hbisect.load_state(repo)
802 state = hbisect.load_state(repo)
803
803
804 # update state
804 # update state
805 if good or bad or skip:
805 if good or bad or skip:
806 if rev:
806 if rev:
807 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
807 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
808 else:
808 else:
809 nodes = [repo.lookup('.')]
809 nodes = [repo.lookup('.')]
810 if good:
810 if good:
811 state['good'] += nodes
811 state['good'] += nodes
812 elif bad:
812 elif bad:
813 state['bad'] += nodes
813 state['bad'] += nodes
814 elif skip:
814 elif skip:
815 state['skip'] += nodes
815 state['skip'] += nodes
816 hbisect.save_state(repo, state)
816 hbisect.save_state(repo, state)
817 if not (state['good'] and state['bad']):
817 if not (state['good'] and state['bad']):
818 return
818 return
819
819
820 def mayupdate(repo, node, show_stats=True):
820 def mayupdate(repo, node, show_stats=True):
821 """common used update sequence"""
821 """common used update sequence"""
822 if noupdate:
822 if noupdate:
823 return
823 return
824 cmdutil.checkunfinished(repo)
824 cmdutil.checkunfinished(repo)
825 cmdutil.bailifchanged(repo)
825 cmdutil.bailifchanged(repo)
826 return hg.clean(repo, node, show_stats=show_stats)
826 return hg.clean(repo, node, show_stats=show_stats)
827
827
828 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
828 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
829
829
830 if command:
830 if command:
831 changesets = 1
831 changesets = 1
832 if noupdate:
832 if noupdate:
833 try:
833 try:
834 node = state['current'][0]
834 node = state['current'][0]
835 except LookupError:
835 except LookupError:
836 raise error.Abort(_('current bisect revision is unknown - '
836 raise error.Abort(_('current bisect revision is unknown - '
837 'start a new bisect to fix'))
837 'start a new bisect to fix'))
838 else:
838 else:
839 node, p2 = repo.dirstate.parents()
839 node, p2 = repo.dirstate.parents()
840 if p2 != nullid:
840 if p2 != nullid:
841 raise error.Abort(_('current bisect revision is a merge'))
841 raise error.Abort(_('current bisect revision is a merge'))
842 if rev:
842 if rev:
843 node = repo[scmutil.revsingle(repo, rev, node)].node()
843 node = repo[scmutil.revsingle(repo, rev, node)].node()
844 try:
844 try:
845 while changesets:
845 while changesets:
846 # update state
846 # update state
847 state['current'] = [node]
847 state['current'] = [node]
848 hbisect.save_state(repo, state)
848 hbisect.save_state(repo, state)
849 status = ui.system(command, environ={'HG_NODE': hex(node)},
849 status = ui.system(command, environ={'HG_NODE': hex(node)},
850 blockedtag='bisect_check')
850 blockedtag='bisect_check')
851 if status == 125:
851 if status == 125:
852 transition = "skip"
852 transition = "skip"
853 elif status == 0:
853 elif status == 0:
854 transition = "good"
854 transition = "good"
855 # status < 0 means process was killed
855 # status < 0 means process was killed
856 elif status == 127:
856 elif status == 127:
857 raise error.Abort(_("failed to execute %s") % command)
857 raise error.Abort(_("failed to execute %s") % command)
858 elif status < 0:
858 elif status < 0:
859 raise error.Abort(_("%s killed") % command)
859 raise error.Abort(_("%s killed") % command)
860 else:
860 else:
861 transition = "bad"
861 transition = "bad"
862 state[transition].append(node)
862 state[transition].append(node)
863 ctx = repo[node]
863 ctx = repo[node]
864 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
864 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
865 transition))
865 transition))
866 hbisect.checkstate(state)
866 hbisect.checkstate(state)
867 # bisect
867 # bisect
868 nodes, changesets, bgood = hbisect.bisect(repo, state)
868 nodes, changesets, bgood = hbisect.bisect(repo, state)
869 # update to next check
869 # update to next check
870 node = nodes[0]
870 node = nodes[0]
871 mayupdate(repo, node, show_stats=False)
871 mayupdate(repo, node, show_stats=False)
872 finally:
872 finally:
873 state['current'] = [node]
873 state['current'] = [node]
874 hbisect.save_state(repo, state)
874 hbisect.save_state(repo, state)
875 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
875 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
876 return
876 return
877
877
878 hbisect.checkstate(state)
878 hbisect.checkstate(state)
879
879
880 # actually bisect
880 # actually bisect
881 nodes, changesets, good = hbisect.bisect(repo, state)
881 nodes, changesets, good = hbisect.bisect(repo, state)
882 if extend:
882 if extend:
883 if not changesets:
883 if not changesets:
884 extendnode = hbisect.extendrange(repo, state, nodes, good)
884 extendnode = hbisect.extendrange(repo, state, nodes, good)
885 if extendnode is not None:
885 if extendnode is not None:
886 ui.write(_("Extending search to changeset %d:%s\n")
886 ui.write(_("Extending search to changeset %d:%s\n")
887 % (extendnode.rev(), extendnode))
887 % (extendnode.rev(), extendnode))
888 state['current'] = [extendnode.node()]
888 state['current'] = [extendnode.node()]
889 hbisect.save_state(repo, state)
889 hbisect.save_state(repo, state)
890 return mayupdate(repo, extendnode.node())
890 return mayupdate(repo, extendnode.node())
891 raise error.Abort(_("nothing to extend"))
891 raise error.Abort(_("nothing to extend"))
892
892
893 if changesets == 0:
893 if changesets == 0:
894 hbisect.printresult(ui, repo, state, displayer, nodes, good)
894 hbisect.printresult(ui, repo, state, displayer, nodes, good)
895 else:
895 else:
896 assert len(nodes) == 1 # only a single node can be tested next
896 assert len(nodes) == 1 # only a single node can be tested next
897 node = nodes[0]
897 node = nodes[0]
898 # compute the approximate number of remaining tests
898 # compute the approximate number of remaining tests
899 tests, size = 0, 2
899 tests, size = 0, 2
900 while size <= changesets:
900 while size <= changesets:
901 tests, size = tests + 1, size * 2
901 tests, size = tests + 1, size * 2
902 rev = repo.changelog.rev(node)
902 rev = repo.changelog.rev(node)
903 ui.write(_("Testing changeset %d:%s "
903 ui.write(_("Testing changeset %d:%s "
904 "(%d changesets remaining, ~%d tests)\n")
904 "(%d changesets remaining, ~%d tests)\n")
905 % (rev, short(node), changesets, tests))
905 % (rev, short(node), changesets, tests))
906 state['current'] = [node]
906 state['current'] = [node]
907 hbisect.save_state(repo, state)
907 hbisect.save_state(repo, state)
908 return mayupdate(repo, node)
908 return mayupdate(repo, node)
909
909
910 @command('bookmarks|bookmark',
910 @command('bookmarks|bookmark',
911 [('f', 'force', False, _('force')),
911 [('f', 'force', False, _('force')),
912 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
912 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
913 ('d', 'delete', False, _('delete a given bookmark')),
913 ('d', 'delete', False, _('delete a given bookmark')),
914 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
914 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
915 ('i', 'inactive', False, _('mark a bookmark inactive')),
915 ('i', 'inactive', False, _('mark a bookmark inactive')),
916 ] + formatteropts,
916 ] + formatteropts,
917 _('hg bookmarks [OPTIONS]... [NAME]...'))
917 _('hg bookmarks [OPTIONS]... [NAME]...'))
918 def bookmark(ui, repo, *names, **opts):
918 def bookmark(ui, repo, *names, **opts):
919 '''create a new bookmark or list existing bookmarks
919 '''create a new bookmark or list existing bookmarks
920
920
921 Bookmarks are labels on changesets to help track lines of development.
921 Bookmarks are labels on changesets to help track lines of development.
922 Bookmarks are unversioned and can be moved, renamed and deleted.
922 Bookmarks are unversioned and can be moved, renamed and deleted.
923 Deleting or moving a bookmark has no effect on the associated changesets.
923 Deleting or moving a bookmark has no effect on the associated changesets.
924
924
925 Creating or updating to a bookmark causes it to be marked as 'active'.
925 Creating or updating to a bookmark causes it to be marked as 'active'.
926 The active bookmark is indicated with a '*'.
926 The active bookmark is indicated with a '*'.
927 When a commit is made, the active bookmark will advance to the new commit.
927 When a commit is made, the active bookmark will advance to the new commit.
928 A plain :hg:`update` will also advance an active bookmark, if possible.
928 A plain :hg:`update` will also advance an active bookmark, if possible.
929 Updating away from a bookmark will cause it to be deactivated.
929 Updating away from a bookmark will cause it to be deactivated.
930
930
931 Bookmarks can be pushed and pulled between repositories (see
931 Bookmarks can be pushed and pulled between repositories (see
932 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
932 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
933 diverged, a new 'divergent bookmark' of the form 'name@path' will
933 diverged, a new 'divergent bookmark' of the form 'name@path' will
934 be created. Using :hg:`merge` will resolve the divergence.
934 be created. Using :hg:`merge` will resolve the divergence.
935
935
936 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
936 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
937 the active bookmark's name.
937 the active bookmark's name.
938
938
939 A bookmark named '@' has the special property that :hg:`clone` will
939 A bookmark named '@' has the special property that :hg:`clone` will
940 check it out by default if it exists.
940 check it out by default if it exists.
941
941
942 .. container:: verbose
942 .. container:: verbose
943
943
944 Examples:
944 Examples:
945
945
946 - create an active bookmark for a new line of development::
946 - create an active bookmark for a new line of development::
947
947
948 hg book new-feature
948 hg book new-feature
949
949
950 - create an inactive bookmark as a place marker::
950 - create an inactive bookmark as a place marker::
951
951
952 hg book -i reviewed
952 hg book -i reviewed
953
953
954 - create an inactive bookmark on another changeset::
954 - create an inactive bookmark on another changeset::
955
955
956 hg book -r .^ tested
956 hg book -r .^ tested
957
957
958 - rename bookmark turkey to dinner::
958 - rename bookmark turkey to dinner::
959
959
960 hg book -m turkey dinner
960 hg book -m turkey dinner
961
961
962 - move the '@' bookmark from another branch::
962 - move the '@' bookmark from another branch::
963
963
964 hg book -f @
964 hg book -f @
965 '''
965 '''
966 force = opts.get(r'force')
966 force = opts.get(r'force')
967 rev = opts.get(r'rev')
967 rev = opts.get(r'rev')
968 delete = opts.get(r'delete')
968 delete = opts.get(r'delete')
969 rename = opts.get(r'rename')
969 rename = opts.get(r'rename')
970 inactive = opts.get(r'inactive')
970 inactive = opts.get(r'inactive')
971
971
972 if delete and rename:
972 if delete and rename:
973 raise error.Abort(_("--delete and --rename are incompatible"))
973 raise error.Abort(_("--delete and --rename are incompatible"))
974 if delete and rev:
974 if delete and rev:
975 raise error.Abort(_("--rev is incompatible with --delete"))
975 raise error.Abort(_("--rev is incompatible with --delete"))
976 if rename and rev:
976 if rename and rev:
977 raise error.Abort(_("--rev is incompatible with --rename"))
977 raise error.Abort(_("--rev is incompatible with --rename"))
978 if not names and (delete or rev):
978 if not names and (delete or rev):
979 raise error.Abort(_("bookmark name required"))
979 raise error.Abort(_("bookmark name required"))
980
980
981 if delete or rename or names or inactive:
981 if delete or rename or names or inactive:
982 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
982 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
983 if delete:
983 if delete:
984 names = pycompat.maplist(repo._bookmarks.expandname, names)
984 names = pycompat.maplist(repo._bookmarks.expandname, names)
985 bookmarks.delete(repo, tr, names)
985 bookmarks.delete(repo, tr, names)
986 elif rename:
986 elif rename:
987 if not names:
987 if not names:
988 raise error.Abort(_("new bookmark name required"))
988 raise error.Abort(_("new bookmark name required"))
989 elif len(names) > 1:
989 elif len(names) > 1:
990 raise error.Abort(_("only one new bookmark name allowed"))
990 raise error.Abort(_("only one new bookmark name allowed"))
991 rename = repo._bookmarks.expandname(rename)
991 rename = repo._bookmarks.expandname(rename)
992 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
992 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
993 elif names:
993 elif names:
994 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
994 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
995 elif inactive:
995 elif inactive:
996 if len(repo._bookmarks) == 0:
996 if len(repo._bookmarks) == 0:
997 ui.status(_("no bookmarks set\n"))
997 ui.status(_("no bookmarks set\n"))
998 elif not repo._activebookmark:
998 elif not repo._activebookmark:
999 ui.status(_("no active bookmark\n"))
999 ui.status(_("no active bookmark\n"))
1000 else:
1000 else:
1001 bookmarks.deactivate(repo)
1001 bookmarks.deactivate(repo)
1002 else: # show bookmarks
1002 else: # show bookmarks
1003 bookmarks.printbookmarks(ui, repo, **opts)
1003 bookmarks.printbookmarks(ui, repo, **opts)
1004
1004
1005 @command('branch',
1005 @command('branch',
1006 [('f', 'force', None,
1006 [('f', 'force', None,
1007 _('set branch name even if it shadows an existing branch')),
1007 _('set branch name even if it shadows an existing branch')),
1008 ('C', 'clean', None, _('reset branch name to parent branch name')),
1008 ('C', 'clean', None, _('reset branch name to parent branch name')),
1009 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1009 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1010 ],
1010 ],
1011 _('[-fC] [NAME]'))
1011 _('[-fC] [NAME]'))
1012 def branch(ui, repo, label=None, **opts):
1012 def branch(ui, repo, label=None, **opts):
1013 """set or show the current branch name
1013 """set or show the current branch name
1014
1014
1015 .. note::
1015 .. note::
1016
1016
1017 Branch names are permanent and global. Use :hg:`bookmark` to create a
1017 Branch names are permanent and global. Use :hg:`bookmark` to create a
1018 light-weight bookmark instead. See :hg:`help glossary` for more
1018 light-weight bookmark instead. See :hg:`help glossary` for more
1019 information about named branches and bookmarks.
1019 information about named branches and bookmarks.
1020
1020
1021 With no argument, show the current branch name. With one argument,
1021 With no argument, show the current branch name. With one argument,
1022 set the working directory branch name (the branch will not exist
1022 set the working directory branch name (the branch will not exist
1023 in the repository until the next commit). Standard practice
1023 in the repository until the next commit). Standard practice
1024 recommends that primary development take place on the 'default'
1024 recommends that primary development take place on the 'default'
1025 branch.
1025 branch.
1026
1026
1027 Unless -f/--force is specified, branch will not let you set a
1027 Unless -f/--force is specified, branch will not let you set a
1028 branch name that already exists.
1028 branch name that already exists.
1029
1029
1030 Use -C/--clean to reset the working directory branch to that of
1030 Use -C/--clean to reset the working directory branch to that of
1031 the parent of the working directory, negating a previous branch
1031 the parent of the working directory, negating a previous branch
1032 change.
1032 change.
1033
1033
1034 Use the command :hg:`update` to switch to an existing branch. Use
1034 Use the command :hg:`update` to switch to an existing branch. Use
1035 :hg:`commit --close-branch` to mark this branch head as closed.
1035 :hg:`commit --close-branch` to mark this branch head as closed.
1036 When all heads of a branch are closed, the branch will be
1036 When all heads of a branch are closed, the branch will be
1037 considered closed.
1037 considered closed.
1038
1038
1039 Returns 0 on success.
1039 Returns 0 on success.
1040 """
1040 """
1041 opts = pycompat.byteskwargs(opts)
1041 opts = pycompat.byteskwargs(opts)
1042 revs = opts.get('rev')
1042 revs = opts.get('rev')
1043 if label:
1043 if label:
1044 label = label.strip()
1044 label = label.strip()
1045
1045
1046 if not opts.get('clean') and not label:
1046 if not opts.get('clean') and not label:
1047 if revs:
1047 if revs:
1048 raise error.Abort(_("no branch name specified for the revisions"))
1048 raise error.Abort(_("no branch name specified for the revisions"))
1049 ui.write("%s\n" % repo.dirstate.branch())
1049 ui.write("%s\n" % repo.dirstate.branch())
1050 return
1050 return
1051
1051
1052 with repo.wlock():
1052 with repo.wlock():
1053 if opts.get('clean'):
1053 if opts.get('clean'):
1054 label = repo[None].p1().branch()
1054 label = repo[None].p1().branch()
1055 repo.dirstate.setbranch(label)
1055 repo.dirstate.setbranch(label)
1056 ui.status(_('reset working directory to branch %s\n') % label)
1056 ui.status(_('reset working directory to branch %s\n') % label)
1057 elif label:
1057 elif label:
1058
1058
1059 scmutil.checknewlabel(repo, label, 'branch')
1059 scmutil.checknewlabel(repo, label, 'branch')
1060 if revs:
1060 if revs:
1061 return cmdutil.changebranch(ui, repo, revs, label)
1061 return cmdutil.changebranch(ui, repo, revs, label)
1062
1062
1063 if not opts.get('force') and label in repo.branchmap():
1063 if not opts.get('force') and label in repo.branchmap():
1064 if label not in [p.branch() for p in repo[None].parents()]:
1064 if label not in [p.branch() for p in repo[None].parents()]:
1065 raise error.Abort(_('a branch of the same name already'
1065 raise error.Abort(_('a branch of the same name already'
1066 ' exists'),
1066 ' exists'),
1067 # i18n: "it" refers to an existing branch
1067 # i18n: "it" refers to an existing branch
1068 hint=_("use 'hg update' to switch to it"))
1068 hint=_("use 'hg update' to switch to it"))
1069
1069
1070 repo.dirstate.setbranch(label)
1070 repo.dirstate.setbranch(label)
1071 ui.status(_('marked working directory as branch %s\n') % label)
1071 ui.status(_('marked working directory as branch %s\n') % label)
1072
1072
1073 # find any open named branches aside from default
1073 # find any open named branches aside from default
1074 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1074 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1075 if n != "default" and not c]
1075 if n != "default" and not c]
1076 if not others:
1076 if not others:
1077 ui.status(_('(branches are permanent and global, '
1077 ui.status(_('(branches are permanent and global, '
1078 'did you want a bookmark?)\n'))
1078 'did you want a bookmark?)\n'))
1079
1079
1080 @command('branches',
1080 @command('branches',
1081 [('a', 'active', False,
1081 [('a', 'active', False,
1082 _('show only branches that have unmerged heads (DEPRECATED)')),
1082 _('show only branches that have unmerged heads (DEPRECATED)')),
1083 ('c', 'closed', False, _('show normal and closed branches')),
1083 ('c', 'closed', False, _('show normal and closed branches')),
1084 ] + formatteropts,
1084 ] + formatteropts,
1085 _('[-c]'), cmdtype=readonly)
1085 _('[-c]'), cmdtype=readonly)
1086 def branches(ui, repo, active=False, closed=False, **opts):
1086 def branches(ui, repo, active=False, closed=False, **opts):
1087 """list repository named branches
1087 """list repository named branches
1088
1088
1089 List the repository's named branches, indicating which ones are
1089 List the repository's named branches, indicating which ones are
1090 inactive. If -c/--closed is specified, also list branches which have
1090 inactive. If -c/--closed is specified, also list branches which have
1091 been marked closed (see :hg:`commit --close-branch`).
1091 been marked closed (see :hg:`commit --close-branch`).
1092
1092
1093 Use the command :hg:`update` to switch to an existing branch.
1093 Use the command :hg:`update` to switch to an existing branch.
1094
1094
1095 Returns 0.
1095 Returns 0.
1096 """
1096 """
1097
1097
1098 opts = pycompat.byteskwargs(opts)
1098 opts = pycompat.byteskwargs(opts)
1099 ui.pager('branches')
1099 ui.pager('branches')
1100 fm = ui.formatter('branches', opts)
1100 fm = ui.formatter('branches', opts)
1101 hexfunc = fm.hexfunc
1101 hexfunc = fm.hexfunc
1102
1102
1103 allheads = set(repo.heads())
1103 allheads = set(repo.heads())
1104 branches = []
1104 branches = []
1105 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1105 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1106 isactive = False
1106 isactive = False
1107 if not isclosed:
1107 if not isclosed:
1108 openheads = set(repo.branchmap().iteropen(heads))
1108 openheads = set(repo.branchmap().iteropen(heads))
1109 isactive = bool(openheads & allheads)
1109 isactive = bool(openheads & allheads)
1110 branches.append((tag, repo[tip], isactive, not isclosed))
1110 branches.append((tag, repo[tip], isactive, not isclosed))
1111 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1111 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1112 reverse=True)
1112 reverse=True)
1113
1113
1114 for tag, ctx, isactive, isopen in branches:
1114 for tag, ctx, isactive, isopen in branches:
1115 if active and not isactive:
1115 if active and not isactive:
1116 continue
1116 continue
1117 if isactive:
1117 if isactive:
1118 label = 'branches.active'
1118 label = 'branches.active'
1119 notice = ''
1119 notice = ''
1120 elif not isopen:
1120 elif not isopen:
1121 if not closed:
1121 if not closed:
1122 continue
1122 continue
1123 label = 'branches.closed'
1123 label = 'branches.closed'
1124 notice = _(' (closed)')
1124 notice = _(' (closed)')
1125 else:
1125 else:
1126 label = 'branches.inactive'
1126 label = 'branches.inactive'
1127 notice = _(' (inactive)')
1127 notice = _(' (inactive)')
1128 current = (tag == repo.dirstate.branch())
1128 current = (tag == repo.dirstate.branch())
1129 if current:
1129 if current:
1130 label = 'branches.current'
1130 label = 'branches.current'
1131
1131
1132 fm.startitem()
1132 fm.startitem()
1133 fm.write('branch', '%s', tag, label=label)
1133 fm.write('branch', '%s', tag, label=label)
1134 rev = ctx.rev()
1134 rev = ctx.rev()
1135 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1135 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1136 fmt = ' ' * padsize + ' %d:%s'
1136 fmt = ' ' * padsize + ' %d:%s'
1137 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1137 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1138 label='log.changeset changeset.%s' % ctx.phasestr())
1138 label='log.changeset changeset.%s' % ctx.phasestr())
1139 fm.context(ctx=ctx)
1139 fm.context(ctx=ctx)
1140 fm.data(active=isactive, closed=not isopen, current=current)
1140 fm.data(active=isactive, closed=not isopen, current=current)
1141 if not ui.quiet:
1141 if not ui.quiet:
1142 fm.plain(notice)
1142 fm.plain(notice)
1143 fm.plain('\n')
1143 fm.plain('\n')
1144 fm.end()
1144 fm.end()
1145
1145
1146 @command('bundle',
1146 @command('bundle',
1147 [('f', 'force', None, _('run even when the destination is unrelated')),
1147 [('f', 'force', None, _('run even when the destination is unrelated')),
1148 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1148 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1149 _('REV')),
1149 _('REV')),
1150 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1150 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1151 _('BRANCH')),
1151 _('BRANCH')),
1152 ('', 'base', [],
1152 ('', 'base', [],
1153 _('a base changeset assumed to be available at the destination'),
1153 _('a base changeset assumed to be available at the destination'),
1154 _('REV')),
1154 _('REV')),
1155 ('a', 'all', None, _('bundle all changesets in the repository')),
1155 ('a', 'all', None, _('bundle all changesets in the repository')),
1156 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1156 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1157 ] + remoteopts,
1157 ] + remoteopts,
1158 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1158 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1159 def bundle(ui, repo, fname, dest=None, **opts):
1159 def bundle(ui, repo, fname, dest=None, **opts):
1160 """create a bundle file
1160 """create a bundle file
1161
1161
1162 Generate a bundle file containing data to be transferred to another
1162 Generate a bundle file containing data to be transferred to another
1163 repository.
1163 repository.
1164
1164
1165 To create a bundle containing all changesets, use -a/--all
1165 To create a bundle containing all changesets, use -a/--all
1166 (or --base null). Otherwise, hg assumes the destination will have
1166 (or --base null). Otherwise, hg assumes the destination will have
1167 all the nodes you specify with --base parameters. Otherwise, hg
1167 all the nodes you specify with --base parameters. Otherwise, hg
1168 will assume the repository has all the nodes in destination, or
1168 will assume the repository has all the nodes in destination, or
1169 default-push/default if no destination is specified, where destination
1169 default-push/default if no destination is specified, where destination
1170 is the repository you provide through DEST option.
1170 is the repository you provide through DEST option.
1171
1171
1172 You can change bundle format with the -t/--type option. See
1172 You can change bundle format with the -t/--type option. See
1173 :hg:`help bundlespec` for documentation on this format. By default,
1173 :hg:`help bundlespec` for documentation on this format. By default,
1174 the most appropriate format is used and compression defaults to
1174 the most appropriate format is used and compression defaults to
1175 bzip2.
1175 bzip2.
1176
1176
1177 The bundle file can then be transferred using conventional means
1177 The bundle file can then be transferred using conventional means
1178 and applied to another repository with the unbundle or pull
1178 and applied to another repository with the unbundle or pull
1179 command. This is useful when direct push and pull are not
1179 command. This is useful when direct push and pull are not
1180 available or when exporting an entire repository is undesirable.
1180 available or when exporting an entire repository is undesirable.
1181
1181
1182 Applying bundles preserves all changeset contents including
1182 Applying bundles preserves all changeset contents including
1183 permissions, copy/rename information, and revision history.
1183 permissions, copy/rename information, and revision history.
1184
1184
1185 Returns 0 on success, 1 if no changes found.
1185 Returns 0 on success, 1 if no changes found.
1186 """
1186 """
1187 opts = pycompat.byteskwargs(opts)
1187 opts = pycompat.byteskwargs(opts)
1188 revs = None
1188 revs = None
1189 if 'rev' in opts:
1189 if 'rev' in opts:
1190 revstrings = opts['rev']
1190 revstrings = opts['rev']
1191 revs = scmutil.revrange(repo, revstrings)
1191 revs = scmutil.revrange(repo, revstrings)
1192 if revstrings and not revs:
1192 if revstrings and not revs:
1193 raise error.Abort(_('no commits to bundle'))
1193 raise error.Abort(_('no commits to bundle'))
1194
1194
1195 bundletype = opts.get('type', 'bzip2').lower()
1195 bundletype = opts.get('type', 'bzip2').lower()
1196 try:
1196 try:
1197 bcompression, cgversion, params = exchange.parsebundlespec(
1197 bcompression, cgversion, params = exchange.parsebundlespec(
1198 repo, bundletype, strict=False)
1198 repo, bundletype, strict=False)
1199 except error.UnsupportedBundleSpecification as e:
1199 except error.UnsupportedBundleSpecification as e:
1200 raise error.Abort(pycompat.bytestr(e),
1200 raise error.Abort(pycompat.bytestr(e),
1201 hint=_("see 'hg help bundlespec' for supported "
1201 hint=_("see 'hg help bundlespec' for supported "
1202 "values for --type"))
1202 "values for --type"))
1203
1203
1204 # Packed bundles are a pseudo bundle format for now.
1204 # Packed bundles are a pseudo bundle format for now.
1205 if cgversion == 's1':
1205 if cgversion == 's1':
1206 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1206 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1207 hint=_("use 'hg debugcreatestreamclonebundle'"))
1207 hint=_("use 'hg debugcreatestreamclonebundle'"))
1208
1208
1209 if opts.get('all'):
1209 if opts.get('all'):
1210 if dest:
1210 if dest:
1211 raise error.Abort(_("--all is incompatible with specifying "
1211 raise error.Abort(_("--all is incompatible with specifying "
1212 "a destination"))
1212 "a destination"))
1213 if opts.get('base'):
1213 if opts.get('base'):
1214 ui.warn(_("ignoring --base because --all was specified\n"))
1214 ui.warn(_("ignoring --base because --all was specified\n"))
1215 base = ['null']
1215 base = ['null']
1216 else:
1216 else:
1217 base = scmutil.revrange(repo, opts.get('base'))
1217 base = scmutil.revrange(repo, opts.get('base'))
1218 if cgversion not in changegroup.supportedoutgoingversions(repo):
1218 if cgversion not in changegroup.supportedoutgoingversions(repo):
1219 raise error.Abort(_("repository does not support bundle version %s") %
1219 raise error.Abort(_("repository does not support bundle version %s") %
1220 cgversion)
1220 cgversion)
1221
1221
1222 if base:
1222 if base:
1223 if dest:
1223 if dest:
1224 raise error.Abort(_("--base is incompatible with specifying "
1224 raise error.Abort(_("--base is incompatible with specifying "
1225 "a destination"))
1225 "a destination"))
1226 common = [repo.lookup(rev) for rev in base]
1226 common = [repo.lookup(rev) for rev in base]
1227 heads = [repo.lookup(r) for r in revs] if revs else None
1227 heads = [repo.lookup(r) for r in revs] if revs else None
1228 outgoing = discovery.outgoing(repo, common, heads)
1228 outgoing = discovery.outgoing(repo, common, heads)
1229 else:
1229 else:
1230 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1230 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1231 dest, branches = hg.parseurl(dest, opts.get('branch'))
1231 dest, branches = hg.parseurl(dest, opts.get('branch'))
1232 other = hg.peer(repo, opts, dest)
1232 other = hg.peer(repo, opts, dest)
1233 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1233 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1234 heads = revs and map(repo.lookup, revs) or revs
1234 heads = revs and map(repo.lookup, revs) or revs
1235 outgoing = discovery.findcommonoutgoing(repo, other,
1235 outgoing = discovery.findcommonoutgoing(repo, other,
1236 onlyheads=heads,
1236 onlyheads=heads,
1237 force=opts.get('force'),
1237 force=opts.get('force'),
1238 portable=True)
1238 portable=True)
1239
1239
1240 if not outgoing.missing:
1240 if not outgoing.missing:
1241 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1241 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1242 return 1
1242 return 1
1243
1243
1244 if cgversion == '01': #bundle1
1244 if cgversion == '01': #bundle1
1245 if bcompression is None:
1245 if bcompression is None:
1246 bcompression = 'UN'
1246 bcompression = 'UN'
1247 bversion = 'HG10' + bcompression
1247 bversion = 'HG10' + bcompression
1248 bcompression = None
1248 bcompression = None
1249 elif cgversion in ('02', '03'):
1249 elif cgversion in ('02', '03'):
1250 bversion = 'HG20'
1250 bversion = 'HG20'
1251 else:
1251 else:
1252 raise error.ProgrammingError(
1252 raise error.ProgrammingError(
1253 'bundle: unexpected changegroup version %s' % cgversion)
1253 'bundle: unexpected changegroup version %s' % cgversion)
1254
1254
1255 # TODO compression options should be derived from bundlespec parsing.
1255 # TODO compression options should be derived from bundlespec parsing.
1256 # This is a temporary hack to allow adjusting bundle compression
1256 # This is a temporary hack to allow adjusting bundle compression
1257 # level without a) formalizing the bundlespec changes to declare it
1257 # level without a) formalizing the bundlespec changes to declare it
1258 # b) introducing a command flag.
1258 # b) introducing a command flag.
1259 compopts = {}
1259 compopts = {}
1260 complevel = ui.configint('experimental', 'bundlecomplevel')
1260 complevel = ui.configint('experimental', 'bundlecomplevel')
1261 if complevel is not None:
1261 if complevel is not None:
1262 compopts['level'] = complevel
1262 compopts['level'] = complevel
1263
1263
1264
1264
1265 contentopts = {'cg.version': cgversion}
1265 contentopts = {'cg.version': cgversion}
1266 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1266 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1267 contentopts['obsolescence'] = True
1267 contentopts['obsolescence'] = True
1268 if repo.ui.configbool('experimental', 'bundle-phases'):
1268 if repo.ui.configbool('experimental', 'bundle-phases'):
1269 contentopts['phases'] = True
1269 contentopts['phases'] = True
1270 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1270 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1271 contentopts, compression=bcompression,
1271 contentopts, compression=bcompression,
1272 compopts=compopts)
1272 compopts=compopts)
1273
1273
1274 @command('cat',
1274 @command('cat',
1275 [('o', 'output', '',
1275 [('o', 'output', '',
1276 _('print output to file with formatted name'), _('FORMAT')),
1276 _('print output to file with formatted name'), _('FORMAT')),
1277 ('r', 'rev', '', _('print the given revision'), _('REV')),
1277 ('r', 'rev', '', _('print the given revision'), _('REV')),
1278 ('', 'decode', None, _('apply any matching decode filter')),
1278 ('', 'decode', None, _('apply any matching decode filter')),
1279 ] + walkopts + formatteropts,
1279 ] + walkopts + formatteropts,
1280 _('[OPTION]... FILE...'),
1280 _('[OPTION]... FILE...'),
1281 inferrepo=True, cmdtype=readonly)
1281 inferrepo=True, cmdtype=readonly)
1282 def cat(ui, repo, file1, *pats, **opts):
1282 def cat(ui, repo, file1, *pats, **opts):
1283 """output the current or given revision of files
1283 """output the current or given revision of files
1284
1284
1285 Print the specified files as they were at the given revision. If
1285 Print the specified files as they were at the given revision. If
1286 no revision is given, the parent of the working directory is used.
1286 no revision is given, the parent of the working directory is used.
1287
1287
1288 Output may be to a file, in which case the name of the file is
1288 Output may be to a file, in which case the name of the file is
1289 given using a template string. See :hg:`help templates`. In addition
1289 given using a template string. See :hg:`help templates`. In addition
1290 to the common template keywords, the following formatting rules are
1290 to the common template keywords, the following formatting rules are
1291 supported:
1291 supported:
1292
1292
1293 :``%%``: literal "%" character
1293 :``%%``: literal "%" character
1294 :``%s``: basename of file being printed
1294 :``%s``: basename of file being printed
1295 :``%d``: dirname of file being printed, or '.' if in repository root
1295 :``%d``: dirname of file being printed, or '.' if in repository root
1296 :``%p``: root-relative path name of file being printed
1296 :``%p``: root-relative path name of file being printed
1297 :``%H``: changeset hash (40 hexadecimal digits)
1297 :``%H``: changeset hash (40 hexadecimal digits)
1298 :``%R``: changeset revision number
1298 :``%R``: changeset revision number
1299 :``%h``: short-form changeset hash (12 hexadecimal digits)
1299 :``%h``: short-form changeset hash (12 hexadecimal digits)
1300 :``%r``: zero-padded changeset revision number
1300 :``%r``: zero-padded changeset revision number
1301 :``%b``: basename of the exporting repository
1301 :``%b``: basename of the exporting repository
1302 :``\\``: literal "\\" character
1302 :``\\``: literal "\\" character
1303
1303
1304 Returns 0 on success.
1304 Returns 0 on success.
1305 """
1305 """
1306 opts = pycompat.byteskwargs(opts)
1306 opts = pycompat.byteskwargs(opts)
1307 rev = opts.get('rev')
1307 rev = opts.get('rev')
1308 if rev:
1308 if rev:
1309 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1309 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1310 ctx = scmutil.revsingle(repo, rev)
1310 ctx = scmutil.revsingle(repo, rev)
1311 m = scmutil.match(ctx, (file1,) + pats, opts)
1311 m = scmutil.match(ctx, (file1,) + pats, opts)
1312 fntemplate = opts.pop('output', '')
1312 fntemplate = opts.pop('output', '')
1313 if cmdutil.isstdiofilename(fntemplate):
1313 if cmdutil.isstdiofilename(fntemplate):
1314 fntemplate = ''
1314 fntemplate = ''
1315
1315
1316 if fntemplate:
1316 if fntemplate:
1317 fm = formatter.nullformatter(ui, 'cat')
1317 fm = formatter.nullformatter(ui, 'cat')
1318 else:
1318 else:
1319 ui.pager('cat')
1319 ui.pager('cat')
1320 fm = ui.formatter('cat', opts)
1320 fm = ui.formatter('cat', opts)
1321 with fm:
1321 with fm:
1322 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1322 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1323 **pycompat.strkwargs(opts))
1323 **pycompat.strkwargs(opts))
1324
1324
1325 @command('^clone',
1325 @command('^clone',
1326 [('U', 'noupdate', None, _('the clone will include an empty working '
1326 [('U', 'noupdate', None, _('the clone will include an empty working '
1327 'directory (only a repository)')),
1327 'directory (only a repository)')),
1328 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1328 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1329 _('REV')),
1329 _('REV')),
1330 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1330 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1331 ' and its ancestors'), _('REV')),
1331 ' and its ancestors'), _('REV')),
1332 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1332 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1333 ' changesets and their ancestors'), _('BRANCH')),
1333 ' changesets and their ancestors'), _('BRANCH')),
1334 ('', 'pull', None, _('use pull protocol to copy metadata')),
1334 ('', 'pull', None, _('use pull protocol to copy metadata')),
1335 ('', 'uncompressed', None,
1335 ('', 'uncompressed', None,
1336 _('an alias to --stream (DEPRECATED)')),
1336 _('an alias to --stream (DEPRECATED)')),
1337 ('', 'stream', None,
1337 ('', 'stream', None,
1338 _('clone with minimal data processing')),
1338 _('clone with minimal data processing')),
1339 ] + remoteopts,
1339 ] + remoteopts,
1340 _('[OPTION]... SOURCE [DEST]'),
1340 _('[OPTION]... SOURCE [DEST]'),
1341 norepo=True)
1341 norepo=True)
1342 def clone(ui, source, dest=None, **opts):
1342 def clone(ui, source, dest=None, **opts):
1343 """make a copy of an existing repository
1343 """make a copy of an existing repository
1344
1344
1345 Create a copy of an existing repository in a new directory.
1345 Create a copy of an existing repository in a new directory.
1346
1346
1347 If no destination directory name is specified, it defaults to the
1347 If no destination directory name is specified, it defaults to the
1348 basename of the source.
1348 basename of the source.
1349
1349
1350 The location of the source is added to the new repository's
1350 The location of the source is added to the new repository's
1351 ``.hg/hgrc`` file, as the default to be used for future pulls.
1351 ``.hg/hgrc`` file, as the default to be used for future pulls.
1352
1352
1353 Only local paths and ``ssh://`` URLs are supported as
1353 Only local paths and ``ssh://`` URLs are supported as
1354 destinations. For ``ssh://`` destinations, no working directory or
1354 destinations. For ``ssh://`` destinations, no working directory or
1355 ``.hg/hgrc`` will be created on the remote side.
1355 ``.hg/hgrc`` will be created on the remote side.
1356
1356
1357 If the source repository has a bookmark called '@' set, that
1357 If the source repository has a bookmark called '@' set, that
1358 revision will be checked out in the new repository by default.
1358 revision will be checked out in the new repository by default.
1359
1359
1360 To check out a particular version, use -u/--update, or
1360 To check out a particular version, use -u/--update, or
1361 -U/--noupdate to create a clone with no working directory.
1361 -U/--noupdate to create a clone with no working directory.
1362
1362
1363 To pull only a subset of changesets, specify one or more revisions
1363 To pull only a subset of changesets, specify one or more revisions
1364 identifiers with -r/--rev or branches with -b/--branch. The
1364 identifiers with -r/--rev or branches with -b/--branch. The
1365 resulting clone will contain only the specified changesets and
1365 resulting clone will contain only the specified changesets and
1366 their ancestors. These options (or 'clone src#rev dest') imply
1366 their ancestors. These options (or 'clone src#rev dest') imply
1367 --pull, even for local source repositories.
1367 --pull, even for local source repositories.
1368
1368
1369 In normal clone mode, the remote normalizes repository data into a common
1369 In normal clone mode, the remote normalizes repository data into a common
1370 exchange format and the receiving end translates this data into its local
1370 exchange format and the receiving end translates this data into its local
1371 storage format. --stream activates a different clone mode that essentially
1371 storage format. --stream activates a different clone mode that essentially
1372 copies repository files from the remote with minimal data processing. This
1372 copies repository files from the remote with minimal data processing. This
1373 significantly reduces the CPU cost of a clone both remotely and locally.
1373 significantly reduces the CPU cost of a clone both remotely and locally.
1374 However, it often increases the transferred data size by 30-40%. This can
1374 However, it often increases the transferred data size by 30-40%. This can
1375 result in substantially faster clones where I/O throughput is plentiful,
1375 result in substantially faster clones where I/O throughput is plentiful,
1376 especially for larger repositories. A side-effect of --stream clones is
1376 especially for larger repositories. A side-effect of --stream clones is
1377 that storage settings and requirements on the remote are applied locally:
1377 that storage settings and requirements on the remote are applied locally:
1378 a modern client may inherit legacy or inefficient storage used by the
1378 a modern client may inherit legacy or inefficient storage used by the
1379 remote or a legacy Mercurial client may not be able to clone from a
1379 remote or a legacy Mercurial client may not be able to clone from a
1380 modern Mercurial remote.
1380 modern Mercurial remote.
1381
1381
1382 .. note::
1382 .. note::
1383
1383
1384 Specifying a tag will include the tagged changeset but not the
1384 Specifying a tag will include the tagged changeset but not the
1385 changeset containing the tag.
1385 changeset containing the tag.
1386
1386
1387 .. container:: verbose
1387 .. container:: verbose
1388
1388
1389 For efficiency, hardlinks are used for cloning whenever the
1389 For efficiency, hardlinks are used for cloning whenever the
1390 source and destination are on the same filesystem (note this
1390 source and destination are on the same filesystem (note this
1391 applies only to the repository data, not to the working
1391 applies only to the repository data, not to the working
1392 directory). Some filesystems, such as AFS, implement hardlinking
1392 directory). Some filesystems, such as AFS, implement hardlinking
1393 incorrectly, but do not report errors. In these cases, use the
1393 incorrectly, but do not report errors. In these cases, use the
1394 --pull option to avoid hardlinking.
1394 --pull option to avoid hardlinking.
1395
1395
1396 Mercurial will update the working directory to the first applicable
1396 Mercurial will update the working directory to the first applicable
1397 revision from this list:
1397 revision from this list:
1398
1398
1399 a) null if -U or the source repository has no changesets
1399 a) null if -U or the source repository has no changesets
1400 b) if -u . and the source repository is local, the first parent of
1400 b) if -u . and the source repository is local, the first parent of
1401 the source repository's working directory
1401 the source repository's working directory
1402 c) the changeset specified with -u (if a branch name, this means the
1402 c) the changeset specified with -u (if a branch name, this means the
1403 latest head of that branch)
1403 latest head of that branch)
1404 d) the changeset specified with -r
1404 d) the changeset specified with -r
1405 e) the tipmost head specified with -b
1405 e) the tipmost head specified with -b
1406 f) the tipmost head specified with the url#branch source syntax
1406 f) the tipmost head specified with the url#branch source syntax
1407 g) the revision marked with the '@' bookmark, if present
1407 g) the revision marked with the '@' bookmark, if present
1408 h) the tipmost head of the default branch
1408 h) the tipmost head of the default branch
1409 i) tip
1409 i) tip
1410
1410
1411 When cloning from servers that support it, Mercurial may fetch
1411 When cloning from servers that support it, Mercurial may fetch
1412 pre-generated data from a server-advertised URL. When this is done,
1412 pre-generated data from a server-advertised URL. When this is done,
1413 hooks operating on incoming changesets and changegroups may fire twice,
1413 hooks operating on incoming changesets and changegroups may fire twice,
1414 once for the bundle fetched from the URL and another for any additional
1414 once for the bundle fetched from the URL and another for any additional
1415 data not fetched from this URL. In addition, if an error occurs, the
1415 data not fetched from this URL. In addition, if an error occurs, the
1416 repository may be rolled back to a partial clone. This behavior may
1416 repository may be rolled back to a partial clone. This behavior may
1417 change in future releases. See :hg:`help -e clonebundles` for more.
1417 change in future releases. See :hg:`help -e clonebundles` for more.
1418
1418
1419 Examples:
1419 Examples:
1420
1420
1421 - clone a remote repository to a new directory named hg/::
1421 - clone a remote repository to a new directory named hg/::
1422
1422
1423 hg clone https://www.mercurial-scm.org/repo/hg/
1423 hg clone https://www.mercurial-scm.org/repo/hg/
1424
1424
1425 - create a lightweight local clone::
1425 - create a lightweight local clone::
1426
1426
1427 hg clone project/ project-feature/
1427 hg clone project/ project-feature/
1428
1428
1429 - clone from an absolute path on an ssh server (note double-slash)::
1429 - clone from an absolute path on an ssh server (note double-slash)::
1430
1430
1431 hg clone ssh://user@server//home/projects/alpha/
1431 hg clone ssh://user@server//home/projects/alpha/
1432
1432
1433 - do a streaming clone while checking out a specified version::
1433 - do a streaming clone while checking out a specified version::
1434
1434
1435 hg clone --stream http://server/repo -u 1.5
1435 hg clone --stream http://server/repo -u 1.5
1436
1436
1437 - create a repository without changesets after a particular revision::
1437 - create a repository without changesets after a particular revision::
1438
1438
1439 hg clone -r 04e544 experimental/ good/
1439 hg clone -r 04e544 experimental/ good/
1440
1440
1441 - clone (and track) a particular named branch::
1441 - clone (and track) a particular named branch::
1442
1442
1443 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1443 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1444
1444
1445 See :hg:`help urls` for details on specifying URLs.
1445 See :hg:`help urls` for details on specifying URLs.
1446
1446
1447 Returns 0 on success.
1447 Returns 0 on success.
1448 """
1448 """
1449 opts = pycompat.byteskwargs(opts)
1449 opts = pycompat.byteskwargs(opts)
1450 if opts.get('noupdate') and opts.get('updaterev'):
1450 if opts.get('noupdate') and opts.get('updaterev'):
1451 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1451 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1452
1452
1453 r = hg.clone(ui, opts, source, dest,
1453 r = hg.clone(ui, opts, source, dest,
1454 pull=opts.get('pull'),
1454 pull=opts.get('pull'),
1455 stream=opts.get('stream') or opts.get('uncompressed'),
1455 stream=opts.get('stream') or opts.get('uncompressed'),
1456 rev=opts.get('rev'),
1456 rev=opts.get('rev'),
1457 update=opts.get('updaterev') or not opts.get('noupdate'),
1457 update=opts.get('updaterev') or not opts.get('noupdate'),
1458 branch=opts.get('branch'),
1458 branch=opts.get('branch'),
1459 shareopts=opts.get('shareopts'))
1459 shareopts=opts.get('shareopts'))
1460
1460
1461 return r is None
1461 return r is None
1462
1462
1463 @command('^commit|ci',
1463 @command('^commit|ci',
1464 [('A', 'addremove', None,
1464 [('A', 'addremove', None,
1465 _('mark new/missing files as added/removed before committing')),
1465 _('mark new/missing files as added/removed before committing')),
1466 ('', 'close-branch', None,
1466 ('', 'close-branch', None,
1467 _('mark a branch head as closed')),
1467 _('mark a branch head as closed')),
1468 ('', 'amend', None, _('amend the parent of the working directory')),
1468 ('', 'amend', None, _('amend the parent of the working directory')),
1469 ('s', 'secret', None, _('use the secret phase for committing')),
1469 ('s', 'secret', None, _('use the secret phase for committing')),
1470 ('e', 'edit', None, _('invoke editor on commit messages')),
1470 ('e', 'edit', None, _('invoke editor on commit messages')),
1471 ('i', 'interactive', None, _('use interactive mode')),
1471 ('i', 'interactive', None, _('use interactive mode')),
1472 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1472 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1473 _('[OPTION]... [FILE]...'),
1473 _('[OPTION]... [FILE]...'),
1474 inferrepo=True)
1474 inferrepo=True)
1475 def commit(ui, repo, *pats, **opts):
1475 def commit(ui, repo, *pats, **opts):
1476 """commit the specified files or all outstanding changes
1476 """commit the specified files or all outstanding changes
1477
1477
1478 Commit changes to the given files into the repository. Unlike a
1478 Commit changes to the given files into the repository. Unlike a
1479 centralized SCM, this operation is a local operation. See
1479 centralized SCM, this operation is a local operation. See
1480 :hg:`push` for a way to actively distribute your changes.
1480 :hg:`push` for a way to actively distribute your changes.
1481
1481
1482 If a list of files is omitted, all changes reported by :hg:`status`
1482 If a list of files is omitted, all changes reported by :hg:`status`
1483 will be committed.
1483 will be committed.
1484
1484
1485 If you are committing the result of a merge, do not provide any
1485 If you are committing the result of a merge, do not provide any
1486 filenames or -I/-X filters.
1486 filenames or -I/-X filters.
1487
1487
1488 If no commit message is specified, Mercurial starts your
1488 If no commit message is specified, Mercurial starts your
1489 configured editor where you can enter a message. In case your
1489 configured editor where you can enter a message. In case your
1490 commit fails, you will find a backup of your message in
1490 commit fails, you will find a backup of your message in
1491 ``.hg/last-message.txt``.
1491 ``.hg/last-message.txt``.
1492
1492
1493 The --close-branch flag can be used to mark the current branch
1493 The --close-branch flag can be used to mark the current branch
1494 head closed. When all heads of a branch are closed, the branch
1494 head closed. When all heads of a branch are closed, the branch
1495 will be considered closed and no longer listed.
1495 will be considered closed and no longer listed.
1496
1496
1497 The --amend flag can be used to amend the parent of the
1497 The --amend flag can be used to amend the parent of the
1498 working directory with a new commit that contains the changes
1498 working directory with a new commit that contains the changes
1499 in the parent in addition to those currently reported by :hg:`status`,
1499 in the parent in addition to those currently reported by :hg:`status`,
1500 if there are any. The old commit is stored in a backup bundle in
1500 if there are any. The old commit is stored in a backup bundle in
1501 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1501 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1502 on how to restore it).
1502 on how to restore it).
1503
1503
1504 Message, user and date are taken from the amended commit unless
1504 Message, user and date are taken from the amended commit unless
1505 specified. When a message isn't specified on the command line,
1505 specified. When a message isn't specified on the command line,
1506 the editor will open with the message of the amended commit.
1506 the editor will open with the message of the amended commit.
1507
1507
1508 It is not possible to amend public changesets (see :hg:`help phases`)
1508 It is not possible to amend public changesets (see :hg:`help phases`)
1509 or changesets that have children.
1509 or changesets that have children.
1510
1510
1511 See :hg:`help dates` for a list of formats valid for -d/--date.
1511 See :hg:`help dates` for a list of formats valid for -d/--date.
1512
1512
1513 Returns 0 on success, 1 if nothing changed.
1513 Returns 0 on success, 1 if nothing changed.
1514
1514
1515 .. container:: verbose
1515 .. container:: verbose
1516
1516
1517 Examples:
1517 Examples:
1518
1518
1519 - commit all files ending in .py::
1519 - commit all files ending in .py::
1520
1520
1521 hg commit --include "set:**.py"
1521 hg commit --include "set:**.py"
1522
1522
1523 - commit all non-binary files::
1523 - commit all non-binary files::
1524
1524
1525 hg commit --exclude "set:binary()"
1525 hg commit --exclude "set:binary()"
1526
1526
1527 - amend the current commit and set the date to now::
1527 - amend the current commit and set the date to now::
1528
1528
1529 hg commit --amend --date now
1529 hg commit --amend --date now
1530 """
1530 """
1531 wlock = lock = None
1531 wlock = lock = None
1532 try:
1532 try:
1533 wlock = repo.wlock()
1533 wlock = repo.wlock()
1534 lock = repo.lock()
1534 lock = repo.lock()
1535 return _docommit(ui, repo, *pats, **opts)
1535 return _docommit(ui, repo, *pats, **opts)
1536 finally:
1536 finally:
1537 release(lock, wlock)
1537 release(lock, wlock)
1538
1538
1539 def _docommit(ui, repo, *pats, **opts):
1539 def _docommit(ui, repo, *pats, **opts):
1540 if opts.get(r'interactive'):
1540 if opts.get(r'interactive'):
1541 opts.pop(r'interactive')
1541 opts.pop(r'interactive')
1542 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1542 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1543 cmdutil.recordfilter, *pats,
1543 cmdutil.recordfilter, *pats,
1544 **opts)
1544 **opts)
1545 # ret can be 0 (no changes to record) or the value returned by
1545 # ret can be 0 (no changes to record) or the value returned by
1546 # commit(), 1 if nothing changed or None on success.
1546 # commit(), 1 if nothing changed or None on success.
1547 return 1 if ret == 0 else ret
1547 return 1 if ret == 0 else ret
1548
1548
1549 opts = pycompat.byteskwargs(opts)
1549 opts = pycompat.byteskwargs(opts)
1550 if opts.get('subrepos'):
1550 if opts.get('subrepos'):
1551 if opts.get('amend'):
1551 if opts.get('amend'):
1552 raise error.Abort(_('cannot amend with --subrepos'))
1552 raise error.Abort(_('cannot amend with --subrepos'))
1553 # Let --subrepos on the command line override config setting.
1553 # Let --subrepos on the command line override config setting.
1554 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1554 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1555
1555
1556 cmdutil.checkunfinished(repo, commit=True)
1556 cmdutil.checkunfinished(repo, commit=True)
1557
1557
1558 branch = repo[None].branch()
1558 branch = repo[None].branch()
1559 bheads = repo.branchheads(branch)
1559 bheads = repo.branchheads(branch)
1560
1560
1561 extra = {}
1561 extra = {}
1562 if opts.get('close_branch'):
1562 if opts.get('close_branch'):
1563 extra['close'] = '1'
1563 extra['close'] = '1'
1564
1564
1565 if not bheads:
1565 if not bheads:
1566 raise error.Abort(_('can only close branch heads'))
1566 raise error.Abort(_('can only close branch heads'))
1567 elif opts.get('amend'):
1567 elif opts.get('amend'):
1568 if repo[None].parents()[0].p1().branch() != branch and \
1568 if repo[None].parents()[0].p1().branch() != branch and \
1569 repo[None].parents()[0].p2().branch() != branch:
1569 repo[None].parents()[0].p2().branch() != branch:
1570 raise error.Abort(_('can only close branch heads'))
1570 raise error.Abort(_('can only close branch heads'))
1571
1571
1572 if opts.get('amend'):
1572 if opts.get('amend'):
1573 if ui.configbool('ui', 'commitsubrepos'):
1573 if ui.configbool('ui', 'commitsubrepos'):
1574 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1574 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1575
1575
1576 old = repo['.']
1576 old = repo['.']
1577 rewriteutil.precheck(repo, [old.rev()], 'amend')
1577 rewriteutil.precheck(repo, [old.rev()], 'amend')
1578
1578
1579 # Currently histedit gets confused if an amend happens while histedit
1579 # Currently histedit gets confused if an amend happens while histedit
1580 # is in progress. Since we have a checkunfinished command, we are
1580 # is in progress. Since we have a checkunfinished command, we are
1581 # temporarily honoring it.
1581 # temporarily honoring it.
1582 #
1582 #
1583 # Note: eventually this guard will be removed. Please do not expect
1583 # Note: eventually this guard will be removed. Please do not expect
1584 # this behavior to remain.
1584 # this behavior to remain.
1585 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1585 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1586 cmdutil.checkunfinished(repo)
1586 cmdutil.checkunfinished(repo)
1587
1587
1588 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1588 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1589 if node == old.node():
1589 if node == old.node():
1590 ui.status(_("nothing changed\n"))
1590 ui.status(_("nothing changed\n"))
1591 return 1
1591 return 1
1592 else:
1592 else:
1593 def commitfunc(ui, repo, message, match, opts):
1593 def commitfunc(ui, repo, message, match, opts):
1594 overrides = {}
1594 overrides = {}
1595 if opts.get('secret'):
1595 if opts.get('secret'):
1596 overrides[('phases', 'new-commit')] = 'secret'
1596 overrides[('phases', 'new-commit')] = 'secret'
1597
1597
1598 baseui = repo.baseui
1598 baseui = repo.baseui
1599 with baseui.configoverride(overrides, 'commit'):
1599 with baseui.configoverride(overrides, 'commit'):
1600 with ui.configoverride(overrides, 'commit'):
1600 with ui.configoverride(overrides, 'commit'):
1601 editform = cmdutil.mergeeditform(repo[None],
1601 editform = cmdutil.mergeeditform(repo[None],
1602 'commit.normal')
1602 'commit.normal')
1603 editor = cmdutil.getcommiteditor(
1603 editor = cmdutil.getcommiteditor(
1604 editform=editform, **pycompat.strkwargs(opts))
1604 editform=editform, **pycompat.strkwargs(opts))
1605 return repo.commit(message,
1605 return repo.commit(message,
1606 opts.get('user'),
1606 opts.get('user'),
1607 opts.get('date'),
1607 opts.get('date'),
1608 match,
1608 match,
1609 editor=editor,
1609 editor=editor,
1610 extra=extra)
1610 extra=extra)
1611
1611
1612 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1612 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1613
1613
1614 if not node:
1614 if not node:
1615 stat = cmdutil.postcommitstatus(repo, pats, opts)
1615 stat = cmdutil.postcommitstatus(repo, pats, opts)
1616 if stat[3]:
1616 if stat[3]:
1617 ui.status(_("nothing changed (%d missing files, see "
1617 ui.status(_("nothing changed (%d missing files, see "
1618 "'hg status')\n") % len(stat[3]))
1618 "'hg status')\n") % len(stat[3]))
1619 else:
1619 else:
1620 ui.status(_("nothing changed\n"))
1620 ui.status(_("nothing changed\n"))
1621 return 1
1621 return 1
1622
1622
1623 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1623 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1624
1624
1625 @command('config|showconfig|debugconfig',
1625 @command('config|showconfig|debugconfig',
1626 [('u', 'untrusted', None, _('show untrusted configuration options')),
1626 [('u', 'untrusted', None, _('show untrusted configuration options')),
1627 ('e', 'edit', None, _('edit user config')),
1627 ('e', 'edit', None, _('edit user config')),
1628 ('l', 'local', None, _('edit repository config')),
1628 ('l', 'local', None, _('edit repository config')),
1629 ('g', 'global', None, _('edit global config'))] + formatteropts,
1629 ('g', 'global', None, _('edit global config'))] + formatteropts,
1630 _('[-u] [NAME]...'),
1630 _('[-u] [NAME]...'),
1631 optionalrepo=True, cmdtype=readonly)
1631 optionalrepo=True, cmdtype=readonly)
1632 def config(ui, repo, *values, **opts):
1632 def config(ui, repo, *values, **opts):
1633 """show combined config settings from all hgrc files
1633 """show combined config settings from all hgrc files
1634
1634
1635 With no arguments, print names and values of all config items.
1635 With no arguments, print names and values of all config items.
1636
1636
1637 With one argument of the form section.name, print just the value
1637 With one argument of the form section.name, print just the value
1638 of that config item.
1638 of that config item.
1639
1639
1640 With multiple arguments, print names and values of all config
1640 With multiple arguments, print names and values of all config
1641 items with matching section names or section.names.
1641 items with matching section names or section.names.
1642
1642
1643 With --edit, start an editor on the user-level config file. With
1643 With --edit, start an editor on the user-level config file. With
1644 --global, edit the system-wide config file. With --local, edit the
1644 --global, edit the system-wide config file. With --local, edit the
1645 repository-level config file.
1645 repository-level config file.
1646
1646
1647 With --debug, the source (filename and line number) is printed
1647 With --debug, the source (filename and line number) is printed
1648 for each config item.
1648 for each config item.
1649
1649
1650 See :hg:`help config` for more information about config files.
1650 See :hg:`help config` for more information about config files.
1651
1651
1652 Returns 0 on success, 1 if NAME does not exist.
1652 Returns 0 on success, 1 if NAME does not exist.
1653
1653
1654 """
1654 """
1655
1655
1656 opts = pycompat.byteskwargs(opts)
1656 opts = pycompat.byteskwargs(opts)
1657 if opts.get('edit') or opts.get('local') or opts.get('global'):
1657 if opts.get('edit') or opts.get('local') or opts.get('global'):
1658 if opts.get('local') and opts.get('global'):
1658 if opts.get('local') and opts.get('global'):
1659 raise error.Abort(_("can't use --local and --global together"))
1659 raise error.Abort(_("can't use --local and --global together"))
1660
1660
1661 if opts.get('local'):
1661 if opts.get('local'):
1662 if not repo:
1662 if not repo:
1663 raise error.Abort(_("can't use --local outside a repository"))
1663 raise error.Abort(_("can't use --local outside a repository"))
1664 paths = [repo.vfs.join('hgrc')]
1664 paths = [repo.vfs.join('hgrc')]
1665 elif opts.get('global'):
1665 elif opts.get('global'):
1666 paths = rcutil.systemrcpath()
1666 paths = rcutil.systemrcpath()
1667 else:
1667 else:
1668 paths = rcutil.userrcpath()
1668 paths = rcutil.userrcpath()
1669
1669
1670 for f in paths:
1670 for f in paths:
1671 if os.path.exists(f):
1671 if os.path.exists(f):
1672 break
1672 break
1673 else:
1673 else:
1674 if opts.get('global'):
1674 if opts.get('global'):
1675 samplehgrc = uimod.samplehgrcs['global']
1675 samplehgrc = uimod.samplehgrcs['global']
1676 elif opts.get('local'):
1676 elif opts.get('local'):
1677 samplehgrc = uimod.samplehgrcs['local']
1677 samplehgrc = uimod.samplehgrcs['local']
1678 else:
1678 else:
1679 samplehgrc = uimod.samplehgrcs['user']
1679 samplehgrc = uimod.samplehgrcs['user']
1680
1680
1681 f = paths[0]
1681 f = paths[0]
1682 fp = open(f, "wb")
1682 fp = open(f, "wb")
1683 fp.write(util.tonativeeol(samplehgrc))
1683 fp.write(util.tonativeeol(samplehgrc))
1684 fp.close()
1684 fp.close()
1685
1685
1686 editor = ui.geteditor()
1686 editor = ui.geteditor()
1687 ui.system("%s \"%s\"" % (editor, f),
1687 ui.system("%s \"%s\"" % (editor, f),
1688 onerr=error.Abort, errprefix=_("edit failed"),
1688 onerr=error.Abort, errprefix=_("edit failed"),
1689 blockedtag='config_edit')
1689 blockedtag='config_edit')
1690 return
1690 return
1691 ui.pager('config')
1691 ui.pager('config')
1692 fm = ui.formatter('config', opts)
1692 fm = ui.formatter('config', opts)
1693 for t, f in rcutil.rccomponents():
1693 for t, f in rcutil.rccomponents():
1694 if t == 'path':
1694 if t == 'path':
1695 ui.debug('read config from: %s\n' % f)
1695 ui.debug('read config from: %s\n' % f)
1696 elif t == 'items':
1696 elif t == 'items':
1697 for section, name, value, source in f:
1697 for section, name, value, source in f:
1698 ui.debug('set config by: %s\n' % source)
1698 ui.debug('set config by: %s\n' % source)
1699 else:
1699 else:
1700 raise error.ProgrammingError('unknown rctype: %s' % t)
1700 raise error.ProgrammingError('unknown rctype: %s' % t)
1701 untrusted = bool(opts.get('untrusted'))
1701 untrusted = bool(opts.get('untrusted'))
1702
1702
1703 selsections = selentries = []
1703 selsections = selentries = []
1704 if values:
1704 if values:
1705 selsections = [v for v in values if '.' not in v]
1705 selsections = [v for v in values if '.' not in v]
1706 selentries = [v for v in values if '.' in v]
1706 selentries = [v for v in values if '.' in v]
1707 uniquesel = (len(selentries) == 1 and not selsections)
1707 uniquesel = (len(selentries) == 1 and not selsections)
1708 selsections = set(selsections)
1708 selsections = set(selsections)
1709 selentries = set(selentries)
1709 selentries = set(selentries)
1710
1710
1711 matched = False
1711 matched = False
1712 for section, name, value in ui.walkconfig(untrusted=untrusted):
1712 for section, name, value in ui.walkconfig(untrusted=untrusted):
1713 source = ui.configsource(section, name, untrusted)
1713 source = ui.configsource(section, name, untrusted)
1714 value = pycompat.bytestr(value)
1714 value = pycompat.bytestr(value)
1715 if fm.isplain():
1715 if fm.isplain():
1716 source = source or 'none'
1716 source = source or 'none'
1717 value = value.replace('\n', '\\n')
1717 value = value.replace('\n', '\\n')
1718 entryname = section + '.' + name
1718 entryname = section + '.' + name
1719 if values and not (section in selsections or entryname in selentries):
1719 if values and not (section in selsections or entryname in selentries):
1720 continue
1720 continue
1721 fm.startitem()
1721 fm.startitem()
1722 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1722 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1723 if uniquesel:
1723 if uniquesel:
1724 fm.data(name=entryname)
1724 fm.data(name=entryname)
1725 fm.write('value', '%s\n', value)
1725 fm.write('value', '%s\n', value)
1726 else:
1726 else:
1727 fm.write('name value', '%s=%s\n', entryname, value)
1727 fm.write('name value', '%s=%s\n', entryname, value)
1728 matched = True
1728 matched = True
1729 fm.end()
1729 fm.end()
1730 if matched:
1730 if matched:
1731 return 0
1731 return 0
1732 return 1
1732 return 1
1733
1733
1734 @command('copy|cp',
1734 @command('copy|cp',
1735 [('A', 'after', None, _('record a copy that has already occurred')),
1735 [('A', 'after', None, _('record a copy that has already occurred')),
1736 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1736 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1737 ] + walkopts + dryrunopts,
1737 ] + walkopts + dryrunopts,
1738 _('[OPTION]... [SOURCE]... DEST'))
1738 _('[OPTION]... [SOURCE]... DEST'))
1739 def copy(ui, repo, *pats, **opts):
1739 def copy(ui, repo, *pats, **opts):
1740 """mark files as copied for the next commit
1740 """mark files as copied for the next commit
1741
1741
1742 Mark dest as having copies of source files. If dest is a
1742 Mark dest as having copies of source files. If dest is a
1743 directory, copies are put in that directory. If dest is a file,
1743 directory, copies are put in that directory. If dest is a file,
1744 the source must be a single file.
1744 the source must be a single file.
1745
1745
1746 By default, this command copies the contents of files as they
1746 By default, this command copies the contents of files as they
1747 exist in the working directory. If invoked with -A/--after, the
1747 exist in the working directory. If invoked with -A/--after, the
1748 operation is recorded, but no copying is performed.
1748 operation is recorded, but no copying is performed.
1749
1749
1750 This command takes effect with the next commit. To undo a copy
1750 This command takes effect with the next commit. To undo a copy
1751 before that, see :hg:`revert`.
1751 before that, see :hg:`revert`.
1752
1752
1753 Returns 0 on success, 1 if errors are encountered.
1753 Returns 0 on success, 1 if errors are encountered.
1754 """
1754 """
1755 opts = pycompat.byteskwargs(opts)
1755 opts = pycompat.byteskwargs(opts)
1756 with repo.wlock(False):
1756 with repo.wlock(False):
1757 return cmdutil.copy(ui, repo, pats, opts)
1757 return cmdutil.copy(ui, repo, pats, opts)
1758
1758
1759 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1759 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1760 def debugcommands(ui, cmd='', *args):
1760 def debugcommands(ui, cmd='', *args):
1761 """list all available commands and options"""
1761 """list all available commands and options"""
1762 for cmd, vals in sorted(table.iteritems()):
1762 for cmd, vals in sorted(table.iteritems()):
1763 cmd = cmd.split('|')[0].strip('^')
1763 cmd = cmd.split('|')[0].strip('^')
1764 opts = ', '.join([i[1] for i in vals[1]])
1764 opts = ', '.join([i[1] for i in vals[1]])
1765 ui.write('%s: %s\n' % (cmd, opts))
1765 ui.write('%s: %s\n' % (cmd, opts))
1766
1766
1767 @command('debugcomplete',
1767 @command('debugcomplete',
1768 [('o', 'options', None, _('show the command options'))],
1768 [('o', 'options', None, _('show the command options'))],
1769 _('[-o] CMD'),
1769 _('[-o] CMD'),
1770 norepo=True)
1770 norepo=True)
1771 def debugcomplete(ui, cmd='', **opts):
1771 def debugcomplete(ui, cmd='', **opts):
1772 """returns the completion list associated with the given command"""
1772 """returns the completion list associated with the given command"""
1773
1773
1774 if opts.get(r'options'):
1774 if opts.get(r'options'):
1775 options = []
1775 options = []
1776 otables = [globalopts]
1776 otables = [globalopts]
1777 if cmd:
1777 if cmd:
1778 aliases, entry = cmdutil.findcmd(cmd, table, False)
1778 aliases, entry = cmdutil.findcmd(cmd, table, False)
1779 otables.append(entry[1])
1779 otables.append(entry[1])
1780 for t in otables:
1780 for t in otables:
1781 for o in t:
1781 for o in t:
1782 if "(DEPRECATED)" in o[3]:
1782 if "(DEPRECATED)" in o[3]:
1783 continue
1783 continue
1784 if o[0]:
1784 if o[0]:
1785 options.append('-%s' % o[0])
1785 options.append('-%s' % o[0])
1786 options.append('--%s' % o[1])
1786 options.append('--%s' % o[1])
1787 ui.write("%s\n" % "\n".join(options))
1787 ui.write("%s\n" % "\n".join(options))
1788 return
1788 return
1789
1789
1790 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1790 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1791 if ui.verbose:
1791 if ui.verbose:
1792 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1792 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1793 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1793 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1794
1794
1795 @command('^diff',
1795 @command('^diff',
1796 [('r', 'rev', [], _('revision'), _('REV')),
1796 [('r', 'rev', [], _('revision'), _('REV')),
1797 ('c', 'change', '', _('change made by revision'), _('REV'))
1797 ('c', 'change', '', _('change made by revision'), _('REV'))
1798 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1798 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1799 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1799 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1800 inferrepo=True, cmdtype=readonly)
1800 inferrepo=True, cmdtype=readonly)
1801 def diff(ui, repo, *pats, **opts):
1801 def diff(ui, repo, *pats, **opts):
1802 """diff repository (or selected files)
1802 """diff repository (or selected files)
1803
1803
1804 Show differences between revisions for the specified files.
1804 Show differences between revisions for the specified files.
1805
1805
1806 Differences between files are shown using the unified diff format.
1806 Differences between files are shown using the unified diff format.
1807
1807
1808 .. note::
1808 .. note::
1809
1809
1810 :hg:`diff` may generate unexpected results for merges, as it will
1810 :hg:`diff` may generate unexpected results for merges, as it will
1811 default to comparing against the working directory's first
1811 default to comparing against the working directory's first
1812 parent changeset if no revisions are specified.
1812 parent changeset if no revisions are specified.
1813
1813
1814 When two revision arguments are given, then changes are shown
1814 When two revision arguments are given, then changes are shown
1815 between those revisions. If only one revision is specified then
1815 between those revisions. If only one revision is specified then
1816 that revision is compared to the working directory, and, when no
1816 that revision is compared to the working directory, and, when no
1817 revisions are specified, the working directory files are compared
1817 revisions are specified, the working directory files are compared
1818 to its first parent.
1818 to its first parent.
1819
1819
1820 Alternatively you can specify -c/--change with a revision to see
1820 Alternatively you can specify -c/--change with a revision to see
1821 the changes in that changeset relative to its first parent.
1821 the changes in that changeset relative to its first parent.
1822
1822
1823 Without the -a/--text option, diff will avoid generating diffs of
1823 Without the -a/--text option, diff will avoid generating diffs of
1824 files it detects as binary. With -a, diff will generate a diff
1824 files it detects as binary. With -a, diff will generate a diff
1825 anyway, probably with undesirable results.
1825 anyway, probably with undesirable results.
1826
1826
1827 Use the -g/--git option to generate diffs in the git extended diff
1827 Use the -g/--git option to generate diffs in the git extended diff
1828 format. For more information, read :hg:`help diffs`.
1828 format. For more information, read :hg:`help diffs`.
1829
1829
1830 .. container:: verbose
1830 .. container:: verbose
1831
1831
1832 Examples:
1832 Examples:
1833
1833
1834 - compare a file in the current working directory to its parent::
1834 - compare a file in the current working directory to its parent::
1835
1835
1836 hg diff foo.c
1836 hg diff foo.c
1837
1837
1838 - compare two historical versions of a directory, with rename info::
1838 - compare two historical versions of a directory, with rename info::
1839
1839
1840 hg diff --git -r 1.0:1.2 lib/
1840 hg diff --git -r 1.0:1.2 lib/
1841
1841
1842 - get change stats relative to the last change on some date::
1842 - get change stats relative to the last change on some date::
1843
1843
1844 hg diff --stat -r "date('may 2')"
1844 hg diff --stat -r "date('may 2')"
1845
1845
1846 - diff all newly-added files that contain a keyword::
1846 - diff all newly-added files that contain a keyword::
1847
1847
1848 hg diff "set:added() and grep(GNU)"
1848 hg diff "set:added() and grep(GNU)"
1849
1849
1850 - compare a revision and its parents::
1850 - compare a revision and its parents::
1851
1851
1852 hg diff -c 9353 # compare against first parent
1852 hg diff -c 9353 # compare against first parent
1853 hg diff -r 9353^:9353 # same using revset syntax
1853 hg diff -r 9353^:9353 # same using revset syntax
1854 hg diff -r 9353^2:9353 # compare against the second parent
1854 hg diff -r 9353^2:9353 # compare against the second parent
1855
1855
1856 Returns 0 on success.
1856 Returns 0 on success.
1857 """
1857 """
1858
1858
1859 opts = pycompat.byteskwargs(opts)
1859 opts = pycompat.byteskwargs(opts)
1860 revs = opts.get('rev')
1860 revs = opts.get('rev')
1861 change = opts.get('change')
1861 change = opts.get('change')
1862 stat = opts.get('stat')
1862 stat = opts.get('stat')
1863 reverse = opts.get('reverse')
1863 reverse = opts.get('reverse')
1864
1864
1865 if revs and change:
1865 if revs and change:
1866 msg = _('cannot specify --rev and --change at the same time')
1866 msg = _('cannot specify --rev and --change at the same time')
1867 raise error.Abort(msg)
1867 raise error.Abort(msg)
1868 elif change:
1868 elif change:
1869 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1869 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1870 node2 = scmutil.revsingle(repo, change, None).node()
1870 node2 = scmutil.revsingle(repo, change, None).node()
1871 node1 = repo[node2].p1().node()
1871 node1 = repo[node2].p1().node()
1872 else:
1872 else:
1873 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1873 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1874 node1, node2 = scmutil.revpair(repo, revs)
1874 node1, node2 = scmutil.revpair(repo, revs)
1875
1875
1876 if reverse:
1876 if reverse:
1877 node1, node2 = node2, node1
1877 node1, node2 = node2, node1
1878
1878
1879 diffopts = patch.diffallopts(ui, opts)
1879 diffopts = patch.diffallopts(ui, opts)
1880 m = scmutil.match(repo[node2], pats, opts)
1880 m = scmutil.match(repo[node2], pats, opts)
1881 ui.pager('diff')
1881 ui.pager('diff')
1882 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1882 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1883 listsubrepos=opts.get('subrepos'),
1883 listsubrepos=opts.get('subrepos'),
1884 root=opts.get('root'))
1884 root=opts.get('root'))
1885
1885
1886 @command('^export',
1886 @command('^export',
1887 [('o', 'output', '',
1887 [('o', 'output', '',
1888 _('print output to file with formatted name'), _('FORMAT')),
1888 _('print output to file with formatted name'), _('FORMAT')),
1889 ('', 'switch-parent', None, _('diff against the second parent')),
1889 ('', 'switch-parent', None, _('diff against the second parent')),
1890 ('r', 'rev', [], _('revisions to export'), _('REV')),
1890 ('r', 'rev', [], _('revisions to export'), _('REV')),
1891 ] + diffopts,
1891 ] + diffopts,
1892 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1892 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1893 def export(ui, repo, *changesets, **opts):
1893 def export(ui, repo, *changesets, **opts):
1894 """dump the header and diffs for one or more changesets
1894 """dump the header and diffs for one or more changesets
1895
1895
1896 Print the changeset header and diffs for one or more revisions.
1896 Print the changeset header and diffs for one or more revisions.
1897 If no revision is given, the parent of the working directory is used.
1897 If no revision is given, the parent of the working directory is used.
1898
1898
1899 The information shown in the changeset header is: author, date,
1899 The information shown in the changeset header is: author, date,
1900 branch name (if non-default), changeset hash, parent(s) and commit
1900 branch name (if non-default), changeset hash, parent(s) and commit
1901 comment.
1901 comment.
1902
1902
1903 .. note::
1903 .. note::
1904
1904
1905 :hg:`export` may generate unexpected diff output for merge
1905 :hg:`export` may generate unexpected diff output for merge
1906 changesets, as it will compare the merge changeset against its
1906 changesets, as it will compare the merge changeset against its
1907 first parent only.
1907 first parent only.
1908
1908
1909 Output may be to a file, in which case the name of the file is
1909 Output may be to a file, in which case the name of the file is
1910 given using a template string. See :hg:`help templates`. In addition
1910 given using a template string. See :hg:`help templates`. In addition
1911 to the common template keywords, the following formatting rules are
1911 to the common template keywords, the following formatting rules are
1912 supported:
1912 supported:
1913
1913
1914 :``%%``: literal "%" character
1914 :``%%``: literal "%" character
1915 :``%H``: changeset hash (40 hexadecimal digits)
1915 :``%H``: changeset hash (40 hexadecimal digits)
1916 :``%N``: number of patches being generated
1916 :``%N``: number of patches being generated
1917 :``%R``: changeset revision number
1917 :``%R``: changeset revision number
1918 :``%b``: basename of the exporting repository
1918 :``%b``: basename of the exporting repository
1919 :``%h``: short-form changeset hash (12 hexadecimal digits)
1919 :``%h``: short-form changeset hash (12 hexadecimal digits)
1920 :``%m``: first line of the commit message (only alphanumeric characters)
1920 :``%m``: first line of the commit message (only alphanumeric characters)
1921 :``%n``: zero-padded sequence number, starting at 1
1921 :``%n``: zero-padded sequence number, starting at 1
1922 :``%r``: zero-padded changeset revision number
1922 :``%r``: zero-padded changeset revision number
1923 :``\\``: literal "\\" character
1923 :``\\``: literal "\\" character
1924
1924
1925 Without the -a/--text option, export will avoid generating diffs
1925 Without the -a/--text option, export will avoid generating diffs
1926 of files it detects as binary. With -a, export will generate a
1926 of files it detects as binary. With -a, export will generate a
1927 diff anyway, probably with undesirable results.
1927 diff anyway, probably with undesirable results.
1928
1928
1929 Use the -g/--git option to generate diffs in the git extended diff
1929 Use the -g/--git option to generate diffs in the git extended diff
1930 format. See :hg:`help diffs` for more information.
1930 format. See :hg:`help diffs` for more information.
1931
1931
1932 With the --switch-parent option, the diff will be against the
1932 With the --switch-parent option, the diff will be against the
1933 second parent. It can be useful to review a merge.
1933 second parent. It can be useful to review a merge.
1934
1934
1935 .. container:: verbose
1935 .. container:: verbose
1936
1936
1937 Examples:
1937 Examples:
1938
1938
1939 - use export and import to transplant a bugfix to the current
1939 - use export and import to transplant a bugfix to the current
1940 branch::
1940 branch::
1941
1941
1942 hg export -r 9353 | hg import -
1942 hg export -r 9353 | hg import -
1943
1943
1944 - export all the changesets between two revisions to a file with
1944 - export all the changesets between two revisions to a file with
1945 rename information::
1945 rename information::
1946
1946
1947 hg export --git -r 123:150 > changes.txt
1947 hg export --git -r 123:150 > changes.txt
1948
1948
1949 - split outgoing changes into a series of patches with
1949 - split outgoing changes into a series of patches with
1950 descriptive names::
1950 descriptive names::
1951
1951
1952 hg export -r "outgoing()" -o "%n-%m.patch"
1952 hg export -r "outgoing()" -o "%n-%m.patch"
1953
1953
1954 Returns 0 on success.
1954 Returns 0 on success.
1955 """
1955 """
1956 opts = pycompat.byteskwargs(opts)
1956 opts = pycompat.byteskwargs(opts)
1957 changesets += tuple(opts.get('rev', []))
1957 changesets += tuple(opts.get('rev', []))
1958 if not changesets:
1958 if not changesets:
1959 changesets = ['.']
1959 changesets = ['.']
1960 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1960 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1961 revs = scmutil.revrange(repo, changesets)
1961 revs = scmutil.revrange(repo, changesets)
1962 if not revs:
1962 if not revs:
1963 raise error.Abort(_("export requires at least one changeset"))
1963 raise error.Abort(_("export requires at least one changeset"))
1964 if len(revs) > 1:
1964 if len(revs) > 1:
1965 ui.note(_('exporting patches:\n'))
1965 ui.note(_('exporting patches:\n'))
1966 else:
1966 else:
1967 ui.note(_('exporting patch:\n'))
1967 ui.note(_('exporting patch:\n'))
1968 ui.pager('export')
1968 ui.pager('export')
1969 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1969 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1970 switch_parent=opts.get('switch_parent'),
1970 switch_parent=opts.get('switch_parent'),
1971 opts=patch.diffallopts(ui, opts))
1971 opts=patch.diffallopts(ui, opts))
1972
1972
1973 @command('files',
1973 @command('files',
1974 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1974 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1975 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1975 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1976 ] + walkopts + formatteropts + subrepoopts,
1976 ] + walkopts + formatteropts + subrepoopts,
1977 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1977 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1978 def files(ui, repo, *pats, **opts):
1978 def files(ui, repo, *pats, **opts):
1979 """list tracked files
1979 """list tracked files
1980
1980
1981 Print files under Mercurial control in the working directory or
1981 Print files under Mercurial control in the working directory or
1982 specified revision for given files (excluding removed files).
1982 specified revision for given files (excluding removed files).
1983 Files can be specified as filenames or filesets.
1983 Files can be specified as filenames or filesets.
1984
1984
1985 If no files are given to match, this command prints the names
1985 If no files are given to match, this command prints the names
1986 of all files under Mercurial control.
1986 of all files under Mercurial control.
1987
1987
1988 .. container:: verbose
1988 .. container:: verbose
1989
1989
1990 Examples:
1990 Examples:
1991
1991
1992 - list all files under the current directory::
1992 - list all files under the current directory::
1993
1993
1994 hg files .
1994 hg files .
1995
1995
1996 - shows sizes and flags for current revision::
1996 - shows sizes and flags for current revision::
1997
1997
1998 hg files -vr .
1998 hg files -vr .
1999
1999
2000 - list all files named README::
2000 - list all files named README::
2001
2001
2002 hg files -I "**/README"
2002 hg files -I "**/README"
2003
2003
2004 - list all binary files::
2004 - list all binary files::
2005
2005
2006 hg files "set:binary()"
2006 hg files "set:binary()"
2007
2007
2008 - find files containing a regular expression::
2008 - find files containing a regular expression::
2009
2009
2010 hg files "set:grep('bob')"
2010 hg files "set:grep('bob')"
2011
2011
2012 - search tracked file contents with xargs and grep::
2012 - search tracked file contents with xargs and grep::
2013
2013
2014 hg files -0 | xargs -0 grep foo
2014 hg files -0 | xargs -0 grep foo
2015
2015
2016 See :hg:`help patterns` and :hg:`help filesets` for more information
2016 See :hg:`help patterns` and :hg:`help filesets` for more information
2017 on specifying file patterns.
2017 on specifying file patterns.
2018
2018
2019 Returns 0 if a match is found, 1 otherwise.
2019 Returns 0 if a match is found, 1 otherwise.
2020
2020
2021 """
2021 """
2022
2022
2023 opts = pycompat.byteskwargs(opts)
2023 opts = pycompat.byteskwargs(opts)
2024 rev = opts.get('rev')
2024 rev = opts.get('rev')
2025 if rev:
2025 if rev:
2026 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2026 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2027 ctx = scmutil.revsingle(repo, rev, None)
2027 ctx = scmutil.revsingle(repo, rev, None)
2028
2028
2029 end = '\n'
2029 end = '\n'
2030 if opts.get('print0'):
2030 if opts.get('print0'):
2031 end = '\0'
2031 end = '\0'
2032 fmt = '%s' + end
2032 fmt = '%s' + end
2033
2033
2034 m = scmutil.match(ctx, pats, opts)
2034 m = scmutil.match(ctx, pats, opts)
2035 ui.pager('files')
2035 ui.pager('files')
2036 with ui.formatter('files', opts) as fm:
2036 with ui.formatter('files', opts) as fm:
2037 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2037 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2038
2038
2039 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2039 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2040 def forget(ui, repo, *pats, **opts):
2040 def forget(ui, repo, *pats, **opts):
2041 """forget the specified files on the next commit
2041 """forget the specified files on the next commit
2042
2042
2043 Mark the specified files so they will no longer be tracked
2043 Mark the specified files so they will no longer be tracked
2044 after the next commit.
2044 after the next commit.
2045
2045
2046 This only removes files from the current branch, not from the
2046 This only removes files from the current branch, not from the
2047 entire project history, and it does not delete them from the
2047 entire project history, and it does not delete them from the
2048 working directory.
2048 working directory.
2049
2049
2050 To delete the file from the working directory, see :hg:`remove`.
2050 To delete the file from the working directory, see :hg:`remove`.
2051
2051
2052 To undo a forget before the next commit, see :hg:`add`.
2052 To undo a forget before the next commit, see :hg:`add`.
2053
2053
2054 .. container:: verbose
2054 .. container:: verbose
2055
2055
2056 Examples:
2056 Examples:
2057
2057
2058 - forget newly-added binary files::
2058 - forget newly-added binary files::
2059
2059
2060 hg forget "set:added() and binary()"
2060 hg forget "set:added() and binary()"
2061
2061
2062 - forget files that would be excluded by .hgignore::
2062 - forget files that would be excluded by .hgignore::
2063
2063
2064 hg forget "set:hgignore()"
2064 hg forget "set:hgignore()"
2065
2065
2066 Returns 0 on success.
2066 Returns 0 on success.
2067 """
2067 """
2068
2068
2069 opts = pycompat.byteskwargs(opts)
2069 opts = pycompat.byteskwargs(opts)
2070 if not pats:
2070 if not pats:
2071 raise error.Abort(_('no files specified'))
2071 raise error.Abort(_('no files specified'))
2072
2072
2073 m = scmutil.match(repo[None], pats, opts)
2073 m = scmutil.match(repo[None], pats, opts)
2074 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2074 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2075 return rejected and 1 or 0
2075 return rejected and 1 or 0
2076
2076
2077 @command(
2077 @command(
2078 'graft',
2078 'graft',
2079 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2079 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2080 ('c', 'continue', False, _('resume interrupted graft')),
2080 ('c', 'continue', False, _('resume interrupted graft')),
2081 ('e', 'edit', False, _('invoke editor on commit messages')),
2081 ('e', 'edit', False, _('invoke editor on commit messages')),
2082 ('', 'log', None, _('append graft info to log message')),
2082 ('', 'log', None, _('append graft info to log message')),
2083 ('f', 'force', False, _('force graft')),
2083 ('f', 'force', False, _('force graft')),
2084 ('D', 'currentdate', False,
2084 ('D', 'currentdate', False,
2085 _('record the current date as commit date')),
2085 _('record the current date as commit date')),
2086 ('U', 'currentuser', False,
2086 ('U', 'currentuser', False,
2087 _('record the current user as committer'), _('DATE'))]
2087 _('record the current user as committer'), _('DATE'))]
2088 + commitopts2 + mergetoolopts + dryrunopts,
2088 + commitopts2 + mergetoolopts + dryrunopts,
2089 _('[OPTION]... [-r REV]... REV...'))
2089 _('[OPTION]... [-r REV]... REV...'))
2090 def graft(ui, repo, *revs, **opts):
2090 def graft(ui, repo, *revs, **opts):
2091 '''copy changes from other branches onto the current branch
2091 '''copy changes from other branches onto the current branch
2092
2092
2093 This command uses Mercurial's merge logic to copy individual
2093 This command uses Mercurial's merge logic to copy individual
2094 changes from other branches without merging branches in the
2094 changes from other branches without merging branches in the
2095 history graph. This is sometimes known as 'backporting' or
2095 history graph. This is sometimes known as 'backporting' or
2096 'cherry-picking'. By default, graft will copy user, date, and
2096 'cherry-picking'. By default, graft will copy user, date, and
2097 description from the source changesets.
2097 description from the source changesets.
2098
2098
2099 Changesets that are ancestors of the current revision, that have
2099 Changesets that are ancestors of the current revision, that have
2100 already been grafted, or that are merges will be skipped.
2100 already been grafted, or that are merges will be skipped.
2101
2101
2102 If --log is specified, log messages will have a comment appended
2102 If --log is specified, log messages will have a comment appended
2103 of the form::
2103 of the form::
2104
2104
2105 (grafted from CHANGESETHASH)
2105 (grafted from CHANGESETHASH)
2106
2106
2107 If --force is specified, revisions will be grafted even if they
2107 If --force is specified, revisions will be grafted even if they
2108 are already ancestors of, or have been grafted to, the destination.
2108 are already ancestors of, or have been grafted to, the destination.
2109 This is useful when the revisions have since been backed out.
2109 This is useful when the revisions have since been backed out.
2110
2110
2111 If a graft merge results in conflicts, the graft process is
2111 If a graft merge results in conflicts, the graft process is
2112 interrupted so that the current merge can be manually resolved.
2112 interrupted so that the current merge can be manually resolved.
2113 Once all conflicts are addressed, the graft process can be
2113 Once all conflicts are addressed, the graft process can be
2114 continued with the -c/--continue option.
2114 continued with the -c/--continue option.
2115
2115
2116 .. note::
2116 .. note::
2117
2117
2118 The -c/--continue option does not reapply earlier options, except
2118 The -c/--continue option does not reapply earlier options, except
2119 for --force.
2119 for --force.
2120
2120
2121 .. container:: verbose
2121 .. container:: verbose
2122
2122
2123 Examples:
2123 Examples:
2124
2124
2125 - copy a single change to the stable branch and edit its description::
2125 - copy a single change to the stable branch and edit its description::
2126
2126
2127 hg update stable
2127 hg update stable
2128 hg graft --edit 9393
2128 hg graft --edit 9393
2129
2129
2130 - graft a range of changesets with one exception, updating dates::
2130 - graft a range of changesets with one exception, updating dates::
2131
2131
2132 hg graft -D "2085::2093 and not 2091"
2132 hg graft -D "2085::2093 and not 2091"
2133
2133
2134 - continue a graft after resolving conflicts::
2134 - continue a graft after resolving conflicts::
2135
2135
2136 hg graft -c
2136 hg graft -c
2137
2137
2138 - show the source of a grafted changeset::
2138 - show the source of a grafted changeset::
2139
2139
2140 hg log --debug -r .
2140 hg log --debug -r .
2141
2141
2142 - show revisions sorted by date::
2142 - show revisions sorted by date::
2143
2143
2144 hg log -r "sort(all(), date)"
2144 hg log -r "sort(all(), date)"
2145
2145
2146 See :hg:`help revisions` for more about specifying revisions.
2146 See :hg:`help revisions` for more about specifying revisions.
2147
2147
2148 Returns 0 on successful completion.
2148 Returns 0 on successful completion.
2149 '''
2149 '''
2150 with repo.wlock():
2150 with repo.wlock():
2151 return _dograft(ui, repo, *revs, **opts)
2151 return _dograft(ui, repo, *revs, **opts)
2152
2152
2153 def _dograft(ui, repo, *revs, **opts):
2153 def _dograft(ui, repo, *revs, **opts):
2154 opts = pycompat.byteskwargs(opts)
2154 opts = pycompat.byteskwargs(opts)
2155 if revs and opts.get('rev'):
2155 if revs and opts.get('rev'):
2156 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2156 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2157 'revision ordering!\n'))
2157 'revision ordering!\n'))
2158
2158
2159 revs = list(revs)
2159 revs = list(revs)
2160 revs.extend(opts.get('rev'))
2160 revs.extend(opts.get('rev'))
2161
2161
2162 if not opts.get('user') and opts.get('currentuser'):
2162 if not opts.get('user') and opts.get('currentuser'):
2163 opts['user'] = ui.username()
2163 opts['user'] = ui.username()
2164 if not opts.get('date') and opts.get('currentdate'):
2164 if not opts.get('date') and opts.get('currentdate'):
2165 opts['date'] = "%d %d" % dateutil.makedate()
2165 opts['date'] = "%d %d" % dateutil.makedate()
2166
2166
2167 editor = cmdutil.getcommiteditor(editform='graft',
2167 editor = cmdutil.getcommiteditor(editform='graft',
2168 **pycompat.strkwargs(opts))
2168 **pycompat.strkwargs(opts))
2169
2169
2170 cont = False
2170 cont = False
2171 if opts.get('continue'):
2171 if opts.get('continue'):
2172 cont = True
2172 cont = True
2173 if revs:
2173 if revs:
2174 raise error.Abort(_("can't specify --continue and revisions"))
2174 raise error.Abort(_("can't specify --continue and revisions"))
2175 # read in unfinished revisions
2175 # read in unfinished revisions
2176 try:
2176 try:
2177 nodes = repo.vfs.read('graftstate').splitlines()
2177 nodes = repo.vfs.read('graftstate').splitlines()
2178 revs = [repo[node].rev() for node in nodes]
2178 revs = [repo[node].rev() for node in nodes]
2179 except IOError as inst:
2179 except IOError as inst:
2180 if inst.errno != errno.ENOENT:
2180 if inst.errno != errno.ENOENT:
2181 raise
2181 raise
2182 cmdutil.wrongtooltocontinue(repo, _('graft'))
2182 cmdutil.wrongtooltocontinue(repo, _('graft'))
2183 else:
2183 else:
2184 if not revs:
2185 raise error.Abort(_('no revisions specified'))
2184 cmdutil.checkunfinished(repo)
2186 cmdutil.checkunfinished(repo)
2185 cmdutil.bailifchanged(repo)
2187 cmdutil.bailifchanged(repo)
2186 if not revs:
2187 raise error.Abort(_('no revisions specified'))
2188 revs = scmutil.revrange(repo, revs)
2188 revs = scmutil.revrange(repo, revs)
2189
2189
2190 skipped = set()
2190 skipped = set()
2191 # check for merges
2191 # check for merges
2192 for rev in repo.revs('%ld and merge()', revs):
2192 for rev in repo.revs('%ld and merge()', revs):
2193 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2193 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2194 skipped.add(rev)
2194 skipped.add(rev)
2195 revs = [r for r in revs if r not in skipped]
2195 revs = [r for r in revs if r not in skipped]
2196 if not revs:
2196 if not revs:
2197 return -1
2197 return -1
2198
2198
2199 # Don't check in the --continue case, in effect retaining --force across
2199 # Don't check in the --continue case, in effect retaining --force across
2200 # --continues. That's because without --force, any revisions we decided to
2200 # --continues. That's because without --force, any revisions we decided to
2201 # skip would have been filtered out here, so they wouldn't have made their
2201 # skip would have been filtered out here, so they wouldn't have made their
2202 # way to the graftstate. With --force, any revisions we would have otherwise
2202 # way to the graftstate. With --force, any revisions we would have otherwise
2203 # skipped would not have been filtered out, and if they hadn't been applied
2203 # skipped would not have been filtered out, and if they hadn't been applied
2204 # already, they'd have been in the graftstate.
2204 # already, they'd have been in the graftstate.
2205 if not (cont or opts.get('force')):
2205 if not (cont or opts.get('force')):
2206 # check for ancestors of dest branch
2206 # check for ancestors of dest branch
2207 crev = repo['.'].rev()
2207 crev = repo['.'].rev()
2208 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2208 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2209 # XXX make this lazy in the future
2209 # XXX make this lazy in the future
2210 # don't mutate while iterating, create a copy
2210 # don't mutate while iterating, create a copy
2211 for rev in list(revs):
2211 for rev in list(revs):
2212 if rev in ancestors:
2212 if rev in ancestors:
2213 ui.warn(_('skipping ancestor revision %d:%s\n') %
2213 ui.warn(_('skipping ancestor revision %d:%s\n') %
2214 (rev, repo[rev]))
2214 (rev, repo[rev]))
2215 # XXX remove on list is slow
2215 # XXX remove on list is slow
2216 revs.remove(rev)
2216 revs.remove(rev)
2217 if not revs:
2217 if not revs:
2218 return -1
2218 return -1
2219
2219
2220 # analyze revs for earlier grafts
2220 # analyze revs for earlier grafts
2221 ids = {}
2221 ids = {}
2222 for ctx in repo.set("%ld", revs):
2222 for ctx in repo.set("%ld", revs):
2223 ids[ctx.hex()] = ctx.rev()
2223 ids[ctx.hex()] = ctx.rev()
2224 n = ctx.extra().get('source')
2224 n = ctx.extra().get('source')
2225 if n:
2225 if n:
2226 ids[n] = ctx.rev()
2226 ids[n] = ctx.rev()
2227
2227
2228 # check ancestors for earlier grafts
2228 # check ancestors for earlier grafts
2229 ui.debug('scanning for duplicate grafts\n')
2229 ui.debug('scanning for duplicate grafts\n')
2230
2230
2231 # The only changesets we can be sure doesn't contain grafts of any
2231 # The only changesets we can be sure doesn't contain grafts of any
2232 # revs, are the ones that are common ancestors of *all* revs:
2232 # revs, are the ones that are common ancestors of *all* revs:
2233 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2233 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2234 ctx = repo[rev]
2234 ctx = repo[rev]
2235 n = ctx.extra().get('source')
2235 n = ctx.extra().get('source')
2236 if n in ids:
2236 if n in ids:
2237 try:
2237 try:
2238 r = repo[n].rev()
2238 r = repo[n].rev()
2239 except error.RepoLookupError:
2239 except error.RepoLookupError:
2240 r = None
2240 r = None
2241 if r in revs:
2241 if r in revs:
2242 ui.warn(_('skipping revision %d:%s '
2242 ui.warn(_('skipping revision %d:%s '
2243 '(already grafted to %d:%s)\n')
2243 '(already grafted to %d:%s)\n')
2244 % (r, repo[r], rev, ctx))
2244 % (r, repo[r], rev, ctx))
2245 revs.remove(r)
2245 revs.remove(r)
2246 elif ids[n] in revs:
2246 elif ids[n] in revs:
2247 if r is None:
2247 if r is None:
2248 ui.warn(_('skipping already grafted revision %d:%s '
2248 ui.warn(_('skipping already grafted revision %d:%s '
2249 '(%d:%s also has unknown origin %s)\n')
2249 '(%d:%s also has unknown origin %s)\n')
2250 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2250 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2251 else:
2251 else:
2252 ui.warn(_('skipping already grafted revision %d:%s '
2252 ui.warn(_('skipping already grafted revision %d:%s '
2253 '(%d:%s also has origin %d:%s)\n')
2253 '(%d:%s also has origin %d:%s)\n')
2254 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2254 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2255 revs.remove(ids[n])
2255 revs.remove(ids[n])
2256 elif ctx.hex() in ids:
2256 elif ctx.hex() in ids:
2257 r = ids[ctx.hex()]
2257 r = ids[ctx.hex()]
2258 ui.warn(_('skipping already grafted revision %d:%s '
2258 ui.warn(_('skipping already grafted revision %d:%s '
2259 '(was grafted from %d:%s)\n') %
2259 '(was grafted from %d:%s)\n') %
2260 (r, repo[r], rev, ctx))
2260 (r, repo[r], rev, ctx))
2261 revs.remove(r)
2261 revs.remove(r)
2262 if not revs:
2262 if not revs:
2263 return -1
2263 return -1
2264
2264
2265 for pos, ctx in enumerate(repo.set("%ld", revs)):
2265 for pos, ctx in enumerate(repo.set("%ld", revs)):
2266 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2266 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2267 ctx.description().split('\n', 1)[0])
2267 ctx.description().split('\n', 1)[0])
2268 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2268 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2269 if names:
2269 if names:
2270 desc += ' (%s)' % ' '.join(names)
2270 desc += ' (%s)' % ' '.join(names)
2271 ui.status(_('grafting %s\n') % desc)
2271 ui.status(_('grafting %s\n') % desc)
2272 if opts.get('dry_run'):
2272 if opts.get('dry_run'):
2273 continue
2273 continue
2274
2274
2275 source = ctx.extra().get('source')
2275 source = ctx.extra().get('source')
2276 extra = {}
2276 extra = {}
2277 if source:
2277 if source:
2278 extra['source'] = source
2278 extra['source'] = source
2279 extra['intermediate-source'] = ctx.hex()
2279 extra['intermediate-source'] = ctx.hex()
2280 else:
2280 else:
2281 extra['source'] = ctx.hex()
2281 extra['source'] = ctx.hex()
2282 user = ctx.user()
2282 user = ctx.user()
2283 if opts.get('user'):
2283 if opts.get('user'):
2284 user = opts['user']
2284 user = opts['user']
2285 date = ctx.date()
2285 date = ctx.date()
2286 if opts.get('date'):
2286 if opts.get('date'):
2287 date = opts['date']
2287 date = opts['date']
2288 message = ctx.description()
2288 message = ctx.description()
2289 if opts.get('log'):
2289 if opts.get('log'):
2290 message += '\n(grafted from %s)' % ctx.hex()
2290 message += '\n(grafted from %s)' % ctx.hex()
2291
2291
2292 # we don't merge the first commit when continuing
2292 # we don't merge the first commit when continuing
2293 if not cont:
2293 if not cont:
2294 # perform the graft merge with p1(rev) as 'ancestor'
2294 # perform the graft merge with p1(rev) as 'ancestor'
2295 try:
2295 try:
2296 # ui.forcemerge is an internal variable, do not document
2296 # ui.forcemerge is an internal variable, do not document
2297 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2297 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2298 'graft')
2298 'graft')
2299 stats = mergemod.graft(repo, ctx, ctx.p1(),
2299 stats = mergemod.graft(repo, ctx, ctx.p1(),
2300 ['local', 'graft'])
2300 ['local', 'graft'])
2301 finally:
2301 finally:
2302 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2302 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2303 # report any conflicts
2303 # report any conflicts
2304 if stats and stats[3] > 0:
2304 if stats and stats[3] > 0:
2305 # write out state for --continue
2305 # write out state for --continue
2306 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2306 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2307 repo.vfs.write('graftstate', ''.join(nodelines))
2307 repo.vfs.write('graftstate', ''.join(nodelines))
2308 extra = ''
2308 extra = ''
2309 if opts.get('user'):
2309 if opts.get('user'):
2310 extra += ' --user %s' % util.shellquote(opts['user'])
2310 extra += ' --user %s' % util.shellquote(opts['user'])
2311 if opts.get('date'):
2311 if opts.get('date'):
2312 extra += ' --date %s' % util.shellquote(opts['date'])
2312 extra += ' --date %s' % util.shellquote(opts['date'])
2313 if opts.get('log'):
2313 if opts.get('log'):
2314 extra += ' --log'
2314 extra += ' --log'
2315 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2315 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2316 raise error.Abort(
2316 raise error.Abort(
2317 _("unresolved conflicts, can't continue"),
2317 _("unresolved conflicts, can't continue"),
2318 hint=hint)
2318 hint=hint)
2319 else:
2319 else:
2320 cont = False
2320 cont = False
2321
2321
2322 # commit
2322 # commit
2323 node = repo.commit(text=message, user=user,
2323 node = repo.commit(text=message, user=user,
2324 date=date, extra=extra, editor=editor)
2324 date=date, extra=extra, editor=editor)
2325 if node is None:
2325 if node is None:
2326 ui.warn(
2326 ui.warn(
2327 _('note: graft of %d:%s created no changes to commit\n') %
2327 _('note: graft of %d:%s created no changes to commit\n') %
2328 (ctx.rev(), ctx))
2328 (ctx.rev(), ctx))
2329
2329
2330 # remove state when we complete successfully
2330 # remove state when we complete successfully
2331 if not opts.get('dry_run'):
2331 if not opts.get('dry_run'):
2332 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2332 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2333
2333
2334 return 0
2334 return 0
2335
2335
2336 @command('grep',
2336 @command('grep',
2337 [('0', 'print0', None, _('end fields with NUL')),
2337 [('0', 'print0', None, _('end fields with NUL')),
2338 ('', 'all', None, _('print all revisions that match')),
2338 ('', 'all', None, _('print all revisions that match')),
2339 ('a', 'text', None, _('treat all files as text')),
2339 ('a', 'text', None, _('treat all files as text')),
2340 ('f', 'follow', None,
2340 ('f', 'follow', None,
2341 _('follow changeset history,'
2341 _('follow changeset history,'
2342 ' or file history across copies and renames')),
2342 ' or file history across copies and renames')),
2343 ('i', 'ignore-case', None, _('ignore case when matching')),
2343 ('i', 'ignore-case', None, _('ignore case when matching')),
2344 ('l', 'files-with-matches', None,
2344 ('l', 'files-with-matches', None,
2345 _('print only filenames and revisions that match')),
2345 _('print only filenames and revisions that match')),
2346 ('n', 'line-number', None, _('print matching line numbers')),
2346 ('n', 'line-number', None, _('print matching line numbers')),
2347 ('r', 'rev', [],
2347 ('r', 'rev', [],
2348 _('only search files changed within revision range'), _('REV')),
2348 _('only search files changed within revision range'), _('REV')),
2349 ('u', 'user', None, _('list the author (long with -v)')),
2349 ('u', 'user', None, _('list the author (long with -v)')),
2350 ('d', 'date', None, _('list the date (short with -q)')),
2350 ('d', 'date', None, _('list the date (short with -q)')),
2351 ] + formatteropts + walkopts,
2351 ] + formatteropts + walkopts,
2352 _('[OPTION]... PATTERN [FILE]...'),
2352 _('[OPTION]... PATTERN [FILE]...'),
2353 inferrepo=True, cmdtype=readonly)
2353 inferrepo=True, cmdtype=readonly)
2354 def grep(ui, repo, pattern, *pats, **opts):
2354 def grep(ui, repo, pattern, *pats, **opts):
2355 """search revision history for a pattern in specified files
2355 """search revision history for a pattern in specified files
2356
2356
2357 Search revision history for a regular expression in the specified
2357 Search revision history for a regular expression in the specified
2358 files or the entire project.
2358 files or the entire project.
2359
2359
2360 By default, grep prints the most recent revision number for each
2360 By default, grep prints the most recent revision number for each
2361 file in which it finds a match. To get it to print every revision
2361 file in which it finds a match. To get it to print every revision
2362 that contains a change in match status ("-" for a match that becomes
2362 that contains a change in match status ("-" for a match that becomes
2363 a non-match, or "+" for a non-match that becomes a match), use the
2363 a non-match, or "+" for a non-match that becomes a match), use the
2364 --all flag.
2364 --all flag.
2365
2365
2366 PATTERN can be any Python (roughly Perl-compatible) regular
2366 PATTERN can be any Python (roughly Perl-compatible) regular
2367 expression.
2367 expression.
2368
2368
2369 If no FILEs are specified (and -f/--follow isn't set), all files in
2369 If no FILEs are specified (and -f/--follow isn't set), all files in
2370 the repository are searched, including those that don't exist in the
2370 the repository are searched, including those that don't exist in the
2371 current branch or have been deleted in a prior changeset.
2371 current branch or have been deleted in a prior changeset.
2372
2372
2373 Returns 0 if a match is found, 1 otherwise.
2373 Returns 0 if a match is found, 1 otherwise.
2374 """
2374 """
2375 opts = pycompat.byteskwargs(opts)
2375 opts = pycompat.byteskwargs(opts)
2376 reflags = re.M
2376 reflags = re.M
2377 if opts.get('ignore_case'):
2377 if opts.get('ignore_case'):
2378 reflags |= re.I
2378 reflags |= re.I
2379 try:
2379 try:
2380 regexp = util.re.compile(pattern, reflags)
2380 regexp = util.re.compile(pattern, reflags)
2381 except re.error as inst:
2381 except re.error as inst:
2382 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2382 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2383 return 1
2383 return 1
2384 sep, eol = ':', '\n'
2384 sep, eol = ':', '\n'
2385 if opts.get('print0'):
2385 if opts.get('print0'):
2386 sep = eol = '\0'
2386 sep = eol = '\0'
2387
2387
2388 getfile = util.lrucachefunc(repo.file)
2388 getfile = util.lrucachefunc(repo.file)
2389
2389
2390 def matchlines(body):
2390 def matchlines(body):
2391 begin = 0
2391 begin = 0
2392 linenum = 0
2392 linenum = 0
2393 while begin < len(body):
2393 while begin < len(body):
2394 match = regexp.search(body, begin)
2394 match = regexp.search(body, begin)
2395 if not match:
2395 if not match:
2396 break
2396 break
2397 mstart, mend = match.span()
2397 mstart, mend = match.span()
2398 linenum += body.count('\n', begin, mstart) + 1
2398 linenum += body.count('\n', begin, mstart) + 1
2399 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2399 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2400 begin = body.find('\n', mend) + 1 or len(body) + 1
2400 begin = body.find('\n', mend) + 1 or len(body) + 1
2401 lend = begin - 1
2401 lend = begin - 1
2402 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2402 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2403
2403
2404 class linestate(object):
2404 class linestate(object):
2405 def __init__(self, line, linenum, colstart, colend):
2405 def __init__(self, line, linenum, colstart, colend):
2406 self.line = line
2406 self.line = line
2407 self.linenum = linenum
2407 self.linenum = linenum
2408 self.colstart = colstart
2408 self.colstart = colstart
2409 self.colend = colend
2409 self.colend = colend
2410
2410
2411 def __hash__(self):
2411 def __hash__(self):
2412 return hash((self.linenum, self.line))
2412 return hash((self.linenum, self.line))
2413
2413
2414 def __eq__(self, other):
2414 def __eq__(self, other):
2415 return self.line == other.line
2415 return self.line == other.line
2416
2416
2417 def findpos(self):
2417 def findpos(self):
2418 """Iterate all (start, end) indices of matches"""
2418 """Iterate all (start, end) indices of matches"""
2419 yield self.colstart, self.colend
2419 yield self.colstart, self.colend
2420 p = self.colend
2420 p = self.colend
2421 while p < len(self.line):
2421 while p < len(self.line):
2422 m = regexp.search(self.line, p)
2422 m = regexp.search(self.line, p)
2423 if not m:
2423 if not m:
2424 break
2424 break
2425 yield m.span()
2425 yield m.span()
2426 p = m.end()
2426 p = m.end()
2427
2427
2428 matches = {}
2428 matches = {}
2429 copies = {}
2429 copies = {}
2430 def grepbody(fn, rev, body):
2430 def grepbody(fn, rev, body):
2431 matches[rev].setdefault(fn, [])
2431 matches[rev].setdefault(fn, [])
2432 m = matches[rev][fn]
2432 m = matches[rev][fn]
2433 for lnum, cstart, cend, line in matchlines(body):
2433 for lnum, cstart, cend, line in matchlines(body):
2434 s = linestate(line, lnum, cstart, cend)
2434 s = linestate(line, lnum, cstart, cend)
2435 m.append(s)
2435 m.append(s)
2436
2436
2437 def difflinestates(a, b):
2437 def difflinestates(a, b):
2438 sm = difflib.SequenceMatcher(None, a, b)
2438 sm = difflib.SequenceMatcher(None, a, b)
2439 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2439 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2440 if tag == 'insert':
2440 if tag == 'insert':
2441 for i in xrange(blo, bhi):
2441 for i in xrange(blo, bhi):
2442 yield ('+', b[i])
2442 yield ('+', b[i])
2443 elif tag == 'delete':
2443 elif tag == 'delete':
2444 for i in xrange(alo, ahi):
2444 for i in xrange(alo, ahi):
2445 yield ('-', a[i])
2445 yield ('-', a[i])
2446 elif tag == 'replace':
2446 elif tag == 'replace':
2447 for i in xrange(alo, ahi):
2447 for i in xrange(alo, ahi):
2448 yield ('-', a[i])
2448 yield ('-', a[i])
2449 for i in xrange(blo, bhi):
2449 for i in xrange(blo, bhi):
2450 yield ('+', b[i])
2450 yield ('+', b[i])
2451
2451
2452 def display(fm, fn, ctx, pstates, states):
2452 def display(fm, fn, ctx, pstates, states):
2453 rev = ctx.rev()
2453 rev = ctx.rev()
2454 if fm.isplain():
2454 if fm.isplain():
2455 formatuser = ui.shortuser
2455 formatuser = ui.shortuser
2456 else:
2456 else:
2457 formatuser = str
2457 formatuser = str
2458 if ui.quiet:
2458 if ui.quiet:
2459 datefmt = '%Y-%m-%d'
2459 datefmt = '%Y-%m-%d'
2460 else:
2460 else:
2461 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2461 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2462 found = False
2462 found = False
2463 @util.cachefunc
2463 @util.cachefunc
2464 def binary():
2464 def binary():
2465 flog = getfile(fn)
2465 flog = getfile(fn)
2466 return util.binary(flog.read(ctx.filenode(fn)))
2466 return util.binary(flog.read(ctx.filenode(fn)))
2467
2467
2468 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2468 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2469 if opts.get('all'):
2469 if opts.get('all'):
2470 iter = difflinestates(pstates, states)
2470 iter = difflinestates(pstates, states)
2471 else:
2471 else:
2472 iter = [('', l) for l in states]
2472 iter = [('', l) for l in states]
2473 for change, l in iter:
2473 for change, l in iter:
2474 fm.startitem()
2474 fm.startitem()
2475 fm.data(node=fm.hexfunc(ctx.node()))
2475 fm.data(node=fm.hexfunc(ctx.node()))
2476 cols = [
2476 cols = [
2477 ('filename', fn, True),
2477 ('filename', fn, True),
2478 ('rev', rev, True),
2478 ('rev', rev, True),
2479 ('linenumber', l.linenum, opts.get('line_number')),
2479 ('linenumber', l.linenum, opts.get('line_number')),
2480 ]
2480 ]
2481 if opts.get('all'):
2481 if opts.get('all'):
2482 cols.append(('change', change, True))
2482 cols.append(('change', change, True))
2483 cols.extend([
2483 cols.extend([
2484 ('user', formatuser(ctx.user()), opts.get('user')),
2484 ('user', formatuser(ctx.user()), opts.get('user')),
2485 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2485 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2486 ])
2486 ])
2487 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2487 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2488 for name, data, cond in cols:
2488 for name, data, cond in cols:
2489 field = fieldnamemap.get(name, name)
2489 field = fieldnamemap.get(name, name)
2490 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2490 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2491 if cond and name != lastcol:
2491 if cond and name != lastcol:
2492 fm.plain(sep, label='grep.sep')
2492 fm.plain(sep, label='grep.sep')
2493 if not opts.get('files_with_matches'):
2493 if not opts.get('files_with_matches'):
2494 fm.plain(sep, label='grep.sep')
2494 fm.plain(sep, label='grep.sep')
2495 if not opts.get('text') and binary():
2495 if not opts.get('text') and binary():
2496 fm.plain(_(" Binary file matches"))
2496 fm.plain(_(" Binary file matches"))
2497 else:
2497 else:
2498 displaymatches(fm.nested('texts'), l)
2498 displaymatches(fm.nested('texts'), l)
2499 fm.plain(eol)
2499 fm.plain(eol)
2500 found = True
2500 found = True
2501 if opts.get('files_with_matches'):
2501 if opts.get('files_with_matches'):
2502 break
2502 break
2503 return found
2503 return found
2504
2504
2505 def displaymatches(fm, l):
2505 def displaymatches(fm, l):
2506 p = 0
2506 p = 0
2507 for s, e in l.findpos():
2507 for s, e in l.findpos():
2508 if p < s:
2508 if p < s:
2509 fm.startitem()
2509 fm.startitem()
2510 fm.write('text', '%s', l.line[p:s])
2510 fm.write('text', '%s', l.line[p:s])
2511 fm.data(matched=False)
2511 fm.data(matched=False)
2512 fm.startitem()
2512 fm.startitem()
2513 fm.write('text', '%s', l.line[s:e], label='grep.match')
2513 fm.write('text', '%s', l.line[s:e], label='grep.match')
2514 fm.data(matched=True)
2514 fm.data(matched=True)
2515 p = e
2515 p = e
2516 if p < len(l.line):
2516 if p < len(l.line):
2517 fm.startitem()
2517 fm.startitem()
2518 fm.write('text', '%s', l.line[p:])
2518 fm.write('text', '%s', l.line[p:])
2519 fm.data(matched=False)
2519 fm.data(matched=False)
2520 fm.end()
2520 fm.end()
2521
2521
2522 skip = {}
2522 skip = {}
2523 revfiles = {}
2523 revfiles = {}
2524 match = scmutil.match(repo[None], pats, opts)
2524 match = scmutil.match(repo[None], pats, opts)
2525 found = False
2525 found = False
2526 follow = opts.get('follow')
2526 follow = opts.get('follow')
2527
2527
2528 def prep(ctx, fns):
2528 def prep(ctx, fns):
2529 rev = ctx.rev()
2529 rev = ctx.rev()
2530 pctx = ctx.p1()
2530 pctx = ctx.p1()
2531 parent = pctx.rev()
2531 parent = pctx.rev()
2532 matches.setdefault(rev, {})
2532 matches.setdefault(rev, {})
2533 matches.setdefault(parent, {})
2533 matches.setdefault(parent, {})
2534 files = revfiles.setdefault(rev, [])
2534 files = revfiles.setdefault(rev, [])
2535 for fn in fns:
2535 for fn in fns:
2536 flog = getfile(fn)
2536 flog = getfile(fn)
2537 try:
2537 try:
2538 fnode = ctx.filenode(fn)
2538 fnode = ctx.filenode(fn)
2539 except error.LookupError:
2539 except error.LookupError:
2540 continue
2540 continue
2541
2541
2542 copied = flog.renamed(fnode)
2542 copied = flog.renamed(fnode)
2543 copy = follow and copied and copied[0]
2543 copy = follow and copied and copied[0]
2544 if copy:
2544 if copy:
2545 copies.setdefault(rev, {})[fn] = copy
2545 copies.setdefault(rev, {})[fn] = copy
2546 if fn in skip:
2546 if fn in skip:
2547 if copy:
2547 if copy:
2548 skip[copy] = True
2548 skip[copy] = True
2549 continue
2549 continue
2550 files.append(fn)
2550 files.append(fn)
2551
2551
2552 if fn not in matches[rev]:
2552 if fn not in matches[rev]:
2553 grepbody(fn, rev, flog.read(fnode))
2553 grepbody(fn, rev, flog.read(fnode))
2554
2554
2555 pfn = copy or fn
2555 pfn = copy or fn
2556 if pfn not in matches[parent]:
2556 if pfn not in matches[parent]:
2557 try:
2557 try:
2558 fnode = pctx.filenode(pfn)
2558 fnode = pctx.filenode(pfn)
2559 grepbody(pfn, parent, flog.read(fnode))
2559 grepbody(pfn, parent, flog.read(fnode))
2560 except error.LookupError:
2560 except error.LookupError:
2561 pass
2561 pass
2562
2562
2563 ui.pager('grep')
2563 ui.pager('grep')
2564 fm = ui.formatter('grep', opts)
2564 fm = ui.formatter('grep', opts)
2565 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2565 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2566 rev = ctx.rev()
2566 rev = ctx.rev()
2567 parent = ctx.p1().rev()
2567 parent = ctx.p1().rev()
2568 for fn in sorted(revfiles.get(rev, [])):
2568 for fn in sorted(revfiles.get(rev, [])):
2569 states = matches[rev][fn]
2569 states = matches[rev][fn]
2570 copy = copies.get(rev, {}).get(fn)
2570 copy = copies.get(rev, {}).get(fn)
2571 if fn in skip:
2571 if fn in skip:
2572 if copy:
2572 if copy:
2573 skip[copy] = True
2573 skip[copy] = True
2574 continue
2574 continue
2575 pstates = matches.get(parent, {}).get(copy or fn, [])
2575 pstates = matches.get(parent, {}).get(copy or fn, [])
2576 if pstates or states:
2576 if pstates or states:
2577 r = display(fm, fn, ctx, pstates, states)
2577 r = display(fm, fn, ctx, pstates, states)
2578 found = found or r
2578 found = found or r
2579 if r and not opts.get('all'):
2579 if r and not opts.get('all'):
2580 skip[fn] = True
2580 skip[fn] = True
2581 if copy:
2581 if copy:
2582 skip[copy] = True
2582 skip[copy] = True
2583 del matches[rev]
2583 del matches[rev]
2584 del revfiles[rev]
2584 del revfiles[rev]
2585 fm.end()
2585 fm.end()
2586
2586
2587 return not found
2587 return not found
2588
2588
2589 @command('heads',
2589 @command('heads',
2590 [('r', 'rev', '',
2590 [('r', 'rev', '',
2591 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2591 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2592 ('t', 'topo', False, _('show topological heads only')),
2592 ('t', 'topo', False, _('show topological heads only')),
2593 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2593 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2594 ('c', 'closed', False, _('show normal and closed branch heads')),
2594 ('c', 'closed', False, _('show normal and closed branch heads')),
2595 ] + templateopts,
2595 ] + templateopts,
2596 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2596 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2597 def heads(ui, repo, *branchrevs, **opts):
2597 def heads(ui, repo, *branchrevs, **opts):
2598 """show branch heads
2598 """show branch heads
2599
2599
2600 With no arguments, show all open branch heads in the repository.
2600 With no arguments, show all open branch heads in the repository.
2601 Branch heads are changesets that have no descendants on the
2601 Branch heads are changesets that have no descendants on the
2602 same branch. They are where development generally takes place and
2602 same branch. They are where development generally takes place and
2603 are the usual targets for update and merge operations.
2603 are the usual targets for update and merge operations.
2604
2604
2605 If one or more REVs are given, only open branch heads on the
2605 If one or more REVs are given, only open branch heads on the
2606 branches associated with the specified changesets are shown. This
2606 branches associated with the specified changesets are shown. This
2607 means that you can use :hg:`heads .` to see the heads on the
2607 means that you can use :hg:`heads .` to see the heads on the
2608 currently checked-out branch.
2608 currently checked-out branch.
2609
2609
2610 If -c/--closed is specified, also show branch heads marked closed
2610 If -c/--closed is specified, also show branch heads marked closed
2611 (see :hg:`commit --close-branch`).
2611 (see :hg:`commit --close-branch`).
2612
2612
2613 If STARTREV is specified, only those heads that are descendants of
2613 If STARTREV is specified, only those heads that are descendants of
2614 STARTREV will be displayed.
2614 STARTREV will be displayed.
2615
2615
2616 If -t/--topo is specified, named branch mechanics will be ignored and only
2616 If -t/--topo is specified, named branch mechanics will be ignored and only
2617 topological heads (changesets with no children) will be shown.
2617 topological heads (changesets with no children) will be shown.
2618
2618
2619 Returns 0 if matching heads are found, 1 if not.
2619 Returns 0 if matching heads are found, 1 if not.
2620 """
2620 """
2621
2621
2622 opts = pycompat.byteskwargs(opts)
2622 opts = pycompat.byteskwargs(opts)
2623 start = None
2623 start = None
2624 rev = opts.get('rev')
2624 rev = opts.get('rev')
2625 if rev:
2625 if rev:
2626 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2626 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2627 start = scmutil.revsingle(repo, rev, None).node()
2627 start = scmutil.revsingle(repo, rev, None).node()
2628
2628
2629 if opts.get('topo'):
2629 if opts.get('topo'):
2630 heads = [repo[h] for h in repo.heads(start)]
2630 heads = [repo[h] for h in repo.heads(start)]
2631 else:
2631 else:
2632 heads = []
2632 heads = []
2633 for branch in repo.branchmap():
2633 for branch in repo.branchmap():
2634 heads += repo.branchheads(branch, start, opts.get('closed'))
2634 heads += repo.branchheads(branch, start, opts.get('closed'))
2635 heads = [repo[h] for h in heads]
2635 heads = [repo[h] for h in heads]
2636
2636
2637 if branchrevs:
2637 if branchrevs:
2638 branches = set(repo[br].branch() for br in branchrevs)
2638 branches = set(repo[br].branch() for br in branchrevs)
2639 heads = [h for h in heads if h.branch() in branches]
2639 heads = [h for h in heads if h.branch() in branches]
2640
2640
2641 if opts.get('active') and branchrevs:
2641 if opts.get('active') and branchrevs:
2642 dagheads = repo.heads(start)
2642 dagheads = repo.heads(start)
2643 heads = [h for h in heads if h.node() in dagheads]
2643 heads = [h for h in heads if h.node() in dagheads]
2644
2644
2645 if branchrevs:
2645 if branchrevs:
2646 haveheads = set(h.branch() for h in heads)
2646 haveheads = set(h.branch() for h in heads)
2647 if branches - haveheads:
2647 if branches - haveheads:
2648 headless = ', '.join(b for b in branches - haveheads)
2648 headless = ', '.join(b for b in branches - haveheads)
2649 msg = _('no open branch heads found on branches %s')
2649 msg = _('no open branch heads found on branches %s')
2650 if opts.get('rev'):
2650 if opts.get('rev'):
2651 msg += _(' (started at %s)') % opts['rev']
2651 msg += _(' (started at %s)') % opts['rev']
2652 ui.warn((msg + '\n') % headless)
2652 ui.warn((msg + '\n') % headless)
2653
2653
2654 if not heads:
2654 if not heads:
2655 return 1
2655 return 1
2656
2656
2657 ui.pager('heads')
2657 ui.pager('heads')
2658 heads = sorted(heads, key=lambda x: -x.rev())
2658 heads = sorted(heads, key=lambda x: -x.rev())
2659 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2659 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2660 for ctx in heads:
2660 for ctx in heads:
2661 displayer.show(ctx)
2661 displayer.show(ctx)
2662 displayer.close()
2662 displayer.close()
2663
2663
2664 @command('help',
2664 @command('help',
2665 [('e', 'extension', None, _('show only help for extensions')),
2665 [('e', 'extension', None, _('show only help for extensions')),
2666 ('c', 'command', None, _('show only help for commands')),
2666 ('c', 'command', None, _('show only help for commands')),
2667 ('k', 'keyword', None, _('show topics matching keyword')),
2667 ('k', 'keyword', None, _('show topics matching keyword')),
2668 ('s', 'system', [], _('show help for specific platform(s)')),
2668 ('s', 'system', [], _('show help for specific platform(s)')),
2669 ],
2669 ],
2670 _('[-ecks] [TOPIC]'),
2670 _('[-ecks] [TOPIC]'),
2671 norepo=True, cmdtype=readonly)
2671 norepo=True, cmdtype=readonly)
2672 def help_(ui, name=None, **opts):
2672 def help_(ui, name=None, **opts):
2673 """show help for a given topic or a help overview
2673 """show help for a given topic or a help overview
2674
2674
2675 With no arguments, print a list of commands with short help messages.
2675 With no arguments, print a list of commands with short help messages.
2676
2676
2677 Given a topic, extension, or command name, print help for that
2677 Given a topic, extension, or command name, print help for that
2678 topic.
2678 topic.
2679
2679
2680 Returns 0 if successful.
2680 Returns 0 if successful.
2681 """
2681 """
2682
2682
2683 keep = opts.get(r'system') or []
2683 keep = opts.get(r'system') or []
2684 if len(keep) == 0:
2684 if len(keep) == 0:
2685 if pycompat.sysplatform.startswith('win'):
2685 if pycompat.sysplatform.startswith('win'):
2686 keep.append('windows')
2686 keep.append('windows')
2687 elif pycompat.sysplatform == 'OpenVMS':
2687 elif pycompat.sysplatform == 'OpenVMS':
2688 keep.append('vms')
2688 keep.append('vms')
2689 elif pycompat.sysplatform == 'plan9':
2689 elif pycompat.sysplatform == 'plan9':
2690 keep.append('plan9')
2690 keep.append('plan9')
2691 else:
2691 else:
2692 keep.append('unix')
2692 keep.append('unix')
2693 keep.append(pycompat.sysplatform.lower())
2693 keep.append(pycompat.sysplatform.lower())
2694 if ui.verbose:
2694 if ui.verbose:
2695 keep.append('verbose')
2695 keep.append('verbose')
2696
2696
2697 commands = sys.modules[__name__]
2697 commands = sys.modules[__name__]
2698 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2698 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2699 ui.pager('help')
2699 ui.pager('help')
2700 ui.write(formatted)
2700 ui.write(formatted)
2701
2701
2702
2702
2703 @command('identify|id',
2703 @command('identify|id',
2704 [('r', 'rev', '',
2704 [('r', 'rev', '',
2705 _('identify the specified revision'), _('REV')),
2705 _('identify the specified revision'), _('REV')),
2706 ('n', 'num', None, _('show local revision number')),
2706 ('n', 'num', None, _('show local revision number')),
2707 ('i', 'id', None, _('show global revision id')),
2707 ('i', 'id', None, _('show global revision id')),
2708 ('b', 'branch', None, _('show branch')),
2708 ('b', 'branch', None, _('show branch')),
2709 ('t', 'tags', None, _('show tags')),
2709 ('t', 'tags', None, _('show tags')),
2710 ('B', 'bookmarks', None, _('show bookmarks')),
2710 ('B', 'bookmarks', None, _('show bookmarks')),
2711 ] + remoteopts + formatteropts,
2711 ] + remoteopts + formatteropts,
2712 _('[-nibtB] [-r REV] [SOURCE]'),
2712 _('[-nibtB] [-r REV] [SOURCE]'),
2713 optionalrepo=True, cmdtype=readonly)
2713 optionalrepo=True, cmdtype=readonly)
2714 def identify(ui, repo, source=None, rev=None,
2714 def identify(ui, repo, source=None, rev=None,
2715 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2715 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2716 """identify the working directory or specified revision
2716 """identify the working directory or specified revision
2717
2717
2718 Print a summary identifying the repository state at REV using one or
2718 Print a summary identifying the repository state at REV using one or
2719 two parent hash identifiers, followed by a "+" if the working
2719 two parent hash identifiers, followed by a "+" if the working
2720 directory has uncommitted changes, the branch name (if not default),
2720 directory has uncommitted changes, the branch name (if not default),
2721 a list of tags, and a list of bookmarks.
2721 a list of tags, and a list of bookmarks.
2722
2722
2723 When REV is not given, print a summary of the current state of the
2723 When REV is not given, print a summary of the current state of the
2724 repository including the working directory. Specify -r. to get information
2724 repository including the working directory. Specify -r. to get information
2725 of the working directory parent without scanning uncommitted changes.
2725 of the working directory parent without scanning uncommitted changes.
2726
2726
2727 Specifying a path to a repository root or Mercurial bundle will
2727 Specifying a path to a repository root or Mercurial bundle will
2728 cause lookup to operate on that repository/bundle.
2728 cause lookup to operate on that repository/bundle.
2729
2729
2730 .. container:: verbose
2730 .. container:: verbose
2731
2731
2732 Examples:
2732 Examples:
2733
2733
2734 - generate a build identifier for the working directory::
2734 - generate a build identifier for the working directory::
2735
2735
2736 hg id --id > build-id.dat
2736 hg id --id > build-id.dat
2737
2737
2738 - find the revision corresponding to a tag::
2738 - find the revision corresponding to a tag::
2739
2739
2740 hg id -n -r 1.3
2740 hg id -n -r 1.3
2741
2741
2742 - check the most recent revision of a remote repository::
2742 - check the most recent revision of a remote repository::
2743
2743
2744 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2744 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2745
2745
2746 See :hg:`log` for generating more information about specific revisions,
2746 See :hg:`log` for generating more information about specific revisions,
2747 including full hash identifiers.
2747 including full hash identifiers.
2748
2748
2749 Returns 0 if successful.
2749 Returns 0 if successful.
2750 """
2750 """
2751
2751
2752 opts = pycompat.byteskwargs(opts)
2752 opts = pycompat.byteskwargs(opts)
2753 if not repo and not source:
2753 if not repo and not source:
2754 raise error.Abort(_("there is no Mercurial repository here "
2754 raise error.Abort(_("there is no Mercurial repository here "
2755 "(.hg not found)"))
2755 "(.hg not found)"))
2756
2756
2757 if ui.debugflag:
2757 if ui.debugflag:
2758 hexfunc = hex
2758 hexfunc = hex
2759 else:
2759 else:
2760 hexfunc = short
2760 hexfunc = short
2761 default = not (num or id or branch or tags or bookmarks)
2761 default = not (num or id or branch or tags or bookmarks)
2762 output = []
2762 output = []
2763 revs = []
2763 revs = []
2764
2764
2765 if source:
2765 if source:
2766 source, branches = hg.parseurl(ui.expandpath(source))
2766 source, branches = hg.parseurl(ui.expandpath(source))
2767 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2767 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2768 repo = peer.local()
2768 repo = peer.local()
2769 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2769 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2770
2770
2771 fm = ui.formatter('identify', opts)
2771 fm = ui.formatter('identify', opts)
2772 fm.startitem()
2772 fm.startitem()
2773
2773
2774 if not repo:
2774 if not repo:
2775 if num or branch or tags:
2775 if num or branch or tags:
2776 raise error.Abort(
2776 raise error.Abort(
2777 _("can't query remote revision number, branch, or tags"))
2777 _("can't query remote revision number, branch, or tags"))
2778 if not rev and revs:
2778 if not rev and revs:
2779 rev = revs[0]
2779 rev = revs[0]
2780 if not rev:
2780 if not rev:
2781 rev = "tip"
2781 rev = "tip"
2782
2782
2783 remoterev = peer.lookup(rev)
2783 remoterev = peer.lookup(rev)
2784 hexrev = hexfunc(remoterev)
2784 hexrev = hexfunc(remoterev)
2785 if default or id:
2785 if default or id:
2786 output = [hexrev]
2786 output = [hexrev]
2787 fm.data(id=hexrev)
2787 fm.data(id=hexrev)
2788
2788
2789 def getbms():
2789 def getbms():
2790 bms = []
2790 bms = []
2791
2791
2792 if 'bookmarks' in peer.listkeys('namespaces'):
2792 if 'bookmarks' in peer.listkeys('namespaces'):
2793 hexremoterev = hex(remoterev)
2793 hexremoterev = hex(remoterev)
2794 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2794 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2795 if bmr == hexremoterev]
2795 if bmr == hexremoterev]
2796
2796
2797 return sorted(bms)
2797 return sorted(bms)
2798
2798
2799 bms = getbms()
2799 bms = getbms()
2800 if bookmarks:
2800 if bookmarks:
2801 output.extend(bms)
2801 output.extend(bms)
2802 elif default and not ui.quiet:
2802 elif default and not ui.quiet:
2803 # multiple bookmarks for a single parent separated by '/'
2803 # multiple bookmarks for a single parent separated by '/'
2804 bm = '/'.join(bms)
2804 bm = '/'.join(bms)
2805 if bm:
2805 if bm:
2806 output.append(bm)
2806 output.append(bm)
2807
2807
2808 fm.data(node=hex(remoterev))
2808 fm.data(node=hex(remoterev))
2809 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2809 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2810 else:
2810 else:
2811 if rev:
2811 if rev:
2812 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2812 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2813 ctx = scmutil.revsingle(repo, rev, None)
2813 ctx = scmutil.revsingle(repo, rev, None)
2814
2814
2815 if ctx.rev() is None:
2815 if ctx.rev() is None:
2816 ctx = repo[None]
2816 ctx = repo[None]
2817 parents = ctx.parents()
2817 parents = ctx.parents()
2818 taglist = []
2818 taglist = []
2819 for p in parents:
2819 for p in parents:
2820 taglist.extend(p.tags())
2820 taglist.extend(p.tags())
2821
2821
2822 dirty = ""
2822 dirty = ""
2823 if ctx.dirty(missing=True, merge=False, branch=False):
2823 if ctx.dirty(missing=True, merge=False, branch=False):
2824 dirty = '+'
2824 dirty = '+'
2825 fm.data(dirty=dirty)
2825 fm.data(dirty=dirty)
2826
2826
2827 hexoutput = [hexfunc(p.node()) for p in parents]
2827 hexoutput = [hexfunc(p.node()) for p in parents]
2828 if default or id:
2828 if default or id:
2829 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2829 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2830 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2830 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2831
2831
2832 if num:
2832 if num:
2833 numoutput = ["%d" % p.rev() for p in parents]
2833 numoutput = ["%d" % p.rev() for p in parents]
2834 output.append("%s%s" % ('+'.join(numoutput), dirty))
2834 output.append("%s%s" % ('+'.join(numoutput), dirty))
2835
2835
2836 fn = fm.nested('parents')
2836 fn = fm.nested('parents')
2837 for p in parents:
2837 for p in parents:
2838 fn.startitem()
2838 fn.startitem()
2839 fn.data(rev=p.rev())
2839 fn.data(rev=p.rev())
2840 fn.data(node=p.hex())
2840 fn.data(node=p.hex())
2841 fn.context(ctx=p)
2841 fn.context(ctx=p)
2842 fn.end()
2842 fn.end()
2843 else:
2843 else:
2844 hexoutput = hexfunc(ctx.node())
2844 hexoutput = hexfunc(ctx.node())
2845 if default or id:
2845 if default or id:
2846 output = [hexoutput]
2846 output = [hexoutput]
2847 fm.data(id=hexoutput)
2847 fm.data(id=hexoutput)
2848
2848
2849 if num:
2849 if num:
2850 output.append(pycompat.bytestr(ctx.rev()))
2850 output.append(pycompat.bytestr(ctx.rev()))
2851 taglist = ctx.tags()
2851 taglist = ctx.tags()
2852
2852
2853 if default and not ui.quiet:
2853 if default and not ui.quiet:
2854 b = ctx.branch()
2854 b = ctx.branch()
2855 if b != 'default':
2855 if b != 'default':
2856 output.append("(%s)" % b)
2856 output.append("(%s)" % b)
2857
2857
2858 # multiple tags for a single parent separated by '/'
2858 # multiple tags for a single parent separated by '/'
2859 t = '/'.join(taglist)
2859 t = '/'.join(taglist)
2860 if t:
2860 if t:
2861 output.append(t)
2861 output.append(t)
2862
2862
2863 # multiple bookmarks for a single parent separated by '/'
2863 # multiple bookmarks for a single parent separated by '/'
2864 bm = '/'.join(ctx.bookmarks())
2864 bm = '/'.join(ctx.bookmarks())
2865 if bm:
2865 if bm:
2866 output.append(bm)
2866 output.append(bm)
2867 else:
2867 else:
2868 if branch:
2868 if branch:
2869 output.append(ctx.branch())
2869 output.append(ctx.branch())
2870
2870
2871 if tags:
2871 if tags:
2872 output.extend(taglist)
2872 output.extend(taglist)
2873
2873
2874 if bookmarks:
2874 if bookmarks:
2875 output.extend(ctx.bookmarks())
2875 output.extend(ctx.bookmarks())
2876
2876
2877 fm.data(node=ctx.hex())
2877 fm.data(node=ctx.hex())
2878 fm.data(branch=ctx.branch())
2878 fm.data(branch=ctx.branch())
2879 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2879 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2880 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2880 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2881 fm.context(ctx=ctx)
2881 fm.context(ctx=ctx)
2882
2882
2883 fm.plain("%s\n" % ' '.join(output))
2883 fm.plain("%s\n" % ' '.join(output))
2884 fm.end()
2884 fm.end()
2885
2885
2886 @command('import|patch',
2886 @command('import|patch',
2887 [('p', 'strip', 1,
2887 [('p', 'strip', 1,
2888 _('directory strip option for patch. This has the same '
2888 _('directory strip option for patch. This has the same '
2889 'meaning as the corresponding patch option'), _('NUM')),
2889 'meaning as the corresponding patch option'), _('NUM')),
2890 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2890 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2891 ('e', 'edit', False, _('invoke editor on commit messages')),
2891 ('e', 'edit', False, _('invoke editor on commit messages')),
2892 ('f', 'force', None,
2892 ('f', 'force', None,
2893 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2893 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2894 ('', 'no-commit', None,
2894 ('', 'no-commit', None,
2895 _("don't commit, just update the working directory")),
2895 _("don't commit, just update the working directory")),
2896 ('', 'bypass', None,
2896 ('', 'bypass', None,
2897 _("apply patch without touching the working directory")),
2897 _("apply patch without touching the working directory")),
2898 ('', 'partial', None,
2898 ('', 'partial', None,
2899 _('commit even if some hunks fail')),
2899 _('commit even if some hunks fail')),
2900 ('', 'exact', None,
2900 ('', 'exact', None,
2901 _('abort if patch would apply lossily')),
2901 _('abort if patch would apply lossily')),
2902 ('', 'prefix', '',
2902 ('', 'prefix', '',
2903 _('apply patch to subdirectory'), _('DIR')),
2903 _('apply patch to subdirectory'), _('DIR')),
2904 ('', 'import-branch', None,
2904 ('', 'import-branch', None,
2905 _('use any branch information in patch (implied by --exact)'))] +
2905 _('use any branch information in patch (implied by --exact)'))] +
2906 commitopts + commitopts2 + similarityopts,
2906 commitopts + commitopts2 + similarityopts,
2907 _('[OPTION]... PATCH...'))
2907 _('[OPTION]... PATCH...'))
2908 def import_(ui, repo, patch1=None, *patches, **opts):
2908 def import_(ui, repo, patch1=None, *patches, **opts):
2909 """import an ordered set of patches
2909 """import an ordered set of patches
2910
2910
2911 Import a list of patches and commit them individually (unless
2911 Import a list of patches and commit them individually (unless
2912 --no-commit is specified).
2912 --no-commit is specified).
2913
2913
2914 To read a patch from standard input (stdin), use "-" as the patch
2914 To read a patch from standard input (stdin), use "-" as the patch
2915 name. If a URL is specified, the patch will be downloaded from
2915 name. If a URL is specified, the patch will be downloaded from
2916 there.
2916 there.
2917
2917
2918 Import first applies changes to the working directory (unless
2918 Import first applies changes to the working directory (unless
2919 --bypass is specified), import will abort if there are outstanding
2919 --bypass is specified), import will abort if there are outstanding
2920 changes.
2920 changes.
2921
2921
2922 Use --bypass to apply and commit patches directly to the
2922 Use --bypass to apply and commit patches directly to the
2923 repository, without affecting the working directory. Without
2923 repository, without affecting the working directory. Without
2924 --exact, patches will be applied on top of the working directory
2924 --exact, patches will be applied on top of the working directory
2925 parent revision.
2925 parent revision.
2926
2926
2927 You can import a patch straight from a mail message. Even patches
2927 You can import a patch straight from a mail message. Even patches
2928 as attachments work (to use the body part, it must have type
2928 as attachments work (to use the body part, it must have type
2929 text/plain or text/x-patch). From and Subject headers of email
2929 text/plain or text/x-patch). From and Subject headers of email
2930 message are used as default committer and commit message. All
2930 message are used as default committer and commit message. All
2931 text/plain body parts before first diff are added to the commit
2931 text/plain body parts before first diff are added to the commit
2932 message.
2932 message.
2933
2933
2934 If the imported patch was generated by :hg:`export`, user and
2934 If the imported patch was generated by :hg:`export`, user and
2935 description from patch override values from message headers and
2935 description from patch override values from message headers and
2936 body. Values given on command line with -m/--message and -u/--user
2936 body. Values given on command line with -m/--message and -u/--user
2937 override these.
2937 override these.
2938
2938
2939 If --exact is specified, import will set the working directory to
2939 If --exact is specified, import will set the working directory to
2940 the parent of each patch before applying it, and will abort if the
2940 the parent of each patch before applying it, and will abort if the
2941 resulting changeset has a different ID than the one recorded in
2941 resulting changeset has a different ID than the one recorded in
2942 the patch. This will guard against various ways that portable
2942 the patch. This will guard against various ways that portable
2943 patch formats and mail systems might fail to transfer Mercurial
2943 patch formats and mail systems might fail to transfer Mercurial
2944 data or metadata. See :hg:`bundle` for lossless transmission.
2944 data or metadata. See :hg:`bundle` for lossless transmission.
2945
2945
2946 Use --partial to ensure a changeset will be created from the patch
2946 Use --partial to ensure a changeset will be created from the patch
2947 even if some hunks fail to apply. Hunks that fail to apply will be
2947 even if some hunks fail to apply. Hunks that fail to apply will be
2948 written to a <target-file>.rej file. Conflicts can then be resolved
2948 written to a <target-file>.rej file. Conflicts can then be resolved
2949 by hand before :hg:`commit --amend` is run to update the created
2949 by hand before :hg:`commit --amend` is run to update the created
2950 changeset. This flag exists to let people import patches that
2950 changeset. This flag exists to let people import patches that
2951 partially apply without losing the associated metadata (author,
2951 partially apply without losing the associated metadata (author,
2952 date, description, ...).
2952 date, description, ...).
2953
2953
2954 .. note::
2954 .. note::
2955
2955
2956 When no hunks apply cleanly, :hg:`import --partial` will create
2956 When no hunks apply cleanly, :hg:`import --partial` will create
2957 an empty changeset, importing only the patch metadata.
2957 an empty changeset, importing only the patch metadata.
2958
2958
2959 With -s/--similarity, hg will attempt to discover renames and
2959 With -s/--similarity, hg will attempt to discover renames and
2960 copies in the patch in the same way as :hg:`addremove`.
2960 copies in the patch in the same way as :hg:`addremove`.
2961
2961
2962 It is possible to use external patch programs to perform the patch
2962 It is possible to use external patch programs to perform the patch
2963 by setting the ``ui.patch`` configuration option. For the default
2963 by setting the ``ui.patch`` configuration option. For the default
2964 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2964 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2965 See :hg:`help config` for more information about configuration
2965 See :hg:`help config` for more information about configuration
2966 files and how to use these options.
2966 files and how to use these options.
2967
2967
2968 See :hg:`help dates` for a list of formats valid for -d/--date.
2968 See :hg:`help dates` for a list of formats valid for -d/--date.
2969
2969
2970 .. container:: verbose
2970 .. container:: verbose
2971
2971
2972 Examples:
2972 Examples:
2973
2973
2974 - import a traditional patch from a website and detect renames::
2974 - import a traditional patch from a website and detect renames::
2975
2975
2976 hg import -s 80 http://example.com/bugfix.patch
2976 hg import -s 80 http://example.com/bugfix.patch
2977
2977
2978 - import a changeset from an hgweb server::
2978 - import a changeset from an hgweb server::
2979
2979
2980 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2980 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2981
2981
2982 - import all the patches in an Unix-style mbox::
2982 - import all the patches in an Unix-style mbox::
2983
2983
2984 hg import incoming-patches.mbox
2984 hg import incoming-patches.mbox
2985
2985
2986 - import patches from stdin::
2986 - import patches from stdin::
2987
2987
2988 hg import -
2988 hg import -
2989
2989
2990 - attempt to exactly restore an exported changeset (not always
2990 - attempt to exactly restore an exported changeset (not always
2991 possible)::
2991 possible)::
2992
2992
2993 hg import --exact proposed-fix.patch
2993 hg import --exact proposed-fix.patch
2994
2994
2995 - use an external tool to apply a patch which is too fuzzy for
2995 - use an external tool to apply a patch which is too fuzzy for
2996 the default internal tool.
2996 the default internal tool.
2997
2997
2998 hg import --config ui.patch="patch --merge" fuzzy.patch
2998 hg import --config ui.patch="patch --merge" fuzzy.patch
2999
2999
3000 - change the default fuzzing from 2 to a less strict 7
3000 - change the default fuzzing from 2 to a less strict 7
3001
3001
3002 hg import --config ui.fuzz=7 fuzz.patch
3002 hg import --config ui.fuzz=7 fuzz.patch
3003
3003
3004 Returns 0 on success, 1 on partial success (see --partial).
3004 Returns 0 on success, 1 on partial success (see --partial).
3005 """
3005 """
3006
3006
3007 opts = pycompat.byteskwargs(opts)
3007 opts = pycompat.byteskwargs(opts)
3008 if not patch1:
3008 if not patch1:
3009 raise error.Abort(_('need at least one patch to import'))
3009 raise error.Abort(_('need at least one patch to import'))
3010
3010
3011 patches = (patch1,) + patches
3011 patches = (patch1,) + patches
3012
3012
3013 date = opts.get('date')
3013 date = opts.get('date')
3014 if date:
3014 if date:
3015 opts['date'] = dateutil.parsedate(date)
3015 opts['date'] = dateutil.parsedate(date)
3016
3016
3017 exact = opts.get('exact')
3017 exact = opts.get('exact')
3018 update = not opts.get('bypass')
3018 update = not opts.get('bypass')
3019 if not update and opts.get('no_commit'):
3019 if not update and opts.get('no_commit'):
3020 raise error.Abort(_('cannot use --no-commit with --bypass'))
3020 raise error.Abort(_('cannot use --no-commit with --bypass'))
3021 try:
3021 try:
3022 sim = float(opts.get('similarity') or 0)
3022 sim = float(opts.get('similarity') or 0)
3023 except ValueError:
3023 except ValueError:
3024 raise error.Abort(_('similarity must be a number'))
3024 raise error.Abort(_('similarity must be a number'))
3025 if sim < 0 or sim > 100:
3025 if sim < 0 or sim > 100:
3026 raise error.Abort(_('similarity must be between 0 and 100'))
3026 raise error.Abort(_('similarity must be between 0 and 100'))
3027 if sim and not update:
3027 if sim and not update:
3028 raise error.Abort(_('cannot use --similarity with --bypass'))
3028 raise error.Abort(_('cannot use --similarity with --bypass'))
3029 if exact:
3029 if exact:
3030 if opts.get('edit'):
3030 if opts.get('edit'):
3031 raise error.Abort(_('cannot use --exact with --edit'))
3031 raise error.Abort(_('cannot use --exact with --edit'))
3032 if opts.get('prefix'):
3032 if opts.get('prefix'):
3033 raise error.Abort(_('cannot use --exact with --prefix'))
3033 raise error.Abort(_('cannot use --exact with --prefix'))
3034
3034
3035 base = opts["base"]
3035 base = opts["base"]
3036 wlock = dsguard = lock = tr = None
3036 wlock = dsguard = lock = tr = None
3037 msgs = []
3037 msgs = []
3038 ret = 0
3038 ret = 0
3039
3039
3040
3040
3041 try:
3041 try:
3042 wlock = repo.wlock()
3042 wlock = repo.wlock()
3043
3043
3044 if update:
3044 if update:
3045 cmdutil.checkunfinished(repo)
3045 cmdutil.checkunfinished(repo)
3046 if (exact or not opts.get('force')):
3046 if (exact or not opts.get('force')):
3047 cmdutil.bailifchanged(repo)
3047 cmdutil.bailifchanged(repo)
3048
3048
3049 if not opts.get('no_commit'):
3049 if not opts.get('no_commit'):
3050 lock = repo.lock()
3050 lock = repo.lock()
3051 tr = repo.transaction('import')
3051 tr = repo.transaction('import')
3052 else:
3052 else:
3053 dsguard = dirstateguard.dirstateguard(repo, 'import')
3053 dsguard = dirstateguard.dirstateguard(repo, 'import')
3054 parents = repo[None].parents()
3054 parents = repo[None].parents()
3055 for patchurl in patches:
3055 for patchurl in patches:
3056 if patchurl == '-':
3056 if patchurl == '-':
3057 ui.status(_('applying patch from stdin\n'))
3057 ui.status(_('applying patch from stdin\n'))
3058 patchfile = ui.fin
3058 patchfile = ui.fin
3059 patchurl = 'stdin' # for error message
3059 patchurl = 'stdin' # for error message
3060 else:
3060 else:
3061 patchurl = os.path.join(base, patchurl)
3061 patchurl = os.path.join(base, patchurl)
3062 ui.status(_('applying %s\n') % patchurl)
3062 ui.status(_('applying %s\n') % patchurl)
3063 patchfile = hg.openpath(ui, patchurl)
3063 patchfile = hg.openpath(ui, patchurl)
3064
3064
3065 haspatch = False
3065 haspatch = False
3066 for hunk in patch.split(patchfile):
3066 for hunk in patch.split(patchfile):
3067 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3067 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3068 parents, opts,
3068 parents, opts,
3069 msgs, hg.clean)
3069 msgs, hg.clean)
3070 if msg:
3070 if msg:
3071 haspatch = True
3071 haspatch = True
3072 ui.note(msg + '\n')
3072 ui.note(msg + '\n')
3073 if update or exact:
3073 if update or exact:
3074 parents = repo[None].parents()
3074 parents = repo[None].parents()
3075 else:
3075 else:
3076 parents = [repo[node]]
3076 parents = [repo[node]]
3077 if rej:
3077 if rej:
3078 ui.write_err(_("patch applied partially\n"))
3078 ui.write_err(_("patch applied partially\n"))
3079 ui.write_err(_("(fix the .rej files and run "
3079 ui.write_err(_("(fix the .rej files and run "
3080 "`hg commit --amend`)\n"))
3080 "`hg commit --amend`)\n"))
3081 ret = 1
3081 ret = 1
3082 break
3082 break
3083
3083
3084 if not haspatch:
3084 if not haspatch:
3085 raise error.Abort(_('%s: no diffs found') % patchurl)
3085 raise error.Abort(_('%s: no diffs found') % patchurl)
3086
3086
3087 if tr:
3087 if tr:
3088 tr.close()
3088 tr.close()
3089 if msgs:
3089 if msgs:
3090 repo.savecommitmessage('\n* * *\n'.join(msgs))
3090 repo.savecommitmessage('\n* * *\n'.join(msgs))
3091 if dsguard:
3091 if dsguard:
3092 dsguard.close()
3092 dsguard.close()
3093 return ret
3093 return ret
3094 finally:
3094 finally:
3095 if tr:
3095 if tr:
3096 tr.release()
3096 tr.release()
3097 release(lock, dsguard, wlock)
3097 release(lock, dsguard, wlock)
3098
3098
3099 @command('incoming|in',
3099 @command('incoming|in',
3100 [('f', 'force', None,
3100 [('f', 'force', None,
3101 _('run even if remote repository is unrelated')),
3101 _('run even if remote repository is unrelated')),
3102 ('n', 'newest-first', None, _('show newest record first')),
3102 ('n', 'newest-first', None, _('show newest record first')),
3103 ('', 'bundle', '',
3103 ('', 'bundle', '',
3104 _('file to store the bundles into'), _('FILE')),
3104 _('file to store the bundles into'), _('FILE')),
3105 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3105 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3106 ('B', 'bookmarks', False, _("compare bookmarks")),
3106 ('B', 'bookmarks', False, _("compare bookmarks")),
3107 ('b', 'branch', [],
3107 ('b', 'branch', [],
3108 _('a specific branch you would like to pull'), _('BRANCH')),
3108 _('a specific branch you would like to pull'), _('BRANCH')),
3109 ] + logopts + remoteopts + subrepoopts,
3109 ] + logopts + remoteopts + subrepoopts,
3110 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3110 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3111 def incoming(ui, repo, source="default", **opts):
3111 def incoming(ui, repo, source="default", **opts):
3112 """show new changesets found in source
3112 """show new changesets found in source
3113
3113
3114 Show new changesets found in the specified path/URL or the default
3114 Show new changesets found in the specified path/URL or the default
3115 pull location. These are the changesets that would have been pulled
3115 pull location. These are the changesets that would have been pulled
3116 by :hg:`pull` at the time you issued this command.
3116 by :hg:`pull` at the time you issued this command.
3117
3117
3118 See pull for valid source format details.
3118 See pull for valid source format details.
3119
3119
3120 .. container:: verbose
3120 .. container:: verbose
3121
3121
3122 With -B/--bookmarks, the result of bookmark comparison between
3122 With -B/--bookmarks, the result of bookmark comparison between
3123 local and remote repositories is displayed. With -v/--verbose,
3123 local and remote repositories is displayed. With -v/--verbose,
3124 status is also displayed for each bookmark like below::
3124 status is also displayed for each bookmark like below::
3125
3125
3126 BM1 01234567890a added
3126 BM1 01234567890a added
3127 BM2 1234567890ab advanced
3127 BM2 1234567890ab advanced
3128 BM3 234567890abc diverged
3128 BM3 234567890abc diverged
3129 BM4 34567890abcd changed
3129 BM4 34567890abcd changed
3130
3130
3131 The action taken locally when pulling depends on the
3131 The action taken locally when pulling depends on the
3132 status of each bookmark:
3132 status of each bookmark:
3133
3133
3134 :``added``: pull will create it
3134 :``added``: pull will create it
3135 :``advanced``: pull will update it
3135 :``advanced``: pull will update it
3136 :``diverged``: pull will create a divergent bookmark
3136 :``diverged``: pull will create a divergent bookmark
3137 :``changed``: result depends on remote changesets
3137 :``changed``: result depends on remote changesets
3138
3138
3139 From the point of view of pulling behavior, bookmark
3139 From the point of view of pulling behavior, bookmark
3140 existing only in the remote repository are treated as ``added``,
3140 existing only in the remote repository are treated as ``added``,
3141 even if it is in fact locally deleted.
3141 even if it is in fact locally deleted.
3142
3142
3143 .. container:: verbose
3143 .. container:: verbose
3144
3144
3145 For remote repository, using --bundle avoids downloading the
3145 For remote repository, using --bundle avoids downloading the
3146 changesets twice if the incoming is followed by a pull.
3146 changesets twice if the incoming is followed by a pull.
3147
3147
3148 Examples:
3148 Examples:
3149
3149
3150 - show incoming changes with patches and full description::
3150 - show incoming changes with patches and full description::
3151
3151
3152 hg incoming -vp
3152 hg incoming -vp
3153
3153
3154 - show incoming changes excluding merges, store a bundle::
3154 - show incoming changes excluding merges, store a bundle::
3155
3155
3156 hg in -vpM --bundle incoming.hg
3156 hg in -vpM --bundle incoming.hg
3157 hg pull incoming.hg
3157 hg pull incoming.hg
3158
3158
3159 - briefly list changes inside a bundle::
3159 - briefly list changes inside a bundle::
3160
3160
3161 hg in changes.hg -T "{desc|firstline}\\n"
3161 hg in changes.hg -T "{desc|firstline}\\n"
3162
3162
3163 Returns 0 if there are incoming changes, 1 otherwise.
3163 Returns 0 if there are incoming changes, 1 otherwise.
3164 """
3164 """
3165 opts = pycompat.byteskwargs(opts)
3165 opts = pycompat.byteskwargs(opts)
3166 if opts.get('graph'):
3166 if opts.get('graph'):
3167 logcmdutil.checkunsupportedgraphflags([], opts)
3167 logcmdutil.checkunsupportedgraphflags([], opts)
3168 def display(other, chlist, displayer):
3168 def display(other, chlist, displayer):
3169 revdag = logcmdutil.graphrevs(other, chlist, opts)
3169 revdag = logcmdutil.graphrevs(other, chlist, opts)
3170 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3170 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3171 graphmod.asciiedges)
3171 graphmod.asciiedges)
3172
3172
3173 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3173 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3174 return 0
3174 return 0
3175
3175
3176 if opts.get('bundle') and opts.get('subrepos'):
3176 if opts.get('bundle') and opts.get('subrepos'):
3177 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3177 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3178
3178
3179 if opts.get('bookmarks'):
3179 if opts.get('bookmarks'):
3180 source, branches = hg.parseurl(ui.expandpath(source),
3180 source, branches = hg.parseurl(ui.expandpath(source),
3181 opts.get('branch'))
3181 opts.get('branch'))
3182 other = hg.peer(repo, opts, source)
3182 other = hg.peer(repo, opts, source)
3183 if 'bookmarks' not in other.listkeys('namespaces'):
3183 if 'bookmarks' not in other.listkeys('namespaces'):
3184 ui.warn(_("remote doesn't support bookmarks\n"))
3184 ui.warn(_("remote doesn't support bookmarks\n"))
3185 return 0
3185 return 0
3186 ui.pager('incoming')
3186 ui.pager('incoming')
3187 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3187 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3188 return bookmarks.incoming(ui, repo, other)
3188 return bookmarks.incoming(ui, repo, other)
3189
3189
3190 repo._subtoppath = ui.expandpath(source)
3190 repo._subtoppath = ui.expandpath(source)
3191 try:
3191 try:
3192 return hg.incoming(ui, repo, source, opts)
3192 return hg.incoming(ui, repo, source, opts)
3193 finally:
3193 finally:
3194 del repo._subtoppath
3194 del repo._subtoppath
3195
3195
3196
3196
3197 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3197 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3198 norepo=True)
3198 norepo=True)
3199 def init(ui, dest=".", **opts):
3199 def init(ui, dest=".", **opts):
3200 """create a new repository in the given directory
3200 """create a new repository in the given directory
3201
3201
3202 Initialize a new repository in the given directory. If the given
3202 Initialize a new repository in the given directory. If the given
3203 directory does not exist, it will be created.
3203 directory does not exist, it will be created.
3204
3204
3205 If no directory is given, the current directory is used.
3205 If no directory is given, the current directory is used.
3206
3206
3207 It is possible to specify an ``ssh://`` URL as the destination.
3207 It is possible to specify an ``ssh://`` URL as the destination.
3208 See :hg:`help urls` for more information.
3208 See :hg:`help urls` for more information.
3209
3209
3210 Returns 0 on success.
3210 Returns 0 on success.
3211 """
3211 """
3212 opts = pycompat.byteskwargs(opts)
3212 opts = pycompat.byteskwargs(opts)
3213 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3213 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3214
3214
3215 @command('locate',
3215 @command('locate',
3216 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3216 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3217 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3217 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3218 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3218 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3219 ] + walkopts,
3219 ] + walkopts,
3220 _('[OPTION]... [PATTERN]...'))
3220 _('[OPTION]... [PATTERN]...'))
3221 def locate(ui, repo, *pats, **opts):
3221 def locate(ui, repo, *pats, **opts):
3222 """locate files matching specific patterns (DEPRECATED)
3222 """locate files matching specific patterns (DEPRECATED)
3223
3223
3224 Print files under Mercurial control in the working directory whose
3224 Print files under Mercurial control in the working directory whose
3225 names match the given patterns.
3225 names match the given patterns.
3226
3226
3227 By default, this command searches all directories in the working
3227 By default, this command searches all directories in the working
3228 directory. To search just the current directory and its
3228 directory. To search just the current directory and its
3229 subdirectories, use "--include .".
3229 subdirectories, use "--include .".
3230
3230
3231 If no patterns are given to match, this command prints the names
3231 If no patterns are given to match, this command prints the names
3232 of all files under Mercurial control in the working directory.
3232 of all files under Mercurial control in the working directory.
3233
3233
3234 If you want to feed the output of this command into the "xargs"
3234 If you want to feed the output of this command into the "xargs"
3235 command, use the -0 option to both this command and "xargs". This
3235 command, use the -0 option to both this command and "xargs". This
3236 will avoid the problem of "xargs" treating single filenames that
3236 will avoid the problem of "xargs" treating single filenames that
3237 contain whitespace as multiple filenames.
3237 contain whitespace as multiple filenames.
3238
3238
3239 See :hg:`help files` for a more versatile command.
3239 See :hg:`help files` for a more versatile command.
3240
3240
3241 Returns 0 if a match is found, 1 otherwise.
3241 Returns 0 if a match is found, 1 otherwise.
3242 """
3242 """
3243 opts = pycompat.byteskwargs(opts)
3243 opts = pycompat.byteskwargs(opts)
3244 if opts.get('print0'):
3244 if opts.get('print0'):
3245 end = '\0'
3245 end = '\0'
3246 else:
3246 else:
3247 end = '\n'
3247 end = '\n'
3248 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3248 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3249
3249
3250 ret = 1
3250 ret = 1
3251 ctx = repo[rev]
3251 ctx = repo[rev]
3252 m = scmutil.match(ctx, pats, opts, default='relglob',
3252 m = scmutil.match(ctx, pats, opts, default='relglob',
3253 badfn=lambda x, y: False)
3253 badfn=lambda x, y: False)
3254
3254
3255 ui.pager('locate')
3255 ui.pager('locate')
3256 for abs in ctx.matches(m):
3256 for abs in ctx.matches(m):
3257 if opts.get('fullpath'):
3257 if opts.get('fullpath'):
3258 ui.write(repo.wjoin(abs), end)
3258 ui.write(repo.wjoin(abs), end)
3259 else:
3259 else:
3260 ui.write(((pats and m.rel(abs)) or abs), end)
3260 ui.write(((pats and m.rel(abs)) or abs), end)
3261 ret = 0
3261 ret = 0
3262
3262
3263 return ret
3263 return ret
3264
3264
3265 @command('^log|history',
3265 @command('^log|history',
3266 [('f', 'follow', None,
3266 [('f', 'follow', None,
3267 _('follow changeset history, or file history across copies and renames')),
3267 _('follow changeset history, or file history across copies and renames')),
3268 ('', 'follow-first', None,
3268 ('', 'follow-first', None,
3269 _('only follow the first parent of merge changesets (DEPRECATED)')),
3269 _('only follow the first parent of merge changesets (DEPRECATED)')),
3270 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3270 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3271 ('C', 'copies', None, _('show copied files')),
3271 ('C', 'copies', None, _('show copied files')),
3272 ('k', 'keyword', [],
3272 ('k', 'keyword', [],
3273 _('do case-insensitive search for a given text'), _('TEXT')),
3273 _('do case-insensitive search for a given text'), _('TEXT')),
3274 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3274 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3275 ('L', 'line-range', [],
3275 ('L', 'line-range', [],
3276 _('follow line range of specified file (EXPERIMENTAL)'),
3276 _('follow line range of specified file (EXPERIMENTAL)'),
3277 _('FILE,RANGE')),
3277 _('FILE,RANGE')),
3278 ('', 'removed', None, _('include revisions where files were removed')),
3278 ('', 'removed', None, _('include revisions where files were removed')),
3279 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3279 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3280 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3280 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3281 ('', 'only-branch', [],
3281 ('', 'only-branch', [],
3282 _('show only changesets within the given named branch (DEPRECATED)'),
3282 _('show only changesets within the given named branch (DEPRECATED)'),
3283 _('BRANCH')),
3283 _('BRANCH')),
3284 ('b', 'branch', [],
3284 ('b', 'branch', [],
3285 _('show changesets within the given named branch'), _('BRANCH')),
3285 _('show changesets within the given named branch'), _('BRANCH')),
3286 ('P', 'prune', [],
3286 ('P', 'prune', [],
3287 _('do not display revision or any of its ancestors'), _('REV')),
3287 _('do not display revision or any of its ancestors'), _('REV')),
3288 ] + logopts + walkopts,
3288 ] + logopts + walkopts,
3289 _('[OPTION]... [FILE]'),
3289 _('[OPTION]... [FILE]'),
3290 inferrepo=True, cmdtype=readonly)
3290 inferrepo=True, cmdtype=readonly)
3291 def log(ui, repo, *pats, **opts):
3291 def log(ui, repo, *pats, **opts):
3292 """show revision history of entire repository or files
3292 """show revision history of entire repository or files
3293
3293
3294 Print the revision history of the specified files or the entire
3294 Print the revision history of the specified files or the entire
3295 project.
3295 project.
3296
3296
3297 If no revision range is specified, the default is ``tip:0`` unless
3297 If no revision range is specified, the default is ``tip:0`` unless
3298 --follow is set, in which case the working directory parent is
3298 --follow is set, in which case the working directory parent is
3299 used as the starting revision.
3299 used as the starting revision.
3300
3300
3301 File history is shown without following rename or copy history of
3301 File history is shown without following rename or copy history of
3302 files. Use -f/--follow with a filename to follow history across
3302 files. Use -f/--follow with a filename to follow history across
3303 renames and copies. --follow without a filename will only show
3303 renames and copies. --follow without a filename will only show
3304 ancestors of the starting revision.
3304 ancestors of the starting revision.
3305
3305
3306 By default this command prints revision number and changeset id,
3306 By default this command prints revision number and changeset id,
3307 tags, non-trivial parents, user, date and time, and a summary for
3307 tags, non-trivial parents, user, date and time, and a summary for
3308 each commit. When the -v/--verbose switch is used, the list of
3308 each commit. When the -v/--verbose switch is used, the list of
3309 changed files and full commit message are shown.
3309 changed files and full commit message are shown.
3310
3310
3311 With --graph the revisions are shown as an ASCII art DAG with the most
3311 With --graph the revisions are shown as an ASCII art DAG with the most
3312 recent changeset at the top.
3312 recent changeset at the top.
3313 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3313 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3314 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3314 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3315 changeset from the lines below is a parent of the 'o' merge on the same
3315 changeset from the lines below is a parent of the 'o' merge on the same
3316 line.
3316 line.
3317 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3317 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3318 of a '|' indicates one or more revisions in a path are omitted.
3318 of a '|' indicates one or more revisions in a path are omitted.
3319
3319
3320 .. container:: verbose
3320 .. container:: verbose
3321
3321
3322 Use -L/--line-range FILE,M:N options to follow the history of lines
3322 Use -L/--line-range FILE,M:N options to follow the history of lines
3323 from M to N in FILE. With -p/--patch only diff hunks affecting
3323 from M to N in FILE. With -p/--patch only diff hunks affecting
3324 specified line range will be shown. This option requires --follow;
3324 specified line range will be shown. This option requires --follow;
3325 it can be specified multiple times. Currently, this option is not
3325 it can be specified multiple times. Currently, this option is not
3326 compatible with --graph. This option is experimental.
3326 compatible with --graph. This option is experimental.
3327
3327
3328 .. note::
3328 .. note::
3329
3329
3330 :hg:`log --patch` may generate unexpected diff output for merge
3330 :hg:`log --patch` may generate unexpected diff output for merge
3331 changesets, as it will only compare the merge changeset against
3331 changesets, as it will only compare the merge changeset against
3332 its first parent. Also, only files different from BOTH parents
3332 its first parent. Also, only files different from BOTH parents
3333 will appear in files:.
3333 will appear in files:.
3334
3334
3335 .. note::
3335 .. note::
3336
3336
3337 For performance reasons, :hg:`log FILE` may omit duplicate changes
3337 For performance reasons, :hg:`log FILE` may omit duplicate changes
3338 made on branches and will not show removals or mode changes. To
3338 made on branches and will not show removals or mode changes. To
3339 see all such changes, use the --removed switch.
3339 see all such changes, use the --removed switch.
3340
3340
3341 .. container:: verbose
3341 .. container:: verbose
3342
3342
3343 .. note::
3343 .. note::
3344
3344
3345 The history resulting from -L/--line-range options depends on diff
3345 The history resulting from -L/--line-range options depends on diff
3346 options; for instance if white-spaces are ignored, respective changes
3346 options; for instance if white-spaces are ignored, respective changes
3347 with only white-spaces in specified line range will not be listed.
3347 with only white-spaces in specified line range will not be listed.
3348
3348
3349 .. container:: verbose
3349 .. container:: verbose
3350
3350
3351 Some examples:
3351 Some examples:
3352
3352
3353 - changesets with full descriptions and file lists::
3353 - changesets with full descriptions and file lists::
3354
3354
3355 hg log -v
3355 hg log -v
3356
3356
3357 - changesets ancestral to the working directory::
3357 - changesets ancestral to the working directory::
3358
3358
3359 hg log -f
3359 hg log -f
3360
3360
3361 - last 10 commits on the current branch::
3361 - last 10 commits on the current branch::
3362
3362
3363 hg log -l 10 -b .
3363 hg log -l 10 -b .
3364
3364
3365 - changesets showing all modifications of a file, including removals::
3365 - changesets showing all modifications of a file, including removals::
3366
3366
3367 hg log --removed file.c
3367 hg log --removed file.c
3368
3368
3369 - all changesets that touch a directory, with diffs, excluding merges::
3369 - all changesets that touch a directory, with diffs, excluding merges::
3370
3370
3371 hg log -Mp lib/
3371 hg log -Mp lib/
3372
3372
3373 - all revision numbers that match a keyword::
3373 - all revision numbers that match a keyword::
3374
3374
3375 hg log -k bug --template "{rev}\\n"
3375 hg log -k bug --template "{rev}\\n"
3376
3376
3377 - the full hash identifier of the working directory parent::
3377 - the full hash identifier of the working directory parent::
3378
3378
3379 hg log -r . --template "{node}\\n"
3379 hg log -r . --template "{node}\\n"
3380
3380
3381 - list available log templates::
3381 - list available log templates::
3382
3382
3383 hg log -T list
3383 hg log -T list
3384
3384
3385 - check if a given changeset is included in a tagged release::
3385 - check if a given changeset is included in a tagged release::
3386
3386
3387 hg log -r "a21ccf and ancestor(1.9)"
3387 hg log -r "a21ccf and ancestor(1.9)"
3388
3388
3389 - find all changesets by some user in a date range::
3389 - find all changesets by some user in a date range::
3390
3390
3391 hg log -k alice -d "may 2008 to jul 2008"
3391 hg log -k alice -d "may 2008 to jul 2008"
3392
3392
3393 - summary of all changesets after the last tag::
3393 - summary of all changesets after the last tag::
3394
3394
3395 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3395 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3396
3396
3397 - changesets touching lines 13 to 23 for file.c::
3397 - changesets touching lines 13 to 23 for file.c::
3398
3398
3399 hg log -L file.c,13:23
3399 hg log -L file.c,13:23
3400
3400
3401 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3401 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3402 main.c with patch::
3402 main.c with patch::
3403
3403
3404 hg log -L file.c,13:23 -L main.c,2:6 -p
3404 hg log -L file.c,13:23 -L main.c,2:6 -p
3405
3405
3406 See :hg:`help dates` for a list of formats valid for -d/--date.
3406 See :hg:`help dates` for a list of formats valid for -d/--date.
3407
3407
3408 See :hg:`help revisions` for more about specifying and ordering
3408 See :hg:`help revisions` for more about specifying and ordering
3409 revisions.
3409 revisions.
3410
3410
3411 See :hg:`help templates` for more about pre-packaged styles and
3411 See :hg:`help templates` for more about pre-packaged styles and
3412 specifying custom templates. The default template used by the log
3412 specifying custom templates. The default template used by the log
3413 command can be customized via the ``ui.logtemplate`` configuration
3413 command can be customized via the ``ui.logtemplate`` configuration
3414 setting.
3414 setting.
3415
3415
3416 Returns 0 on success.
3416 Returns 0 on success.
3417
3417
3418 """
3418 """
3419 opts = pycompat.byteskwargs(opts)
3419 opts = pycompat.byteskwargs(opts)
3420 linerange = opts.get('line_range')
3420 linerange = opts.get('line_range')
3421
3421
3422 if linerange and not opts.get('follow'):
3422 if linerange and not opts.get('follow'):
3423 raise error.Abort(_('--line-range requires --follow'))
3423 raise error.Abort(_('--line-range requires --follow'))
3424
3424
3425 if linerange and pats:
3425 if linerange and pats:
3426 # TODO: take pats as patterns with no line-range filter
3426 # TODO: take pats as patterns with no line-range filter
3427 raise error.Abort(
3427 raise error.Abort(
3428 _('FILE arguments are not compatible with --line-range option')
3428 _('FILE arguments are not compatible with --line-range option')
3429 )
3429 )
3430
3430
3431 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3431 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3432 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3432 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3433 if linerange:
3433 if linerange:
3434 # TODO: should follow file history from logcmdutil._initialrevs(),
3434 # TODO: should follow file history from logcmdutil._initialrevs(),
3435 # then filter the result by logcmdutil._makerevset() and --limit
3435 # then filter the result by logcmdutil._makerevset() and --limit
3436 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3436 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3437
3437
3438 getrenamed = None
3438 getrenamed = None
3439 if opts.get('copies'):
3439 if opts.get('copies'):
3440 endrev = None
3440 endrev = None
3441 if opts.get('rev'):
3441 if opts.get('rev'):
3442 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3442 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3443 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3443 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3444
3444
3445 ui.pager('log')
3445 ui.pager('log')
3446 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3446 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3447 buffered=True)
3447 buffered=True)
3448 if opts.get('graph'):
3448 if opts.get('graph'):
3449 displayfn = logcmdutil.displaygraphrevs
3449 displayfn = logcmdutil.displaygraphrevs
3450 else:
3450 else:
3451 displayfn = logcmdutil.displayrevs
3451 displayfn = logcmdutil.displayrevs
3452 displayfn(ui, repo, revs, displayer, getrenamed)
3452 displayfn(ui, repo, revs, displayer, getrenamed)
3453
3453
3454 @command('manifest',
3454 @command('manifest',
3455 [('r', 'rev', '', _('revision to display'), _('REV')),
3455 [('r', 'rev', '', _('revision to display'), _('REV')),
3456 ('', 'all', False, _("list files from all revisions"))]
3456 ('', 'all', False, _("list files from all revisions"))]
3457 + formatteropts,
3457 + formatteropts,
3458 _('[-r REV]'), cmdtype=readonly)
3458 _('[-r REV]'), cmdtype=readonly)
3459 def manifest(ui, repo, node=None, rev=None, **opts):
3459 def manifest(ui, repo, node=None, rev=None, **opts):
3460 """output the current or given revision of the project manifest
3460 """output the current or given revision of the project manifest
3461
3461
3462 Print a list of version controlled files for the given revision.
3462 Print a list of version controlled files for the given revision.
3463 If no revision is given, the first parent of the working directory
3463 If no revision is given, the first parent of the working directory
3464 is used, or the null revision if no revision is checked out.
3464 is used, or the null revision if no revision is checked out.
3465
3465
3466 With -v, print file permissions, symlink and executable bits.
3466 With -v, print file permissions, symlink and executable bits.
3467 With --debug, print file revision hashes.
3467 With --debug, print file revision hashes.
3468
3468
3469 If option --all is specified, the list of all files from all revisions
3469 If option --all is specified, the list of all files from all revisions
3470 is printed. This includes deleted and renamed files.
3470 is printed. This includes deleted and renamed files.
3471
3471
3472 Returns 0 on success.
3472 Returns 0 on success.
3473 """
3473 """
3474 opts = pycompat.byteskwargs(opts)
3474 opts = pycompat.byteskwargs(opts)
3475 fm = ui.formatter('manifest', opts)
3475 fm = ui.formatter('manifest', opts)
3476
3476
3477 if opts.get('all'):
3477 if opts.get('all'):
3478 if rev or node:
3478 if rev or node:
3479 raise error.Abort(_("can't specify a revision with --all"))
3479 raise error.Abort(_("can't specify a revision with --all"))
3480
3480
3481 res = []
3481 res = []
3482 prefix = "data/"
3482 prefix = "data/"
3483 suffix = ".i"
3483 suffix = ".i"
3484 plen = len(prefix)
3484 plen = len(prefix)
3485 slen = len(suffix)
3485 slen = len(suffix)
3486 with repo.lock():
3486 with repo.lock():
3487 for fn, b, size in repo.store.datafiles():
3487 for fn, b, size in repo.store.datafiles():
3488 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3488 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3489 res.append(fn[plen:-slen])
3489 res.append(fn[plen:-slen])
3490 ui.pager('manifest')
3490 ui.pager('manifest')
3491 for f in res:
3491 for f in res:
3492 fm.startitem()
3492 fm.startitem()
3493 fm.write("path", '%s\n', f)
3493 fm.write("path", '%s\n', f)
3494 fm.end()
3494 fm.end()
3495 return
3495 return
3496
3496
3497 if rev and node:
3497 if rev and node:
3498 raise error.Abort(_("please specify just one revision"))
3498 raise error.Abort(_("please specify just one revision"))
3499
3499
3500 if not node:
3500 if not node:
3501 node = rev
3501 node = rev
3502
3502
3503 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3503 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3504 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3504 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3505 if node:
3505 if node:
3506 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3506 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3507 ctx = scmutil.revsingle(repo, node)
3507 ctx = scmutil.revsingle(repo, node)
3508 mf = ctx.manifest()
3508 mf = ctx.manifest()
3509 ui.pager('manifest')
3509 ui.pager('manifest')
3510 for f in ctx:
3510 for f in ctx:
3511 fm.startitem()
3511 fm.startitem()
3512 fl = ctx[f].flags()
3512 fl = ctx[f].flags()
3513 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3513 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3514 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3514 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3515 fm.write('path', '%s\n', f)
3515 fm.write('path', '%s\n', f)
3516 fm.end()
3516 fm.end()
3517
3517
3518 @command('^merge',
3518 @command('^merge',
3519 [('f', 'force', None,
3519 [('f', 'force', None,
3520 _('force a merge including outstanding changes (DEPRECATED)')),
3520 _('force a merge including outstanding changes (DEPRECATED)')),
3521 ('r', 'rev', '', _('revision to merge'), _('REV')),
3521 ('r', 'rev', '', _('revision to merge'), _('REV')),
3522 ('P', 'preview', None,
3522 ('P', 'preview', None,
3523 _('review revisions to merge (no merge is performed)')),
3523 _('review revisions to merge (no merge is performed)')),
3524 ('', 'abort', None, _('abort the ongoing merge')),
3524 ('', 'abort', None, _('abort the ongoing merge')),
3525 ] + mergetoolopts,
3525 ] + mergetoolopts,
3526 _('[-P] [[-r] REV]'))
3526 _('[-P] [[-r] REV]'))
3527 def merge(ui, repo, node=None, **opts):
3527 def merge(ui, repo, node=None, **opts):
3528 """merge another revision into working directory
3528 """merge another revision into working directory
3529
3529
3530 The current working directory is updated with all changes made in
3530 The current working directory is updated with all changes made in
3531 the requested revision since the last common predecessor revision.
3531 the requested revision since the last common predecessor revision.
3532
3532
3533 Files that changed between either parent are marked as changed for
3533 Files that changed between either parent are marked as changed for
3534 the next commit and a commit must be performed before any further
3534 the next commit and a commit must be performed before any further
3535 updates to the repository are allowed. The next commit will have
3535 updates to the repository are allowed. The next commit will have
3536 two parents.
3536 two parents.
3537
3537
3538 ``--tool`` can be used to specify the merge tool used for file
3538 ``--tool`` can be used to specify the merge tool used for file
3539 merges. It overrides the HGMERGE environment variable and your
3539 merges. It overrides the HGMERGE environment variable and your
3540 configuration files. See :hg:`help merge-tools` for options.
3540 configuration files. See :hg:`help merge-tools` for options.
3541
3541
3542 If no revision is specified, the working directory's parent is a
3542 If no revision is specified, the working directory's parent is a
3543 head revision, and the current branch contains exactly one other
3543 head revision, and the current branch contains exactly one other
3544 head, the other head is merged with by default. Otherwise, an
3544 head, the other head is merged with by default. Otherwise, an
3545 explicit revision with which to merge with must be provided.
3545 explicit revision with which to merge with must be provided.
3546
3546
3547 See :hg:`help resolve` for information on handling file conflicts.
3547 See :hg:`help resolve` for information on handling file conflicts.
3548
3548
3549 To undo an uncommitted merge, use :hg:`merge --abort` which
3549 To undo an uncommitted merge, use :hg:`merge --abort` which
3550 will check out a clean copy of the original merge parent, losing
3550 will check out a clean copy of the original merge parent, losing
3551 all changes.
3551 all changes.
3552
3552
3553 Returns 0 on success, 1 if there are unresolved files.
3553 Returns 0 on success, 1 if there are unresolved files.
3554 """
3554 """
3555
3555
3556 opts = pycompat.byteskwargs(opts)
3556 opts = pycompat.byteskwargs(opts)
3557 abort = opts.get('abort')
3557 abort = opts.get('abort')
3558 if abort and repo.dirstate.p2() == nullid:
3558 if abort and repo.dirstate.p2() == nullid:
3559 cmdutil.wrongtooltocontinue(repo, _('merge'))
3559 cmdutil.wrongtooltocontinue(repo, _('merge'))
3560 if abort:
3560 if abort:
3561 if node:
3561 if node:
3562 raise error.Abort(_("cannot specify a node with --abort"))
3562 raise error.Abort(_("cannot specify a node with --abort"))
3563 if opts.get('rev'):
3563 if opts.get('rev'):
3564 raise error.Abort(_("cannot specify both --rev and --abort"))
3564 raise error.Abort(_("cannot specify both --rev and --abort"))
3565 if opts.get('preview'):
3565 if opts.get('preview'):
3566 raise error.Abort(_("cannot specify --preview with --abort"))
3566 raise error.Abort(_("cannot specify --preview with --abort"))
3567 if opts.get('rev') and node:
3567 if opts.get('rev') and node:
3568 raise error.Abort(_("please specify just one revision"))
3568 raise error.Abort(_("please specify just one revision"))
3569 if not node:
3569 if not node:
3570 node = opts.get('rev')
3570 node = opts.get('rev')
3571
3571
3572 if node:
3572 if node:
3573 node = scmutil.revsingle(repo, node).node()
3573 node = scmutil.revsingle(repo, node).node()
3574
3574
3575 if not node and not abort:
3575 if not node and not abort:
3576 node = repo[destutil.destmerge(repo)].node()
3576 node = repo[destutil.destmerge(repo)].node()
3577
3577
3578 if opts.get('preview'):
3578 if opts.get('preview'):
3579 # find nodes that are ancestors of p2 but not of p1
3579 # find nodes that are ancestors of p2 but not of p1
3580 p1 = repo.lookup('.')
3580 p1 = repo.lookup('.')
3581 p2 = repo.lookup(node)
3581 p2 = repo.lookup(node)
3582 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3582 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3583
3583
3584 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3584 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3585 for node in nodes:
3585 for node in nodes:
3586 displayer.show(repo[node])
3586 displayer.show(repo[node])
3587 displayer.close()
3587 displayer.close()
3588 return 0
3588 return 0
3589
3589
3590 try:
3590 try:
3591 # ui.forcemerge is an internal variable, do not document
3591 # ui.forcemerge is an internal variable, do not document
3592 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3592 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3593 force = opts.get('force')
3593 force = opts.get('force')
3594 labels = ['working copy', 'merge rev']
3594 labels = ['working copy', 'merge rev']
3595 return hg.merge(repo, node, force=force, mergeforce=force,
3595 return hg.merge(repo, node, force=force, mergeforce=force,
3596 labels=labels, abort=abort)
3596 labels=labels, abort=abort)
3597 finally:
3597 finally:
3598 ui.setconfig('ui', 'forcemerge', '', 'merge')
3598 ui.setconfig('ui', 'forcemerge', '', 'merge')
3599
3599
3600 @command('outgoing|out',
3600 @command('outgoing|out',
3601 [('f', 'force', None, _('run even when the destination is unrelated')),
3601 [('f', 'force', None, _('run even when the destination is unrelated')),
3602 ('r', 'rev', [],
3602 ('r', 'rev', [],
3603 _('a changeset intended to be included in the destination'), _('REV')),
3603 _('a changeset intended to be included in the destination'), _('REV')),
3604 ('n', 'newest-first', None, _('show newest record first')),
3604 ('n', 'newest-first', None, _('show newest record first')),
3605 ('B', 'bookmarks', False, _('compare bookmarks')),
3605 ('B', 'bookmarks', False, _('compare bookmarks')),
3606 ('b', 'branch', [], _('a specific branch you would like to push'),
3606 ('b', 'branch', [], _('a specific branch you would like to push'),
3607 _('BRANCH')),
3607 _('BRANCH')),
3608 ] + logopts + remoteopts + subrepoopts,
3608 ] + logopts + remoteopts + subrepoopts,
3609 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3609 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3610 def outgoing(ui, repo, dest=None, **opts):
3610 def outgoing(ui, repo, dest=None, **opts):
3611 """show changesets not found in the destination
3611 """show changesets not found in the destination
3612
3612
3613 Show changesets not found in the specified destination repository
3613 Show changesets not found in the specified destination repository
3614 or the default push location. These are the changesets that would
3614 or the default push location. These are the changesets that would
3615 be pushed if a push was requested.
3615 be pushed if a push was requested.
3616
3616
3617 See pull for details of valid destination formats.
3617 See pull for details of valid destination formats.
3618
3618
3619 .. container:: verbose
3619 .. container:: verbose
3620
3620
3621 With -B/--bookmarks, the result of bookmark comparison between
3621 With -B/--bookmarks, the result of bookmark comparison between
3622 local and remote repositories is displayed. With -v/--verbose,
3622 local and remote repositories is displayed. With -v/--verbose,
3623 status is also displayed for each bookmark like below::
3623 status is also displayed for each bookmark like below::
3624
3624
3625 BM1 01234567890a added
3625 BM1 01234567890a added
3626 BM2 deleted
3626 BM2 deleted
3627 BM3 234567890abc advanced
3627 BM3 234567890abc advanced
3628 BM4 34567890abcd diverged
3628 BM4 34567890abcd diverged
3629 BM5 4567890abcde changed
3629 BM5 4567890abcde changed
3630
3630
3631 The action taken when pushing depends on the
3631 The action taken when pushing depends on the
3632 status of each bookmark:
3632 status of each bookmark:
3633
3633
3634 :``added``: push with ``-B`` will create it
3634 :``added``: push with ``-B`` will create it
3635 :``deleted``: push with ``-B`` will delete it
3635 :``deleted``: push with ``-B`` will delete it
3636 :``advanced``: push will update it
3636 :``advanced``: push will update it
3637 :``diverged``: push with ``-B`` will update it
3637 :``diverged``: push with ``-B`` will update it
3638 :``changed``: push with ``-B`` will update it
3638 :``changed``: push with ``-B`` will update it
3639
3639
3640 From the point of view of pushing behavior, bookmarks
3640 From the point of view of pushing behavior, bookmarks
3641 existing only in the remote repository are treated as
3641 existing only in the remote repository are treated as
3642 ``deleted``, even if it is in fact added remotely.
3642 ``deleted``, even if it is in fact added remotely.
3643
3643
3644 Returns 0 if there are outgoing changes, 1 otherwise.
3644 Returns 0 if there are outgoing changes, 1 otherwise.
3645 """
3645 """
3646 opts = pycompat.byteskwargs(opts)
3646 opts = pycompat.byteskwargs(opts)
3647 if opts.get('graph'):
3647 if opts.get('graph'):
3648 logcmdutil.checkunsupportedgraphflags([], opts)
3648 logcmdutil.checkunsupportedgraphflags([], opts)
3649 o, other = hg._outgoing(ui, repo, dest, opts)
3649 o, other = hg._outgoing(ui, repo, dest, opts)
3650 if not o:
3650 if not o:
3651 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3651 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3652 return
3652 return
3653
3653
3654 revdag = logcmdutil.graphrevs(repo, o, opts)
3654 revdag = logcmdutil.graphrevs(repo, o, opts)
3655 ui.pager('outgoing')
3655 ui.pager('outgoing')
3656 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3656 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3657 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3657 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3658 graphmod.asciiedges)
3658 graphmod.asciiedges)
3659 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3659 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3660 return 0
3660 return 0
3661
3661
3662 if opts.get('bookmarks'):
3662 if opts.get('bookmarks'):
3663 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3663 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3664 dest, branches = hg.parseurl(dest, opts.get('branch'))
3664 dest, branches = hg.parseurl(dest, opts.get('branch'))
3665 other = hg.peer(repo, opts, dest)
3665 other = hg.peer(repo, opts, dest)
3666 if 'bookmarks' not in other.listkeys('namespaces'):
3666 if 'bookmarks' not in other.listkeys('namespaces'):
3667 ui.warn(_("remote doesn't support bookmarks\n"))
3667 ui.warn(_("remote doesn't support bookmarks\n"))
3668 return 0
3668 return 0
3669 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3669 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3670 ui.pager('outgoing')
3670 ui.pager('outgoing')
3671 return bookmarks.outgoing(ui, repo, other)
3671 return bookmarks.outgoing(ui, repo, other)
3672
3672
3673 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3673 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3674 try:
3674 try:
3675 return hg.outgoing(ui, repo, dest, opts)
3675 return hg.outgoing(ui, repo, dest, opts)
3676 finally:
3676 finally:
3677 del repo._subtoppath
3677 del repo._subtoppath
3678
3678
3679 @command('parents',
3679 @command('parents',
3680 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3680 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3681 ] + templateopts,
3681 ] + templateopts,
3682 _('[-r REV] [FILE]'),
3682 _('[-r REV] [FILE]'),
3683 inferrepo=True)
3683 inferrepo=True)
3684 def parents(ui, repo, file_=None, **opts):
3684 def parents(ui, repo, file_=None, **opts):
3685 """show the parents of the working directory or revision (DEPRECATED)
3685 """show the parents of the working directory or revision (DEPRECATED)
3686
3686
3687 Print the working directory's parent revisions. If a revision is
3687 Print the working directory's parent revisions. If a revision is
3688 given via -r/--rev, the parent of that revision will be printed.
3688 given via -r/--rev, the parent of that revision will be printed.
3689 If a file argument is given, the revision in which the file was
3689 If a file argument is given, the revision in which the file was
3690 last changed (before the working directory revision or the
3690 last changed (before the working directory revision or the
3691 argument to --rev if given) is printed.
3691 argument to --rev if given) is printed.
3692
3692
3693 This command is equivalent to::
3693 This command is equivalent to::
3694
3694
3695 hg log -r "p1()+p2()" or
3695 hg log -r "p1()+p2()" or
3696 hg log -r "p1(REV)+p2(REV)" or
3696 hg log -r "p1(REV)+p2(REV)" or
3697 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3697 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3698 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3698 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3699
3699
3700 See :hg:`summary` and :hg:`help revsets` for related information.
3700 See :hg:`summary` and :hg:`help revsets` for related information.
3701
3701
3702 Returns 0 on success.
3702 Returns 0 on success.
3703 """
3703 """
3704
3704
3705 opts = pycompat.byteskwargs(opts)
3705 opts = pycompat.byteskwargs(opts)
3706 rev = opts.get('rev')
3706 rev = opts.get('rev')
3707 if rev:
3707 if rev:
3708 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3708 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3709 ctx = scmutil.revsingle(repo, rev, None)
3709 ctx = scmutil.revsingle(repo, rev, None)
3710
3710
3711 if file_:
3711 if file_:
3712 m = scmutil.match(ctx, (file_,), opts)
3712 m = scmutil.match(ctx, (file_,), opts)
3713 if m.anypats() or len(m.files()) != 1:
3713 if m.anypats() or len(m.files()) != 1:
3714 raise error.Abort(_('can only specify an explicit filename'))
3714 raise error.Abort(_('can only specify an explicit filename'))
3715 file_ = m.files()[0]
3715 file_ = m.files()[0]
3716 filenodes = []
3716 filenodes = []
3717 for cp in ctx.parents():
3717 for cp in ctx.parents():
3718 if not cp:
3718 if not cp:
3719 continue
3719 continue
3720 try:
3720 try:
3721 filenodes.append(cp.filenode(file_))
3721 filenodes.append(cp.filenode(file_))
3722 except error.LookupError:
3722 except error.LookupError:
3723 pass
3723 pass
3724 if not filenodes:
3724 if not filenodes:
3725 raise error.Abort(_("'%s' not found in manifest!") % file_)
3725 raise error.Abort(_("'%s' not found in manifest!") % file_)
3726 p = []
3726 p = []
3727 for fn in filenodes:
3727 for fn in filenodes:
3728 fctx = repo.filectx(file_, fileid=fn)
3728 fctx = repo.filectx(file_, fileid=fn)
3729 p.append(fctx.node())
3729 p.append(fctx.node())
3730 else:
3730 else:
3731 p = [cp.node() for cp in ctx.parents()]
3731 p = [cp.node() for cp in ctx.parents()]
3732
3732
3733 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3733 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3734 for n in p:
3734 for n in p:
3735 if n != nullid:
3735 if n != nullid:
3736 displayer.show(repo[n])
3736 displayer.show(repo[n])
3737 displayer.close()
3737 displayer.close()
3738
3738
3739 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3739 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3740 cmdtype=readonly)
3740 cmdtype=readonly)
3741 def paths(ui, repo, search=None, **opts):
3741 def paths(ui, repo, search=None, **opts):
3742 """show aliases for remote repositories
3742 """show aliases for remote repositories
3743
3743
3744 Show definition of symbolic path name NAME. If no name is given,
3744 Show definition of symbolic path name NAME. If no name is given,
3745 show definition of all available names.
3745 show definition of all available names.
3746
3746
3747 Option -q/--quiet suppresses all output when searching for NAME
3747 Option -q/--quiet suppresses all output when searching for NAME
3748 and shows only the path names when listing all definitions.
3748 and shows only the path names when listing all definitions.
3749
3749
3750 Path names are defined in the [paths] section of your
3750 Path names are defined in the [paths] section of your
3751 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3751 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3752 repository, ``.hg/hgrc`` is used, too.
3752 repository, ``.hg/hgrc`` is used, too.
3753
3753
3754 The path names ``default`` and ``default-push`` have a special
3754 The path names ``default`` and ``default-push`` have a special
3755 meaning. When performing a push or pull operation, they are used
3755 meaning. When performing a push or pull operation, they are used
3756 as fallbacks if no location is specified on the command-line.
3756 as fallbacks if no location is specified on the command-line.
3757 When ``default-push`` is set, it will be used for push and
3757 When ``default-push`` is set, it will be used for push and
3758 ``default`` will be used for pull; otherwise ``default`` is used
3758 ``default`` will be used for pull; otherwise ``default`` is used
3759 as the fallback for both. When cloning a repository, the clone
3759 as the fallback for both. When cloning a repository, the clone
3760 source is written as ``default`` in ``.hg/hgrc``.
3760 source is written as ``default`` in ``.hg/hgrc``.
3761
3761
3762 .. note::
3762 .. note::
3763
3763
3764 ``default`` and ``default-push`` apply to all inbound (e.g.
3764 ``default`` and ``default-push`` apply to all inbound (e.g.
3765 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3765 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3766 and :hg:`bundle`) operations.
3766 and :hg:`bundle`) operations.
3767
3767
3768 See :hg:`help urls` for more information.
3768 See :hg:`help urls` for more information.
3769
3769
3770 Returns 0 on success.
3770 Returns 0 on success.
3771 """
3771 """
3772
3772
3773 opts = pycompat.byteskwargs(opts)
3773 opts = pycompat.byteskwargs(opts)
3774 ui.pager('paths')
3774 ui.pager('paths')
3775 if search:
3775 if search:
3776 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3776 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3777 if name == search]
3777 if name == search]
3778 else:
3778 else:
3779 pathitems = sorted(ui.paths.iteritems())
3779 pathitems = sorted(ui.paths.iteritems())
3780
3780
3781 fm = ui.formatter('paths', opts)
3781 fm = ui.formatter('paths', opts)
3782 if fm.isplain():
3782 if fm.isplain():
3783 hidepassword = util.hidepassword
3783 hidepassword = util.hidepassword
3784 else:
3784 else:
3785 hidepassword = bytes
3785 hidepassword = bytes
3786 if ui.quiet:
3786 if ui.quiet:
3787 namefmt = '%s\n'
3787 namefmt = '%s\n'
3788 else:
3788 else:
3789 namefmt = '%s = '
3789 namefmt = '%s = '
3790 showsubopts = not search and not ui.quiet
3790 showsubopts = not search and not ui.quiet
3791
3791
3792 for name, path in pathitems:
3792 for name, path in pathitems:
3793 fm.startitem()
3793 fm.startitem()
3794 fm.condwrite(not search, 'name', namefmt, name)
3794 fm.condwrite(not search, 'name', namefmt, name)
3795 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3795 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3796 for subopt, value in sorted(path.suboptions.items()):
3796 for subopt, value in sorted(path.suboptions.items()):
3797 assert subopt not in ('name', 'url')
3797 assert subopt not in ('name', 'url')
3798 if showsubopts:
3798 if showsubopts:
3799 fm.plain('%s:%s = ' % (name, subopt))
3799 fm.plain('%s:%s = ' % (name, subopt))
3800 fm.condwrite(showsubopts, subopt, '%s\n', value)
3800 fm.condwrite(showsubopts, subopt, '%s\n', value)
3801
3801
3802 fm.end()
3802 fm.end()
3803
3803
3804 if search and not pathitems:
3804 if search and not pathitems:
3805 if not ui.quiet:
3805 if not ui.quiet:
3806 ui.warn(_("not found!\n"))
3806 ui.warn(_("not found!\n"))
3807 return 1
3807 return 1
3808 else:
3808 else:
3809 return 0
3809 return 0
3810
3810
3811 @command('phase',
3811 @command('phase',
3812 [('p', 'public', False, _('set changeset phase to public')),
3812 [('p', 'public', False, _('set changeset phase to public')),
3813 ('d', 'draft', False, _('set changeset phase to draft')),
3813 ('d', 'draft', False, _('set changeset phase to draft')),
3814 ('s', 'secret', False, _('set changeset phase to secret')),
3814 ('s', 'secret', False, _('set changeset phase to secret')),
3815 ('f', 'force', False, _('allow to move boundary backward')),
3815 ('f', 'force', False, _('allow to move boundary backward')),
3816 ('r', 'rev', [], _('target revision'), _('REV')),
3816 ('r', 'rev', [], _('target revision'), _('REV')),
3817 ],
3817 ],
3818 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3818 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3819 def phase(ui, repo, *revs, **opts):
3819 def phase(ui, repo, *revs, **opts):
3820 """set or show the current phase name
3820 """set or show the current phase name
3821
3821
3822 With no argument, show the phase name of the current revision(s).
3822 With no argument, show the phase name of the current revision(s).
3823
3823
3824 With one of -p/--public, -d/--draft or -s/--secret, change the
3824 With one of -p/--public, -d/--draft or -s/--secret, change the
3825 phase value of the specified revisions.
3825 phase value of the specified revisions.
3826
3826
3827 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3827 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3828 lower phase to a higher phase. Phases are ordered as follows::
3828 lower phase to a higher phase. Phases are ordered as follows::
3829
3829
3830 public < draft < secret
3830 public < draft < secret
3831
3831
3832 Returns 0 on success, 1 if some phases could not be changed.
3832 Returns 0 on success, 1 if some phases could not be changed.
3833
3833
3834 (For more information about the phases concept, see :hg:`help phases`.)
3834 (For more information about the phases concept, see :hg:`help phases`.)
3835 """
3835 """
3836 opts = pycompat.byteskwargs(opts)
3836 opts = pycompat.byteskwargs(opts)
3837 # search for a unique phase argument
3837 # search for a unique phase argument
3838 targetphase = None
3838 targetphase = None
3839 for idx, name in enumerate(phases.phasenames):
3839 for idx, name in enumerate(phases.phasenames):
3840 if opts[name]:
3840 if opts[name]:
3841 if targetphase is not None:
3841 if targetphase is not None:
3842 raise error.Abort(_('only one phase can be specified'))
3842 raise error.Abort(_('only one phase can be specified'))
3843 targetphase = idx
3843 targetphase = idx
3844
3844
3845 # look for specified revision
3845 # look for specified revision
3846 revs = list(revs)
3846 revs = list(revs)
3847 revs.extend(opts['rev'])
3847 revs.extend(opts['rev'])
3848 if not revs:
3848 if not revs:
3849 # display both parents as the second parent phase can influence
3849 # display both parents as the second parent phase can influence
3850 # the phase of a merge commit
3850 # the phase of a merge commit
3851 revs = [c.rev() for c in repo[None].parents()]
3851 revs = [c.rev() for c in repo[None].parents()]
3852
3852
3853 revs = scmutil.revrange(repo, revs)
3853 revs = scmutil.revrange(repo, revs)
3854
3854
3855 ret = 0
3855 ret = 0
3856 if targetphase is None:
3856 if targetphase is None:
3857 # display
3857 # display
3858 for r in revs:
3858 for r in revs:
3859 ctx = repo[r]
3859 ctx = repo[r]
3860 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3860 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3861 else:
3861 else:
3862 with repo.lock(), repo.transaction("phase") as tr:
3862 with repo.lock(), repo.transaction("phase") as tr:
3863 # set phase
3863 # set phase
3864 if not revs:
3864 if not revs:
3865 raise error.Abort(_('empty revision set'))
3865 raise error.Abort(_('empty revision set'))
3866 nodes = [repo[r].node() for r in revs]
3866 nodes = [repo[r].node() for r in revs]
3867 # moving revision from public to draft may hide them
3867 # moving revision from public to draft may hide them
3868 # We have to check result on an unfiltered repository
3868 # We have to check result on an unfiltered repository
3869 unfi = repo.unfiltered()
3869 unfi = repo.unfiltered()
3870 getphase = unfi._phasecache.phase
3870 getphase = unfi._phasecache.phase
3871 olddata = [getphase(unfi, r) for r in unfi]
3871 olddata = [getphase(unfi, r) for r in unfi]
3872 phases.advanceboundary(repo, tr, targetphase, nodes)
3872 phases.advanceboundary(repo, tr, targetphase, nodes)
3873 if opts['force']:
3873 if opts['force']:
3874 phases.retractboundary(repo, tr, targetphase, nodes)
3874 phases.retractboundary(repo, tr, targetphase, nodes)
3875 getphase = unfi._phasecache.phase
3875 getphase = unfi._phasecache.phase
3876 newdata = [getphase(unfi, r) for r in unfi]
3876 newdata = [getphase(unfi, r) for r in unfi]
3877 changes = sum(newdata[r] != olddata[r] for r in unfi)
3877 changes = sum(newdata[r] != olddata[r] for r in unfi)
3878 cl = unfi.changelog
3878 cl = unfi.changelog
3879 rejected = [n for n in nodes
3879 rejected = [n for n in nodes
3880 if newdata[cl.rev(n)] < targetphase]
3880 if newdata[cl.rev(n)] < targetphase]
3881 if rejected:
3881 if rejected:
3882 ui.warn(_('cannot move %i changesets to a higher '
3882 ui.warn(_('cannot move %i changesets to a higher '
3883 'phase, use --force\n') % len(rejected))
3883 'phase, use --force\n') % len(rejected))
3884 ret = 1
3884 ret = 1
3885 if changes:
3885 if changes:
3886 msg = _('phase changed for %i changesets\n') % changes
3886 msg = _('phase changed for %i changesets\n') % changes
3887 if ret:
3887 if ret:
3888 ui.status(msg)
3888 ui.status(msg)
3889 else:
3889 else:
3890 ui.note(msg)
3890 ui.note(msg)
3891 else:
3891 else:
3892 ui.warn(_('no phases changed\n'))
3892 ui.warn(_('no phases changed\n'))
3893 return ret
3893 return ret
3894
3894
3895 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3895 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3896 """Run after a changegroup has been added via pull/unbundle
3896 """Run after a changegroup has been added via pull/unbundle
3897
3897
3898 This takes arguments below:
3898 This takes arguments below:
3899
3899
3900 :modheads: change of heads by pull/unbundle
3900 :modheads: change of heads by pull/unbundle
3901 :optupdate: updating working directory is needed or not
3901 :optupdate: updating working directory is needed or not
3902 :checkout: update destination revision (or None to default destination)
3902 :checkout: update destination revision (or None to default destination)
3903 :brev: a name, which might be a bookmark to be activated after updating
3903 :brev: a name, which might be a bookmark to be activated after updating
3904 """
3904 """
3905 if modheads == 0:
3905 if modheads == 0:
3906 return
3906 return
3907 if optupdate:
3907 if optupdate:
3908 try:
3908 try:
3909 return hg.updatetotally(ui, repo, checkout, brev)
3909 return hg.updatetotally(ui, repo, checkout, brev)
3910 except error.UpdateAbort as inst:
3910 except error.UpdateAbort as inst:
3911 msg = _("not updating: %s") % util.forcebytestr(inst)
3911 msg = _("not updating: %s") % util.forcebytestr(inst)
3912 hint = inst.hint
3912 hint = inst.hint
3913 raise error.UpdateAbort(msg, hint=hint)
3913 raise error.UpdateAbort(msg, hint=hint)
3914 if modheads > 1:
3914 if modheads > 1:
3915 currentbranchheads = len(repo.branchheads())
3915 currentbranchheads = len(repo.branchheads())
3916 if currentbranchheads == modheads:
3916 if currentbranchheads == modheads:
3917 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3917 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3918 elif currentbranchheads > 1:
3918 elif currentbranchheads > 1:
3919 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3919 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3920 "merge)\n"))
3920 "merge)\n"))
3921 else:
3921 else:
3922 ui.status(_("(run 'hg heads' to see heads)\n"))
3922 ui.status(_("(run 'hg heads' to see heads)\n"))
3923 elif not ui.configbool('commands', 'update.requiredest'):
3923 elif not ui.configbool('commands', 'update.requiredest'):
3924 ui.status(_("(run 'hg update' to get a working copy)\n"))
3924 ui.status(_("(run 'hg update' to get a working copy)\n"))
3925
3925
3926 @command('^pull',
3926 @command('^pull',
3927 [('u', 'update', None,
3927 [('u', 'update', None,
3928 _('update to new branch head if new descendants were pulled')),
3928 _('update to new branch head if new descendants were pulled')),
3929 ('f', 'force', None, _('run even when remote repository is unrelated')),
3929 ('f', 'force', None, _('run even when remote repository is unrelated')),
3930 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3930 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3931 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3931 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3932 ('b', 'branch', [], _('a specific branch you would like to pull'),
3932 ('b', 'branch', [], _('a specific branch you would like to pull'),
3933 _('BRANCH')),
3933 _('BRANCH')),
3934 ] + remoteopts,
3934 ] + remoteopts,
3935 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3935 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3936 def pull(ui, repo, source="default", **opts):
3936 def pull(ui, repo, source="default", **opts):
3937 """pull changes from the specified source
3937 """pull changes from the specified source
3938
3938
3939 Pull changes from a remote repository to a local one.
3939 Pull changes from a remote repository to a local one.
3940
3940
3941 This finds all changes from the repository at the specified path
3941 This finds all changes from the repository at the specified path
3942 or URL and adds them to a local repository (the current one unless
3942 or URL and adds them to a local repository (the current one unless
3943 -R is specified). By default, this does not update the copy of the
3943 -R is specified). By default, this does not update the copy of the
3944 project in the working directory.
3944 project in the working directory.
3945
3945
3946 Use :hg:`incoming` if you want to see what would have been added
3946 Use :hg:`incoming` if you want to see what would have been added
3947 by a pull at the time you issued this command. If you then decide
3947 by a pull at the time you issued this command. If you then decide
3948 to add those changes to the repository, you should use :hg:`pull
3948 to add those changes to the repository, you should use :hg:`pull
3949 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3949 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3950
3950
3951 If SOURCE is omitted, the 'default' path will be used.
3951 If SOURCE is omitted, the 'default' path will be used.
3952 See :hg:`help urls` for more information.
3952 See :hg:`help urls` for more information.
3953
3953
3954 Specifying bookmark as ``.`` is equivalent to specifying the active
3954 Specifying bookmark as ``.`` is equivalent to specifying the active
3955 bookmark's name.
3955 bookmark's name.
3956
3956
3957 Returns 0 on success, 1 if an update had unresolved files.
3957 Returns 0 on success, 1 if an update had unresolved files.
3958 """
3958 """
3959
3959
3960 opts = pycompat.byteskwargs(opts)
3960 opts = pycompat.byteskwargs(opts)
3961 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3961 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3962 msg = _('update destination required by configuration')
3962 msg = _('update destination required by configuration')
3963 hint = _('use hg pull followed by hg update DEST')
3963 hint = _('use hg pull followed by hg update DEST')
3964 raise error.Abort(msg, hint=hint)
3964 raise error.Abort(msg, hint=hint)
3965
3965
3966 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3966 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3967 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3967 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3968 other = hg.peer(repo, opts, source)
3968 other = hg.peer(repo, opts, source)
3969 try:
3969 try:
3970 revs, checkout = hg.addbranchrevs(repo, other, branches,
3970 revs, checkout = hg.addbranchrevs(repo, other, branches,
3971 opts.get('rev'))
3971 opts.get('rev'))
3972
3972
3973
3973
3974 pullopargs = {}
3974 pullopargs = {}
3975 if opts.get('bookmark'):
3975 if opts.get('bookmark'):
3976 if not revs:
3976 if not revs:
3977 revs = []
3977 revs = []
3978 # The list of bookmark used here is not the one used to actually
3978 # The list of bookmark used here is not the one used to actually
3979 # update the bookmark name. This can result in the revision pulled
3979 # update the bookmark name. This can result in the revision pulled
3980 # not ending up with the name of the bookmark because of a race
3980 # not ending up with the name of the bookmark because of a race
3981 # condition on the server. (See issue 4689 for details)
3981 # condition on the server. (See issue 4689 for details)
3982 remotebookmarks = other.listkeys('bookmarks')
3982 remotebookmarks = other.listkeys('bookmarks')
3983 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3983 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3984 pullopargs['remotebookmarks'] = remotebookmarks
3984 pullopargs['remotebookmarks'] = remotebookmarks
3985 for b in opts['bookmark']:
3985 for b in opts['bookmark']:
3986 b = repo._bookmarks.expandname(b)
3986 b = repo._bookmarks.expandname(b)
3987 if b not in remotebookmarks:
3987 if b not in remotebookmarks:
3988 raise error.Abort(_('remote bookmark %s not found!') % b)
3988 raise error.Abort(_('remote bookmark %s not found!') % b)
3989 revs.append(hex(remotebookmarks[b]))
3989 revs.append(hex(remotebookmarks[b]))
3990
3990
3991 if revs:
3991 if revs:
3992 try:
3992 try:
3993 # When 'rev' is a bookmark name, we cannot guarantee that it
3993 # When 'rev' is a bookmark name, we cannot guarantee that it
3994 # will be updated with that name because of a race condition
3994 # will be updated with that name because of a race condition
3995 # server side. (See issue 4689 for details)
3995 # server side. (See issue 4689 for details)
3996 oldrevs = revs
3996 oldrevs = revs
3997 revs = [] # actually, nodes
3997 revs = [] # actually, nodes
3998 for r in oldrevs:
3998 for r in oldrevs:
3999 node = other.lookup(r)
3999 node = other.lookup(r)
4000 revs.append(node)
4000 revs.append(node)
4001 if r == checkout:
4001 if r == checkout:
4002 checkout = node
4002 checkout = node
4003 except error.CapabilityError:
4003 except error.CapabilityError:
4004 err = _("other repository doesn't support revision lookup, "
4004 err = _("other repository doesn't support revision lookup, "
4005 "so a rev cannot be specified.")
4005 "so a rev cannot be specified.")
4006 raise error.Abort(err)
4006 raise error.Abort(err)
4007
4007
4008 wlock = util.nullcontextmanager()
4008 wlock = util.nullcontextmanager()
4009 if opts.get('update'):
4009 if opts.get('update'):
4010 wlock = repo.wlock()
4010 wlock = repo.wlock()
4011 with wlock:
4011 with wlock:
4012 pullopargs.update(opts.get('opargs', {}))
4012 pullopargs.update(opts.get('opargs', {}))
4013 modheads = exchange.pull(repo, other, heads=revs,
4013 modheads = exchange.pull(repo, other, heads=revs,
4014 force=opts.get('force'),
4014 force=opts.get('force'),
4015 bookmarks=opts.get('bookmark', ()),
4015 bookmarks=opts.get('bookmark', ()),
4016 opargs=pullopargs).cgresult
4016 opargs=pullopargs).cgresult
4017
4017
4018 # brev is a name, which might be a bookmark to be activated at
4018 # brev is a name, which might be a bookmark to be activated at
4019 # the end of the update. In other words, it is an explicit
4019 # the end of the update. In other words, it is an explicit
4020 # destination of the update
4020 # destination of the update
4021 brev = None
4021 brev = None
4022
4022
4023 if checkout:
4023 if checkout:
4024 checkout = "%d" % repo.changelog.rev(checkout)
4024 checkout = "%d" % repo.changelog.rev(checkout)
4025
4025
4026 # order below depends on implementation of
4026 # order below depends on implementation of
4027 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4027 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4028 # because 'checkout' is determined without it.
4028 # because 'checkout' is determined without it.
4029 if opts.get('rev'):
4029 if opts.get('rev'):
4030 brev = opts['rev'][0]
4030 brev = opts['rev'][0]
4031 elif opts.get('branch'):
4031 elif opts.get('branch'):
4032 brev = opts['branch'][0]
4032 brev = opts['branch'][0]
4033 else:
4033 else:
4034 brev = branches[0]
4034 brev = branches[0]
4035 repo._subtoppath = source
4035 repo._subtoppath = source
4036 try:
4036 try:
4037 ret = postincoming(ui, repo, modheads, opts.get('update'),
4037 ret = postincoming(ui, repo, modheads, opts.get('update'),
4038 checkout, brev)
4038 checkout, brev)
4039
4039
4040 finally:
4040 finally:
4041 del repo._subtoppath
4041 del repo._subtoppath
4042
4042
4043 finally:
4043 finally:
4044 other.close()
4044 other.close()
4045 return ret
4045 return ret
4046
4046
4047 @command('^push',
4047 @command('^push',
4048 [('f', 'force', None, _('force push')),
4048 [('f', 'force', None, _('force push')),
4049 ('r', 'rev', [],
4049 ('r', 'rev', [],
4050 _('a changeset intended to be included in the destination'),
4050 _('a changeset intended to be included in the destination'),
4051 _('REV')),
4051 _('REV')),
4052 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4052 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4053 ('b', 'branch', [],
4053 ('b', 'branch', [],
4054 _('a specific branch you would like to push'), _('BRANCH')),
4054 _('a specific branch you would like to push'), _('BRANCH')),
4055 ('', 'new-branch', False, _('allow pushing a new branch')),
4055 ('', 'new-branch', False, _('allow pushing a new branch')),
4056 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4056 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4057 ] + remoteopts,
4057 ] + remoteopts,
4058 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4058 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4059 def push(ui, repo, dest=None, **opts):
4059 def push(ui, repo, dest=None, **opts):
4060 """push changes to the specified destination
4060 """push changes to the specified destination
4061
4061
4062 Push changesets from the local repository to the specified
4062 Push changesets from the local repository to the specified
4063 destination.
4063 destination.
4064
4064
4065 This operation is symmetrical to pull: it is identical to a pull
4065 This operation is symmetrical to pull: it is identical to a pull
4066 in the destination repository from the current one.
4066 in the destination repository from the current one.
4067
4067
4068 By default, push will not allow creation of new heads at the
4068 By default, push will not allow creation of new heads at the
4069 destination, since multiple heads would make it unclear which head
4069 destination, since multiple heads would make it unclear which head
4070 to use. In this situation, it is recommended to pull and merge
4070 to use. In this situation, it is recommended to pull and merge
4071 before pushing.
4071 before pushing.
4072
4072
4073 Use --new-branch if you want to allow push to create a new named
4073 Use --new-branch if you want to allow push to create a new named
4074 branch that is not present at the destination. This allows you to
4074 branch that is not present at the destination. This allows you to
4075 only create a new branch without forcing other changes.
4075 only create a new branch without forcing other changes.
4076
4076
4077 .. note::
4077 .. note::
4078
4078
4079 Extra care should be taken with the -f/--force option,
4079 Extra care should be taken with the -f/--force option,
4080 which will push all new heads on all branches, an action which will
4080 which will push all new heads on all branches, an action which will
4081 almost always cause confusion for collaborators.
4081 almost always cause confusion for collaborators.
4082
4082
4083 If -r/--rev is used, the specified revision and all its ancestors
4083 If -r/--rev is used, the specified revision and all its ancestors
4084 will be pushed to the remote repository.
4084 will be pushed to the remote repository.
4085
4085
4086 If -B/--bookmark is used, the specified bookmarked revision, its
4086 If -B/--bookmark is used, the specified bookmarked revision, its
4087 ancestors, and the bookmark will be pushed to the remote
4087 ancestors, and the bookmark will be pushed to the remote
4088 repository. Specifying ``.`` is equivalent to specifying the active
4088 repository. Specifying ``.`` is equivalent to specifying the active
4089 bookmark's name.
4089 bookmark's name.
4090
4090
4091 Please see :hg:`help urls` for important details about ``ssh://``
4091 Please see :hg:`help urls` for important details about ``ssh://``
4092 URLs. If DESTINATION is omitted, a default path will be used.
4092 URLs. If DESTINATION is omitted, a default path will be used.
4093
4093
4094 .. container:: verbose
4094 .. container:: verbose
4095
4095
4096 The --pushvars option sends strings to the server that become
4096 The --pushvars option sends strings to the server that become
4097 environment variables prepended with ``HG_USERVAR_``. For example,
4097 environment variables prepended with ``HG_USERVAR_``. For example,
4098 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4098 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4099 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4099 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4100
4100
4101 pushvars can provide for user-overridable hooks as well as set debug
4101 pushvars can provide for user-overridable hooks as well as set debug
4102 levels. One example is having a hook that blocks commits containing
4102 levels. One example is having a hook that blocks commits containing
4103 conflict markers, but enables the user to override the hook if the file
4103 conflict markers, but enables the user to override the hook if the file
4104 is using conflict markers for testing purposes or the file format has
4104 is using conflict markers for testing purposes or the file format has
4105 strings that look like conflict markers.
4105 strings that look like conflict markers.
4106
4106
4107 By default, servers will ignore `--pushvars`. To enable it add the
4107 By default, servers will ignore `--pushvars`. To enable it add the
4108 following to your configuration file::
4108 following to your configuration file::
4109
4109
4110 [push]
4110 [push]
4111 pushvars.server = true
4111 pushvars.server = true
4112
4112
4113 Returns 0 if push was successful, 1 if nothing to push.
4113 Returns 0 if push was successful, 1 if nothing to push.
4114 """
4114 """
4115
4115
4116 opts = pycompat.byteskwargs(opts)
4116 opts = pycompat.byteskwargs(opts)
4117 if opts.get('bookmark'):
4117 if opts.get('bookmark'):
4118 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4118 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4119 for b in opts['bookmark']:
4119 for b in opts['bookmark']:
4120 # translate -B options to -r so changesets get pushed
4120 # translate -B options to -r so changesets get pushed
4121 b = repo._bookmarks.expandname(b)
4121 b = repo._bookmarks.expandname(b)
4122 if b in repo._bookmarks:
4122 if b in repo._bookmarks:
4123 opts.setdefault('rev', []).append(b)
4123 opts.setdefault('rev', []).append(b)
4124 else:
4124 else:
4125 # if we try to push a deleted bookmark, translate it to null
4125 # if we try to push a deleted bookmark, translate it to null
4126 # this lets simultaneous -r, -b options continue working
4126 # this lets simultaneous -r, -b options continue working
4127 opts.setdefault('rev', []).append("null")
4127 opts.setdefault('rev', []).append("null")
4128
4128
4129 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4129 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4130 if not path:
4130 if not path:
4131 raise error.Abort(_('default repository not configured!'),
4131 raise error.Abort(_('default repository not configured!'),
4132 hint=_("see 'hg help config.paths'"))
4132 hint=_("see 'hg help config.paths'"))
4133 dest = path.pushloc or path.loc
4133 dest = path.pushloc or path.loc
4134 branches = (path.branch, opts.get('branch') or [])
4134 branches = (path.branch, opts.get('branch') or [])
4135 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4135 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4136 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4136 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4137 other = hg.peer(repo, opts, dest)
4137 other = hg.peer(repo, opts, dest)
4138
4138
4139 if revs:
4139 if revs:
4140 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4140 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4141 if not revs:
4141 if not revs:
4142 raise error.Abort(_("specified revisions evaluate to an empty set"),
4142 raise error.Abort(_("specified revisions evaluate to an empty set"),
4143 hint=_("use different revision arguments"))
4143 hint=_("use different revision arguments"))
4144 elif path.pushrev:
4144 elif path.pushrev:
4145 # It doesn't make any sense to specify ancestor revisions. So limit
4145 # It doesn't make any sense to specify ancestor revisions. So limit
4146 # to DAG heads to make discovery simpler.
4146 # to DAG heads to make discovery simpler.
4147 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4147 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4148 revs = scmutil.revrange(repo, [expr])
4148 revs = scmutil.revrange(repo, [expr])
4149 revs = [repo[rev].node() for rev in revs]
4149 revs = [repo[rev].node() for rev in revs]
4150 if not revs:
4150 if not revs:
4151 raise error.Abort(_('default push revset for path evaluates to an '
4151 raise error.Abort(_('default push revset for path evaluates to an '
4152 'empty set'))
4152 'empty set'))
4153
4153
4154 repo._subtoppath = dest
4154 repo._subtoppath = dest
4155 try:
4155 try:
4156 # push subrepos depth-first for coherent ordering
4156 # push subrepos depth-first for coherent ordering
4157 c = repo['']
4157 c = repo['']
4158 subs = c.substate # only repos that are committed
4158 subs = c.substate # only repos that are committed
4159 for s in sorted(subs):
4159 for s in sorted(subs):
4160 result = c.sub(s).push(opts)
4160 result = c.sub(s).push(opts)
4161 if result == 0:
4161 if result == 0:
4162 return not result
4162 return not result
4163 finally:
4163 finally:
4164 del repo._subtoppath
4164 del repo._subtoppath
4165
4165
4166 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4166 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4167 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4167 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4168
4168
4169 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4169 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4170 newbranch=opts.get('new_branch'),
4170 newbranch=opts.get('new_branch'),
4171 bookmarks=opts.get('bookmark', ()),
4171 bookmarks=opts.get('bookmark', ()),
4172 opargs=opargs)
4172 opargs=opargs)
4173
4173
4174 result = not pushop.cgresult
4174 result = not pushop.cgresult
4175
4175
4176 if pushop.bkresult is not None:
4176 if pushop.bkresult is not None:
4177 if pushop.bkresult == 2:
4177 if pushop.bkresult == 2:
4178 result = 2
4178 result = 2
4179 elif not result and pushop.bkresult:
4179 elif not result and pushop.bkresult:
4180 result = 2
4180 result = 2
4181
4181
4182 return result
4182 return result
4183
4183
4184 @command('recover', [])
4184 @command('recover', [])
4185 def recover(ui, repo):
4185 def recover(ui, repo):
4186 """roll back an interrupted transaction
4186 """roll back an interrupted transaction
4187
4187
4188 Recover from an interrupted commit or pull.
4188 Recover from an interrupted commit or pull.
4189
4189
4190 This command tries to fix the repository status after an
4190 This command tries to fix the repository status after an
4191 interrupted operation. It should only be necessary when Mercurial
4191 interrupted operation. It should only be necessary when Mercurial
4192 suggests it.
4192 suggests it.
4193
4193
4194 Returns 0 if successful, 1 if nothing to recover or verify fails.
4194 Returns 0 if successful, 1 if nothing to recover or verify fails.
4195 """
4195 """
4196 if repo.recover():
4196 if repo.recover():
4197 return hg.verify(repo)
4197 return hg.verify(repo)
4198 return 1
4198 return 1
4199
4199
4200 @command('^remove|rm',
4200 @command('^remove|rm',
4201 [('A', 'after', None, _('record delete for missing files')),
4201 [('A', 'after', None, _('record delete for missing files')),
4202 ('f', 'force', None,
4202 ('f', 'force', None,
4203 _('forget added files, delete modified files')),
4203 _('forget added files, delete modified files')),
4204 ] + subrepoopts + walkopts,
4204 ] + subrepoopts + walkopts,
4205 _('[OPTION]... FILE...'),
4205 _('[OPTION]... FILE...'),
4206 inferrepo=True)
4206 inferrepo=True)
4207 def remove(ui, repo, *pats, **opts):
4207 def remove(ui, repo, *pats, **opts):
4208 """remove the specified files on the next commit
4208 """remove the specified files on the next commit
4209
4209
4210 Schedule the indicated files for removal from the current branch.
4210 Schedule the indicated files for removal from the current branch.
4211
4211
4212 This command schedules the files to be removed at the next commit.
4212 This command schedules the files to be removed at the next commit.
4213 To undo a remove before that, see :hg:`revert`. To undo added
4213 To undo a remove before that, see :hg:`revert`. To undo added
4214 files, see :hg:`forget`.
4214 files, see :hg:`forget`.
4215
4215
4216 .. container:: verbose
4216 .. container:: verbose
4217
4217
4218 -A/--after can be used to remove only files that have already
4218 -A/--after can be used to remove only files that have already
4219 been deleted, -f/--force can be used to force deletion, and -Af
4219 been deleted, -f/--force can be used to force deletion, and -Af
4220 can be used to remove files from the next revision without
4220 can be used to remove files from the next revision without
4221 deleting them from the working directory.
4221 deleting them from the working directory.
4222
4222
4223 The following table details the behavior of remove for different
4223 The following table details the behavior of remove for different
4224 file states (columns) and option combinations (rows). The file
4224 file states (columns) and option combinations (rows). The file
4225 states are Added [A], Clean [C], Modified [M] and Missing [!]
4225 states are Added [A], Clean [C], Modified [M] and Missing [!]
4226 (as reported by :hg:`status`). The actions are Warn, Remove
4226 (as reported by :hg:`status`). The actions are Warn, Remove
4227 (from branch) and Delete (from disk):
4227 (from branch) and Delete (from disk):
4228
4228
4229 ========= == == == ==
4229 ========= == == == ==
4230 opt/state A C M !
4230 opt/state A C M !
4231 ========= == == == ==
4231 ========= == == == ==
4232 none W RD W R
4232 none W RD W R
4233 -f R RD RD R
4233 -f R RD RD R
4234 -A W W W R
4234 -A W W W R
4235 -Af R R R R
4235 -Af R R R R
4236 ========= == == == ==
4236 ========= == == == ==
4237
4237
4238 .. note::
4238 .. note::
4239
4239
4240 :hg:`remove` never deletes files in Added [A] state from the
4240 :hg:`remove` never deletes files in Added [A] state from the
4241 working directory, not even if ``--force`` is specified.
4241 working directory, not even if ``--force`` is specified.
4242
4242
4243 Returns 0 on success, 1 if any warnings encountered.
4243 Returns 0 on success, 1 if any warnings encountered.
4244 """
4244 """
4245
4245
4246 opts = pycompat.byteskwargs(opts)
4246 opts = pycompat.byteskwargs(opts)
4247 after, force = opts.get('after'), opts.get('force')
4247 after, force = opts.get('after'), opts.get('force')
4248 if not pats and not after:
4248 if not pats and not after:
4249 raise error.Abort(_('no files specified'))
4249 raise error.Abort(_('no files specified'))
4250
4250
4251 m = scmutil.match(repo[None], pats, opts)
4251 m = scmutil.match(repo[None], pats, opts)
4252 subrepos = opts.get('subrepos')
4252 subrepos = opts.get('subrepos')
4253 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4253 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4254
4254
4255 @command('rename|move|mv',
4255 @command('rename|move|mv',
4256 [('A', 'after', None, _('record a rename that has already occurred')),
4256 [('A', 'after', None, _('record a rename that has already occurred')),
4257 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4257 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4258 ] + walkopts + dryrunopts,
4258 ] + walkopts + dryrunopts,
4259 _('[OPTION]... SOURCE... DEST'))
4259 _('[OPTION]... SOURCE... DEST'))
4260 def rename(ui, repo, *pats, **opts):
4260 def rename(ui, repo, *pats, **opts):
4261 """rename files; equivalent of copy + remove
4261 """rename files; equivalent of copy + remove
4262
4262
4263 Mark dest as copies of sources; mark sources for deletion. If dest
4263 Mark dest as copies of sources; mark sources for deletion. If dest
4264 is a directory, copies are put in that directory. If dest is a
4264 is a directory, copies are put in that directory. If dest is a
4265 file, there can only be one source.
4265 file, there can only be one source.
4266
4266
4267 By default, this command copies the contents of files as they
4267 By default, this command copies the contents of files as they
4268 exist in the working directory. If invoked with -A/--after, the
4268 exist in the working directory. If invoked with -A/--after, the
4269 operation is recorded, but no copying is performed.
4269 operation is recorded, but no copying is performed.
4270
4270
4271 This command takes effect at the next commit. To undo a rename
4271 This command takes effect at the next commit. To undo a rename
4272 before that, see :hg:`revert`.
4272 before that, see :hg:`revert`.
4273
4273
4274 Returns 0 on success, 1 if errors are encountered.
4274 Returns 0 on success, 1 if errors are encountered.
4275 """
4275 """
4276 opts = pycompat.byteskwargs(opts)
4276 opts = pycompat.byteskwargs(opts)
4277 with repo.wlock(False):
4277 with repo.wlock(False):
4278 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4278 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4279
4279
4280 @command('resolve',
4280 @command('resolve',
4281 [('a', 'all', None, _('select all unresolved files')),
4281 [('a', 'all', None, _('select all unresolved files')),
4282 ('l', 'list', None, _('list state of files needing merge')),
4282 ('l', 'list', None, _('list state of files needing merge')),
4283 ('m', 'mark', None, _('mark files as resolved')),
4283 ('m', 'mark', None, _('mark files as resolved')),
4284 ('u', 'unmark', None, _('mark files as unresolved')),
4284 ('u', 'unmark', None, _('mark files as unresolved')),
4285 ('n', 'no-status', None, _('hide status prefix'))]
4285 ('n', 'no-status', None, _('hide status prefix'))]
4286 + mergetoolopts + walkopts + formatteropts,
4286 + mergetoolopts + walkopts + formatteropts,
4287 _('[OPTION]... [FILE]...'),
4287 _('[OPTION]... [FILE]...'),
4288 inferrepo=True)
4288 inferrepo=True)
4289 def resolve(ui, repo, *pats, **opts):
4289 def resolve(ui, repo, *pats, **opts):
4290 """redo merges or set/view the merge status of files
4290 """redo merges or set/view the merge status of files
4291
4291
4292 Merges with unresolved conflicts are often the result of
4292 Merges with unresolved conflicts are often the result of
4293 non-interactive merging using the ``internal:merge`` configuration
4293 non-interactive merging using the ``internal:merge`` configuration
4294 setting, or a command-line merge tool like ``diff3``. The resolve
4294 setting, or a command-line merge tool like ``diff3``. The resolve
4295 command is used to manage the files involved in a merge, after
4295 command is used to manage the files involved in a merge, after
4296 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4296 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4297 working directory must have two parents). See :hg:`help
4297 working directory must have two parents). See :hg:`help
4298 merge-tools` for information on configuring merge tools.
4298 merge-tools` for information on configuring merge tools.
4299
4299
4300 The resolve command can be used in the following ways:
4300 The resolve command can be used in the following ways:
4301
4301
4302 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4302 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4303 files, discarding any previous merge attempts. Re-merging is not
4303 files, discarding any previous merge attempts. Re-merging is not
4304 performed for files already marked as resolved. Use ``--all/-a``
4304 performed for files already marked as resolved. Use ``--all/-a``
4305 to select all unresolved files. ``--tool`` can be used to specify
4305 to select all unresolved files. ``--tool`` can be used to specify
4306 the merge tool used for the given files. It overrides the HGMERGE
4306 the merge tool used for the given files. It overrides the HGMERGE
4307 environment variable and your configuration files. Previous file
4307 environment variable and your configuration files. Previous file
4308 contents are saved with a ``.orig`` suffix.
4308 contents are saved with a ``.orig`` suffix.
4309
4309
4310 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4310 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4311 (e.g. after having manually fixed-up the files). The default is
4311 (e.g. after having manually fixed-up the files). The default is
4312 to mark all unresolved files.
4312 to mark all unresolved files.
4313
4313
4314 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4314 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4315 default is to mark all resolved files.
4315 default is to mark all resolved files.
4316
4316
4317 - :hg:`resolve -l`: list files which had or still have conflicts.
4317 - :hg:`resolve -l`: list files which had or still have conflicts.
4318 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4318 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4319 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4319 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4320 the list. See :hg:`help filesets` for details.
4320 the list. See :hg:`help filesets` for details.
4321
4321
4322 .. note::
4322 .. note::
4323
4323
4324 Mercurial will not let you commit files with unresolved merge
4324 Mercurial will not let you commit files with unresolved merge
4325 conflicts. You must use :hg:`resolve -m ...` before you can
4325 conflicts. You must use :hg:`resolve -m ...` before you can
4326 commit after a conflicting merge.
4326 commit after a conflicting merge.
4327
4327
4328 Returns 0 on success, 1 if any files fail a resolve attempt.
4328 Returns 0 on success, 1 if any files fail a resolve attempt.
4329 """
4329 """
4330
4330
4331 opts = pycompat.byteskwargs(opts)
4331 opts = pycompat.byteskwargs(opts)
4332 flaglist = 'all mark unmark list no_status'.split()
4332 flaglist = 'all mark unmark list no_status'.split()
4333 all, mark, unmark, show, nostatus = \
4333 all, mark, unmark, show, nostatus = \
4334 [opts.get(o) for o in flaglist]
4334 [opts.get(o) for o in flaglist]
4335
4335
4336 if (show and (mark or unmark)) or (mark and unmark):
4336 if (show and (mark or unmark)) or (mark and unmark):
4337 raise error.Abort(_("too many options specified"))
4337 raise error.Abort(_("too many options specified"))
4338 if pats and all:
4338 if pats and all:
4339 raise error.Abort(_("can't specify --all and patterns"))
4339 raise error.Abort(_("can't specify --all and patterns"))
4340 if not (all or pats or show or mark or unmark):
4340 if not (all or pats or show or mark or unmark):
4341 raise error.Abort(_('no files or directories specified'),
4341 raise error.Abort(_('no files or directories specified'),
4342 hint=('use --all to re-merge all unresolved files'))
4342 hint=('use --all to re-merge all unresolved files'))
4343
4343
4344 if show:
4344 if show:
4345 ui.pager('resolve')
4345 ui.pager('resolve')
4346 fm = ui.formatter('resolve', opts)
4346 fm = ui.formatter('resolve', opts)
4347 ms = mergemod.mergestate.read(repo)
4347 ms = mergemod.mergestate.read(repo)
4348 m = scmutil.match(repo[None], pats, opts)
4348 m = scmutil.match(repo[None], pats, opts)
4349
4349
4350 # Labels and keys based on merge state. Unresolved path conflicts show
4350 # Labels and keys based on merge state. Unresolved path conflicts show
4351 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4351 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4352 # resolved conflicts.
4352 # resolved conflicts.
4353 mergestateinfo = {
4353 mergestateinfo = {
4354 'u': ('resolve.unresolved', 'U'),
4354 'u': ('resolve.unresolved', 'U'),
4355 'r': ('resolve.resolved', 'R'),
4355 'r': ('resolve.resolved', 'R'),
4356 'pu': ('resolve.unresolved', 'P'),
4356 'pu': ('resolve.unresolved', 'P'),
4357 'pr': ('resolve.resolved', 'R'),
4357 'pr': ('resolve.resolved', 'R'),
4358 'd': ('resolve.driverresolved', 'D'),
4358 'd': ('resolve.driverresolved', 'D'),
4359 }
4359 }
4360
4360
4361 for f in ms:
4361 for f in ms:
4362 if not m(f):
4362 if not m(f):
4363 continue
4363 continue
4364
4364
4365 label, key = mergestateinfo[ms[f]]
4365 label, key = mergestateinfo[ms[f]]
4366 fm.startitem()
4366 fm.startitem()
4367 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4367 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4368 fm.write('path', '%s\n', f, label=label)
4368 fm.write('path', '%s\n', f, label=label)
4369 fm.end()
4369 fm.end()
4370 return 0
4370 return 0
4371
4371
4372 with repo.wlock():
4372 with repo.wlock():
4373 ms = mergemod.mergestate.read(repo)
4373 ms = mergemod.mergestate.read(repo)
4374
4374
4375 if not (ms.active() or repo.dirstate.p2() != nullid):
4375 if not (ms.active() or repo.dirstate.p2() != nullid):
4376 raise error.Abort(
4376 raise error.Abort(
4377 _('resolve command not applicable when not merging'))
4377 _('resolve command not applicable when not merging'))
4378
4378
4379 wctx = repo[None]
4379 wctx = repo[None]
4380
4380
4381 if ms.mergedriver and ms.mdstate() == 'u':
4381 if ms.mergedriver and ms.mdstate() == 'u':
4382 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4382 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4383 ms.commit()
4383 ms.commit()
4384 # allow mark and unmark to go through
4384 # allow mark and unmark to go through
4385 if not mark and not unmark and not proceed:
4385 if not mark and not unmark and not proceed:
4386 return 1
4386 return 1
4387
4387
4388 m = scmutil.match(wctx, pats, opts)
4388 m = scmutil.match(wctx, pats, opts)
4389 ret = 0
4389 ret = 0
4390 didwork = False
4390 didwork = False
4391 runconclude = False
4391 runconclude = False
4392
4392
4393 tocomplete = []
4393 tocomplete = []
4394 for f in ms:
4394 for f in ms:
4395 if not m(f):
4395 if not m(f):
4396 continue
4396 continue
4397
4397
4398 didwork = True
4398 didwork = True
4399
4399
4400 # don't let driver-resolved files be marked, and run the conclude
4400 # don't let driver-resolved files be marked, and run the conclude
4401 # step if asked to resolve
4401 # step if asked to resolve
4402 if ms[f] == "d":
4402 if ms[f] == "d":
4403 exact = m.exact(f)
4403 exact = m.exact(f)
4404 if mark:
4404 if mark:
4405 if exact:
4405 if exact:
4406 ui.warn(_('not marking %s as it is driver-resolved\n')
4406 ui.warn(_('not marking %s as it is driver-resolved\n')
4407 % f)
4407 % f)
4408 elif unmark:
4408 elif unmark:
4409 if exact:
4409 if exact:
4410 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4410 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4411 % f)
4411 % f)
4412 else:
4412 else:
4413 runconclude = True
4413 runconclude = True
4414 continue
4414 continue
4415
4415
4416 # path conflicts must be resolved manually
4416 # path conflicts must be resolved manually
4417 if ms[f] in ("pu", "pr"):
4417 if ms[f] in ("pu", "pr"):
4418 if mark:
4418 if mark:
4419 ms.mark(f, "pr")
4419 ms.mark(f, "pr")
4420 elif unmark:
4420 elif unmark:
4421 ms.mark(f, "pu")
4421 ms.mark(f, "pu")
4422 elif ms[f] == "pu":
4422 elif ms[f] == "pu":
4423 ui.warn(_('%s: path conflict must be resolved manually\n')
4423 ui.warn(_('%s: path conflict must be resolved manually\n')
4424 % f)
4424 % f)
4425 continue
4425 continue
4426
4426
4427 if mark:
4427 if mark:
4428 ms.mark(f, "r")
4428 ms.mark(f, "r")
4429 elif unmark:
4429 elif unmark:
4430 ms.mark(f, "u")
4430 ms.mark(f, "u")
4431 else:
4431 else:
4432 # backup pre-resolve (merge uses .orig for its own purposes)
4432 # backup pre-resolve (merge uses .orig for its own purposes)
4433 a = repo.wjoin(f)
4433 a = repo.wjoin(f)
4434 try:
4434 try:
4435 util.copyfile(a, a + ".resolve")
4435 util.copyfile(a, a + ".resolve")
4436 except (IOError, OSError) as inst:
4436 except (IOError, OSError) as inst:
4437 if inst.errno != errno.ENOENT:
4437 if inst.errno != errno.ENOENT:
4438 raise
4438 raise
4439
4439
4440 try:
4440 try:
4441 # preresolve file
4441 # preresolve file
4442 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4442 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4443 'resolve')
4443 'resolve')
4444 complete, r = ms.preresolve(f, wctx)
4444 complete, r = ms.preresolve(f, wctx)
4445 if not complete:
4445 if not complete:
4446 tocomplete.append(f)
4446 tocomplete.append(f)
4447 elif r:
4447 elif r:
4448 ret = 1
4448 ret = 1
4449 finally:
4449 finally:
4450 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4450 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4451 ms.commit()
4451 ms.commit()
4452
4452
4453 # replace filemerge's .orig file with our resolve file, but only
4453 # replace filemerge's .orig file with our resolve file, but only
4454 # for merges that are complete
4454 # for merges that are complete
4455 if complete:
4455 if complete:
4456 try:
4456 try:
4457 util.rename(a + ".resolve",
4457 util.rename(a + ".resolve",
4458 scmutil.origpath(ui, repo, a))
4458 scmutil.origpath(ui, repo, a))
4459 except OSError as inst:
4459 except OSError as inst:
4460 if inst.errno != errno.ENOENT:
4460 if inst.errno != errno.ENOENT:
4461 raise
4461 raise
4462
4462
4463 for f in tocomplete:
4463 for f in tocomplete:
4464 try:
4464 try:
4465 # resolve file
4465 # resolve file
4466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4467 'resolve')
4467 'resolve')
4468 r = ms.resolve(f, wctx)
4468 r = ms.resolve(f, wctx)
4469 if r:
4469 if r:
4470 ret = 1
4470 ret = 1
4471 finally:
4471 finally:
4472 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4472 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4473 ms.commit()
4473 ms.commit()
4474
4474
4475 # replace filemerge's .orig file with our resolve file
4475 # replace filemerge's .orig file with our resolve file
4476 a = repo.wjoin(f)
4476 a = repo.wjoin(f)
4477 try:
4477 try:
4478 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4478 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4479 except OSError as inst:
4479 except OSError as inst:
4480 if inst.errno != errno.ENOENT:
4480 if inst.errno != errno.ENOENT:
4481 raise
4481 raise
4482
4482
4483 ms.commit()
4483 ms.commit()
4484 ms.recordactions()
4484 ms.recordactions()
4485
4485
4486 if not didwork and pats:
4486 if not didwork and pats:
4487 hint = None
4487 hint = None
4488 if not any([p for p in pats if p.find(':') >= 0]):
4488 if not any([p for p in pats if p.find(':') >= 0]):
4489 pats = ['path:%s' % p for p in pats]
4489 pats = ['path:%s' % p for p in pats]
4490 m = scmutil.match(wctx, pats, opts)
4490 m = scmutil.match(wctx, pats, opts)
4491 for f in ms:
4491 for f in ms:
4492 if not m(f):
4492 if not m(f):
4493 continue
4493 continue
4494 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4494 flags = ''.join(['-%s ' % o[0:1] for o in flaglist
4495 if opts.get(o)])
4495 if opts.get(o)])
4496 hint = _("(try: hg resolve %s%s)\n") % (
4496 hint = _("(try: hg resolve %s%s)\n") % (
4497 flags,
4497 flags,
4498 ' '.join(pats))
4498 ' '.join(pats))
4499 break
4499 break
4500 ui.warn(_("arguments do not match paths that need resolving\n"))
4500 ui.warn(_("arguments do not match paths that need resolving\n"))
4501 if hint:
4501 if hint:
4502 ui.warn(hint)
4502 ui.warn(hint)
4503 elif ms.mergedriver and ms.mdstate() != 's':
4503 elif ms.mergedriver and ms.mdstate() != 's':
4504 # run conclude step when either a driver-resolved file is requested
4504 # run conclude step when either a driver-resolved file is requested
4505 # or there are no driver-resolved files
4505 # or there are no driver-resolved files
4506 # we can't use 'ret' to determine whether any files are unresolved
4506 # we can't use 'ret' to determine whether any files are unresolved
4507 # because we might not have tried to resolve some
4507 # because we might not have tried to resolve some
4508 if ((runconclude or not list(ms.driverresolved()))
4508 if ((runconclude or not list(ms.driverresolved()))
4509 and not list(ms.unresolved())):
4509 and not list(ms.unresolved())):
4510 proceed = mergemod.driverconclude(repo, ms, wctx)
4510 proceed = mergemod.driverconclude(repo, ms, wctx)
4511 ms.commit()
4511 ms.commit()
4512 if not proceed:
4512 if not proceed:
4513 return 1
4513 return 1
4514
4514
4515 # Nudge users into finishing an unfinished operation
4515 # Nudge users into finishing an unfinished operation
4516 unresolvedf = list(ms.unresolved())
4516 unresolvedf = list(ms.unresolved())
4517 driverresolvedf = list(ms.driverresolved())
4517 driverresolvedf = list(ms.driverresolved())
4518 if not unresolvedf and not driverresolvedf:
4518 if not unresolvedf and not driverresolvedf:
4519 ui.status(_('(no more unresolved files)\n'))
4519 ui.status(_('(no more unresolved files)\n'))
4520 cmdutil.checkafterresolved(repo)
4520 cmdutil.checkafterresolved(repo)
4521 elif not unresolvedf:
4521 elif not unresolvedf:
4522 ui.status(_('(no more unresolved files -- '
4522 ui.status(_('(no more unresolved files -- '
4523 'run "hg resolve --all" to conclude)\n'))
4523 'run "hg resolve --all" to conclude)\n'))
4524
4524
4525 return ret
4525 return ret
4526
4526
4527 @command('revert',
4527 @command('revert',
4528 [('a', 'all', None, _('revert all changes when no arguments given')),
4528 [('a', 'all', None, _('revert all changes when no arguments given')),
4529 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4529 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4530 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4530 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4531 ('C', 'no-backup', None, _('do not save backup copies of files')),
4531 ('C', 'no-backup', None, _('do not save backup copies of files')),
4532 ('i', 'interactive', None, _('interactively select the changes')),
4532 ('i', 'interactive', None, _('interactively select the changes')),
4533 ] + walkopts + dryrunopts,
4533 ] + walkopts + dryrunopts,
4534 _('[OPTION]... [-r REV] [NAME]...'))
4534 _('[OPTION]... [-r REV] [NAME]...'))
4535 def revert(ui, repo, *pats, **opts):
4535 def revert(ui, repo, *pats, **opts):
4536 """restore files to their checkout state
4536 """restore files to their checkout state
4537
4537
4538 .. note::
4538 .. note::
4539
4539
4540 To check out earlier revisions, you should use :hg:`update REV`.
4540 To check out earlier revisions, you should use :hg:`update REV`.
4541 To cancel an uncommitted merge (and lose your changes),
4541 To cancel an uncommitted merge (and lose your changes),
4542 use :hg:`merge --abort`.
4542 use :hg:`merge --abort`.
4543
4543
4544 With no revision specified, revert the specified files or directories
4544 With no revision specified, revert the specified files or directories
4545 to the contents they had in the parent of the working directory.
4545 to the contents they had in the parent of the working directory.
4546 This restores the contents of files to an unmodified
4546 This restores the contents of files to an unmodified
4547 state and unschedules adds, removes, copies, and renames. If the
4547 state and unschedules adds, removes, copies, and renames. If the
4548 working directory has two parents, you must explicitly specify a
4548 working directory has two parents, you must explicitly specify a
4549 revision.
4549 revision.
4550
4550
4551 Using the -r/--rev or -d/--date options, revert the given files or
4551 Using the -r/--rev or -d/--date options, revert the given files or
4552 directories to their states as of a specific revision. Because
4552 directories to their states as of a specific revision. Because
4553 revert does not change the working directory parents, this will
4553 revert does not change the working directory parents, this will
4554 cause these files to appear modified. This can be helpful to "back
4554 cause these files to appear modified. This can be helpful to "back
4555 out" some or all of an earlier change. See :hg:`backout` for a
4555 out" some or all of an earlier change. See :hg:`backout` for a
4556 related method.
4556 related method.
4557
4557
4558 Modified files are saved with a .orig suffix before reverting.
4558 Modified files are saved with a .orig suffix before reverting.
4559 To disable these backups, use --no-backup. It is possible to store
4559 To disable these backups, use --no-backup. It is possible to store
4560 the backup files in a custom directory relative to the root of the
4560 the backup files in a custom directory relative to the root of the
4561 repository by setting the ``ui.origbackuppath`` configuration
4561 repository by setting the ``ui.origbackuppath`` configuration
4562 option.
4562 option.
4563
4563
4564 See :hg:`help dates` for a list of formats valid for -d/--date.
4564 See :hg:`help dates` for a list of formats valid for -d/--date.
4565
4565
4566 See :hg:`help backout` for a way to reverse the effect of an
4566 See :hg:`help backout` for a way to reverse the effect of an
4567 earlier changeset.
4567 earlier changeset.
4568
4568
4569 Returns 0 on success.
4569 Returns 0 on success.
4570 """
4570 """
4571
4571
4572 opts = pycompat.byteskwargs(opts)
4572 opts = pycompat.byteskwargs(opts)
4573 if opts.get("date"):
4573 if opts.get("date"):
4574 if opts.get("rev"):
4574 if opts.get("rev"):
4575 raise error.Abort(_("you can't specify a revision and a date"))
4575 raise error.Abort(_("you can't specify a revision and a date"))
4576 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4576 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4577
4577
4578 parent, p2 = repo.dirstate.parents()
4578 parent, p2 = repo.dirstate.parents()
4579 if not opts.get('rev') and p2 != nullid:
4579 if not opts.get('rev') and p2 != nullid:
4580 # revert after merge is a trap for new users (issue2915)
4580 # revert after merge is a trap for new users (issue2915)
4581 raise error.Abort(_('uncommitted merge with no revision specified'),
4581 raise error.Abort(_('uncommitted merge with no revision specified'),
4582 hint=_("use 'hg update' or see 'hg help revert'"))
4582 hint=_("use 'hg update' or see 'hg help revert'"))
4583
4583
4584 rev = opts.get('rev')
4584 rev = opts.get('rev')
4585 if rev:
4585 if rev:
4586 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4586 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4587 ctx = scmutil.revsingle(repo, rev)
4587 ctx = scmutil.revsingle(repo, rev)
4588
4588
4589 if (not (pats or opts.get('include') or opts.get('exclude') or
4589 if (not (pats or opts.get('include') or opts.get('exclude') or
4590 opts.get('all') or opts.get('interactive'))):
4590 opts.get('all') or opts.get('interactive'))):
4591 msg = _("no files or directories specified")
4591 msg = _("no files or directories specified")
4592 if p2 != nullid:
4592 if p2 != nullid:
4593 hint = _("uncommitted merge, use --all to discard all changes,"
4593 hint = _("uncommitted merge, use --all to discard all changes,"
4594 " or 'hg update -C .' to abort the merge")
4594 " or 'hg update -C .' to abort the merge")
4595 raise error.Abort(msg, hint=hint)
4595 raise error.Abort(msg, hint=hint)
4596 dirty = any(repo.status())
4596 dirty = any(repo.status())
4597 node = ctx.node()
4597 node = ctx.node()
4598 if node != parent:
4598 if node != parent:
4599 if dirty:
4599 if dirty:
4600 hint = _("uncommitted changes, use --all to discard all"
4600 hint = _("uncommitted changes, use --all to discard all"
4601 " changes, or 'hg update %s' to update") % ctx.rev()
4601 " changes, or 'hg update %s' to update") % ctx.rev()
4602 else:
4602 else:
4603 hint = _("use --all to revert all files,"
4603 hint = _("use --all to revert all files,"
4604 " or 'hg update %s' to update") % ctx.rev()
4604 " or 'hg update %s' to update") % ctx.rev()
4605 elif dirty:
4605 elif dirty:
4606 hint = _("uncommitted changes, use --all to discard all changes")
4606 hint = _("uncommitted changes, use --all to discard all changes")
4607 else:
4607 else:
4608 hint = _("use --all to revert all files")
4608 hint = _("use --all to revert all files")
4609 raise error.Abort(msg, hint=hint)
4609 raise error.Abort(msg, hint=hint)
4610
4610
4611 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4611 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4612 **pycompat.strkwargs(opts))
4612 **pycompat.strkwargs(opts))
4613
4613
4614 @command('rollback', dryrunopts +
4614 @command('rollback', dryrunopts +
4615 [('f', 'force', False, _('ignore safety measures'))])
4615 [('f', 'force', False, _('ignore safety measures'))])
4616 def rollback(ui, repo, **opts):
4616 def rollback(ui, repo, **opts):
4617 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4617 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4618
4618
4619 Please use :hg:`commit --amend` instead of rollback to correct
4619 Please use :hg:`commit --amend` instead of rollback to correct
4620 mistakes in the last commit.
4620 mistakes in the last commit.
4621
4621
4622 This command should be used with care. There is only one level of
4622 This command should be used with care. There is only one level of
4623 rollback, and there is no way to undo a rollback. It will also
4623 rollback, and there is no way to undo a rollback. It will also
4624 restore the dirstate at the time of the last transaction, losing
4624 restore the dirstate at the time of the last transaction, losing
4625 any dirstate changes since that time. This command does not alter
4625 any dirstate changes since that time. This command does not alter
4626 the working directory.
4626 the working directory.
4627
4627
4628 Transactions are used to encapsulate the effects of all commands
4628 Transactions are used to encapsulate the effects of all commands
4629 that create new changesets or propagate existing changesets into a
4629 that create new changesets or propagate existing changesets into a
4630 repository.
4630 repository.
4631
4631
4632 .. container:: verbose
4632 .. container:: verbose
4633
4633
4634 For example, the following commands are transactional, and their
4634 For example, the following commands are transactional, and their
4635 effects can be rolled back:
4635 effects can be rolled back:
4636
4636
4637 - commit
4637 - commit
4638 - import
4638 - import
4639 - pull
4639 - pull
4640 - push (with this repository as the destination)
4640 - push (with this repository as the destination)
4641 - unbundle
4641 - unbundle
4642
4642
4643 To avoid permanent data loss, rollback will refuse to rollback a
4643 To avoid permanent data loss, rollback will refuse to rollback a
4644 commit transaction if it isn't checked out. Use --force to
4644 commit transaction if it isn't checked out. Use --force to
4645 override this protection.
4645 override this protection.
4646
4646
4647 The rollback command can be entirely disabled by setting the
4647 The rollback command can be entirely disabled by setting the
4648 ``ui.rollback`` configuration setting to false. If you're here
4648 ``ui.rollback`` configuration setting to false. If you're here
4649 because you want to use rollback and it's disabled, you can
4649 because you want to use rollback and it's disabled, you can
4650 re-enable the command by setting ``ui.rollback`` to true.
4650 re-enable the command by setting ``ui.rollback`` to true.
4651
4651
4652 This command is not intended for use on public repositories. Once
4652 This command is not intended for use on public repositories. Once
4653 changes are visible for pull by other users, rolling a transaction
4653 changes are visible for pull by other users, rolling a transaction
4654 back locally is ineffective (someone else may already have pulled
4654 back locally is ineffective (someone else may already have pulled
4655 the changes). Furthermore, a race is possible with readers of the
4655 the changes). Furthermore, a race is possible with readers of the
4656 repository; for example an in-progress pull from the repository
4656 repository; for example an in-progress pull from the repository
4657 may fail if a rollback is performed.
4657 may fail if a rollback is performed.
4658
4658
4659 Returns 0 on success, 1 if no rollback data is available.
4659 Returns 0 on success, 1 if no rollback data is available.
4660 """
4660 """
4661 if not ui.configbool('ui', 'rollback'):
4661 if not ui.configbool('ui', 'rollback'):
4662 raise error.Abort(_('rollback is disabled because it is unsafe'),
4662 raise error.Abort(_('rollback is disabled because it is unsafe'),
4663 hint=('see `hg help -v rollback` for information'))
4663 hint=('see `hg help -v rollback` for information'))
4664 return repo.rollback(dryrun=opts.get(r'dry_run'),
4664 return repo.rollback(dryrun=opts.get(r'dry_run'),
4665 force=opts.get(r'force'))
4665 force=opts.get(r'force'))
4666
4666
4667 @command('root', [], cmdtype=readonly)
4667 @command('root', [], cmdtype=readonly)
4668 def root(ui, repo):
4668 def root(ui, repo):
4669 """print the root (top) of the current working directory
4669 """print the root (top) of the current working directory
4670
4670
4671 Print the root directory of the current repository.
4671 Print the root directory of the current repository.
4672
4672
4673 Returns 0 on success.
4673 Returns 0 on success.
4674 """
4674 """
4675 ui.write(repo.root + "\n")
4675 ui.write(repo.root + "\n")
4676
4676
4677 @command('^serve',
4677 @command('^serve',
4678 [('A', 'accesslog', '', _('name of access log file to write to'),
4678 [('A', 'accesslog', '', _('name of access log file to write to'),
4679 _('FILE')),
4679 _('FILE')),
4680 ('d', 'daemon', None, _('run server in background')),
4680 ('d', 'daemon', None, _('run server in background')),
4681 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4681 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4682 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4682 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4683 # use string type, then we can check if something was passed
4683 # use string type, then we can check if something was passed
4684 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4684 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4685 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4685 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4686 _('ADDR')),
4686 _('ADDR')),
4687 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4687 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4688 _('PREFIX')),
4688 _('PREFIX')),
4689 ('n', 'name', '',
4689 ('n', 'name', '',
4690 _('name to show in web pages (default: working directory)'), _('NAME')),
4690 _('name to show in web pages (default: working directory)'), _('NAME')),
4691 ('', 'web-conf', '',
4691 ('', 'web-conf', '',
4692 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4692 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4693 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4693 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4694 _('FILE')),
4694 _('FILE')),
4695 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4695 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4696 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4696 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4697 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4697 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4698 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4698 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4699 ('', 'style', '', _('template style to use'), _('STYLE')),
4699 ('', 'style', '', _('template style to use'), _('STYLE')),
4700 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4700 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4701 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4701 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4702 + subrepoopts,
4702 + subrepoopts,
4703 _('[OPTION]...'),
4703 _('[OPTION]...'),
4704 optionalrepo=True)
4704 optionalrepo=True)
4705 def serve(ui, repo, **opts):
4705 def serve(ui, repo, **opts):
4706 """start stand-alone webserver
4706 """start stand-alone webserver
4707
4707
4708 Start a local HTTP repository browser and pull server. You can use
4708 Start a local HTTP repository browser and pull server. You can use
4709 this for ad-hoc sharing and browsing of repositories. It is
4709 this for ad-hoc sharing and browsing of repositories. It is
4710 recommended to use a real web server to serve a repository for
4710 recommended to use a real web server to serve a repository for
4711 longer periods of time.
4711 longer periods of time.
4712
4712
4713 Please note that the server does not implement access control.
4713 Please note that the server does not implement access control.
4714 This means that, by default, anybody can read from the server and
4714 This means that, by default, anybody can read from the server and
4715 nobody can write to it by default. Set the ``web.allow-push``
4715 nobody can write to it by default. Set the ``web.allow-push``
4716 option to ``*`` to allow everybody to push to the server. You
4716 option to ``*`` to allow everybody to push to the server. You
4717 should use a real web server if you need to authenticate users.
4717 should use a real web server if you need to authenticate users.
4718
4718
4719 By default, the server logs accesses to stdout and errors to
4719 By default, the server logs accesses to stdout and errors to
4720 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4720 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4721 files.
4721 files.
4722
4722
4723 To have the server choose a free port number to listen on, specify
4723 To have the server choose a free port number to listen on, specify
4724 a port number of 0; in this case, the server will print the port
4724 a port number of 0; in this case, the server will print the port
4725 number it uses.
4725 number it uses.
4726
4726
4727 Returns 0 on success.
4727 Returns 0 on success.
4728 """
4728 """
4729
4729
4730 opts = pycompat.byteskwargs(opts)
4730 opts = pycompat.byteskwargs(opts)
4731 if opts["stdio"] and opts["cmdserver"]:
4731 if opts["stdio"] and opts["cmdserver"]:
4732 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4732 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4733
4733
4734 if opts["stdio"]:
4734 if opts["stdio"]:
4735 if repo is None:
4735 if repo is None:
4736 raise error.RepoError(_("there is no Mercurial repository here"
4736 raise error.RepoError(_("there is no Mercurial repository here"
4737 " (.hg not found)"))
4737 " (.hg not found)"))
4738 s = wireprotoserver.sshserver(ui, repo)
4738 s = wireprotoserver.sshserver(ui, repo)
4739 s.serve_forever()
4739 s.serve_forever()
4740
4740
4741 service = server.createservice(ui, repo, opts)
4741 service = server.createservice(ui, repo, opts)
4742 return server.runservice(opts, initfn=service.init, runfn=service.run)
4742 return server.runservice(opts, initfn=service.init, runfn=service.run)
4743
4743
4744 @command('^status|st',
4744 @command('^status|st',
4745 [('A', 'all', None, _('show status of all files')),
4745 [('A', 'all', None, _('show status of all files')),
4746 ('m', 'modified', None, _('show only modified files')),
4746 ('m', 'modified', None, _('show only modified files')),
4747 ('a', 'added', None, _('show only added files')),
4747 ('a', 'added', None, _('show only added files')),
4748 ('r', 'removed', None, _('show only removed files')),
4748 ('r', 'removed', None, _('show only removed files')),
4749 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4749 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4750 ('c', 'clean', None, _('show only files without changes')),
4750 ('c', 'clean', None, _('show only files without changes')),
4751 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4751 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4752 ('i', 'ignored', None, _('show only ignored files')),
4752 ('i', 'ignored', None, _('show only ignored files')),
4753 ('n', 'no-status', None, _('hide status prefix')),
4753 ('n', 'no-status', None, _('hide status prefix')),
4754 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4754 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4755 ('C', 'copies', None, _('show source of copied files')),
4755 ('C', 'copies', None, _('show source of copied files')),
4756 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4756 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4757 ('', 'rev', [], _('show difference from revision'), _('REV')),
4757 ('', 'rev', [], _('show difference from revision'), _('REV')),
4758 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4758 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4759 ] + walkopts + subrepoopts + formatteropts,
4759 ] + walkopts + subrepoopts + formatteropts,
4760 _('[OPTION]... [FILE]...'),
4760 _('[OPTION]... [FILE]...'),
4761 inferrepo=True, cmdtype=readonly)
4761 inferrepo=True, cmdtype=readonly)
4762 def status(ui, repo, *pats, **opts):
4762 def status(ui, repo, *pats, **opts):
4763 """show changed files in the working directory
4763 """show changed files in the working directory
4764
4764
4765 Show status of files in the repository. If names are given, only
4765 Show status of files in the repository. If names are given, only
4766 files that match are shown. Files that are clean or ignored or
4766 files that match are shown. Files that are clean or ignored or
4767 the source of a copy/move operation, are not listed unless
4767 the source of a copy/move operation, are not listed unless
4768 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4768 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4769 Unless options described with "show only ..." are given, the
4769 Unless options described with "show only ..." are given, the
4770 options -mardu are used.
4770 options -mardu are used.
4771
4771
4772 Option -q/--quiet hides untracked (unknown and ignored) files
4772 Option -q/--quiet hides untracked (unknown and ignored) files
4773 unless explicitly requested with -u/--unknown or -i/--ignored.
4773 unless explicitly requested with -u/--unknown or -i/--ignored.
4774
4774
4775 .. note::
4775 .. note::
4776
4776
4777 :hg:`status` may appear to disagree with diff if permissions have
4777 :hg:`status` may appear to disagree with diff if permissions have
4778 changed or a merge has occurred. The standard diff format does
4778 changed or a merge has occurred. The standard diff format does
4779 not report permission changes and diff only reports changes
4779 not report permission changes and diff only reports changes
4780 relative to one merge parent.
4780 relative to one merge parent.
4781
4781
4782 If one revision is given, it is used as the base revision.
4782 If one revision is given, it is used as the base revision.
4783 If two revisions are given, the differences between them are
4783 If two revisions are given, the differences between them are
4784 shown. The --change option can also be used as a shortcut to list
4784 shown. The --change option can also be used as a shortcut to list
4785 the changed files of a revision from its first parent.
4785 the changed files of a revision from its first parent.
4786
4786
4787 The codes used to show the status of files are::
4787 The codes used to show the status of files are::
4788
4788
4789 M = modified
4789 M = modified
4790 A = added
4790 A = added
4791 R = removed
4791 R = removed
4792 C = clean
4792 C = clean
4793 ! = missing (deleted by non-hg command, but still tracked)
4793 ! = missing (deleted by non-hg command, but still tracked)
4794 ? = not tracked
4794 ? = not tracked
4795 I = ignored
4795 I = ignored
4796 = origin of the previous file (with --copies)
4796 = origin of the previous file (with --copies)
4797
4797
4798 .. container:: verbose
4798 .. container:: verbose
4799
4799
4800 The -t/--terse option abbreviates the output by showing only the directory
4800 The -t/--terse option abbreviates the output by showing only the directory
4801 name if all the files in it share the same status. The option takes an
4801 name if all the files in it share the same status. The option takes an
4802 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4802 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4803 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4803 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4804 for 'ignored' and 'c' for clean.
4804 for 'ignored' and 'c' for clean.
4805
4805
4806 It abbreviates only those statuses which are passed. Note that clean and
4806 It abbreviates only those statuses which are passed. Note that clean and
4807 ignored files are not displayed with '--terse ic' unless the -c/--clean
4807 ignored files are not displayed with '--terse ic' unless the -c/--clean
4808 and -i/--ignored options are also used.
4808 and -i/--ignored options are also used.
4809
4809
4810 The -v/--verbose option shows information when the repository is in an
4810 The -v/--verbose option shows information when the repository is in an
4811 unfinished merge, shelve, rebase state etc. You can have this behavior
4811 unfinished merge, shelve, rebase state etc. You can have this behavior
4812 turned on by default by enabling the ``commands.status.verbose`` option.
4812 turned on by default by enabling the ``commands.status.verbose`` option.
4813
4813
4814 You can skip displaying some of these states by setting
4814 You can skip displaying some of these states by setting
4815 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4815 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4816 'histedit', 'merge', 'rebase', or 'unshelve'.
4816 'histedit', 'merge', 'rebase', or 'unshelve'.
4817
4817
4818 Examples:
4818 Examples:
4819
4819
4820 - show changes in the working directory relative to a
4820 - show changes in the working directory relative to a
4821 changeset::
4821 changeset::
4822
4822
4823 hg status --rev 9353
4823 hg status --rev 9353
4824
4824
4825 - show changes in the working directory relative to the
4825 - show changes in the working directory relative to the
4826 current directory (see :hg:`help patterns` for more information)::
4826 current directory (see :hg:`help patterns` for more information)::
4827
4827
4828 hg status re:
4828 hg status re:
4829
4829
4830 - show all changes including copies in an existing changeset::
4830 - show all changes including copies in an existing changeset::
4831
4831
4832 hg status --copies --change 9353
4832 hg status --copies --change 9353
4833
4833
4834 - get a NUL separated list of added files, suitable for xargs::
4834 - get a NUL separated list of added files, suitable for xargs::
4835
4835
4836 hg status -an0
4836 hg status -an0
4837
4837
4838 - show more information about the repository status, abbreviating
4838 - show more information about the repository status, abbreviating
4839 added, removed, modified, deleted, and untracked paths::
4839 added, removed, modified, deleted, and untracked paths::
4840
4840
4841 hg status -v -t mardu
4841 hg status -v -t mardu
4842
4842
4843 Returns 0 on success.
4843 Returns 0 on success.
4844
4844
4845 """
4845 """
4846
4846
4847 opts = pycompat.byteskwargs(opts)
4847 opts = pycompat.byteskwargs(opts)
4848 revs = opts.get('rev')
4848 revs = opts.get('rev')
4849 change = opts.get('change')
4849 change = opts.get('change')
4850 terse = opts.get('terse')
4850 terse = opts.get('terse')
4851
4851
4852 if revs and change:
4852 if revs and change:
4853 msg = _('cannot specify --rev and --change at the same time')
4853 msg = _('cannot specify --rev and --change at the same time')
4854 raise error.Abort(msg)
4854 raise error.Abort(msg)
4855 elif revs and terse:
4855 elif revs and terse:
4856 msg = _('cannot use --terse with --rev')
4856 msg = _('cannot use --terse with --rev')
4857 raise error.Abort(msg)
4857 raise error.Abort(msg)
4858 elif change:
4858 elif change:
4859 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4859 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4860 node2 = scmutil.revsingle(repo, change, None).node()
4860 node2 = scmutil.revsingle(repo, change, None).node()
4861 node1 = repo[node2].p1().node()
4861 node1 = repo[node2].p1().node()
4862 else:
4862 else:
4863 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4863 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4864 node1, node2 = scmutil.revpair(repo, revs)
4864 node1, node2 = scmutil.revpair(repo, revs)
4865
4865
4866 if pats or ui.configbool('commands', 'status.relative'):
4866 if pats or ui.configbool('commands', 'status.relative'):
4867 cwd = repo.getcwd()
4867 cwd = repo.getcwd()
4868 else:
4868 else:
4869 cwd = ''
4869 cwd = ''
4870
4870
4871 if opts.get('print0'):
4871 if opts.get('print0'):
4872 end = '\0'
4872 end = '\0'
4873 else:
4873 else:
4874 end = '\n'
4874 end = '\n'
4875 copy = {}
4875 copy = {}
4876 states = 'modified added removed deleted unknown ignored clean'.split()
4876 states = 'modified added removed deleted unknown ignored clean'.split()
4877 show = [k for k in states if opts.get(k)]
4877 show = [k for k in states if opts.get(k)]
4878 if opts.get('all'):
4878 if opts.get('all'):
4879 show += ui.quiet and (states[:4] + ['clean']) or states
4879 show += ui.quiet and (states[:4] + ['clean']) or states
4880
4880
4881 if not show:
4881 if not show:
4882 if ui.quiet:
4882 if ui.quiet:
4883 show = states[:4]
4883 show = states[:4]
4884 else:
4884 else:
4885 show = states[:5]
4885 show = states[:5]
4886
4886
4887 m = scmutil.match(repo[node2], pats, opts)
4887 m = scmutil.match(repo[node2], pats, opts)
4888 if terse:
4888 if terse:
4889 # we need to compute clean and unknown to terse
4889 # we need to compute clean and unknown to terse
4890 stat = repo.status(node1, node2, m,
4890 stat = repo.status(node1, node2, m,
4891 'ignored' in show or 'i' in terse,
4891 'ignored' in show or 'i' in terse,
4892 True, True, opts.get('subrepos'))
4892 True, True, opts.get('subrepos'))
4893
4893
4894 stat = cmdutil.tersedir(stat, terse)
4894 stat = cmdutil.tersedir(stat, terse)
4895 else:
4895 else:
4896 stat = repo.status(node1, node2, m,
4896 stat = repo.status(node1, node2, m,
4897 'ignored' in show, 'clean' in show,
4897 'ignored' in show, 'clean' in show,
4898 'unknown' in show, opts.get('subrepos'))
4898 'unknown' in show, opts.get('subrepos'))
4899
4899
4900 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4900 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4901
4901
4902 if (opts.get('all') or opts.get('copies')
4902 if (opts.get('all') or opts.get('copies')
4903 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4903 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4904 copy = copies.pathcopies(repo[node1], repo[node2], m)
4904 copy = copies.pathcopies(repo[node1], repo[node2], m)
4905
4905
4906 ui.pager('status')
4906 ui.pager('status')
4907 fm = ui.formatter('status', opts)
4907 fm = ui.formatter('status', opts)
4908 fmt = '%s' + end
4908 fmt = '%s' + end
4909 showchar = not opts.get('no_status')
4909 showchar = not opts.get('no_status')
4910
4910
4911 for state, char, files in changestates:
4911 for state, char, files in changestates:
4912 if state in show:
4912 if state in show:
4913 label = 'status.' + state
4913 label = 'status.' + state
4914 for f in files:
4914 for f in files:
4915 fm.startitem()
4915 fm.startitem()
4916 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4916 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4917 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4917 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4918 if f in copy:
4918 if f in copy:
4919 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4919 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4920 label='status.copied')
4920 label='status.copied')
4921
4921
4922 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4922 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4923 and not ui.plain()):
4923 and not ui.plain()):
4924 cmdutil.morestatus(repo, fm)
4924 cmdutil.morestatus(repo, fm)
4925 fm.end()
4925 fm.end()
4926
4926
4927 @command('^summary|sum',
4927 @command('^summary|sum',
4928 [('', 'remote', None, _('check for push and pull'))],
4928 [('', 'remote', None, _('check for push and pull'))],
4929 '[--remote]', cmdtype=readonly)
4929 '[--remote]', cmdtype=readonly)
4930 def summary(ui, repo, **opts):
4930 def summary(ui, repo, **opts):
4931 """summarize working directory state
4931 """summarize working directory state
4932
4932
4933 This generates a brief summary of the working directory state,
4933 This generates a brief summary of the working directory state,
4934 including parents, branch, commit status, phase and available updates.
4934 including parents, branch, commit status, phase and available updates.
4935
4935
4936 With the --remote option, this will check the default paths for
4936 With the --remote option, this will check the default paths for
4937 incoming and outgoing changes. This can be time-consuming.
4937 incoming and outgoing changes. This can be time-consuming.
4938
4938
4939 Returns 0 on success.
4939 Returns 0 on success.
4940 """
4940 """
4941
4941
4942 opts = pycompat.byteskwargs(opts)
4942 opts = pycompat.byteskwargs(opts)
4943 ui.pager('summary')
4943 ui.pager('summary')
4944 ctx = repo[None]
4944 ctx = repo[None]
4945 parents = ctx.parents()
4945 parents = ctx.parents()
4946 pnode = parents[0].node()
4946 pnode = parents[0].node()
4947 marks = []
4947 marks = []
4948
4948
4949 ms = None
4949 ms = None
4950 try:
4950 try:
4951 ms = mergemod.mergestate.read(repo)
4951 ms = mergemod.mergestate.read(repo)
4952 except error.UnsupportedMergeRecords as e:
4952 except error.UnsupportedMergeRecords as e:
4953 s = ' '.join(e.recordtypes)
4953 s = ' '.join(e.recordtypes)
4954 ui.warn(
4954 ui.warn(
4955 _('warning: merge state has unsupported record types: %s\n') % s)
4955 _('warning: merge state has unsupported record types: %s\n') % s)
4956 unresolved = []
4956 unresolved = []
4957 else:
4957 else:
4958 unresolved = list(ms.unresolved())
4958 unresolved = list(ms.unresolved())
4959
4959
4960 for p in parents:
4960 for p in parents:
4961 # label with log.changeset (instead of log.parent) since this
4961 # label with log.changeset (instead of log.parent) since this
4962 # shows a working directory parent *changeset*:
4962 # shows a working directory parent *changeset*:
4963 # i18n: column positioning for "hg summary"
4963 # i18n: column positioning for "hg summary"
4964 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4964 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4965 label=logcmdutil.changesetlabels(p))
4965 label=logcmdutil.changesetlabels(p))
4966 ui.write(' '.join(p.tags()), label='log.tag')
4966 ui.write(' '.join(p.tags()), label='log.tag')
4967 if p.bookmarks():
4967 if p.bookmarks():
4968 marks.extend(p.bookmarks())
4968 marks.extend(p.bookmarks())
4969 if p.rev() == -1:
4969 if p.rev() == -1:
4970 if not len(repo):
4970 if not len(repo):
4971 ui.write(_(' (empty repository)'))
4971 ui.write(_(' (empty repository)'))
4972 else:
4972 else:
4973 ui.write(_(' (no revision checked out)'))
4973 ui.write(_(' (no revision checked out)'))
4974 if p.obsolete():
4974 if p.obsolete():
4975 ui.write(_(' (obsolete)'))
4975 ui.write(_(' (obsolete)'))
4976 if p.isunstable():
4976 if p.isunstable():
4977 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4977 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4978 for instability in p.instabilities())
4978 for instability in p.instabilities())
4979 ui.write(' ('
4979 ui.write(' ('
4980 + ', '.join(instabilities)
4980 + ', '.join(instabilities)
4981 + ')')
4981 + ')')
4982 ui.write('\n')
4982 ui.write('\n')
4983 if p.description():
4983 if p.description():
4984 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4984 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4985 label='log.summary')
4985 label='log.summary')
4986
4986
4987 branch = ctx.branch()
4987 branch = ctx.branch()
4988 bheads = repo.branchheads(branch)
4988 bheads = repo.branchheads(branch)
4989 # i18n: column positioning for "hg summary"
4989 # i18n: column positioning for "hg summary"
4990 m = _('branch: %s\n') % branch
4990 m = _('branch: %s\n') % branch
4991 if branch != 'default':
4991 if branch != 'default':
4992 ui.write(m, label='log.branch')
4992 ui.write(m, label='log.branch')
4993 else:
4993 else:
4994 ui.status(m, label='log.branch')
4994 ui.status(m, label='log.branch')
4995
4995
4996 if marks:
4996 if marks:
4997 active = repo._activebookmark
4997 active = repo._activebookmark
4998 # i18n: column positioning for "hg summary"
4998 # i18n: column positioning for "hg summary"
4999 ui.write(_('bookmarks:'), label='log.bookmark')
4999 ui.write(_('bookmarks:'), label='log.bookmark')
5000 if active is not None:
5000 if active is not None:
5001 if active in marks:
5001 if active in marks:
5002 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5002 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5003 marks.remove(active)
5003 marks.remove(active)
5004 else:
5004 else:
5005 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5005 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5006 for m in marks:
5006 for m in marks:
5007 ui.write(' ' + m, label='log.bookmark')
5007 ui.write(' ' + m, label='log.bookmark')
5008 ui.write('\n', label='log.bookmark')
5008 ui.write('\n', label='log.bookmark')
5009
5009
5010 status = repo.status(unknown=True)
5010 status = repo.status(unknown=True)
5011
5011
5012 c = repo.dirstate.copies()
5012 c = repo.dirstate.copies()
5013 copied, renamed = [], []
5013 copied, renamed = [], []
5014 for d, s in c.iteritems():
5014 for d, s in c.iteritems():
5015 if s in status.removed:
5015 if s in status.removed:
5016 status.removed.remove(s)
5016 status.removed.remove(s)
5017 renamed.append(d)
5017 renamed.append(d)
5018 else:
5018 else:
5019 copied.append(d)
5019 copied.append(d)
5020 if d in status.added:
5020 if d in status.added:
5021 status.added.remove(d)
5021 status.added.remove(d)
5022
5022
5023 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5023 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5024
5024
5025 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5025 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5026 (ui.label(_('%d added'), 'status.added'), status.added),
5026 (ui.label(_('%d added'), 'status.added'), status.added),
5027 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5027 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5028 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5028 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5029 (ui.label(_('%d copied'), 'status.copied'), copied),
5029 (ui.label(_('%d copied'), 'status.copied'), copied),
5030 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5030 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5031 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5031 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5032 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5032 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5033 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5033 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5034 t = []
5034 t = []
5035 for l, s in labels:
5035 for l, s in labels:
5036 if s:
5036 if s:
5037 t.append(l % len(s))
5037 t.append(l % len(s))
5038
5038
5039 t = ', '.join(t)
5039 t = ', '.join(t)
5040 cleanworkdir = False
5040 cleanworkdir = False
5041
5041
5042 if repo.vfs.exists('graftstate'):
5042 if repo.vfs.exists('graftstate'):
5043 t += _(' (graft in progress)')
5043 t += _(' (graft in progress)')
5044 if repo.vfs.exists('updatestate'):
5044 if repo.vfs.exists('updatestate'):
5045 t += _(' (interrupted update)')
5045 t += _(' (interrupted update)')
5046 elif len(parents) > 1:
5046 elif len(parents) > 1:
5047 t += _(' (merge)')
5047 t += _(' (merge)')
5048 elif branch != parents[0].branch():
5048 elif branch != parents[0].branch():
5049 t += _(' (new branch)')
5049 t += _(' (new branch)')
5050 elif (parents[0].closesbranch() and
5050 elif (parents[0].closesbranch() and
5051 pnode in repo.branchheads(branch, closed=True)):
5051 pnode in repo.branchheads(branch, closed=True)):
5052 t += _(' (head closed)')
5052 t += _(' (head closed)')
5053 elif not (status.modified or status.added or status.removed or renamed or
5053 elif not (status.modified or status.added or status.removed or renamed or
5054 copied or subs):
5054 copied or subs):
5055 t += _(' (clean)')
5055 t += _(' (clean)')
5056 cleanworkdir = True
5056 cleanworkdir = True
5057 elif pnode not in bheads:
5057 elif pnode not in bheads:
5058 t += _(' (new branch head)')
5058 t += _(' (new branch head)')
5059
5059
5060 if parents:
5060 if parents:
5061 pendingphase = max(p.phase() for p in parents)
5061 pendingphase = max(p.phase() for p in parents)
5062 else:
5062 else:
5063 pendingphase = phases.public
5063 pendingphase = phases.public
5064
5064
5065 if pendingphase > phases.newcommitphase(ui):
5065 if pendingphase > phases.newcommitphase(ui):
5066 t += ' (%s)' % phases.phasenames[pendingphase]
5066 t += ' (%s)' % phases.phasenames[pendingphase]
5067
5067
5068 if cleanworkdir:
5068 if cleanworkdir:
5069 # i18n: column positioning for "hg summary"
5069 # i18n: column positioning for "hg summary"
5070 ui.status(_('commit: %s\n') % t.strip())
5070 ui.status(_('commit: %s\n') % t.strip())
5071 else:
5071 else:
5072 # i18n: column positioning for "hg summary"
5072 # i18n: column positioning for "hg summary"
5073 ui.write(_('commit: %s\n') % t.strip())
5073 ui.write(_('commit: %s\n') % t.strip())
5074
5074
5075 # all ancestors of branch heads - all ancestors of parent = new csets
5075 # all ancestors of branch heads - all ancestors of parent = new csets
5076 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5076 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5077 bheads))
5077 bheads))
5078
5078
5079 if new == 0:
5079 if new == 0:
5080 # i18n: column positioning for "hg summary"
5080 # i18n: column positioning for "hg summary"
5081 ui.status(_('update: (current)\n'))
5081 ui.status(_('update: (current)\n'))
5082 elif pnode not in bheads:
5082 elif pnode not in bheads:
5083 # i18n: column positioning for "hg summary"
5083 # i18n: column positioning for "hg summary"
5084 ui.write(_('update: %d new changesets (update)\n') % new)
5084 ui.write(_('update: %d new changesets (update)\n') % new)
5085 else:
5085 else:
5086 # i18n: column positioning for "hg summary"
5086 # i18n: column positioning for "hg summary"
5087 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5087 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5088 (new, len(bheads)))
5088 (new, len(bheads)))
5089
5089
5090 t = []
5090 t = []
5091 draft = len(repo.revs('draft()'))
5091 draft = len(repo.revs('draft()'))
5092 if draft:
5092 if draft:
5093 t.append(_('%d draft') % draft)
5093 t.append(_('%d draft') % draft)
5094 secret = len(repo.revs('secret()'))
5094 secret = len(repo.revs('secret()'))
5095 if secret:
5095 if secret:
5096 t.append(_('%d secret') % secret)
5096 t.append(_('%d secret') % secret)
5097
5097
5098 if draft or secret:
5098 if draft or secret:
5099 ui.status(_('phases: %s\n') % ', '.join(t))
5099 ui.status(_('phases: %s\n') % ', '.join(t))
5100
5100
5101 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5101 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5102 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5102 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5103 numtrouble = len(repo.revs(trouble + "()"))
5103 numtrouble = len(repo.revs(trouble + "()"))
5104 # We write all the possibilities to ease translation
5104 # We write all the possibilities to ease translation
5105 troublemsg = {
5105 troublemsg = {
5106 "orphan": _("orphan: %d changesets"),
5106 "orphan": _("orphan: %d changesets"),
5107 "contentdivergent": _("content-divergent: %d changesets"),
5107 "contentdivergent": _("content-divergent: %d changesets"),
5108 "phasedivergent": _("phase-divergent: %d changesets"),
5108 "phasedivergent": _("phase-divergent: %d changesets"),
5109 }
5109 }
5110 if numtrouble > 0:
5110 if numtrouble > 0:
5111 ui.status(troublemsg[trouble] % numtrouble + "\n")
5111 ui.status(troublemsg[trouble] % numtrouble + "\n")
5112
5112
5113 cmdutil.summaryhooks(ui, repo)
5113 cmdutil.summaryhooks(ui, repo)
5114
5114
5115 if opts.get('remote'):
5115 if opts.get('remote'):
5116 needsincoming, needsoutgoing = True, True
5116 needsincoming, needsoutgoing = True, True
5117 else:
5117 else:
5118 needsincoming, needsoutgoing = False, False
5118 needsincoming, needsoutgoing = False, False
5119 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5119 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5120 if i:
5120 if i:
5121 needsincoming = True
5121 needsincoming = True
5122 if o:
5122 if o:
5123 needsoutgoing = True
5123 needsoutgoing = True
5124 if not needsincoming and not needsoutgoing:
5124 if not needsincoming and not needsoutgoing:
5125 return
5125 return
5126
5126
5127 def getincoming():
5127 def getincoming():
5128 source, branches = hg.parseurl(ui.expandpath('default'))
5128 source, branches = hg.parseurl(ui.expandpath('default'))
5129 sbranch = branches[0]
5129 sbranch = branches[0]
5130 try:
5130 try:
5131 other = hg.peer(repo, {}, source)
5131 other = hg.peer(repo, {}, source)
5132 except error.RepoError:
5132 except error.RepoError:
5133 if opts.get('remote'):
5133 if opts.get('remote'):
5134 raise
5134 raise
5135 return source, sbranch, None, None, None
5135 return source, sbranch, None, None, None
5136 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5136 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5137 if revs:
5137 if revs:
5138 revs = [other.lookup(rev) for rev in revs]
5138 revs = [other.lookup(rev) for rev in revs]
5139 ui.debug('comparing with %s\n' % util.hidepassword(source))
5139 ui.debug('comparing with %s\n' % util.hidepassword(source))
5140 repo.ui.pushbuffer()
5140 repo.ui.pushbuffer()
5141 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5141 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5142 repo.ui.popbuffer()
5142 repo.ui.popbuffer()
5143 return source, sbranch, other, commoninc, commoninc[1]
5143 return source, sbranch, other, commoninc, commoninc[1]
5144
5144
5145 if needsincoming:
5145 if needsincoming:
5146 source, sbranch, sother, commoninc, incoming = getincoming()
5146 source, sbranch, sother, commoninc, incoming = getincoming()
5147 else:
5147 else:
5148 source = sbranch = sother = commoninc = incoming = None
5148 source = sbranch = sother = commoninc = incoming = None
5149
5149
5150 def getoutgoing():
5150 def getoutgoing():
5151 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5151 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5152 dbranch = branches[0]
5152 dbranch = branches[0]
5153 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5153 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5154 if source != dest:
5154 if source != dest:
5155 try:
5155 try:
5156 dother = hg.peer(repo, {}, dest)
5156 dother = hg.peer(repo, {}, dest)
5157 except error.RepoError:
5157 except error.RepoError:
5158 if opts.get('remote'):
5158 if opts.get('remote'):
5159 raise
5159 raise
5160 return dest, dbranch, None, None
5160 return dest, dbranch, None, None
5161 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5161 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5162 elif sother is None:
5162 elif sother is None:
5163 # there is no explicit destination peer, but source one is invalid
5163 # there is no explicit destination peer, but source one is invalid
5164 return dest, dbranch, None, None
5164 return dest, dbranch, None, None
5165 else:
5165 else:
5166 dother = sother
5166 dother = sother
5167 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5167 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5168 common = None
5168 common = None
5169 else:
5169 else:
5170 common = commoninc
5170 common = commoninc
5171 if revs:
5171 if revs:
5172 revs = [repo.lookup(rev) for rev in revs]
5172 revs = [repo.lookup(rev) for rev in revs]
5173 repo.ui.pushbuffer()
5173 repo.ui.pushbuffer()
5174 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5174 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5175 commoninc=common)
5175 commoninc=common)
5176 repo.ui.popbuffer()
5176 repo.ui.popbuffer()
5177 return dest, dbranch, dother, outgoing
5177 return dest, dbranch, dother, outgoing
5178
5178
5179 if needsoutgoing:
5179 if needsoutgoing:
5180 dest, dbranch, dother, outgoing = getoutgoing()
5180 dest, dbranch, dother, outgoing = getoutgoing()
5181 else:
5181 else:
5182 dest = dbranch = dother = outgoing = None
5182 dest = dbranch = dother = outgoing = None
5183
5183
5184 if opts.get('remote'):
5184 if opts.get('remote'):
5185 t = []
5185 t = []
5186 if incoming:
5186 if incoming:
5187 t.append(_('1 or more incoming'))
5187 t.append(_('1 or more incoming'))
5188 o = outgoing.missing
5188 o = outgoing.missing
5189 if o:
5189 if o:
5190 t.append(_('%d outgoing') % len(o))
5190 t.append(_('%d outgoing') % len(o))
5191 other = dother or sother
5191 other = dother or sother
5192 if 'bookmarks' in other.listkeys('namespaces'):
5192 if 'bookmarks' in other.listkeys('namespaces'):
5193 counts = bookmarks.summary(repo, other)
5193 counts = bookmarks.summary(repo, other)
5194 if counts[0] > 0:
5194 if counts[0] > 0:
5195 t.append(_('%d incoming bookmarks') % counts[0])
5195 t.append(_('%d incoming bookmarks') % counts[0])
5196 if counts[1] > 0:
5196 if counts[1] > 0:
5197 t.append(_('%d outgoing bookmarks') % counts[1])
5197 t.append(_('%d outgoing bookmarks') % counts[1])
5198
5198
5199 if t:
5199 if t:
5200 # i18n: column positioning for "hg summary"
5200 # i18n: column positioning for "hg summary"
5201 ui.write(_('remote: %s\n') % (', '.join(t)))
5201 ui.write(_('remote: %s\n') % (', '.join(t)))
5202 else:
5202 else:
5203 # i18n: column positioning for "hg summary"
5203 # i18n: column positioning for "hg summary"
5204 ui.status(_('remote: (synced)\n'))
5204 ui.status(_('remote: (synced)\n'))
5205
5205
5206 cmdutil.summaryremotehooks(ui, repo, opts,
5206 cmdutil.summaryremotehooks(ui, repo, opts,
5207 ((source, sbranch, sother, commoninc),
5207 ((source, sbranch, sother, commoninc),
5208 (dest, dbranch, dother, outgoing)))
5208 (dest, dbranch, dother, outgoing)))
5209
5209
5210 @command('tag',
5210 @command('tag',
5211 [('f', 'force', None, _('force tag')),
5211 [('f', 'force', None, _('force tag')),
5212 ('l', 'local', None, _('make the tag local')),
5212 ('l', 'local', None, _('make the tag local')),
5213 ('r', 'rev', '', _('revision to tag'), _('REV')),
5213 ('r', 'rev', '', _('revision to tag'), _('REV')),
5214 ('', 'remove', None, _('remove a tag')),
5214 ('', 'remove', None, _('remove a tag')),
5215 # -l/--local is already there, commitopts cannot be used
5215 # -l/--local is already there, commitopts cannot be used
5216 ('e', 'edit', None, _('invoke editor on commit messages')),
5216 ('e', 'edit', None, _('invoke editor on commit messages')),
5217 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5217 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5218 ] + commitopts2,
5218 ] + commitopts2,
5219 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5219 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5220 def tag(ui, repo, name1, *names, **opts):
5220 def tag(ui, repo, name1, *names, **opts):
5221 """add one or more tags for the current or given revision
5221 """add one or more tags for the current or given revision
5222
5222
5223 Name a particular revision using <name>.
5223 Name a particular revision using <name>.
5224
5224
5225 Tags are used to name particular revisions of the repository and are
5225 Tags are used to name particular revisions of the repository and are
5226 very useful to compare different revisions, to go back to significant
5226 very useful to compare different revisions, to go back to significant
5227 earlier versions or to mark branch points as releases, etc. Changing
5227 earlier versions or to mark branch points as releases, etc. Changing
5228 an existing tag is normally disallowed; use -f/--force to override.
5228 an existing tag is normally disallowed; use -f/--force to override.
5229
5229
5230 If no revision is given, the parent of the working directory is
5230 If no revision is given, the parent of the working directory is
5231 used.
5231 used.
5232
5232
5233 To facilitate version control, distribution, and merging of tags,
5233 To facilitate version control, distribution, and merging of tags,
5234 they are stored as a file named ".hgtags" which is managed similarly
5234 they are stored as a file named ".hgtags" which is managed similarly
5235 to other project files and can be hand-edited if necessary. This
5235 to other project files and can be hand-edited if necessary. This
5236 also means that tagging creates a new commit. The file
5236 also means that tagging creates a new commit. The file
5237 ".hg/localtags" is used for local tags (not shared among
5237 ".hg/localtags" is used for local tags (not shared among
5238 repositories).
5238 repositories).
5239
5239
5240 Tag commits are usually made at the head of a branch. If the parent
5240 Tag commits are usually made at the head of a branch. If the parent
5241 of the working directory is not a branch head, :hg:`tag` aborts; use
5241 of the working directory is not a branch head, :hg:`tag` aborts; use
5242 -f/--force to force the tag commit to be based on a non-head
5242 -f/--force to force the tag commit to be based on a non-head
5243 changeset.
5243 changeset.
5244
5244
5245 See :hg:`help dates` for a list of formats valid for -d/--date.
5245 See :hg:`help dates` for a list of formats valid for -d/--date.
5246
5246
5247 Since tag names have priority over branch names during revision
5247 Since tag names have priority over branch names during revision
5248 lookup, using an existing branch name as a tag name is discouraged.
5248 lookup, using an existing branch name as a tag name is discouraged.
5249
5249
5250 Returns 0 on success.
5250 Returns 0 on success.
5251 """
5251 """
5252 opts = pycompat.byteskwargs(opts)
5252 opts = pycompat.byteskwargs(opts)
5253 wlock = lock = None
5253 wlock = lock = None
5254 try:
5254 try:
5255 wlock = repo.wlock()
5255 wlock = repo.wlock()
5256 lock = repo.lock()
5256 lock = repo.lock()
5257 rev_ = "."
5257 rev_ = "."
5258 names = [t.strip() for t in (name1,) + names]
5258 names = [t.strip() for t in (name1,) + names]
5259 if len(names) != len(set(names)):
5259 if len(names) != len(set(names)):
5260 raise error.Abort(_('tag names must be unique'))
5260 raise error.Abort(_('tag names must be unique'))
5261 for n in names:
5261 for n in names:
5262 scmutil.checknewlabel(repo, n, 'tag')
5262 scmutil.checknewlabel(repo, n, 'tag')
5263 if not n:
5263 if not n:
5264 raise error.Abort(_('tag names cannot consist entirely of '
5264 raise error.Abort(_('tag names cannot consist entirely of '
5265 'whitespace'))
5265 'whitespace'))
5266 if opts.get('rev') and opts.get('remove'):
5266 if opts.get('rev') and opts.get('remove'):
5267 raise error.Abort(_("--rev and --remove are incompatible"))
5267 raise error.Abort(_("--rev and --remove are incompatible"))
5268 if opts.get('rev'):
5268 if opts.get('rev'):
5269 rev_ = opts['rev']
5269 rev_ = opts['rev']
5270 message = opts.get('message')
5270 message = opts.get('message')
5271 if opts.get('remove'):
5271 if opts.get('remove'):
5272 if opts.get('local'):
5272 if opts.get('local'):
5273 expectedtype = 'local'
5273 expectedtype = 'local'
5274 else:
5274 else:
5275 expectedtype = 'global'
5275 expectedtype = 'global'
5276
5276
5277 for n in names:
5277 for n in names:
5278 if not repo.tagtype(n):
5278 if not repo.tagtype(n):
5279 raise error.Abort(_("tag '%s' does not exist") % n)
5279 raise error.Abort(_("tag '%s' does not exist") % n)
5280 if repo.tagtype(n) != expectedtype:
5280 if repo.tagtype(n) != expectedtype:
5281 if expectedtype == 'global':
5281 if expectedtype == 'global':
5282 raise error.Abort(_("tag '%s' is not a global tag") % n)
5282 raise error.Abort(_("tag '%s' is not a global tag") % n)
5283 else:
5283 else:
5284 raise error.Abort(_("tag '%s' is not a local tag") % n)
5284 raise error.Abort(_("tag '%s' is not a local tag") % n)
5285 rev_ = 'null'
5285 rev_ = 'null'
5286 if not message:
5286 if not message:
5287 # we don't translate commit messages
5287 # we don't translate commit messages
5288 message = 'Removed tag %s' % ', '.join(names)
5288 message = 'Removed tag %s' % ', '.join(names)
5289 elif not opts.get('force'):
5289 elif not opts.get('force'):
5290 for n in names:
5290 for n in names:
5291 if n in repo.tags():
5291 if n in repo.tags():
5292 raise error.Abort(_("tag '%s' already exists "
5292 raise error.Abort(_("tag '%s' already exists "
5293 "(use -f to force)") % n)
5293 "(use -f to force)") % n)
5294 if not opts.get('local'):
5294 if not opts.get('local'):
5295 p1, p2 = repo.dirstate.parents()
5295 p1, p2 = repo.dirstate.parents()
5296 if p2 != nullid:
5296 if p2 != nullid:
5297 raise error.Abort(_('uncommitted merge'))
5297 raise error.Abort(_('uncommitted merge'))
5298 bheads = repo.branchheads()
5298 bheads = repo.branchheads()
5299 if not opts.get('force') and bheads and p1 not in bheads:
5299 if not opts.get('force') and bheads and p1 not in bheads:
5300 raise error.Abort(_('working directory is not at a branch head '
5300 raise error.Abort(_('working directory is not at a branch head '
5301 '(use -f to force)'))
5301 '(use -f to force)'))
5302 r = scmutil.revsingle(repo, rev_).node()
5302 r = scmutil.revsingle(repo, rev_).node()
5303
5303
5304 if not message:
5304 if not message:
5305 # we don't translate commit messages
5305 # we don't translate commit messages
5306 message = ('Added tag %s for changeset %s' %
5306 message = ('Added tag %s for changeset %s' %
5307 (', '.join(names), short(r)))
5307 (', '.join(names), short(r)))
5308
5308
5309 date = opts.get('date')
5309 date = opts.get('date')
5310 if date:
5310 if date:
5311 date = dateutil.parsedate(date)
5311 date = dateutil.parsedate(date)
5312
5312
5313 if opts.get('remove'):
5313 if opts.get('remove'):
5314 editform = 'tag.remove'
5314 editform = 'tag.remove'
5315 else:
5315 else:
5316 editform = 'tag.add'
5316 editform = 'tag.add'
5317 editor = cmdutil.getcommiteditor(editform=editform,
5317 editor = cmdutil.getcommiteditor(editform=editform,
5318 **pycompat.strkwargs(opts))
5318 **pycompat.strkwargs(opts))
5319
5319
5320 # don't allow tagging the null rev
5320 # don't allow tagging the null rev
5321 if (not opts.get('remove') and
5321 if (not opts.get('remove') and
5322 scmutil.revsingle(repo, rev_).rev() == nullrev):
5322 scmutil.revsingle(repo, rev_).rev() == nullrev):
5323 raise error.Abort(_("cannot tag null revision"))
5323 raise error.Abort(_("cannot tag null revision"))
5324
5324
5325 tagsmod.tag(repo, names, r, message, opts.get('local'),
5325 tagsmod.tag(repo, names, r, message, opts.get('local'),
5326 opts.get('user'), date, editor=editor)
5326 opts.get('user'), date, editor=editor)
5327 finally:
5327 finally:
5328 release(lock, wlock)
5328 release(lock, wlock)
5329
5329
5330 @command('tags', formatteropts, '', cmdtype=readonly)
5330 @command('tags', formatteropts, '', cmdtype=readonly)
5331 def tags(ui, repo, **opts):
5331 def tags(ui, repo, **opts):
5332 """list repository tags
5332 """list repository tags
5333
5333
5334 This lists both regular and local tags. When the -v/--verbose
5334 This lists both regular and local tags. When the -v/--verbose
5335 switch is used, a third column "local" is printed for local tags.
5335 switch is used, a third column "local" is printed for local tags.
5336 When the -q/--quiet switch is used, only the tag name is printed.
5336 When the -q/--quiet switch is used, only the tag name is printed.
5337
5337
5338 Returns 0 on success.
5338 Returns 0 on success.
5339 """
5339 """
5340
5340
5341 opts = pycompat.byteskwargs(opts)
5341 opts = pycompat.byteskwargs(opts)
5342 ui.pager('tags')
5342 ui.pager('tags')
5343 fm = ui.formatter('tags', opts)
5343 fm = ui.formatter('tags', opts)
5344 hexfunc = fm.hexfunc
5344 hexfunc = fm.hexfunc
5345 tagtype = ""
5345 tagtype = ""
5346
5346
5347 for t, n in reversed(repo.tagslist()):
5347 for t, n in reversed(repo.tagslist()):
5348 hn = hexfunc(n)
5348 hn = hexfunc(n)
5349 label = 'tags.normal'
5349 label = 'tags.normal'
5350 tagtype = ''
5350 tagtype = ''
5351 if repo.tagtype(t) == 'local':
5351 if repo.tagtype(t) == 'local':
5352 label = 'tags.local'
5352 label = 'tags.local'
5353 tagtype = 'local'
5353 tagtype = 'local'
5354
5354
5355 fm.startitem()
5355 fm.startitem()
5356 fm.write('tag', '%s', t, label=label)
5356 fm.write('tag', '%s', t, label=label)
5357 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5357 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5358 fm.condwrite(not ui.quiet, 'rev node', fmt,
5358 fm.condwrite(not ui.quiet, 'rev node', fmt,
5359 repo.changelog.rev(n), hn, label=label)
5359 repo.changelog.rev(n), hn, label=label)
5360 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5360 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5361 tagtype, label=label)
5361 tagtype, label=label)
5362 fm.plain('\n')
5362 fm.plain('\n')
5363 fm.end()
5363 fm.end()
5364
5364
5365 @command('tip',
5365 @command('tip',
5366 [('p', 'patch', None, _('show patch')),
5366 [('p', 'patch', None, _('show patch')),
5367 ('g', 'git', None, _('use git extended diff format')),
5367 ('g', 'git', None, _('use git extended diff format')),
5368 ] + templateopts,
5368 ] + templateopts,
5369 _('[-p] [-g]'))
5369 _('[-p] [-g]'))
5370 def tip(ui, repo, **opts):
5370 def tip(ui, repo, **opts):
5371 """show the tip revision (DEPRECATED)
5371 """show the tip revision (DEPRECATED)
5372
5372
5373 The tip revision (usually just called the tip) is the changeset
5373 The tip revision (usually just called the tip) is the changeset
5374 most recently added to the repository (and therefore the most
5374 most recently added to the repository (and therefore the most
5375 recently changed head).
5375 recently changed head).
5376
5376
5377 If you have just made a commit, that commit will be the tip. If
5377 If you have just made a commit, that commit will be the tip. If
5378 you have just pulled changes from another repository, the tip of
5378 you have just pulled changes from another repository, the tip of
5379 that repository becomes the current tip. The "tip" tag is special
5379 that repository becomes the current tip. The "tip" tag is special
5380 and cannot be renamed or assigned to a different changeset.
5380 and cannot be renamed or assigned to a different changeset.
5381
5381
5382 This command is deprecated, please use :hg:`heads` instead.
5382 This command is deprecated, please use :hg:`heads` instead.
5383
5383
5384 Returns 0 on success.
5384 Returns 0 on success.
5385 """
5385 """
5386 opts = pycompat.byteskwargs(opts)
5386 opts = pycompat.byteskwargs(opts)
5387 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5387 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5388 displayer.show(repo['tip'])
5388 displayer.show(repo['tip'])
5389 displayer.close()
5389 displayer.close()
5390
5390
5391 @command('unbundle',
5391 @command('unbundle',
5392 [('u', 'update', None,
5392 [('u', 'update', None,
5393 _('update to new branch head if changesets were unbundled'))],
5393 _('update to new branch head if changesets were unbundled'))],
5394 _('[-u] FILE...'))
5394 _('[-u] FILE...'))
5395 def unbundle(ui, repo, fname1, *fnames, **opts):
5395 def unbundle(ui, repo, fname1, *fnames, **opts):
5396 """apply one or more bundle files
5396 """apply one or more bundle files
5397
5397
5398 Apply one or more bundle files generated by :hg:`bundle`.
5398 Apply one or more bundle files generated by :hg:`bundle`.
5399
5399
5400 Returns 0 on success, 1 if an update has unresolved files.
5400 Returns 0 on success, 1 if an update has unresolved files.
5401 """
5401 """
5402 fnames = (fname1,) + fnames
5402 fnames = (fname1,) + fnames
5403
5403
5404 with repo.lock():
5404 with repo.lock():
5405 for fname in fnames:
5405 for fname in fnames:
5406 f = hg.openpath(ui, fname)
5406 f = hg.openpath(ui, fname)
5407 gen = exchange.readbundle(ui, f, fname)
5407 gen = exchange.readbundle(ui, f, fname)
5408 if isinstance(gen, streamclone.streamcloneapplier):
5408 if isinstance(gen, streamclone.streamcloneapplier):
5409 raise error.Abort(
5409 raise error.Abort(
5410 _('packed bundles cannot be applied with '
5410 _('packed bundles cannot be applied with '
5411 '"hg unbundle"'),
5411 '"hg unbundle"'),
5412 hint=_('use "hg debugapplystreamclonebundle"'))
5412 hint=_('use "hg debugapplystreamclonebundle"'))
5413 url = 'bundle:' + fname
5413 url = 'bundle:' + fname
5414 try:
5414 try:
5415 txnname = 'unbundle'
5415 txnname = 'unbundle'
5416 if not isinstance(gen, bundle2.unbundle20):
5416 if not isinstance(gen, bundle2.unbundle20):
5417 txnname = 'unbundle\n%s' % util.hidepassword(url)
5417 txnname = 'unbundle\n%s' % util.hidepassword(url)
5418 with repo.transaction(txnname) as tr:
5418 with repo.transaction(txnname) as tr:
5419 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5419 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5420 url=url)
5420 url=url)
5421 except error.BundleUnknownFeatureError as exc:
5421 except error.BundleUnknownFeatureError as exc:
5422 raise error.Abort(
5422 raise error.Abort(
5423 _('%s: unknown bundle feature, %s') % (fname, exc),
5423 _('%s: unknown bundle feature, %s') % (fname, exc),
5424 hint=_("see https://mercurial-scm.org/"
5424 hint=_("see https://mercurial-scm.org/"
5425 "wiki/BundleFeature for more "
5425 "wiki/BundleFeature for more "
5426 "information"))
5426 "information"))
5427 modheads = bundle2.combinechangegroupresults(op)
5427 modheads = bundle2.combinechangegroupresults(op)
5428
5428
5429 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5429 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5430
5430
5431 @command('^update|up|checkout|co',
5431 @command('^update|up|checkout|co',
5432 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5432 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5433 ('c', 'check', None, _('require clean working directory')),
5433 ('c', 'check', None, _('require clean working directory')),
5434 ('m', 'merge', None, _('merge uncommitted changes')),
5434 ('m', 'merge', None, _('merge uncommitted changes')),
5435 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5435 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5436 ('r', 'rev', '', _('revision'), _('REV'))
5436 ('r', 'rev', '', _('revision'), _('REV'))
5437 ] + mergetoolopts,
5437 ] + mergetoolopts,
5438 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5438 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5439 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5439 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5440 merge=None, tool=None):
5440 merge=None, tool=None):
5441 """update working directory (or switch revisions)
5441 """update working directory (or switch revisions)
5442
5442
5443 Update the repository's working directory to the specified
5443 Update the repository's working directory to the specified
5444 changeset. If no changeset is specified, update to the tip of the
5444 changeset. If no changeset is specified, update to the tip of the
5445 current named branch and move the active bookmark (see :hg:`help
5445 current named branch and move the active bookmark (see :hg:`help
5446 bookmarks`).
5446 bookmarks`).
5447
5447
5448 Update sets the working directory's parent revision to the specified
5448 Update sets the working directory's parent revision to the specified
5449 changeset (see :hg:`help parents`).
5449 changeset (see :hg:`help parents`).
5450
5450
5451 If the changeset is not a descendant or ancestor of the working
5451 If the changeset is not a descendant or ancestor of the working
5452 directory's parent and there are uncommitted changes, the update is
5452 directory's parent and there are uncommitted changes, the update is
5453 aborted. With the -c/--check option, the working directory is checked
5453 aborted. With the -c/--check option, the working directory is checked
5454 for uncommitted changes; if none are found, the working directory is
5454 for uncommitted changes; if none are found, the working directory is
5455 updated to the specified changeset.
5455 updated to the specified changeset.
5456
5456
5457 .. container:: verbose
5457 .. container:: verbose
5458
5458
5459 The -C/--clean, -c/--check, and -m/--merge options control what
5459 The -C/--clean, -c/--check, and -m/--merge options control what
5460 happens if the working directory contains uncommitted changes.
5460 happens if the working directory contains uncommitted changes.
5461 At most of one of them can be specified.
5461 At most of one of them can be specified.
5462
5462
5463 1. If no option is specified, and if
5463 1. If no option is specified, and if
5464 the requested changeset is an ancestor or descendant of
5464 the requested changeset is an ancestor or descendant of
5465 the working directory's parent, the uncommitted changes
5465 the working directory's parent, the uncommitted changes
5466 are merged into the requested changeset and the merged
5466 are merged into the requested changeset and the merged
5467 result is left uncommitted. If the requested changeset is
5467 result is left uncommitted. If the requested changeset is
5468 not an ancestor or descendant (that is, it is on another
5468 not an ancestor or descendant (that is, it is on another
5469 branch), the update is aborted and the uncommitted changes
5469 branch), the update is aborted and the uncommitted changes
5470 are preserved.
5470 are preserved.
5471
5471
5472 2. With the -m/--merge option, the update is allowed even if the
5472 2. With the -m/--merge option, the update is allowed even if the
5473 requested changeset is not an ancestor or descendant of
5473 requested changeset is not an ancestor or descendant of
5474 the working directory's parent.
5474 the working directory's parent.
5475
5475
5476 3. With the -c/--check option, the update is aborted and the
5476 3. With the -c/--check option, the update is aborted and the
5477 uncommitted changes are preserved.
5477 uncommitted changes are preserved.
5478
5478
5479 4. With the -C/--clean option, uncommitted changes are discarded and
5479 4. With the -C/--clean option, uncommitted changes are discarded and
5480 the working directory is updated to the requested changeset.
5480 the working directory is updated to the requested changeset.
5481
5481
5482 To cancel an uncommitted merge (and lose your changes), use
5482 To cancel an uncommitted merge (and lose your changes), use
5483 :hg:`merge --abort`.
5483 :hg:`merge --abort`.
5484
5484
5485 Use null as the changeset to remove the working directory (like
5485 Use null as the changeset to remove the working directory (like
5486 :hg:`clone -U`).
5486 :hg:`clone -U`).
5487
5487
5488 If you want to revert just one file to an older revision, use
5488 If you want to revert just one file to an older revision, use
5489 :hg:`revert [-r REV] NAME`.
5489 :hg:`revert [-r REV] NAME`.
5490
5490
5491 See :hg:`help dates` for a list of formats valid for -d/--date.
5491 See :hg:`help dates` for a list of formats valid for -d/--date.
5492
5492
5493 Returns 0 on success, 1 if there are unresolved files.
5493 Returns 0 on success, 1 if there are unresolved files.
5494 """
5494 """
5495 if rev and node:
5495 if rev and node:
5496 raise error.Abort(_("please specify just one revision"))
5496 raise error.Abort(_("please specify just one revision"))
5497
5497
5498 if ui.configbool('commands', 'update.requiredest'):
5498 if ui.configbool('commands', 'update.requiredest'):
5499 if not node and not rev and not date:
5499 if not node and not rev and not date:
5500 raise error.Abort(_('you must specify a destination'),
5500 raise error.Abort(_('you must specify a destination'),
5501 hint=_('for example: hg update ".::"'))
5501 hint=_('for example: hg update ".::"'))
5502
5502
5503 if rev is None or rev == '':
5503 if rev is None or rev == '':
5504 rev = node
5504 rev = node
5505
5505
5506 if date and rev is not None:
5506 if date and rev is not None:
5507 raise error.Abort(_("you can't specify a revision and a date"))
5507 raise error.Abort(_("you can't specify a revision and a date"))
5508
5508
5509 if len([x for x in (clean, check, merge) if x]) > 1:
5509 if len([x for x in (clean, check, merge) if x]) > 1:
5510 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5510 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5511 "or -m/--merge"))
5511 "or -m/--merge"))
5512
5512
5513 updatecheck = None
5513 updatecheck = None
5514 if check:
5514 if check:
5515 updatecheck = 'abort'
5515 updatecheck = 'abort'
5516 elif merge:
5516 elif merge:
5517 updatecheck = 'none'
5517 updatecheck = 'none'
5518
5518
5519 with repo.wlock():
5519 with repo.wlock():
5520 cmdutil.clearunfinished(repo)
5520 cmdutil.clearunfinished(repo)
5521
5521
5522 if date:
5522 if date:
5523 rev = cmdutil.finddate(ui, repo, date)
5523 rev = cmdutil.finddate(ui, repo, date)
5524
5524
5525 # if we defined a bookmark, we have to remember the original name
5525 # if we defined a bookmark, we have to remember the original name
5526 brev = rev
5526 brev = rev
5527 if rev:
5527 if rev:
5528 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5528 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5529 ctx = scmutil.revsingle(repo, rev, rev)
5529 ctx = scmutil.revsingle(repo, rev, rev)
5530 rev = ctx.rev()
5530 rev = ctx.rev()
5531 if ctx.hidden():
5531 if ctx.hidden():
5532 ctxstr = ctx.hex()[:12]
5532 ctxstr = ctx.hex()[:12]
5533 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5533 ui.warn(_("updating to a hidden changeset %s\n") % ctxstr)
5534
5534
5535 if ctx.obsolete():
5535 if ctx.obsolete():
5536 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5536 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5537 ui.warn("(%s)\n" % obsfatemsg)
5537 ui.warn("(%s)\n" % obsfatemsg)
5538
5538
5539 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5539 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5540
5540
5541 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5541 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5542 updatecheck=updatecheck)
5542 updatecheck=updatecheck)
5543
5543
5544 @command('verify', [])
5544 @command('verify', [])
5545 def verify(ui, repo):
5545 def verify(ui, repo):
5546 """verify the integrity of the repository
5546 """verify the integrity of the repository
5547
5547
5548 Verify the integrity of the current repository.
5548 Verify the integrity of the current repository.
5549
5549
5550 This will perform an extensive check of the repository's
5550 This will perform an extensive check of the repository's
5551 integrity, validating the hashes and checksums of each entry in
5551 integrity, validating the hashes and checksums of each entry in
5552 the changelog, manifest, and tracked files, as well as the
5552 the changelog, manifest, and tracked files, as well as the
5553 integrity of their crosslinks and indices.
5553 integrity of their crosslinks and indices.
5554
5554
5555 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5555 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5556 for more information about recovery from corruption of the
5556 for more information about recovery from corruption of the
5557 repository.
5557 repository.
5558
5558
5559 Returns 0 on success, 1 if errors are encountered.
5559 Returns 0 on success, 1 if errors are encountered.
5560 """
5560 """
5561 return hg.verify(repo)
5561 return hg.verify(repo)
5562
5562
5563 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5563 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5564 def version_(ui, **opts):
5564 def version_(ui, **opts):
5565 """output version and copyright information"""
5565 """output version and copyright information"""
5566 opts = pycompat.byteskwargs(opts)
5566 opts = pycompat.byteskwargs(opts)
5567 if ui.verbose:
5567 if ui.verbose:
5568 ui.pager('version')
5568 ui.pager('version')
5569 fm = ui.formatter("version", opts)
5569 fm = ui.formatter("version", opts)
5570 fm.startitem()
5570 fm.startitem()
5571 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5571 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5572 util.version())
5572 util.version())
5573 license = _(
5573 license = _(
5574 "(see https://mercurial-scm.org for more information)\n"
5574 "(see https://mercurial-scm.org for more information)\n"
5575 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5575 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5576 "This is free software; see the source for copying conditions. "
5576 "This is free software; see the source for copying conditions. "
5577 "There is NO\nwarranty; "
5577 "There is NO\nwarranty; "
5578 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5578 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5579 )
5579 )
5580 if not ui.quiet:
5580 if not ui.quiet:
5581 fm.plain(license)
5581 fm.plain(license)
5582
5582
5583 if ui.verbose:
5583 if ui.verbose:
5584 fm.plain(_("\nEnabled extensions:\n\n"))
5584 fm.plain(_("\nEnabled extensions:\n\n"))
5585 # format names and versions into columns
5585 # format names and versions into columns
5586 names = []
5586 names = []
5587 vers = []
5587 vers = []
5588 isinternals = []
5588 isinternals = []
5589 for name, module in extensions.extensions():
5589 for name, module in extensions.extensions():
5590 names.append(name)
5590 names.append(name)
5591 vers.append(extensions.moduleversion(module) or None)
5591 vers.append(extensions.moduleversion(module) or None)
5592 isinternals.append(extensions.ismoduleinternal(module))
5592 isinternals.append(extensions.ismoduleinternal(module))
5593 fn = fm.nested("extensions")
5593 fn = fm.nested("extensions")
5594 if names:
5594 if names:
5595 namefmt = " %%-%ds " % max(len(n) for n in names)
5595 namefmt = " %%-%ds " % max(len(n) for n in names)
5596 places = [_("external"), _("internal")]
5596 places = [_("external"), _("internal")]
5597 for n, v, p in zip(names, vers, isinternals):
5597 for n, v, p in zip(names, vers, isinternals):
5598 fn.startitem()
5598 fn.startitem()
5599 fn.condwrite(ui.verbose, "name", namefmt, n)
5599 fn.condwrite(ui.verbose, "name", namefmt, n)
5600 if ui.verbose:
5600 if ui.verbose:
5601 fn.plain("%s " % places[p])
5601 fn.plain("%s " % places[p])
5602 fn.data(bundled=p)
5602 fn.data(bundled=p)
5603 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5603 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5604 if ui.verbose:
5604 if ui.verbose:
5605 fn.plain("\n")
5605 fn.plain("\n")
5606 fn.end()
5606 fn.end()
5607 fm.end()
5607 fm.end()
5608
5608
5609 def loadcmdtable(ui, name, cmdtable):
5609 def loadcmdtable(ui, name, cmdtable):
5610 """Load command functions from specified cmdtable
5610 """Load command functions from specified cmdtable
5611 """
5611 """
5612 overrides = [cmd for cmd in cmdtable if cmd in table]
5612 overrides = [cmd for cmd in cmdtable if cmd in table]
5613 if overrides:
5613 if overrides:
5614 ui.warn(_("extension '%s' overrides commands: %s\n")
5614 ui.warn(_("extension '%s' overrides commands: %s\n")
5615 % (name, " ".join(overrides)))
5615 % (name, " ".join(overrides)))
5616 table.update(cmdtable)
5616 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now