##// END OF EJS Templates
commands: check for empty rev before passing to scmutil.unhidehashlikerevs...
Pulkit Goyal -
r35535:ba0fb0e3 default
parent child Browse files
Show More
@@ -1,5605 +1,5610 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 rcutil,
49 rcutil,
50 registrar,
50 registrar,
51 revsetlang,
51 revsetlang,
52 rewriteutil,
52 rewriteutil,
53 scmutil,
53 scmutil,
54 server,
54 server,
55 sshserver,
55 sshserver,
56 streamclone,
56 streamclone,
57 tags as tagsmod,
57 tags as tagsmod,
58 templatekw,
58 templatekw,
59 ui as uimod,
59 ui as uimod,
60 util,
60 util,
61 )
61 )
62
62
63 release = lockmod.release
63 release = lockmod.release
64
64
65 table = {}
65 table = {}
66 table.update(debugcommandsmod.command._table)
66 table.update(debugcommandsmod.command._table)
67
67
68 command = registrar.command(table)
68 command = registrar.command(table)
69 readonly = registrar.command.readonly
69 readonly = registrar.command.readonly
70
70
71 # common command options
71 # common command options
72
72
73 globalopts = [
73 globalopts = [
74 ('R', 'repository', '',
74 ('R', 'repository', '',
75 _('repository root directory or name of overlay bundle file'),
75 _('repository root directory or name of overlay bundle file'),
76 _('REPO')),
76 _('REPO')),
77 ('', 'cwd', '',
77 ('', 'cwd', '',
78 _('change working directory'), _('DIR')),
78 _('change working directory'), _('DIR')),
79 ('y', 'noninteractive', None,
79 ('y', 'noninteractive', None,
80 _('do not prompt, automatically pick the first choice for all prompts')),
80 _('do not prompt, automatically pick the first choice for all prompts')),
81 ('q', 'quiet', None, _('suppress output')),
81 ('q', 'quiet', None, _('suppress output')),
82 ('v', 'verbose', None, _('enable additional output')),
82 ('v', 'verbose', None, _('enable additional output')),
83 ('', 'color', '',
83 ('', 'color', '',
84 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
85 # and should not be translated
85 # and should not be translated
86 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _("when to colorize (boolean, always, auto, never, or debug)"),
87 _('TYPE')),
87 _('TYPE')),
88 ('', 'config', [],
88 ('', 'config', [],
89 _('set/override config option (use \'section.name=value\')'),
89 _('set/override config option (use \'section.name=value\')'),
90 _('CONFIG')),
90 _('CONFIG')),
91 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debug', None, _('enable debugging output')),
92 ('', 'debugger', None, _('start debugger')),
92 ('', 'debugger', None, _('start debugger')),
93 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
94 _('ENCODE')),
94 _('ENCODE')),
95 ('', 'encodingmode', encoding.encodingmode,
95 ('', 'encodingmode', encoding.encodingmode,
96 _('set the charset encoding mode'), _('MODE')),
96 _('set the charset encoding mode'), _('MODE')),
97 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'traceback', None, _('always print a traceback on exception')),
98 ('', 'time', None, _('time how long the command takes')),
98 ('', 'time', None, _('time how long the command takes')),
99 ('', 'profile', None, _('print command execution profile')),
99 ('', 'profile', None, _('print command execution profile')),
100 ('', 'version', None, _('output version information and exit')),
100 ('', 'version', None, _('output version information and exit')),
101 ('h', 'help', None, _('display help and exit')),
101 ('h', 'help', None, _('display help and exit')),
102 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'hidden', False, _('consider hidden changesets')),
103 ('', 'pager', 'auto',
103 ('', 'pager', 'auto',
104 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
105 ]
105 ]
106
106
107 dryrunopts = cmdutil.dryrunopts
107 dryrunopts = cmdutil.dryrunopts
108 remoteopts = cmdutil.remoteopts
108 remoteopts = cmdutil.remoteopts
109 walkopts = cmdutil.walkopts
109 walkopts = cmdutil.walkopts
110 commitopts = cmdutil.commitopts
110 commitopts = cmdutil.commitopts
111 commitopts2 = cmdutil.commitopts2
111 commitopts2 = cmdutil.commitopts2
112 formatteropts = cmdutil.formatteropts
112 formatteropts = cmdutil.formatteropts
113 templateopts = cmdutil.templateopts
113 templateopts = cmdutil.templateopts
114 logopts = cmdutil.logopts
114 logopts = cmdutil.logopts
115 diffopts = cmdutil.diffopts
115 diffopts = cmdutil.diffopts
116 diffwsopts = cmdutil.diffwsopts
116 diffwsopts = cmdutil.diffwsopts
117 diffopts2 = cmdutil.diffopts2
117 diffopts2 = cmdutil.diffopts2
118 mergetoolopts = cmdutil.mergetoolopts
118 mergetoolopts = cmdutil.mergetoolopts
119 similarityopts = cmdutil.similarityopts
119 similarityopts = cmdutil.similarityopts
120 subrepoopts = cmdutil.subrepoopts
120 subrepoopts = cmdutil.subrepoopts
121 debugrevlogopts = cmdutil.debugrevlogopts
121 debugrevlogopts = cmdutil.debugrevlogopts
122
122
123 # Commands start here, listed alphabetically
123 # Commands start here, listed alphabetically
124
124
125 @command('^add',
125 @command('^add',
126 walkopts + subrepoopts + dryrunopts,
126 walkopts + subrepoopts + dryrunopts,
127 _('[OPTION]... [FILE]...'),
127 _('[OPTION]... [FILE]...'),
128 inferrepo=True)
128 inferrepo=True)
129 def add(ui, repo, *pats, **opts):
129 def add(ui, repo, *pats, **opts):
130 """add the specified files on the next commit
130 """add the specified files on the next commit
131
131
132 Schedule files to be version controlled and added to the
132 Schedule files to be version controlled and added to the
133 repository.
133 repository.
134
134
135 The files will be added to the repository at the next commit. To
135 The files will be added to the repository at the next commit. To
136 undo an add before that, see :hg:`forget`.
136 undo an add before that, see :hg:`forget`.
137
137
138 If no names are given, add all files to the repository (except
138 If no names are given, add all files to the repository (except
139 files matching ``.hgignore``).
139 files matching ``.hgignore``).
140
140
141 .. container:: verbose
141 .. container:: verbose
142
142
143 Examples:
143 Examples:
144
144
145 - New (unknown) files are added
145 - New (unknown) files are added
146 automatically by :hg:`add`::
146 automatically by :hg:`add`::
147
147
148 $ ls
148 $ ls
149 foo.c
149 foo.c
150 $ hg status
150 $ hg status
151 ? foo.c
151 ? foo.c
152 $ hg add
152 $ hg add
153 adding foo.c
153 adding foo.c
154 $ hg status
154 $ hg status
155 A foo.c
155 A foo.c
156
156
157 - Specific files to be added can be specified::
157 - Specific files to be added can be specified::
158
158
159 $ ls
159 $ ls
160 bar.c foo.c
160 bar.c foo.c
161 $ hg status
161 $ hg status
162 ? bar.c
162 ? bar.c
163 ? foo.c
163 ? foo.c
164 $ hg add bar.c
164 $ hg add bar.c
165 $ hg status
165 $ hg status
166 A bar.c
166 A bar.c
167 ? foo.c
167 ? foo.c
168
168
169 Returns 0 if all files are successfully added.
169 Returns 0 if all files are successfully added.
170 """
170 """
171
171
172 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
172 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
173 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
173 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
174 return rejected and 1 or 0
174 return rejected and 1 or 0
175
175
176 @command('addremove',
176 @command('addremove',
177 similarityopts + subrepoopts + walkopts + dryrunopts,
177 similarityopts + subrepoopts + walkopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def addremove(ui, repo, *pats, **opts):
180 def addremove(ui, repo, *pats, **opts):
181 """add all new files, delete all missing files
181 """add all new files, delete all missing files
182
182
183 Add all new files and remove all missing files from the
183 Add all new files and remove all missing files from the
184 repository.
184 repository.
185
185
186 Unless names are given, new files are ignored if they match any of
186 Unless names are given, new files are ignored if they match any of
187 the patterns in ``.hgignore``. As with add, these changes take
187 the patterns in ``.hgignore``. As with add, these changes take
188 effect at the next commit.
188 effect at the next commit.
189
189
190 Use the -s/--similarity option to detect renamed files. This
190 Use the -s/--similarity option to detect renamed files. This
191 option takes a percentage between 0 (disabled) and 100 (files must
191 option takes a percentage between 0 (disabled) and 100 (files must
192 be identical) as its parameter. With a parameter greater than 0,
192 be identical) as its parameter. With a parameter greater than 0,
193 this compares every removed file with every added file and records
193 this compares every removed file with every added file and records
194 those similar enough as renames. Detecting renamed files this way
194 those similar enough as renames. Detecting renamed files this way
195 can be expensive. After using this option, :hg:`status -C` can be
195 can be expensive. After using this option, :hg:`status -C` can be
196 used to check which files were identified as moved or renamed. If
196 used to check which files were identified as moved or renamed. If
197 not specified, -s/--similarity defaults to 100 and only renames of
197 not specified, -s/--similarity defaults to 100 and only renames of
198 identical files are detected.
198 identical files are detected.
199
199
200 .. container:: verbose
200 .. container:: verbose
201
201
202 Examples:
202 Examples:
203
203
204 - A number of files (bar.c and foo.c) are new,
204 - A number of files (bar.c and foo.c) are new,
205 while foobar.c has been removed (without using :hg:`remove`)
205 while foobar.c has been removed (without using :hg:`remove`)
206 from the repository::
206 from the repository::
207
207
208 $ ls
208 $ ls
209 bar.c foo.c
209 bar.c foo.c
210 $ hg status
210 $ hg status
211 ! foobar.c
211 ! foobar.c
212 ? bar.c
212 ? bar.c
213 ? foo.c
213 ? foo.c
214 $ hg addremove
214 $ hg addremove
215 adding bar.c
215 adding bar.c
216 adding foo.c
216 adding foo.c
217 removing foobar.c
217 removing foobar.c
218 $ hg status
218 $ hg status
219 A bar.c
219 A bar.c
220 A foo.c
220 A foo.c
221 R foobar.c
221 R foobar.c
222
222
223 - A file foobar.c was moved to foo.c without using :hg:`rename`.
223 - A file foobar.c was moved to foo.c without using :hg:`rename`.
224 Afterwards, it was edited slightly::
224 Afterwards, it was edited slightly::
225
225
226 $ ls
226 $ ls
227 foo.c
227 foo.c
228 $ hg status
228 $ hg status
229 ! foobar.c
229 ! foobar.c
230 ? foo.c
230 ? foo.c
231 $ hg addremove --similarity 90
231 $ hg addremove --similarity 90
232 removing foobar.c
232 removing foobar.c
233 adding foo.c
233 adding foo.c
234 recording removal of foobar.c as rename to foo.c (94% similar)
234 recording removal of foobar.c as rename to foo.c (94% similar)
235 $ hg status -C
235 $ hg status -C
236 A foo.c
236 A foo.c
237 foobar.c
237 foobar.c
238 R foobar.c
238 R foobar.c
239
239
240 Returns 0 if all files are successfully added.
240 Returns 0 if all files are successfully added.
241 """
241 """
242 opts = pycompat.byteskwargs(opts)
242 opts = pycompat.byteskwargs(opts)
243 try:
243 try:
244 sim = float(opts.get('similarity') or 100)
244 sim = float(opts.get('similarity') or 100)
245 except ValueError:
245 except ValueError:
246 raise error.Abort(_('similarity must be a number'))
246 raise error.Abort(_('similarity must be a number'))
247 if sim < 0 or sim > 100:
247 if sim < 0 or sim > 100:
248 raise error.Abort(_('similarity must be between 0 and 100'))
248 raise error.Abort(_('similarity must be between 0 and 100'))
249 matcher = scmutil.match(repo[None], pats, opts)
249 matcher = scmutil.match(repo[None], pats, opts)
250 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
250 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
251
251
252 @command('^annotate|blame',
252 @command('^annotate|blame',
253 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
253 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
254 ('', 'follow', None,
254 ('', 'follow', None,
255 _('follow copies/renames and list the filename (DEPRECATED)')),
255 _('follow copies/renames and list the filename (DEPRECATED)')),
256 ('', 'no-follow', None, _("don't follow copies and renames")),
256 ('', 'no-follow', None, _("don't follow copies and renames")),
257 ('a', 'text', None, _('treat all files as text')),
257 ('a', 'text', None, _('treat all files as text')),
258 ('u', 'user', None, _('list the author (long with -v)')),
258 ('u', 'user', None, _('list the author (long with -v)')),
259 ('f', 'file', None, _('list the filename')),
259 ('f', 'file', None, _('list the filename')),
260 ('d', 'date', None, _('list the date (short with -q)')),
260 ('d', 'date', None, _('list the date (short with -q)')),
261 ('n', 'number', None, _('list the revision number (default)')),
261 ('n', 'number', None, _('list the revision number (default)')),
262 ('c', 'changeset', None, _('list the changeset')),
262 ('c', 'changeset', None, _('list the changeset')),
263 ('l', 'line-number', None, _('show line number at the first appearance')),
263 ('l', 'line-number', None, _('show line number at the first appearance')),
264 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
264 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
265 ] + diffwsopts + walkopts + formatteropts,
265 ] + diffwsopts + walkopts + formatteropts,
266 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
266 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
267 inferrepo=True)
267 inferrepo=True)
268 def annotate(ui, repo, *pats, **opts):
268 def annotate(ui, repo, *pats, **opts):
269 """show changeset information by line for each file
269 """show changeset information by line for each file
270
270
271 List changes in files, showing the revision id responsible for
271 List changes in files, showing the revision id responsible for
272 each line.
272 each line.
273
273
274 This command is useful for discovering when a change was made and
274 This command is useful for discovering when a change was made and
275 by whom.
275 by whom.
276
276
277 If you include --file, --user, or --date, the revision number is
277 If you include --file, --user, or --date, the revision number is
278 suppressed unless you also include --number.
278 suppressed unless you also include --number.
279
279
280 Without the -a/--text option, annotate will avoid processing files
280 Without the -a/--text option, annotate will avoid processing files
281 it detects as binary. With -a, annotate will annotate the file
281 it detects as binary. With -a, annotate will annotate the file
282 anyway, although the results will probably be neither useful
282 anyway, although the results will probably be neither useful
283 nor desirable.
283 nor desirable.
284
284
285 Returns 0 on success.
285 Returns 0 on success.
286 """
286 """
287 opts = pycompat.byteskwargs(opts)
287 opts = pycompat.byteskwargs(opts)
288 if not pats:
288 if not pats:
289 raise error.Abort(_('at least one filename or pattern is required'))
289 raise error.Abort(_('at least one filename or pattern is required'))
290
290
291 if opts.get('follow'):
291 if opts.get('follow'):
292 # --follow is deprecated and now just an alias for -f/--file
292 # --follow is deprecated and now just an alias for -f/--file
293 # to mimic the behavior of Mercurial before version 1.5
293 # to mimic the behavior of Mercurial before version 1.5
294 opts['file'] = True
294 opts['file'] = True
295
295
296 ctx = scmutil.revsingle(repo, opts.get('rev'))
296 ctx = scmutil.revsingle(repo, opts.get('rev'))
297
297
298 rootfm = ui.formatter('annotate', opts)
298 rootfm = ui.formatter('annotate', opts)
299 if ui.quiet:
299 if ui.quiet:
300 datefunc = util.shortdate
300 datefunc = util.shortdate
301 else:
301 else:
302 datefunc = util.datestr
302 datefunc = util.datestr
303 if ctx.rev() is None:
303 if ctx.rev() is None:
304 def hexfn(node):
304 def hexfn(node):
305 if node is None:
305 if node is None:
306 return None
306 return None
307 else:
307 else:
308 return rootfm.hexfunc(node)
308 return rootfm.hexfunc(node)
309 if opts.get('changeset'):
309 if opts.get('changeset'):
310 # omit "+" suffix which is appended to node hex
310 # omit "+" suffix which is appended to node hex
311 def formatrev(rev):
311 def formatrev(rev):
312 if rev is None:
312 if rev is None:
313 return '%d' % ctx.p1().rev()
313 return '%d' % ctx.p1().rev()
314 else:
314 else:
315 return '%d' % rev
315 return '%d' % rev
316 else:
316 else:
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 def formathex(hex):
322 def formathex(hex):
323 if hex is None:
323 if hex is None:
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
325 else:
325 else:
326 return '%s ' % hex
326 return '%s ' % hex
327 else:
327 else:
328 hexfn = rootfm.hexfunc
328 hexfn = rootfm.hexfunc
329 formatrev = formathex = pycompat.bytestr
329 formatrev = formathex = pycompat.bytestr
330
330
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
335 ('file', ' ', lambda x: x.fctx.path(), str),
335 ('file', ' ', lambda x: x.fctx.path(), str),
336 ('line_number', ':', lambda x: x.lineno, str),
336 ('line_number', ':', lambda x: x.lineno, str),
337 ]
337 ]
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
339
339
340 if (not opts.get('user') and not opts.get('changeset')
340 if (not opts.get('user') and not opts.get('changeset')
341 and not opts.get('date') and not opts.get('file')):
341 and not opts.get('date') and not opts.get('file')):
342 opts['number'] = True
342 opts['number'] = True
343
343
344 linenumber = opts.get('line_number') is not None
344 linenumber = opts.get('line_number') is not None
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
346 raise error.Abort(_('at least one of -n/-c is required for -l'))
346 raise error.Abort(_('at least one of -n/-c is required for -l'))
347
347
348 ui.pager('annotate')
348 ui.pager('annotate')
349
349
350 if rootfm.isplain():
350 if rootfm.isplain():
351 def makefunc(get, fmt):
351 def makefunc(get, fmt):
352 return lambda x: fmt(get(x))
352 return lambda x: fmt(get(x))
353 else:
353 else:
354 def makefunc(get, fmt):
354 def makefunc(get, fmt):
355 return get
355 return get
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
357 if opts.get(op)]
357 if opts.get(op)]
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
359 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
359 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
360 if opts.get(op))
360 if opts.get(op))
361
361
362 def bad(x, y):
362 def bad(x, y):
363 raise error.Abort("%s: %s" % (x, y))
363 raise error.Abort("%s: %s" % (x, y))
364
364
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
366
366
367 follow = not opts.get('no_follow')
367 follow = not opts.get('no_follow')
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
369 whitespace=True)
369 whitespace=True)
370 skiprevs = opts.get('skip')
370 skiprevs = opts.get('skip')
371 if skiprevs:
371 if skiprevs:
372 skiprevs = scmutil.revrange(repo, skiprevs)
372 skiprevs = scmutil.revrange(repo, skiprevs)
373
373
374 for abs in ctx.walk(m):
374 for abs in ctx.walk(m):
375 fctx = ctx[abs]
375 fctx = ctx[abs]
376 rootfm.startitem()
376 rootfm.startitem()
377 rootfm.data(abspath=abs, path=m.rel(abs))
377 rootfm.data(abspath=abs, path=m.rel(abs))
378 if not opts.get('text') and fctx.isbinary():
378 if not opts.get('text') and fctx.isbinary():
379 rootfm.plain(_("%s: binary file\n")
379 rootfm.plain(_("%s: binary file\n")
380 % ((pats and m.rel(abs)) or abs))
380 % ((pats and m.rel(abs)) or abs))
381 continue
381 continue
382
382
383 fm = rootfm.nested('lines')
383 fm = rootfm.nested('lines')
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
385 skiprevs=skiprevs, diffopts=diffopts)
385 skiprevs=skiprevs, diffopts=diffopts)
386 if not lines:
386 if not lines:
387 fm.end()
387 fm.end()
388 continue
388 continue
389 formats = []
389 formats = []
390 pieces = []
390 pieces = []
391
391
392 for f, sep in funcmap:
392 for f, sep in funcmap:
393 l = [f(n) for n, dummy in lines]
393 l = [f(n) for n, dummy in lines]
394 if fm.isplain():
394 if fm.isplain():
395 sizes = [encoding.colwidth(x) for x in l]
395 sizes = [encoding.colwidth(x) for x in l]
396 ml = max(sizes)
396 ml = max(sizes)
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
398 else:
398 else:
399 formats.append(['%s' for x in l])
399 formats.append(['%s' for x in l])
400 pieces.append(l)
400 pieces.append(l)
401
401
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
403 fm.startitem()
403 fm.startitem()
404 fm.write(fields, "".join(f), *p)
404 fm.write(fields, "".join(f), *p)
405 if l[0].skip:
405 if l[0].skip:
406 fmt = "* %s"
406 fmt = "* %s"
407 else:
407 else:
408 fmt = ": %s"
408 fmt = ": %s"
409 fm.write('line', fmt, l[1])
409 fm.write('line', fmt, l[1])
410
410
411 if not lines[-1][1].endswith('\n'):
411 if not lines[-1][1].endswith('\n'):
412 fm.plain('\n')
412 fm.plain('\n')
413 fm.end()
413 fm.end()
414
414
415 rootfm.end()
415 rootfm.end()
416
416
417 @command('archive',
417 @command('archive',
418 [('', 'no-decode', None, _('do not pass files through decoders')),
418 [('', 'no-decode', None, _('do not pass files through decoders')),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
420 _('PREFIX')),
420 _('PREFIX')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
423 ] + subrepoopts + walkopts,
423 ] + subrepoopts + walkopts,
424 _('[OPTION]... DEST'))
424 _('[OPTION]... DEST'))
425 def archive(ui, repo, dest, **opts):
425 def archive(ui, repo, dest, **opts):
426 '''create an unversioned archive of a repository revision
426 '''create an unversioned archive of a repository revision
427
427
428 By default, the revision used is the parent of the working
428 By default, the revision used is the parent of the working
429 directory; use -r/--rev to specify a different revision.
429 directory; use -r/--rev to specify a different revision.
430
430
431 The archive type is automatically detected based on file
431 The archive type is automatically detected based on file
432 extension (to override, use -t/--type).
432 extension (to override, use -t/--type).
433
433
434 .. container:: verbose
434 .. container:: verbose
435
435
436 Examples:
436 Examples:
437
437
438 - create a zip file containing the 1.0 release::
438 - create a zip file containing the 1.0 release::
439
439
440 hg archive -r 1.0 project-1.0.zip
440 hg archive -r 1.0 project-1.0.zip
441
441
442 - create a tarball excluding .hg files::
442 - create a tarball excluding .hg files::
443
443
444 hg archive project.tar.gz -X ".hg*"
444 hg archive project.tar.gz -X ".hg*"
445
445
446 Valid types are:
446 Valid types are:
447
447
448 :``files``: a directory full of files (default)
448 :``files``: a directory full of files (default)
449 :``tar``: tar archive, uncompressed
449 :``tar``: tar archive, uncompressed
450 :``tbz2``: tar archive, compressed using bzip2
450 :``tbz2``: tar archive, compressed using bzip2
451 :``tgz``: tar archive, compressed using gzip
451 :``tgz``: tar archive, compressed using gzip
452 :``uzip``: zip archive, uncompressed
452 :``uzip``: zip archive, uncompressed
453 :``zip``: zip archive, compressed using deflate
453 :``zip``: zip archive, compressed using deflate
454
454
455 The exact name of the destination archive or directory is given
455 The exact name of the destination archive or directory is given
456 using a format string; see :hg:`help export` for details.
456 using a format string; see :hg:`help export` for details.
457
457
458 Each member added to an archive file has a directory prefix
458 Each member added to an archive file has a directory prefix
459 prepended. Use -p/--prefix to specify a format string for the
459 prepended. Use -p/--prefix to specify a format string for the
460 prefix. The default is the basename of the archive, with suffixes
460 prefix. The default is the basename of the archive, with suffixes
461 removed.
461 removed.
462
462
463 Returns 0 on success.
463 Returns 0 on success.
464 '''
464 '''
465
465
466 opts = pycompat.byteskwargs(opts)
466 opts = pycompat.byteskwargs(opts)
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
468 if not ctx:
468 if not ctx:
469 raise error.Abort(_('no working directory: please specify a revision'))
469 raise error.Abort(_('no working directory: please specify a revision'))
470 node = ctx.node()
470 node = ctx.node()
471 dest = cmdutil.makefilename(repo, dest, node)
471 dest = cmdutil.makefilename(repo, dest, node)
472 if os.path.realpath(dest) == repo.root:
472 if os.path.realpath(dest) == repo.root:
473 raise error.Abort(_('repository root cannot be destination'))
473 raise error.Abort(_('repository root cannot be destination'))
474
474
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
476 prefix = opts.get('prefix')
476 prefix = opts.get('prefix')
477
477
478 if dest == '-':
478 if dest == '-':
479 if kind == 'files':
479 if kind == 'files':
480 raise error.Abort(_('cannot archive plain files to stdout'))
480 raise error.Abort(_('cannot archive plain files to stdout'))
481 dest = cmdutil.makefileobj(repo, dest)
481 dest = cmdutil.makefileobj(repo, dest)
482 if not prefix:
482 if not prefix:
483 prefix = os.path.basename(repo.root) + '-%h'
483 prefix = os.path.basename(repo.root) + '-%h'
484
484
485 prefix = cmdutil.makefilename(repo, prefix, node)
485 prefix = cmdutil.makefilename(repo, prefix, node)
486 match = scmutil.match(ctx, [], opts)
486 match = scmutil.match(ctx, [], opts)
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
488 match, prefix, subrepos=opts.get('subrepos'))
488 match, prefix, subrepos=opts.get('subrepos'))
489
489
490 @command('backout',
490 @command('backout',
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
492 ('', 'commit', None,
492 ('', 'commit', None,
493 _('commit if no conflicts were encountered (DEPRECATED)')),
493 _('commit if no conflicts were encountered (DEPRECATED)')),
494 ('', 'no-commit', None, _('do not commit')),
494 ('', 'no-commit', None, _('do not commit')),
495 ('', 'parent', '',
495 ('', 'parent', '',
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
500 _('[OPTION]... [-r] REV'))
500 _('[OPTION]... [-r] REV'))
501 def backout(ui, repo, node=None, rev=None, **opts):
501 def backout(ui, repo, node=None, rev=None, **opts):
502 '''reverse effect of earlier changeset
502 '''reverse effect of earlier changeset
503
503
504 Prepare a new changeset with the effect of REV undone in the
504 Prepare a new changeset with the effect of REV undone in the
505 current working directory. If no conflicts were encountered,
505 current working directory. If no conflicts were encountered,
506 it will be committed immediately.
506 it will be committed immediately.
507
507
508 If REV is the parent of the working directory, then this new changeset
508 If REV is the parent of the working directory, then this new changeset
509 is committed automatically (unless --no-commit is specified).
509 is committed automatically (unless --no-commit is specified).
510
510
511 .. note::
511 .. note::
512
512
513 :hg:`backout` cannot be used to fix either an unwanted or
513 :hg:`backout` cannot be used to fix either an unwanted or
514 incorrect merge.
514 incorrect merge.
515
515
516 .. container:: verbose
516 .. container:: verbose
517
517
518 Examples:
518 Examples:
519
519
520 - Reverse the effect of the parent of the working directory.
520 - Reverse the effect of the parent of the working directory.
521 This backout will be committed immediately::
521 This backout will be committed immediately::
522
522
523 hg backout -r .
523 hg backout -r .
524
524
525 - Reverse the effect of previous bad revision 23::
525 - Reverse the effect of previous bad revision 23::
526
526
527 hg backout -r 23
527 hg backout -r 23
528
528
529 - Reverse the effect of previous bad revision 23 and
529 - Reverse the effect of previous bad revision 23 and
530 leave changes uncommitted::
530 leave changes uncommitted::
531
531
532 hg backout -r 23 --no-commit
532 hg backout -r 23 --no-commit
533 hg commit -m "Backout revision 23"
533 hg commit -m "Backout revision 23"
534
534
535 By default, the pending changeset will have one parent,
535 By default, the pending changeset will have one parent,
536 maintaining a linear history. With --merge, the pending
536 maintaining a linear history. With --merge, the pending
537 changeset will instead have two parents: the old parent of the
537 changeset will instead have two parents: the old parent of the
538 working directory and a new child of REV that simply undoes REV.
538 working directory and a new child of REV that simply undoes REV.
539
539
540 Before version 1.7, the behavior without --merge was equivalent
540 Before version 1.7, the behavior without --merge was equivalent
541 to specifying --merge followed by :hg:`update --clean .` to
541 to specifying --merge followed by :hg:`update --clean .` to
542 cancel the merge and leave the child of REV as a head to be
542 cancel the merge and leave the child of REV as a head to be
543 merged separately.
543 merged separately.
544
544
545 See :hg:`help dates` for a list of formats valid for -d/--date.
545 See :hg:`help dates` for a list of formats valid for -d/--date.
546
546
547 See :hg:`help revert` for a way to restore files to the state
547 See :hg:`help revert` for a way to restore files to the state
548 of another revision.
548 of another revision.
549
549
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
551 files.
551 files.
552 '''
552 '''
553 wlock = lock = None
553 wlock = lock = None
554 try:
554 try:
555 wlock = repo.wlock()
555 wlock = repo.wlock()
556 lock = repo.lock()
556 lock = repo.lock()
557 return _dobackout(ui, repo, node, rev, **opts)
557 return _dobackout(ui, repo, node, rev, **opts)
558 finally:
558 finally:
559 release(lock, wlock)
559 release(lock, wlock)
560
560
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
562 opts = pycompat.byteskwargs(opts)
562 opts = pycompat.byteskwargs(opts)
563 if opts.get('commit') and opts.get('no_commit'):
563 if opts.get('commit') and opts.get('no_commit'):
564 raise error.Abort(_("cannot use --commit with --no-commit"))
564 raise error.Abort(_("cannot use --commit with --no-commit"))
565 if opts.get('merge') and opts.get('no_commit'):
565 if opts.get('merge') and opts.get('no_commit'):
566 raise error.Abort(_("cannot use --merge with --no-commit"))
566 raise error.Abort(_("cannot use --merge with --no-commit"))
567
567
568 if rev and node:
568 if rev and node:
569 raise error.Abort(_("please specify just one revision"))
569 raise error.Abort(_("please specify just one revision"))
570
570
571 if not rev:
571 if not rev:
572 rev = node
572 rev = node
573
573
574 if not rev:
574 if not rev:
575 raise error.Abort(_("please specify a revision to backout"))
575 raise error.Abort(_("please specify a revision to backout"))
576
576
577 date = opts.get('date')
577 date = opts.get('date')
578 if date:
578 if date:
579 opts['date'] = util.parsedate(date)
579 opts['date'] = util.parsedate(date)
580
580
581 cmdutil.checkunfinished(repo)
581 cmdutil.checkunfinished(repo)
582 cmdutil.bailifchanged(repo)
582 cmdutil.bailifchanged(repo)
583 node = scmutil.revsingle(repo, rev).node()
583 node = scmutil.revsingle(repo, rev).node()
584
584
585 op1, op2 = repo.dirstate.parents()
585 op1, op2 = repo.dirstate.parents()
586 if not repo.changelog.isancestor(node, op1):
586 if not repo.changelog.isancestor(node, op1):
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
588
588
589 p1, p2 = repo.changelog.parents(node)
589 p1, p2 = repo.changelog.parents(node)
590 if p1 == nullid:
590 if p1 == nullid:
591 raise error.Abort(_('cannot backout a change with no parents'))
591 raise error.Abort(_('cannot backout a change with no parents'))
592 if p2 != nullid:
592 if p2 != nullid:
593 if not opts.get('parent'):
593 if not opts.get('parent'):
594 raise error.Abort(_('cannot backout a merge changeset'))
594 raise error.Abort(_('cannot backout a merge changeset'))
595 p = repo.lookup(opts['parent'])
595 p = repo.lookup(opts['parent'])
596 if p not in (p1, p2):
596 if p not in (p1, p2):
597 raise error.Abort(_('%s is not a parent of %s') %
597 raise error.Abort(_('%s is not a parent of %s') %
598 (short(p), short(node)))
598 (short(p), short(node)))
599 parent = p
599 parent = p
600 else:
600 else:
601 if opts.get('parent'):
601 if opts.get('parent'):
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
603 parent = p1
603 parent = p1
604
604
605 # the backout should appear on the same branch
605 # the backout should appear on the same branch
606 branch = repo.dirstate.branch()
606 branch = repo.dirstate.branch()
607 bheads = repo.branchheads(branch)
607 bheads = repo.branchheads(branch)
608 rctx = scmutil.revsingle(repo, hex(parent))
608 rctx = scmutil.revsingle(repo, hex(parent))
609 if not opts.get('merge') and op1 != node:
609 if not opts.get('merge') and op1 != node:
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
611 try:
611 try:
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
613 'backout')
613 'backout')
614 stats = mergemod.update(repo, parent, True, True, node, False)
614 stats = mergemod.update(repo, parent, True, True, node, False)
615 repo.setparents(op1, op2)
615 repo.setparents(op1, op2)
616 dsguard.close()
616 dsguard.close()
617 hg._showstats(repo, stats)
617 hg._showstats(repo, stats)
618 if stats[3]:
618 if stats[3]:
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
620 "file merges\n"))
620 "file merges\n"))
621 return 1
621 return 1
622 finally:
622 finally:
623 ui.setconfig('ui', 'forcemerge', '', '')
623 ui.setconfig('ui', 'forcemerge', '', '')
624 lockmod.release(dsguard)
624 lockmod.release(dsguard)
625 else:
625 else:
626 hg.clean(repo, node, show_stats=False)
626 hg.clean(repo, node, show_stats=False)
627 repo.dirstate.setbranch(branch)
627 repo.dirstate.setbranch(branch)
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
629
629
630 if opts.get('no_commit'):
630 if opts.get('no_commit'):
631 msg = _("changeset %s backed out, "
631 msg = _("changeset %s backed out, "
632 "don't forget to commit.\n")
632 "don't forget to commit.\n")
633 ui.status(msg % short(node))
633 ui.status(msg % short(node))
634 return 0
634 return 0
635
635
636 def commitfunc(ui, repo, message, match, opts):
636 def commitfunc(ui, repo, message, match, opts):
637 editform = 'backout'
637 editform = 'backout'
638 e = cmdutil.getcommiteditor(editform=editform,
638 e = cmdutil.getcommiteditor(editform=editform,
639 **pycompat.strkwargs(opts))
639 **pycompat.strkwargs(opts))
640 if not message:
640 if not message:
641 # we don't translate commit messages
641 # we don't translate commit messages
642 message = "Backed out changeset %s" % short(node)
642 message = "Backed out changeset %s" % short(node)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
644 return repo.commit(message, opts.get('user'), opts.get('date'),
644 return repo.commit(message, opts.get('user'), opts.get('date'),
645 match, editor=e)
645 match, editor=e)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
647 if not newnode:
647 if not newnode:
648 ui.status(_("nothing changed\n"))
648 ui.status(_("nothing changed\n"))
649 return 1
649 return 1
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
651
651
652 def nice(node):
652 def nice(node):
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
654 ui.status(_('changeset %s backs out changeset %s\n') %
654 ui.status(_('changeset %s backs out changeset %s\n') %
655 (nice(repo.changelog.tip()), nice(node)))
655 (nice(repo.changelog.tip()), nice(node)))
656 if opts.get('merge') and op1 != node:
656 if opts.get('merge') and op1 != node:
657 hg.clean(repo, op1, show_stats=False)
657 hg.clean(repo, op1, show_stats=False)
658 ui.status(_('merging with changeset %s\n')
658 ui.status(_('merging with changeset %s\n')
659 % nice(repo.changelog.tip()))
659 % nice(repo.changelog.tip()))
660 try:
660 try:
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
662 'backout')
662 'backout')
663 return hg.merge(repo, hex(repo.changelog.tip()))
663 return hg.merge(repo, hex(repo.changelog.tip()))
664 finally:
664 finally:
665 ui.setconfig('ui', 'forcemerge', '', '')
665 ui.setconfig('ui', 'forcemerge', '', '')
666 return 0
666 return 0
667
667
668 @command('bisect',
668 @command('bisect',
669 [('r', 'reset', False, _('reset bisect state')),
669 [('r', 'reset', False, _('reset bisect state')),
670 ('g', 'good', False, _('mark changeset good')),
670 ('g', 'good', False, _('mark changeset good')),
671 ('b', 'bad', False, _('mark changeset bad')),
671 ('b', 'bad', False, _('mark changeset bad')),
672 ('s', 'skip', False, _('skip testing changeset')),
672 ('s', 'skip', False, _('skip testing changeset')),
673 ('e', 'extend', False, _('extend the bisect range')),
673 ('e', 'extend', False, _('extend the bisect range')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('U', 'noupdate', False, _('do not update to target'))],
675 ('U', 'noupdate', False, _('do not update to target'))],
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 def bisect(ui, repo, rev=None, extra=None, command=None,
677 def bisect(ui, repo, rev=None, extra=None, command=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
679 noupdate=None):
679 noupdate=None):
680 """subdivision search of changesets
680 """subdivision search of changesets
681
681
682 This command helps to find changesets which introduce problems. To
682 This command helps to find changesets which introduce problems. To
683 use, mark the earliest changeset you know exhibits the problem as
683 use, mark the earliest changeset you know exhibits the problem as
684 bad, then mark the latest changeset which is free from the problem
684 bad, then mark the latest changeset which is free from the problem
685 as good. Bisect will update your working directory to a revision
685 as good. Bisect will update your working directory to a revision
686 for testing (unless the -U/--noupdate option is specified). Once
686 for testing (unless the -U/--noupdate option is specified). Once
687 you have performed tests, mark the working directory as good or
687 you have performed tests, mark the working directory as good or
688 bad, and bisect will either update to another candidate changeset
688 bad, and bisect will either update to another candidate changeset
689 or announce that it has found the bad revision.
689 or announce that it has found the bad revision.
690
690
691 As a shortcut, you can also use the revision argument to mark a
691 As a shortcut, you can also use the revision argument to mark a
692 revision as good or bad without checking it out first.
692 revision as good or bad without checking it out first.
693
693
694 If you supply a command, it will be used for automatic bisection.
694 If you supply a command, it will be used for automatic bisection.
695 The environment variable HG_NODE will contain the ID of the
695 The environment variable HG_NODE will contain the ID of the
696 changeset being tested. The exit status of the command will be
696 changeset being tested. The exit status of the command will be
697 used to mark revisions as good or bad: status 0 means good, 125
697 used to mark revisions as good or bad: status 0 means good, 125
698 means to skip the revision, 127 (command not found) will abort the
698 means to skip the revision, 127 (command not found) will abort the
699 bisection, and any other non-zero exit status means the revision
699 bisection, and any other non-zero exit status means the revision
700 is bad.
700 is bad.
701
701
702 .. container:: verbose
702 .. container:: verbose
703
703
704 Some examples:
704 Some examples:
705
705
706 - start a bisection with known bad revision 34, and good revision 12::
706 - start a bisection with known bad revision 34, and good revision 12::
707
707
708 hg bisect --bad 34
708 hg bisect --bad 34
709 hg bisect --good 12
709 hg bisect --good 12
710
710
711 - advance the current bisection by marking current revision as good or
711 - advance the current bisection by marking current revision as good or
712 bad::
712 bad::
713
713
714 hg bisect --good
714 hg bisect --good
715 hg bisect --bad
715 hg bisect --bad
716
716
717 - mark the current revision, or a known revision, to be skipped (e.g. if
717 - mark the current revision, or a known revision, to be skipped (e.g. if
718 that revision is not usable because of another issue)::
718 that revision is not usable because of another issue)::
719
719
720 hg bisect --skip
720 hg bisect --skip
721 hg bisect --skip 23
721 hg bisect --skip 23
722
722
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724
724
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726
726
727 - forget the current bisection::
727 - forget the current bisection::
728
728
729 hg bisect --reset
729 hg bisect --reset
730
730
731 - use 'make && make tests' to automatically find the first broken
731 - use 'make && make tests' to automatically find the first broken
732 revision::
732 revision::
733
733
734 hg bisect --reset
734 hg bisect --reset
735 hg bisect --bad 34
735 hg bisect --bad 34
736 hg bisect --good 12
736 hg bisect --good 12
737 hg bisect --command "make && make tests"
737 hg bisect --command "make && make tests"
738
738
739 - see all changesets whose states are already known in the current
739 - see all changesets whose states are already known in the current
740 bisection::
740 bisection::
741
741
742 hg log -r "bisect(pruned)"
742 hg log -r "bisect(pruned)"
743
743
744 - see the changeset currently being bisected (especially useful
744 - see the changeset currently being bisected (especially useful
745 if running with -U/--noupdate)::
745 if running with -U/--noupdate)::
746
746
747 hg log -r "bisect(current)"
747 hg log -r "bisect(current)"
748
748
749 - see all changesets that took part in the current bisection::
749 - see all changesets that took part in the current bisection::
750
750
751 hg log -r "bisect(range)"
751 hg log -r "bisect(range)"
752
752
753 - you can even get a nice graph::
753 - you can even get a nice graph::
754
754
755 hg log --graph -r "bisect(range)"
755 hg log --graph -r "bisect(range)"
756
756
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758
758
759 Returns 0 on success.
759 Returns 0 on success.
760 """
760 """
761 # backward compatibility
761 # backward compatibility
762 if rev in "good bad reset init".split():
762 if rev in "good bad reset init".split():
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 cmd, rev, extra = rev, extra, None
764 cmd, rev, extra = rev, extra, None
765 if cmd == "good":
765 if cmd == "good":
766 good = True
766 good = True
767 elif cmd == "bad":
767 elif cmd == "bad":
768 bad = True
768 bad = True
769 else:
769 else:
770 reset = True
770 reset = True
771 elif extra:
771 elif extra:
772 raise error.Abort(_('incompatible arguments'))
772 raise error.Abort(_('incompatible arguments'))
773
773
774 incompatibles = {
774 incompatibles = {
775 '--bad': bad,
775 '--bad': bad,
776 '--command': bool(command),
776 '--command': bool(command),
777 '--extend': extend,
777 '--extend': extend,
778 '--good': good,
778 '--good': good,
779 '--reset': reset,
779 '--reset': reset,
780 '--skip': skip,
780 '--skip': skip,
781 }
781 }
782
782
783 enabled = [x for x in incompatibles if incompatibles[x]]
783 enabled = [x for x in incompatibles if incompatibles[x]]
784
784
785 if len(enabled) > 1:
785 if len(enabled) > 1:
786 raise error.Abort(_('%s and %s are incompatible') %
786 raise error.Abort(_('%s and %s are incompatible') %
787 tuple(sorted(enabled)[0:2]))
787 tuple(sorted(enabled)[0:2]))
788
788
789 if reset:
789 if reset:
790 hbisect.resetstate(repo)
790 hbisect.resetstate(repo)
791 return
791 return
792
792
793 state = hbisect.load_state(repo)
793 state = hbisect.load_state(repo)
794
794
795 # update state
795 # update state
796 if good or bad or skip:
796 if good or bad or skip:
797 if rev:
797 if rev:
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
799 else:
799 else:
800 nodes = [repo.lookup('.')]
800 nodes = [repo.lookup('.')]
801 if good:
801 if good:
802 state['good'] += nodes
802 state['good'] += nodes
803 elif bad:
803 elif bad:
804 state['bad'] += nodes
804 state['bad'] += nodes
805 elif skip:
805 elif skip:
806 state['skip'] += nodes
806 state['skip'] += nodes
807 hbisect.save_state(repo, state)
807 hbisect.save_state(repo, state)
808 if not (state['good'] and state['bad']):
808 if not (state['good'] and state['bad']):
809 return
809 return
810
810
811 def mayupdate(repo, node, show_stats=True):
811 def mayupdate(repo, node, show_stats=True):
812 """common used update sequence"""
812 """common used update sequence"""
813 if noupdate:
813 if noupdate:
814 return
814 return
815 cmdutil.checkunfinished(repo)
815 cmdutil.checkunfinished(repo)
816 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
817 return hg.clean(repo, node, show_stats=show_stats)
817 return hg.clean(repo, node, show_stats=show_stats)
818
818
819 displayer = cmdutil.show_changeset(ui, repo, {})
819 displayer = cmdutil.show_changeset(ui, repo, {})
820
820
821 if command:
821 if command:
822 changesets = 1
822 changesets = 1
823 if noupdate:
823 if noupdate:
824 try:
824 try:
825 node = state['current'][0]
825 node = state['current'][0]
826 except LookupError:
826 except LookupError:
827 raise error.Abort(_('current bisect revision is unknown - '
827 raise error.Abort(_('current bisect revision is unknown - '
828 'start a new bisect to fix'))
828 'start a new bisect to fix'))
829 else:
829 else:
830 node, p2 = repo.dirstate.parents()
830 node, p2 = repo.dirstate.parents()
831 if p2 != nullid:
831 if p2 != nullid:
832 raise error.Abort(_('current bisect revision is a merge'))
832 raise error.Abort(_('current bisect revision is a merge'))
833 if rev:
833 if rev:
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 try:
835 try:
836 while changesets:
836 while changesets:
837 # update state
837 # update state
838 state['current'] = [node]
838 state['current'] = [node]
839 hbisect.save_state(repo, state)
839 hbisect.save_state(repo, state)
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 blockedtag='bisect_check')
841 blockedtag='bisect_check')
842 if status == 125:
842 if status == 125:
843 transition = "skip"
843 transition = "skip"
844 elif status == 0:
844 elif status == 0:
845 transition = "good"
845 transition = "good"
846 # status < 0 means process was killed
846 # status < 0 means process was killed
847 elif status == 127:
847 elif status == 127:
848 raise error.Abort(_("failed to execute %s") % command)
848 raise error.Abort(_("failed to execute %s") % command)
849 elif status < 0:
849 elif status < 0:
850 raise error.Abort(_("%s killed") % command)
850 raise error.Abort(_("%s killed") % command)
851 else:
851 else:
852 transition = "bad"
852 transition = "bad"
853 state[transition].append(node)
853 state[transition].append(node)
854 ctx = repo[node]
854 ctx = repo[node]
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
856 hbisect.checkstate(state)
856 hbisect.checkstate(state)
857 # bisect
857 # bisect
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
859 # update to next check
859 # update to next check
860 node = nodes[0]
860 node = nodes[0]
861 mayupdate(repo, node, show_stats=False)
861 mayupdate(repo, node, show_stats=False)
862 finally:
862 finally:
863 state['current'] = [node]
863 state['current'] = [node]
864 hbisect.save_state(repo, state)
864 hbisect.save_state(repo, state)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
866 return
866 return
867
867
868 hbisect.checkstate(state)
868 hbisect.checkstate(state)
869
869
870 # actually bisect
870 # actually bisect
871 nodes, changesets, good = hbisect.bisect(repo, state)
871 nodes, changesets, good = hbisect.bisect(repo, state)
872 if extend:
872 if extend:
873 if not changesets:
873 if not changesets:
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
875 if extendnode is not None:
875 if extendnode is not None:
876 ui.write(_("Extending search to changeset %d:%s\n")
876 ui.write(_("Extending search to changeset %d:%s\n")
877 % (extendnode.rev(), extendnode))
877 % (extendnode.rev(), extendnode))
878 state['current'] = [extendnode.node()]
878 state['current'] = [extendnode.node()]
879 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
880 return mayupdate(repo, extendnode.node())
880 return mayupdate(repo, extendnode.node())
881 raise error.Abort(_("nothing to extend"))
881 raise error.Abort(_("nothing to extend"))
882
882
883 if changesets == 0:
883 if changesets == 0:
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
885 else:
885 else:
886 assert len(nodes) == 1 # only a single node can be tested next
886 assert len(nodes) == 1 # only a single node can be tested next
887 node = nodes[0]
887 node = nodes[0]
888 # compute the approximate number of remaining tests
888 # compute the approximate number of remaining tests
889 tests, size = 0, 2
889 tests, size = 0, 2
890 while size <= changesets:
890 while size <= changesets:
891 tests, size = tests + 1, size * 2
891 tests, size = tests + 1, size * 2
892 rev = repo.changelog.rev(node)
892 rev = repo.changelog.rev(node)
893 ui.write(_("Testing changeset %d:%s "
893 ui.write(_("Testing changeset %d:%s "
894 "(%d changesets remaining, ~%d tests)\n")
894 "(%d changesets remaining, ~%d tests)\n")
895 % (rev, short(node), changesets, tests))
895 % (rev, short(node), changesets, tests))
896 state['current'] = [node]
896 state['current'] = [node]
897 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
898 return mayupdate(repo, node)
898 return mayupdate(repo, node)
899
899
900 @command('bookmarks|bookmark',
900 @command('bookmarks|bookmark',
901 [('f', 'force', False, _('force')),
901 [('f', 'force', False, _('force')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
903 ('d', 'delete', False, _('delete a given bookmark')),
903 ('d', 'delete', False, _('delete a given bookmark')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
906 ] + formatteropts,
906 ] + formatteropts,
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 def bookmark(ui, repo, *names, **opts):
908 def bookmark(ui, repo, *names, **opts):
909 '''create a new bookmark or list existing bookmarks
909 '''create a new bookmark or list existing bookmarks
910
910
911 Bookmarks are labels on changesets to help track lines of development.
911 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Deleting or moving a bookmark has no effect on the associated changesets.
913 Deleting or moving a bookmark has no effect on the associated changesets.
914
914
915 Creating or updating to a bookmark causes it to be marked as 'active'.
915 Creating or updating to a bookmark causes it to be marked as 'active'.
916 The active bookmark is indicated with a '*'.
916 The active bookmark is indicated with a '*'.
917 When a commit is made, the active bookmark will advance to the new commit.
917 When a commit is made, the active bookmark will advance to the new commit.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
919 Updating away from a bookmark will cause it to be deactivated.
919 Updating away from a bookmark will cause it to be deactivated.
920
920
921 Bookmarks can be pushed and pulled between repositories (see
921 Bookmarks can be pushed and pulled between repositories (see
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 be created. Using :hg:`merge` will resolve the divergence.
924 be created. Using :hg:`merge` will resolve the divergence.
925
925
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
927 the active bookmark's name.
927 the active bookmark's name.
928
928
929 A bookmark named '@' has the special property that :hg:`clone` will
929 A bookmark named '@' has the special property that :hg:`clone` will
930 check it out by default if it exists.
930 check it out by default if it exists.
931
931
932 .. container:: verbose
932 .. container:: verbose
933
933
934 Examples:
934 Examples:
935
935
936 - create an active bookmark for a new line of development::
936 - create an active bookmark for a new line of development::
937
937
938 hg book new-feature
938 hg book new-feature
939
939
940 - create an inactive bookmark as a place marker::
940 - create an inactive bookmark as a place marker::
941
941
942 hg book -i reviewed
942 hg book -i reviewed
943
943
944 - create an inactive bookmark on another changeset::
944 - create an inactive bookmark on another changeset::
945
945
946 hg book -r .^ tested
946 hg book -r .^ tested
947
947
948 - rename bookmark turkey to dinner::
948 - rename bookmark turkey to dinner::
949
949
950 hg book -m turkey dinner
950 hg book -m turkey dinner
951
951
952 - move the '@' bookmark from another branch::
952 - move the '@' bookmark from another branch::
953
953
954 hg book -f @
954 hg book -f @
955 '''
955 '''
956 force = opts.get(r'force')
956 force = opts.get(r'force')
957 rev = opts.get(r'rev')
957 rev = opts.get(r'rev')
958 delete = opts.get(r'delete')
958 delete = opts.get(r'delete')
959 rename = opts.get(r'rename')
959 rename = opts.get(r'rename')
960 inactive = opts.get(r'inactive')
960 inactive = opts.get(r'inactive')
961
961
962 if delete and rename:
962 if delete and rename:
963 raise error.Abort(_("--delete and --rename are incompatible"))
963 raise error.Abort(_("--delete and --rename are incompatible"))
964 if delete and rev:
964 if delete and rev:
965 raise error.Abort(_("--rev is incompatible with --delete"))
965 raise error.Abort(_("--rev is incompatible with --delete"))
966 if rename and rev:
966 if rename and rev:
967 raise error.Abort(_("--rev is incompatible with --rename"))
967 raise error.Abort(_("--rev is incompatible with --rename"))
968 if not names and (delete or rev):
968 if not names and (delete or rev):
969 raise error.Abort(_("bookmark name required"))
969 raise error.Abort(_("bookmark name required"))
970
970
971 if delete or rename or names or inactive:
971 if delete or rename or names or inactive:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
973 if delete:
973 if delete:
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
975 bookmarks.delete(repo, tr, names)
975 bookmarks.delete(repo, tr, names)
976 elif rename:
976 elif rename:
977 if not names:
977 if not names:
978 raise error.Abort(_("new bookmark name required"))
978 raise error.Abort(_("new bookmark name required"))
979 elif len(names) > 1:
979 elif len(names) > 1:
980 raise error.Abort(_("only one new bookmark name allowed"))
980 raise error.Abort(_("only one new bookmark name allowed"))
981 rename = repo._bookmarks.expandname(rename)
981 rename = repo._bookmarks.expandname(rename)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
983 elif names:
983 elif names:
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
985 elif inactive:
985 elif inactive:
986 if len(repo._bookmarks) == 0:
986 if len(repo._bookmarks) == 0:
987 ui.status(_("no bookmarks set\n"))
987 ui.status(_("no bookmarks set\n"))
988 elif not repo._activebookmark:
988 elif not repo._activebookmark:
989 ui.status(_("no active bookmark\n"))
989 ui.status(_("no active bookmark\n"))
990 else:
990 else:
991 bookmarks.deactivate(repo)
991 bookmarks.deactivate(repo)
992 else: # show bookmarks
992 else: # show bookmarks
993 bookmarks.printbookmarks(ui, repo, **opts)
993 bookmarks.printbookmarks(ui, repo, **opts)
994
994
995 @command('branch',
995 @command('branch',
996 [('f', 'force', None,
996 [('f', 'force', None,
997 _('set branch name even if it shadows an existing branch')),
997 _('set branch name even if it shadows an existing branch')),
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
999 _('[-fC] [NAME]'))
999 _('[-fC] [NAME]'))
1000 def branch(ui, repo, label=None, **opts):
1000 def branch(ui, repo, label=None, **opts):
1001 """set or show the current branch name
1001 """set or show the current branch name
1002
1002
1003 .. note::
1003 .. note::
1004
1004
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1007 information about named branches and bookmarks.
1007 information about named branches and bookmarks.
1008
1008
1009 With no argument, show the current branch name. With one argument,
1009 With no argument, show the current branch name. With one argument,
1010 set the working directory branch name (the branch will not exist
1010 set the working directory branch name (the branch will not exist
1011 in the repository until the next commit). Standard practice
1011 in the repository until the next commit). Standard practice
1012 recommends that primary development take place on the 'default'
1012 recommends that primary development take place on the 'default'
1013 branch.
1013 branch.
1014
1014
1015 Unless -f/--force is specified, branch will not let you set a
1015 Unless -f/--force is specified, branch will not let you set a
1016 branch name that already exists.
1016 branch name that already exists.
1017
1017
1018 Use -C/--clean to reset the working directory branch to that of
1018 Use -C/--clean to reset the working directory branch to that of
1019 the parent of the working directory, negating a previous branch
1019 the parent of the working directory, negating a previous branch
1020 change.
1020 change.
1021
1021
1022 Use the command :hg:`update` to switch to an existing branch. Use
1022 Use the command :hg:`update` to switch to an existing branch. Use
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1024 When all heads of a branch are closed, the branch will be
1024 When all heads of a branch are closed, the branch will be
1025 considered closed.
1025 considered closed.
1026
1026
1027 Returns 0 on success.
1027 Returns 0 on success.
1028 """
1028 """
1029 opts = pycompat.byteskwargs(opts)
1029 opts = pycompat.byteskwargs(opts)
1030 if label:
1030 if label:
1031 label = label.strip()
1031 label = label.strip()
1032
1032
1033 if not opts.get('clean') and not label:
1033 if not opts.get('clean') and not label:
1034 ui.write("%s\n" % repo.dirstate.branch())
1034 ui.write("%s\n" % repo.dirstate.branch())
1035 return
1035 return
1036
1036
1037 with repo.wlock():
1037 with repo.wlock():
1038 if opts.get('clean'):
1038 if opts.get('clean'):
1039 label = repo[None].p1().branch()
1039 label = repo[None].p1().branch()
1040 repo.dirstate.setbranch(label)
1040 repo.dirstate.setbranch(label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1042 elif label:
1042 elif label:
1043 if not opts.get('force') and label in repo.branchmap():
1043 if not opts.get('force') and label in repo.branchmap():
1044 if label not in [p.branch() for p in repo[None].parents()]:
1044 if label not in [p.branch() for p in repo[None].parents()]:
1045 raise error.Abort(_('a branch of the same name already'
1045 raise error.Abort(_('a branch of the same name already'
1046 ' exists'),
1046 ' exists'),
1047 # i18n: "it" refers to an existing branch
1047 # i18n: "it" refers to an existing branch
1048 hint=_("use 'hg update' to switch to it"))
1048 hint=_("use 'hg update' to switch to it"))
1049 scmutil.checknewlabel(repo, label, 'branch')
1049 scmutil.checknewlabel(repo, label, 'branch')
1050 repo.dirstate.setbranch(label)
1050 repo.dirstate.setbranch(label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1052
1052
1053 # find any open named branches aside from default
1053 # find any open named branches aside from default
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1055 if n != "default" and not c]
1055 if n != "default" and not c]
1056 if not others:
1056 if not others:
1057 ui.status(_('(branches are permanent and global, '
1057 ui.status(_('(branches are permanent and global, '
1058 'did you want a bookmark?)\n'))
1058 'did you want a bookmark?)\n'))
1059
1059
1060 @command('branches',
1060 @command('branches',
1061 [('a', 'active', False,
1061 [('a', 'active', False,
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1064 ] + formatteropts,
1064 ] + formatteropts,
1065 _('[-c]'), cmdtype=readonly)
1065 _('[-c]'), cmdtype=readonly)
1066 def branches(ui, repo, active=False, closed=False, **opts):
1066 def branches(ui, repo, active=False, closed=False, **opts):
1067 """list repository named branches
1067 """list repository named branches
1068
1068
1069 List the repository's named branches, indicating which ones are
1069 List the repository's named branches, indicating which ones are
1070 inactive. If -c/--closed is specified, also list branches which have
1070 inactive. If -c/--closed is specified, also list branches which have
1071 been marked closed (see :hg:`commit --close-branch`).
1071 been marked closed (see :hg:`commit --close-branch`).
1072
1072
1073 Use the command :hg:`update` to switch to an existing branch.
1073 Use the command :hg:`update` to switch to an existing branch.
1074
1074
1075 Returns 0.
1075 Returns 0.
1076 """
1076 """
1077
1077
1078 opts = pycompat.byteskwargs(opts)
1078 opts = pycompat.byteskwargs(opts)
1079 ui.pager('branches')
1079 ui.pager('branches')
1080 fm = ui.formatter('branches', opts)
1080 fm = ui.formatter('branches', opts)
1081 hexfunc = fm.hexfunc
1081 hexfunc = fm.hexfunc
1082
1082
1083 allheads = set(repo.heads())
1083 allheads = set(repo.heads())
1084 branches = []
1084 branches = []
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1086 isactive = False
1086 isactive = False
1087 if not isclosed:
1087 if not isclosed:
1088 openheads = set(repo.branchmap().iteropen(heads))
1088 openheads = set(repo.branchmap().iteropen(heads))
1089 isactive = bool(openheads & allheads)
1089 isactive = bool(openheads & allheads)
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1092 reverse=True)
1092 reverse=True)
1093
1093
1094 for tag, ctx, isactive, isopen in branches:
1094 for tag, ctx, isactive, isopen in branches:
1095 if active and not isactive:
1095 if active and not isactive:
1096 continue
1096 continue
1097 if isactive:
1097 if isactive:
1098 label = 'branches.active'
1098 label = 'branches.active'
1099 notice = ''
1099 notice = ''
1100 elif not isopen:
1100 elif not isopen:
1101 if not closed:
1101 if not closed:
1102 continue
1102 continue
1103 label = 'branches.closed'
1103 label = 'branches.closed'
1104 notice = _(' (closed)')
1104 notice = _(' (closed)')
1105 else:
1105 else:
1106 label = 'branches.inactive'
1106 label = 'branches.inactive'
1107 notice = _(' (inactive)')
1107 notice = _(' (inactive)')
1108 current = (tag == repo.dirstate.branch())
1108 current = (tag == repo.dirstate.branch())
1109 if current:
1109 if current:
1110 label = 'branches.current'
1110 label = 'branches.current'
1111
1111
1112 fm.startitem()
1112 fm.startitem()
1113 fm.write('branch', '%s', tag, label=label)
1113 fm.write('branch', '%s', tag, label=label)
1114 rev = ctx.rev()
1114 rev = ctx.rev()
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1116 fmt = ' ' * padsize + ' %d:%s'
1116 fmt = ' ' * padsize + ' %d:%s'
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1119 fm.context(ctx=ctx)
1119 fm.context(ctx=ctx)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1121 if not ui.quiet:
1121 if not ui.quiet:
1122 fm.plain(notice)
1122 fm.plain(notice)
1123 fm.plain('\n')
1123 fm.plain('\n')
1124 fm.end()
1124 fm.end()
1125
1125
1126 @command('bundle',
1126 @command('bundle',
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1129 _('REV')),
1129 _('REV')),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1131 _('BRANCH')),
1131 _('BRANCH')),
1132 ('', 'base', [],
1132 ('', 'base', [],
1133 _('a base changeset assumed to be available at the destination'),
1133 _('a base changeset assumed to be available at the destination'),
1134 _('REV')),
1134 _('REV')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1137 ] + remoteopts,
1137 ] + remoteopts,
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1139 def bundle(ui, repo, fname, dest=None, **opts):
1139 def bundle(ui, repo, fname, dest=None, **opts):
1140 """create a bundle file
1140 """create a bundle file
1141
1141
1142 Generate a bundle file containing data to be added to a repository.
1142 Generate a bundle file containing data to be added to a repository.
1143
1143
1144 To create a bundle containing all changesets, use -a/--all
1144 To create a bundle containing all changesets, use -a/--all
1145 (or --base null). Otherwise, hg assumes the destination will have
1145 (or --base null). Otherwise, hg assumes the destination will have
1146 all the nodes you specify with --base parameters. Otherwise, hg
1146 all the nodes you specify with --base parameters. Otherwise, hg
1147 will assume the repository has all the nodes in destination, or
1147 will assume the repository has all the nodes in destination, or
1148 default-push/default if no destination is specified.
1148 default-push/default if no destination is specified.
1149
1149
1150 You can change bundle format with the -t/--type option. See
1150 You can change bundle format with the -t/--type option. See
1151 :hg:`help bundlespec` for documentation on this format. By default,
1151 :hg:`help bundlespec` for documentation on this format. By default,
1152 the most appropriate format is used and compression defaults to
1152 the most appropriate format is used and compression defaults to
1153 bzip2.
1153 bzip2.
1154
1154
1155 The bundle file can then be transferred using conventional means
1155 The bundle file can then be transferred using conventional means
1156 and applied to another repository with the unbundle or pull
1156 and applied to another repository with the unbundle or pull
1157 command. This is useful when direct push and pull are not
1157 command. This is useful when direct push and pull are not
1158 available or when exporting an entire repository is undesirable.
1158 available or when exporting an entire repository is undesirable.
1159
1159
1160 Applying bundles preserves all changeset contents including
1160 Applying bundles preserves all changeset contents including
1161 permissions, copy/rename information, and revision history.
1161 permissions, copy/rename information, and revision history.
1162
1162
1163 Returns 0 on success, 1 if no changes found.
1163 Returns 0 on success, 1 if no changes found.
1164 """
1164 """
1165 opts = pycompat.byteskwargs(opts)
1165 opts = pycompat.byteskwargs(opts)
1166 revs = None
1166 revs = None
1167 if 'rev' in opts:
1167 if 'rev' in opts:
1168 revstrings = opts['rev']
1168 revstrings = opts['rev']
1169 revs = scmutil.revrange(repo, revstrings)
1169 revs = scmutil.revrange(repo, revstrings)
1170 if revstrings and not revs:
1170 if revstrings and not revs:
1171 raise error.Abort(_('no commits to bundle'))
1171 raise error.Abort(_('no commits to bundle'))
1172
1172
1173 bundletype = opts.get('type', 'bzip2').lower()
1173 bundletype = opts.get('type', 'bzip2').lower()
1174 try:
1174 try:
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1176 repo, bundletype, strict=False)
1176 repo, bundletype, strict=False)
1177 except error.UnsupportedBundleSpecification as e:
1177 except error.UnsupportedBundleSpecification as e:
1178 raise error.Abort(str(e),
1178 raise error.Abort(str(e),
1179 hint=_("see 'hg help bundlespec' for supported "
1179 hint=_("see 'hg help bundlespec' for supported "
1180 "values for --type"))
1180 "values for --type"))
1181
1181
1182 # Packed bundles are a pseudo bundle format for now.
1182 # Packed bundles are a pseudo bundle format for now.
1183 if cgversion == 's1':
1183 if cgversion == 's1':
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1186
1186
1187 if opts.get('all'):
1187 if opts.get('all'):
1188 if dest:
1188 if dest:
1189 raise error.Abort(_("--all is incompatible with specifying "
1189 raise error.Abort(_("--all is incompatible with specifying "
1190 "a destination"))
1190 "a destination"))
1191 if opts.get('base'):
1191 if opts.get('base'):
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1193 base = ['null']
1193 base = ['null']
1194 else:
1194 else:
1195 base = scmutil.revrange(repo, opts.get('base'))
1195 base = scmutil.revrange(repo, opts.get('base'))
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1197 raise error.Abort(_("repository does not support bundle version %s") %
1197 raise error.Abort(_("repository does not support bundle version %s") %
1198 cgversion)
1198 cgversion)
1199
1199
1200 if base:
1200 if base:
1201 if dest:
1201 if dest:
1202 raise error.Abort(_("--base is incompatible with specifying "
1202 raise error.Abort(_("--base is incompatible with specifying "
1203 "a destination"))
1203 "a destination"))
1204 common = [repo.lookup(rev) for rev in base]
1204 common = [repo.lookup(rev) for rev in base]
1205 heads = revs and map(repo.lookup, revs) or None
1205 heads = revs and map(repo.lookup, revs) or None
1206 outgoing = discovery.outgoing(repo, common, heads)
1206 outgoing = discovery.outgoing(repo, common, heads)
1207 else:
1207 else:
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1210 other = hg.peer(repo, opts, dest)
1210 other = hg.peer(repo, opts, dest)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1212 heads = revs and map(repo.lookup, revs) or revs
1212 heads = revs and map(repo.lookup, revs) or revs
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1214 onlyheads=heads,
1214 onlyheads=heads,
1215 force=opts.get('force'),
1215 force=opts.get('force'),
1216 portable=True)
1216 portable=True)
1217
1217
1218 if not outgoing.missing:
1218 if not outgoing.missing:
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1220 return 1
1220 return 1
1221
1221
1222 if cgversion == '01': #bundle1
1222 if cgversion == '01': #bundle1
1223 if bcompression is None:
1223 if bcompression is None:
1224 bcompression = 'UN'
1224 bcompression = 'UN'
1225 bversion = 'HG10' + bcompression
1225 bversion = 'HG10' + bcompression
1226 bcompression = None
1226 bcompression = None
1227 elif cgversion in ('02', '03'):
1227 elif cgversion in ('02', '03'):
1228 bversion = 'HG20'
1228 bversion = 'HG20'
1229 else:
1229 else:
1230 raise error.ProgrammingError(
1230 raise error.ProgrammingError(
1231 'bundle: unexpected changegroup version %s' % cgversion)
1231 'bundle: unexpected changegroup version %s' % cgversion)
1232
1232
1233 # TODO compression options should be derived from bundlespec parsing.
1233 # TODO compression options should be derived from bundlespec parsing.
1234 # This is a temporary hack to allow adjusting bundle compression
1234 # This is a temporary hack to allow adjusting bundle compression
1235 # level without a) formalizing the bundlespec changes to declare it
1235 # level without a) formalizing the bundlespec changes to declare it
1236 # b) introducing a command flag.
1236 # b) introducing a command flag.
1237 compopts = {}
1237 compopts = {}
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1239 if complevel is not None:
1239 if complevel is not None:
1240 compopts['level'] = complevel
1240 compopts['level'] = complevel
1241
1241
1242
1242
1243 contentopts = {'cg.version': cgversion}
1243 contentopts = {'cg.version': cgversion}
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1245 contentopts['obsolescence'] = True
1245 contentopts['obsolescence'] = True
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1247 contentopts['phases'] = True
1247 contentopts['phases'] = True
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1249 contentopts, compression=bcompression,
1249 contentopts, compression=bcompression,
1250 compopts=compopts)
1250 compopts=compopts)
1251
1251
1252 @command('cat',
1252 @command('cat',
1253 [('o', 'output', '',
1253 [('o', 'output', '',
1254 _('print output to file with formatted name'), _('FORMAT')),
1254 _('print output to file with formatted name'), _('FORMAT')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1257 ] + walkopts + formatteropts,
1257 ] + walkopts + formatteropts,
1258 _('[OPTION]... FILE...'),
1258 _('[OPTION]... FILE...'),
1259 inferrepo=True, cmdtype=readonly)
1259 inferrepo=True, cmdtype=readonly)
1260 def cat(ui, repo, file1, *pats, **opts):
1260 def cat(ui, repo, file1, *pats, **opts):
1261 """output the current or given revision of files
1261 """output the current or given revision of files
1262
1262
1263 Print the specified files as they were at the given revision. If
1263 Print the specified files as they were at the given revision. If
1264 no revision is given, the parent of the working directory is used.
1264 no revision is given, the parent of the working directory is used.
1265
1265
1266 Output may be to a file, in which case the name of the file is
1266 Output may be to a file, in which case the name of the file is
1267 given using a format string. The formatting rules as follows:
1267 given using a format string. The formatting rules as follows:
1268
1268
1269 :``%%``: literal "%" character
1269 :``%%``: literal "%" character
1270 :``%s``: basename of file being printed
1270 :``%s``: basename of file being printed
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1272 :``%p``: root-relative path name of file being printed
1272 :``%p``: root-relative path name of file being printed
1273 :``%H``: changeset hash (40 hexadecimal digits)
1273 :``%H``: changeset hash (40 hexadecimal digits)
1274 :``%R``: changeset revision number
1274 :``%R``: changeset revision number
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1276 :``%r``: zero-padded changeset revision number
1276 :``%r``: zero-padded changeset revision number
1277 :``%b``: basename of the exporting repository
1277 :``%b``: basename of the exporting repository
1278
1278
1279 Returns 0 on success.
1279 Returns 0 on success.
1280 """
1280 """
1281 opts = pycompat.byteskwargs(opts)
1281 opts = pycompat.byteskwargs(opts)
1282 rev = opts.get('rev')
1282 rev = opts.get('rev')
1283 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1283 if rev:
1284 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1284 ctx = scmutil.revsingle(repo, rev)
1285 ctx = scmutil.revsingle(repo, rev)
1285 m = scmutil.match(ctx, (file1,) + pats, opts)
1286 m = scmutil.match(ctx, (file1,) + pats, opts)
1286 fntemplate = opts.pop('output', '')
1287 fntemplate = opts.pop('output', '')
1287 if cmdutil.isstdiofilename(fntemplate):
1288 if cmdutil.isstdiofilename(fntemplate):
1288 fntemplate = ''
1289 fntemplate = ''
1289
1290
1290 if fntemplate:
1291 if fntemplate:
1291 fm = formatter.nullformatter(ui, 'cat')
1292 fm = formatter.nullformatter(ui, 'cat')
1292 else:
1293 else:
1293 ui.pager('cat')
1294 ui.pager('cat')
1294 fm = ui.formatter('cat', opts)
1295 fm = ui.formatter('cat', opts)
1295 with fm:
1296 with fm:
1296 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1297 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1297 **pycompat.strkwargs(opts))
1298 **pycompat.strkwargs(opts))
1298
1299
1299 @command('^clone',
1300 @command('^clone',
1300 [('U', 'noupdate', None, _('the clone will include an empty working '
1301 [('U', 'noupdate', None, _('the clone will include an empty working '
1301 'directory (only a repository)')),
1302 'directory (only a repository)')),
1302 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1303 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1303 _('REV')),
1304 _('REV')),
1304 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1305 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1305 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1306 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1306 ('', 'pull', None, _('use pull protocol to copy metadata')),
1307 ('', 'pull', None, _('use pull protocol to copy metadata')),
1307 ('', 'uncompressed', None,
1308 ('', 'uncompressed', None,
1308 _('an alias to --stream (DEPRECATED)')),
1309 _('an alias to --stream (DEPRECATED)')),
1309 ('', 'stream', None,
1310 ('', 'stream', None,
1310 _('clone with minimal data processing')),
1311 _('clone with minimal data processing')),
1311 ] + remoteopts,
1312 ] + remoteopts,
1312 _('[OPTION]... SOURCE [DEST]'),
1313 _('[OPTION]... SOURCE [DEST]'),
1313 norepo=True)
1314 norepo=True)
1314 def clone(ui, source, dest=None, **opts):
1315 def clone(ui, source, dest=None, **opts):
1315 """make a copy of an existing repository
1316 """make a copy of an existing repository
1316
1317
1317 Create a copy of an existing repository in a new directory.
1318 Create a copy of an existing repository in a new directory.
1318
1319
1319 If no destination directory name is specified, it defaults to the
1320 If no destination directory name is specified, it defaults to the
1320 basename of the source.
1321 basename of the source.
1321
1322
1322 The location of the source is added to the new repository's
1323 The location of the source is added to the new repository's
1323 ``.hg/hgrc`` file, as the default to be used for future pulls.
1324 ``.hg/hgrc`` file, as the default to be used for future pulls.
1324
1325
1325 Only local paths and ``ssh://`` URLs are supported as
1326 Only local paths and ``ssh://`` URLs are supported as
1326 destinations. For ``ssh://`` destinations, no working directory or
1327 destinations. For ``ssh://`` destinations, no working directory or
1327 ``.hg/hgrc`` will be created on the remote side.
1328 ``.hg/hgrc`` will be created on the remote side.
1328
1329
1329 If the source repository has a bookmark called '@' set, that
1330 If the source repository has a bookmark called '@' set, that
1330 revision will be checked out in the new repository by default.
1331 revision will be checked out in the new repository by default.
1331
1332
1332 To check out a particular version, use -u/--update, or
1333 To check out a particular version, use -u/--update, or
1333 -U/--noupdate to create a clone with no working directory.
1334 -U/--noupdate to create a clone with no working directory.
1334
1335
1335 To pull only a subset of changesets, specify one or more revisions
1336 To pull only a subset of changesets, specify one or more revisions
1336 identifiers with -r/--rev or branches with -b/--branch. The
1337 identifiers with -r/--rev or branches with -b/--branch. The
1337 resulting clone will contain only the specified changesets and
1338 resulting clone will contain only the specified changesets and
1338 their ancestors. These options (or 'clone src#rev dest') imply
1339 their ancestors. These options (or 'clone src#rev dest') imply
1339 --pull, even for local source repositories.
1340 --pull, even for local source repositories.
1340
1341
1341 In normal clone mode, the remote normalizes repository data into a common
1342 In normal clone mode, the remote normalizes repository data into a common
1342 exchange format and the receiving end translates this data into its local
1343 exchange format and the receiving end translates this data into its local
1343 storage format. --stream activates a different clone mode that essentially
1344 storage format. --stream activates a different clone mode that essentially
1344 copies repository files from the remote with minimal data processing. This
1345 copies repository files from the remote with minimal data processing. This
1345 significantly reduces the CPU cost of a clone both remotely and locally.
1346 significantly reduces the CPU cost of a clone both remotely and locally.
1346 However, it often increases the transferred data size by 30-40%. This can
1347 However, it often increases the transferred data size by 30-40%. This can
1347 result in substantially faster clones where I/O throughput is plentiful,
1348 result in substantially faster clones where I/O throughput is plentiful,
1348 especially for larger repositories. A side-effect of --stream clones is
1349 especially for larger repositories. A side-effect of --stream clones is
1349 that storage settings and requirements on the remote are applied locally:
1350 that storage settings and requirements on the remote are applied locally:
1350 a modern client may inherit legacy or inefficient storage used by the
1351 a modern client may inherit legacy or inefficient storage used by the
1351 remote or a legacy Mercurial client may not be able to clone from a
1352 remote or a legacy Mercurial client may not be able to clone from a
1352 modern Mercurial remote.
1353 modern Mercurial remote.
1353
1354
1354 .. note::
1355 .. note::
1355
1356
1356 Specifying a tag will include the tagged changeset but not the
1357 Specifying a tag will include the tagged changeset but not the
1357 changeset containing the tag.
1358 changeset containing the tag.
1358
1359
1359 .. container:: verbose
1360 .. container:: verbose
1360
1361
1361 For efficiency, hardlinks are used for cloning whenever the
1362 For efficiency, hardlinks are used for cloning whenever the
1362 source and destination are on the same filesystem (note this
1363 source and destination are on the same filesystem (note this
1363 applies only to the repository data, not to the working
1364 applies only to the repository data, not to the working
1364 directory). Some filesystems, such as AFS, implement hardlinking
1365 directory). Some filesystems, such as AFS, implement hardlinking
1365 incorrectly, but do not report errors. In these cases, use the
1366 incorrectly, but do not report errors. In these cases, use the
1366 --pull option to avoid hardlinking.
1367 --pull option to avoid hardlinking.
1367
1368
1368 Mercurial will update the working directory to the first applicable
1369 Mercurial will update the working directory to the first applicable
1369 revision from this list:
1370 revision from this list:
1370
1371
1371 a) null if -U or the source repository has no changesets
1372 a) null if -U or the source repository has no changesets
1372 b) if -u . and the source repository is local, the first parent of
1373 b) if -u . and the source repository is local, the first parent of
1373 the source repository's working directory
1374 the source repository's working directory
1374 c) the changeset specified with -u (if a branch name, this means the
1375 c) the changeset specified with -u (if a branch name, this means the
1375 latest head of that branch)
1376 latest head of that branch)
1376 d) the changeset specified with -r
1377 d) the changeset specified with -r
1377 e) the tipmost head specified with -b
1378 e) the tipmost head specified with -b
1378 f) the tipmost head specified with the url#branch source syntax
1379 f) the tipmost head specified with the url#branch source syntax
1379 g) the revision marked with the '@' bookmark, if present
1380 g) the revision marked with the '@' bookmark, if present
1380 h) the tipmost head of the default branch
1381 h) the tipmost head of the default branch
1381 i) tip
1382 i) tip
1382
1383
1383 When cloning from servers that support it, Mercurial may fetch
1384 When cloning from servers that support it, Mercurial may fetch
1384 pre-generated data from a server-advertised URL. When this is done,
1385 pre-generated data from a server-advertised URL. When this is done,
1385 hooks operating on incoming changesets and changegroups may fire twice,
1386 hooks operating on incoming changesets and changegroups may fire twice,
1386 once for the bundle fetched from the URL and another for any additional
1387 once for the bundle fetched from the URL and another for any additional
1387 data not fetched from this URL. In addition, if an error occurs, the
1388 data not fetched from this URL. In addition, if an error occurs, the
1388 repository may be rolled back to a partial clone. This behavior may
1389 repository may be rolled back to a partial clone. This behavior may
1389 change in future releases. See :hg:`help -e clonebundles` for more.
1390 change in future releases. See :hg:`help -e clonebundles` for more.
1390
1391
1391 Examples:
1392 Examples:
1392
1393
1393 - clone a remote repository to a new directory named hg/::
1394 - clone a remote repository to a new directory named hg/::
1394
1395
1395 hg clone https://www.mercurial-scm.org/repo/hg/
1396 hg clone https://www.mercurial-scm.org/repo/hg/
1396
1397
1397 - create a lightweight local clone::
1398 - create a lightweight local clone::
1398
1399
1399 hg clone project/ project-feature/
1400 hg clone project/ project-feature/
1400
1401
1401 - clone from an absolute path on an ssh server (note double-slash)::
1402 - clone from an absolute path on an ssh server (note double-slash)::
1402
1403
1403 hg clone ssh://user@server//home/projects/alpha/
1404 hg clone ssh://user@server//home/projects/alpha/
1404
1405
1405 - do a streaming clone while checking out a specified version::
1406 - do a streaming clone while checking out a specified version::
1406
1407
1407 hg clone --stream http://server/repo -u 1.5
1408 hg clone --stream http://server/repo -u 1.5
1408
1409
1409 - create a repository without changesets after a particular revision::
1410 - create a repository without changesets after a particular revision::
1410
1411
1411 hg clone -r 04e544 experimental/ good/
1412 hg clone -r 04e544 experimental/ good/
1412
1413
1413 - clone (and track) a particular named branch::
1414 - clone (and track) a particular named branch::
1414
1415
1415 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1416 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1416
1417
1417 See :hg:`help urls` for details on specifying URLs.
1418 See :hg:`help urls` for details on specifying URLs.
1418
1419
1419 Returns 0 on success.
1420 Returns 0 on success.
1420 """
1421 """
1421 opts = pycompat.byteskwargs(opts)
1422 opts = pycompat.byteskwargs(opts)
1422 if opts.get('noupdate') and opts.get('updaterev'):
1423 if opts.get('noupdate') and opts.get('updaterev'):
1423 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1424 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1424
1425
1425 r = hg.clone(ui, opts, source, dest,
1426 r = hg.clone(ui, opts, source, dest,
1426 pull=opts.get('pull'),
1427 pull=opts.get('pull'),
1427 stream=opts.get('stream') or opts.get('uncompressed'),
1428 stream=opts.get('stream') or opts.get('uncompressed'),
1428 rev=opts.get('rev'),
1429 rev=opts.get('rev'),
1429 update=opts.get('updaterev') or not opts.get('noupdate'),
1430 update=opts.get('updaterev') or not opts.get('noupdate'),
1430 branch=opts.get('branch'),
1431 branch=opts.get('branch'),
1431 shareopts=opts.get('shareopts'))
1432 shareopts=opts.get('shareopts'))
1432
1433
1433 return r is None
1434 return r is None
1434
1435
1435 @command('^commit|ci',
1436 @command('^commit|ci',
1436 [('A', 'addremove', None,
1437 [('A', 'addremove', None,
1437 _('mark new/missing files as added/removed before committing')),
1438 _('mark new/missing files as added/removed before committing')),
1438 ('', 'close-branch', None,
1439 ('', 'close-branch', None,
1439 _('mark a branch head as closed')),
1440 _('mark a branch head as closed')),
1440 ('', 'amend', None, _('amend the parent of the working directory')),
1441 ('', 'amend', None, _('amend the parent of the working directory')),
1441 ('s', 'secret', None, _('use the secret phase for committing')),
1442 ('s', 'secret', None, _('use the secret phase for committing')),
1442 ('e', 'edit', None, _('invoke editor on commit messages')),
1443 ('e', 'edit', None, _('invoke editor on commit messages')),
1443 ('i', 'interactive', None, _('use interactive mode')),
1444 ('i', 'interactive', None, _('use interactive mode')),
1444 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1445 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1445 _('[OPTION]... [FILE]...'),
1446 _('[OPTION]... [FILE]...'),
1446 inferrepo=True)
1447 inferrepo=True)
1447 def commit(ui, repo, *pats, **opts):
1448 def commit(ui, repo, *pats, **opts):
1448 """commit the specified files or all outstanding changes
1449 """commit the specified files or all outstanding changes
1449
1450
1450 Commit changes to the given files into the repository. Unlike a
1451 Commit changes to the given files into the repository. Unlike a
1451 centralized SCM, this operation is a local operation. See
1452 centralized SCM, this operation is a local operation. See
1452 :hg:`push` for a way to actively distribute your changes.
1453 :hg:`push` for a way to actively distribute your changes.
1453
1454
1454 If a list of files is omitted, all changes reported by :hg:`status`
1455 If a list of files is omitted, all changes reported by :hg:`status`
1455 will be committed.
1456 will be committed.
1456
1457
1457 If you are committing the result of a merge, do not provide any
1458 If you are committing the result of a merge, do not provide any
1458 filenames or -I/-X filters.
1459 filenames or -I/-X filters.
1459
1460
1460 If no commit message is specified, Mercurial starts your
1461 If no commit message is specified, Mercurial starts your
1461 configured editor where you can enter a message. In case your
1462 configured editor where you can enter a message. In case your
1462 commit fails, you will find a backup of your message in
1463 commit fails, you will find a backup of your message in
1463 ``.hg/last-message.txt``.
1464 ``.hg/last-message.txt``.
1464
1465
1465 The --close-branch flag can be used to mark the current branch
1466 The --close-branch flag can be used to mark the current branch
1466 head closed. When all heads of a branch are closed, the branch
1467 head closed. When all heads of a branch are closed, the branch
1467 will be considered closed and no longer listed.
1468 will be considered closed and no longer listed.
1468
1469
1469 The --amend flag can be used to amend the parent of the
1470 The --amend flag can be used to amend the parent of the
1470 working directory with a new commit that contains the changes
1471 working directory with a new commit that contains the changes
1471 in the parent in addition to those currently reported by :hg:`status`,
1472 in the parent in addition to those currently reported by :hg:`status`,
1472 if there are any. The old commit is stored in a backup bundle in
1473 if there are any. The old commit is stored in a backup bundle in
1473 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1474 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1474 on how to restore it).
1475 on how to restore it).
1475
1476
1476 Message, user and date are taken from the amended commit unless
1477 Message, user and date are taken from the amended commit unless
1477 specified. When a message isn't specified on the command line,
1478 specified. When a message isn't specified on the command line,
1478 the editor will open with the message of the amended commit.
1479 the editor will open with the message of the amended commit.
1479
1480
1480 It is not possible to amend public changesets (see :hg:`help phases`)
1481 It is not possible to amend public changesets (see :hg:`help phases`)
1481 or changesets that have children.
1482 or changesets that have children.
1482
1483
1483 See :hg:`help dates` for a list of formats valid for -d/--date.
1484 See :hg:`help dates` for a list of formats valid for -d/--date.
1484
1485
1485 Returns 0 on success, 1 if nothing changed.
1486 Returns 0 on success, 1 if nothing changed.
1486
1487
1487 .. container:: verbose
1488 .. container:: verbose
1488
1489
1489 Examples:
1490 Examples:
1490
1491
1491 - commit all files ending in .py::
1492 - commit all files ending in .py::
1492
1493
1493 hg commit --include "set:**.py"
1494 hg commit --include "set:**.py"
1494
1495
1495 - commit all non-binary files::
1496 - commit all non-binary files::
1496
1497
1497 hg commit --exclude "set:binary()"
1498 hg commit --exclude "set:binary()"
1498
1499
1499 - amend the current commit and set the date to now::
1500 - amend the current commit and set the date to now::
1500
1501
1501 hg commit --amend --date now
1502 hg commit --amend --date now
1502 """
1503 """
1503 wlock = lock = None
1504 wlock = lock = None
1504 try:
1505 try:
1505 wlock = repo.wlock()
1506 wlock = repo.wlock()
1506 lock = repo.lock()
1507 lock = repo.lock()
1507 return _docommit(ui, repo, *pats, **opts)
1508 return _docommit(ui, repo, *pats, **opts)
1508 finally:
1509 finally:
1509 release(lock, wlock)
1510 release(lock, wlock)
1510
1511
1511 def _docommit(ui, repo, *pats, **opts):
1512 def _docommit(ui, repo, *pats, **opts):
1512 if opts.get(r'interactive'):
1513 if opts.get(r'interactive'):
1513 opts.pop(r'interactive')
1514 opts.pop(r'interactive')
1514 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1515 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1515 cmdutil.recordfilter, *pats,
1516 cmdutil.recordfilter, *pats,
1516 **opts)
1517 **opts)
1517 # ret can be 0 (no changes to record) or the value returned by
1518 # ret can be 0 (no changes to record) or the value returned by
1518 # commit(), 1 if nothing changed or None on success.
1519 # commit(), 1 if nothing changed or None on success.
1519 return 1 if ret == 0 else ret
1520 return 1 if ret == 0 else ret
1520
1521
1521 opts = pycompat.byteskwargs(opts)
1522 opts = pycompat.byteskwargs(opts)
1522 if opts.get('subrepos'):
1523 if opts.get('subrepos'):
1523 if opts.get('amend'):
1524 if opts.get('amend'):
1524 raise error.Abort(_('cannot amend with --subrepos'))
1525 raise error.Abort(_('cannot amend with --subrepos'))
1525 # Let --subrepos on the command line override config setting.
1526 # Let --subrepos on the command line override config setting.
1526 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1527 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1527
1528
1528 cmdutil.checkunfinished(repo, commit=True)
1529 cmdutil.checkunfinished(repo, commit=True)
1529
1530
1530 branch = repo[None].branch()
1531 branch = repo[None].branch()
1531 bheads = repo.branchheads(branch)
1532 bheads = repo.branchheads(branch)
1532
1533
1533 extra = {}
1534 extra = {}
1534 if opts.get('close_branch'):
1535 if opts.get('close_branch'):
1535 extra['close'] = 1
1536 extra['close'] = 1
1536
1537
1537 if not bheads:
1538 if not bheads:
1538 raise error.Abort(_('can only close branch heads'))
1539 raise error.Abort(_('can only close branch heads'))
1539 elif opts.get('amend'):
1540 elif opts.get('amend'):
1540 if repo[None].parents()[0].p1().branch() != branch and \
1541 if repo[None].parents()[0].p1().branch() != branch and \
1541 repo[None].parents()[0].p2().branch() != branch:
1542 repo[None].parents()[0].p2().branch() != branch:
1542 raise error.Abort(_('can only close branch heads'))
1543 raise error.Abort(_('can only close branch heads'))
1543
1544
1544 if opts.get('amend'):
1545 if opts.get('amend'):
1545 if ui.configbool('ui', 'commitsubrepos'):
1546 if ui.configbool('ui', 'commitsubrepos'):
1546 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1547 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1547
1548
1548 old = repo['.']
1549 old = repo['.']
1549 rewriteutil.precheck(repo, [old.rev()], 'amend')
1550 rewriteutil.precheck(repo, [old.rev()], 'amend')
1550
1551
1551 # Currently histedit gets confused if an amend happens while histedit
1552 # Currently histedit gets confused if an amend happens while histedit
1552 # is in progress. Since we have a checkunfinished command, we are
1553 # is in progress. Since we have a checkunfinished command, we are
1553 # temporarily honoring it.
1554 # temporarily honoring it.
1554 #
1555 #
1555 # Note: eventually this guard will be removed. Please do not expect
1556 # Note: eventually this guard will be removed. Please do not expect
1556 # this behavior to remain.
1557 # this behavior to remain.
1557 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1558 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1558 cmdutil.checkunfinished(repo)
1559 cmdutil.checkunfinished(repo)
1559
1560
1560 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1561 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1561 if node == old.node():
1562 if node == old.node():
1562 ui.status(_("nothing changed\n"))
1563 ui.status(_("nothing changed\n"))
1563 return 1
1564 return 1
1564 else:
1565 else:
1565 def commitfunc(ui, repo, message, match, opts):
1566 def commitfunc(ui, repo, message, match, opts):
1566 overrides = {}
1567 overrides = {}
1567 if opts.get('secret'):
1568 if opts.get('secret'):
1568 overrides[('phases', 'new-commit')] = 'secret'
1569 overrides[('phases', 'new-commit')] = 'secret'
1569
1570
1570 baseui = repo.baseui
1571 baseui = repo.baseui
1571 with baseui.configoverride(overrides, 'commit'):
1572 with baseui.configoverride(overrides, 'commit'):
1572 with ui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1573 editform = cmdutil.mergeeditform(repo[None],
1574 editform = cmdutil.mergeeditform(repo[None],
1574 'commit.normal')
1575 'commit.normal')
1575 editor = cmdutil.getcommiteditor(
1576 editor = cmdutil.getcommiteditor(
1576 editform=editform, **pycompat.strkwargs(opts))
1577 editform=editform, **pycompat.strkwargs(opts))
1577 return repo.commit(message,
1578 return repo.commit(message,
1578 opts.get('user'),
1579 opts.get('user'),
1579 opts.get('date'),
1580 opts.get('date'),
1580 match,
1581 match,
1581 editor=editor,
1582 editor=editor,
1582 extra=extra)
1583 extra=extra)
1583
1584
1584 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1585
1586
1586 if not node:
1587 if not node:
1587 stat = cmdutil.postcommitstatus(repo, pats, opts)
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1588 if stat[3]:
1589 if stat[3]:
1589 ui.status(_("nothing changed (%d missing files, see "
1590 ui.status(_("nothing changed (%d missing files, see "
1590 "'hg status')\n") % len(stat[3]))
1591 "'hg status')\n") % len(stat[3]))
1591 else:
1592 else:
1592 ui.status(_("nothing changed\n"))
1593 ui.status(_("nothing changed\n"))
1593 return 1
1594 return 1
1594
1595
1595 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1596
1597
1597 @command('config|showconfig|debugconfig',
1598 @command('config|showconfig|debugconfig',
1598 [('u', 'untrusted', None, _('show untrusted configuration options')),
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1599 ('e', 'edit', None, _('edit user config')),
1600 ('e', 'edit', None, _('edit user config')),
1600 ('l', 'local', None, _('edit repository config')),
1601 ('l', 'local', None, _('edit repository config')),
1601 ('g', 'global', None, _('edit global config'))] + formatteropts,
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1602 _('[-u] [NAME]...'),
1603 _('[-u] [NAME]...'),
1603 optionalrepo=True, cmdtype=readonly)
1604 optionalrepo=True, cmdtype=readonly)
1604 def config(ui, repo, *values, **opts):
1605 def config(ui, repo, *values, **opts):
1605 """show combined config settings from all hgrc files
1606 """show combined config settings from all hgrc files
1606
1607
1607 With no arguments, print names and values of all config items.
1608 With no arguments, print names and values of all config items.
1608
1609
1609 With one argument of the form section.name, print just the value
1610 With one argument of the form section.name, print just the value
1610 of that config item.
1611 of that config item.
1611
1612
1612 With multiple arguments, print names and values of all config
1613 With multiple arguments, print names and values of all config
1613 items with matching section names.
1614 items with matching section names.
1614
1615
1615 With --edit, start an editor on the user-level config file. With
1616 With --edit, start an editor on the user-level config file. With
1616 --global, edit the system-wide config file. With --local, edit the
1617 --global, edit the system-wide config file. With --local, edit the
1617 repository-level config file.
1618 repository-level config file.
1618
1619
1619 With --debug, the source (filename and line number) is printed
1620 With --debug, the source (filename and line number) is printed
1620 for each config item.
1621 for each config item.
1621
1622
1622 See :hg:`help config` for more information about config files.
1623 See :hg:`help config` for more information about config files.
1623
1624
1624 Returns 0 on success, 1 if NAME does not exist.
1625 Returns 0 on success, 1 if NAME does not exist.
1625
1626
1626 """
1627 """
1627
1628
1628 opts = pycompat.byteskwargs(opts)
1629 opts = pycompat.byteskwargs(opts)
1629 if opts.get('edit') or opts.get('local') or opts.get('global'):
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1630 if opts.get('local') and opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1631 raise error.Abort(_("can't use --local and --global together"))
1632 raise error.Abort(_("can't use --local and --global together"))
1632
1633
1633 if opts.get('local'):
1634 if opts.get('local'):
1634 if not repo:
1635 if not repo:
1635 raise error.Abort(_("can't use --local outside a repository"))
1636 raise error.Abort(_("can't use --local outside a repository"))
1636 paths = [repo.vfs.join('hgrc')]
1637 paths = [repo.vfs.join('hgrc')]
1637 elif opts.get('global'):
1638 elif opts.get('global'):
1638 paths = rcutil.systemrcpath()
1639 paths = rcutil.systemrcpath()
1639 else:
1640 else:
1640 paths = rcutil.userrcpath()
1641 paths = rcutil.userrcpath()
1641
1642
1642 for f in paths:
1643 for f in paths:
1643 if os.path.exists(f):
1644 if os.path.exists(f):
1644 break
1645 break
1645 else:
1646 else:
1646 if opts.get('global'):
1647 if opts.get('global'):
1647 samplehgrc = uimod.samplehgrcs['global']
1648 samplehgrc = uimod.samplehgrcs['global']
1648 elif opts.get('local'):
1649 elif opts.get('local'):
1649 samplehgrc = uimod.samplehgrcs['local']
1650 samplehgrc = uimod.samplehgrcs['local']
1650 else:
1651 else:
1651 samplehgrc = uimod.samplehgrcs['user']
1652 samplehgrc = uimod.samplehgrcs['user']
1652
1653
1653 f = paths[0]
1654 f = paths[0]
1654 fp = open(f, "wb")
1655 fp = open(f, "wb")
1655 fp.write(util.tonativeeol(samplehgrc))
1656 fp.write(util.tonativeeol(samplehgrc))
1656 fp.close()
1657 fp.close()
1657
1658
1658 editor = ui.geteditor()
1659 editor = ui.geteditor()
1659 ui.system("%s \"%s\"" % (editor, f),
1660 ui.system("%s \"%s\"" % (editor, f),
1660 onerr=error.Abort, errprefix=_("edit failed"),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1661 blockedtag='config_edit')
1662 blockedtag='config_edit')
1662 return
1663 return
1663 ui.pager('config')
1664 ui.pager('config')
1664 fm = ui.formatter('config', opts)
1665 fm = ui.formatter('config', opts)
1665 for t, f in rcutil.rccomponents():
1666 for t, f in rcutil.rccomponents():
1666 if t == 'path':
1667 if t == 'path':
1667 ui.debug('read config from: %s\n' % f)
1668 ui.debug('read config from: %s\n' % f)
1668 elif t == 'items':
1669 elif t == 'items':
1669 for section, name, value, source in f:
1670 for section, name, value, source in f:
1670 ui.debug('set config by: %s\n' % source)
1671 ui.debug('set config by: %s\n' % source)
1671 else:
1672 else:
1672 raise error.ProgrammingError('unknown rctype: %s' % t)
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1673 untrusted = bool(opts.get('untrusted'))
1674 untrusted = bool(opts.get('untrusted'))
1674 if values:
1675 if values:
1675 sections = [v for v in values if '.' not in v]
1676 sections = [v for v in values if '.' not in v]
1676 items = [v for v in values if '.' in v]
1677 items = [v for v in values if '.' in v]
1677 if len(items) > 1 or items and sections:
1678 if len(items) > 1 or items and sections:
1678 raise error.Abort(_('only one config item permitted'))
1679 raise error.Abort(_('only one config item permitted'))
1679 matched = False
1680 matched = False
1680 for section, name, value in ui.walkconfig(untrusted=untrusted):
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1681 source = ui.configsource(section, name, untrusted)
1682 source = ui.configsource(section, name, untrusted)
1682 value = pycompat.bytestr(value)
1683 value = pycompat.bytestr(value)
1683 if fm.isplain():
1684 if fm.isplain():
1684 source = source or 'none'
1685 source = source or 'none'
1685 value = value.replace('\n', '\\n')
1686 value = value.replace('\n', '\\n')
1686 entryname = section + '.' + name
1687 entryname = section + '.' + name
1687 if values:
1688 if values:
1688 for v in values:
1689 for v in values:
1689 if v == section:
1690 if v == section:
1690 fm.startitem()
1691 fm.startitem()
1691 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1692 fm.write('name value', '%s=%s\n', entryname, value)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1693 matched = True
1694 matched = True
1694 elif v == entryname:
1695 elif v == entryname:
1695 fm.startitem()
1696 fm.startitem()
1696 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1697 fm.write('value', '%s\n', value)
1698 fm.write('value', '%s\n', value)
1698 fm.data(name=entryname)
1699 fm.data(name=entryname)
1699 matched = True
1700 matched = True
1700 else:
1701 else:
1701 fm.startitem()
1702 fm.startitem()
1702 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1703 fm.write('name value', '%s=%s\n', entryname, value)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1704 matched = True
1705 matched = True
1705 fm.end()
1706 fm.end()
1706 if matched:
1707 if matched:
1707 return 0
1708 return 0
1708 return 1
1709 return 1
1709
1710
1710 @command('copy|cp',
1711 @command('copy|cp',
1711 [('A', 'after', None, _('record a copy that has already occurred')),
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1712 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1713 ] + walkopts + dryrunopts,
1714 ] + walkopts + dryrunopts,
1714 _('[OPTION]... [SOURCE]... DEST'))
1715 _('[OPTION]... [SOURCE]... DEST'))
1715 def copy(ui, repo, *pats, **opts):
1716 def copy(ui, repo, *pats, **opts):
1716 """mark files as copied for the next commit
1717 """mark files as copied for the next commit
1717
1718
1718 Mark dest as having copies of source files. If dest is a
1719 Mark dest as having copies of source files. If dest is a
1719 directory, copies are put in that directory. If dest is a file,
1720 directory, copies are put in that directory. If dest is a file,
1720 the source must be a single file.
1721 the source must be a single file.
1721
1722
1722 By default, this command copies the contents of files as they
1723 By default, this command copies the contents of files as they
1723 exist in the working directory. If invoked with -A/--after, the
1724 exist in the working directory. If invoked with -A/--after, the
1724 operation is recorded, but no copying is performed.
1725 operation is recorded, but no copying is performed.
1725
1726
1726 This command takes effect with the next commit. To undo a copy
1727 This command takes effect with the next commit. To undo a copy
1727 before that, see :hg:`revert`.
1728 before that, see :hg:`revert`.
1728
1729
1729 Returns 0 on success, 1 if errors are encountered.
1730 Returns 0 on success, 1 if errors are encountered.
1730 """
1731 """
1731 opts = pycompat.byteskwargs(opts)
1732 opts = pycompat.byteskwargs(opts)
1732 with repo.wlock(False):
1733 with repo.wlock(False):
1733 return cmdutil.copy(ui, repo, pats, opts)
1734 return cmdutil.copy(ui, repo, pats, opts)
1734
1735
1735 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1736 def debugcommands(ui, cmd='', *args):
1737 def debugcommands(ui, cmd='', *args):
1737 """list all available commands and options"""
1738 """list all available commands and options"""
1738 for cmd, vals in sorted(table.iteritems()):
1739 for cmd, vals in sorted(table.iteritems()):
1739 cmd = cmd.split('|')[0].strip('^')
1740 cmd = cmd.split('|')[0].strip('^')
1740 opts = ', '.join([i[1] for i in vals[1]])
1741 opts = ', '.join([i[1] for i in vals[1]])
1741 ui.write('%s: %s\n' % (cmd, opts))
1742 ui.write('%s: %s\n' % (cmd, opts))
1742
1743
1743 @command('debugcomplete',
1744 @command('debugcomplete',
1744 [('o', 'options', None, _('show the command options'))],
1745 [('o', 'options', None, _('show the command options'))],
1745 _('[-o] CMD'),
1746 _('[-o] CMD'),
1746 norepo=True)
1747 norepo=True)
1747 def debugcomplete(ui, cmd='', **opts):
1748 def debugcomplete(ui, cmd='', **opts):
1748 """returns the completion list associated with the given command"""
1749 """returns the completion list associated with the given command"""
1749
1750
1750 if opts.get(r'options'):
1751 if opts.get(r'options'):
1751 options = []
1752 options = []
1752 otables = [globalopts]
1753 otables = [globalopts]
1753 if cmd:
1754 if cmd:
1754 aliases, entry = cmdutil.findcmd(cmd, table, False)
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1755 otables.append(entry[1])
1756 otables.append(entry[1])
1756 for t in otables:
1757 for t in otables:
1757 for o in t:
1758 for o in t:
1758 if "(DEPRECATED)" in o[3]:
1759 if "(DEPRECATED)" in o[3]:
1759 continue
1760 continue
1760 if o[0]:
1761 if o[0]:
1761 options.append('-%s' % o[0])
1762 options.append('-%s' % o[0])
1762 options.append('--%s' % o[1])
1763 options.append('--%s' % o[1])
1763 ui.write("%s\n" % "\n".join(options))
1764 ui.write("%s\n" % "\n".join(options))
1764 return
1765 return
1765
1766
1766 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1767 if ui.verbose:
1768 if ui.verbose:
1768 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1769 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1770
1771
1771 @command('^diff',
1772 @command('^diff',
1772 [('r', 'rev', [], _('revision'), _('REV')),
1773 [('r', 'rev', [], _('revision'), _('REV')),
1773 ('c', 'change', '', _('change made by revision'), _('REV'))
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1774 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1775 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1776 inferrepo=True, cmdtype=readonly)
1777 inferrepo=True, cmdtype=readonly)
1777 def diff(ui, repo, *pats, **opts):
1778 def diff(ui, repo, *pats, **opts):
1778 """diff repository (or selected files)
1779 """diff repository (or selected files)
1779
1780
1780 Show differences between revisions for the specified files.
1781 Show differences between revisions for the specified files.
1781
1782
1782 Differences between files are shown using the unified diff format.
1783 Differences between files are shown using the unified diff format.
1783
1784
1784 .. note::
1785 .. note::
1785
1786
1786 :hg:`diff` may generate unexpected results for merges, as it will
1787 :hg:`diff` may generate unexpected results for merges, as it will
1787 default to comparing against the working directory's first
1788 default to comparing against the working directory's first
1788 parent changeset if no revisions are specified.
1789 parent changeset if no revisions are specified.
1789
1790
1790 When two revision arguments are given, then changes are shown
1791 When two revision arguments are given, then changes are shown
1791 between those revisions. If only one revision is specified then
1792 between those revisions. If only one revision is specified then
1792 that revision is compared to the working directory, and, when no
1793 that revision is compared to the working directory, and, when no
1793 revisions are specified, the working directory files are compared
1794 revisions are specified, the working directory files are compared
1794 to its first parent.
1795 to its first parent.
1795
1796
1796 Alternatively you can specify -c/--change with a revision to see
1797 Alternatively you can specify -c/--change with a revision to see
1797 the changes in that changeset relative to its first parent.
1798 the changes in that changeset relative to its first parent.
1798
1799
1799 Without the -a/--text option, diff will avoid generating diffs of
1800 Without the -a/--text option, diff will avoid generating diffs of
1800 files it detects as binary. With -a, diff will generate a diff
1801 files it detects as binary. With -a, diff will generate a diff
1801 anyway, probably with undesirable results.
1802 anyway, probably with undesirable results.
1802
1803
1803 Use the -g/--git option to generate diffs in the git extended diff
1804 Use the -g/--git option to generate diffs in the git extended diff
1804 format. For more information, read :hg:`help diffs`.
1805 format. For more information, read :hg:`help diffs`.
1805
1806
1806 .. container:: verbose
1807 .. container:: verbose
1807
1808
1808 Examples:
1809 Examples:
1809
1810
1810 - compare a file in the current working directory to its parent::
1811 - compare a file in the current working directory to its parent::
1811
1812
1812 hg diff foo.c
1813 hg diff foo.c
1813
1814
1814 - compare two historical versions of a directory, with rename info::
1815 - compare two historical versions of a directory, with rename info::
1815
1816
1816 hg diff --git -r 1.0:1.2 lib/
1817 hg diff --git -r 1.0:1.2 lib/
1817
1818
1818 - get change stats relative to the last change on some date::
1819 - get change stats relative to the last change on some date::
1819
1820
1820 hg diff --stat -r "date('may 2')"
1821 hg diff --stat -r "date('may 2')"
1821
1822
1822 - diff all newly-added files that contain a keyword::
1823 - diff all newly-added files that contain a keyword::
1823
1824
1824 hg diff "set:added() and grep(GNU)"
1825 hg diff "set:added() and grep(GNU)"
1825
1826
1826 - compare a revision and its parents::
1827 - compare a revision and its parents::
1827
1828
1828 hg diff -c 9353 # compare against first parent
1829 hg diff -c 9353 # compare against first parent
1829 hg diff -r 9353^:9353 # same using revset syntax
1830 hg diff -r 9353^:9353 # same using revset syntax
1830 hg diff -r 9353^2:9353 # compare against the second parent
1831 hg diff -r 9353^2:9353 # compare against the second parent
1831
1832
1832 Returns 0 on success.
1833 Returns 0 on success.
1833 """
1834 """
1834
1835
1835 opts = pycompat.byteskwargs(opts)
1836 opts = pycompat.byteskwargs(opts)
1836 revs = opts.get('rev')
1837 revs = opts.get('rev')
1837 change = opts.get('change')
1838 change = opts.get('change')
1838 stat = opts.get('stat')
1839 stat = opts.get('stat')
1839 reverse = opts.get('reverse')
1840 reverse = opts.get('reverse')
1840
1841
1841 if revs and change:
1842 if revs and change:
1842 msg = _('cannot specify --rev and --change at the same time')
1843 msg = _('cannot specify --rev and --change at the same time')
1843 raise error.Abort(msg)
1844 raise error.Abort(msg)
1844 elif change:
1845 elif change:
1845 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1846 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1846 node2 = scmutil.revsingle(repo, change, None).node()
1847 node2 = scmutil.revsingle(repo, change, None).node()
1847 node1 = repo[node2].p1().node()
1848 node1 = repo[node2].p1().node()
1848 else:
1849 else:
1849 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1850 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1850 node1, node2 = scmutil.revpair(repo, revs)
1851 node1, node2 = scmutil.revpair(repo, revs)
1851
1852
1852 if reverse:
1853 if reverse:
1853 node1, node2 = node2, node1
1854 node1, node2 = node2, node1
1854
1855
1855 diffopts = patch.diffallopts(ui, opts)
1856 diffopts = patch.diffallopts(ui, opts)
1856 m = scmutil.match(repo[node2], pats, opts)
1857 m = scmutil.match(repo[node2], pats, opts)
1857 ui.pager('diff')
1858 ui.pager('diff')
1858 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1859 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1859 listsubrepos=opts.get('subrepos'),
1860 listsubrepos=opts.get('subrepos'),
1860 root=opts.get('root'))
1861 root=opts.get('root'))
1861
1862
1862 @command('^export',
1863 @command('^export',
1863 [('o', 'output', '',
1864 [('o', 'output', '',
1864 _('print output to file with formatted name'), _('FORMAT')),
1865 _('print output to file with formatted name'), _('FORMAT')),
1865 ('', 'switch-parent', None, _('diff against the second parent')),
1866 ('', 'switch-parent', None, _('diff against the second parent')),
1866 ('r', 'rev', [], _('revisions to export'), _('REV')),
1867 ('r', 'rev', [], _('revisions to export'), _('REV')),
1867 ] + diffopts,
1868 ] + diffopts,
1868 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1869 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1869 def export(ui, repo, *changesets, **opts):
1870 def export(ui, repo, *changesets, **opts):
1870 """dump the header and diffs for one or more changesets
1871 """dump the header and diffs for one or more changesets
1871
1872
1872 Print the changeset header and diffs for one or more revisions.
1873 Print the changeset header and diffs for one or more revisions.
1873 If no revision is given, the parent of the working directory is used.
1874 If no revision is given, the parent of the working directory is used.
1874
1875
1875 The information shown in the changeset header is: author, date,
1876 The information shown in the changeset header is: author, date,
1876 branch name (if non-default), changeset hash, parent(s) and commit
1877 branch name (if non-default), changeset hash, parent(s) and commit
1877 comment.
1878 comment.
1878
1879
1879 .. note::
1880 .. note::
1880
1881
1881 :hg:`export` may generate unexpected diff output for merge
1882 :hg:`export` may generate unexpected diff output for merge
1882 changesets, as it will compare the merge changeset against its
1883 changesets, as it will compare the merge changeset against its
1883 first parent only.
1884 first parent only.
1884
1885
1885 Output may be to a file, in which case the name of the file is
1886 Output may be to a file, in which case the name of the file is
1886 given using a format string. The formatting rules are as follows:
1887 given using a format string. The formatting rules are as follows:
1887
1888
1888 :``%%``: literal "%" character
1889 :``%%``: literal "%" character
1889 :``%H``: changeset hash (40 hexadecimal digits)
1890 :``%H``: changeset hash (40 hexadecimal digits)
1890 :``%N``: number of patches being generated
1891 :``%N``: number of patches being generated
1891 :``%R``: changeset revision number
1892 :``%R``: changeset revision number
1892 :``%b``: basename of the exporting repository
1893 :``%b``: basename of the exporting repository
1893 :``%h``: short-form changeset hash (12 hexadecimal digits)
1894 :``%h``: short-form changeset hash (12 hexadecimal digits)
1894 :``%m``: first line of the commit message (only alphanumeric characters)
1895 :``%m``: first line of the commit message (only alphanumeric characters)
1895 :``%n``: zero-padded sequence number, starting at 1
1896 :``%n``: zero-padded sequence number, starting at 1
1896 :``%r``: zero-padded changeset revision number
1897 :``%r``: zero-padded changeset revision number
1897
1898
1898 Without the -a/--text option, export will avoid generating diffs
1899 Without the -a/--text option, export will avoid generating diffs
1899 of files it detects as binary. With -a, export will generate a
1900 of files it detects as binary. With -a, export will generate a
1900 diff anyway, probably with undesirable results.
1901 diff anyway, probably with undesirable results.
1901
1902
1902 Use the -g/--git option to generate diffs in the git extended diff
1903 Use the -g/--git option to generate diffs in the git extended diff
1903 format. See :hg:`help diffs` for more information.
1904 format. See :hg:`help diffs` for more information.
1904
1905
1905 With the --switch-parent option, the diff will be against the
1906 With the --switch-parent option, the diff will be against the
1906 second parent. It can be useful to review a merge.
1907 second parent. It can be useful to review a merge.
1907
1908
1908 .. container:: verbose
1909 .. container:: verbose
1909
1910
1910 Examples:
1911 Examples:
1911
1912
1912 - use export and import to transplant a bugfix to the current
1913 - use export and import to transplant a bugfix to the current
1913 branch::
1914 branch::
1914
1915
1915 hg export -r 9353 | hg import -
1916 hg export -r 9353 | hg import -
1916
1917
1917 - export all the changesets between two revisions to a file with
1918 - export all the changesets between two revisions to a file with
1918 rename information::
1919 rename information::
1919
1920
1920 hg export --git -r 123:150 > changes.txt
1921 hg export --git -r 123:150 > changes.txt
1921
1922
1922 - split outgoing changes into a series of patches with
1923 - split outgoing changes into a series of patches with
1923 descriptive names::
1924 descriptive names::
1924
1925
1925 hg export -r "outgoing()" -o "%n-%m.patch"
1926 hg export -r "outgoing()" -o "%n-%m.patch"
1926
1927
1927 Returns 0 on success.
1928 Returns 0 on success.
1928 """
1929 """
1929 opts = pycompat.byteskwargs(opts)
1930 opts = pycompat.byteskwargs(opts)
1930 changesets += tuple(opts.get('rev', []))
1931 changesets += tuple(opts.get('rev', []))
1931 if not changesets:
1932 if not changesets:
1932 changesets = ['.']
1933 changesets = ['.']
1933 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1934 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1934 revs = scmutil.revrange(repo, changesets)
1935 revs = scmutil.revrange(repo, changesets)
1935 if not revs:
1936 if not revs:
1936 raise error.Abort(_("export requires at least one changeset"))
1937 raise error.Abort(_("export requires at least one changeset"))
1937 if len(revs) > 1:
1938 if len(revs) > 1:
1938 ui.note(_('exporting patches:\n'))
1939 ui.note(_('exporting patches:\n'))
1939 else:
1940 else:
1940 ui.note(_('exporting patch:\n'))
1941 ui.note(_('exporting patch:\n'))
1941 ui.pager('export')
1942 ui.pager('export')
1942 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1943 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1943 switch_parent=opts.get('switch_parent'),
1944 switch_parent=opts.get('switch_parent'),
1944 opts=patch.diffallopts(ui, opts))
1945 opts=patch.diffallopts(ui, opts))
1945
1946
1946 @command('files',
1947 @command('files',
1947 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1948 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1948 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1949 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1949 ] + walkopts + formatteropts + subrepoopts,
1950 ] + walkopts + formatteropts + subrepoopts,
1950 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1951 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1951 def files(ui, repo, *pats, **opts):
1952 def files(ui, repo, *pats, **opts):
1952 """list tracked files
1953 """list tracked files
1953
1954
1954 Print files under Mercurial control in the working directory or
1955 Print files under Mercurial control in the working directory or
1955 specified revision for given files (excluding removed files).
1956 specified revision for given files (excluding removed files).
1956 Files can be specified as filenames or filesets.
1957 Files can be specified as filenames or filesets.
1957
1958
1958 If no files are given to match, this command prints the names
1959 If no files are given to match, this command prints the names
1959 of all files under Mercurial control.
1960 of all files under Mercurial control.
1960
1961
1961 .. container:: verbose
1962 .. container:: verbose
1962
1963
1963 Examples:
1964 Examples:
1964
1965
1965 - list all files under the current directory::
1966 - list all files under the current directory::
1966
1967
1967 hg files .
1968 hg files .
1968
1969
1969 - shows sizes and flags for current revision::
1970 - shows sizes and flags for current revision::
1970
1971
1971 hg files -vr .
1972 hg files -vr .
1972
1973
1973 - list all files named README::
1974 - list all files named README::
1974
1975
1975 hg files -I "**/README"
1976 hg files -I "**/README"
1976
1977
1977 - list all binary files::
1978 - list all binary files::
1978
1979
1979 hg files "set:binary()"
1980 hg files "set:binary()"
1980
1981
1981 - find files containing a regular expression::
1982 - find files containing a regular expression::
1982
1983
1983 hg files "set:grep('bob')"
1984 hg files "set:grep('bob')"
1984
1985
1985 - search tracked file contents with xargs and grep::
1986 - search tracked file contents with xargs and grep::
1986
1987
1987 hg files -0 | xargs -0 grep foo
1988 hg files -0 | xargs -0 grep foo
1988
1989
1989 See :hg:`help patterns` and :hg:`help filesets` for more information
1990 See :hg:`help patterns` and :hg:`help filesets` for more information
1990 on specifying file patterns.
1991 on specifying file patterns.
1991
1992
1992 Returns 0 if a match is found, 1 otherwise.
1993 Returns 0 if a match is found, 1 otherwise.
1993
1994
1994 """
1995 """
1995
1996
1996 opts = pycompat.byteskwargs(opts)
1997 opts = pycompat.byteskwargs(opts)
1997 rev = opts.get('rev')
1998 rev = opts.get('rev')
1998 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1999 if rev:
2000 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1999 ctx = scmutil.revsingle(repo, rev, None)
2001 ctx = scmutil.revsingle(repo, rev, None)
2000
2002
2001 end = '\n'
2003 end = '\n'
2002 if opts.get('print0'):
2004 if opts.get('print0'):
2003 end = '\0'
2005 end = '\0'
2004 fmt = '%s' + end
2006 fmt = '%s' + end
2005
2007
2006 m = scmutil.match(ctx, pats, opts)
2008 m = scmutil.match(ctx, pats, opts)
2007 ui.pager('files')
2009 ui.pager('files')
2008 with ui.formatter('files', opts) as fm:
2010 with ui.formatter('files', opts) as fm:
2009 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2011 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2010
2012
2011 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2013 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2012 def forget(ui, repo, *pats, **opts):
2014 def forget(ui, repo, *pats, **opts):
2013 """forget the specified files on the next commit
2015 """forget the specified files on the next commit
2014
2016
2015 Mark the specified files so they will no longer be tracked
2017 Mark the specified files so they will no longer be tracked
2016 after the next commit.
2018 after the next commit.
2017
2019
2018 This only removes files from the current branch, not from the
2020 This only removes files from the current branch, not from the
2019 entire project history, and it does not delete them from the
2021 entire project history, and it does not delete them from the
2020 working directory.
2022 working directory.
2021
2023
2022 To delete the file from the working directory, see :hg:`remove`.
2024 To delete the file from the working directory, see :hg:`remove`.
2023
2025
2024 To undo a forget before the next commit, see :hg:`add`.
2026 To undo a forget before the next commit, see :hg:`add`.
2025
2027
2026 .. container:: verbose
2028 .. container:: verbose
2027
2029
2028 Examples:
2030 Examples:
2029
2031
2030 - forget newly-added binary files::
2032 - forget newly-added binary files::
2031
2033
2032 hg forget "set:added() and binary()"
2034 hg forget "set:added() and binary()"
2033
2035
2034 - forget files that would be excluded by .hgignore::
2036 - forget files that would be excluded by .hgignore::
2035
2037
2036 hg forget "set:hgignore()"
2038 hg forget "set:hgignore()"
2037
2039
2038 Returns 0 on success.
2040 Returns 0 on success.
2039 """
2041 """
2040
2042
2041 opts = pycompat.byteskwargs(opts)
2043 opts = pycompat.byteskwargs(opts)
2042 if not pats:
2044 if not pats:
2043 raise error.Abort(_('no files specified'))
2045 raise error.Abort(_('no files specified'))
2044
2046
2045 m = scmutil.match(repo[None], pats, opts)
2047 m = scmutil.match(repo[None], pats, opts)
2046 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2047 return rejected and 1 or 0
2049 return rejected and 1 or 0
2048
2050
2049 @command(
2051 @command(
2050 'graft',
2052 'graft',
2051 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2052 ('c', 'continue', False, _('resume interrupted graft')),
2054 ('c', 'continue', False, _('resume interrupted graft')),
2053 ('e', 'edit', False, _('invoke editor on commit messages')),
2055 ('e', 'edit', False, _('invoke editor on commit messages')),
2054 ('', 'log', None, _('append graft info to log message')),
2056 ('', 'log', None, _('append graft info to log message')),
2055 ('f', 'force', False, _('force graft')),
2057 ('f', 'force', False, _('force graft')),
2056 ('D', 'currentdate', False,
2058 ('D', 'currentdate', False,
2057 _('record the current date as commit date')),
2059 _('record the current date as commit date')),
2058 ('U', 'currentuser', False,
2060 ('U', 'currentuser', False,
2059 _('record the current user as committer'), _('DATE'))]
2061 _('record the current user as committer'), _('DATE'))]
2060 + commitopts2 + mergetoolopts + dryrunopts,
2062 + commitopts2 + mergetoolopts + dryrunopts,
2061 _('[OPTION]... [-r REV]... REV...'))
2063 _('[OPTION]... [-r REV]... REV...'))
2062 def graft(ui, repo, *revs, **opts):
2064 def graft(ui, repo, *revs, **opts):
2063 '''copy changes from other branches onto the current branch
2065 '''copy changes from other branches onto the current branch
2064
2066
2065 This command uses Mercurial's merge logic to copy individual
2067 This command uses Mercurial's merge logic to copy individual
2066 changes from other branches without merging branches in the
2068 changes from other branches without merging branches in the
2067 history graph. This is sometimes known as 'backporting' or
2069 history graph. This is sometimes known as 'backporting' or
2068 'cherry-picking'. By default, graft will copy user, date, and
2070 'cherry-picking'. By default, graft will copy user, date, and
2069 description from the source changesets.
2071 description from the source changesets.
2070
2072
2071 Changesets that are ancestors of the current revision, that have
2073 Changesets that are ancestors of the current revision, that have
2072 already been grafted, or that are merges will be skipped.
2074 already been grafted, or that are merges will be skipped.
2073
2075
2074 If --log is specified, log messages will have a comment appended
2076 If --log is specified, log messages will have a comment appended
2075 of the form::
2077 of the form::
2076
2078
2077 (grafted from CHANGESETHASH)
2079 (grafted from CHANGESETHASH)
2078
2080
2079 If --force is specified, revisions will be grafted even if they
2081 If --force is specified, revisions will be grafted even if they
2080 are already ancestors of, or have been grafted to, the destination.
2082 are already ancestors of, or have been grafted to, the destination.
2081 This is useful when the revisions have since been backed out.
2083 This is useful when the revisions have since been backed out.
2082
2084
2083 If a graft merge results in conflicts, the graft process is
2085 If a graft merge results in conflicts, the graft process is
2084 interrupted so that the current merge can be manually resolved.
2086 interrupted so that the current merge can be manually resolved.
2085 Once all conflicts are addressed, the graft process can be
2087 Once all conflicts are addressed, the graft process can be
2086 continued with the -c/--continue option.
2088 continued with the -c/--continue option.
2087
2089
2088 .. note::
2090 .. note::
2089
2091
2090 The -c/--continue option does not reapply earlier options, except
2092 The -c/--continue option does not reapply earlier options, except
2091 for --force.
2093 for --force.
2092
2094
2093 .. container:: verbose
2095 .. container:: verbose
2094
2096
2095 Examples:
2097 Examples:
2096
2098
2097 - copy a single change to the stable branch and edit its description::
2099 - copy a single change to the stable branch and edit its description::
2098
2100
2099 hg update stable
2101 hg update stable
2100 hg graft --edit 9393
2102 hg graft --edit 9393
2101
2103
2102 - graft a range of changesets with one exception, updating dates::
2104 - graft a range of changesets with one exception, updating dates::
2103
2105
2104 hg graft -D "2085::2093 and not 2091"
2106 hg graft -D "2085::2093 and not 2091"
2105
2107
2106 - continue a graft after resolving conflicts::
2108 - continue a graft after resolving conflicts::
2107
2109
2108 hg graft -c
2110 hg graft -c
2109
2111
2110 - show the source of a grafted changeset::
2112 - show the source of a grafted changeset::
2111
2113
2112 hg log --debug -r .
2114 hg log --debug -r .
2113
2115
2114 - show revisions sorted by date::
2116 - show revisions sorted by date::
2115
2117
2116 hg log -r "sort(all(), date)"
2118 hg log -r "sort(all(), date)"
2117
2119
2118 See :hg:`help revisions` for more about specifying revisions.
2120 See :hg:`help revisions` for more about specifying revisions.
2119
2121
2120 Returns 0 on successful completion.
2122 Returns 0 on successful completion.
2121 '''
2123 '''
2122 with repo.wlock():
2124 with repo.wlock():
2123 return _dograft(ui, repo, *revs, **opts)
2125 return _dograft(ui, repo, *revs, **opts)
2124
2126
2125 def _dograft(ui, repo, *revs, **opts):
2127 def _dograft(ui, repo, *revs, **opts):
2126 opts = pycompat.byteskwargs(opts)
2128 opts = pycompat.byteskwargs(opts)
2127 if revs and opts.get('rev'):
2129 if revs and opts.get('rev'):
2128 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2130 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2129 'revision ordering!\n'))
2131 'revision ordering!\n'))
2130
2132
2131 revs = list(revs)
2133 revs = list(revs)
2132 revs.extend(opts.get('rev'))
2134 revs.extend(opts.get('rev'))
2133
2135
2134 if not opts.get('user') and opts.get('currentuser'):
2136 if not opts.get('user') and opts.get('currentuser'):
2135 opts['user'] = ui.username()
2137 opts['user'] = ui.username()
2136 if not opts.get('date') and opts.get('currentdate'):
2138 if not opts.get('date') and opts.get('currentdate'):
2137 opts['date'] = "%d %d" % util.makedate()
2139 opts['date'] = "%d %d" % util.makedate()
2138
2140
2139 editor = cmdutil.getcommiteditor(editform='graft',
2141 editor = cmdutil.getcommiteditor(editform='graft',
2140 **pycompat.strkwargs(opts))
2142 **pycompat.strkwargs(opts))
2141
2143
2142 cont = False
2144 cont = False
2143 if opts.get('continue'):
2145 if opts.get('continue'):
2144 cont = True
2146 cont = True
2145 if revs:
2147 if revs:
2146 raise error.Abort(_("can't specify --continue and revisions"))
2148 raise error.Abort(_("can't specify --continue and revisions"))
2147 # read in unfinished revisions
2149 # read in unfinished revisions
2148 try:
2150 try:
2149 nodes = repo.vfs.read('graftstate').splitlines()
2151 nodes = repo.vfs.read('graftstate').splitlines()
2150 revs = [repo[node].rev() for node in nodes]
2152 revs = [repo[node].rev() for node in nodes]
2151 except IOError as inst:
2153 except IOError as inst:
2152 if inst.errno != errno.ENOENT:
2154 if inst.errno != errno.ENOENT:
2153 raise
2155 raise
2154 cmdutil.wrongtooltocontinue(repo, _('graft'))
2156 cmdutil.wrongtooltocontinue(repo, _('graft'))
2155 else:
2157 else:
2156 cmdutil.checkunfinished(repo)
2158 cmdutil.checkunfinished(repo)
2157 cmdutil.bailifchanged(repo)
2159 cmdutil.bailifchanged(repo)
2158 if not revs:
2160 if not revs:
2159 raise error.Abort(_('no revisions specified'))
2161 raise error.Abort(_('no revisions specified'))
2160 revs = scmutil.revrange(repo, revs)
2162 revs = scmutil.revrange(repo, revs)
2161
2163
2162 skipped = set()
2164 skipped = set()
2163 # check for merges
2165 # check for merges
2164 for rev in repo.revs('%ld and merge()', revs):
2166 for rev in repo.revs('%ld and merge()', revs):
2165 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2167 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2166 skipped.add(rev)
2168 skipped.add(rev)
2167 revs = [r for r in revs if r not in skipped]
2169 revs = [r for r in revs if r not in skipped]
2168 if not revs:
2170 if not revs:
2169 return -1
2171 return -1
2170
2172
2171 # Don't check in the --continue case, in effect retaining --force across
2173 # Don't check in the --continue case, in effect retaining --force across
2172 # --continues. That's because without --force, any revisions we decided to
2174 # --continues. That's because without --force, any revisions we decided to
2173 # skip would have been filtered out here, so they wouldn't have made their
2175 # skip would have been filtered out here, so they wouldn't have made their
2174 # way to the graftstate. With --force, any revisions we would have otherwise
2176 # way to the graftstate. With --force, any revisions we would have otherwise
2175 # skipped would not have been filtered out, and if they hadn't been applied
2177 # skipped would not have been filtered out, and if they hadn't been applied
2176 # already, they'd have been in the graftstate.
2178 # already, they'd have been in the graftstate.
2177 if not (cont or opts.get('force')):
2179 if not (cont or opts.get('force')):
2178 # check for ancestors of dest branch
2180 # check for ancestors of dest branch
2179 crev = repo['.'].rev()
2181 crev = repo['.'].rev()
2180 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2182 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2181 # XXX make this lazy in the future
2183 # XXX make this lazy in the future
2182 # don't mutate while iterating, create a copy
2184 # don't mutate while iterating, create a copy
2183 for rev in list(revs):
2185 for rev in list(revs):
2184 if rev in ancestors:
2186 if rev in ancestors:
2185 ui.warn(_('skipping ancestor revision %d:%s\n') %
2187 ui.warn(_('skipping ancestor revision %d:%s\n') %
2186 (rev, repo[rev]))
2188 (rev, repo[rev]))
2187 # XXX remove on list is slow
2189 # XXX remove on list is slow
2188 revs.remove(rev)
2190 revs.remove(rev)
2189 if not revs:
2191 if not revs:
2190 return -1
2192 return -1
2191
2193
2192 # analyze revs for earlier grafts
2194 # analyze revs for earlier grafts
2193 ids = {}
2195 ids = {}
2194 for ctx in repo.set("%ld", revs):
2196 for ctx in repo.set("%ld", revs):
2195 ids[ctx.hex()] = ctx.rev()
2197 ids[ctx.hex()] = ctx.rev()
2196 n = ctx.extra().get('source')
2198 n = ctx.extra().get('source')
2197 if n:
2199 if n:
2198 ids[n] = ctx.rev()
2200 ids[n] = ctx.rev()
2199
2201
2200 # check ancestors for earlier grafts
2202 # check ancestors for earlier grafts
2201 ui.debug('scanning for duplicate grafts\n')
2203 ui.debug('scanning for duplicate grafts\n')
2202
2204
2203 # The only changesets we can be sure doesn't contain grafts of any
2205 # The only changesets we can be sure doesn't contain grafts of any
2204 # revs, are the ones that are common ancestors of *all* revs:
2206 # revs, are the ones that are common ancestors of *all* revs:
2205 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2207 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2206 ctx = repo[rev]
2208 ctx = repo[rev]
2207 n = ctx.extra().get('source')
2209 n = ctx.extra().get('source')
2208 if n in ids:
2210 if n in ids:
2209 try:
2211 try:
2210 r = repo[n].rev()
2212 r = repo[n].rev()
2211 except error.RepoLookupError:
2213 except error.RepoLookupError:
2212 r = None
2214 r = None
2213 if r in revs:
2215 if r in revs:
2214 ui.warn(_('skipping revision %d:%s '
2216 ui.warn(_('skipping revision %d:%s '
2215 '(already grafted to %d:%s)\n')
2217 '(already grafted to %d:%s)\n')
2216 % (r, repo[r], rev, ctx))
2218 % (r, repo[r], rev, ctx))
2217 revs.remove(r)
2219 revs.remove(r)
2218 elif ids[n] in revs:
2220 elif ids[n] in revs:
2219 if r is None:
2221 if r is None:
2220 ui.warn(_('skipping already grafted revision %d:%s '
2222 ui.warn(_('skipping already grafted revision %d:%s '
2221 '(%d:%s also has unknown origin %s)\n')
2223 '(%d:%s also has unknown origin %s)\n')
2222 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2224 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2223 else:
2225 else:
2224 ui.warn(_('skipping already grafted revision %d:%s '
2226 ui.warn(_('skipping already grafted revision %d:%s '
2225 '(%d:%s also has origin %d:%s)\n')
2227 '(%d:%s also has origin %d:%s)\n')
2226 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2228 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2227 revs.remove(ids[n])
2229 revs.remove(ids[n])
2228 elif ctx.hex() in ids:
2230 elif ctx.hex() in ids:
2229 r = ids[ctx.hex()]
2231 r = ids[ctx.hex()]
2230 ui.warn(_('skipping already grafted revision %d:%s '
2232 ui.warn(_('skipping already grafted revision %d:%s '
2231 '(was grafted from %d:%s)\n') %
2233 '(was grafted from %d:%s)\n') %
2232 (r, repo[r], rev, ctx))
2234 (r, repo[r], rev, ctx))
2233 revs.remove(r)
2235 revs.remove(r)
2234 if not revs:
2236 if not revs:
2235 return -1
2237 return -1
2236
2238
2237 for pos, ctx in enumerate(repo.set("%ld", revs)):
2239 for pos, ctx in enumerate(repo.set("%ld", revs)):
2238 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2240 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2239 ctx.description().split('\n', 1)[0])
2241 ctx.description().split('\n', 1)[0])
2240 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2242 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2241 if names:
2243 if names:
2242 desc += ' (%s)' % ' '.join(names)
2244 desc += ' (%s)' % ' '.join(names)
2243 ui.status(_('grafting %s\n') % desc)
2245 ui.status(_('grafting %s\n') % desc)
2244 if opts.get('dry_run'):
2246 if opts.get('dry_run'):
2245 continue
2247 continue
2246
2248
2247 source = ctx.extra().get('source')
2249 source = ctx.extra().get('source')
2248 extra = {}
2250 extra = {}
2249 if source:
2251 if source:
2250 extra['source'] = source
2252 extra['source'] = source
2251 extra['intermediate-source'] = ctx.hex()
2253 extra['intermediate-source'] = ctx.hex()
2252 else:
2254 else:
2253 extra['source'] = ctx.hex()
2255 extra['source'] = ctx.hex()
2254 user = ctx.user()
2256 user = ctx.user()
2255 if opts.get('user'):
2257 if opts.get('user'):
2256 user = opts['user']
2258 user = opts['user']
2257 date = ctx.date()
2259 date = ctx.date()
2258 if opts.get('date'):
2260 if opts.get('date'):
2259 date = opts['date']
2261 date = opts['date']
2260 message = ctx.description()
2262 message = ctx.description()
2261 if opts.get('log'):
2263 if opts.get('log'):
2262 message += '\n(grafted from %s)' % ctx.hex()
2264 message += '\n(grafted from %s)' % ctx.hex()
2263
2265
2264 # we don't merge the first commit when continuing
2266 # we don't merge the first commit when continuing
2265 if not cont:
2267 if not cont:
2266 # perform the graft merge with p1(rev) as 'ancestor'
2268 # perform the graft merge with p1(rev) as 'ancestor'
2267 try:
2269 try:
2268 # ui.forcemerge is an internal variable, do not document
2270 # ui.forcemerge is an internal variable, do not document
2269 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2270 'graft')
2272 'graft')
2271 stats = mergemod.graft(repo, ctx, ctx.p1(),
2273 stats = mergemod.graft(repo, ctx, ctx.p1(),
2272 ['local', 'graft'])
2274 ['local', 'graft'])
2273 finally:
2275 finally:
2274 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2276 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2275 # report any conflicts
2277 # report any conflicts
2276 if stats and stats[3] > 0:
2278 if stats and stats[3] > 0:
2277 # write out state for --continue
2279 # write out state for --continue
2278 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2280 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2279 repo.vfs.write('graftstate', ''.join(nodelines))
2281 repo.vfs.write('graftstate', ''.join(nodelines))
2280 extra = ''
2282 extra = ''
2281 if opts.get('user'):
2283 if opts.get('user'):
2282 extra += ' --user %s' % util.shellquote(opts['user'])
2284 extra += ' --user %s' % util.shellquote(opts['user'])
2283 if opts.get('date'):
2285 if opts.get('date'):
2284 extra += ' --date %s' % util.shellquote(opts['date'])
2286 extra += ' --date %s' % util.shellquote(opts['date'])
2285 if opts.get('log'):
2287 if opts.get('log'):
2286 extra += ' --log'
2288 extra += ' --log'
2287 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2289 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2288 raise error.Abort(
2290 raise error.Abort(
2289 _("unresolved conflicts, can't continue"),
2291 _("unresolved conflicts, can't continue"),
2290 hint=hint)
2292 hint=hint)
2291 else:
2293 else:
2292 cont = False
2294 cont = False
2293
2295
2294 # commit
2296 # commit
2295 node = repo.commit(text=message, user=user,
2297 node = repo.commit(text=message, user=user,
2296 date=date, extra=extra, editor=editor)
2298 date=date, extra=extra, editor=editor)
2297 if node is None:
2299 if node is None:
2298 ui.warn(
2300 ui.warn(
2299 _('note: graft of %d:%s created no changes to commit\n') %
2301 _('note: graft of %d:%s created no changes to commit\n') %
2300 (ctx.rev(), ctx))
2302 (ctx.rev(), ctx))
2301
2303
2302 # remove state when we complete successfully
2304 # remove state when we complete successfully
2303 if not opts.get('dry_run'):
2305 if not opts.get('dry_run'):
2304 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2306 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2305
2307
2306 return 0
2308 return 0
2307
2309
2308 @command('grep',
2310 @command('grep',
2309 [('0', 'print0', None, _('end fields with NUL')),
2311 [('0', 'print0', None, _('end fields with NUL')),
2310 ('', 'all', None, _('print all revisions that match')),
2312 ('', 'all', None, _('print all revisions that match')),
2311 ('a', 'text', None, _('treat all files as text')),
2313 ('a', 'text', None, _('treat all files as text')),
2312 ('f', 'follow', None,
2314 ('f', 'follow', None,
2313 _('follow changeset history,'
2315 _('follow changeset history,'
2314 ' or file history across copies and renames')),
2316 ' or file history across copies and renames')),
2315 ('i', 'ignore-case', None, _('ignore case when matching')),
2317 ('i', 'ignore-case', None, _('ignore case when matching')),
2316 ('l', 'files-with-matches', None,
2318 ('l', 'files-with-matches', None,
2317 _('print only filenames and revisions that match')),
2319 _('print only filenames and revisions that match')),
2318 ('n', 'line-number', None, _('print matching line numbers')),
2320 ('n', 'line-number', None, _('print matching line numbers')),
2319 ('r', 'rev', [],
2321 ('r', 'rev', [],
2320 _('only search files changed within revision range'), _('REV')),
2322 _('only search files changed within revision range'), _('REV')),
2321 ('u', 'user', None, _('list the author (long with -v)')),
2323 ('u', 'user', None, _('list the author (long with -v)')),
2322 ('d', 'date', None, _('list the date (short with -q)')),
2324 ('d', 'date', None, _('list the date (short with -q)')),
2323 ] + formatteropts + walkopts,
2325 ] + formatteropts + walkopts,
2324 _('[OPTION]... PATTERN [FILE]...'),
2326 _('[OPTION]... PATTERN [FILE]...'),
2325 inferrepo=True, cmdtype=readonly)
2327 inferrepo=True, cmdtype=readonly)
2326 def grep(ui, repo, pattern, *pats, **opts):
2328 def grep(ui, repo, pattern, *pats, **opts):
2327 """search revision history for a pattern in specified files
2329 """search revision history for a pattern in specified files
2328
2330
2329 Search revision history for a regular expression in the specified
2331 Search revision history for a regular expression in the specified
2330 files or the entire project.
2332 files or the entire project.
2331
2333
2332 By default, grep prints the most recent revision number for each
2334 By default, grep prints the most recent revision number for each
2333 file in which it finds a match. To get it to print every revision
2335 file in which it finds a match. To get it to print every revision
2334 that contains a change in match status ("-" for a match that becomes
2336 that contains a change in match status ("-" for a match that becomes
2335 a non-match, or "+" for a non-match that becomes a match), use the
2337 a non-match, or "+" for a non-match that becomes a match), use the
2336 --all flag.
2338 --all flag.
2337
2339
2338 PATTERN can be any Python (roughly Perl-compatible) regular
2340 PATTERN can be any Python (roughly Perl-compatible) regular
2339 expression.
2341 expression.
2340
2342
2341 If no FILEs are specified (and -f/--follow isn't set), all files in
2343 If no FILEs are specified (and -f/--follow isn't set), all files in
2342 the repository are searched, including those that don't exist in the
2344 the repository are searched, including those that don't exist in the
2343 current branch or have been deleted in a prior changeset.
2345 current branch or have been deleted in a prior changeset.
2344
2346
2345 Returns 0 if a match is found, 1 otherwise.
2347 Returns 0 if a match is found, 1 otherwise.
2346 """
2348 """
2347 opts = pycompat.byteskwargs(opts)
2349 opts = pycompat.byteskwargs(opts)
2348 reflags = re.M
2350 reflags = re.M
2349 if opts.get('ignore_case'):
2351 if opts.get('ignore_case'):
2350 reflags |= re.I
2352 reflags |= re.I
2351 try:
2353 try:
2352 regexp = util.re.compile(pattern, reflags)
2354 regexp = util.re.compile(pattern, reflags)
2353 except re.error as inst:
2355 except re.error as inst:
2354 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2356 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2355 return 1
2357 return 1
2356 sep, eol = ':', '\n'
2358 sep, eol = ':', '\n'
2357 if opts.get('print0'):
2359 if opts.get('print0'):
2358 sep = eol = '\0'
2360 sep = eol = '\0'
2359
2361
2360 getfile = util.lrucachefunc(repo.file)
2362 getfile = util.lrucachefunc(repo.file)
2361
2363
2362 def matchlines(body):
2364 def matchlines(body):
2363 begin = 0
2365 begin = 0
2364 linenum = 0
2366 linenum = 0
2365 while begin < len(body):
2367 while begin < len(body):
2366 match = regexp.search(body, begin)
2368 match = regexp.search(body, begin)
2367 if not match:
2369 if not match:
2368 break
2370 break
2369 mstart, mend = match.span()
2371 mstart, mend = match.span()
2370 linenum += body.count('\n', begin, mstart) + 1
2372 linenum += body.count('\n', begin, mstart) + 1
2371 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2373 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2372 begin = body.find('\n', mend) + 1 or len(body) + 1
2374 begin = body.find('\n', mend) + 1 or len(body) + 1
2373 lend = begin - 1
2375 lend = begin - 1
2374 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2376 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2375
2377
2376 class linestate(object):
2378 class linestate(object):
2377 def __init__(self, line, linenum, colstart, colend):
2379 def __init__(self, line, linenum, colstart, colend):
2378 self.line = line
2380 self.line = line
2379 self.linenum = linenum
2381 self.linenum = linenum
2380 self.colstart = colstart
2382 self.colstart = colstart
2381 self.colend = colend
2383 self.colend = colend
2382
2384
2383 def __hash__(self):
2385 def __hash__(self):
2384 return hash((self.linenum, self.line))
2386 return hash((self.linenum, self.line))
2385
2387
2386 def __eq__(self, other):
2388 def __eq__(self, other):
2387 return self.line == other.line
2389 return self.line == other.line
2388
2390
2389 def findpos(self):
2391 def findpos(self):
2390 """Iterate all (start, end) indices of matches"""
2392 """Iterate all (start, end) indices of matches"""
2391 yield self.colstart, self.colend
2393 yield self.colstart, self.colend
2392 p = self.colend
2394 p = self.colend
2393 while p < len(self.line):
2395 while p < len(self.line):
2394 m = regexp.search(self.line, p)
2396 m = regexp.search(self.line, p)
2395 if not m:
2397 if not m:
2396 break
2398 break
2397 yield m.span()
2399 yield m.span()
2398 p = m.end()
2400 p = m.end()
2399
2401
2400 matches = {}
2402 matches = {}
2401 copies = {}
2403 copies = {}
2402 def grepbody(fn, rev, body):
2404 def grepbody(fn, rev, body):
2403 matches[rev].setdefault(fn, [])
2405 matches[rev].setdefault(fn, [])
2404 m = matches[rev][fn]
2406 m = matches[rev][fn]
2405 for lnum, cstart, cend, line in matchlines(body):
2407 for lnum, cstart, cend, line in matchlines(body):
2406 s = linestate(line, lnum, cstart, cend)
2408 s = linestate(line, lnum, cstart, cend)
2407 m.append(s)
2409 m.append(s)
2408
2410
2409 def difflinestates(a, b):
2411 def difflinestates(a, b):
2410 sm = difflib.SequenceMatcher(None, a, b)
2412 sm = difflib.SequenceMatcher(None, a, b)
2411 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2413 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2412 if tag == 'insert':
2414 if tag == 'insert':
2413 for i in xrange(blo, bhi):
2415 for i in xrange(blo, bhi):
2414 yield ('+', b[i])
2416 yield ('+', b[i])
2415 elif tag == 'delete':
2417 elif tag == 'delete':
2416 for i in xrange(alo, ahi):
2418 for i in xrange(alo, ahi):
2417 yield ('-', a[i])
2419 yield ('-', a[i])
2418 elif tag == 'replace':
2420 elif tag == 'replace':
2419 for i in xrange(alo, ahi):
2421 for i in xrange(alo, ahi):
2420 yield ('-', a[i])
2422 yield ('-', a[i])
2421 for i in xrange(blo, bhi):
2423 for i in xrange(blo, bhi):
2422 yield ('+', b[i])
2424 yield ('+', b[i])
2423
2425
2424 def display(fm, fn, ctx, pstates, states):
2426 def display(fm, fn, ctx, pstates, states):
2425 rev = ctx.rev()
2427 rev = ctx.rev()
2426 if fm.isplain():
2428 if fm.isplain():
2427 formatuser = ui.shortuser
2429 formatuser = ui.shortuser
2428 else:
2430 else:
2429 formatuser = str
2431 formatuser = str
2430 if ui.quiet:
2432 if ui.quiet:
2431 datefmt = '%Y-%m-%d'
2433 datefmt = '%Y-%m-%d'
2432 else:
2434 else:
2433 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2435 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2434 found = False
2436 found = False
2435 @util.cachefunc
2437 @util.cachefunc
2436 def binary():
2438 def binary():
2437 flog = getfile(fn)
2439 flog = getfile(fn)
2438 return util.binary(flog.read(ctx.filenode(fn)))
2440 return util.binary(flog.read(ctx.filenode(fn)))
2439
2441
2440 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2442 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2441 if opts.get('all'):
2443 if opts.get('all'):
2442 iter = difflinestates(pstates, states)
2444 iter = difflinestates(pstates, states)
2443 else:
2445 else:
2444 iter = [('', l) for l in states]
2446 iter = [('', l) for l in states]
2445 for change, l in iter:
2447 for change, l in iter:
2446 fm.startitem()
2448 fm.startitem()
2447 fm.data(node=fm.hexfunc(ctx.node()))
2449 fm.data(node=fm.hexfunc(ctx.node()))
2448 cols = [
2450 cols = [
2449 ('filename', fn, True),
2451 ('filename', fn, True),
2450 ('rev', rev, True),
2452 ('rev', rev, True),
2451 ('linenumber', l.linenum, opts.get('line_number')),
2453 ('linenumber', l.linenum, opts.get('line_number')),
2452 ]
2454 ]
2453 if opts.get('all'):
2455 if opts.get('all'):
2454 cols.append(('change', change, True))
2456 cols.append(('change', change, True))
2455 cols.extend([
2457 cols.extend([
2456 ('user', formatuser(ctx.user()), opts.get('user')),
2458 ('user', formatuser(ctx.user()), opts.get('user')),
2457 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2459 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2458 ])
2460 ])
2459 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2461 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2460 for name, data, cond in cols:
2462 for name, data, cond in cols:
2461 field = fieldnamemap.get(name, name)
2463 field = fieldnamemap.get(name, name)
2462 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2464 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2463 if cond and name != lastcol:
2465 if cond and name != lastcol:
2464 fm.plain(sep, label='grep.sep')
2466 fm.plain(sep, label='grep.sep')
2465 if not opts.get('files_with_matches'):
2467 if not opts.get('files_with_matches'):
2466 fm.plain(sep, label='grep.sep')
2468 fm.plain(sep, label='grep.sep')
2467 if not opts.get('text') and binary():
2469 if not opts.get('text') and binary():
2468 fm.plain(_(" Binary file matches"))
2470 fm.plain(_(" Binary file matches"))
2469 else:
2471 else:
2470 displaymatches(fm.nested('texts'), l)
2472 displaymatches(fm.nested('texts'), l)
2471 fm.plain(eol)
2473 fm.plain(eol)
2472 found = True
2474 found = True
2473 if opts.get('files_with_matches'):
2475 if opts.get('files_with_matches'):
2474 break
2476 break
2475 return found
2477 return found
2476
2478
2477 def displaymatches(fm, l):
2479 def displaymatches(fm, l):
2478 p = 0
2480 p = 0
2479 for s, e in l.findpos():
2481 for s, e in l.findpos():
2480 if p < s:
2482 if p < s:
2481 fm.startitem()
2483 fm.startitem()
2482 fm.write('text', '%s', l.line[p:s])
2484 fm.write('text', '%s', l.line[p:s])
2483 fm.data(matched=False)
2485 fm.data(matched=False)
2484 fm.startitem()
2486 fm.startitem()
2485 fm.write('text', '%s', l.line[s:e], label='grep.match')
2487 fm.write('text', '%s', l.line[s:e], label='grep.match')
2486 fm.data(matched=True)
2488 fm.data(matched=True)
2487 p = e
2489 p = e
2488 if p < len(l.line):
2490 if p < len(l.line):
2489 fm.startitem()
2491 fm.startitem()
2490 fm.write('text', '%s', l.line[p:])
2492 fm.write('text', '%s', l.line[p:])
2491 fm.data(matched=False)
2493 fm.data(matched=False)
2492 fm.end()
2494 fm.end()
2493
2495
2494 skip = {}
2496 skip = {}
2495 revfiles = {}
2497 revfiles = {}
2496 match = scmutil.match(repo[None], pats, opts)
2498 match = scmutil.match(repo[None], pats, opts)
2497 found = False
2499 found = False
2498 follow = opts.get('follow')
2500 follow = opts.get('follow')
2499
2501
2500 def prep(ctx, fns):
2502 def prep(ctx, fns):
2501 rev = ctx.rev()
2503 rev = ctx.rev()
2502 pctx = ctx.p1()
2504 pctx = ctx.p1()
2503 parent = pctx.rev()
2505 parent = pctx.rev()
2504 matches.setdefault(rev, {})
2506 matches.setdefault(rev, {})
2505 matches.setdefault(parent, {})
2507 matches.setdefault(parent, {})
2506 files = revfiles.setdefault(rev, [])
2508 files = revfiles.setdefault(rev, [])
2507 for fn in fns:
2509 for fn in fns:
2508 flog = getfile(fn)
2510 flog = getfile(fn)
2509 try:
2511 try:
2510 fnode = ctx.filenode(fn)
2512 fnode = ctx.filenode(fn)
2511 except error.LookupError:
2513 except error.LookupError:
2512 continue
2514 continue
2513
2515
2514 copied = flog.renamed(fnode)
2516 copied = flog.renamed(fnode)
2515 copy = follow and copied and copied[0]
2517 copy = follow and copied and copied[0]
2516 if copy:
2518 if copy:
2517 copies.setdefault(rev, {})[fn] = copy
2519 copies.setdefault(rev, {})[fn] = copy
2518 if fn in skip:
2520 if fn in skip:
2519 if copy:
2521 if copy:
2520 skip[copy] = True
2522 skip[copy] = True
2521 continue
2523 continue
2522 files.append(fn)
2524 files.append(fn)
2523
2525
2524 if fn not in matches[rev]:
2526 if fn not in matches[rev]:
2525 grepbody(fn, rev, flog.read(fnode))
2527 grepbody(fn, rev, flog.read(fnode))
2526
2528
2527 pfn = copy or fn
2529 pfn = copy or fn
2528 if pfn not in matches[parent]:
2530 if pfn not in matches[parent]:
2529 try:
2531 try:
2530 fnode = pctx.filenode(pfn)
2532 fnode = pctx.filenode(pfn)
2531 grepbody(pfn, parent, flog.read(fnode))
2533 grepbody(pfn, parent, flog.read(fnode))
2532 except error.LookupError:
2534 except error.LookupError:
2533 pass
2535 pass
2534
2536
2535 ui.pager('grep')
2537 ui.pager('grep')
2536 fm = ui.formatter('grep', opts)
2538 fm = ui.formatter('grep', opts)
2537 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2539 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2538 rev = ctx.rev()
2540 rev = ctx.rev()
2539 parent = ctx.p1().rev()
2541 parent = ctx.p1().rev()
2540 for fn in sorted(revfiles.get(rev, [])):
2542 for fn in sorted(revfiles.get(rev, [])):
2541 states = matches[rev][fn]
2543 states = matches[rev][fn]
2542 copy = copies.get(rev, {}).get(fn)
2544 copy = copies.get(rev, {}).get(fn)
2543 if fn in skip:
2545 if fn in skip:
2544 if copy:
2546 if copy:
2545 skip[copy] = True
2547 skip[copy] = True
2546 continue
2548 continue
2547 pstates = matches.get(parent, {}).get(copy or fn, [])
2549 pstates = matches.get(parent, {}).get(copy or fn, [])
2548 if pstates or states:
2550 if pstates or states:
2549 r = display(fm, fn, ctx, pstates, states)
2551 r = display(fm, fn, ctx, pstates, states)
2550 found = found or r
2552 found = found or r
2551 if r and not opts.get('all'):
2553 if r and not opts.get('all'):
2552 skip[fn] = True
2554 skip[fn] = True
2553 if copy:
2555 if copy:
2554 skip[copy] = True
2556 skip[copy] = True
2555 del matches[rev]
2557 del matches[rev]
2556 del revfiles[rev]
2558 del revfiles[rev]
2557 fm.end()
2559 fm.end()
2558
2560
2559 return not found
2561 return not found
2560
2562
2561 @command('heads',
2563 @command('heads',
2562 [('r', 'rev', '',
2564 [('r', 'rev', '',
2563 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2565 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2564 ('t', 'topo', False, _('show topological heads only')),
2566 ('t', 'topo', False, _('show topological heads only')),
2565 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2567 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2566 ('c', 'closed', False, _('show normal and closed branch heads')),
2568 ('c', 'closed', False, _('show normal and closed branch heads')),
2567 ] + templateopts,
2569 ] + templateopts,
2568 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2570 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2569 def heads(ui, repo, *branchrevs, **opts):
2571 def heads(ui, repo, *branchrevs, **opts):
2570 """show branch heads
2572 """show branch heads
2571
2573
2572 With no arguments, show all open branch heads in the repository.
2574 With no arguments, show all open branch heads in the repository.
2573 Branch heads are changesets that have no descendants on the
2575 Branch heads are changesets that have no descendants on the
2574 same branch. They are where development generally takes place and
2576 same branch. They are where development generally takes place and
2575 are the usual targets for update and merge operations.
2577 are the usual targets for update and merge operations.
2576
2578
2577 If one or more REVs are given, only open branch heads on the
2579 If one or more REVs are given, only open branch heads on the
2578 branches associated with the specified changesets are shown. This
2580 branches associated with the specified changesets are shown. This
2579 means that you can use :hg:`heads .` to see the heads on the
2581 means that you can use :hg:`heads .` to see the heads on the
2580 currently checked-out branch.
2582 currently checked-out branch.
2581
2583
2582 If -c/--closed is specified, also show branch heads marked closed
2584 If -c/--closed is specified, also show branch heads marked closed
2583 (see :hg:`commit --close-branch`).
2585 (see :hg:`commit --close-branch`).
2584
2586
2585 If STARTREV is specified, only those heads that are descendants of
2587 If STARTREV is specified, only those heads that are descendants of
2586 STARTREV will be displayed.
2588 STARTREV will be displayed.
2587
2589
2588 If -t/--topo is specified, named branch mechanics will be ignored and only
2590 If -t/--topo is specified, named branch mechanics will be ignored and only
2589 topological heads (changesets with no children) will be shown.
2591 topological heads (changesets with no children) will be shown.
2590
2592
2591 Returns 0 if matching heads are found, 1 if not.
2593 Returns 0 if matching heads are found, 1 if not.
2592 """
2594 """
2593
2595
2594 opts = pycompat.byteskwargs(opts)
2596 opts = pycompat.byteskwargs(opts)
2595 start = None
2597 start = None
2596 rev = opts.get('rev')
2598 rev = opts.get('rev')
2597 if rev:
2599 if rev:
2598 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2600 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2599 start = scmutil.revsingle(repo, rev, None).node()
2601 start = scmutil.revsingle(repo, rev, None).node()
2600
2602
2601 if opts.get('topo'):
2603 if opts.get('topo'):
2602 heads = [repo[h] for h in repo.heads(start)]
2604 heads = [repo[h] for h in repo.heads(start)]
2603 else:
2605 else:
2604 heads = []
2606 heads = []
2605 for branch in repo.branchmap():
2607 for branch in repo.branchmap():
2606 heads += repo.branchheads(branch, start, opts.get('closed'))
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2607 heads = [repo[h] for h in heads]
2609 heads = [repo[h] for h in heads]
2608
2610
2609 if branchrevs:
2611 if branchrevs:
2610 branches = set(repo[br].branch() for br in branchrevs)
2612 branches = set(repo[br].branch() for br in branchrevs)
2611 heads = [h for h in heads if h.branch() in branches]
2613 heads = [h for h in heads if h.branch() in branches]
2612
2614
2613 if opts.get('active') and branchrevs:
2615 if opts.get('active') and branchrevs:
2614 dagheads = repo.heads(start)
2616 dagheads = repo.heads(start)
2615 heads = [h for h in heads if h.node() in dagheads]
2617 heads = [h for h in heads if h.node() in dagheads]
2616
2618
2617 if branchrevs:
2619 if branchrevs:
2618 haveheads = set(h.branch() for h in heads)
2620 haveheads = set(h.branch() for h in heads)
2619 if branches - haveheads:
2621 if branches - haveheads:
2620 headless = ', '.join(b for b in branches - haveheads)
2622 headless = ', '.join(b for b in branches - haveheads)
2621 msg = _('no open branch heads found on branches %s')
2623 msg = _('no open branch heads found on branches %s')
2622 if opts.get('rev'):
2624 if opts.get('rev'):
2623 msg += _(' (started at %s)') % opts['rev']
2625 msg += _(' (started at %s)') % opts['rev']
2624 ui.warn((msg + '\n') % headless)
2626 ui.warn((msg + '\n') % headless)
2625
2627
2626 if not heads:
2628 if not heads:
2627 return 1
2629 return 1
2628
2630
2629 ui.pager('heads')
2631 ui.pager('heads')
2630 heads = sorted(heads, key=lambda x: -x.rev())
2632 heads = sorted(heads, key=lambda x: -x.rev())
2631 displayer = cmdutil.show_changeset(ui, repo, opts)
2633 displayer = cmdutil.show_changeset(ui, repo, opts)
2632 for ctx in heads:
2634 for ctx in heads:
2633 displayer.show(ctx)
2635 displayer.show(ctx)
2634 displayer.close()
2636 displayer.close()
2635
2637
2636 @command('help',
2638 @command('help',
2637 [('e', 'extension', None, _('show only help for extensions')),
2639 [('e', 'extension', None, _('show only help for extensions')),
2638 ('c', 'command', None, _('show only help for commands')),
2640 ('c', 'command', None, _('show only help for commands')),
2639 ('k', 'keyword', None, _('show topics matching keyword')),
2641 ('k', 'keyword', None, _('show topics matching keyword')),
2640 ('s', 'system', [], _('show help for specific platform(s)')),
2642 ('s', 'system', [], _('show help for specific platform(s)')),
2641 ],
2643 ],
2642 _('[-ecks] [TOPIC]'),
2644 _('[-ecks] [TOPIC]'),
2643 norepo=True, cmdtype=readonly)
2645 norepo=True, cmdtype=readonly)
2644 def help_(ui, name=None, **opts):
2646 def help_(ui, name=None, **opts):
2645 """show help for a given topic or a help overview
2647 """show help for a given topic or a help overview
2646
2648
2647 With no arguments, print a list of commands with short help messages.
2649 With no arguments, print a list of commands with short help messages.
2648
2650
2649 Given a topic, extension, or command name, print help for that
2651 Given a topic, extension, or command name, print help for that
2650 topic.
2652 topic.
2651
2653
2652 Returns 0 if successful.
2654 Returns 0 if successful.
2653 """
2655 """
2654
2656
2655 keep = opts.get(r'system') or []
2657 keep = opts.get(r'system') or []
2656 if len(keep) == 0:
2658 if len(keep) == 0:
2657 if pycompat.sysplatform.startswith('win'):
2659 if pycompat.sysplatform.startswith('win'):
2658 keep.append('windows')
2660 keep.append('windows')
2659 elif pycompat.sysplatform == 'OpenVMS':
2661 elif pycompat.sysplatform == 'OpenVMS':
2660 keep.append('vms')
2662 keep.append('vms')
2661 elif pycompat.sysplatform == 'plan9':
2663 elif pycompat.sysplatform == 'plan9':
2662 keep.append('plan9')
2664 keep.append('plan9')
2663 else:
2665 else:
2664 keep.append('unix')
2666 keep.append('unix')
2665 keep.append(pycompat.sysplatform.lower())
2667 keep.append(pycompat.sysplatform.lower())
2666 if ui.verbose:
2668 if ui.verbose:
2667 keep.append('verbose')
2669 keep.append('verbose')
2668
2670
2669 commands = sys.modules[__name__]
2671 commands = sys.modules[__name__]
2670 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2672 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2671 ui.pager('help')
2673 ui.pager('help')
2672 ui.write(formatted)
2674 ui.write(formatted)
2673
2675
2674
2676
2675 @command('identify|id',
2677 @command('identify|id',
2676 [('r', 'rev', '',
2678 [('r', 'rev', '',
2677 _('identify the specified revision'), _('REV')),
2679 _('identify the specified revision'), _('REV')),
2678 ('n', 'num', None, _('show local revision number')),
2680 ('n', 'num', None, _('show local revision number')),
2679 ('i', 'id', None, _('show global revision id')),
2681 ('i', 'id', None, _('show global revision id')),
2680 ('b', 'branch', None, _('show branch')),
2682 ('b', 'branch', None, _('show branch')),
2681 ('t', 'tags', None, _('show tags')),
2683 ('t', 'tags', None, _('show tags')),
2682 ('B', 'bookmarks', None, _('show bookmarks')),
2684 ('B', 'bookmarks', None, _('show bookmarks')),
2683 ] + remoteopts + formatteropts,
2685 ] + remoteopts + formatteropts,
2684 _('[-nibtB] [-r REV] [SOURCE]'),
2686 _('[-nibtB] [-r REV] [SOURCE]'),
2685 optionalrepo=True, cmdtype=readonly)
2687 optionalrepo=True, cmdtype=readonly)
2686 def identify(ui, repo, source=None, rev=None,
2688 def identify(ui, repo, source=None, rev=None,
2687 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2689 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2688 """identify the working directory or specified revision
2690 """identify the working directory or specified revision
2689
2691
2690 Print a summary identifying the repository state at REV using one or
2692 Print a summary identifying the repository state at REV using one or
2691 two parent hash identifiers, followed by a "+" if the working
2693 two parent hash identifiers, followed by a "+" if the working
2692 directory has uncommitted changes, the branch name (if not default),
2694 directory has uncommitted changes, the branch name (if not default),
2693 a list of tags, and a list of bookmarks.
2695 a list of tags, and a list of bookmarks.
2694
2696
2695 When REV is not given, print a summary of the current state of the
2697 When REV is not given, print a summary of the current state of the
2696 repository.
2698 repository.
2697
2699
2698 Specifying a path to a repository root or Mercurial bundle will
2700 Specifying a path to a repository root or Mercurial bundle will
2699 cause lookup to operate on that repository/bundle.
2701 cause lookup to operate on that repository/bundle.
2700
2702
2701 .. container:: verbose
2703 .. container:: verbose
2702
2704
2703 Examples:
2705 Examples:
2704
2706
2705 - generate a build identifier for the working directory::
2707 - generate a build identifier for the working directory::
2706
2708
2707 hg id --id > build-id.dat
2709 hg id --id > build-id.dat
2708
2710
2709 - find the revision corresponding to a tag::
2711 - find the revision corresponding to a tag::
2710
2712
2711 hg id -n -r 1.3
2713 hg id -n -r 1.3
2712
2714
2713 - check the most recent revision of a remote repository::
2715 - check the most recent revision of a remote repository::
2714
2716
2715 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2717 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2716
2718
2717 See :hg:`log` for generating more information about specific revisions,
2719 See :hg:`log` for generating more information about specific revisions,
2718 including full hash identifiers.
2720 including full hash identifiers.
2719
2721
2720 Returns 0 if successful.
2722 Returns 0 if successful.
2721 """
2723 """
2722
2724
2723 opts = pycompat.byteskwargs(opts)
2725 opts = pycompat.byteskwargs(opts)
2724 if not repo and not source:
2726 if not repo and not source:
2725 raise error.Abort(_("there is no Mercurial repository here "
2727 raise error.Abort(_("there is no Mercurial repository here "
2726 "(.hg not found)"))
2728 "(.hg not found)"))
2727
2729
2728 if ui.debugflag:
2730 if ui.debugflag:
2729 hexfunc = hex
2731 hexfunc = hex
2730 else:
2732 else:
2731 hexfunc = short
2733 hexfunc = short
2732 default = not (num or id or branch or tags or bookmarks)
2734 default = not (num or id or branch or tags or bookmarks)
2733 output = []
2735 output = []
2734 revs = []
2736 revs = []
2735
2737
2736 if source:
2738 if source:
2737 source, branches = hg.parseurl(ui.expandpath(source))
2739 source, branches = hg.parseurl(ui.expandpath(source))
2738 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2740 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2739 repo = peer.local()
2741 repo = peer.local()
2740 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2742 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2741
2743
2742 fm = ui.formatter('identify', opts)
2744 fm = ui.formatter('identify', opts)
2743 fm.startitem()
2745 fm.startitem()
2744
2746
2745 if not repo:
2747 if not repo:
2746 if num or branch or tags:
2748 if num or branch or tags:
2747 raise error.Abort(
2749 raise error.Abort(
2748 _("can't query remote revision number, branch, or tags"))
2750 _("can't query remote revision number, branch, or tags"))
2749 if not rev and revs:
2751 if not rev and revs:
2750 rev = revs[0]
2752 rev = revs[0]
2751 if not rev:
2753 if not rev:
2752 rev = "tip"
2754 rev = "tip"
2753
2755
2754 remoterev = peer.lookup(rev)
2756 remoterev = peer.lookup(rev)
2755 hexrev = hexfunc(remoterev)
2757 hexrev = hexfunc(remoterev)
2756 if default or id:
2758 if default or id:
2757 output = [hexrev]
2759 output = [hexrev]
2758 fm.data(id=hexrev)
2760 fm.data(id=hexrev)
2759
2761
2760 def getbms():
2762 def getbms():
2761 bms = []
2763 bms = []
2762
2764
2763 if 'bookmarks' in peer.listkeys('namespaces'):
2765 if 'bookmarks' in peer.listkeys('namespaces'):
2764 hexremoterev = hex(remoterev)
2766 hexremoterev = hex(remoterev)
2765 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2767 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2766 if bmr == hexremoterev]
2768 if bmr == hexremoterev]
2767
2769
2768 return sorted(bms)
2770 return sorted(bms)
2769
2771
2770 bms = getbms()
2772 bms = getbms()
2771 if bookmarks:
2773 if bookmarks:
2772 output.extend(bms)
2774 output.extend(bms)
2773 elif default and not ui.quiet:
2775 elif default and not ui.quiet:
2774 # multiple bookmarks for a single parent separated by '/'
2776 # multiple bookmarks for a single parent separated by '/'
2775 bm = '/'.join(bms)
2777 bm = '/'.join(bms)
2776 if bm:
2778 if bm:
2777 output.append(bm)
2779 output.append(bm)
2778
2780
2779 fm.data(node=hex(remoterev))
2781 fm.data(node=hex(remoterev))
2780 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2782 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2781 else:
2783 else:
2782 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2784 if rev:
2785 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2783 ctx = scmutil.revsingle(repo, rev, None)
2786 ctx = scmutil.revsingle(repo, rev, None)
2784
2787
2785 if ctx.rev() is None:
2788 if ctx.rev() is None:
2786 ctx = repo[None]
2789 ctx = repo[None]
2787 parents = ctx.parents()
2790 parents = ctx.parents()
2788 taglist = []
2791 taglist = []
2789 for p in parents:
2792 for p in parents:
2790 taglist.extend(p.tags())
2793 taglist.extend(p.tags())
2791
2794
2792 dirty = ""
2795 dirty = ""
2793 if ctx.dirty(missing=True, merge=False, branch=False):
2796 if ctx.dirty(missing=True, merge=False, branch=False):
2794 dirty = '+'
2797 dirty = '+'
2795 fm.data(dirty=dirty)
2798 fm.data(dirty=dirty)
2796
2799
2797 hexoutput = [hexfunc(p.node()) for p in parents]
2800 hexoutput = [hexfunc(p.node()) for p in parents]
2798 if default or id:
2801 if default or id:
2799 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2802 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2800 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2803 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2801
2804
2802 if num:
2805 if num:
2803 numoutput = ["%d" % p.rev() for p in parents]
2806 numoutput = ["%d" % p.rev() for p in parents]
2804 output.append("%s%s" % ('+'.join(numoutput), dirty))
2807 output.append("%s%s" % ('+'.join(numoutput), dirty))
2805
2808
2806 fn = fm.nested('parents')
2809 fn = fm.nested('parents')
2807 for p in parents:
2810 for p in parents:
2808 fn.startitem()
2811 fn.startitem()
2809 fn.data(rev=p.rev())
2812 fn.data(rev=p.rev())
2810 fn.data(node=p.hex())
2813 fn.data(node=p.hex())
2811 fn.context(ctx=p)
2814 fn.context(ctx=p)
2812 fn.end()
2815 fn.end()
2813 else:
2816 else:
2814 hexoutput = hexfunc(ctx.node())
2817 hexoutput = hexfunc(ctx.node())
2815 if default or id:
2818 if default or id:
2816 output = [hexoutput]
2819 output = [hexoutput]
2817 fm.data(id=hexoutput)
2820 fm.data(id=hexoutput)
2818
2821
2819 if num:
2822 if num:
2820 output.append(pycompat.bytestr(ctx.rev()))
2823 output.append(pycompat.bytestr(ctx.rev()))
2821 taglist = ctx.tags()
2824 taglist = ctx.tags()
2822
2825
2823 if default and not ui.quiet:
2826 if default and not ui.quiet:
2824 b = ctx.branch()
2827 b = ctx.branch()
2825 if b != 'default':
2828 if b != 'default':
2826 output.append("(%s)" % b)
2829 output.append("(%s)" % b)
2827
2830
2828 # multiple tags for a single parent separated by '/'
2831 # multiple tags for a single parent separated by '/'
2829 t = '/'.join(taglist)
2832 t = '/'.join(taglist)
2830 if t:
2833 if t:
2831 output.append(t)
2834 output.append(t)
2832
2835
2833 # multiple bookmarks for a single parent separated by '/'
2836 # multiple bookmarks for a single parent separated by '/'
2834 bm = '/'.join(ctx.bookmarks())
2837 bm = '/'.join(ctx.bookmarks())
2835 if bm:
2838 if bm:
2836 output.append(bm)
2839 output.append(bm)
2837 else:
2840 else:
2838 if branch:
2841 if branch:
2839 output.append(ctx.branch())
2842 output.append(ctx.branch())
2840
2843
2841 if tags:
2844 if tags:
2842 output.extend(taglist)
2845 output.extend(taglist)
2843
2846
2844 if bookmarks:
2847 if bookmarks:
2845 output.extend(ctx.bookmarks())
2848 output.extend(ctx.bookmarks())
2846
2849
2847 fm.data(node=ctx.hex())
2850 fm.data(node=ctx.hex())
2848 fm.data(branch=ctx.branch())
2851 fm.data(branch=ctx.branch())
2849 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2852 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2850 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2853 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2851 fm.context(ctx=ctx)
2854 fm.context(ctx=ctx)
2852
2855
2853 fm.plain("%s\n" % ' '.join(output))
2856 fm.plain("%s\n" % ' '.join(output))
2854 fm.end()
2857 fm.end()
2855
2858
2856 @command('import|patch',
2859 @command('import|patch',
2857 [('p', 'strip', 1,
2860 [('p', 'strip', 1,
2858 _('directory strip option for patch. This has the same '
2861 _('directory strip option for patch. This has the same '
2859 'meaning as the corresponding patch option'), _('NUM')),
2862 'meaning as the corresponding patch option'), _('NUM')),
2860 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2863 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2861 ('e', 'edit', False, _('invoke editor on commit messages')),
2864 ('e', 'edit', False, _('invoke editor on commit messages')),
2862 ('f', 'force', None,
2865 ('f', 'force', None,
2863 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2866 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2864 ('', 'no-commit', None,
2867 ('', 'no-commit', None,
2865 _("don't commit, just update the working directory")),
2868 _("don't commit, just update the working directory")),
2866 ('', 'bypass', None,
2869 ('', 'bypass', None,
2867 _("apply patch without touching the working directory")),
2870 _("apply patch without touching the working directory")),
2868 ('', 'partial', None,
2871 ('', 'partial', None,
2869 _('commit even if some hunks fail')),
2872 _('commit even if some hunks fail')),
2870 ('', 'exact', None,
2873 ('', 'exact', None,
2871 _('abort if patch would apply lossily')),
2874 _('abort if patch would apply lossily')),
2872 ('', 'prefix', '',
2875 ('', 'prefix', '',
2873 _('apply patch to subdirectory'), _('DIR')),
2876 _('apply patch to subdirectory'), _('DIR')),
2874 ('', 'import-branch', None,
2877 ('', 'import-branch', None,
2875 _('use any branch information in patch (implied by --exact)'))] +
2878 _('use any branch information in patch (implied by --exact)'))] +
2876 commitopts + commitopts2 + similarityopts,
2879 commitopts + commitopts2 + similarityopts,
2877 _('[OPTION]... PATCH...'))
2880 _('[OPTION]... PATCH...'))
2878 def import_(ui, repo, patch1=None, *patches, **opts):
2881 def import_(ui, repo, patch1=None, *patches, **opts):
2879 """import an ordered set of patches
2882 """import an ordered set of patches
2880
2883
2881 Import a list of patches and commit them individually (unless
2884 Import a list of patches and commit them individually (unless
2882 --no-commit is specified).
2885 --no-commit is specified).
2883
2886
2884 To read a patch from standard input (stdin), use "-" as the patch
2887 To read a patch from standard input (stdin), use "-" as the patch
2885 name. If a URL is specified, the patch will be downloaded from
2888 name. If a URL is specified, the patch will be downloaded from
2886 there.
2889 there.
2887
2890
2888 Import first applies changes to the working directory (unless
2891 Import first applies changes to the working directory (unless
2889 --bypass is specified), import will abort if there are outstanding
2892 --bypass is specified), import will abort if there are outstanding
2890 changes.
2893 changes.
2891
2894
2892 Use --bypass to apply and commit patches directly to the
2895 Use --bypass to apply and commit patches directly to the
2893 repository, without affecting the working directory. Without
2896 repository, without affecting the working directory. Without
2894 --exact, patches will be applied on top of the working directory
2897 --exact, patches will be applied on top of the working directory
2895 parent revision.
2898 parent revision.
2896
2899
2897 You can import a patch straight from a mail message. Even patches
2900 You can import a patch straight from a mail message. Even patches
2898 as attachments work (to use the body part, it must have type
2901 as attachments work (to use the body part, it must have type
2899 text/plain or text/x-patch). From and Subject headers of email
2902 text/plain or text/x-patch). From and Subject headers of email
2900 message are used as default committer and commit message. All
2903 message are used as default committer and commit message. All
2901 text/plain body parts before first diff are added to the commit
2904 text/plain body parts before first diff are added to the commit
2902 message.
2905 message.
2903
2906
2904 If the imported patch was generated by :hg:`export`, user and
2907 If the imported patch was generated by :hg:`export`, user and
2905 description from patch override values from message headers and
2908 description from patch override values from message headers and
2906 body. Values given on command line with -m/--message and -u/--user
2909 body. Values given on command line with -m/--message and -u/--user
2907 override these.
2910 override these.
2908
2911
2909 If --exact is specified, import will set the working directory to
2912 If --exact is specified, import will set the working directory to
2910 the parent of each patch before applying it, and will abort if the
2913 the parent of each patch before applying it, and will abort if the
2911 resulting changeset has a different ID than the one recorded in
2914 resulting changeset has a different ID than the one recorded in
2912 the patch. This will guard against various ways that portable
2915 the patch. This will guard against various ways that portable
2913 patch formats and mail systems might fail to transfer Mercurial
2916 patch formats and mail systems might fail to transfer Mercurial
2914 data or metadata. See :hg:`bundle` for lossless transmission.
2917 data or metadata. See :hg:`bundle` for lossless transmission.
2915
2918
2916 Use --partial to ensure a changeset will be created from the patch
2919 Use --partial to ensure a changeset will be created from the patch
2917 even if some hunks fail to apply. Hunks that fail to apply will be
2920 even if some hunks fail to apply. Hunks that fail to apply will be
2918 written to a <target-file>.rej file. Conflicts can then be resolved
2921 written to a <target-file>.rej file. Conflicts can then be resolved
2919 by hand before :hg:`commit --amend` is run to update the created
2922 by hand before :hg:`commit --amend` is run to update the created
2920 changeset. This flag exists to let people import patches that
2923 changeset. This flag exists to let people import patches that
2921 partially apply without losing the associated metadata (author,
2924 partially apply without losing the associated metadata (author,
2922 date, description, ...).
2925 date, description, ...).
2923
2926
2924 .. note::
2927 .. note::
2925
2928
2926 When no hunks apply cleanly, :hg:`import --partial` will create
2929 When no hunks apply cleanly, :hg:`import --partial` will create
2927 an empty changeset, importing only the patch metadata.
2930 an empty changeset, importing only the patch metadata.
2928
2931
2929 With -s/--similarity, hg will attempt to discover renames and
2932 With -s/--similarity, hg will attempt to discover renames and
2930 copies in the patch in the same way as :hg:`addremove`.
2933 copies in the patch in the same way as :hg:`addremove`.
2931
2934
2932 It is possible to use external patch programs to perform the patch
2935 It is possible to use external patch programs to perform the patch
2933 by setting the ``ui.patch`` configuration option. For the default
2936 by setting the ``ui.patch`` configuration option. For the default
2934 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2937 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2935 See :hg:`help config` for more information about configuration
2938 See :hg:`help config` for more information about configuration
2936 files and how to use these options.
2939 files and how to use these options.
2937
2940
2938 See :hg:`help dates` for a list of formats valid for -d/--date.
2941 See :hg:`help dates` for a list of formats valid for -d/--date.
2939
2942
2940 .. container:: verbose
2943 .. container:: verbose
2941
2944
2942 Examples:
2945 Examples:
2943
2946
2944 - import a traditional patch from a website and detect renames::
2947 - import a traditional patch from a website and detect renames::
2945
2948
2946 hg import -s 80 http://example.com/bugfix.patch
2949 hg import -s 80 http://example.com/bugfix.patch
2947
2950
2948 - import a changeset from an hgweb server::
2951 - import a changeset from an hgweb server::
2949
2952
2950 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2953 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2951
2954
2952 - import all the patches in an Unix-style mbox::
2955 - import all the patches in an Unix-style mbox::
2953
2956
2954 hg import incoming-patches.mbox
2957 hg import incoming-patches.mbox
2955
2958
2956 - import patches from stdin::
2959 - import patches from stdin::
2957
2960
2958 hg import -
2961 hg import -
2959
2962
2960 - attempt to exactly restore an exported changeset (not always
2963 - attempt to exactly restore an exported changeset (not always
2961 possible)::
2964 possible)::
2962
2965
2963 hg import --exact proposed-fix.patch
2966 hg import --exact proposed-fix.patch
2964
2967
2965 - use an external tool to apply a patch which is too fuzzy for
2968 - use an external tool to apply a patch which is too fuzzy for
2966 the default internal tool.
2969 the default internal tool.
2967
2970
2968 hg import --config ui.patch="patch --merge" fuzzy.patch
2971 hg import --config ui.patch="patch --merge" fuzzy.patch
2969
2972
2970 - change the default fuzzing from 2 to a less strict 7
2973 - change the default fuzzing from 2 to a less strict 7
2971
2974
2972 hg import --config ui.fuzz=7 fuzz.patch
2975 hg import --config ui.fuzz=7 fuzz.patch
2973
2976
2974 Returns 0 on success, 1 on partial success (see --partial).
2977 Returns 0 on success, 1 on partial success (see --partial).
2975 """
2978 """
2976
2979
2977 opts = pycompat.byteskwargs(opts)
2980 opts = pycompat.byteskwargs(opts)
2978 if not patch1:
2981 if not patch1:
2979 raise error.Abort(_('need at least one patch to import'))
2982 raise error.Abort(_('need at least one patch to import'))
2980
2983
2981 patches = (patch1,) + patches
2984 patches = (patch1,) + patches
2982
2985
2983 date = opts.get('date')
2986 date = opts.get('date')
2984 if date:
2987 if date:
2985 opts['date'] = util.parsedate(date)
2988 opts['date'] = util.parsedate(date)
2986
2989
2987 exact = opts.get('exact')
2990 exact = opts.get('exact')
2988 update = not opts.get('bypass')
2991 update = not opts.get('bypass')
2989 if not update and opts.get('no_commit'):
2992 if not update and opts.get('no_commit'):
2990 raise error.Abort(_('cannot use --no-commit with --bypass'))
2993 raise error.Abort(_('cannot use --no-commit with --bypass'))
2991 try:
2994 try:
2992 sim = float(opts.get('similarity') or 0)
2995 sim = float(opts.get('similarity') or 0)
2993 except ValueError:
2996 except ValueError:
2994 raise error.Abort(_('similarity must be a number'))
2997 raise error.Abort(_('similarity must be a number'))
2995 if sim < 0 or sim > 100:
2998 if sim < 0 or sim > 100:
2996 raise error.Abort(_('similarity must be between 0 and 100'))
2999 raise error.Abort(_('similarity must be between 0 and 100'))
2997 if sim and not update:
3000 if sim and not update:
2998 raise error.Abort(_('cannot use --similarity with --bypass'))
3001 raise error.Abort(_('cannot use --similarity with --bypass'))
2999 if exact:
3002 if exact:
3000 if opts.get('edit'):
3003 if opts.get('edit'):
3001 raise error.Abort(_('cannot use --exact with --edit'))
3004 raise error.Abort(_('cannot use --exact with --edit'))
3002 if opts.get('prefix'):
3005 if opts.get('prefix'):
3003 raise error.Abort(_('cannot use --exact with --prefix'))
3006 raise error.Abort(_('cannot use --exact with --prefix'))
3004
3007
3005 base = opts["base"]
3008 base = opts["base"]
3006 wlock = dsguard = lock = tr = None
3009 wlock = dsguard = lock = tr = None
3007 msgs = []
3010 msgs = []
3008 ret = 0
3011 ret = 0
3009
3012
3010
3013
3011 try:
3014 try:
3012 wlock = repo.wlock()
3015 wlock = repo.wlock()
3013
3016
3014 if update:
3017 if update:
3015 cmdutil.checkunfinished(repo)
3018 cmdutil.checkunfinished(repo)
3016 if (exact or not opts.get('force')):
3019 if (exact or not opts.get('force')):
3017 cmdutil.bailifchanged(repo)
3020 cmdutil.bailifchanged(repo)
3018
3021
3019 if not opts.get('no_commit'):
3022 if not opts.get('no_commit'):
3020 lock = repo.lock()
3023 lock = repo.lock()
3021 tr = repo.transaction('import')
3024 tr = repo.transaction('import')
3022 else:
3025 else:
3023 dsguard = dirstateguard.dirstateguard(repo, 'import')
3026 dsguard = dirstateguard.dirstateguard(repo, 'import')
3024 parents = repo[None].parents()
3027 parents = repo[None].parents()
3025 for patchurl in patches:
3028 for patchurl in patches:
3026 if patchurl == '-':
3029 if patchurl == '-':
3027 ui.status(_('applying patch from stdin\n'))
3030 ui.status(_('applying patch from stdin\n'))
3028 patchfile = ui.fin
3031 patchfile = ui.fin
3029 patchurl = 'stdin' # for error message
3032 patchurl = 'stdin' # for error message
3030 else:
3033 else:
3031 patchurl = os.path.join(base, patchurl)
3034 patchurl = os.path.join(base, patchurl)
3032 ui.status(_('applying %s\n') % patchurl)
3035 ui.status(_('applying %s\n') % patchurl)
3033 patchfile = hg.openpath(ui, patchurl)
3036 patchfile = hg.openpath(ui, patchurl)
3034
3037
3035 haspatch = False
3038 haspatch = False
3036 for hunk in patch.split(patchfile):
3039 for hunk in patch.split(patchfile):
3037 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3040 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3038 parents, opts,
3041 parents, opts,
3039 msgs, hg.clean)
3042 msgs, hg.clean)
3040 if msg:
3043 if msg:
3041 haspatch = True
3044 haspatch = True
3042 ui.note(msg + '\n')
3045 ui.note(msg + '\n')
3043 if update or exact:
3046 if update or exact:
3044 parents = repo[None].parents()
3047 parents = repo[None].parents()
3045 else:
3048 else:
3046 parents = [repo[node]]
3049 parents = [repo[node]]
3047 if rej:
3050 if rej:
3048 ui.write_err(_("patch applied partially\n"))
3051 ui.write_err(_("patch applied partially\n"))
3049 ui.write_err(_("(fix the .rej files and run "
3052 ui.write_err(_("(fix the .rej files and run "
3050 "`hg commit --amend`)\n"))
3053 "`hg commit --amend`)\n"))
3051 ret = 1
3054 ret = 1
3052 break
3055 break
3053
3056
3054 if not haspatch:
3057 if not haspatch:
3055 raise error.Abort(_('%s: no diffs found') % patchurl)
3058 raise error.Abort(_('%s: no diffs found') % patchurl)
3056
3059
3057 if tr:
3060 if tr:
3058 tr.close()
3061 tr.close()
3059 if msgs:
3062 if msgs:
3060 repo.savecommitmessage('\n* * *\n'.join(msgs))
3063 repo.savecommitmessage('\n* * *\n'.join(msgs))
3061 if dsguard:
3064 if dsguard:
3062 dsguard.close()
3065 dsguard.close()
3063 return ret
3066 return ret
3064 finally:
3067 finally:
3065 if tr:
3068 if tr:
3066 tr.release()
3069 tr.release()
3067 release(lock, dsguard, wlock)
3070 release(lock, dsguard, wlock)
3068
3071
3069 @command('incoming|in',
3072 @command('incoming|in',
3070 [('f', 'force', None,
3073 [('f', 'force', None,
3071 _('run even if remote repository is unrelated')),
3074 _('run even if remote repository is unrelated')),
3072 ('n', 'newest-first', None, _('show newest record first')),
3075 ('n', 'newest-first', None, _('show newest record first')),
3073 ('', 'bundle', '',
3076 ('', 'bundle', '',
3074 _('file to store the bundles into'), _('FILE')),
3077 _('file to store the bundles into'), _('FILE')),
3075 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3078 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3076 ('B', 'bookmarks', False, _("compare bookmarks")),
3079 ('B', 'bookmarks', False, _("compare bookmarks")),
3077 ('b', 'branch', [],
3080 ('b', 'branch', [],
3078 _('a specific branch you would like to pull'), _('BRANCH')),
3081 _('a specific branch you would like to pull'), _('BRANCH')),
3079 ] + logopts + remoteopts + subrepoopts,
3082 ] + logopts + remoteopts + subrepoopts,
3080 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3083 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3081 def incoming(ui, repo, source="default", **opts):
3084 def incoming(ui, repo, source="default", **opts):
3082 """show new changesets found in source
3085 """show new changesets found in source
3083
3086
3084 Show new changesets found in the specified path/URL or the default
3087 Show new changesets found in the specified path/URL or the default
3085 pull location. These are the changesets that would have been pulled
3088 pull location. These are the changesets that would have been pulled
3086 by :hg:`pull` at the time you issued this command.
3089 by :hg:`pull` at the time you issued this command.
3087
3090
3088 See pull for valid source format details.
3091 See pull for valid source format details.
3089
3092
3090 .. container:: verbose
3093 .. container:: verbose
3091
3094
3092 With -B/--bookmarks, the result of bookmark comparison between
3095 With -B/--bookmarks, the result of bookmark comparison between
3093 local and remote repositories is displayed. With -v/--verbose,
3096 local and remote repositories is displayed. With -v/--verbose,
3094 status is also displayed for each bookmark like below::
3097 status is also displayed for each bookmark like below::
3095
3098
3096 BM1 01234567890a added
3099 BM1 01234567890a added
3097 BM2 1234567890ab advanced
3100 BM2 1234567890ab advanced
3098 BM3 234567890abc diverged
3101 BM3 234567890abc diverged
3099 BM4 34567890abcd changed
3102 BM4 34567890abcd changed
3100
3103
3101 The action taken locally when pulling depends on the
3104 The action taken locally when pulling depends on the
3102 status of each bookmark:
3105 status of each bookmark:
3103
3106
3104 :``added``: pull will create it
3107 :``added``: pull will create it
3105 :``advanced``: pull will update it
3108 :``advanced``: pull will update it
3106 :``diverged``: pull will create a divergent bookmark
3109 :``diverged``: pull will create a divergent bookmark
3107 :``changed``: result depends on remote changesets
3110 :``changed``: result depends on remote changesets
3108
3111
3109 From the point of view of pulling behavior, bookmark
3112 From the point of view of pulling behavior, bookmark
3110 existing only in the remote repository are treated as ``added``,
3113 existing only in the remote repository are treated as ``added``,
3111 even if it is in fact locally deleted.
3114 even if it is in fact locally deleted.
3112
3115
3113 .. container:: verbose
3116 .. container:: verbose
3114
3117
3115 For remote repository, using --bundle avoids downloading the
3118 For remote repository, using --bundle avoids downloading the
3116 changesets twice if the incoming is followed by a pull.
3119 changesets twice if the incoming is followed by a pull.
3117
3120
3118 Examples:
3121 Examples:
3119
3122
3120 - show incoming changes with patches and full description::
3123 - show incoming changes with patches and full description::
3121
3124
3122 hg incoming -vp
3125 hg incoming -vp
3123
3126
3124 - show incoming changes excluding merges, store a bundle::
3127 - show incoming changes excluding merges, store a bundle::
3125
3128
3126 hg in -vpM --bundle incoming.hg
3129 hg in -vpM --bundle incoming.hg
3127 hg pull incoming.hg
3130 hg pull incoming.hg
3128
3131
3129 - briefly list changes inside a bundle::
3132 - briefly list changes inside a bundle::
3130
3133
3131 hg in changes.hg -T "{desc|firstline}\\n"
3134 hg in changes.hg -T "{desc|firstline}\\n"
3132
3135
3133 Returns 0 if there are incoming changes, 1 otherwise.
3136 Returns 0 if there are incoming changes, 1 otherwise.
3134 """
3137 """
3135 opts = pycompat.byteskwargs(opts)
3138 opts = pycompat.byteskwargs(opts)
3136 if opts.get('graph'):
3139 if opts.get('graph'):
3137 cmdutil.checkunsupportedgraphflags([], opts)
3140 cmdutil.checkunsupportedgraphflags([], opts)
3138 def display(other, chlist, displayer):
3141 def display(other, chlist, displayer):
3139 revdag = cmdutil.graphrevs(other, chlist, opts)
3142 revdag = cmdutil.graphrevs(other, chlist, opts)
3140 cmdutil.displaygraph(ui, repo, revdag, displayer,
3143 cmdutil.displaygraph(ui, repo, revdag, displayer,
3141 graphmod.asciiedges)
3144 graphmod.asciiedges)
3142
3145
3143 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3146 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3144 return 0
3147 return 0
3145
3148
3146 if opts.get('bundle') and opts.get('subrepos'):
3149 if opts.get('bundle') and opts.get('subrepos'):
3147 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3150 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3148
3151
3149 if opts.get('bookmarks'):
3152 if opts.get('bookmarks'):
3150 source, branches = hg.parseurl(ui.expandpath(source),
3153 source, branches = hg.parseurl(ui.expandpath(source),
3151 opts.get('branch'))
3154 opts.get('branch'))
3152 other = hg.peer(repo, opts, source)
3155 other = hg.peer(repo, opts, source)
3153 if 'bookmarks' not in other.listkeys('namespaces'):
3156 if 'bookmarks' not in other.listkeys('namespaces'):
3154 ui.warn(_("remote doesn't support bookmarks\n"))
3157 ui.warn(_("remote doesn't support bookmarks\n"))
3155 return 0
3158 return 0
3156 ui.pager('incoming')
3159 ui.pager('incoming')
3157 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3160 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3158 return bookmarks.incoming(ui, repo, other)
3161 return bookmarks.incoming(ui, repo, other)
3159
3162
3160 repo._subtoppath = ui.expandpath(source)
3163 repo._subtoppath = ui.expandpath(source)
3161 try:
3164 try:
3162 return hg.incoming(ui, repo, source, opts)
3165 return hg.incoming(ui, repo, source, opts)
3163 finally:
3166 finally:
3164 del repo._subtoppath
3167 del repo._subtoppath
3165
3168
3166
3169
3167 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3170 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3168 norepo=True)
3171 norepo=True)
3169 def init(ui, dest=".", **opts):
3172 def init(ui, dest=".", **opts):
3170 """create a new repository in the given directory
3173 """create a new repository in the given directory
3171
3174
3172 Initialize a new repository in the given directory. If the given
3175 Initialize a new repository in the given directory. If the given
3173 directory does not exist, it will be created.
3176 directory does not exist, it will be created.
3174
3177
3175 If no directory is given, the current directory is used.
3178 If no directory is given, the current directory is used.
3176
3179
3177 It is possible to specify an ``ssh://`` URL as the destination.
3180 It is possible to specify an ``ssh://`` URL as the destination.
3178 See :hg:`help urls` for more information.
3181 See :hg:`help urls` for more information.
3179
3182
3180 Returns 0 on success.
3183 Returns 0 on success.
3181 """
3184 """
3182 opts = pycompat.byteskwargs(opts)
3185 opts = pycompat.byteskwargs(opts)
3183 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3186 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3184
3187
3185 @command('locate',
3188 @command('locate',
3186 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3189 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3187 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3190 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3188 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3191 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3189 ] + walkopts,
3192 ] + walkopts,
3190 _('[OPTION]... [PATTERN]...'))
3193 _('[OPTION]... [PATTERN]...'))
3191 def locate(ui, repo, *pats, **opts):
3194 def locate(ui, repo, *pats, **opts):
3192 """locate files matching specific patterns (DEPRECATED)
3195 """locate files matching specific patterns (DEPRECATED)
3193
3196
3194 Print files under Mercurial control in the working directory whose
3197 Print files under Mercurial control in the working directory whose
3195 names match the given patterns.
3198 names match the given patterns.
3196
3199
3197 By default, this command searches all directories in the working
3200 By default, this command searches all directories in the working
3198 directory. To search just the current directory and its
3201 directory. To search just the current directory and its
3199 subdirectories, use "--include .".
3202 subdirectories, use "--include .".
3200
3203
3201 If no patterns are given to match, this command prints the names
3204 If no patterns are given to match, this command prints the names
3202 of all files under Mercurial control in the working directory.
3205 of all files under Mercurial control in the working directory.
3203
3206
3204 If you want to feed the output of this command into the "xargs"
3207 If you want to feed the output of this command into the "xargs"
3205 command, use the -0 option to both this command and "xargs". This
3208 command, use the -0 option to both this command and "xargs". This
3206 will avoid the problem of "xargs" treating single filenames that
3209 will avoid the problem of "xargs" treating single filenames that
3207 contain whitespace as multiple filenames.
3210 contain whitespace as multiple filenames.
3208
3211
3209 See :hg:`help files` for a more versatile command.
3212 See :hg:`help files` for a more versatile command.
3210
3213
3211 Returns 0 if a match is found, 1 otherwise.
3214 Returns 0 if a match is found, 1 otherwise.
3212 """
3215 """
3213 opts = pycompat.byteskwargs(opts)
3216 opts = pycompat.byteskwargs(opts)
3214 if opts.get('print0'):
3217 if opts.get('print0'):
3215 end = '\0'
3218 end = '\0'
3216 else:
3219 else:
3217 end = '\n'
3220 end = '\n'
3218 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3221 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3219
3222
3220 ret = 1
3223 ret = 1
3221 ctx = repo[rev]
3224 ctx = repo[rev]
3222 m = scmutil.match(ctx, pats, opts, default='relglob',
3225 m = scmutil.match(ctx, pats, opts, default='relglob',
3223 badfn=lambda x, y: False)
3226 badfn=lambda x, y: False)
3224
3227
3225 ui.pager('locate')
3228 ui.pager('locate')
3226 for abs in ctx.matches(m):
3229 for abs in ctx.matches(m):
3227 if opts.get('fullpath'):
3230 if opts.get('fullpath'):
3228 ui.write(repo.wjoin(abs), end)
3231 ui.write(repo.wjoin(abs), end)
3229 else:
3232 else:
3230 ui.write(((pats and m.rel(abs)) or abs), end)
3233 ui.write(((pats and m.rel(abs)) or abs), end)
3231 ret = 0
3234 ret = 0
3232
3235
3233 return ret
3236 return ret
3234
3237
3235 @command('^log|history',
3238 @command('^log|history',
3236 [('f', 'follow', None,
3239 [('f', 'follow', None,
3237 _('follow changeset history, or file history across copies and renames')),
3240 _('follow changeset history, or file history across copies and renames')),
3238 ('', 'follow-first', None,
3241 ('', 'follow-first', None,
3239 _('only follow the first parent of merge changesets (DEPRECATED)')),
3242 _('only follow the first parent of merge changesets (DEPRECATED)')),
3240 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3243 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3241 ('C', 'copies', None, _('show copied files')),
3244 ('C', 'copies', None, _('show copied files')),
3242 ('k', 'keyword', [],
3245 ('k', 'keyword', [],
3243 _('do case-insensitive search for a given text'), _('TEXT')),
3246 _('do case-insensitive search for a given text'), _('TEXT')),
3244 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3247 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3245 ('L', 'line-range', [],
3248 ('L', 'line-range', [],
3246 _('follow line range of specified file (EXPERIMENTAL)'),
3249 _('follow line range of specified file (EXPERIMENTAL)'),
3247 _('FILE,RANGE')),
3250 _('FILE,RANGE')),
3248 ('', 'removed', None, _('include revisions where files were removed')),
3251 ('', 'removed', None, _('include revisions where files were removed')),
3249 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3252 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3250 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3253 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3251 ('', 'only-branch', [],
3254 ('', 'only-branch', [],
3252 _('show only changesets within the given named branch (DEPRECATED)'),
3255 _('show only changesets within the given named branch (DEPRECATED)'),
3253 _('BRANCH')),
3256 _('BRANCH')),
3254 ('b', 'branch', [],
3257 ('b', 'branch', [],
3255 _('show changesets within the given named branch'), _('BRANCH')),
3258 _('show changesets within the given named branch'), _('BRANCH')),
3256 ('P', 'prune', [],
3259 ('P', 'prune', [],
3257 _('do not display revision or any of its ancestors'), _('REV')),
3260 _('do not display revision or any of its ancestors'), _('REV')),
3258 ] + logopts + walkopts,
3261 ] + logopts + walkopts,
3259 _('[OPTION]... [FILE]'),
3262 _('[OPTION]... [FILE]'),
3260 inferrepo=True, cmdtype=readonly)
3263 inferrepo=True, cmdtype=readonly)
3261 def log(ui, repo, *pats, **opts):
3264 def log(ui, repo, *pats, **opts):
3262 """show revision history of entire repository or files
3265 """show revision history of entire repository or files
3263
3266
3264 Print the revision history of the specified files or the entire
3267 Print the revision history of the specified files or the entire
3265 project.
3268 project.
3266
3269
3267 If no revision range is specified, the default is ``tip:0`` unless
3270 If no revision range is specified, the default is ``tip:0`` unless
3268 --follow is set, in which case the working directory parent is
3271 --follow is set, in which case the working directory parent is
3269 used as the starting revision.
3272 used as the starting revision.
3270
3273
3271 File history is shown without following rename or copy history of
3274 File history is shown without following rename or copy history of
3272 files. Use -f/--follow with a filename to follow history across
3275 files. Use -f/--follow with a filename to follow history across
3273 renames and copies. --follow without a filename will only show
3276 renames and copies. --follow without a filename will only show
3274 ancestors or descendants of the starting revision.
3277 ancestors or descendants of the starting revision.
3275
3278
3276 By default this command prints revision number and changeset id,
3279 By default this command prints revision number and changeset id,
3277 tags, non-trivial parents, user, date and time, and a summary for
3280 tags, non-trivial parents, user, date and time, and a summary for
3278 each commit. When the -v/--verbose switch is used, the list of
3281 each commit. When the -v/--verbose switch is used, the list of
3279 changed files and full commit message are shown.
3282 changed files and full commit message are shown.
3280
3283
3281 With --graph the revisions are shown as an ASCII art DAG with the most
3284 With --graph the revisions are shown as an ASCII art DAG with the most
3282 recent changeset at the top.
3285 recent changeset at the top.
3283 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3286 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3284 and '+' represents a fork where the changeset from the lines below is a
3287 and '+' represents a fork where the changeset from the lines below is a
3285 parent of the 'o' merge on the same line.
3288 parent of the 'o' merge on the same line.
3286 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3289 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3287 of a '|' indicates one or more revisions in a path are omitted.
3290 of a '|' indicates one or more revisions in a path are omitted.
3288
3291
3289 .. container:: verbose
3292 .. container:: verbose
3290
3293
3291 Use -L/--line-range FILE,M:N options to follow the history of lines
3294 Use -L/--line-range FILE,M:N options to follow the history of lines
3292 from M to N in FILE. With -p/--patch only diff hunks affecting
3295 from M to N in FILE. With -p/--patch only diff hunks affecting
3293 specified line range will be shown. This option requires --follow;
3296 specified line range will be shown. This option requires --follow;
3294 it can be specified multiple times. Currently, this option is not
3297 it can be specified multiple times. Currently, this option is not
3295 compatible with --graph. This option is experimental.
3298 compatible with --graph. This option is experimental.
3296
3299
3297 .. note::
3300 .. note::
3298
3301
3299 :hg:`log --patch` may generate unexpected diff output for merge
3302 :hg:`log --patch` may generate unexpected diff output for merge
3300 changesets, as it will only compare the merge changeset against
3303 changesets, as it will only compare the merge changeset against
3301 its first parent. Also, only files different from BOTH parents
3304 its first parent. Also, only files different from BOTH parents
3302 will appear in files:.
3305 will appear in files:.
3303
3306
3304 .. note::
3307 .. note::
3305
3308
3306 For performance reasons, :hg:`log FILE` may omit duplicate changes
3309 For performance reasons, :hg:`log FILE` may omit duplicate changes
3307 made on branches and will not show removals or mode changes. To
3310 made on branches and will not show removals or mode changes. To
3308 see all such changes, use the --removed switch.
3311 see all such changes, use the --removed switch.
3309
3312
3310 .. container:: verbose
3313 .. container:: verbose
3311
3314
3312 .. note::
3315 .. note::
3313
3316
3314 The history resulting from -L/--line-range options depends on diff
3317 The history resulting from -L/--line-range options depends on diff
3315 options; for instance if white-spaces are ignored, respective changes
3318 options; for instance if white-spaces are ignored, respective changes
3316 with only white-spaces in specified line range will not be listed.
3319 with only white-spaces in specified line range will not be listed.
3317
3320
3318 .. container:: verbose
3321 .. container:: verbose
3319
3322
3320 Some examples:
3323 Some examples:
3321
3324
3322 - changesets with full descriptions and file lists::
3325 - changesets with full descriptions and file lists::
3323
3326
3324 hg log -v
3327 hg log -v
3325
3328
3326 - changesets ancestral to the working directory::
3329 - changesets ancestral to the working directory::
3327
3330
3328 hg log -f
3331 hg log -f
3329
3332
3330 - last 10 commits on the current branch::
3333 - last 10 commits on the current branch::
3331
3334
3332 hg log -l 10 -b .
3335 hg log -l 10 -b .
3333
3336
3334 - changesets showing all modifications of a file, including removals::
3337 - changesets showing all modifications of a file, including removals::
3335
3338
3336 hg log --removed file.c
3339 hg log --removed file.c
3337
3340
3338 - all changesets that touch a directory, with diffs, excluding merges::
3341 - all changesets that touch a directory, with diffs, excluding merges::
3339
3342
3340 hg log -Mp lib/
3343 hg log -Mp lib/
3341
3344
3342 - all revision numbers that match a keyword::
3345 - all revision numbers that match a keyword::
3343
3346
3344 hg log -k bug --template "{rev}\\n"
3347 hg log -k bug --template "{rev}\\n"
3345
3348
3346 - the full hash identifier of the working directory parent::
3349 - the full hash identifier of the working directory parent::
3347
3350
3348 hg log -r . --template "{node}\\n"
3351 hg log -r . --template "{node}\\n"
3349
3352
3350 - list available log templates::
3353 - list available log templates::
3351
3354
3352 hg log -T list
3355 hg log -T list
3353
3356
3354 - check if a given changeset is included in a tagged release::
3357 - check if a given changeset is included in a tagged release::
3355
3358
3356 hg log -r "a21ccf and ancestor(1.9)"
3359 hg log -r "a21ccf and ancestor(1.9)"
3357
3360
3358 - find all changesets by some user in a date range::
3361 - find all changesets by some user in a date range::
3359
3362
3360 hg log -k alice -d "may 2008 to jul 2008"
3363 hg log -k alice -d "may 2008 to jul 2008"
3361
3364
3362 - summary of all changesets after the last tag::
3365 - summary of all changesets after the last tag::
3363
3366
3364 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3367 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3365
3368
3366 - changesets touching lines 13 to 23 for file.c::
3369 - changesets touching lines 13 to 23 for file.c::
3367
3370
3368 hg log -L file.c,13:23
3371 hg log -L file.c,13:23
3369
3372
3370 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3373 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3371 main.c with patch::
3374 main.c with patch::
3372
3375
3373 hg log -L file.c,13:23 -L main.c,2:6 -p
3376 hg log -L file.c,13:23 -L main.c,2:6 -p
3374
3377
3375 See :hg:`help dates` for a list of formats valid for -d/--date.
3378 See :hg:`help dates` for a list of formats valid for -d/--date.
3376
3379
3377 See :hg:`help revisions` for more about specifying and ordering
3380 See :hg:`help revisions` for more about specifying and ordering
3378 revisions.
3381 revisions.
3379
3382
3380 See :hg:`help templates` for more about pre-packaged styles and
3383 See :hg:`help templates` for more about pre-packaged styles and
3381 specifying custom templates. The default template used by the log
3384 specifying custom templates. The default template used by the log
3382 command can be customized via the ``ui.logtemplate`` configuration
3385 command can be customized via the ``ui.logtemplate`` configuration
3383 setting.
3386 setting.
3384
3387
3385 Returns 0 on success.
3388 Returns 0 on success.
3386
3389
3387 """
3390 """
3388 opts = pycompat.byteskwargs(opts)
3391 opts = pycompat.byteskwargs(opts)
3389 linerange = opts.get('line_range')
3392 linerange = opts.get('line_range')
3390
3393
3391 if linerange and not opts.get('follow'):
3394 if linerange and not opts.get('follow'):
3392 raise error.Abort(_('--line-range requires --follow'))
3395 raise error.Abort(_('--line-range requires --follow'))
3393
3396
3394 if linerange and pats:
3397 if linerange and pats:
3395 raise error.Abort(
3398 raise error.Abort(
3396 _('FILE arguments are not compatible with --line-range option')
3399 _('FILE arguments are not compatible with --line-range option')
3397 )
3400 )
3398
3401
3399 if opts.get('follow') and opts.get('rev'):
3402 if opts.get('follow') and opts.get('rev'):
3400 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3403 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3401 del opts['follow']
3404 del opts['follow']
3402
3405
3403 if opts.get('graph'):
3406 if opts.get('graph'):
3404 if linerange:
3407 if linerange:
3405 raise error.Abort(_('graph not supported with line range patterns'))
3408 raise error.Abort(_('graph not supported with line range patterns'))
3406 return cmdutil.graphlog(ui, repo, pats, opts)
3409 return cmdutil.graphlog(ui, repo, pats, opts)
3407
3410
3408 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3411 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3409 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3412 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3410 hunksfilter = None
3413 hunksfilter = None
3411
3414
3412 if linerange:
3415 if linerange:
3413 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3416 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3414 repo, revs, opts)
3417 repo, revs, opts)
3415
3418
3416 if filematcher is not None and lrfilematcher is not None:
3419 if filematcher is not None and lrfilematcher is not None:
3417 basefilematcher = filematcher
3420 basefilematcher = filematcher
3418
3421
3419 def filematcher(rev):
3422 def filematcher(rev):
3420 files = (basefilematcher(rev).files()
3423 files = (basefilematcher(rev).files()
3421 + lrfilematcher(rev).files())
3424 + lrfilematcher(rev).files())
3422 return scmutil.matchfiles(repo, files)
3425 return scmutil.matchfiles(repo, files)
3423
3426
3424 elif filematcher is None:
3427 elif filematcher is None:
3425 filematcher = lrfilematcher
3428 filematcher = lrfilematcher
3426
3429
3427 limit = cmdutil.loglimit(opts)
3430 limit = cmdutil.loglimit(opts)
3428 count = 0
3431 count = 0
3429
3432
3430 getrenamed = None
3433 getrenamed = None
3431 if opts.get('copies'):
3434 if opts.get('copies'):
3432 endrev = None
3435 endrev = None
3433 if opts.get('rev'):
3436 if opts.get('rev'):
3434 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3437 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3435 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3438 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3436
3439
3437 ui.pager('log')
3440 ui.pager('log')
3438 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3441 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3439 for rev in revs:
3442 for rev in revs:
3440 if count == limit:
3443 if count == limit:
3441 break
3444 break
3442 ctx = repo[rev]
3445 ctx = repo[rev]
3443 copies = None
3446 copies = None
3444 if getrenamed is not None and rev:
3447 if getrenamed is not None and rev:
3445 copies = []
3448 copies = []
3446 for fn in ctx.files():
3449 for fn in ctx.files():
3447 rename = getrenamed(fn, rev)
3450 rename = getrenamed(fn, rev)
3448 if rename:
3451 if rename:
3449 copies.append((fn, rename[0]))
3452 copies.append((fn, rename[0]))
3450 if filematcher:
3453 if filematcher:
3451 revmatchfn = filematcher(ctx.rev())
3454 revmatchfn = filematcher(ctx.rev())
3452 else:
3455 else:
3453 revmatchfn = None
3456 revmatchfn = None
3454 if hunksfilter:
3457 if hunksfilter:
3455 revhunksfilter = hunksfilter(rev)
3458 revhunksfilter = hunksfilter(rev)
3456 else:
3459 else:
3457 revhunksfilter = None
3460 revhunksfilter = None
3458 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3461 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3459 hunksfilterfn=revhunksfilter)
3462 hunksfilterfn=revhunksfilter)
3460 if displayer.flush(ctx):
3463 if displayer.flush(ctx):
3461 count += 1
3464 count += 1
3462
3465
3463 displayer.close()
3466 displayer.close()
3464
3467
3465 @command('manifest',
3468 @command('manifest',
3466 [('r', 'rev', '', _('revision to display'), _('REV')),
3469 [('r', 'rev', '', _('revision to display'), _('REV')),
3467 ('', 'all', False, _("list files from all revisions"))]
3470 ('', 'all', False, _("list files from all revisions"))]
3468 + formatteropts,
3471 + formatteropts,
3469 _('[-r REV]'), cmdtype=readonly)
3472 _('[-r REV]'), cmdtype=readonly)
3470 def manifest(ui, repo, node=None, rev=None, **opts):
3473 def manifest(ui, repo, node=None, rev=None, **opts):
3471 """output the current or given revision of the project manifest
3474 """output the current or given revision of the project manifest
3472
3475
3473 Print a list of version controlled files for the given revision.
3476 Print a list of version controlled files for the given revision.
3474 If no revision is given, the first parent of the working directory
3477 If no revision is given, the first parent of the working directory
3475 is used, or the null revision if no revision is checked out.
3478 is used, or the null revision if no revision is checked out.
3476
3479
3477 With -v, print file permissions, symlink and executable bits.
3480 With -v, print file permissions, symlink and executable bits.
3478 With --debug, print file revision hashes.
3481 With --debug, print file revision hashes.
3479
3482
3480 If option --all is specified, the list of all files from all revisions
3483 If option --all is specified, the list of all files from all revisions
3481 is printed. This includes deleted and renamed files.
3484 is printed. This includes deleted and renamed files.
3482
3485
3483 Returns 0 on success.
3486 Returns 0 on success.
3484 """
3487 """
3485 opts = pycompat.byteskwargs(opts)
3488 opts = pycompat.byteskwargs(opts)
3486 fm = ui.formatter('manifest', opts)
3489 fm = ui.formatter('manifest', opts)
3487
3490
3488 if opts.get('all'):
3491 if opts.get('all'):
3489 if rev or node:
3492 if rev or node:
3490 raise error.Abort(_("can't specify a revision with --all"))
3493 raise error.Abort(_("can't specify a revision with --all"))
3491
3494
3492 res = []
3495 res = []
3493 prefix = "data/"
3496 prefix = "data/"
3494 suffix = ".i"
3497 suffix = ".i"
3495 plen = len(prefix)
3498 plen = len(prefix)
3496 slen = len(suffix)
3499 slen = len(suffix)
3497 with repo.lock():
3500 with repo.lock():
3498 for fn, b, size in repo.store.datafiles():
3501 for fn, b, size in repo.store.datafiles():
3499 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3500 res.append(fn[plen:-slen])
3503 res.append(fn[plen:-slen])
3501 ui.pager('manifest')
3504 ui.pager('manifest')
3502 for f in res:
3505 for f in res:
3503 fm.startitem()
3506 fm.startitem()
3504 fm.write("path", '%s\n', f)
3507 fm.write("path", '%s\n', f)
3505 fm.end()
3508 fm.end()
3506 return
3509 return
3507
3510
3508 if rev and node:
3511 if rev and node:
3509 raise error.Abort(_("please specify just one revision"))
3512 raise error.Abort(_("please specify just one revision"))
3510
3513
3511 if not node:
3514 if not node:
3512 node = rev
3515 node = rev
3513
3516
3514 char = {'l': '@', 'x': '*', '': ''}
3517 char = {'l': '@', 'x': '*', '': ''}
3515 mode = {'l': '644', 'x': '755', '': '644'}
3518 mode = {'l': '644', 'x': '755', '': '644'}
3516 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3519 if node:
3520 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3517 ctx = scmutil.revsingle(repo, node)
3521 ctx = scmutil.revsingle(repo, node)
3518 mf = ctx.manifest()
3522 mf = ctx.manifest()
3519 ui.pager('manifest')
3523 ui.pager('manifest')
3520 for f in ctx:
3524 for f in ctx:
3521 fm.startitem()
3525 fm.startitem()
3522 fl = ctx[f].flags()
3526 fl = ctx[f].flags()
3523 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3527 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3524 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3528 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3525 fm.write('path', '%s\n', f)
3529 fm.write('path', '%s\n', f)
3526 fm.end()
3530 fm.end()
3527
3531
3528 @command('^merge',
3532 @command('^merge',
3529 [('f', 'force', None,
3533 [('f', 'force', None,
3530 _('force a merge including outstanding changes (DEPRECATED)')),
3534 _('force a merge including outstanding changes (DEPRECATED)')),
3531 ('r', 'rev', '', _('revision to merge'), _('REV')),
3535 ('r', 'rev', '', _('revision to merge'), _('REV')),
3532 ('P', 'preview', None,
3536 ('P', 'preview', None,
3533 _('review revisions to merge (no merge is performed)'))
3537 _('review revisions to merge (no merge is performed)'))
3534 ] + mergetoolopts,
3538 ] + mergetoolopts,
3535 _('[-P] [[-r] REV]'))
3539 _('[-P] [[-r] REV]'))
3536 def merge(ui, repo, node=None, **opts):
3540 def merge(ui, repo, node=None, **opts):
3537 """merge another revision into working directory
3541 """merge another revision into working directory
3538
3542
3539 The current working directory is updated with all changes made in
3543 The current working directory is updated with all changes made in
3540 the requested revision since the last common predecessor revision.
3544 the requested revision since the last common predecessor revision.
3541
3545
3542 Files that changed between either parent are marked as changed for
3546 Files that changed between either parent are marked as changed for
3543 the next commit and a commit must be performed before any further
3547 the next commit and a commit must be performed before any further
3544 updates to the repository are allowed. The next commit will have
3548 updates to the repository are allowed. The next commit will have
3545 two parents.
3549 two parents.
3546
3550
3547 ``--tool`` can be used to specify the merge tool used for file
3551 ``--tool`` can be used to specify the merge tool used for file
3548 merges. It overrides the HGMERGE environment variable and your
3552 merges. It overrides the HGMERGE environment variable and your
3549 configuration files. See :hg:`help merge-tools` for options.
3553 configuration files. See :hg:`help merge-tools` for options.
3550
3554
3551 If no revision is specified, the working directory's parent is a
3555 If no revision is specified, the working directory's parent is a
3552 head revision, and the current branch contains exactly one other
3556 head revision, and the current branch contains exactly one other
3553 head, the other head is merged with by default. Otherwise, an
3557 head, the other head is merged with by default. Otherwise, an
3554 explicit revision with which to merge with must be provided.
3558 explicit revision with which to merge with must be provided.
3555
3559
3556 See :hg:`help resolve` for information on handling file conflicts.
3560 See :hg:`help resolve` for information on handling file conflicts.
3557
3561
3558 To undo an uncommitted merge, use :hg:`update --clean .` which
3562 To undo an uncommitted merge, use :hg:`update --clean .` which
3559 will check out a clean copy of the original merge parent, losing
3563 will check out a clean copy of the original merge parent, losing
3560 all changes.
3564 all changes.
3561
3565
3562 Returns 0 on success, 1 if there are unresolved files.
3566 Returns 0 on success, 1 if there are unresolved files.
3563 """
3567 """
3564
3568
3565 opts = pycompat.byteskwargs(opts)
3569 opts = pycompat.byteskwargs(opts)
3566 if opts.get('rev') and node:
3570 if opts.get('rev') and node:
3567 raise error.Abort(_("please specify just one revision"))
3571 raise error.Abort(_("please specify just one revision"))
3568 if not node:
3572 if not node:
3569 node = opts.get('rev')
3573 node = opts.get('rev')
3570
3574
3571 if node:
3575 if node:
3572 node = scmutil.revsingle(repo, node).node()
3576 node = scmutil.revsingle(repo, node).node()
3573
3577
3574 if not node:
3578 if not node:
3575 node = repo[destutil.destmerge(repo)].node()
3579 node = repo[destutil.destmerge(repo)].node()
3576
3580
3577 if opts.get('preview'):
3581 if opts.get('preview'):
3578 # find nodes that are ancestors of p2 but not of p1
3582 # find nodes that are ancestors of p2 but not of p1
3579 p1 = repo.lookup('.')
3583 p1 = repo.lookup('.')
3580 p2 = repo.lookup(node)
3584 p2 = repo.lookup(node)
3581 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3582
3586
3583 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3584 for node in nodes:
3588 for node in nodes:
3585 displayer.show(repo[node])
3589 displayer.show(repo[node])
3586 displayer.close()
3590 displayer.close()
3587 return 0
3591 return 0
3588
3592
3589 try:
3593 try:
3590 # ui.forcemerge is an internal variable, do not document
3594 # ui.forcemerge is an internal variable, do not document
3591 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3592 force = opts.get('force')
3596 force = opts.get('force')
3593 labels = ['working copy', 'merge rev']
3597 labels = ['working copy', 'merge rev']
3594 return hg.merge(repo, node, force=force, mergeforce=force,
3598 return hg.merge(repo, node, force=force, mergeforce=force,
3595 labels=labels)
3599 labels=labels)
3596 finally:
3600 finally:
3597 ui.setconfig('ui', 'forcemerge', '', 'merge')
3601 ui.setconfig('ui', 'forcemerge', '', 'merge')
3598
3602
3599 @command('outgoing|out',
3603 @command('outgoing|out',
3600 [('f', 'force', None, _('run even when the destination is unrelated')),
3604 [('f', 'force', None, _('run even when the destination is unrelated')),
3601 ('r', 'rev', [],
3605 ('r', 'rev', [],
3602 _('a changeset intended to be included in the destination'), _('REV')),
3606 _('a changeset intended to be included in the destination'), _('REV')),
3603 ('n', 'newest-first', None, _('show newest record first')),
3607 ('n', 'newest-first', None, _('show newest record first')),
3604 ('B', 'bookmarks', False, _('compare bookmarks')),
3608 ('B', 'bookmarks', False, _('compare bookmarks')),
3605 ('b', 'branch', [], _('a specific branch you would like to push'),
3609 ('b', 'branch', [], _('a specific branch you would like to push'),
3606 _('BRANCH')),
3610 _('BRANCH')),
3607 ] + logopts + remoteopts + subrepoopts,
3611 ] + logopts + remoteopts + subrepoopts,
3608 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3612 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3609 def outgoing(ui, repo, dest=None, **opts):
3613 def outgoing(ui, repo, dest=None, **opts):
3610 """show changesets not found in the destination
3614 """show changesets not found in the destination
3611
3615
3612 Show changesets not found in the specified destination repository
3616 Show changesets not found in the specified destination repository
3613 or the default push location. These are the changesets that would
3617 or the default push location. These are the changesets that would
3614 be pushed if a push was requested.
3618 be pushed if a push was requested.
3615
3619
3616 See pull for details of valid destination formats.
3620 See pull for details of valid destination formats.
3617
3621
3618 .. container:: verbose
3622 .. container:: verbose
3619
3623
3620 With -B/--bookmarks, the result of bookmark comparison between
3624 With -B/--bookmarks, the result of bookmark comparison between
3621 local and remote repositories is displayed. With -v/--verbose,
3625 local and remote repositories is displayed. With -v/--verbose,
3622 status is also displayed for each bookmark like below::
3626 status is also displayed for each bookmark like below::
3623
3627
3624 BM1 01234567890a added
3628 BM1 01234567890a added
3625 BM2 deleted
3629 BM2 deleted
3626 BM3 234567890abc advanced
3630 BM3 234567890abc advanced
3627 BM4 34567890abcd diverged
3631 BM4 34567890abcd diverged
3628 BM5 4567890abcde changed
3632 BM5 4567890abcde changed
3629
3633
3630 The action taken when pushing depends on the
3634 The action taken when pushing depends on the
3631 status of each bookmark:
3635 status of each bookmark:
3632
3636
3633 :``added``: push with ``-B`` will create it
3637 :``added``: push with ``-B`` will create it
3634 :``deleted``: push with ``-B`` will delete it
3638 :``deleted``: push with ``-B`` will delete it
3635 :``advanced``: push will update it
3639 :``advanced``: push will update it
3636 :``diverged``: push with ``-B`` will update it
3640 :``diverged``: push with ``-B`` will update it
3637 :``changed``: push with ``-B`` will update it
3641 :``changed``: push with ``-B`` will update it
3638
3642
3639 From the point of view of pushing behavior, bookmarks
3643 From the point of view of pushing behavior, bookmarks
3640 existing only in the remote repository are treated as
3644 existing only in the remote repository are treated as
3641 ``deleted``, even if it is in fact added remotely.
3645 ``deleted``, even if it is in fact added remotely.
3642
3646
3643 Returns 0 if there are outgoing changes, 1 otherwise.
3647 Returns 0 if there are outgoing changes, 1 otherwise.
3644 """
3648 """
3645 opts = pycompat.byteskwargs(opts)
3649 opts = pycompat.byteskwargs(opts)
3646 if opts.get('graph'):
3650 if opts.get('graph'):
3647 cmdutil.checkunsupportedgraphflags([], opts)
3651 cmdutil.checkunsupportedgraphflags([], opts)
3648 o, other = hg._outgoing(ui, repo, dest, opts)
3652 o, other = hg._outgoing(ui, repo, dest, opts)
3649 if not o:
3653 if not o:
3650 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3651 return
3655 return
3652
3656
3653 revdag = cmdutil.graphrevs(repo, o, opts)
3657 revdag = cmdutil.graphrevs(repo, o, opts)
3654 ui.pager('outgoing')
3658 ui.pager('outgoing')
3655 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3659 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3656 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3660 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3657 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3658 return 0
3662 return 0
3659
3663
3660 if opts.get('bookmarks'):
3664 if opts.get('bookmarks'):
3661 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3665 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3662 dest, branches = hg.parseurl(dest, opts.get('branch'))
3666 dest, branches = hg.parseurl(dest, opts.get('branch'))
3663 other = hg.peer(repo, opts, dest)
3667 other = hg.peer(repo, opts, dest)
3664 if 'bookmarks' not in other.listkeys('namespaces'):
3668 if 'bookmarks' not in other.listkeys('namespaces'):
3665 ui.warn(_("remote doesn't support bookmarks\n"))
3669 ui.warn(_("remote doesn't support bookmarks\n"))
3666 return 0
3670 return 0
3667 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3671 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3668 ui.pager('outgoing')
3672 ui.pager('outgoing')
3669 return bookmarks.outgoing(ui, repo, other)
3673 return bookmarks.outgoing(ui, repo, other)
3670
3674
3671 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3675 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3672 try:
3676 try:
3673 return hg.outgoing(ui, repo, dest, opts)
3677 return hg.outgoing(ui, repo, dest, opts)
3674 finally:
3678 finally:
3675 del repo._subtoppath
3679 del repo._subtoppath
3676
3680
3677 @command('parents',
3681 @command('parents',
3678 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3682 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3679 ] + templateopts,
3683 ] + templateopts,
3680 _('[-r REV] [FILE]'),
3684 _('[-r REV] [FILE]'),
3681 inferrepo=True)
3685 inferrepo=True)
3682 def parents(ui, repo, file_=None, **opts):
3686 def parents(ui, repo, file_=None, **opts):
3683 """show the parents of the working directory or revision (DEPRECATED)
3687 """show the parents of the working directory or revision (DEPRECATED)
3684
3688
3685 Print the working directory's parent revisions. If a revision is
3689 Print the working directory's parent revisions. If a revision is
3686 given via -r/--rev, the parent of that revision will be printed.
3690 given via -r/--rev, the parent of that revision will be printed.
3687 If a file argument is given, the revision in which the file was
3691 If a file argument is given, the revision in which the file was
3688 last changed (before the working directory revision or the
3692 last changed (before the working directory revision or the
3689 argument to --rev if given) is printed.
3693 argument to --rev if given) is printed.
3690
3694
3691 This command is equivalent to::
3695 This command is equivalent to::
3692
3696
3693 hg log -r "p1()+p2()" or
3697 hg log -r "p1()+p2()" or
3694 hg log -r "p1(REV)+p2(REV)" or
3698 hg log -r "p1(REV)+p2(REV)" or
3695 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3699 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3696 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3700 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3697
3701
3698 See :hg:`summary` and :hg:`help revsets` for related information.
3702 See :hg:`summary` and :hg:`help revsets` for related information.
3699
3703
3700 Returns 0 on success.
3704 Returns 0 on success.
3701 """
3705 """
3702
3706
3703 opts = pycompat.byteskwargs(opts)
3707 opts = pycompat.byteskwargs(opts)
3704 rev = opts.get('rev')
3708 rev = opts.get('rev')
3705 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3709 if rev:
3710 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3706 ctx = scmutil.revsingle(repo, rev, None)
3711 ctx = scmutil.revsingle(repo, rev, None)
3707
3712
3708 if file_:
3713 if file_:
3709 m = scmutil.match(ctx, (file_,), opts)
3714 m = scmutil.match(ctx, (file_,), opts)
3710 if m.anypats() or len(m.files()) != 1:
3715 if m.anypats() or len(m.files()) != 1:
3711 raise error.Abort(_('can only specify an explicit filename'))
3716 raise error.Abort(_('can only specify an explicit filename'))
3712 file_ = m.files()[0]
3717 file_ = m.files()[0]
3713 filenodes = []
3718 filenodes = []
3714 for cp in ctx.parents():
3719 for cp in ctx.parents():
3715 if not cp:
3720 if not cp:
3716 continue
3721 continue
3717 try:
3722 try:
3718 filenodes.append(cp.filenode(file_))
3723 filenodes.append(cp.filenode(file_))
3719 except error.LookupError:
3724 except error.LookupError:
3720 pass
3725 pass
3721 if not filenodes:
3726 if not filenodes:
3722 raise error.Abort(_("'%s' not found in manifest!") % file_)
3727 raise error.Abort(_("'%s' not found in manifest!") % file_)
3723 p = []
3728 p = []
3724 for fn in filenodes:
3729 for fn in filenodes:
3725 fctx = repo.filectx(file_, fileid=fn)
3730 fctx = repo.filectx(file_, fileid=fn)
3726 p.append(fctx.node())
3731 p.append(fctx.node())
3727 else:
3732 else:
3728 p = [cp.node() for cp in ctx.parents()]
3733 p = [cp.node() for cp in ctx.parents()]
3729
3734
3730 displayer = cmdutil.show_changeset(ui, repo, opts)
3735 displayer = cmdutil.show_changeset(ui, repo, opts)
3731 for n in p:
3736 for n in p:
3732 if n != nullid:
3737 if n != nullid:
3733 displayer.show(repo[n])
3738 displayer.show(repo[n])
3734 displayer.close()
3739 displayer.close()
3735
3740
3736 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3741 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3737 cmdtype=readonly)
3742 cmdtype=readonly)
3738 def paths(ui, repo, search=None, **opts):
3743 def paths(ui, repo, search=None, **opts):
3739 """show aliases for remote repositories
3744 """show aliases for remote repositories
3740
3745
3741 Show definition of symbolic path name NAME. If no name is given,
3746 Show definition of symbolic path name NAME. If no name is given,
3742 show definition of all available names.
3747 show definition of all available names.
3743
3748
3744 Option -q/--quiet suppresses all output when searching for NAME
3749 Option -q/--quiet suppresses all output when searching for NAME
3745 and shows only the path names when listing all definitions.
3750 and shows only the path names when listing all definitions.
3746
3751
3747 Path names are defined in the [paths] section of your
3752 Path names are defined in the [paths] section of your
3748 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3753 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3749 repository, ``.hg/hgrc`` is used, too.
3754 repository, ``.hg/hgrc`` is used, too.
3750
3755
3751 The path names ``default`` and ``default-push`` have a special
3756 The path names ``default`` and ``default-push`` have a special
3752 meaning. When performing a push or pull operation, they are used
3757 meaning. When performing a push or pull operation, they are used
3753 as fallbacks if no location is specified on the command-line.
3758 as fallbacks if no location is specified on the command-line.
3754 When ``default-push`` is set, it will be used for push and
3759 When ``default-push`` is set, it will be used for push and
3755 ``default`` will be used for pull; otherwise ``default`` is used
3760 ``default`` will be used for pull; otherwise ``default`` is used
3756 as the fallback for both. When cloning a repository, the clone
3761 as the fallback for both. When cloning a repository, the clone
3757 source is written as ``default`` in ``.hg/hgrc``.
3762 source is written as ``default`` in ``.hg/hgrc``.
3758
3763
3759 .. note::
3764 .. note::
3760
3765
3761 ``default`` and ``default-push`` apply to all inbound (e.g.
3766 ``default`` and ``default-push`` apply to all inbound (e.g.
3762 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3767 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3763 and :hg:`bundle`) operations.
3768 and :hg:`bundle`) operations.
3764
3769
3765 See :hg:`help urls` for more information.
3770 See :hg:`help urls` for more information.
3766
3771
3767 Returns 0 on success.
3772 Returns 0 on success.
3768 """
3773 """
3769
3774
3770 opts = pycompat.byteskwargs(opts)
3775 opts = pycompat.byteskwargs(opts)
3771 ui.pager('paths')
3776 ui.pager('paths')
3772 if search:
3777 if search:
3773 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3778 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3774 if name == search]
3779 if name == search]
3775 else:
3780 else:
3776 pathitems = sorted(ui.paths.iteritems())
3781 pathitems = sorted(ui.paths.iteritems())
3777
3782
3778 fm = ui.formatter('paths', opts)
3783 fm = ui.formatter('paths', opts)
3779 if fm.isplain():
3784 if fm.isplain():
3780 hidepassword = util.hidepassword
3785 hidepassword = util.hidepassword
3781 else:
3786 else:
3782 hidepassword = str
3787 hidepassword = str
3783 if ui.quiet:
3788 if ui.quiet:
3784 namefmt = '%s\n'
3789 namefmt = '%s\n'
3785 else:
3790 else:
3786 namefmt = '%s = '
3791 namefmt = '%s = '
3787 showsubopts = not search and not ui.quiet
3792 showsubopts = not search and not ui.quiet
3788
3793
3789 for name, path in pathitems:
3794 for name, path in pathitems:
3790 fm.startitem()
3795 fm.startitem()
3791 fm.condwrite(not search, 'name', namefmt, name)
3796 fm.condwrite(not search, 'name', namefmt, name)
3792 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3797 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3793 for subopt, value in sorted(path.suboptions.items()):
3798 for subopt, value in sorted(path.suboptions.items()):
3794 assert subopt not in ('name', 'url')
3799 assert subopt not in ('name', 'url')
3795 if showsubopts:
3800 if showsubopts:
3796 fm.plain('%s:%s = ' % (name, subopt))
3801 fm.plain('%s:%s = ' % (name, subopt))
3797 fm.condwrite(showsubopts, subopt, '%s\n', value)
3802 fm.condwrite(showsubopts, subopt, '%s\n', value)
3798
3803
3799 fm.end()
3804 fm.end()
3800
3805
3801 if search and not pathitems:
3806 if search and not pathitems:
3802 if not ui.quiet:
3807 if not ui.quiet:
3803 ui.warn(_("not found!\n"))
3808 ui.warn(_("not found!\n"))
3804 return 1
3809 return 1
3805 else:
3810 else:
3806 return 0
3811 return 0
3807
3812
3808 @command('phase',
3813 @command('phase',
3809 [('p', 'public', False, _('set changeset phase to public')),
3814 [('p', 'public', False, _('set changeset phase to public')),
3810 ('d', 'draft', False, _('set changeset phase to draft')),
3815 ('d', 'draft', False, _('set changeset phase to draft')),
3811 ('s', 'secret', False, _('set changeset phase to secret')),
3816 ('s', 'secret', False, _('set changeset phase to secret')),
3812 ('f', 'force', False, _('allow to move boundary backward')),
3817 ('f', 'force', False, _('allow to move boundary backward')),
3813 ('r', 'rev', [], _('target revision'), _('REV')),
3818 ('r', 'rev', [], _('target revision'), _('REV')),
3814 ],
3819 ],
3815 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3820 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3816 def phase(ui, repo, *revs, **opts):
3821 def phase(ui, repo, *revs, **opts):
3817 """set or show the current phase name
3822 """set or show the current phase name
3818
3823
3819 With no argument, show the phase name of the current revision(s).
3824 With no argument, show the phase name of the current revision(s).
3820
3825
3821 With one of -p/--public, -d/--draft or -s/--secret, change the
3826 With one of -p/--public, -d/--draft or -s/--secret, change the
3822 phase value of the specified revisions.
3827 phase value of the specified revisions.
3823
3828
3824 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3829 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3825 lower phase to a higher phase. Phases are ordered as follows::
3830 lower phase to a higher phase. Phases are ordered as follows::
3826
3831
3827 public < draft < secret
3832 public < draft < secret
3828
3833
3829 Returns 0 on success, 1 if some phases could not be changed.
3834 Returns 0 on success, 1 if some phases could not be changed.
3830
3835
3831 (For more information about the phases concept, see :hg:`help phases`.)
3836 (For more information about the phases concept, see :hg:`help phases`.)
3832 """
3837 """
3833 opts = pycompat.byteskwargs(opts)
3838 opts = pycompat.byteskwargs(opts)
3834 # search for a unique phase argument
3839 # search for a unique phase argument
3835 targetphase = None
3840 targetphase = None
3836 for idx, name in enumerate(phases.phasenames):
3841 for idx, name in enumerate(phases.phasenames):
3837 if opts[name]:
3842 if opts[name]:
3838 if targetphase is not None:
3843 if targetphase is not None:
3839 raise error.Abort(_('only one phase can be specified'))
3844 raise error.Abort(_('only one phase can be specified'))
3840 targetphase = idx
3845 targetphase = idx
3841
3846
3842 # look for specified revision
3847 # look for specified revision
3843 revs = list(revs)
3848 revs = list(revs)
3844 revs.extend(opts['rev'])
3849 revs.extend(opts['rev'])
3845 if not revs:
3850 if not revs:
3846 # display both parents as the second parent phase can influence
3851 # display both parents as the second parent phase can influence
3847 # the phase of a merge commit
3852 # the phase of a merge commit
3848 revs = [c.rev() for c in repo[None].parents()]
3853 revs = [c.rev() for c in repo[None].parents()]
3849
3854
3850 revs = scmutil.revrange(repo, revs)
3855 revs = scmutil.revrange(repo, revs)
3851
3856
3852 lock = None
3857 lock = None
3853 ret = 0
3858 ret = 0
3854 if targetphase is None:
3859 if targetphase is None:
3855 # display
3860 # display
3856 for r in revs:
3861 for r in revs:
3857 ctx = repo[r]
3862 ctx = repo[r]
3858 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3863 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3859 else:
3864 else:
3860 tr = None
3865 tr = None
3861 lock = repo.lock()
3866 lock = repo.lock()
3862 try:
3867 try:
3863 tr = repo.transaction("phase")
3868 tr = repo.transaction("phase")
3864 # set phase
3869 # set phase
3865 if not revs:
3870 if not revs:
3866 raise error.Abort(_('empty revision set'))
3871 raise error.Abort(_('empty revision set'))
3867 nodes = [repo[r].node() for r in revs]
3872 nodes = [repo[r].node() for r in revs]
3868 # moving revision from public to draft may hide them
3873 # moving revision from public to draft may hide them
3869 # We have to check result on an unfiltered repository
3874 # We have to check result on an unfiltered repository
3870 unfi = repo.unfiltered()
3875 unfi = repo.unfiltered()
3871 getphase = unfi._phasecache.phase
3876 getphase = unfi._phasecache.phase
3872 olddata = [getphase(unfi, r) for r in unfi]
3877 olddata = [getphase(unfi, r) for r in unfi]
3873 phases.advanceboundary(repo, tr, targetphase, nodes)
3878 phases.advanceboundary(repo, tr, targetphase, nodes)
3874 if opts['force']:
3879 if opts['force']:
3875 phases.retractboundary(repo, tr, targetphase, nodes)
3880 phases.retractboundary(repo, tr, targetphase, nodes)
3876 tr.close()
3881 tr.close()
3877 finally:
3882 finally:
3878 if tr is not None:
3883 if tr is not None:
3879 tr.release()
3884 tr.release()
3880 lock.release()
3885 lock.release()
3881 getphase = unfi._phasecache.phase
3886 getphase = unfi._phasecache.phase
3882 newdata = [getphase(unfi, r) for r in unfi]
3887 newdata = [getphase(unfi, r) for r in unfi]
3883 changes = sum(newdata[r] != olddata[r] for r in unfi)
3888 changes = sum(newdata[r] != olddata[r] for r in unfi)
3884 cl = unfi.changelog
3889 cl = unfi.changelog
3885 rejected = [n for n in nodes
3890 rejected = [n for n in nodes
3886 if newdata[cl.rev(n)] < targetphase]
3891 if newdata[cl.rev(n)] < targetphase]
3887 if rejected:
3892 if rejected:
3888 ui.warn(_('cannot move %i changesets to a higher '
3893 ui.warn(_('cannot move %i changesets to a higher '
3889 'phase, use --force\n') % len(rejected))
3894 'phase, use --force\n') % len(rejected))
3890 ret = 1
3895 ret = 1
3891 if changes:
3896 if changes:
3892 msg = _('phase changed for %i changesets\n') % changes
3897 msg = _('phase changed for %i changesets\n') % changes
3893 if ret:
3898 if ret:
3894 ui.status(msg)
3899 ui.status(msg)
3895 else:
3900 else:
3896 ui.note(msg)
3901 ui.note(msg)
3897 else:
3902 else:
3898 ui.warn(_('no phases changed\n'))
3903 ui.warn(_('no phases changed\n'))
3899 return ret
3904 return ret
3900
3905
3901 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3906 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3902 """Run after a changegroup has been added via pull/unbundle
3907 """Run after a changegroup has been added via pull/unbundle
3903
3908
3904 This takes arguments below:
3909 This takes arguments below:
3905
3910
3906 :modheads: change of heads by pull/unbundle
3911 :modheads: change of heads by pull/unbundle
3907 :optupdate: updating working directory is needed or not
3912 :optupdate: updating working directory is needed or not
3908 :checkout: update destination revision (or None to default destination)
3913 :checkout: update destination revision (or None to default destination)
3909 :brev: a name, which might be a bookmark to be activated after updating
3914 :brev: a name, which might be a bookmark to be activated after updating
3910 """
3915 """
3911 if modheads == 0:
3916 if modheads == 0:
3912 return
3917 return
3913 if optupdate:
3918 if optupdate:
3914 try:
3919 try:
3915 return hg.updatetotally(ui, repo, checkout, brev)
3920 return hg.updatetotally(ui, repo, checkout, brev)
3916 except error.UpdateAbort as inst:
3921 except error.UpdateAbort as inst:
3917 msg = _("not updating: %s") % str(inst)
3922 msg = _("not updating: %s") % str(inst)
3918 hint = inst.hint
3923 hint = inst.hint
3919 raise error.UpdateAbort(msg, hint=hint)
3924 raise error.UpdateAbort(msg, hint=hint)
3920 if modheads > 1:
3925 if modheads > 1:
3921 currentbranchheads = len(repo.branchheads())
3926 currentbranchheads = len(repo.branchheads())
3922 if currentbranchheads == modheads:
3927 if currentbranchheads == modheads:
3923 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3928 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3924 elif currentbranchheads > 1:
3929 elif currentbranchheads > 1:
3925 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3930 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3926 "merge)\n"))
3931 "merge)\n"))
3927 else:
3932 else:
3928 ui.status(_("(run 'hg heads' to see heads)\n"))
3933 ui.status(_("(run 'hg heads' to see heads)\n"))
3929 elif not ui.configbool('commands', 'update.requiredest'):
3934 elif not ui.configbool('commands', 'update.requiredest'):
3930 ui.status(_("(run 'hg update' to get a working copy)\n"))
3935 ui.status(_("(run 'hg update' to get a working copy)\n"))
3931
3936
3932 @command('^pull',
3937 @command('^pull',
3933 [('u', 'update', None,
3938 [('u', 'update', None,
3934 _('update to new branch head if new descendants were pulled')),
3939 _('update to new branch head if new descendants were pulled')),
3935 ('f', 'force', None, _('run even when remote repository is unrelated')),
3940 ('f', 'force', None, _('run even when remote repository is unrelated')),
3936 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3937 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3942 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3938 ('b', 'branch', [], _('a specific branch you would like to pull'),
3943 ('b', 'branch', [], _('a specific branch you would like to pull'),
3939 _('BRANCH')),
3944 _('BRANCH')),
3940 ] + remoteopts,
3945 ] + remoteopts,
3941 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3946 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3942 def pull(ui, repo, source="default", **opts):
3947 def pull(ui, repo, source="default", **opts):
3943 """pull changes from the specified source
3948 """pull changes from the specified source
3944
3949
3945 Pull changes from a remote repository to a local one.
3950 Pull changes from a remote repository to a local one.
3946
3951
3947 This finds all changes from the repository at the specified path
3952 This finds all changes from the repository at the specified path
3948 or URL and adds them to a local repository (the current one unless
3953 or URL and adds them to a local repository (the current one unless
3949 -R is specified). By default, this does not update the copy of the
3954 -R is specified). By default, this does not update the copy of the
3950 project in the working directory.
3955 project in the working directory.
3951
3956
3952 Use :hg:`incoming` if you want to see what would have been added
3957 Use :hg:`incoming` if you want to see what would have been added
3953 by a pull at the time you issued this command. If you then decide
3958 by a pull at the time you issued this command. If you then decide
3954 to add those changes to the repository, you should use :hg:`pull
3959 to add those changes to the repository, you should use :hg:`pull
3955 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3960 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3956
3961
3957 If SOURCE is omitted, the 'default' path will be used.
3962 If SOURCE is omitted, the 'default' path will be used.
3958 See :hg:`help urls` for more information.
3963 See :hg:`help urls` for more information.
3959
3964
3960 Specifying bookmark as ``.`` is equivalent to specifying the active
3965 Specifying bookmark as ``.`` is equivalent to specifying the active
3961 bookmark's name.
3966 bookmark's name.
3962
3967
3963 Returns 0 on success, 1 if an update had unresolved files.
3968 Returns 0 on success, 1 if an update had unresolved files.
3964 """
3969 """
3965
3970
3966 opts = pycompat.byteskwargs(opts)
3971 opts = pycompat.byteskwargs(opts)
3967 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3972 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3968 msg = _('update destination required by configuration')
3973 msg = _('update destination required by configuration')
3969 hint = _('use hg pull followed by hg update DEST')
3974 hint = _('use hg pull followed by hg update DEST')
3970 raise error.Abort(msg, hint=hint)
3975 raise error.Abort(msg, hint=hint)
3971
3976
3972 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3977 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3973 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3978 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3974 other = hg.peer(repo, opts, source)
3979 other = hg.peer(repo, opts, source)
3975 try:
3980 try:
3976 revs, checkout = hg.addbranchrevs(repo, other, branches,
3981 revs, checkout = hg.addbranchrevs(repo, other, branches,
3977 opts.get('rev'))
3982 opts.get('rev'))
3978
3983
3979
3984
3980 pullopargs = {}
3985 pullopargs = {}
3981 if opts.get('bookmark'):
3986 if opts.get('bookmark'):
3982 if not revs:
3987 if not revs:
3983 revs = []
3988 revs = []
3984 # The list of bookmark used here is not the one used to actually
3989 # The list of bookmark used here is not the one used to actually
3985 # update the bookmark name. This can result in the revision pulled
3990 # update the bookmark name. This can result in the revision pulled
3986 # not ending up with the name of the bookmark because of a race
3991 # not ending up with the name of the bookmark because of a race
3987 # condition on the server. (See issue 4689 for details)
3992 # condition on the server. (See issue 4689 for details)
3988 remotebookmarks = other.listkeys('bookmarks')
3993 remotebookmarks = other.listkeys('bookmarks')
3989 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3994 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3990 pullopargs['remotebookmarks'] = remotebookmarks
3995 pullopargs['remotebookmarks'] = remotebookmarks
3991 for b in opts['bookmark']:
3996 for b in opts['bookmark']:
3992 b = repo._bookmarks.expandname(b)
3997 b = repo._bookmarks.expandname(b)
3993 if b not in remotebookmarks:
3998 if b not in remotebookmarks:
3994 raise error.Abort(_('remote bookmark %s not found!') % b)
3999 raise error.Abort(_('remote bookmark %s not found!') % b)
3995 revs.append(hex(remotebookmarks[b]))
4000 revs.append(hex(remotebookmarks[b]))
3996
4001
3997 if revs:
4002 if revs:
3998 try:
4003 try:
3999 # When 'rev' is a bookmark name, we cannot guarantee that it
4004 # When 'rev' is a bookmark name, we cannot guarantee that it
4000 # will be updated with that name because of a race condition
4005 # will be updated with that name because of a race condition
4001 # server side. (See issue 4689 for details)
4006 # server side. (See issue 4689 for details)
4002 oldrevs = revs
4007 oldrevs = revs
4003 revs = [] # actually, nodes
4008 revs = [] # actually, nodes
4004 for r in oldrevs:
4009 for r in oldrevs:
4005 node = other.lookup(r)
4010 node = other.lookup(r)
4006 revs.append(node)
4011 revs.append(node)
4007 if r == checkout:
4012 if r == checkout:
4008 checkout = node
4013 checkout = node
4009 except error.CapabilityError:
4014 except error.CapabilityError:
4010 err = _("other repository doesn't support revision lookup, "
4015 err = _("other repository doesn't support revision lookup, "
4011 "so a rev cannot be specified.")
4016 "so a rev cannot be specified.")
4012 raise error.Abort(err)
4017 raise error.Abort(err)
4013
4018
4014 pullopargs.update(opts.get('opargs', {}))
4019 pullopargs.update(opts.get('opargs', {}))
4015 modheads = exchange.pull(repo, other, heads=revs,
4020 modheads = exchange.pull(repo, other, heads=revs,
4016 force=opts.get('force'),
4021 force=opts.get('force'),
4017 bookmarks=opts.get('bookmark', ()),
4022 bookmarks=opts.get('bookmark', ()),
4018 opargs=pullopargs).cgresult
4023 opargs=pullopargs).cgresult
4019
4024
4020 # brev is a name, which might be a bookmark to be activated at
4025 # brev is a name, which might be a bookmark to be activated at
4021 # the end of the update. In other words, it is an explicit
4026 # the end of the update. In other words, it is an explicit
4022 # destination of the update
4027 # destination of the update
4023 brev = None
4028 brev = None
4024
4029
4025 if checkout:
4030 if checkout:
4026 checkout = str(repo.changelog.rev(checkout))
4031 checkout = str(repo.changelog.rev(checkout))
4027
4032
4028 # order below depends on implementation of
4033 # order below depends on implementation of
4029 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4034 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4030 # because 'checkout' is determined without it.
4035 # because 'checkout' is determined without it.
4031 if opts.get('rev'):
4036 if opts.get('rev'):
4032 brev = opts['rev'][0]
4037 brev = opts['rev'][0]
4033 elif opts.get('branch'):
4038 elif opts.get('branch'):
4034 brev = opts['branch'][0]
4039 brev = opts['branch'][0]
4035 else:
4040 else:
4036 brev = branches[0]
4041 brev = branches[0]
4037 repo._subtoppath = source
4042 repo._subtoppath = source
4038 try:
4043 try:
4039 ret = postincoming(ui, repo, modheads, opts.get('update'),
4044 ret = postincoming(ui, repo, modheads, opts.get('update'),
4040 checkout, brev)
4045 checkout, brev)
4041
4046
4042 finally:
4047 finally:
4043 del repo._subtoppath
4048 del repo._subtoppath
4044
4049
4045 finally:
4050 finally:
4046 other.close()
4051 other.close()
4047 return ret
4052 return ret
4048
4053
4049 @command('^push',
4054 @command('^push',
4050 [('f', 'force', None, _('force push')),
4055 [('f', 'force', None, _('force push')),
4051 ('r', 'rev', [],
4056 ('r', 'rev', [],
4052 _('a changeset intended to be included in the destination'),
4057 _('a changeset intended to be included in the destination'),
4053 _('REV')),
4058 _('REV')),
4054 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4059 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4055 ('b', 'branch', [],
4060 ('b', 'branch', [],
4056 _('a specific branch you would like to push'), _('BRANCH')),
4061 _('a specific branch you would like to push'), _('BRANCH')),
4057 ('', 'new-branch', False, _('allow pushing a new branch')),
4062 ('', 'new-branch', False, _('allow pushing a new branch')),
4058 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4063 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4059 ] + remoteopts,
4064 ] + remoteopts,
4060 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4061 def push(ui, repo, dest=None, **opts):
4066 def push(ui, repo, dest=None, **opts):
4062 """push changes to the specified destination
4067 """push changes to the specified destination
4063
4068
4064 Push changesets from the local repository to the specified
4069 Push changesets from the local repository to the specified
4065 destination.
4070 destination.
4066
4071
4067 This operation is symmetrical to pull: it is identical to a pull
4072 This operation is symmetrical to pull: it is identical to a pull
4068 in the destination repository from the current one.
4073 in the destination repository from the current one.
4069
4074
4070 By default, push will not allow creation of new heads at the
4075 By default, push will not allow creation of new heads at the
4071 destination, since multiple heads would make it unclear which head
4076 destination, since multiple heads would make it unclear which head
4072 to use. In this situation, it is recommended to pull and merge
4077 to use. In this situation, it is recommended to pull and merge
4073 before pushing.
4078 before pushing.
4074
4079
4075 Use --new-branch if you want to allow push to create a new named
4080 Use --new-branch if you want to allow push to create a new named
4076 branch that is not present at the destination. This allows you to
4081 branch that is not present at the destination. This allows you to
4077 only create a new branch without forcing other changes.
4082 only create a new branch without forcing other changes.
4078
4083
4079 .. note::
4084 .. note::
4080
4085
4081 Extra care should be taken with the -f/--force option,
4086 Extra care should be taken with the -f/--force option,
4082 which will push all new heads on all branches, an action which will
4087 which will push all new heads on all branches, an action which will
4083 almost always cause confusion for collaborators.
4088 almost always cause confusion for collaborators.
4084
4089
4085 If -r/--rev is used, the specified revision and all its ancestors
4090 If -r/--rev is used, the specified revision and all its ancestors
4086 will be pushed to the remote repository.
4091 will be pushed to the remote repository.
4087
4092
4088 If -B/--bookmark is used, the specified bookmarked revision, its
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4089 ancestors, and the bookmark will be pushed to the remote
4094 ancestors, and the bookmark will be pushed to the remote
4090 repository. Specifying ``.`` is equivalent to specifying the active
4095 repository. Specifying ``.`` is equivalent to specifying the active
4091 bookmark's name.
4096 bookmark's name.
4092
4097
4093 Please see :hg:`help urls` for important details about ``ssh://``
4098 Please see :hg:`help urls` for important details about ``ssh://``
4094 URLs. If DESTINATION is omitted, a default path will be used.
4099 URLs. If DESTINATION is omitted, a default path will be used.
4095
4100
4096 .. container:: verbose
4101 .. container:: verbose
4097
4102
4098 The --pushvars option sends strings to the server that become
4103 The --pushvars option sends strings to the server that become
4099 environment variables prepended with ``HG_USERVAR_``. For example,
4104 environment variables prepended with ``HG_USERVAR_``. For example,
4100 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4105 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4101 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4106 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4102
4107
4103 pushvars can provide for user-overridable hooks as well as set debug
4108 pushvars can provide for user-overridable hooks as well as set debug
4104 levels. One example is having a hook that blocks commits containing
4109 levels. One example is having a hook that blocks commits containing
4105 conflict markers, but enables the user to override the hook if the file
4110 conflict markers, but enables the user to override the hook if the file
4106 is using conflict markers for testing purposes or the file format has
4111 is using conflict markers for testing purposes or the file format has
4107 strings that look like conflict markers.
4112 strings that look like conflict markers.
4108
4113
4109 By default, servers will ignore `--pushvars`. To enable it add the
4114 By default, servers will ignore `--pushvars`. To enable it add the
4110 following to your configuration file::
4115 following to your configuration file::
4111
4116
4112 [push]
4117 [push]
4113 pushvars.server = true
4118 pushvars.server = true
4114
4119
4115 Returns 0 if push was successful, 1 if nothing to push.
4120 Returns 0 if push was successful, 1 if nothing to push.
4116 """
4121 """
4117
4122
4118 opts = pycompat.byteskwargs(opts)
4123 opts = pycompat.byteskwargs(opts)
4119 if opts.get('bookmark'):
4124 if opts.get('bookmark'):
4120 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4125 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4121 for b in opts['bookmark']:
4126 for b in opts['bookmark']:
4122 # translate -B options to -r so changesets get pushed
4127 # translate -B options to -r so changesets get pushed
4123 b = repo._bookmarks.expandname(b)
4128 b = repo._bookmarks.expandname(b)
4124 if b in repo._bookmarks:
4129 if b in repo._bookmarks:
4125 opts.setdefault('rev', []).append(b)
4130 opts.setdefault('rev', []).append(b)
4126 else:
4131 else:
4127 # if we try to push a deleted bookmark, translate it to null
4132 # if we try to push a deleted bookmark, translate it to null
4128 # this lets simultaneous -r, -b options continue working
4133 # this lets simultaneous -r, -b options continue working
4129 opts.setdefault('rev', []).append("null")
4134 opts.setdefault('rev', []).append("null")
4130
4135
4131 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4136 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4132 if not path:
4137 if not path:
4133 raise error.Abort(_('default repository not configured!'),
4138 raise error.Abort(_('default repository not configured!'),
4134 hint=_("see 'hg help config.paths'"))
4139 hint=_("see 'hg help config.paths'"))
4135 dest = path.pushloc or path.loc
4140 dest = path.pushloc or path.loc
4136 branches = (path.branch, opts.get('branch') or [])
4141 branches = (path.branch, opts.get('branch') or [])
4137 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4142 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4138 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4143 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4139 other = hg.peer(repo, opts, dest)
4144 other = hg.peer(repo, opts, dest)
4140
4145
4141 if revs:
4146 if revs:
4142 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4147 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4143 if not revs:
4148 if not revs:
4144 raise error.Abort(_("specified revisions evaluate to an empty set"),
4149 raise error.Abort(_("specified revisions evaluate to an empty set"),
4145 hint=_("use different revision arguments"))
4150 hint=_("use different revision arguments"))
4146 elif path.pushrev:
4151 elif path.pushrev:
4147 # It doesn't make any sense to specify ancestor revisions. So limit
4152 # It doesn't make any sense to specify ancestor revisions. So limit
4148 # to DAG heads to make discovery simpler.
4153 # to DAG heads to make discovery simpler.
4149 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4154 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4150 revs = scmutil.revrange(repo, [expr])
4155 revs = scmutil.revrange(repo, [expr])
4151 revs = [repo[rev].node() for rev in revs]
4156 revs = [repo[rev].node() for rev in revs]
4152 if not revs:
4157 if not revs:
4153 raise error.Abort(_('default push revset for path evaluates to an '
4158 raise error.Abort(_('default push revset for path evaluates to an '
4154 'empty set'))
4159 'empty set'))
4155
4160
4156 repo._subtoppath = dest
4161 repo._subtoppath = dest
4157 try:
4162 try:
4158 # push subrepos depth-first for coherent ordering
4163 # push subrepos depth-first for coherent ordering
4159 c = repo['']
4164 c = repo['']
4160 subs = c.substate # only repos that are committed
4165 subs = c.substate # only repos that are committed
4161 for s in sorted(subs):
4166 for s in sorted(subs):
4162 result = c.sub(s).push(opts)
4167 result = c.sub(s).push(opts)
4163 if result == 0:
4168 if result == 0:
4164 return not result
4169 return not result
4165 finally:
4170 finally:
4166 del repo._subtoppath
4171 del repo._subtoppath
4167
4172
4168 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4173 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4169 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4174 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4170
4175
4171 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4176 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4172 newbranch=opts.get('new_branch'),
4177 newbranch=opts.get('new_branch'),
4173 bookmarks=opts.get('bookmark', ()),
4178 bookmarks=opts.get('bookmark', ()),
4174 opargs=opargs)
4179 opargs=opargs)
4175
4180
4176 result = not pushop.cgresult
4181 result = not pushop.cgresult
4177
4182
4178 if pushop.bkresult is not None:
4183 if pushop.bkresult is not None:
4179 if pushop.bkresult == 2:
4184 if pushop.bkresult == 2:
4180 result = 2
4185 result = 2
4181 elif not result and pushop.bkresult:
4186 elif not result and pushop.bkresult:
4182 result = 2
4187 result = 2
4183
4188
4184 return result
4189 return result
4185
4190
4186 @command('recover', [])
4191 @command('recover', [])
4187 def recover(ui, repo):
4192 def recover(ui, repo):
4188 """roll back an interrupted transaction
4193 """roll back an interrupted transaction
4189
4194
4190 Recover from an interrupted commit or pull.
4195 Recover from an interrupted commit or pull.
4191
4196
4192 This command tries to fix the repository status after an
4197 This command tries to fix the repository status after an
4193 interrupted operation. It should only be necessary when Mercurial
4198 interrupted operation. It should only be necessary when Mercurial
4194 suggests it.
4199 suggests it.
4195
4200
4196 Returns 0 if successful, 1 if nothing to recover or verify fails.
4201 Returns 0 if successful, 1 if nothing to recover or verify fails.
4197 """
4202 """
4198 if repo.recover():
4203 if repo.recover():
4199 return hg.verify(repo)
4204 return hg.verify(repo)
4200 return 1
4205 return 1
4201
4206
4202 @command('^remove|rm',
4207 @command('^remove|rm',
4203 [('A', 'after', None, _('record delete for missing files')),
4208 [('A', 'after', None, _('record delete for missing files')),
4204 ('f', 'force', None,
4209 ('f', 'force', None,
4205 _('forget added files, delete modified files')),
4210 _('forget added files, delete modified files')),
4206 ] + subrepoopts + walkopts,
4211 ] + subrepoopts + walkopts,
4207 _('[OPTION]... FILE...'),
4212 _('[OPTION]... FILE...'),
4208 inferrepo=True)
4213 inferrepo=True)
4209 def remove(ui, repo, *pats, **opts):
4214 def remove(ui, repo, *pats, **opts):
4210 """remove the specified files on the next commit
4215 """remove the specified files on the next commit
4211
4216
4212 Schedule the indicated files for removal from the current branch.
4217 Schedule the indicated files for removal from the current branch.
4213
4218
4214 This command schedules the files to be removed at the next commit.
4219 This command schedules the files to be removed at the next commit.
4215 To undo a remove before that, see :hg:`revert`. To undo added
4220 To undo a remove before that, see :hg:`revert`. To undo added
4216 files, see :hg:`forget`.
4221 files, see :hg:`forget`.
4217
4222
4218 .. container:: verbose
4223 .. container:: verbose
4219
4224
4220 -A/--after can be used to remove only files that have already
4225 -A/--after can be used to remove only files that have already
4221 been deleted, -f/--force can be used to force deletion, and -Af
4226 been deleted, -f/--force can be used to force deletion, and -Af
4222 can be used to remove files from the next revision without
4227 can be used to remove files from the next revision without
4223 deleting them from the working directory.
4228 deleting them from the working directory.
4224
4229
4225 The following table details the behavior of remove for different
4230 The following table details the behavior of remove for different
4226 file states (columns) and option combinations (rows). The file
4231 file states (columns) and option combinations (rows). The file
4227 states are Added [A], Clean [C], Modified [M] and Missing [!]
4232 states are Added [A], Clean [C], Modified [M] and Missing [!]
4228 (as reported by :hg:`status`). The actions are Warn, Remove
4233 (as reported by :hg:`status`). The actions are Warn, Remove
4229 (from branch) and Delete (from disk):
4234 (from branch) and Delete (from disk):
4230
4235
4231 ========= == == == ==
4236 ========= == == == ==
4232 opt/state A C M !
4237 opt/state A C M !
4233 ========= == == == ==
4238 ========= == == == ==
4234 none W RD W R
4239 none W RD W R
4235 -f R RD RD R
4240 -f R RD RD R
4236 -A W W W R
4241 -A W W W R
4237 -Af R R R R
4242 -Af R R R R
4238 ========= == == == ==
4243 ========= == == == ==
4239
4244
4240 .. note::
4245 .. note::
4241
4246
4242 :hg:`remove` never deletes files in Added [A] state from the
4247 :hg:`remove` never deletes files in Added [A] state from the
4243 working directory, not even if ``--force`` is specified.
4248 working directory, not even if ``--force`` is specified.
4244
4249
4245 Returns 0 on success, 1 if any warnings encountered.
4250 Returns 0 on success, 1 if any warnings encountered.
4246 """
4251 """
4247
4252
4248 opts = pycompat.byteskwargs(opts)
4253 opts = pycompat.byteskwargs(opts)
4249 after, force = opts.get('after'), opts.get('force')
4254 after, force = opts.get('after'), opts.get('force')
4250 if not pats and not after:
4255 if not pats and not after:
4251 raise error.Abort(_('no files specified'))
4256 raise error.Abort(_('no files specified'))
4252
4257
4253 m = scmutil.match(repo[None], pats, opts)
4258 m = scmutil.match(repo[None], pats, opts)
4254 subrepos = opts.get('subrepos')
4259 subrepos = opts.get('subrepos')
4255 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4260 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4256
4261
4257 @command('rename|move|mv',
4262 @command('rename|move|mv',
4258 [('A', 'after', None, _('record a rename that has already occurred')),
4263 [('A', 'after', None, _('record a rename that has already occurred')),
4259 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4264 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4260 ] + walkopts + dryrunopts,
4265 ] + walkopts + dryrunopts,
4261 _('[OPTION]... SOURCE... DEST'))
4266 _('[OPTION]... SOURCE... DEST'))
4262 def rename(ui, repo, *pats, **opts):
4267 def rename(ui, repo, *pats, **opts):
4263 """rename files; equivalent of copy + remove
4268 """rename files; equivalent of copy + remove
4264
4269
4265 Mark dest as copies of sources; mark sources for deletion. If dest
4270 Mark dest as copies of sources; mark sources for deletion. If dest
4266 is a directory, copies are put in that directory. If dest is a
4271 is a directory, copies are put in that directory. If dest is a
4267 file, there can only be one source.
4272 file, there can only be one source.
4268
4273
4269 By default, this command copies the contents of files as they
4274 By default, this command copies the contents of files as they
4270 exist in the working directory. If invoked with -A/--after, the
4275 exist in the working directory. If invoked with -A/--after, the
4271 operation is recorded, but no copying is performed.
4276 operation is recorded, but no copying is performed.
4272
4277
4273 This command takes effect at the next commit. To undo a rename
4278 This command takes effect at the next commit. To undo a rename
4274 before that, see :hg:`revert`.
4279 before that, see :hg:`revert`.
4275
4280
4276 Returns 0 on success, 1 if errors are encountered.
4281 Returns 0 on success, 1 if errors are encountered.
4277 """
4282 """
4278 opts = pycompat.byteskwargs(opts)
4283 opts = pycompat.byteskwargs(opts)
4279 with repo.wlock(False):
4284 with repo.wlock(False):
4280 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4285 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4281
4286
4282 @command('resolve',
4287 @command('resolve',
4283 [('a', 'all', None, _('select all unresolved files')),
4288 [('a', 'all', None, _('select all unresolved files')),
4284 ('l', 'list', None, _('list state of files needing merge')),
4289 ('l', 'list', None, _('list state of files needing merge')),
4285 ('m', 'mark', None, _('mark files as resolved')),
4290 ('m', 'mark', None, _('mark files as resolved')),
4286 ('u', 'unmark', None, _('mark files as unresolved')),
4291 ('u', 'unmark', None, _('mark files as unresolved')),
4287 ('n', 'no-status', None, _('hide status prefix'))]
4292 ('n', 'no-status', None, _('hide status prefix'))]
4288 + mergetoolopts + walkopts + formatteropts,
4293 + mergetoolopts + walkopts + formatteropts,
4289 _('[OPTION]... [FILE]...'),
4294 _('[OPTION]... [FILE]...'),
4290 inferrepo=True)
4295 inferrepo=True)
4291 def resolve(ui, repo, *pats, **opts):
4296 def resolve(ui, repo, *pats, **opts):
4292 """redo merges or set/view the merge status of files
4297 """redo merges or set/view the merge status of files
4293
4298
4294 Merges with unresolved conflicts are often the result of
4299 Merges with unresolved conflicts are often the result of
4295 non-interactive merging using the ``internal:merge`` configuration
4300 non-interactive merging using the ``internal:merge`` configuration
4296 setting, or a command-line merge tool like ``diff3``. The resolve
4301 setting, or a command-line merge tool like ``diff3``. The resolve
4297 command is used to manage the files involved in a merge, after
4302 command is used to manage the files involved in a merge, after
4298 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4303 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4299 working directory must have two parents). See :hg:`help
4304 working directory must have two parents). See :hg:`help
4300 merge-tools` for information on configuring merge tools.
4305 merge-tools` for information on configuring merge tools.
4301
4306
4302 The resolve command can be used in the following ways:
4307 The resolve command can be used in the following ways:
4303
4308
4304 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4309 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4305 files, discarding any previous merge attempts. Re-merging is not
4310 files, discarding any previous merge attempts. Re-merging is not
4306 performed for files already marked as resolved. Use ``--all/-a``
4311 performed for files already marked as resolved. Use ``--all/-a``
4307 to select all unresolved files. ``--tool`` can be used to specify
4312 to select all unresolved files. ``--tool`` can be used to specify
4308 the merge tool used for the given files. It overrides the HGMERGE
4313 the merge tool used for the given files. It overrides the HGMERGE
4309 environment variable and your configuration files. Previous file
4314 environment variable and your configuration files. Previous file
4310 contents are saved with a ``.orig`` suffix.
4315 contents are saved with a ``.orig`` suffix.
4311
4316
4312 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4317 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4313 (e.g. after having manually fixed-up the files). The default is
4318 (e.g. after having manually fixed-up the files). The default is
4314 to mark all unresolved files.
4319 to mark all unresolved files.
4315
4320
4316 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4321 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4317 default is to mark all resolved files.
4322 default is to mark all resolved files.
4318
4323
4319 - :hg:`resolve -l`: list files which had or still have conflicts.
4324 - :hg:`resolve -l`: list files which had or still have conflicts.
4320 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4325 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4321 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4326 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4322 the list. See :hg:`help filesets` for details.
4327 the list. See :hg:`help filesets` for details.
4323
4328
4324 .. note::
4329 .. note::
4325
4330
4326 Mercurial will not let you commit files with unresolved merge
4331 Mercurial will not let you commit files with unresolved merge
4327 conflicts. You must use :hg:`resolve -m ...` before you can
4332 conflicts. You must use :hg:`resolve -m ...` before you can
4328 commit after a conflicting merge.
4333 commit after a conflicting merge.
4329
4334
4330 Returns 0 on success, 1 if any files fail a resolve attempt.
4335 Returns 0 on success, 1 if any files fail a resolve attempt.
4331 """
4336 """
4332
4337
4333 opts = pycompat.byteskwargs(opts)
4338 opts = pycompat.byteskwargs(opts)
4334 flaglist = 'all mark unmark list no_status'.split()
4339 flaglist = 'all mark unmark list no_status'.split()
4335 all, mark, unmark, show, nostatus = \
4340 all, mark, unmark, show, nostatus = \
4336 [opts.get(o) for o in flaglist]
4341 [opts.get(o) for o in flaglist]
4337
4342
4338 if (show and (mark or unmark)) or (mark and unmark):
4343 if (show and (mark or unmark)) or (mark and unmark):
4339 raise error.Abort(_("too many options specified"))
4344 raise error.Abort(_("too many options specified"))
4340 if pats and all:
4345 if pats and all:
4341 raise error.Abort(_("can't specify --all and patterns"))
4346 raise error.Abort(_("can't specify --all and patterns"))
4342 if not (all or pats or show or mark or unmark):
4347 if not (all or pats or show or mark or unmark):
4343 raise error.Abort(_('no files or directories specified'),
4348 raise error.Abort(_('no files or directories specified'),
4344 hint=('use --all to re-merge all unresolved files'))
4349 hint=('use --all to re-merge all unresolved files'))
4345
4350
4346 if show:
4351 if show:
4347 ui.pager('resolve')
4352 ui.pager('resolve')
4348 fm = ui.formatter('resolve', opts)
4353 fm = ui.formatter('resolve', opts)
4349 ms = mergemod.mergestate.read(repo)
4354 ms = mergemod.mergestate.read(repo)
4350 m = scmutil.match(repo[None], pats, opts)
4355 m = scmutil.match(repo[None], pats, opts)
4351
4356
4352 # Labels and keys based on merge state. Unresolved path conflicts show
4357 # Labels and keys based on merge state. Unresolved path conflicts show
4353 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4358 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4354 # resolved conflicts.
4359 # resolved conflicts.
4355 mergestateinfo = {
4360 mergestateinfo = {
4356 'u': ('resolve.unresolved', 'U'),
4361 'u': ('resolve.unresolved', 'U'),
4357 'r': ('resolve.resolved', 'R'),
4362 'r': ('resolve.resolved', 'R'),
4358 'pu': ('resolve.unresolved', 'P'),
4363 'pu': ('resolve.unresolved', 'P'),
4359 'pr': ('resolve.resolved', 'R'),
4364 'pr': ('resolve.resolved', 'R'),
4360 'd': ('resolve.driverresolved', 'D'),
4365 'd': ('resolve.driverresolved', 'D'),
4361 }
4366 }
4362
4367
4363 for f in ms:
4368 for f in ms:
4364 if not m(f):
4369 if not m(f):
4365 continue
4370 continue
4366
4371
4367 label, key = mergestateinfo[ms[f]]
4372 label, key = mergestateinfo[ms[f]]
4368 fm.startitem()
4373 fm.startitem()
4369 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4374 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4370 fm.write('path', '%s\n', f, label=label)
4375 fm.write('path', '%s\n', f, label=label)
4371 fm.end()
4376 fm.end()
4372 return 0
4377 return 0
4373
4378
4374 with repo.wlock():
4379 with repo.wlock():
4375 ms = mergemod.mergestate.read(repo)
4380 ms = mergemod.mergestate.read(repo)
4376
4381
4377 if not (ms.active() or repo.dirstate.p2() != nullid):
4382 if not (ms.active() or repo.dirstate.p2() != nullid):
4378 raise error.Abort(
4383 raise error.Abort(
4379 _('resolve command not applicable when not merging'))
4384 _('resolve command not applicable when not merging'))
4380
4385
4381 wctx = repo[None]
4386 wctx = repo[None]
4382
4387
4383 if ms.mergedriver and ms.mdstate() == 'u':
4388 if ms.mergedriver and ms.mdstate() == 'u':
4384 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4389 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4385 ms.commit()
4390 ms.commit()
4386 # allow mark and unmark to go through
4391 # allow mark and unmark to go through
4387 if not mark and not unmark and not proceed:
4392 if not mark and not unmark and not proceed:
4388 return 1
4393 return 1
4389
4394
4390 m = scmutil.match(wctx, pats, opts)
4395 m = scmutil.match(wctx, pats, opts)
4391 ret = 0
4396 ret = 0
4392 didwork = False
4397 didwork = False
4393 runconclude = False
4398 runconclude = False
4394
4399
4395 tocomplete = []
4400 tocomplete = []
4396 for f in ms:
4401 for f in ms:
4397 if not m(f):
4402 if not m(f):
4398 continue
4403 continue
4399
4404
4400 didwork = True
4405 didwork = True
4401
4406
4402 # don't let driver-resolved files be marked, and run the conclude
4407 # don't let driver-resolved files be marked, and run the conclude
4403 # step if asked to resolve
4408 # step if asked to resolve
4404 if ms[f] == "d":
4409 if ms[f] == "d":
4405 exact = m.exact(f)
4410 exact = m.exact(f)
4406 if mark:
4411 if mark:
4407 if exact:
4412 if exact:
4408 ui.warn(_('not marking %s as it is driver-resolved\n')
4413 ui.warn(_('not marking %s as it is driver-resolved\n')
4409 % f)
4414 % f)
4410 elif unmark:
4415 elif unmark:
4411 if exact:
4416 if exact:
4412 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4417 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4413 % f)
4418 % f)
4414 else:
4419 else:
4415 runconclude = True
4420 runconclude = True
4416 continue
4421 continue
4417
4422
4418 # path conflicts must be resolved manually
4423 # path conflicts must be resolved manually
4419 if ms[f] in ("pu", "pr"):
4424 if ms[f] in ("pu", "pr"):
4420 if mark:
4425 if mark:
4421 ms.mark(f, "pr")
4426 ms.mark(f, "pr")
4422 elif unmark:
4427 elif unmark:
4423 ms.mark(f, "pu")
4428 ms.mark(f, "pu")
4424 elif ms[f] == "pu":
4429 elif ms[f] == "pu":
4425 ui.warn(_('%s: path conflict must be resolved manually\n')
4430 ui.warn(_('%s: path conflict must be resolved manually\n')
4426 % f)
4431 % f)
4427 continue
4432 continue
4428
4433
4429 if mark:
4434 if mark:
4430 ms.mark(f, "r")
4435 ms.mark(f, "r")
4431 elif unmark:
4436 elif unmark:
4432 ms.mark(f, "u")
4437 ms.mark(f, "u")
4433 else:
4438 else:
4434 # backup pre-resolve (merge uses .orig for its own purposes)
4439 # backup pre-resolve (merge uses .orig for its own purposes)
4435 a = repo.wjoin(f)
4440 a = repo.wjoin(f)
4436 try:
4441 try:
4437 util.copyfile(a, a + ".resolve")
4442 util.copyfile(a, a + ".resolve")
4438 except (IOError, OSError) as inst:
4443 except (IOError, OSError) as inst:
4439 if inst.errno != errno.ENOENT:
4444 if inst.errno != errno.ENOENT:
4440 raise
4445 raise
4441
4446
4442 try:
4447 try:
4443 # preresolve file
4448 # preresolve file
4444 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4449 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4445 'resolve')
4450 'resolve')
4446 complete, r = ms.preresolve(f, wctx)
4451 complete, r = ms.preresolve(f, wctx)
4447 if not complete:
4452 if not complete:
4448 tocomplete.append(f)
4453 tocomplete.append(f)
4449 elif r:
4454 elif r:
4450 ret = 1
4455 ret = 1
4451 finally:
4456 finally:
4452 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4457 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4453 ms.commit()
4458 ms.commit()
4454
4459
4455 # replace filemerge's .orig file with our resolve file, but only
4460 # replace filemerge's .orig file with our resolve file, but only
4456 # for merges that are complete
4461 # for merges that are complete
4457 if complete:
4462 if complete:
4458 try:
4463 try:
4459 util.rename(a + ".resolve",
4464 util.rename(a + ".resolve",
4460 scmutil.origpath(ui, repo, a))
4465 scmutil.origpath(ui, repo, a))
4461 except OSError as inst:
4466 except OSError as inst:
4462 if inst.errno != errno.ENOENT:
4467 if inst.errno != errno.ENOENT:
4463 raise
4468 raise
4464
4469
4465 for f in tocomplete:
4470 for f in tocomplete:
4466 try:
4471 try:
4467 # resolve file
4472 # resolve file
4468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4473 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4469 'resolve')
4474 'resolve')
4470 r = ms.resolve(f, wctx)
4475 r = ms.resolve(f, wctx)
4471 if r:
4476 if r:
4472 ret = 1
4477 ret = 1
4473 finally:
4478 finally:
4474 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4479 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4475 ms.commit()
4480 ms.commit()
4476
4481
4477 # replace filemerge's .orig file with our resolve file
4482 # replace filemerge's .orig file with our resolve file
4478 a = repo.wjoin(f)
4483 a = repo.wjoin(f)
4479 try:
4484 try:
4480 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4485 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4481 except OSError as inst:
4486 except OSError as inst:
4482 if inst.errno != errno.ENOENT:
4487 if inst.errno != errno.ENOENT:
4483 raise
4488 raise
4484
4489
4485 ms.commit()
4490 ms.commit()
4486 ms.recordactions()
4491 ms.recordactions()
4487
4492
4488 if not didwork and pats:
4493 if not didwork and pats:
4489 hint = None
4494 hint = None
4490 if not any([p for p in pats if p.find(':') >= 0]):
4495 if not any([p for p in pats if p.find(':') >= 0]):
4491 pats = ['path:%s' % p for p in pats]
4496 pats = ['path:%s' % p for p in pats]
4492 m = scmutil.match(wctx, pats, opts)
4497 m = scmutil.match(wctx, pats, opts)
4493 for f in ms:
4498 for f in ms:
4494 if not m(f):
4499 if not m(f):
4495 continue
4500 continue
4496 flags = ''.join(['-%s ' % o[0] for o in flaglist
4501 flags = ''.join(['-%s ' % o[0] for o in flaglist
4497 if opts.get(o)])
4502 if opts.get(o)])
4498 hint = _("(try: hg resolve %s%s)\n") % (
4503 hint = _("(try: hg resolve %s%s)\n") % (
4499 flags,
4504 flags,
4500 ' '.join(pats))
4505 ' '.join(pats))
4501 break
4506 break
4502 ui.warn(_("arguments do not match paths that need resolving\n"))
4507 ui.warn(_("arguments do not match paths that need resolving\n"))
4503 if hint:
4508 if hint:
4504 ui.warn(hint)
4509 ui.warn(hint)
4505 elif ms.mergedriver and ms.mdstate() != 's':
4510 elif ms.mergedriver and ms.mdstate() != 's':
4506 # run conclude step when either a driver-resolved file is requested
4511 # run conclude step when either a driver-resolved file is requested
4507 # or there are no driver-resolved files
4512 # or there are no driver-resolved files
4508 # we can't use 'ret' to determine whether any files are unresolved
4513 # we can't use 'ret' to determine whether any files are unresolved
4509 # because we might not have tried to resolve some
4514 # because we might not have tried to resolve some
4510 if ((runconclude or not list(ms.driverresolved()))
4515 if ((runconclude or not list(ms.driverresolved()))
4511 and not list(ms.unresolved())):
4516 and not list(ms.unresolved())):
4512 proceed = mergemod.driverconclude(repo, ms, wctx)
4517 proceed = mergemod.driverconclude(repo, ms, wctx)
4513 ms.commit()
4518 ms.commit()
4514 if not proceed:
4519 if not proceed:
4515 return 1
4520 return 1
4516
4521
4517 # Nudge users into finishing an unfinished operation
4522 # Nudge users into finishing an unfinished operation
4518 unresolvedf = list(ms.unresolved())
4523 unresolvedf = list(ms.unresolved())
4519 driverresolvedf = list(ms.driverresolved())
4524 driverresolvedf = list(ms.driverresolved())
4520 if not unresolvedf and not driverresolvedf:
4525 if not unresolvedf and not driverresolvedf:
4521 ui.status(_('(no more unresolved files)\n'))
4526 ui.status(_('(no more unresolved files)\n'))
4522 cmdutil.checkafterresolved(repo)
4527 cmdutil.checkafterresolved(repo)
4523 elif not unresolvedf:
4528 elif not unresolvedf:
4524 ui.status(_('(no more unresolved files -- '
4529 ui.status(_('(no more unresolved files -- '
4525 'run "hg resolve --all" to conclude)\n'))
4530 'run "hg resolve --all" to conclude)\n'))
4526
4531
4527 return ret
4532 return ret
4528
4533
4529 @command('revert',
4534 @command('revert',
4530 [('a', 'all', None, _('revert all changes when no arguments given')),
4535 [('a', 'all', None, _('revert all changes when no arguments given')),
4531 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4536 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4532 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4537 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4533 ('C', 'no-backup', None, _('do not save backup copies of files')),
4538 ('C', 'no-backup', None, _('do not save backup copies of files')),
4534 ('i', 'interactive', None, _('interactively select the changes')),
4539 ('i', 'interactive', None, _('interactively select the changes')),
4535 ] + walkopts + dryrunopts,
4540 ] + walkopts + dryrunopts,
4536 _('[OPTION]... [-r REV] [NAME]...'))
4541 _('[OPTION]... [-r REV] [NAME]...'))
4537 def revert(ui, repo, *pats, **opts):
4542 def revert(ui, repo, *pats, **opts):
4538 """restore files to their checkout state
4543 """restore files to their checkout state
4539
4544
4540 .. note::
4545 .. note::
4541
4546
4542 To check out earlier revisions, you should use :hg:`update REV`.
4547 To check out earlier revisions, you should use :hg:`update REV`.
4543 To cancel an uncommitted merge (and lose your changes),
4548 To cancel an uncommitted merge (and lose your changes),
4544 use :hg:`update --clean .`.
4549 use :hg:`update --clean .`.
4545
4550
4546 With no revision specified, revert the specified files or directories
4551 With no revision specified, revert the specified files or directories
4547 to the contents they had in the parent of the working directory.
4552 to the contents they had in the parent of the working directory.
4548 This restores the contents of files to an unmodified
4553 This restores the contents of files to an unmodified
4549 state and unschedules adds, removes, copies, and renames. If the
4554 state and unschedules adds, removes, copies, and renames. If the
4550 working directory has two parents, you must explicitly specify a
4555 working directory has two parents, you must explicitly specify a
4551 revision.
4556 revision.
4552
4557
4553 Using the -r/--rev or -d/--date options, revert the given files or
4558 Using the -r/--rev or -d/--date options, revert the given files or
4554 directories to their states as of a specific revision. Because
4559 directories to their states as of a specific revision. Because
4555 revert does not change the working directory parents, this will
4560 revert does not change the working directory parents, this will
4556 cause these files to appear modified. This can be helpful to "back
4561 cause these files to appear modified. This can be helpful to "back
4557 out" some or all of an earlier change. See :hg:`backout` for a
4562 out" some or all of an earlier change. See :hg:`backout` for a
4558 related method.
4563 related method.
4559
4564
4560 Modified files are saved with a .orig suffix before reverting.
4565 Modified files are saved with a .orig suffix before reverting.
4561 To disable these backups, use --no-backup. It is possible to store
4566 To disable these backups, use --no-backup. It is possible to store
4562 the backup files in a custom directory relative to the root of the
4567 the backup files in a custom directory relative to the root of the
4563 repository by setting the ``ui.origbackuppath`` configuration
4568 repository by setting the ``ui.origbackuppath`` configuration
4564 option.
4569 option.
4565
4570
4566 See :hg:`help dates` for a list of formats valid for -d/--date.
4571 See :hg:`help dates` for a list of formats valid for -d/--date.
4567
4572
4568 See :hg:`help backout` for a way to reverse the effect of an
4573 See :hg:`help backout` for a way to reverse the effect of an
4569 earlier changeset.
4574 earlier changeset.
4570
4575
4571 Returns 0 on success.
4576 Returns 0 on success.
4572 """
4577 """
4573
4578
4574 opts = pycompat.byteskwargs(opts)
4579 opts = pycompat.byteskwargs(opts)
4575 if opts.get("date"):
4580 if opts.get("date"):
4576 if opts.get("rev"):
4581 if opts.get("rev"):
4577 raise error.Abort(_("you can't specify a revision and a date"))
4582 raise error.Abort(_("you can't specify a revision and a date"))
4578 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4583 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4579
4584
4580 parent, p2 = repo.dirstate.parents()
4585 parent, p2 = repo.dirstate.parents()
4581 if not opts.get('rev') and p2 != nullid:
4586 if not opts.get('rev') and p2 != nullid:
4582 # revert after merge is a trap for new users (issue2915)
4587 # revert after merge is a trap for new users (issue2915)
4583 raise error.Abort(_('uncommitted merge with no revision specified'),
4588 raise error.Abort(_('uncommitted merge with no revision specified'),
4584 hint=_("use 'hg update' or see 'hg help revert'"))
4589 hint=_("use 'hg update' or see 'hg help revert'"))
4585
4590
4586 ctx = scmutil.revsingle(repo, opts.get('rev'))
4591 ctx = scmutil.revsingle(repo, opts.get('rev'))
4587
4592
4588 if (not (pats or opts.get('include') or opts.get('exclude') or
4593 if (not (pats or opts.get('include') or opts.get('exclude') or
4589 opts.get('all') or opts.get('interactive'))):
4594 opts.get('all') or opts.get('interactive'))):
4590 msg = _("no files or directories specified")
4595 msg = _("no files or directories specified")
4591 if p2 != nullid:
4596 if p2 != nullid:
4592 hint = _("uncommitted merge, use --all to discard all changes,"
4597 hint = _("uncommitted merge, use --all to discard all changes,"
4593 " or 'hg update -C .' to abort the merge")
4598 " or 'hg update -C .' to abort the merge")
4594 raise error.Abort(msg, hint=hint)
4599 raise error.Abort(msg, hint=hint)
4595 dirty = any(repo.status())
4600 dirty = any(repo.status())
4596 node = ctx.node()
4601 node = ctx.node()
4597 if node != parent:
4602 if node != parent:
4598 if dirty:
4603 if dirty:
4599 hint = _("uncommitted changes, use --all to discard all"
4604 hint = _("uncommitted changes, use --all to discard all"
4600 " changes, or 'hg update %s' to update") % ctx.rev()
4605 " changes, or 'hg update %s' to update") % ctx.rev()
4601 else:
4606 else:
4602 hint = _("use --all to revert all files,"
4607 hint = _("use --all to revert all files,"
4603 " or 'hg update %s' to update") % ctx.rev()
4608 " or 'hg update %s' to update") % ctx.rev()
4604 elif dirty:
4609 elif dirty:
4605 hint = _("uncommitted changes, use --all to discard all changes")
4610 hint = _("uncommitted changes, use --all to discard all changes")
4606 else:
4611 else:
4607 hint = _("use --all to revert all files")
4612 hint = _("use --all to revert all files")
4608 raise error.Abort(msg, hint=hint)
4613 raise error.Abort(msg, hint=hint)
4609
4614
4610 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4615 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4611 **pycompat.strkwargs(opts))
4616 **pycompat.strkwargs(opts))
4612
4617
4613 @command('rollback', dryrunopts +
4618 @command('rollback', dryrunopts +
4614 [('f', 'force', False, _('ignore safety measures'))])
4619 [('f', 'force', False, _('ignore safety measures'))])
4615 def rollback(ui, repo, **opts):
4620 def rollback(ui, repo, **opts):
4616 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4621 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4617
4622
4618 Please use :hg:`commit --amend` instead of rollback to correct
4623 Please use :hg:`commit --amend` instead of rollback to correct
4619 mistakes in the last commit.
4624 mistakes in the last commit.
4620
4625
4621 This command should be used with care. There is only one level of
4626 This command should be used with care. There is only one level of
4622 rollback, and there is no way to undo a rollback. It will also
4627 rollback, and there is no way to undo a rollback. It will also
4623 restore the dirstate at the time of the last transaction, losing
4628 restore the dirstate at the time of the last transaction, losing
4624 any dirstate changes since that time. This command does not alter
4629 any dirstate changes since that time. This command does not alter
4625 the working directory.
4630 the working directory.
4626
4631
4627 Transactions are used to encapsulate the effects of all commands
4632 Transactions are used to encapsulate the effects of all commands
4628 that create new changesets or propagate existing changesets into a
4633 that create new changesets or propagate existing changesets into a
4629 repository.
4634 repository.
4630
4635
4631 .. container:: verbose
4636 .. container:: verbose
4632
4637
4633 For example, the following commands are transactional, and their
4638 For example, the following commands are transactional, and their
4634 effects can be rolled back:
4639 effects can be rolled back:
4635
4640
4636 - commit
4641 - commit
4637 - import
4642 - import
4638 - pull
4643 - pull
4639 - push (with this repository as the destination)
4644 - push (with this repository as the destination)
4640 - unbundle
4645 - unbundle
4641
4646
4642 To avoid permanent data loss, rollback will refuse to rollback a
4647 To avoid permanent data loss, rollback will refuse to rollback a
4643 commit transaction if it isn't checked out. Use --force to
4648 commit transaction if it isn't checked out. Use --force to
4644 override this protection.
4649 override this protection.
4645
4650
4646 The rollback command can be entirely disabled by setting the
4651 The rollback command can be entirely disabled by setting the
4647 ``ui.rollback`` configuration setting to false. If you're here
4652 ``ui.rollback`` configuration setting to false. If you're here
4648 because you want to use rollback and it's disabled, you can
4653 because you want to use rollback and it's disabled, you can
4649 re-enable the command by setting ``ui.rollback`` to true.
4654 re-enable the command by setting ``ui.rollback`` to true.
4650
4655
4651 This command is not intended for use on public repositories. Once
4656 This command is not intended for use on public repositories. Once
4652 changes are visible for pull by other users, rolling a transaction
4657 changes are visible for pull by other users, rolling a transaction
4653 back locally is ineffective (someone else may already have pulled
4658 back locally is ineffective (someone else may already have pulled
4654 the changes). Furthermore, a race is possible with readers of the
4659 the changes). Furthermore, a race is possible with readers of the
4655 repository; for example an in-progress pull from the repository
4660 repository; for example an in-progress pull from the repository
4656 may fail if a rollback is performed.
4661 may fail if a rollback is performed.
4657
4662
4658 Returns 0 on success, 1 if no rollback data is available.
4663 Returns 0 on success, 1 if no rollback data is available.
4659 """
4664 """
4660 if not ui.configbool('ui', 'rollback'):
4665 if not ui.configbool('ui', 'rollback'):
4661 raise error.Abort(_('rollback is disabled because it is unsafe'),
4666 raise error.Abort(_('rollback is disabled because it is unsafe'),
4662 hint=('see `hg help -v rollback` for information'))
4667 hint=('see `hg help -v rollback` for information'))
4663 return repo.rollback(dryrun=opts.get(r'dry_run'),
4668 return repo.rollback(dryrun=opts.get(r'dry_run'),
4664 force=opts.get(r'force'))
4669 force=opts.get(r'force'))
4665
4670
4666 @command('root', [], cmdtype=readonly)
4671 @command('root', [], cmdtype=readonly)
4667 def root(ui, repo):
4672 def root(ui, repo):
4668 """print the root (top) of the current working directory
4673 """print the root (top) of the current working directory
4669
4674
4670 Print the root directory of the current repository.
4675 Print the root directory of the current repository.
4671
4676
4672 Returns 0 on success.
4677 Returns 0 on success.
4673 """
4678 """
4674 ui.write(repo.root + "\n")
4679 ui.write(repo.root + "\n")
4675
4680
4676 @command('^serve',
4681 @command('^serve',
4677 [('A', 'accesslog', '', _('name of access log file to write to'),
4682 [('A', 'accesslog', '', _('name of access log file to write to'),
4678 _('FILE')),
4683 _('FILE')),
4679 ('d', 'daemon', None, _('run server in background')),
4684 ('d', 'daemon', None, _('run server in background')),
4680 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4685 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4681 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4686 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4682 # use string type, then we can check if something was passed
4687 # use string type, then we can check if something was passed
4683 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4688 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4684 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4689 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4685 _('ADDR')),
4690 _('ADDR')),
4686 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4691 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4687 _('PREFIX')),
4692 _('PREFIX')),
4688 ('n', 'name', '',
4693 ('n', 'name', '',
4689 _('name to show in web pages (default: working directory)'), _('NAME')),
4694 _('name to show in web pages (default: working directory)'), _('NAME')),
4690 ('', 'web-conf', '',
4695 ('', 'web-conf', '',
4691 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4696 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4692 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4697 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4693 _('FILE')),
4698 _('FILE')),
4694 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4699 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4695 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4700 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4696 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4701 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4697 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4702 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4698 ('', 'style', '', _('template style to use'), _('STYLE')),
4703 ('', 'style', '', _('template style to use'), _('STYLE')),
4699 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4704 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4700 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4705 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4701 + subrepoopts,
4706 + subrepoopts,
4702 _('[OPTION]...'),
4707 _('[OPTION]...'),
4703 optionalrepo=True)
4708 optionalrepo=True)
4704 def serve(ui, repo, **opts):
4709 def serve(ui, repo, **opts):
4705 """start stand-alone webserver
4710 """start stand-alone webserver
4706
4711
4707 Start a local HTTP repository browser and pull server. You can use
4712 Start a local HTTP repository browser and pull server. You can use
4708 this for ad-hoc sharing and browsing of repositories. It is
4713 this for ad-hoc sharing and browsing of repositories. It is
4709 recommended to use a real web server to serve a repository for
4714 recommended to use a real web server to serve a repository for
4710 longer periods of time.
4715 longer periods of time.
4711
4716
4712 Please note that the server does not implement access control.
4717 Please note that the server does not implement access control.
4713 This means that, by default, anybody can read from the server and
4718 This means that, by default, anybody can read from the server and
4714 nobody can write to it by default. Set the ``web.allow-push``
4719 nobody can write to it by default. Set the ``web.allow-push``
4715 option to ``*`` to allow everybody to push to the server. You
4720 option to ``*`` to allow everybody to push to the server. You
4716 should use a real web server if you need to authenticate users.
4721 should use a real web server if you need to authenticate users.
4717
4722
4718 By default, the server logs accesses to stdout and errors to
4723 By default, the server logs accesses to stdout and errors to
4719 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4724 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4720 files.
4725 files.
4721
4726
4722 To have the server choose a free port number to listen on, specify
4727 To have the server choose a free port number to listen on, specify
4723 a port number of 0; in this case, the server will print the port
4728 a port number of 0; in this case, the server will print the port
4724 number it uses.
4729 number it uses.
4725
4730
4726 Returns 0 on success.
4731 Returns 0 on success.
4727 """
4732 """
4728
4733
4729 opts = pycompat.byteskwargs(opts)
4734 opts = pycompat.byteskwargs(opts)
4730 if opts["stdio"] and opts["cmdserver"]:
4735 if opts["stdio"] and opts["cmdserver"]:
4731 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4736 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4732
4737
4733 if opts["stdio"]:
4738 if opts["stdio"]:
4734 if repo is None:
4739 if repo is None:
4735 raise error.RepoError(_("there is no Mercurial repository here"
4740 raise error.RepoError(_("there is no Mercurial repository here"
4736 " (.hg not found)"))
4741 " (.hg not found)"))
4737 s = sshserver.sshserver(ui, repo)
4742 s = sshserver.sshserver(ui, repo)
4738 s.serve_forever()
4743 s.serve_forever()
4739
4744
4740 service = server.createservice(ui, repo, opts)
4745 service = server.createservice(ui, repo, opts)
4741 return server.runservice(opts, initfn=service.init, runfn=service.run)
4746 return server.runservice(opts, initfn=service.init, runfn=service.run)
4742
4747
4743 @command('^status|st',
4748 @command('^status|st',
4744 [('A', 'all', None, _('show status of all files')),
4749 [('A', 'all', None, _('show status of all files')),
4745 ('m', 'modified', None, _('show only modified files')),
4750 ('m', 'modified', None, _('show only modified files')),
4746 ('a', 'added', None, _('show only added files')),
4751 ('a', 'added', None, _('show only added files')),
4747 ('r', 'removed', None, _('show only removed files')),
4752 ('r', 'removed', None, _('show only removed files')),
4748 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4753 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4749 ('c', 'clean', None, _('show only files without changes')),
4754 ('c', 'clean', None, _('show only files without changes')),
4750 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4755 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4751 ('i', 'ignored', None, _('show only ignored files')),
4756 ('i', 'ignored', None, _('show only ignored files')),
4752 ('n', 'no-status', None, _('hide status prefix')),
4757 ('n', 'no-status', None, _('hide status prefix')),
4753 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4758 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4754 ('C', 'copies', None, _('show source of copied files')),
4759 ('C', 'copies', None, _('show source of copied files')),
4755 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4760 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4756 ('', 'rev', [], _('show difference from revision'), _('REV')),
4761 ('', 'rev', [], _('show difference from revision'), _('REV')),
4757 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4762 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4758 ] + walkopts + subrepoopts + formatteropts,
4763 ] + walkopts + subrepoopts + formatteropts,
4759 _('[OPTION]... [FILE]...'),
4764 _('[OPTION]... [FILE]...'),
4760 inferrepo=True, cmdtype=readonly)
4765 inferrepo=True, cmdtype=readonly)
4761 def status(ui, repo, *pats, **opts):
4766 def status(ui, repo, *pats, **opts):
4762 """show changed files in the working directory
4767 """show changed files in the working directory
4763
4768
4764 Show status of files in the repository. If names are given, only
4769 Show status of files in the repository. If names are given, only
4765 files that match are shown. Files that are clean or ignored or
4770 files that match are shown. Files that are clean or ignored or
4766 the source of a copy/move operation, are not listed unless
4771 the source of a copy/move operation, are not listed unless
4767 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4772 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4768 Unless options described with "show only ..." are given, the
4773 Unless options described with "show only ..." are given, the
4769 options -mardu are used.
4774 options -mardu are used.
4770
4775
4771 Option -q/--quiet hides untracked (unknown and ignored) files
4776 Option -q/--quiet hides untracked (unknown and ignored) files
4772 unless explicitly requested with -u/--unknown or -i/--ignored.
4777 unless explicitly requested with -u/--unknown or -i/--ignored.
4773
4778
4774 .. note::
4779 .. note::
4775
4780
4776 :hg:`status` may appear to disagree with diff if permissions have
4781 :hg:`status` may appear to disagree with diff if permissions have
4777 changed or a merge has occurred. The standard diff format does
4782 changed or a merge has occurred. The standard diff format does
4778 not report permission changes and diff only reports changes
4783 not report permission changes and diff only reports changes
4779 relative to one merge parent.
4784 relative to one merge parent.
4780
4785
4781 If one revision is given, it is used as the base revision.
4786 If one revision is given, it is used as the base revision.
4782 If two revisions are given, the differences between them are
4787 If two revisions are given, the differences between them are
4783 shown. The --change option can also be used as a shortcut to list
4788 shown. The --change option can also be used as a shortcut to list
4784 the changed files of a revision from its first parent.
4789 the changed files of a revision from its first parent.
4785
4790
4786 The codes used to show the status of files are::
4791 The codes used to show the status of files are::
4787
4792
4788 M = modified
4793 M = modified
4789 A = added
4794 A = added
4790 R = removed
4795 R = removed
4791 C = clean
4796 C = clean
4792 ! = missing (deleted by non-hg command, but still tracked)
4797 ! = missing (deleted by non-hg command, but still tracked)
4793 ? = not tracked
4798 ? = not tracked
4794 I = ignored
4799 I = ignored
4795 = origin of the previous file (with --copies)
4800 = origin of the previous file (with --copies)
4796
4801
4797 .. container:: verbose
4802 .. container:: verbose
4798
4803
4799 The -t/--terse option abbreviates the output by showing only the directory
4804 The -t/--terse option abbreviates the output by showing only the directory
4800 name if all the files in it share the same status. The option takes an
4805 name if all the files in it share the same status. The option takes an
4801 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4806 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4802 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4807 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4803 for 'ignored' and 'c' for clean.
4808 for 'ignored' and 'c' for clean.
4804
4809
4805 It abbreviates only those statuses which are passed. Note that clean and
4810 It abbreviates only those statuses which are passed. Note that clean and
4806 ignored files are not displayed with '--terse ic' unless the -c/--clean
4811 ignored files are not displayed with '--terse ic' unless the -c/--clean
4807 and -i/--ignored options are also used.
4812 and -i/--ignored options are also used.
4808
4813
4809 The -v/--verbose option shows information when the repository is in an
4814 The -v/--verbose option shows information when the repository is in an
4810 unfinished merge, shelve, rebase state etc. You can have this behavior
4815 unfinished merge, shelve, rebase state etc. You can have this behavior
4811 turned on by default by enabling the ``commands.status.verbose`` option.
4816 turned on by default by enabling the ``commands.status.verbose`` option.
4812
4817
4813 You can skip displaying some of these states by setting
4818 You can skip displaying some of these states by setting
4814 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4819 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4815 'histedit', 'merge', 'rebase', or 'unshelve'.
4820 'histedit', 'merge', 'rebase', or 'unshelve'.
4816
4821
4817 Examples:
4822 Examples:
4818
4823
4819 - show changes in the working directory relative to a
4824 - show changes in the working directory relative to a
4820 changeset::
4825 changeset::
4821
4826
4822 hg status --rev 9353
4827 hg status --rev 9353
4823
4828
4824 - show changes in the working directory relative to the
4829 - show changes in the working directory relative to the
4825 current directory (see :hg:`help patterns` for more information)::
4830 current directory (see :hg:`help patterns` for more information)::
4826
4831
4827 hg status re:
4832 hg status re:
4828
4833
4829 - show all changes including copies in an existing changeset::
4834 - show all changes including copies in an existing changeset::
4830
4835
4831 hg status --copies --change 9353
4836 hg status --copies --change 9353
4832
4837
4833 - get a NUL separated list of added files, suitable for xargs::
4838 - get a NUL separated list of added files, suitable for xargs::
4834
4839
4835 hg status -an0
4840 hg status -an0
4836
4841
4837 - show more information about the repository status, abbreviating
4842 - show more information about the repository status, abbreviating
4838 added, removed, modified, deleted, and untracked paths::
4843 added, removed, modified, deleted, and untracked paths::
4839
4844
4840 hg status -v -t mardu
4845 hg status -v -t mardu
4841
4846
4842 Returns 0 on success.
4847 Returns 0 on success.
4843
4848
4844 """
4849 """
4845
4850
4846 opts = pycompat.byteskwargs(opts)
4851 opts = pycompat.byteskwargs(opts)
4847 revs = opts.get('rev')
4852 revs = opts.get('rev')
4848 change = opts.get('change')
4853 change = opts.get('change')
4849 terse = opts.get('terse')
4854 terse = opts.get('terse')
4850
4855
4851 if revs and change:
4856 if revs and change:
4852 msg = _('cannot specify --rev and --change at the same time')
4857 msg = _('cannot specify --rev and --change at the same time')
4853 raise error.Abort(msg)
4858 raise error.Abort(msg)
4854 elif revs and terse:
4859 elif revs and terse:
4855 msg = _('cannot use --terse with --rev')
4860 msg = _('cannot use --terse with --rev')
4856 raise error.Abort(msg)
4861 raise error.Abort(msg)
4857 elif change:
4862 elif change:
4858 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4863 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4859 node2 = scmutil.revsingle(repo, change, None).node()
4864 node2 = scmutil.revsingle(repo, change, None).node()
4860 node1 = repo[node2].p1().node()
4865 node1 = repo[node2].p1().node()
4861 else:
4866 else:
4862 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4867 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4863 node1, node2 = scmutil.revpair(repo, revs)
4868 node1, node2 = scmutil.revpair(repo, revs)
4864
4869
4865 if pats or ui.configbool('commands', 'status.relative'):
4870 if pats or ui.configbool('commands', 'status.relative'):
4866 cwd = repo.getcwd()
4871 cwd = repo.getcwd()
4867 else:
4872 else:
4868 cwd = ''
4873 cwd = ''
4869
4874
4870 if opts.get('print0'):
4875 if opts.get('print0'):
4871 end = '\0'
4876 end = '\0'
4872 else:
4877 else:
4873 end = '\n'
4878 end = '\n'
4874 copy = {}
4879 copy = {}
4875 states = 'modified added removed deleted unknown ignored clean'.split()
4880 states = 'modified added removed deleted unknown ignored clean'.split()
4876 show = [k for k in states if opts.get(k)]
4881 show = [k for k in states if opts.get(k)]
4877 if opts.get('all'):
4882 if opts.get('all'):
4878 show += ui.quiet and (states[:4] + ['clean']) or states
4883 show += ui.quiet and (states[:4] + ['clean']) or states
4879
4884
4880 if not show:
4885 if not show:
4881 if ui.quiet:
4886 if ui.quiet:
4882 show = states[:4]
4887 show = states[:4]
4883 else:
4888 else:
4884 show = states[:5]
4889 show = states[:5]
4885
4890
4886 m = scmutil.match(repo[node2], pats, opts)
4891 m = scmutil.match(repo[node2], pats, opts)
4887 if terse:
4892 if terse:
4888 # we need to compute clean and unknown to terse
4893 # we need to compute clean and unknown to terse
4889 stat = repo.status(node1, node2, m,
4894 stat = repo.status(node1, node2, m,
4890 'ignored' in show or 'i' in terse,
4895 'ignored' in show or 'i' in terse,
4891 True, True, opts.get('subrepos'))
4896 True, True, opts.get('subrepos'))
4892
4897
4893 stat = cmdutil.tersedir(stat, terse)
4898 stat = cmdutil.tersedir(stat, terse)
4894 else:
4899 else:
4895 stat = repo.status(node1, node2, m,
4900 stat = repo.status(node1, node2, m,
4896 'ignored' in show, 'clean' in show,
4901 'ignored' in show, 'clean' in show,
4897 'unknown' in show, opts.get('subrepos'))
4902 'unknown' in show, opts.get('subrepos'))
4898
4903
4899 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4904 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4900
4905
4901 if (opts.get('all') or opts.get('copies')
4906 if (opts.get('all') or opts.get('copies')
4902 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4907 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4903 copy = copies.pathcopies(repo[node1], repo[node2], m)
4908 copy = copies.pathcopies(repo[node1], repo[node2], m)
4904
4909
4905 ui.pager('status')
4910 ui.pager('status')
4906 fm = ui.formatter('status', opts)
4911 fm = ui.formatter('status', opts)
4907 fmt = '%s' + end
4912 fmt = '%s' + end
4908 showchar = not opts.get('no_status')
4913 showchar = not opts.get('no_status')
4909
4914
4910 for state, char, files in changestates:
4915 for state, char, files in changestates:
4911 if state in show:
4916 if state in show:
4912 label = 'status.' + state
4917 label = 'status.' + state
4913 for f in files:
4918 for f in files:
4914 fm.startitem()
4919 fm.startitem()
4915 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4920 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4916 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4921 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4917 if f in copy:
4922 if f in copy:
4918 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4923 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4919 label='status.copied')
4924 label='status.copied')
4920
4925
4921 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4926 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4922 and not ui.plain()):
4927 and not ui.plain()):
4923 cmdutil.morestatus(repo, fm)
4928 cmdutil.morestatus(repo, fm)
4924 fm.end()
4929 fm.end()
4925
4930
4926 @command('^summary|sum',
4931 @command('^summary|sum',
4927 [('', 'remote', None, _('check for push and pull'))],
4932 [('', 'remote', None, _('check for push and pull'))],
4928 '[--remote]', cmdtype=readonly)
4933 '[--remote]', cmdtype=readonly)
4929 def summary(ui, repo, **opts):
4934 def summary(ui, repo, **opts):
4930 """summarize working directory state
4935 """summarize working directory state
4931
4936
4932 This generates a brief summary of the working directory state,
4937 This generates a brief summary of the working directory state,
4933 including parents, branch, commit status, phase and available updates.
4938 including parents, branch, commit status, phase and available updates.
4934
4939
4935 With the --remote option, this will check the default paths for
4940 With the --remote option, this will check the default paths for
4936 incoming and outgoing changes. This can be time-consuming.
4941 incoming and outgoing changes. This can be time-consuming.
4937
4942
4938 Returns 0 on success.
4943 Returns 0 on success.
4939 """
4944 """
4940
4945
4941 opts = pycompat.byteskwargs(opts)
4946 opts = pycompat.byteskwargs(opts)
4942 ui.pager('summary')
4947 ui.pager('summary')
4943 ctx = repo[None]
4948 ctx = repo[None]
4944 parents = ctx.parents()
4949 parents = ctx.parents()
4945 pnode = parents[0].node()
4950 pnode = parents[0].node()
4946 marks = []
4951 marks = []
4947
4952
4948 ms = None
4953 ms = None
4949 try:
4954 try:
4950 ms = mergemod.mergestate.read(repo)
4955 ms = mergemod.mergestate.read(repo)
4951 except error.UnsupportedMergeRecords as e:
4956 except error.UnsupportedMergeRecords as e:
4952 s = ' '.join(e.recordtypes)
4957 s = ' '.join(e.recordtypes)
4953 ui.warn(
4958 ui.warn(
4954 _('warning: merge state has unsupported record types: %s\n') % s)
4959 _('warning: merge state has unsupported record types: %s\n') % s)
4955 unresolved = []
4960 unresolved = []
4956 else:
4961 else:
4957 unresolved = list(ms.unresolved())
4962 unresolved = list(ms.unresolved())
4958
4963
4959 for p in parents:
4964 for p in parents:
4960 # label with log.changeset (instead of log.parent) since this
4965 # label with log.changeset (instead of log.parent) since this
4961 # shows a working directory parent *changeset*:
4966 # shows a working directory parent *changeset*:
4962 # i18n: column positioning for "hg summary"
4967 # i18n: column positioning for "hg summary"
4963 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4968 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4964 label=cmdutil._changesetlabels(p))
4969 label=cmdutil._changesetlabels(p))
4965 ui.write(' '.join(p.tags()), label='log.tag')
4970 ui.write(' '.join(p.tags()), label='log.tag')
4966 if p.bookmarks():
4971 if p.bookmarks():
4967 marks.extend(p.bookmarks())
4972 marks.extend(p.bookmarks())
4968 if p.rev() == -1:
4973 if p.rev() == -1:
4969 if not len(repo):
4974 if not len(repo):
4970 ui.write(_(' (empty repository)'))
4975 ui.write(_(' (empty repository)'))
4971 else:
4976 else:
4972 ui.write(_(' (no revision checked out)'))
4977 ui.write(_(' (no revision checked out)'))
4973 if p.obsolete():
4978 if p.obsolete():
4974 ui.write(_(' (obsolete)'))
4979 ui.write(_(' (obsolete)'))
4975 if p.isunstable():
4980 if p.isunstable():
4976 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4981 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4977 for instability in p.instabilities())
4982 for instability in p.instabilities())
4978 ui.write(' ('
4983 ui.write(' ('
4979 + ', '.join(instabilities)
4984 + ', '.join(instabilities)
4980 + ')')
4985 + ')')
4981 ui.write('\n')
4986 ui.write('\n')
4982 if p.description():
4987 if p.description():
4983 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4988 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4984 label='log.summary')
4989 label='log.summary')
4985
4990
4986 branch = ctx.branch()
4991 branch = ctx.branch()
4987 bheads = repo.branchheads(branch)
4992 bheads = repo.branchheads(branch)
4988 # i18n: column positioning for "hg summary"
4993 # i18n: column positioning for "hg summary"
4989 m = _('branch: %s\n') % branch
4994 m = _('branch: %s\n') % branch
4990 if branch != 'default':
4995 if branch != 'default':
4991 ui.write(m, label='log.branch')
4996 ui.write(m, label='log.branch')
4992 else:
4997 else:
4993 ui.status(m, label='log.branch')
4998 ui.status(m, label='log.branch')
4994
4999
4995 if marks:
5000 if marks:
4996 active = repo._activebookmark
5001 active = repo._activebookmark
4997 # i18n: column positioning for "hg summary"
5002 # i18n: column positioning for "hg summary"
4998 ui.write(_('bookmarks:'), label='log.bookmark')
5003 ui.write(_('bookmarks:'), label='log.bookmark')
4999 if active is not None:
5004 if active is not None:
5000 if active in marks:
5005 if active in marks:
5001 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5006 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5002 marks.remove(active)
5007 marks.remove(active)
5003 else:
5008 else:
5004 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5009 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5005 for m in marks:
5010 for m in marks:
5006 ui.write(' ' + m, label='log.bookmark')
5011 ui.write(' ' + m, label='log.bookmark')
5007 ui.write('\n', label='log.bookmark')
5012 ui.write('\n', label='log.bookmark')
5008
5013
5009 status = repo.status(unknown=True)
5014 status = repo.status(unknown=True)
5010
5015
5011 c = repo.dirstate.copies()
5016 c = repo.dirstate.copies()
5012 copied, renamed = [], []
5017 copied, renamed = [], []
5013 for d, s in c.iteritems():
5018 for d, s in c.iteritems():
5014 if s in status.removed:
5019 if s in status.removed:
5015 status.removed.remove(s)
5020 status.removed.remove(s)
5016 renamed.append(d)
5021 renamed.append(d)
5017 else:
5022 else:
5018 copied.append(d)
5023 copied.append(d)
5019 if d in status.added:
5024 if d in status.added:
5020 status.added.remove(d)
5025 status.added.remove(d)
5021
5026
5022 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5027 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5023
5028
5024 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5029 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5025 (ui.label(_('%d added'), 'status.added'), status.added),
5030 (ui.label(_('%d added'), 'status.added'), status.added),
5026 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5031 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5027 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5032 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5028 (ui.label(_('%d copied'), 'status.copied'), copied),
5033 (ui.label(_('%d copied'), 'status.copied'), copied),
5029 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5034 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5030 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5035 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5031 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5036 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5032 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5037 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5033 t = []
5038 t = []
5034 for l, s in labels:
5039 for l, s in labels:
5035 if s:
5040 if s:
5036 t.append(l % len(s))
5041 t.append(l % len(s))
5037
5042
5038 t = ', '.join(t)
5043 t = ', '.join(t)
5039 cleanworkdir = False
5044 cleanworkdir = False
5040
5045
5041 if repo.vfs.exists('graftstate'):
5046 if repo.vfs.exists('graftstate'):
5042 t += _(' (graft in progress)')
5047 t += _(' (graft in progress)')
5043 if repo.vfs.exists('updatestate'):
5048 if repo.vfs.exists('updatestate'):
5044 t += _(' (interrupted update)')
5049 t += _(' (interrupted update)')
5045 elif len(parents) > 1:
5050 elif len(parents) > 1:
5046 t += _(' (merge)')
5051 t += _(' (merge)')
5047 elif branch != parents[0].branch():
5052 elif branch != parents[0].branch():
5048 t += _(' (new branch)')
5053 t += _(' (new branch)')
5049 elif (parents[0].closesbranch() and
5054 elif (parents[0].closesbranch() and
5050 pnode in repo.branchheads(branch, closed=True)):
5055 pnode in repo.branchheads(branch, closed=True)):
5051 t += _(' (head closed)')
5056 t += _(' (head closed)')
5052 elif not (status.modified or status.added or status.removed or renamed or
5057 elif not (status.modified or status.added or status.removed or renamed or
5053 copied or subs):
5058 copied or subs):
5054 t += _(' (clean)')
5059 t += _(' (clean)')
5055 cleanworkdir = True
5060 cleanworkdir = True
5056 elif pnode not in bheads:
5061 elif pnode not in bheads:
5057 t += _(' (new branch head)')
5062 t += _(' (new branch head)')
5058
5063
5059 if parents:
5064 if parents:
5060 pendingphase = max(p.phase() for p in parents)
5065 pendingphase = max(p.phase() for p in parents)
5061 else:
5066 else:
5062 pendingphase = phases.public
5067 pendingphase = phases.public
5063
5068
5064 if pendingphase > phases.newcommitphase(ui):
5069 if pendingphase > phases.newcommitphase(ui):
5065 t += ' (%s)' % phases.phasenames[pendingphase]
5070 t += ' (%s)' % phases.phasenames[pendingphase]
5066
5071
5067 if cleanworkdir:
5072 if cleanworkdir:
5068 # i18n: column positioning for "hg summary"
5073 # i18n: column positioning for "hg summary"
5069 ui.status(_('commit: %s\n') % t.strip())
5074 ui.status(_('commit: %s\n') % t.strip())
5070 else:
5075 else:
5071 # i18n: column positioning for "hg summary"
5076 # i18n: column positioning for "hg summary"
5072 ui.write(_('commit: %s\n') % t.strip())
5077 ui.write(_('commit: %s\n') % t.strip())
5073
5078
5074 # all ancestors of branch heads - all ancestors of parent = new csets
5079 # all ancestors of branch heads - all ancestors of parent = new csets
5075 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5080 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5076 bheads))
5081 bheads))
5077
5082
5078 if new == 0:
5083 if new == 0:
5079 # i18n: column positioning for "hg summary"
5084 # i18n: column positioning for "hg summary"
5080 ui.status(_('update: (current)\n'))
5085 ui.status(_('update: (current)\n'))
5081 elif pnode not in bheads:
5086 elif pnode not in bheads:
5082 # i18n: column positioning for "hg summary"
5087 # i18n: column positioning for "hg summary"
5083 ui.write(_('update: %d new changesets (update)\n') % new)
5088 ui.write(_('update: %d new changesets (update)\n') % new)
5084 else:
5089 else:
5085 # i18n: column positioning for "hg summary"
5090 # i18n: column positioning for "hg summary"
5086 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5091 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5087 (new, len(bheads)))
5092 (new, len(bheads)))
5088
5093
5089 t = []
5094 t = []
5090 draft = len(repo.revs('draft()'))
5095 draft = len(repo.revs('draft()'))
5091 if draft:
5096 if draft:
5092 t.append(_('%d draft') % draft)
5097 t.append(_('%d draft') % draft)
5093 secret = len(repo.revs('secret()'))
5098 secret = len(repo.revs('secret()'))
5094 if secret:
5099 if secret:
5095 t.append(_('%d secret') % secret)
5100 t.append(_('%d secret') % secret)
5096
5101
5097 if draft or secret:
5102 if draft or secret:
5098 ui.status(_('phases: %s\n') % ', '.join(t))
5103 ui.status(_('phases: %s\n') % ', '.join(t))
5099
5104
5100 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5105 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5101 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5106 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5102 numtrouble = len(repo.revs(trouble + "()"))
5107 numtrouble = len(repo.revs(trouble + "()"))
5103 # We write all the possibilities to ease translation
5108 # We write all the possibilities to ease translation
5104 troublemsg = {
5109 troublemsg = {
5105 "orphan": _("orphan: %d changesets"),
5110 "orphan": _("orphan: %d changesets"),
5106 "contentdivergent": _("content-divergent: %d changesets"),
5111 "contentdivergent": _("content-divergent: %d changesets"),
5107 "phasedivergent": _("phase-divergent: %d changesets"),
5112 "phasedivergent": _("phase-divergent: %d changesets"),
5108 }
5113 }
5109 if numtrouble > 0:
5114 if numtrouble > 0:
5110 ui.status(troublemsg[trouble] % numtrouble + "\n")
5115 ui.status(troublemsg[trouble] % numtrouble + "\n")
5111
5116
5112 cmdutil.summaryhooks(ui, repo)
5117 cmdutil.summaryhooks(ui, repo)
5113
5118
5114 if opts.get('remote'):
5119 if opts.get('remote'):
5115 needsincoming, needsoutgoing = True, True
5120 needsincoming, needsoutgoing = True, True
5116 else:
5121 else:
5117 needsincoming, needsoutgoing = False, False
5122 needsincoming, needsoutgoing = False, False
5118 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5123 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5119 if i:
5124 if i:
5120 needsincoming = True
5125 needsincoming = True
5121 if o:
5126 if o:
5122 needsoutgoing = True
5127 needsoutgoing = True
5123 if not needsincoming and not needsoutgoing:
5128 if not needsincoming and not needsoutgoing:
5124 return
5129 return
5125
5130
5126 def getincoming():
5131 def getincoming():
5127 source, branches = hg.parseurl(ui.expandpath('default'))
5132 source, branches = hg.parseurl(ui.expandpath('default'))
5128 sbranch = branches[0]
5133 sbranch = branches[0]
5129 try:
5134 try:
5130 other = hg.peer(repo, {}, source)
5135 other = hg.peer(repo, {}, source)
5131 except error.RepoError:
5136 except error.RepoError:
5132 if opts.get('remote'):
5137 if opts.get('remote'):
5133 raise
5138 raise
5134 return source, sbranch, None, None, None
5139 return source, sbranch, None, None, None
5135 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5140 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5136 if revs:
5141 if revs:
5137 revs = [other.lookup(rev) for rev in revs]
5142 revs = [other.lookup(rev) for rev in revs]
5138 ui.debug('comparing with %s\n' % util.hidepassword(source))
5143 ui.debug('comparing with %s\n' % util.hidepassword(source))
5139 repo.ui.pushbuffer()
5144 repo.ui.pushbuffer()
5140 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5145 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5141 repo.ui.popbuffer()
5146 repo.ui.popbuffer()
5142 return source, sbranch, other, commoninc, commoninc[1]
5147 return source, sbranch, other, commoninc, commoninc[1]
5143
5148
5144 if needsincoming:
5149 if needsincoming:
5145 source, sbranch, sother, commoninc, incoming = getincoming()
5150 source, sbranch, sother, commoninc, incoming = getincoming()
5146 else:
5151 else:
5147 source = sbranch = sother = commoninc = incoming = None
5152 source = sbranch = sother = commoninc = incoming = None
5148
5153
5149 def getoutgoing():
5154 def getoutgoing():
5150 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5155 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5151 dbranch = branches[0]
5156 dbranch = branches[0]
5152 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5157 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5153 if source != dest:
5158 if source != dest:
5154 try:
5159 try:
5155 dother = hg.peer(repo, {}, dest)
5160 dother = hg.peer(repo, {}, dest)
5156 except error.RepoError:
5161 except error.RepoError:
5157 if opts.get('remote'):
5162 if opts.get('remote'):
5158 raise
5163 raise
5159 return dest, dbranch, None, None
5164 return dest, dbranch, None, None
5160 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5165 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5161 elif sother is None:
5166 elif sother is None:
5162 # there is no explicit destination peer, but source one is invalid
5167 # there is no explicit destination peer, but source one is invalid
5163 return dest, dbranch, None, None
5168 return dest, dbranch, None, None
5164 else:
5169 else:
5165 dother = sother
5170 dother = sother
5166 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5171 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5167 common = None
5172 common = None
5168 else:
5173 else:
5169 common = commoninc
5174 common = commoninc
5170 if revs:
5175 if revs:
5171 revs = [repo.lookup(rev) for rev in revs]
5176 revs = [repo.lookup(rev) for rev in revs]
5172 repo.ui.pushbuffer()
5177 repo.ui.pushbuffer()
5173 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5178 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5174 commoninc=common)
5179 commoninc=common)
5175 repo.ui.popbuffer()
5180 repo.ui.popbuffer()
5176 return dest, dbranch, dother, outgoing
5181 return dest, dbranch, dother, outgoing
5177
5182
5178 if needsoutgoing:
5183 if needsoutgoing:
5179 dest, dbranch, dother, outgoing = getoutgoing()
5184 dest, dbranch, dother, outgoing = getoutgoing()
5180 else:
5185 else:
5181 dest = dbranch = dother = outgoing = None
5186 dest = dbranch = dother = outgoing = None
5182
5187
5183 if opts.get('remote'):
5188 if opts.get('remote'):
5184 t = []
5189 t = []
5185 if incoming:
5190 if incoming:
5186 t.append(_('1 or more incoming'))
5191 t.append(_('1 or more incoming'))
5187 o = outgoing.missing
5192 o = outgoing.missing
5188 if o:
5193 if o:
5189 t.append(_('%d outgoing') % len(o))
5194 t.append(_('%d outgoing') % len(o))
5190 other = dother or sother
5195 other = dother or sother
5191 if 'bookmarks' in other.listkeys('namespaces'):
5196 if 'bookmarks' in other.listkeys('namespaces'):
5192 counts = bookmarks.summary(repo, other)
5197 counts = bookmarks.summary(repo, other)
5193 if counts[0] > 0:
5198 if counts[0] > 0:
5194 t.append(_('%d incoming bookmarks') % counts[0])
5199 t.append(_('%d incoming bookmarks') % counts[0])
5195 if counts[1] > 0:
5200 if counts[1] > 0:
5196 t.append(_('%d outgoing bookmarks') % counts[1])
5201 t.append(_('%d outgoing bookmarks') % counts[1])
5197
5202
5198 if t:
5203 if t:
5199 # i18n: column positioning for "hg summary"
5204 # i18n: column positioning for "hg summary"
5200 ui.write(_('remote: %s\n') % (', '.join(t)))
5205 ui.write(_('remote: %s\n') % (', '.join(t)))
5201 else:
5206 else:
5202 # i18n: column positioning for "hg summary"
5207 # i18n: column positioning for "hg summary"
5203 ui.status(_('remote: (synced)\n'))
5208 ui.status(_('remote: (synced)\n'))
5204
5209
5205 cmdutil.summaryremotehooks(ui, repo, opts,
5210 cmdutil.summaryremotehooks(ui, repo, opts,
5206 ((source, sbranch, sother, commoninc),
5211 ((source, sbranch, sother, commoninc),
5207 (dest, dbranch, dother, outgoing)))
5212 (dest, dbranch, dother, outgoing)))
5208
5213
5209 @command('tag',
5214 @command('tag',
5210 [('f', 'force', None, _('force tag')),
5215 [('f', 'force', None, _('force tag')),
5211 ('l', 'local', None, _('make the tag local')),
5216 ('l', 'local', None, _('make the tag local')),
5212 ('r', 'rev', '', _('revision to tag'), _('REV')),
5217 ('r', 'rev', '', _('revision to tag'), _('REV')),
5213 ('', 'remove', None, _('remove a tag')),
5218 ('', 'remove', None, _('remove a tag')),
5214 # -l/--local is already there, commitopts cannot be used
5219 # -l/--local is already there, commitopts cannot be used
5215 ('e', 'edit', None, _('invoke editor on commit messages')),
5220 ('e', 'edit', None, _('invoke editor on commit messages')),
5216 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5221 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5217 ] + commitopts2,
5222 ] + commitopts2,
5218 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5223 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5219 def tag(ui, repo, name1, *names, **opts):
5224 def tag(ui, repo, name1, *names, **opts):
5220 """add one or more tags for the current or given revision
5225 """add one or more tags for the current or given revision
5221
5226
5222 Name a particular revision using <name>.
5227 Name a particular revision using <name>.
5223
5228
5224 Tags are used to name particular revisions of the repository and are
5229 Tags are used to name particular revisions of the repository and are
5225 very useful to compare different revisions, to go back to significant
5230 very useful to compare different revisions, to go back to significant
5226 earlier versions or to mark branch points as releases, etc. Changing
5231 earlier versions or to mark branch points as releases, etc. Changing
5227 an existing tag is normally disallowed; use -f/--force to override.
5232 an existing tag is normally disallowed; use -f/--force to override.
5228
5233
5229 If no revision is given, the parent of the working directory is
5234 If no revision is given, the parent of the working directory is
5230 used.
5235 used.
5231
5236
5232 To facilitate version control, distribution, and merging of tags,
5237 To facilitate version control, distribution, and merging of tags,
5233 they are stored as a file named ".hgtags" which is managed similarly
5238 they are stored as a file named ".hgtags" which is managed similarly
5234 to other project files and can be hand-edited if necessary. This
5239 to other project files and can be hand-edited if necessary. This
5235 also means that tagging creates a new commit. The file
5240 also means that tagging creates a new commit. The file
5236 ".hg/localtags" is used for local tags (not shared among
5241 ".hg/localtags" is used for local tags (not shared among
5237 repositories).
5242 repositories).
5238
5243
5239 Tag commits are usually made at the head of a branch. If the parent
5244 Tag commits are usually made at the head of a branch. If the parent
5240 of the working directory is not a branch head, :hg:`tag` aborts; use
5245 of the working directory is not a branch head, :hg:`tag` aborts; use
5241 -f/--force to force the tag commit to be based on a non-head
5246 -f/--force to force the tag commit to be based on a non-head
5242 changeset.
5247 changeset.
5243
5248
5244 See :hg:`help dates` for a list of formats valid for -d/--date.
5249 See :hg:`help dates` for a list of formats valid for -d/--date.
5245
5250
5246 Since tag names have priority over branch names during revision
5251 Since tag names have priority over branch names during revision
5247 lookup, using an existing branch name as a tag name is discouraged.
5252 lookup, using an existing branch name as a tag name is discouraged.
5248
5253
5249 Returns 0 on success.
5254 Returns 0 on success.
5250 """
5255 """
5251 opts = pycompat.byteskwargs(opts)
5256 opts = pycompat.byteskwargs(opts)
5252 wlock = lock = None
5257 wlock = lock = None
5253 try:
5258 try:
5254 wlock = repo.wlock()
5259 wlock = repo.wlock()
5255 lock = repo.lock()
5260 lock = repo.lock()
5256 rev_ = "."
5261 rev_ = "."
5257 names = [t.strip() for t in (name1,) + names]
5262 names = [t.strip() for t in (name1,) + names]
5258 if len(names) != len(set(names)):
5263 if len(names) != len(set(names)):
5259 raise error.Abort(_('tag names must be unique'))
5264 raise error.Abort(_('tag names must be unique'))
5260 for n in names:
5265 for n in names:
5261 scmutil.checknewlabel(repo, n, 'tag')
5266 scmutil.checknewlabel(repo, n, 'tag')
5262 if not n:
5267 if not n:
5263 raise error.Abort(_('tag names cannot consist entirely of '
5268 raise error.Abort(_('tag names cannot consist entirely of '
5264 'whitespace'))
5269 'whitespace'))
5265 if opts.get('rev') and opts.get('remove'):
5270 if opts.get('rev') and opts.get('remove'):
5266 raise error.Abort(_("--rev and --remove are incompatible"))
5271 raise error.Abort(_("--rev and --remove are incompatible"))
5267 if opts.get('rev'):
5272 if opts.get('rev'):
5268 rev_ = opts['rev']
5273 rev_ = opts['rev']
5269 message = opts.get('message')
5274 message = opts.get('message')
5270 if opts.get('remove'):
5275 if opts.get('remove'):
5271 if opts.get('local'):
5276 if opts.get('local'):
5272 expectedtype = 'local'
5277 expectedtype = 'local'
5273 else:
5278 else:
5274 expectedtype = 'global'
5279 expectedtype = 'global'
5275
5280
5276 for n in names:
5281 for n in names:
5277 if not repo.tagtype(n):
5282 if not repo.tagtype(n):
5278 raise error.Abort(_("tag '%s' does not exist") % n)
5283 raise error.Abort(_("tag '%s' does not exist") % n)
5279 if repo.tagtype(n) != expectedtype:
5284 if repo.tagtype(n) != expectedtype:
5280 if expectedtype == 'global':
5285 if expectedtype == 'global':
5281 raise error.Abort(_("tag '%s' is not a global tag") % n)
5286 raise error.Abort(_("tag '%s' is not a global tag") % n)
5282 else:
5287 else:
5283 raise error.Abort(_("tag '%s' is not a local tag") % n)
5288 raise error.Abort(_("tag '%s' is not a local tag") % n)
5284 rev_ = 'null'
5289 rev_ = 'null'
5285 if not message:
5290 if not message:
5286 # we don't translate commit messages
5291 # we don't translate commit messages
5287 message = 'Removed tag %s' % ', '.join(names)
5292 message = 'Removed tag %s' % ', '.join(names)
5288 elif not opts.get('force'):
5293 elif not opts.get('force'):
5289 for n in names:
5294 for n in names:
5290 if n in repo.tags():
5295 if n in repo.tags():
5291 raise error.Abort(_("tag '%s' already exists "
5296 raise error.Abort(_("tag '%s' already exists "
5292 "(use -f to force)") % n)
5297 "(use -f to force)") % n)
5293 if not opts.get('local'):
5298 if not opts.get('local'):
5294 p1, p2 = repo.dirstate.parents()
5299 p1, p2 = repo.dirstate.parents()
5295 if p2 != nullid:
5300 if p2 != nullid:
5296 raise error.Abort(_('uncommitted merge'))
5301 raise error.Abort(_('uncommitted merge'))
5297 bheads = repo.branchheads()
5302 bheads = repo.branchheads()
5298 if not opts.get('force') and bheads and p1 not in bheads:
5303 if not opts.get('force') and bheads and p1 not in bheads:
5299 raise error.Abort(_('working directory is not at a branch head '
5304 raise error.Abort(_('working directory is not at a branch head '
5300 '(use -f to force)'))
5305 '(use -f to force)'))
5301 r = scmutil.revsingle(repo, rev_).node()
5306 r = scmutil.revsingle(repo, rev_).node()
5302
5307
5303 if not message:
5308 if not message:
5304 # we don't translate commit messages
5309 # we don't translate commit messages
5305 message = ('Added tag %s for changeset %s' %
5310 message = ('Added tag %s for changeset %s' %
5306 (', '.join(names), short(r)))
5311 (', '.join(names), short(r)))
5307
5312
5308 date = opts.get('date')
5313 date = opts.get('date')
5309 if date:
5314 if date:
5310 date = util.parsedate(date)
5315 date = util.parsedate(date)
5311
5316
5312 if opts.get('remove'):
5317 if opts.get('remove'):
5313 editform = 'tag.remove'
5318 editform = 'tag.remove'
5314 else:
5319 else:
5315 editform = 'tag.add'
5320 editform = 'tag.add'
5316 editor = cmdutil.getcommiteditor(editform=editform,
5321 editor = cmdutil.getcommiteditor(editform=editform,
5317 **pycompat.strkwargs(opts))
5322 **pycompat.strkwargs(opts))
5318
5323
5319 # don't allow tagging the null rev
5324 # don't allow tagging the null rev
5320 if (not opts.get('remove') and
5325 if (not opts.get('remove') and
5321 scmutil.revsingle(repo, rev_).rev() == nullrev):
5326 scmutil.revsingle(repo, rev_).rev() == nullrev):
5322 raise error.Abort(_("cannot tag null revision"))
5327 raise error.Abort(_("cannot tag null revision"))
5323
5328
5324 tagsmod.tag(repo, names, r, message, opts.get('local'),
5329 tagsmod.tag(repo, names, r, message, opts.get('local'),
5325 opts.get('user'), date, editor=editor)
5330 opts.get('user'), date, editor=editor)
5326 finally:
5331 finally:
5327 release(lock, wlock)
5332 release(lock, wlock)
5328
5333
5329 @command('tags', formatteropts, '', cmdtype=readonly)
5334 @command('tags', formatteropts, '', cmdtype=readonly)
5330 def tags(ui, repo, **opts):
5335 def tags(ui, repo, **opts):
5331 """list repository tags
5336 """list repository tags
5332
5337
5333 This lists both regular and local tags. When the -v/--verbose
5338 This lists both regular and local tags. When the -v/--verbose
5334 switch is used, a third column "local" is printed for local tags.
5339 switch is used, a third column "local" is printed for local tags.
5335 When the -q/--quiet switch is used, only the tag name is printed.
5340 When the -q/--quiet switch is used, only the tag name is printed.
5336
5341
5337 Returns 0 on success.
5342 Returns 0 on success.
5338 """
5343 """
5339
5344
5340 opts = pycompat.byteskwargs(opts)
5345 opts = pycompat.byteskwargs(opts)
5341 ui.pager('tags')
5346 ui.pager('tags')
5342 fm = ui.formatter('tags', opts)
5347 fm = ui.formatter('tags', opts)
5343 hexfunc = fm.hexfunc
5348 hexfunc = fm.hexfunc
5344 tagtype = ""
5349 tagtype = ""
5345
5350
5346 for t, n in reversed(repo.tagslist()):
5351 for t, n in reversed(repo.tagslist()):
5347 hn = hexfunc(n)
5352 hn = hexfunc(n)
5348 label = 'tags.normal'
5353 label = 'tags.normal'
5349 tagtype = ''
5354 tagtype = ''
5350 if repo.tagtype(t) == 'local':
5355 if repo.tagtype(t) == 'local':
5351 label = 'tags.local'
5356 label = 'tags.local'
5352 tagtype = 'local'
5357 tagtype = 'local'
5353
5358
5354 fm.startitem()
5359 fm.startitem()
5355 fm.write('tag', '%s', t, label=label)
5360 fm.write('tag', '%s', t, label=label)
5356 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5361 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5357 fm.condwrite(not ui.quiet, 'rev node', fmt,
5362 fm.condwrite(not ui.quiet, 'rev node', fmt,
5358 repo.changelog.rev(n), hn, label=label)
5363 repo.changelog.rev(n), hn, label=label)
5359 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5364 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5360 tagtype, label=label)
5365 tagtype, label=label)
5361 fm.plain('\n')
5366 fm.plain('\n')
5362 fm.end()
5367 fm.end()
5363
5368
5364 @command('tip',
5369 @command('tip',
5365 [('p', 'patch', None, _('show patch')),
5370 [('p', 'patch', None, _('show patch')),
5366 ('g', 'git', None, _('use git extended diff format')),
5371 ('g', 'git', None, _('use git extended diff format')),
5367 ] + templateopts,
5372 ] + templateopts,
5368 _('[-p] [-g]'))
5373 _('[-p] [-g]'))
5369 def tip(ui, repo, **opts):
5374 def tip(ui, repo, **opts):
5370 """show the tip revision (DEPRECATED)
5375 """show the tip revision (DEPRECATED)
5371
5376
5372 The tip revision (usually just called the tip) is the changeset
5377 The tip revision (usually just called the tip) is the changeset
5373 most recently added to the repository (and therefore the most
5378 most recently added to the repository (and therefore the most
5374 recently changed head).
5379 recently changed head).
5375
5380
5376 If you have just made a commit, that commit will be the tip. If
5381 If you have just made a commit, that commit will be the tip. If
5377 you have just pulled changes from another repository, the tip of
5382 you have just pulled changes from another repository, the tip of
5378 that repository becomes the current tip. The "tip" tag is special
5383 that repository becomes the current tip. The "tip" tag is special
5379 and cannot be renamed or assigned to a different changeset.
5384 and cannot be renamed or assigned to a different changeset.
5380
5385
5381 This command is deprecated, please use :hg:`heads` instead.
5386 This command is deprecated, please use :hg:`heads` instead.
5382
5387
5383 Returns 0 on success.
5388 Returns 0 on success.
5384 """
5389 """
5385 opts = pycompat.byteskwargs(opts)
5390 opts = pycompat.byteskwargs(opts)
5386 displayer = cmdutil.show_changeset(ui, repo, opts)
5391 displayer = cmdutil.show_changeset(ui, repo, opts)
5387 displayer.show(repo['tip'])
5392 displayer.show(repo['tip'])
5388 displayer.close()
5393 displayer.close()
5389
5394
5390 @command('unbundle',
5395 @command('unbundle',
5391 [('u', 'update', None,
5396 [('u', 'update', None,
5392 _('update to new branch head if changesets were unbundled'))],
5397 _('update to new branch head if changesets were unbundled'))],
5393 _('[-u] FILE...'))
5398 _('[-u] FILE...'))
5394 def unbundle(ui, repo, fname1, *fnames, **opts):
5399 def unbundle(ui, repo, fname1, *fnames, **opts):
5395 """apply one or more bundle files
5400 """apply one or more bundle files
5396
5401
5397 Apply one or more bundle files generated by :hg:`bundle`.
5402 Apply one or more bundle files generated by :hg:`bundle`.
5398
5403
5399 Returns 0 on success, 1 if an update has unresolved files.
5404 Returns 0 on success, 1 if an update has unresolved files.
5400 """
5405 """
5401 fnames = (fname1,) + fnames
5406 fnames = (fname1,) + fnames
5402
5407
5403 with repo.lock():
5408 with repo.lock():
5404 for fname in fnames:
5409 for fname in fnames:
5405 f = hg.openpath(ui, fname)
5410 f = hg.openpath(ui, fname)
5406 gen = exchange.readbundle(ui, f, fname)
5411 gen = exchange.readbundle(ui, f, fname)
5407 if isinstance(gen, streamclone.streamcloneapplier):
5412 if isinstance(gen, streamclone.streamcloneapplier):
5408 raise error.Abort(
5413 raise error.Abort(
5409 _('packed bundles cannot be applied with '
5414 _('packed bundles cannot be applied with '
5410 '"hg unbundle"'),
5415 '"hg unbundle"'),
5411 hint=_('use "hg debugapplystreamclonebundle"'))
5416 hint=_('use "hg debugapplystreamclonebundle"'))
5412 url = 'bundle:' + fname
5417 url = 'bundle:' + fname
5413 try:
5418 try:
5414 txnname = 'unbundle'
5419 txnname = 'unbundle'
5415 if not isinstance(gen, bundle2.unbundle20):
5420 if not isinstance(gen, bundle2.unbundle20):
5416 txnname = 'unbundle\n%s' % util.hidepassword(url)
5421 txnname = 'unbundle\n%s' % util.hidepassword(url)
5417 with repo.transaction(txnname) as tr:
5422 with repo.transaction(txnname) as tr:
5418 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5423 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5419 url=url)
5424 url=url)
5420 except error.BundleUnknownFeatureError as exc:
5425 except error.BundleUnknownFeatureError as exc:
5421 raise error.Abort(
5426 raise error.Abort(
5422 _('%s: unknown bundle feature, %s') % (fname, exc),
5427 _('%s: unknown bundle feature, %s') % (fname, exc),
5423 hint=_("see https://mercurial-scm.org/"
5428 hint=_("see https://mercurial-scm.org/"
5424 "wiki/BundleFeature for more "
5429 "wiki/BundleFeature for more "
5425 "information"))
5430 "information"))
5426 modheads = bundle2.combinechangegroupresults(op)
5431 modheads = bundle2.combinechangegroupresults(op)
5427
5432
5428 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5433 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5429
5434
5430 @command('^update|up|checkout|co',
5435 @command('^update|up|checkout|co',
5431 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5436 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5432 ('c', 'check', None, _('require clean working directory')),
5437 ('c', 'check', None, _('require clean working directory')),
5433 ('m', 'merge', None, _('merge uncommitted changes')),
5438 ('m', 'merge', None, _('merge uncommitted changes')),
5434 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5439 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5435 ('r', 'rev', '', _('revision'), _('REV'))
5440 ('r', 'rev', '', _('revision'), _('REV'))
5436 ] + mergetoolopts,
5441 ] + mergetoolopts,
5437 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5442 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5438 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5443 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5439 merge=None, tool=None):
5444 merge=None, tool=None):
5440 """update working directory (or switch revisions)
5445 """update working directory (or switch revisions)
5441
5446
5442 Update the repository's working directory to the specified
5447 Update the repository's working directory to the specified
5443 changeset. If no changeset is specified, update to the tip of the
5448 changeset. If no changeset is specified, update to the tip of the
5444 current named branch and move the active bookmark (see :hg:`help
5449 current named branch and move the active bookmark (see :hg:`help
5445 bookmarks`).
5450 bookmarks`).
5446
5451
5447 Update sets the working directory's parent revision to the specified
5452 Update sets the working directory's parent revision to the specified
5448 changeset (see :hg:`help parents`).
5453 changeset (see :hg:`help parents`).
5449
5454
5450 If the changeset is not a descendant or ancestor of the working
5455 If the changeset is not a descendant or ancestor of the working
5451 directory's parent and there are uncommitted changes, the update is
5456 directory's parent and there are uncommitted changes, the update is
5452 aborted. With the -c/--check option, the working directory is checked
5457 aborted. With the -c/--check option, the working directory is checked
5453 for uncommitted changes; if none are found, the working directory is
5458 for uncommitted changes; if none are found, the working directory is
5454 updated to the specified changeset.
5459 updated to the specified changeset.
5455
5460
5456 .. container:: verbose
5461 .. container:: verbose
5457
5462
5458 The -C/--clean, -c/--check, and -m/--merge options control what
5463 The -C/--clean, -c/--check, and -m/--merge options control what
5459 happens if the working directory contains uncommitted changes.
5464 happens if the working directory contains uncommitted changes.
5460 At most of one of them can be specified.
5465 At most of one of them can be specified.
5461
5466
5462 1. If no option is specified, and if
5467 1. If no option is specified, and if
5463 the requested changeset is an ancestor or descendant of
5468 the requested changeset is an ancestor or descendant of
5464 the working directory's parent, the uncommitted changes
5469 the working directory's parent, the uncommitted changes
5465 are merged into the requested changeset and the merged
5470 are merged into the requested changeset and the merged
5466 result is left uncommitted. If the requested changeset is
5471 result is left uncommitted. If the requested changeset is
5467 not an ancestor or descendant (that is, it is on another
5472 not an ancestor or descendant (that is, it is on another
5468 branch), the update is aborted and the uncommitted changes
5473 branch), the update is aborted and the uncommitted changes
5469 are preserved.
5474 are preserved.
5470
5475
5471 2. With the -m/--merge option, the update is allowed even if the
5476 2. With the -m/--merge option, the update is allowed even if the
5472 requested changeset is not an ancestor or descendant of
5477 requested changeset is not an ancestor or descendant of
5473 the working directory's parent.
5478 the working directory's parent.
5474
5479
5475 3. With the -c/--check option, the update is aborted and the
5480 3. With the -c/--check option, the update is aborted and the
5476 uncommitted changes are preserved.
5481 uncommitted changes are preserved.
5477
5482
5478 4. With the -C/--clean option, uncommitted changes are discarded and
5483 4. With the -C/--clean option, uncommitted changes are discarded and
5479 the working directory is updated to the requested changeset.
5484 the working directory is updated to the requested changeset.
5480
5485
5481 To cancel an uncommitted merge (and lose your changes), use
5486 To cancel an uncommitted merge (and lose your changes), use
5482 :hg:`update --clean .`.
5487 :hg:`update --clean .`.
5483
5488
5484 Use null as the changeset to remove the working directory (like
5489 Use null as the changeset to remove the working directory (like
5485 :hg:`clone -U`).
5490 :hg:`clone -U`).
5486
5491
5487 If you want to revert just one file to an older revision, use
5492 If you want to revert just one file to an older revision, use
5488 :hg:`revert [-r REV] NAME`.
5493 :hg:`revert [-r REV] NAME`.
5489
5494
5490 See :hg:`help dates` for a list of formats valid for -d/--date.
5495 See :hg:`help dates` for a list of formats valid for -d/--date.
5491
5496
5492 Returns 0 on success, 1 if there are unresolved files.
5497 Returns 0 on success, 1 if there are unresolved files.
5493 """
5498 """
5494 if rev and node:
5499 if rev and node:
5495 raise error.Abort(_("please specify just one revision"))
5500 raise error.Abort(_("please specify just one revision"))
5496
5501
5497 if ui.configbool('commands', 'update.requiredest'):
5502 if ui.configbool('commands', 'update.requiredest'):
5498 if not node and not rev and not date:
5503 if not node and not rev and not date:
5499 raise error.Abort(_('you must specify a destination'),
5504 raise error.Abort(_('you must specify a destination'),
5500 hint=_('for example: hg update ".::"'))
5505 hint=_('for example: hg update ".::"'))
5501
5506
5502 if rev is None or rev == '':
5507 if rev is None or rev == '':
5503 rev = node
5508 rev = node
5504
5509
5505 if date and rev is not None:
5510 if date and rev is not None:
5506 raise error.Abort(_("you can't specify a revision and a date"))
5511 raise error.Abort(_("you can't specify a revision and a date"))
5507
5512
5508 if len([x for x in (clean, check, merge) if x]) > 1:
5513 if len([x for x in (clean, check, merge) if x]) > 1:
5509 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5514 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5510 "or -m/--merge"))
5515 "or -m/--merge"))
5511
5516
5512 updatecheck = None
5517 updatecheck = None
5513 if check:
5518 if check:
5514 updatecheck = 'abort'
5519 updatecheck = 'abort'
5515 elif merge:
5520 elif merge:
5516 updatecheck = 'none'
5521 updatecheck = 'none'
5517
5522
5518 with repo.wlock():
5523 with repo.wlock():
5519 cmdutil.clearunfinished(repo)
5524 cmdutil.clearunfinished(repo)
5520
5525
5521 if date:
5526 if date:
5522 rev = cmdutil.finddate(ui, repo, date)
5527 rev = cmdutil.finddate(ui, repo, date)
5523
5528
5524 # if we defined a bookmark, we have to remember the original name
5529 # if we defined a bookmark, we have to remember the original name
5525 brev = rev
5530 brev = rev
5526 rev = scmutil.revsingle(repo, rev, rev).rev()
5531 rev = scmutil.revsingle(repo, rev, rev).rev()
5527
5532
5528 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5533 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5529
5534
5530 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5535 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5531 updatecheck=updatecheck)
5536 updatecheck=updatecheck)
5532
5537
5533 @command('verify', [])
5538 @command('verify', [])
5534 def verify(ui, repo):
5539 def verify(ui, repo):
5535 """verify the integrity of the repository
5540 """verify the integrity of the repository
5536
5541
5537 Verify the integrity of the current repository.
5542 Verify the integrity of the current repository.
5538
5543
5539 This will perform an extensive check of the repository's
5544 This will perform an extensive check of the repository's
5540 integrity, validating the hashes and checksums of each entry in
5545 integrity, validating the hashes and checksums of each entry in
5541 the changelog, manifest, and tracked files, as well as the
5546 the changelog, manifest, and tracked files, as well as the
5542 integrity of their crosslinks and indices.
5547 integrity of their crosslinks and indices.
5543
5548
5544 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5549 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5545 for more information about recovery from corruption of the
5550 for more information about recovery from corruption of the
5546 repository.
5551 repository.
5547
5552
5548 Returns 0 on success, 1 if errors are encountered.
5553 Returns 0 on success, 1 if errors are encountered.
5549 """
5554 """
5550 return hg.verify(repo)
5555 return hg.verify(repo)
5551
5556
5552 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5557 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5553 def version_(ui, **opts):
5558 def version_(ui, **opts):
5554 """output version and copyright information"""
5559 """output version and copyright information"""
5555 opts = pycompat.byteskwargs(opts)
5560 opts = pycompat.byteskwargs(opts)
5556 if ui.verbose:
5561 if ui.verbose:
5557 ui.pager('version')
5562 ui.pager('version')
5558 fm = ui.formatter("version", opts)
5563 fm = ui.formatter("version", opts)
5559 fm.startitem()
5564 fm.startitem()
5560 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5565 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5561 util.version())
5566 util.version())
5562 license = _(
5567 license = _(
5563 "(see https://mercurial-scm.org for more information)\n"
5568 "(see https://mercurial-scm.org for more information)\n"
5564 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5569 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5565 "This is free software; see the source for copying conditions. "
5570 "This is free software; see the source for copying conditions. "
5566 "There is NO\nwarranty; "
5571 "There is NO\nwarranty; "
5567 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5572 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5568 )
5573 )
5569 if not ui.quiet:
5574 if not ui.quiet:
5570 fm.plain(license)
5575 fm.plain(license)
5571
5576
5572 if ui.verbose:
5577 if ui.verbose:
5573 fm.plain(_("\nEnabled extensions:\n\n"))
5578 fm.plain(_("\nEnabled extensions:\n\n"))
5574 # format names and versions into columns
5579 # format names and versions into columns
5575 names = []
5580 names = []
5576 vers = []
5581 vers = []
5577 isinternals = []
5582 isinternals = []
5578 for name, module in extensions.extensions():
5583 for name, module in extensions.extensions():
5579 names.append(name)
5584 names.append(name)
5580 vers.append(extensions.moduleversion(module) or None)
5585 vers.append(extensions.moduleversion(module) or None)
5581 isinternals.append(extensions.ismoduleinternal(module))
5586 isinternals.append(extensions.ismoduleinternal(module))
5582 fn = fm.nested("extensions")
5587 fn = fm.nested("extensions")
5583 if names:
5588 if names:
5584 namefmt = " %%-%ds " % max(len(n) for n in names)
5589 namefmt = " %%-%ds " % max(len(n) for n in names)
5585 places = [_("external"), _("internal")]
5590 places = [_("external"), _("internal")]
5586 for n, v, p in zip(names, vers, isinternals):
5591 for n, v, p in zip(names, vers, isinternals):
5587 fn.startitem()
5592 fn.startitem()
5588 fn.condwrite(ui.verbose, "name", namefmt, n)
5593 fn.condwrite(ui.verbose, "name", namefmt, n)
5589 if ui.verbose:
5594 if ui.verbose:
5590 fn.plain("%s " % places[p])
5595 fn.plain("%s " % places[p])
5591 fn.data(bundled=p)
5596 fn.data(bundled=p)
5592 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5597 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5593 if ui.verbose:
5598 if ui.verbose:
5594 fn.plain("\n")
5599 fn.plain("\n")
5595 fn.end()
5600 fn.end()
5596 fm.end()
5601 fm.end()
5597
5602
5598 def loadcmdtable(ui, name, cmdtable):
5603 def loadcmdtable(ui, name, cmdtable):
5599 """Load command functions from specified cmdtable
5604 """Load command functions from specified cmdtable
5600 """
5605 """
5601 overrides = [cmd for cmd in cmdtable if cmd in table]
5606 overrides = [cmd for cmd in cmdtable if cmd in table]
5602 if overrides:
5607 if overrides:
5603 ui.warn(_("extension '%s' overrides commands: %s\n")
5608 ui.warn(_("extension '%s' overrides commands: %s\n")
5604 % (name, " ".join(overrides)))
5609 % (name, " ".join(overrides)))
5605 table.update(cmdtable)
5610 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now