##// END OF EJS Templates
annotate: add support to specify hidden revs if directaccess config is set...
Pulkit Goyal -
r35552:b6ce3568 default
parent child Browse files
Show More
@@ -1,5617 +1,5620 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 rev = opts.get('rev')
297 if rev:
298 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
299 ctx = scmutil.revsingle(repo, rev)
297
300
298 rootfm = ui.formatter('annotate', opts)
301 rootfm = ui.formatter('annotate', opts)
299 if ui.quiet:
302 if ui.quiet:
300 datefunc = util.shortdate
303 datefunc = util.shortdate
301 else:
304 else:
302 datefunc = util.datestr
305 datefunc = util.datestr
303 if ctx.rev() is None:
306 if ctx.rev() is None:
304 def hexfn(node):
307 def hexfn(node):
305 if node is None:
308 if node is None:
306 return None
309 return None
307 else:
310 else:
308 return rootfm.hexfunc(node)
311 return rootfm.hexfunc(node)
309 if opts.get('changeset'):
312 if opts.get('changeset'):
310 # omit "+" suffix which is appended to node hex
313 # omit "+" suffix which is appended to node hex
311 def formatrev(rev):
314 def formatrev(rev):
312 if rev is None:
315 if rev is None:
313 return '%d' % ctx.p1().rev()
316 return '%d' % ctx.p1().rev()
314 else:
317 else:
315 return '%d' % rev
318 return '%d' % rev
316 else:
319 else:
317 def formatrev(rev):
320 def formatrev(rev):
318 if rev is None:
321 if rev is None:
319 return '%d+' % ctx.p1().rev()
322 return '%d+' % ctx.p1().rev()
320 else:
323 else:
321 return '%d ' % rev
324 return '%d ' % rev
322 def formathex(hex):
325 def formathex(hex):
323 if hex is None:
326 if hex is None:
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
327 return '%s+' % rootfm.hexfunc(ctx.p1().node())
325 else:
328 else:
326 return '%s ' % hex
329 return '%s ' % hex
327 else:
330 else:
328 hexfn = rootfm.hexfunc
331 hexfn = rootfm.hexfunc
329 formatrev = formathex = pycompat.bytestr
332 formatrev = formathex = pycompat.bytestr
330
333
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
334 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
335 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
336 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
337 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
335 ('file', ' ', lambda x: x.fctx.path(), str),
338 ('file', ' ', lambda x: x.fctx.path(), str),
336 ('line_number', ':', lambda x: x.lineno, str),
339 ('line_number', ':', lambda x: x.lineno, str),
337 ]
340 ]
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
341 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
339
342
340 if (not opts.get('user') and not opts.get('changeset')
343 if (not opts.get('user') and not opts.get('changeset')
341 and not opts.get('date') and not opts.get('file')):
344 and not opts.get('date') and not opts.get('file')):
342 opts['number'] = True
345 opts['number'] = True
343
346
344 linenumber = opts.get('line_number') is not None
347 linenumber = opts.get('line_number') is not None
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
348 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'))
349 raise error.Abort(_('at least one of -n/-c is required for -l'))
347
350
348 ui.pager('annotate')
351 ui.pager('annotate')
349
352
350 if rootfm.isplain():
353 if rootfm.isplain():
351 def makefunc(get, fmt):
354 def makefunc(get, fmt):
352 return lambda x: fmt(get(x))
355 return lambda x: fmt(get(x))
353 else:
356 else:
354 def makefunc(get, fmt):
357 def makefunc(get, fmt):
355 return get
358 return get
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
359 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
357 if opts.get(op)]
360 if opts.get(op)]
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
361 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
362 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
360 if opts.get(op))
363 if opts.get(op))
361
364
362 def bad(x, y):
365 def bad(x, y):
363 raise error.Abort("%s: %s" % (x, y))
366 raise error.Abort("%s: %s" % (x, y))
364
367
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
368 m = scmutil.match(ctx, pats, opts, badfn=bad)
366
369
367 follow = not opts.get('no_follow')
370 follow = not opts.get('no_follow')
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
371 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
369 whitespace=True)
372 whitespace=True)
370 skiprevs = opts.get('skip')
373 skiprevs = opts.get('skip')
371 if skiprevs:
374 if skiprevs:
372 skiprevs = scmutil.revrange(repo, skiprevs)
375 skiprevs = scmutil.revrange(repo, skiprevs)
373
376
374 for abs in ctx.walk(m):
377 for abs in ctx.walk(m):
375 fctx = ctx[abs]
378 fctx = ctx[abs]
376 rootfm.startitem()
379 rootfm.startitem()
377 rootfm.data(abspath=abs, path=m.rel(abs))
380 rootfm.data(abspath=abs, path=m.rel(abs))
378 if not opts.get('text') and fctx.isbinary():
381 if not opts.get('text') and fctx.isbinary():
379 rootfm.plain(_("%s: binary file\n")
382 rootfm.plain(_("%s: binary file\n")
380 % ((pats and m.rel(abs)) or abs))
383 % ((pats and m.rel(abs)) or abs))
381 continue
384 continue
382
385
383 fm = rootfm.nested('lines')
386 fm = rootfm.nested('lines')
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
387 lines = fctx.annotate(follow=follow, linenumber=linenumber,
385 skiprevs=skiprevs, diffopts=diffopts)
388 skiprevs=skiprevs, diffopts=diffopts)
386 if not lines:
389 if not lines:
387 fm.end()
390 fm.end()
388 continue
391 continue
389 formats = []
392 formats = []
390 pieces = []
393 pieces = []
391
394
392 for f, sep in funcmap:
395 for f, sep in funcmap:
393 l = [f(n) for n, dummy in lines]
396 l = [f(n) for n, dummy in lines]
394 if fm.isplain():
397 if fm.isplain():
395 sizes = [encoding.colwidth(x) for x in l]
398 sizes = [encoding.colwidth(x) for x in l]
396 ml = max(sizes)
399 ml = max(sizes)
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
400 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
398 else:
401 else:
399 formats.append(['%s' for x in l])
402 formats.append(['%s' for x in l])
400 pieces.append(l)
403 pieces.append(l)
401
404
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
405 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
403 fm.startitem()
406 fm.startitem()
404 fm.write(fields, "".join(f), *p)
407 fm.write(fields, "".join(f), *p)
405 if l[0].skip:
408 if l[0].skip:
406 fmt = "* %s"
409 fmt = "* %s"
407 else:
410 else:
408 fmt = ": %s"
411 fmt = ": %s"
409 fm.write('line', fmt, l[1])
412 fm.write('line', fmt, l[1])
410
413
411 if not lines[-1][1].endswith('\n'):
414 if not lines[-1][1].endswith('\n'):
412 fm.plain('\n')
415 fm.plain('\n')
413 fm.end()
416 fm.end()
414
417
415 rootfm.end()
418 rootfm.end()
416
419
417 @command('archive',
420 @command('archive',
418 [('', 'no-decode', None, _('do not pass files through decoders')),
421 [('', 'no-decode', None, _('do not pass files through decoders')),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
422 ('p', 'prefix', '', _('directory prefix for files in archive'),
420 _('PREFIX')),
423 _('PREFIX')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
424 ('r', 'rev', '', _('revision to distribute'), _('REV')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
425 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
423 ] + subrepoopts + walkopts,
426 ] + subrepoopts + walkopts,
424 _('[OPTION]... DEST'))
427 _('[OPTION]... DEST'))
425 def archive(ui, repo, dest, **opts):
428 def archive(ui, repo, dest, **opts):
426 '''create an unversioned archive of a repository revision
429 '''create an unversioned archive of a repository revision
427
430
428 By default, the revision used is the parent of the working
431 By default, the revision used is the parent of the working
429 directory; use -r/--rev to specify a different revision.
432 directory; use -r/--rev to specify a different revision.
430
433
431 The archive type is automatically detected based on file
434 The archive type is automatically detected based on file
432 extension (to override, use -t/--type).
435 extension (to override, use -t/--type).
433
436
434 .. container:: verbose
437 .. container:: verbose
435
438
436 Examples:
439 Examples:
437
440
438 - create a zip file containing the 1.0 release::
441 - create a zip file containing the 1.0 release::
439
442
440 hg archive -r 1.0 project-1.0.zip
443 hg archive -r 1.0 project-1.0.zip
441
444
442 - create a tarball excluding .hg files::
445 - create a tarball excluding .hg files::
443
446
444 hg archive project.tar.gz -X ".hg*"
447 hg archive project.tar.gz -X ".hg*"
445
448
446 Valid types are:
449 Valid types are:
447
450
448 :``files``: a directory full of files (default)
451 :``files``: a directory full of files (default)
449 :``tar``: tar archive, uncompressed
452 :``tar``: tar archive, uncompressed
450 :``tbz2``: tar archive, compressed using bzip2
453 :``tbz2``: tar archive, compressed using bzip2
451 :``tgz``: tar archive, compressed using gzip
454 :``tgz``: tar archive, compressed using gzip
452 :``uzip``: zip archive, uncompressed
455 :``uzip``: zip archive, uncompressed
453 :``zip``: zip archive, compressed using deflate
456 :``zip``: zip archive, compressed using deflate
454
457
455 The exact name of the destination archive or directory is given
458 The exact name of the destination archive or directory is given
456 using a format string; see :hg:`help export` for details.
459 using a format string; see :hg:`help export` for details.
457
460
458 Each member added to an archive file has a directory prefix
461 Each member added to an archive file has a directory prefix
459 prepended. Use -p/--prefix to specify a format string for the
462 prepended. Use -p/--prefix to specify a format string for the
460 prefix. The default is the basename of the archive, with suffixes
463 prefix. The default is the basename of the archive, with suffixes
461 removed.
464 removed.
462
465
463 Returns 0 on success.
466 Returns 0 on success.
464 '''
467 '''
465
468
466 opts = pycompat.byteskwargs(opts)
469 opts = pycompat.byteskwargs(opts)
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
470 ctx = scmutil.revsingle(repo, opts.get('rev'))
468 if not ctx:
471 if not ctx:
469 raise error.Abort(_('no working directory: please specify a revision'))
472 raise error.Abort(_('no working directory: please specify a revision'))
470 node = ctx.node()
473 node = ctx.node()
471 dest = cmdutil.makefilename(repo, dest, node)
474 dest = cmdutil.makefilename(repo, dest, node)
472 if os.path.realpath(dest) == repo.root:
475 if os.path.realpath(dest) == repo.root:
473 raise error.Abort(_('repository root cannot be destination'))
476 raise error.Abort(_('repository root cannot be destination'))
474
477
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
478 kind = opts.get('type') or archival.guesskind(dest) or 'files'
476 prefix = opts.get('prefix')
479 prefix = opts.get('prefix')
477
480
478 if dest == '-':
481 if dest == '-':
479 if kind == 'files':
482 if kind == 'files':
480 raise error.Abort(_('cannot archive plain files to stdout'))
483 raise error.Abort(_('cannot archive plain files to stdout'))
481 dest = cmdutil.makefileobj(repo, dest)
484 dest = cmdutil.makefileobj(repo, dest)
482 if not prefix:
485 if not prefix:
483 prefix = os.path.basename(repo.root) + '-%h'
486 prefix = os.path.basename(repo.root) + '-%h'
484
487
485 prefix = cmdutil.makefilename(repo, prefix, node)
488 prefix = cmdutil.makefilename(repo, prefix, node)
486 match = scmutil.match(ctx, [], opts)
489 match = scmutil.match(ctx, [], opts)
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
490 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
488 match, prefix, subrepos=opts.get('subrepos'))
491 match, prefix, subrepos=opts.get('subrepos'))
489
492
490 @command('backout',
493 @command('backout',
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
494 [('', 'merge', None, _('merge with old dirstate parent after backout')),
492 ('', 'commit', None,
495 ('', 'commit', None,
493 _('commit if no conflicts were encountered (DEPRECATED)')),
496 _('commit if no conflicts were encountered (DEPRECATED)')),
494 ('', 'no-commit', None, _('do not commit')),
497 ('', 'no-commit', None, _('do not commit')),
495 ('', 'parent', '',
498 ('', 'parent', '',
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
499 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
500 ('r', 'rev', '', _('revision to backout'), _('REV')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
501 ('e', 'edit', False, _('invoke editor on commit messages')),
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
502 ] + mergetoolopts + walkopts + commitopts + commitopts2,
500 _('[OPTION]... [-r] REV'))
503 _('[OPTION]... [-r] REV'))
501 def backout(ui, repo, node=None, rev=None, **opts):
504 def backout(ui, repo, node=None, rev=None, **opts):
502 '''reverse effect of earlier changeset
505 '''reverse effect of earlier changeset
503
506
504 Prepare a new changeset with the effect of REV undone in the
507 Prepare a new changeset with the effect of REV undone in the
505 current working directory. If no conflicts were encountered,
508 current working directory. If no conflicts were encountered,
506 it will be committed immediately.
509 it will be committed immediately.
507
510
508 If REV is the parent of the working directory, then this new changeset
511 If REV is the parent of the working directory, then this new changeset
509 is committed automatically (unless --no-commit is specified).
512 is committed automatically (unless --no-commit is specified).
510
513
511 .. note::
514 .. note::
512
515
513 :hg:`backout` cannot be used to fix either an unwanted or
516 :hg:`backout` cannot be used to fix either an unwanted or
514 incorrect merge.
517 incorrect merge.
515
518
516 .. container:: verbose
519 .. container:: verbose
517
520
518 Examples:
521 Examples:
519
522
520 - Reverse the effect of the parent of the working directory.
523 - Reverse the effect of the parent of the working directory.
521 This backout will be committed immediately::
524 This backout will be committed immediately::
522
525
523 hg backout -r .
526 hg backout -r .
524
527
525 - Reverse the effect of previous bad revision 23::
528 - Reverse the effect of previous bad revision 23::
526
529
527 hg backout -r 23
530 hg backout -r 23
528
531
529 - Reverse the effect of previous bad revision 23 and
532 - Reverse the effect of previous bad revision 23 and
530 leave changes uncommitted::
533 leave changes uncommitted::
531
534
532 hg backout -r 23 --no-commit
535 hg backout -r 23 --no-commit
533 hg commit -m "Backout revision 23"
536 hg commit -m "Backout revision 23"
534
537
535 By default, the pending changeset will have one parent,
538 By default, the pending changeset will have one parent,
536 maintaining a linear history. With --merge, the pending
539 maintaining a linear history. With --merge, the pending
537 changeset will instead have two parents: the old parent of the
540 changeset will instead have two parents: the old parent of the
538 working directory and a new child of REV that simply undoes REV.
541 working directory and a new child of REV that simply undoes REV.
539
542
540 Before version 1.7, the behavior without --merge was equivalent
543 Before version 1.7, the behavior without --merge was equivalent
541 to specifying --merge followed by :hg:`update --clean .` to
544 to specifying --merge followed by :hg:`update --clean .` to
542 cancel the merge and leave the child of REV as a head to be
545 cancel the merge and leave the child of REV as a head to be
543 merged separately.
546 merged separately.
544
547
545 See :hg:`help dates` for a list of formats valid for -d/--date.
548 See :hg:`help dates` for a list of formats valid for -d/--date.
546
549
547 See :hg:`help revert` for a way to restore files to the state
550 See :hg:`help revert` for a way to restore files to the state
548 of another revision.
551 of another revision.
549
552
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
553 Returns 0 on success, 1 if nothing to backout or there are unresolved
551 files.
554 files.
552 '''
555 '''
553 wlock = lock = None
556 wlock = lock = None
554 try:
557 try:
555 wlock = repo.wlock()
558 wlock = repo.wlock()
556 lock = repo.lock()
559 lock = repo.lock()
557 return _dobackout(ui, repo, node, rev, **opts)
560 return _dobackout(ui, repo, node, rev, **opts)
558 finally:
561 finally:
559 release(lock, wlock)
562 release(lock, wlock)
560
563
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
564 def _dobackout(ui, repo, node=None, rev=None, **opts):
562 opts = pycompat.byteskwargs(opts)
565 opts = pycompat.byteskwargs(opts)
563 if opts.get('commit') and opts.get('no_commit'):
566 if opts.get('commit') and opts.get('no_commit'):
564 raise error.Abort(_("cannot use --commit with --no-commit"))
567 raise error.Abort(_("cannot use --commit with --no-commit"))
565 if opts.get('merge') and opts.get('no_commit'):
568 if opts.get('merge') and opts.get('no_commit'):
566 raise error.Abort(_("cannot use --merge with --no-commit"))
569 raise error.Abort(_("cannot use --merge with --no-commit"))
567
570
568 if rev and node:
571 if rev and node:
569 raise error.Abort(_("please specify just one revision"))
572 raise error.Abort(_("please specify just one revision"))
570
573
571 if not rev:
574 if not rev:
572 rev = node
575 rev = node
573
576
574 if not rev:
577 if not rev:
575 raise error.Abort(_("please specify a revision to backout"))
578 raise error.Abort(_("please specify a revision to backout"))
576
579
577 date = opts.get('date')
580 date = opts.get('date')
578 if date:
581 if date:
579 opts['date'] = util.parsedate(date)
582 opts['date'] = util.parsedate(date)
580
583
581 cmdutil.checkunfinished(repo)
584 cmdutil.checkunfinished(repo)
582 cmdutil.bailifchanged(repo)
585 cmdutil.bailifchanged(repo)
583 node = scmutil.revsingle(repo, rev).node()
586 node = scmutil.revsingle(repo, rev).node()
584
587
585 op1, op2 = repo.dirstate.parents()
588 op1, op2 = repo.dirstate.parents()
586 if not repo.changelog.isancestor(node, op1):
589 if not repo.changelog.isancestor(node, op1):
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
590 raise error.Abort(_('cannot backout change that is not an ancestor'))
588
591
589 p1, p2 = repo.changelog.parents(node)
592 p1, p2 = repo.changelog.parents(node)
590 if p1 == nullid:
593 if p1 == nullid:
591 raise error.Abort(_('cannot backout a change with no parents'))
594 raise error.Abort(_('cannot backout a change with no parents'))
592 if p2 != nullid:
595 if p2 != nullid:
593 if not opts.get('parent'):
596 if not opts.get('parent'):
594 raise error.Abort(_('cannot backout a merge changeset'))
597 raise error.Abort(_('cannot backout a merge changeset'))
595 p = repo.lookup(opts['parent'])
598 p = repo.lookup(opts['parent'])
596 if p not in (p1, p2):
599 if p not in (p1, p2):
597 raise error.Abort(_('%s is not a parent of %s') %
600 raise error.Abort(_('%s is not a parent of %s') %
598 (short(p), short(node)))
601 (short(p), short(node)))
599 parent = p
602 parent = p
600 else:
603 else:
601 if opts.get('parent'):
604 if opts.get('parent'):
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
605 raise error.Abort(_('cannot use --parent on non-merge changeset'))
603 parent = p1
606 parent = p1
604
607
605 # the backout should appear on the same branch
608 # the backout should appear on the same branch
606 branch = repo.dirstate.branch()
609 branch = repo.dirstate.branch()
607 bheads = repo.branchheads(branch)
610 bheads = repo.branchheads(branch)
608 rctx = scmutil.revsingle(repo, hex(parent))
611 rctx = scmutil.revsingle(repo, hex(parent))
609 if not opts.get('merge') and op1 != node:
612 if not opts.get('merge') and op1 != node:
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
613 dsguard = dirstateguard.dirstateguard(repo, 'backout')
611 try:
614 try:
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
615 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
613 'backout')
616 'backout')
614 stats = mergemod.update(repo, parent, True, True, node, False)
617 stats = mergemod.update(repo, parent, True, True, node, False)
615 repo.setparents(op1, op2)
618 repo.setparents(op1, op2)
616 dsguard.close()
619 dsguard.close()
617 hg._showstats(repo, stats)
620 hg._showstats(repo, stats)
618 if stats[3]:
621 if stats[3]:
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
622 repo.ui.status(_("use 'hg resolve' to retry unresolved "
620 "file merges\n"))
623 "file merges\n"))
621 return 1
624 return 1
622 finally:
625 finally:
623 ui.setconfig('ui', 'forcemerge', '', '')
626 ui.setconfig('ui', 'forcemerge', '', '')
624 lockmod.release(dsguard)
627 lockmod.release(dsguard)
625 else:
628 else:
626 hg.clean(repo, node, show_stats=False)
629 hg.clean(repo, node, show_stats=False)
627 repo.dirstate.setbranch(branch)
630 repo.dirstate.setbranch(branch)
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
631 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
629
632
630 if opts.get('no_commit'):
633 if opts.get('no_commit'):
631 msg = _("changeset %s backed out, "
634 msg = _("changeset %s backed out, "
632 "don't forget to commit.\n")
635 "don't forget to commit.\n")
633 ui.status(msg % short(node))
636 ui.status(msg % short(node))
634 return 0
637 return 0
635
638
636 def commitfunc(ui, repo, message, match, opts):
639 def commitfunc(ui, repo, message, match, opts):
637 editform = 'backout'
640 editform = 'backout'
638 e = cmdutil.getcommiteditor(editform=editform,
641 e = cmdutil.getcommiteditor(editform=editform,
639 **pycompat.strkwargs(opts))
642 **pycompat.strkwargs(opts))
640 if not message:
643 if not message:
641 # we don't translate commit messages
644 # we don't translate commit messages
642 message = "Backed out changeset %s" % short(node)
645 message = "Backed out changeset %s" % short(node)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
646 e = cmdutil.getcommiteditor(edit=True, editform=editform)
644 return repo.commit(message, opts.get('user'), opts.get('date'),
647 return repo.commit(message, opts.get('user'), opts.get('date'),
645 match, editor=e)
648 match, editor=e)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
649 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
647 if not newnode:
650 if not newnode:
648 ui.status(_("nothing changed\n"))
651 ui.status(_("nothing changed\n"))
649 return 1
652 return 1
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
653 cmdutil.commitstatus(repo, newnode, branch, bheads)
651
654
652 def nice(node):
655 def nice(node):
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
656 return '%d:%s' % (repo.changelog.rev(node), short(node))
654 ui.status(_('changeset %s backs out changeset %s\n') %
657 ui.status(_('changeset %s backs out changeset %s\n') %
655 (nice(repo.changelog.tip()), nice(node)))
658 (nice(repo.changelog.tip()), nice(node)))
656 if opts.get('merge') and op1 != node:
659 if opts.get('merge') and op1 != node:
657 hg.clean(repo, op1, show_stats=False)
660 hg.clean(repo, op1, show_stats=False)
658 ui.status(_('merging with changeset %s\n')
661 ui.status(_('merging with changeset %s\n')
659 % nice(repo.changelog.tip()))
662 % nice(repo.changelog.tip()))
660 try:
663 try:
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
664 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
662 'backout')
665 'backout')
663 return hg.merge(repo, hex(repo.changelog.tip()))
666 return hg.merge(repo, hex(repo.changelog.tip()))
664 finally:
667 finally:
665 ui.setconfig('ui', 'forcemerge', '', '')
668 ui.setconfig('ui', 'forcemerge', '', '')
666 return 0
669 return 0
667
670
668 @command('bisect',
671 @command('bisect',
669 [('r', 'reset', False, _('reset bisect state')),
672 [('r', 'reset', False, _('reset bisect state')),
670 ('g', 'good', False, _('mark changeset good')),
673 ('g', 'good', False, _('mark changeset good')),
671 ('b', 'bad', False, _('mark changeset bad')),
674 ('b', 'bad', False, _('mark changeset bad')),
672 ('s', 'skip', False, _('skip testing changeset')),
675 ('s', 'skip', False, _('skip testing changeset')),
673 ('e', 'extend', False, _('extend the bisect range')),
676 ('e', 'extend', False, _('extend the bisect range')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
677 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('U', 'noupdate', False, _('do not update to target'))],
678 ('U', 'noupdate', False, _('do not update to target'))],
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
679 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 def bisect(ui, repo, rev=None, extra=None, command=None,
680 def bisect(ui, repo, rev=None, extra=None, command=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
681 reset=None, good=None, bad=None, skip=None, extend=None,
679 noupdate=None):
682 noupdate=None):
680 """subdivision search of changesets
683 """subdivision search of changesets
681
684
682 This command helps to find changesets which introduce problems. To
685 This command helps to find changesets which introduce problems. To
683 use, mark the earliest changeset you know exhibits the problem as
686 use, mark the earliest changeset you know exhibits the problem as
684 bad, then mark the latest changeset which is free from the problem
687 bad, then mark the latest changeset which is free from the problem
685 as good. Bisect will update your working directory to a revision
688 as good. Bisect will update your working directory to a revision
686 for testing (unless the -U/--noupdate option is specified). Once
689 for testing (unless the -U/--noupdate option is specified). Once
687 you have performed tests, mark the working directory as good or
690 you have performed tests, mark the working directory as good or
688 bad, and bisect will either update to another candidate changeset
691 bad, and bisect will either update to another candidate changeset
689 or announce that it has found the bad revision.
692 or announce that it has found the bad revision.
690
693
691 As a shortcut, you can also use the revision argument to mark a
694 As a shortcut, you can also use the revision argument to mark a
692 revision as good or bad without checking it out first.
695 revision as good or bad without checking it out first.
693
696
694 If you supply a command, it will be used for automatic bisection.
697 If you supply a command, it will be used for automatic bisection.
695 The environment variable HG_NODE will contain the ID of the
698 The environment variable HG_NODE will contain the ID of the
696 changeset being tested. The exit status of the command will be
699 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
700 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
701 means to skip the revision, 127 (command not found) will abort the
699 bisection, and any other non-zero exit status means the revision
702 bisection, and any other non-zero exit status means the revision
700 is bad.
703 is bad.
701
704
702 .. container:: verbose
705 .. container:: verbose
703
706
704 Some examples:
707 Some examples:
705
708
706 - start a bisection with known bad revision 34, and good revision 12::
709 - start a bisection with known bad revision 34, and good revision 12::
707
710
708 hg bisect --bad 34
711 hg bisect --bad 34
709 hg bisect --good 12
712 hg bisect --good 12
710
713
711 - advance the current bisection by marking current revision as good or
714 - advance the current bisection by marking current revision as good or
712 bad::
715 bad::
713
716
714 hg bisect --good
717 hg bisect --good
715 hg bisect --bad
718 hg bisect --bad
716
719
717 - mark the current revision, or a known revision, to be skipped (e.g. if
720 - mark the current revision, or a known revision, to be skipped (e.g. if
718 that revision is not usable because of another issue)::
721 that revision is not usable because of another issue)::
719
722
720 hg bisect --skip
723 hg bisect --skip
721 hg bisect --skip 23
724 hg bisect --skip 23
722
725
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
726 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724
727
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
728 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726
729
727 - forget the current bisection::
730 - forget the current bisection::
728
731
729 hg bisect --reset
732 hg bisect --reset
730
733
731 - use 'make && make tests' to automatically find the first broken
734 - use 'make && make tests' to automatically find the first broken
732 revision::
735 revision::
733
736
734 hg bisect --reset
737 hg bisect --reset
735 hg bisect --bad 34
738 hg bisect --bad 34
736 hg bisect --good 12
739 hg bisect --good 12
737 hg bisect --command "make && make tests"
740 hg bisect --command "make && make tests"
738
741
739 - see all changesets whose states are already known in the current
742 - see all changesets whose states are already known in the current
740 bisection::
743 bisection::
741
744
742 hg log -r "bisect(pruned)"
745 hg log -r "bisect(pruned)"
743
746
744 - see the changeset currently being bisected (especially useful
747 - see the changeset currently being bisected (especially useful
745 if running with -U/--noupdate)::
748 if running with -U/--noupdate)::
746
749
747 hg log -r "bisect(current)"
750 hg log -r "bisect(current)"
748
751
749 - see all changesets that took part in the current bisection::
752 - see all changesets that took part in the current bisection::
750
753
751 hg log -r "bisect(range)"
754 hg log -r "bisect(range)"
752
755
753 - you can even get a nice graph::
756 - you can even get a nice graph::
754
757
755 hg log --graph -r "bisect(range)"
758 hg log --graph -r "bisect(range)"
756
759
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
760 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758
761
759 Returns 0 on success.
762 Returns 0 on success.
760 """
763 """
761 # backward compatibility
764 # backward compatibility
762 if rev in "good bad reset init".split():
765 if rev in "good bad reset init".split():
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
766 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 cmd, rev, extra = rev, extra, None
767 cmd, rev, extra = rev, extra, None
765 if cmd == "good":
768 if cmd == "good":
766 good = True
769 good = True
767 elif cmd == "bad":
770 elif cmd == "bad":
768 bad = True
771 bad = True
769 else:
772 else:
770 reset = True
773 reset = True
771 elif extra:
774 elif extra:
772 raise error.Abort(_('incompatible arguments'))
775 raise error.Abort(_('incompatible arguments'))
773
776
774 incompatibles = {
777 incompatibles = {
775 '--bad': bad,
778 '--bad': bad,
776 '--command': bool(command),
779 '--command': bool(command),
777 '--extend': extend,
780 '--extend': extend,
778 '--good': good,
781 '--good': good,
779 '--reset': reset,
782 '--reset': reset,
780 '--skip': skip,
783 '--skip': skip,
781 }
784 }
782
785
783 enabled = [x for x in incompatibles if incompatibles[x]]
786 enabled = [x for x in incompatibles if incompatibles[x]]
784
787
785 if len(enabled) > 1:
788 if len(enabled) > 1:
786 raise error.Abort(_('%s and %s are incompatible') %
789 raise error.Abort(_('%s and %s are incompatible') %
787 tuple(sorted(enabled)[0:2]))
790 tuple(sorted(enabled)[0:2]))
788
791
789 if reset:
792 if reset:
790 hbisect.resetstate(repo)
793 hbisect.resetstate(repo)
791 return
794 return
792
795
793 state = hbisect.load_state(repo)
796 state = hbisect.load_state(repo)
794
797
795 # update state
798 # update state
796 if good or bad or skip:
799 if good or bad or skip:
797 if rev:
800 if rev:
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
801 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
799 else:
802 else:
800 nodes = [repo.lookup('.')]
803 nodes = [repo.lookup('.')]
801 if good:
804 if good:
802 state['good'] += nodes
805 state['good'] += nodes
803 elif bad:
806 elif bad:
804 state['bad'] += nodes
807 state['bad'] += nodes
805 elif skip:
808 elif skip:
806 state['skip'] += nodes
809 state['skip'] += nodes
807 hbisect.save_state(repo, state)
810 hbisect.save_state(repo, state)
808 if not (state['good'] and state['bad']):
811 if not (state['good'] and state['bad']):
809 return
812 return
810
813
811 def mayupdate(repo, node, show_stats=True):
814 def mayupdate(repo, node, show_stats=True):
812 """common used update sequence"""
815 """common used update sequence"""
813 if noupdate:
816 if noupdate:
814 return
817 return
815 cmdutil.checkunfinished(repo)
818 cmdutil.checkunfinished(repo)
816 cmdutil.bailifchanged(repo)
819 cmdutil.bailifchanged(repo)
817 return hg.clean(repo, node, show_stats=show_stats)
820 return hg.clean(repo, node, show_stats=show_stats)
818
821
819 displayer = cmdutil.show_changeset(ui, repo, {})
822 displayer = cmdutil.show_changeset(ui, repo, {})
820
823
821 if command:
824 if command:
822 changesets = 1
825 changesets = 1
823 if noupdate:
826 if noupdate:
824 try:
827 try:
825 node = state['current'][0]
828 node = state['current'][0]
826 except LookupError:
829 except LookupError:
827 raise error.Abort(_('current bisect revision is unknown - '
830 raise error.Abort(_('current bisect revision is unknown - '
828 'start a new bisect to fix'))
831 'start a new bisect to fix'))
829 else:
832 else:
830 node, p2 = repo.dirstate.parents()
833 node, p2 = repo.dirstate.parents()
831 if p2 != nullid:
834 if p2 != nullid:
832 raise error.Abort(_('current bisect revision is a merge'))
835 raise error.Abort(_('current bisect revision is a merge'))
833 if rev:
836 if rev:
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
837 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 try:
838 try:
836 while changesets:
839 while changesets:
837 # update state
840 # update state
838 state['current'] = [node]
841 state['current'] = [node]
839 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
843 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 blockedtag='bisect_check')
844 blockedtag='bisect_check')
842 if status == 125:
845 if status == 125:
843 transition = "skip"
846 transition = "skip"
844 elif status == 0:
847 elif status == 0:
845 transition = "good"
848 transition = "good"
846 # status < 0 means process was killed
849 # status < 0 means process was killed
847 elif status == 127:
850 elif status == 127:
848 raise error.Abort(_("failed to execute %s") % command)
851 raise error.Abort(_("failed to execute %s") % command)
849 elif status < 0:
852 elif status < 0:
850 raise error.Abort(_("%s killed") % command)
853 raise error.Abort(_("%s killed") % command)
851 else:
854 else:
852 transition = "bad"
855 transition = "bad"
853 state[transition].append(node)
856 state[transition].append(node)
854 ctx = repo[node]
857 ctx = repo[node]
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
858 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
856 hbisect.checkstate(state)
859 hbisect.checkstate(state)
857 # bisect
860 # bisect
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
861 nodes, changesets, bgood = hbisect.bisect(repo, state)
859 # update to next check
862 # update to next check
860 node = nodes[0]
863 node = nodes[0]
861 mayupdate(repo, node, show_stats=False)
864 mayupdate(repo, node, show_stats=False)
862 finally:
865 finally:
863 state['current'] = [node]
866 state['current'] = [node]
864 hbisect.save_state(repo, state)
867 hbisect.save_state(repo, state)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
868 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
866 return
869 return
867
870
868 hbisect.checkstate(state)
871 hbisect.checkstate(state)
869
872
870 # actually bisect
873 # actually bisect
871 nodes, changesets, good = hbisect.bisect(repo, state)
874 nodes, changesets, good = hbisect.bisect(repo, state)
872 if extend:
875 if extend:
873 if not changesets:
876 if not changesets:
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
877 extendnode = hbisect.extendrange(repo, state, nodes, good)
875 if extendnode is not None:
878 if extendnode is not None:
876 ui.write(_("Extending search to changeset %d:%s\n")
879 ui.write(_("Extending search to changeset %d:%s\n")
877 % (extendnode.rev(), extendnode))
880 % (extendnode.rev(), extendnode))
878 state['current'] = [extendnode.node()]
881 state['current'] = [extendnode.node()]
879 hbisect.save_state(repo, state)
882 hbisect.save_state(repo, state)
880 return mayupdate(repo, extendnode.node())
883 return mayupdate(repo, extendnode.node())
881 raise error.Abort(_("nothing to extend"))
884 raise error.Abort(_("nothing to extend"))
882
885
883 if changesets == 0:
886 if changesets == 0:
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
887 hbisect.printresult(ui, repo, state, displayer, nodes, good)
885 else:
888 else:
886 assert len(nodes) == 1 # only a single node can be tested next
889 assert len(nodes) == 1 # only a single node can be tested next
887 node = nodes[0]
890 node = nodes[0]
888 # compute the approximate number of remaining tests
891 # compute the approximate number of remaining tests
889 tests, size = 0, 2
892 tests, size = 0, 2
890 while size <= changesets:
893 while size <= changesets:
891 tests, size = tests + 1, size * 2
894 tests, size = tests + 1, size * 2
892 rev = repo.changelog.rev(node)
895 rev = repo.changelog.rev(node)
893 ui.write(_("Testing changeset %d:%s "
896 ui.write(_("Testing changeset %d:%s "
894 "(%d changesets remaining, ~%d tests)\n")
897 "(%d changesets remaining, ~%d tests)\n")
895 % (rev, short(node), changesets, tests))
898 % (rev, short(node), changesets, tests))
896 state['current'] = [node]
899 state['current'] = [node]
897 hbisect.save_state(repo, state)
900 hbisect.save_state(repo, state)
898 return mayupdate(repo, node)
901 return mayupdate(repo, node)
899
902
900 @command('bookmarks|bookmark',
903 @command('bookmarks|bookmark',
901 [('f', 'force', False, _('force')),
904 [('f', 'force', False, _('force')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
905 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
903 ('d', 'delete', False, _('delete a given bookmark')),
906 ('d', 'delete', False, _('delete a given bookmark')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
907 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
908 ('i', 'inactive', False, _('mark a bookmark inactive')),
906 ] + formatteropts,
909 ] + formatteropts,
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
910 _('hg bookmarks [OPTIONS]... [NAME]...'))
908 def bookmark(ui, repo, *names, **opts):
911 def bookmark(ui, repo, *names, **opts):
909 '''create a new bookmark or list existing bookmarks
912 '''create a new bookmark or list existing bookmarks
910
913
911 Bookmarks are labels on changesets to help track lines of development.
914 Bookmarks are labels on changesets to help track lines of development.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
915 Bookmarks are unversioned and can be moved, renamed and deleted.
913 Deleting or moving a bookmark has no effect on the associated changesets.
916 Deleting or moving a bookmark has no effect on the associated changesets.
914
917
915 Creating or updating to a bookmark causes it to be marked as 'active'.
918 Creating or updating to a bookmark causes it to be marked as 'active'.
916 The active bookmark is indicated with a '*'.
919 The active bookmark is indicated with a '*'.
917 When a commit is made, the active bookmark will advance to the new commit.
920 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.
921 A plain :hg:`update` will also advance an active bookmark, if possible.
919 Updating away from a bookmark will cause it to be deactivated.
922 Updating away from a bookmark will cause it to be deactivated.
920
923
921 Bookmarks can be pushed and pulled between repositories (see
924 Bookmarks can be pushed and pulled between repositories (see
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
925 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
926 diverged, a new 'divergent bookmark' of the form 'name@path' will
924 be created. Using :hg:`merge` will resolve the divergence.
927 be created. Using :hg:`merge` will resolve the divergence.
925
928
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
929 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
927 the active bookmark's name.
930 the active bookmark's name.
928
931
929 A bookmark named '@' has the special property that :hg:`clone` will
932 A bookmark named '@' has the special property that :hg:`clone` will
930 check it out by default if it exists.
933 check it out by default if it exists.
931
934
932 .. container:: verbose
935 .. container:: verbose
933
936
934 Examples:
937 Examples:
935
938
936 - create an active bookmark for a new line of development::
939 - create an active bookmark for a new line of development::
937
940
938 hg book new-feature
941 hg book new-feature
939
942
940 - create an inactive bookmark as a place marker::
943 - create an inactive bookmark as a place marker::
941
944
942 hg book -i reviewed
945 hg book -i reviewed
943
946
944 - create an inactive bookmark on another changeset::
947 - create an inactive bookmark on another changeset::
945
948
946 hg book -r .^ tested
949 hg book -r .^ tested
947
950
948 - rename bookmark turkey to dinner::
951 - rename bookmark turkey to dinner::
949
952
950 hg book -m turkey dinner
953 hg book -m turkey dinner
951
954
952 - move the '@' bookmark from another branch::
955 - move the '@' bookmark from another branch::
953
956
954 hg book -f @
957 hg book -f @
955 '''
958 '''
956 force = opts.get(r'force')
959 force = opts.get(r'force')
957 rev = opts.get(r'rev')
960 rev = opts.get(r'rev')
958 delete = opts.get(r'delete')
961 delete = opts.get(r'delete')
959 rename = opts.get(r'rename')
962 rename = opts.get(r'rename')
960 inactive = opts.get(r'inactive')
963 inactive = opts.get(r'inactive')
961
964
962 if delete and rename:
965 if delete and rename:
963 raise error.Abort(_("--delete and --rename are incompatible"))
966 raise error.Abort(_("--delete and --rename are incompatible"))
964 if delete and rev:
967 if delete and rev:
965 raise error.Abort(_("--rev is incompatible with --delete"))
968 raise error.Abort(_("--rev is incompatible with --delete"))
966 if rename and rev:
969 if rename and rev:
967 raise error.Abort(_("--rev is incompatible with --rename"))
970 raise error.Abort(_("--rev is incompatible with --rename"))
968 if not names and (delete or rev):
971 if not names and (delete or rev):
969 raise error.Abort(_("bookmark name required"))
972 raise error.Abort(_("bookmark name required"))
970
973
971 if delete or rename or names or inactive:
974 if delete or rename or names or inactive:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
975 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
973 if delete:
976 if delete:
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
977 names = pycompat.maplist(repo._bookmarks.expandname, names)
975 bookmarks.delete(repo, tr, names)
978 bookmarks.delete(repo, tr, names)
976 elif rename:
979 elif rename:
977 if not names:
980 if not names:
978 raise error.Abort(_("new bookmark name required"))
981 raise error.Abort(_("new bookmark name required"))
979 elif len(names) > 1:
982 elif len(names) > 1:
980 raise error.Abort(_("only one new bookmark name allowed"))
983 raise error.Abort(_("only one new bookmark name allowed"))
981 rename = repo._bookmarks.expandname(rename)
984 rename = repo._bookmarks.expandname(rename)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
985 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
983 elif names:
986 elif names:
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
987 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
985 elif inactive:
988 elif inactive:
986 if len(repo._bookmarks) == 0:
989 if len(repo._bookmarks) == 0:
987 ui.status(_("no bookmarks set\n"))
990 ui.status(_("no bookmarks set\n"))
988 elif not repo._activebookmark:
991 elif not repo._activebookmark:
989 ui.status(_("no active bookmark\n"))
992 ui.status(_("no active bookmark\n"))
990 else:
993 else:
991 bookmarks.deactivate(repo)
994 bookmarks.deactivate(repo)
992 else: # show bookmarks
995 else: # show bookmarks
993 bookmarks.printbookmarks(ui, repo, **opts)
996 bookmarks.printbookmarks(ui, repo, **opts)
994
997
995 @command('branch',
998 @command('branch',
996 [('f', 'force', None,
999 [('f', 'force', None,
997 _('set branch name even if it shadows an existing branch')),
1000 _('set branch name even if it shadows an existing branch')),
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1001 ('C', 'clean', None, _('reset branch name to parent branch name'))],
999 _('[-fC] [NAME]'))
1002 _('[-fC] [NAME]'))
1000 def branch(ui, repo, label=None, **opts):
1003 def branch(ui, repo, label=None, **opts):
1001 """set or show the current branch name
1004 """set or show the current branch name
1002
1005
1003 .. note::
1006 .. note::
1004
1007
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1008 Branch names are permanent and global. Use :hg:`bookmark` to create a
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1009 light-weight bookmark instead. See :hg:`help glossary` for more
1007 information about named branches and bookmarks.
1010 information about named branches and bookmarks.
1008
1011
1009 With no argument, show the current branch name. With one argument,
1012 With no argument, show the current branch name. With one argument,
1010 set the working directory branch name (the branch will not exist
1013 set the working directory branch name (the branch will not exist
1011 in the repository until the next commit). Standard practice
1014 in the repository until the next commit). Standard practice
1012 recommends that primary development take place on the 'default'
1015 recommends that primary development take place on the 'default'
1013 branch.
1016 branch.
1014
1017
1015 Unless -f/--force is specified, branch will not let you set a
1018 Unless -f/--force is specified, branch will not let you set a
1016 branch name that already exists.
1019 branch name that already exists.
1017
1020
1018 Use -C/--clean to reset the working directory branch to that of
1021 Use -C/--clean to reset the working directory branch to that of
1019 the parent of the working directory, negating a previous branch
1022 the parent of the working directory, negating a previous branch
1020 change.
1023 change.
1021
1024
1022 Use the command :hg:`update` to switch to an existing branch. Use
1025 Use the command :hg:`update` to switch to an existing branch. Use
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1026 :hg:`commit --close-branch` to mark this branch head as closed.
1024 When all heads of a branch are closed, the branch will be
1027 When all heads of a branch are closed, the branch will be
1025 considered closed.
1028 considered closed.
1026
1029
1027 Returns 0 on success.
1030 Returns 0 on success.
1028 """
1031 """
1029 opts = pycompat.byteskwargs(opts)
1032 opts = pycompat.byteskwargs(opts)
1030 if label:
1033 if label:
1031 label = label.strip()
1034 label = label.strip()
1032
1035
1033 if not opts.get('clean') and not label:
1036 if not opts.get('clean') and not label:
1034 ui.write("%s\n" % repo.dirstate.branch())
1037 ui.write("%s\n" % repo.dirstate.branch())
1035 return
1038 return
1036
1039
1037 with repo.wlock():
1040 with repo.wlock():
1038 if opts.get('clean'):
1041 if opts.get('clean'):
1039 label = repo[None].p1().branch()
1042 label = repo[None].p1().branch()
1040 repo.dirstate.setbranch(label)
1043 repo.dirstate.setbranch(label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1044 ui.status(_('reset working directory to branch %s\n') % label)
1042 elif label:
1045 elif label:
1043 if not opts.get('force') and label in repo.branchmap():
1046 if not opts.get('force') and label in repo.branchmap():
1044 if label not in [p.branch() for p in repo[None].parents()]:
1047 if label not in [p.branch() for p in repo[None].parents()]:
1045 raise error.Abort(_('a branch of the same name already'
1048 raise error.Abort(_('a branch of the same name already'
1046 ' exists'),
1049 ' exists'),
1047 # i18n: "it" refers to an existing branch
1050 # i18n: "it" refers to an existing branch
1048 hint=_("use 'hg update' to switch to it"))
1051 hint=_("use 'hg update' to switch to it"))
1049 scmutil.checknewlabel(repo, label, 'branch')
1052 scmutil.checknewlabel(repo, label, 'branch')
1050 repo.dirstate.setbranch(label)
1053 repo.dirstate.setbranch(label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1054 ui.status(_('marked working directory as branch %s\n') % label)
1052
1055
1053 # find any open named branches aside from default
1056 # find any open named branches aside from default
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1057 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1055 if n != "default" and not c]
1058 if n != "default" and not c]
1056 if not others:
1059 if not others:
1057 ui.status(_('(branches are permanent and global, '
1060 ui.status(_('(branches are permanent and global, '
1058 'did you want a bookmark?)\n'))
1061 'did you want a bookmark?)\n'))
1059
1062
1060 @command('branches',
1063 @command('branches',
1061 [('a', 'active', False,
1064 [('a', 'active', False,
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1065 _('show only branches that have unmerged heads (DEPRECATED)')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1066 ('c', 'closed', False, _('show normal and closed branches')),
1064 ] + formatteropts,
1067 ] + formatteropts,
1065 _('[-c]'), cmdtype=readonly)
1068 _('[-c]'), cmdtype=readonly)
1066 def branches(ui, repo, active=False, closed=False, **opts):
1069 def branches(ui, repo, active=False, closed=False, **opts):
1067 """list repository named branches
1070 """list repository named branches
1068
1071
1069 List the repository's named branches, indicating which ones are
1072 List the repository's named branches, indicating which ones are
1070 inactive. If -c/--closed is specified, also list branches which have
1073 inactive. If -c/--closed is specified, also list branches which have
1071 been marked closed (see :hg:`commit --close-branch`).
1074 been marked closed (see :hg:`commit --close-branch`).
1072
1075
1073 Use the command :hg:`update` to switch to an existing branch.
1076 Use the command :hg:`update` to switch to an existing branch.
1074
1077
1075 Returns 0.
1078 Returns 0.
1076 """
1079 """
1077
1080
1078 opts = pycompat.byteskwargs(opts)
1081 opts = pycompat.byteskwargs(opts)
1079 ui.pager('branches')
1082 ui.pager('branches')
1080 fm = ui.formatter('branches', opts)
1083 fm = ui.formatter('branches', opts)
1081 hexfunc = fm.hexfunc
1084 hexfunc = fm.hexfunc
1082
1085
1083 allheads = set(repo.heads())
1086 allheads = set(repo.heads())
1084 branches = []
1087 branches = []
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1088 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1086 isactive = False
1089 isactive = False
1087 if not isclosed:
1090 if not isclosed:
1088 openheads = set(repo.branchmap().iteropen(heads))
1091 openheads = set(repo.branchmap().iteropen(heads))
1089 isactive = bool(openheads & allheads)
1092 isactive = bool(openheads & allheads)
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1093 branches.append((tag, repo[tip], isactive, not isclosed))
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1094 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1092 reverse=True)
1095 reverse=True)
1093
1096
1094 for tag, ctx, isactive, isopen in branches:
1097 for tag, ctx, isactive, isopen in branches:
1095 if active and not isactive:
1098 if active and not isactive:
1096 continue
1099 continue
1097 if isactive:
1100 if isactive:
1098 label = 'branches.active'
1101 label = 'branches.active'
1099 notice = ''
1102 notice = ''
1100 elif not isopen:
1103 elif not isopen:
1101 if not closed:
1104 if not closed:
1102 continue
1105 continue
1103 label = 'branches.closed'
1106 label = 'branches.closed'
1104 notice = _(' (closed)')
1107 notice = _(' (closed)')
1105 else:
1108 else:
1106 label = 'branches.inactive'
1109 label = 'branches.inactive'
1107 notice = _(' (inactive)')
1110 notice = _(' (inactive)')
1108 current = (tag == repo.dirstate.branch())
1111 current = (tag == repo.dirstate.branch())
1109 if current:
1112 if current:
1110 label = 'branches.current'
1113 label = 'branches.current'
1111
1114
1112 fm.startitem()
1115 fm.startitem()
1113 fm.write('branch', '%s', tag, label=label)
1116 fm.write('branch', '%s', tag, label=label)
1114 rev = ctx.rev()
1117 rev = ctx.rev()
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1118 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1116 fmt = ' ' * padsize + ' %d:%s'
1119 fmt = ' ' * padsize + ' %d:%s'
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1120 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1121 label='log.changeset changeset.%s' % ctx.phasestr())
1119 fm.context(ctx=ctx)
1122 fm.context(ctx=ctx)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1123 fm.data(active=isactive, closed=not isopen, current=current)
1121 if not ui.quiet:
1124 if not ui.quiet:
1122 fm.plain(notice)
1125 fm.plain(notice)
1123 fm.plain('\n')
1126 fm.plain('\n')
1124 fm.end()
1127 fm.end()
1125
1128
1126 @command('bundle',
1129 @command('bundle',
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1130 [('f', 'force', None, _('run even when the destination is unrelated')),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1131 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1129 _('REV')),
1132 _('REV')),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1133 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1131 _('BRANCH')),
1134 _('BRANCH')),
1132 ('', 'base', [],
1135 ('', 'base', [],
1133 _('a base changeset assumed to be available at the destination'),
1136 _('a base changeset assumed to be available at the destination'),
1134 _('REV')),
1137 _('REV')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1138 ('a', 'all', None, _('bundle all changesets in the repository')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1139 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1137 ] + remoteopts,
1140 ] + remoteopts,
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1141 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1139 def bundle(ui, repo, fname, dest=None, **opts):
1142 def bundle(ui, repo, fname, dest=None, **opts):
1140 """create a bundle file
1143 """create a bundle file
1141
1144
1142 Generate a bundle file containing data to be added to a repository.
1145 Generate a bundle file containing data to be added to a repository.
1143
1146
1144 To create a bundle containing all changesets, use -a/--all
1147 To create a bundle containing all changesets, use -a/--all
1145 (or --base null). Otherwise, hg assumes the destination will have
1148 (or --base null). Otherwise, hg assumes the destination will have
1146 all the nodes you specify with --base parameters. Otherwise, hg
1149 all the nodes you specify with --base parameters. Otherwise, hg
1147 will assume the repository has all the nodes in destination, or
1150 will assume the repository has all the nodes in destination, or
1148 default-push/default if no destination is specified.
1151 default-push/default if no destination is specified.
1149
1152
1150 You can change bundle format with the -t/--type option. See
1153 You can change bundle format with the -t/--type option. See
1151 :hg:`help bundlespec` for documentation on this format. By default,
1154 :hg:`help bundlespec` for documentation on this format. By default,
1152 the most appropriate format is used and compression defaults to
1155 the most appropriate format is used and compression defaults to
1153 bzip2.
1156 bzip2.
1154
1157
1155 The bundle file can then be transferred using conventional means
1158 The bundle file can then be transferred using conventional means
1156 and applied to another repository with the unbundle or pull
1159 and applied to another repository with the unbundle or pull
1157 command. This is useful when direct push and pull are not
1160 command. This is useful when direct push and pull are not
1158 available or when exporting an entire repository is undesirable.
1161 available or when exporting an entire repository is undesirable.
1159
1162
1160 Applying bundles preserves all changeset contents including
1163 Applying bundles preserves all changeset contents including
1161 permissions, copy/rename information, and revision history.
1164 permissions, copy/rename information, and revision history.
1162
1165
1163 Returns 0 on success, 1 if no changes found.
1166 Returns 0 on success, 1 if no changes found.
1164 """
1167 """
1165 opts = pycompat.byteskwargs(opts)
1168 opts = pycompat.byteskwargs(opts)
1166 revs = None
1169 revs = None
1167 if 'rev' in opts:
1170 if 'rev' in opts:
1168 revstrings = opts['rev']
1171 revstrings = opts['rev']
1169 revs = scmutil.revrange(repo, revstrings)
1172 revs = scmutil.revrange(repo, revstrings)
1170 if revstrings and not revs:
1173 if revstrings and not revs:
1171 raise error.Abort(_('no commits to bundle'))
1174 raise error.Abort(_('no commits to bundle'))
1172
1175
1173 bundletype = opts.get('type', 'bzip2').lower()
1176 bundletype = opts.get('type', 'bzip2').lower()
1174 try:
1177 try:
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1178 bcompression, cgversion, params = exchange.parsebundlespec(
1176 repo, bundletype, strict=False)
1179 repo, bundletype, strict=False)
1177 except error.UnsupportedBundleSpecification as e:
1180 except error.UnsupportedBundleSpecification as e:
1178 raise error.Abort(str(e),
1181 raise error.Abort(str(e),
1179 hint=_("see 'hg help bundlespec' for supported "
1182 hint=_("see 'hg help bundlespec' for supported "
1180 "values for --type"))
1183 "values for --type"))
1181
1184
1182 # Packed bundles are a pseudo bundle format for now.
1185 # Packed bundles are a pseudo bundle format for now.
1183 if cgversion == 's1':
1186 if cgversion == 's1':
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1187 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1188 hint=_("use 'hg debugcreatestreamclonebundle'"))
1186
1189
1187 if opts.get('all'):
1190 if opts.get('all'):
1188 if dest:
1191 if dest:
1189 raise error.Abort(_("--all is incompatible with specifying "
1192 raise error.Abort(_("--all is incompatible with specifying "
1190 "a destination"))
1193 "a destination"))
1191 if opts.get('base'):
1194 if opts.get('base'):
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1195 ui.warn(_("ignoring --base because --all was specified\n"))
1193 base = ['null']
1196 base = ['null']
1194 else:
1197 else:
1195 base = scmutil.revrange(repo, opts.get('base'))
1198 base = scmutil.revrange(repo, opts.get('base'))
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1199 if cgversion not in changegroup.supportedoutgoingversions(repo):
1197 raise error.Abort(_("repository does not support bundle version %s") %
1200 raise error.Abort(_("repository does not support bundle version %s") %
1198 cgversion)
1201 cgversion)
1199
1202
1200 if base:
1203 if base:
1201 if dest:
1204 if dest:
1202 raise error.Abort(_("--base is incompatible with specifying "
1205 raise error.Abort(_("--base is incompatible with specifying "
1203 "a destination"))
1206 "a destination"))
1204 common = [repo.lookup(rev) for rev in base]
1207 common = [repo.lookup(rev) for rev in base]
1205 heads = revs and map(repo.lookup, revs) or None
1208 heads = revs and map(repo.lookup, revs) or None
1206 outgoing = discovery.outgoing(repo, common, heads)
1209 outgoing = discovery.outgoing(repo, common, heads)
1207 else:
1210 else:
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1211 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1212 dest, branches = hg.parseurl(dest, opts.get('branch'))
1210 other = hg.peer(repo, opts, dest)
1213 other = hg.peer(repo, opts, dest)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1214 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1212 heads = revs and map(repo.lookup, revs) or revs
1215 heads = revs and map(repo.lookup, revs) or revs
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1216 outgoing = discovery.findcommonoutgoing(repo, other,
1214 onlyheads=heads,
1217 onlyheads=heads,
1215 force=opts.get('force'),
1218 force=opts.get('force'),
1216 portable=True)
1219 portable=True)
1217
1220
1218 if not outgoing.missing:
1221 if not outgoing.missing:
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1222 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1220 return 1
1223 return 1
1221
1224
1222 if cgversion == '01': #bundle1
1225 if cgversion == '01': #bundle1
1223 if bcompression is None:
1226 if bcompression is None:
1224 bcompression = 'UN'
1227 bcompression = 'UN'
1225 bversion = 'HG10' + bcompression
1228 bversion = 'HG10' + bcompression
1226 bcompression = None
1229 bcompression = None
1227 elif cgversion in ('02', '03'):
1230 elif cgversion in ('02', '03'):
1228 bversion = 'HG20'
1231 bversion = 'HG20'
1229 else:
1232 else:
1230 raise error.ProgrammingError(
1233 raise error.ProgrammingError(
1231 'bundle: unexpected changegroup version %s' % cgversion)
1234 'bundle: unexpected changegroup version %s' % cgversion)
1232
1235
1233 # TODO compression options should be derived from bundlespec parsing.
1236 # TODO compression options should be derived from bundlespec parsing.
1234 # This is a temporary hack to allow adjusting bundle compression
1237 # This is a temporary hack to allow adjusting bundle compression
1235 # level without a) formalizing the bundlespec changes to declare it
1238 # level without a) formalizing the bundlespec changes to declare it
1236 # b) introducing a command flag.
1239 # b) introducing a command flag.
1237 compopts = {}
1240 compopts = {}
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1241 complevel = ui.configint('experimental', 'bundlecomplevel')
1239 if complevel is not None:
1242 if complevel is not None:
1240 compopts['level'] = complevel
1243 compopts['level'] = complevel
1241
1244
1242
1245
1243 contentopts = {'cg.version': cgversion}
1246 contentopts = {'cg.version': cgversion}
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1247 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1245 contentopts['obsolescence'] = True
1248 contentopts['obsolescence'] = True
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1249 if repo.ui.configbool('experimental', 'bundle-phases'):
1247 contentopts['phases'] = True
1250 contentopts['phases'] = True
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1251 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1249 contentopts, compression=bcompression,
1252 contentopts, compression=bcompression,
1250 compopts=compopts)
1253 compopts=compopts)
1251
1254
1252 @command('cat',
1255 @command('cat',
1253 [('o', 'output', '',
1256 [('o', 'output', '',
1254 _('print output to file with formatted name'), _('FORMAT')),
1257 _('print output to file with formatted name'), _('FORMAT')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1258 ('r', 'rev', '', _('print the given revision'), _('REV')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1259 ('', 'decode', None, _('apply any matching decode filter')),
1257 ] + walkopts + formatteropts,
1260 ] + walkopts + formatteropts,
1258 _('[OPTION]... FILE...'),
1261 _('[OPTION]... FILE...'),
1259 inferrepo=True, cmdtype=readonly)
1262 inferrepo=True, cmdtype=readonly)
1260 def cat(ui, repo, file1, *pats, **opts):
1263 def cat(ui, repo, file1, *pats, **opts):
1261 """output the current or given revision of files
1264 """output the current or given revision of files
1262
1265
1263 Print the specified files as they were at the given revision. If
1266 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.
1267 no revision is given, the parent of the working directory is used.
1265
1268
1266 Output may be to a file, in which case the name of the file is
1269 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:
1270 given using a format string. The formatting rules as follows:
1268
1271
1269 :``%%``: literal "%" character
1272 :``%%``: literal "%" character
1270 :``%s``: basename of file being printed
1273 :``%s``: basename of file being printed
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1274 :``%d``: dirname of file being printed, or '.' if in repository root
1272 :``%p``: root-relative path name of file being printed
1275 :``%p``: root-relative path name of file being printed
1273 :``%H``: changeset hash (40 hexadecimal digits)
1276 :``%H``: changeset hash (40 hexadecimal digits)
1274 :``%R``: changeset revision number
1277 :``%R``: changeset revision number
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1278 :``%h``: short-form changeset hash (12 hexadecimal digits)
1276 :``%r``: zero-padded changeset revision number
1279 :``%r``: zero-padded changeset revision number
1277 :``%b``: basename of the exporting repository
1280 :``%b``: basename of the exporting repository
1278
1281
1279 Returns 0 on success.
1282 Returns 0 on success.
1280 """
1283 """
1281 opts = pycompat.byteskwargs(opts)
1284 opts = pycompat.byteskwargs(opts)
1282 rev = opts.get('rev')
1285 rev = opts.get('rev')
1283 if rev:
1286 if rev:
1284 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1287 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1285 ctx = scmutil.revsingle(repo, rev)
1288 ctx = scmutil.revsingle(repo, rev)
1286 m = scmutil.match(ctx, (file1,) + pats, opts)
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1287 fntemplate = opts.pop('output', '')
1290 fntemplate = opts.pop('output', '')
1288 if cmdutil.isstdiofilename(fntemplate):
1291 if cmdutil.isstdiofilename(fntemplate):
1289 fntemplate = ''
1292 fntemplate = ''
1290
1293
1291 if fntemplate:
1294 if fntemplate:
1292 fm = formatter.nullformatter(ui, 'cat')
1295 fm = formatter.nullformatter(ui, 'cat')
1293 else:
1296 else:
1294 ui.pager('cat')
1297 ui.pager('cat')
1295 fm = ui.formatter('cat', opts)
1298 fm = ui.formatter('cat', opts)
1296 with fm:
1299 with fm:
1297 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1300 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1298 **pycompat.strkwargs(opts))
1301 **pycompat.strkwargs(opts))
1299
1302
1300 @command('^clone',
1303 @command('^clone',
1301 [('U', 'noupdate', None, _('the clone will include an empty working '
1304 [('U', 'noupdate', None, _('the clone will include an empty working '
1302 'directory (only a repository)')),
1305 'directory (only a repository)')),
1303 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1306 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1304 _('REV')),
1307 _('REV')),
1305 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1308 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1306 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1309 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1307 ('', 'pull', None, _('use pull protocol to copy metadata')),
1310 ('', 'pull', None, _('use pull protocol to copy metadata')),
1308 ('', 'uncompressed', None,
1311 ('', 'uncompressed', None,
1309 _('an alias to --stream (DEPRECATED)')),
1312 _('an alias to --stream (DEPRECATED)')),
1310 ('', 'stream', None,
1313 ('', 'stream', None,
1311 _('clone with minimal data processing')),
1314 _('clone with minimal data processing')),
1312 ] + remoteopts,
1315 ] + remoteopts,
1313 _('[OPTION]... SOURCE [DEST]'),
1316 _('[OPTION]... SOURCE [DEST]'),
1314 norepo=True)
1317 norepo=True)
1315 def clone(ui, source, dest=None, **opts):
1318 def clone(ui, source, dest=None, **opts):
1316 """make a copy of an existing repository
1319 """make a copy of an existing repository
1317
1320
1318 Create a copy of an existing repository in a new directory.
1321 Create a copy of an existing repository in a new directory.
1319
1322
1320 If no destination directory name is specified, it defaults to the
1323 If no destination directory name is specified, it defaults to the
1321 basename of the source.
1324 basename of the source.
1322
1325
1323 The location of the source is added to the new repository's
1326 The location of the source is added to the new repository's
1324 ``.hg/hgrc`` file, as the default to be used for future pulls.
1327 ``.hg/hgrc`` file, as the default to be used for future pulls.
1325
1328
1326 Only local paths and ``ssh://`` URLs are supported as
1329 Only local paths and ``ssh://`` URLs are supported as
1327 destinations. For ``ssh://`` destinations, no working directory or
1330 destinations. For ``ssh://`` destinations, no working directory or
1328 ``.hg/hgrc`` will be created on the remote side.
1331 ``.hg/hgrc`` will be created on the remote side.
1329
1332
1330 If the source repository has a bookmark called '@' set, that
1333 If the source repository has a bookmark called '@' set, that
1331 revision will be checked out in the new repository by default.
1334 revision will be checked out in the new repository by default.
1332
1335
1333 To check out a particular version, use -u/--update, or
1336 To check out a particular version, use -u/--update, or
1334 -U/--noupdate to create a clone with no working directory.
1337 -U/--noupdate to create a clone with no working directory.
1335
1338
1336 To pull only a subset of changesets, specify one or more revisions
1339 To pull only a subset of changesets, specify one or more revisions
1337 identifiers with -r/--rev or branches with -b/--branch. The
1340 identifiers with -r/--rev or branches with -b/--branch. The
1338 resulting clone will contain only the specified changesets and
1341 resulting clone will contain only the specified changesets and
1339 their ancestors. These options (or 'clone src#rev dest') imply
1342 their ancestors. These options (or 'clone src#rev dest') imply
1340 --pull, even for local source repositories.
1343 --pull, even for local source repositories.
1341
1344
1342 In normal clone mode, the remote normalizes repository data into a common
1345 In normal clone mode, the remote normalizes repository data into a common
1343 exchange format and the receiving end translates this data into its local
1346 exchange format and the receiving end translates this data into its local
1344 storage format. --stream activates a different clone mode that essentially
1347 storage format. --stream activates a different clone mode that essentially
1345 copies repository files from the remote with minimal data processing. This
1348 copies repository files from the remote with minimal data processing. This
1346 significantly reduces the CPU cost of a clone both remotely and locally.
1349 significantly reduces the CPU cost of a clone both remotely and locally.
1347 However, it often increases the transferred data size by 30-40%. This can
1350 However, it often increases the transferred data size by 30-40%. This can
1348 result in substantially faster clones where I/O throughput is plentiful,
1351 result in substantially faster clones where I/O throughput is plentiful,
1349 especially for larger repositories. A side-effect of --stream clones is
1352 especially for larger repositories. A side-effect of --stream clones is
1350 that storage settings and requirements on the remote are applied locally:
1353 that storage settings and requirements on the remote are applied locally:
1351 a modern client may inherit legacy or inefficient storage used by the
1354 a modern client may inherit legacy or inefficient storage used by the
1352 remote or a legacy Mercurial client may not be able to clone from a
1355 remote or a legacy Mercurial client may not be able to clone from a
1353 modern Mercurial remote.
1356 modern Mercurial remote.
1354
1357
1355 .. note::
1358 .. note::
1356
1359
1357 Specifying a tag will include the tagged changeset but not the
1360 Specifying a tag will include the tagged changeset but not the
1358 changeset containing the tag.
1361 changeset containing the tag.
1359
1362
1360 .. container:: verbose
1363 .. container:: verbose
1361
1364
1362 For efficiency, hardlinks are used for cloning whenever the
1365 For efficiency, hardlinks are used for cloning whenever the
1363 source and destination are on the same filesystem (note this
1366 source and destination are on the same filesystem (note this
1364 applies only to the repository data, not to the working
1367 applies only to the repository data, not to the working
1365 directory). Some filesystems, such as AFS, implement hardlinking
1368 directory). Some filesystems, such as AFS, implement hardlinking
1366 incorrectly, but do not report errors. In these cases, use the
1369 incorrectly, but do not report errors. In these cases, use the
1367 --pull option to avoid hardlinking.
1370 --pull option to avoid hardlinking.
1368
1371
1369 Mercurial will update the working directory to the first applicable
1372 Mercurial will update the working directory to the first applicable
1370 revision from this list:
1373 revision from this list:
1371
1374
1372 a) null if -U or the source repository has no changesets
1375 a) null if -U or the source repository has no changesets
1373 b) if -u . and the source repository is local, the first parent of
1376 b) if -u . and the source repository is local, the first parent of
1374 the source repository's working directory
1377 the source repository's working directory
1375 c) the changeset specified with -u (if a branch name, this means the
1378 c) the changeset specified with -u (if a branch name, this means the
1376 latest head of that branch)
1379 latest head of that branch)
1377 d) the changeset specified with -r
1380 d) the changeset specified with -r
1378 e) the tipmost head specified with -b
1381 e) the tipmost head specified with -b
1379 f) the tipmost head specified with the url#branch source syntax
1382 f) the tipmost head specified with the url#branch source syntax
1380 g) the revision marked with the '@' bookmark, if present
1383 g) the revision marked with the '@' bookmark, if present
1381 h) the tipmost head of the default branch
1384 h) the tipmost head of the default branch
1382 i) tip
1385 i) tip
1383
1386
1384 When cloning from servers that support it, Mercurial may fetch
1387 When cloning from servers that support it, Mercurial may fetch
1385 pre-generated data from a server-advertised URL. When this is done,
1388 pre-generated data from a server-advertised URL. When this is done,
1386 hooks operating on incoming changesets and changegroups may fire twice,
1389 hooks operating on incoming changesets and changegroups may fire twice,
1387 once for the bundle fetched from the URL and another for any additional
1390 once for the bundle fetched from the URL and another for any additional
1388 data not fetched from this URL. In addition, if an error occurs, the
1391 data not fetched from this URL. In addition, if an error occurs, the
1389 repository may be rolled back to a partial clone. This behavior may
1392 repository may be rolled back to a partial clone. This behavior may
1390 change in future releases. See :hg:`help -e clonebundles` for more.
1393 change in future releases. See :hg:`help -e clonebundles` for more.
1391
1394
1392 Examples:
1395 Examples:
1393
1396
1394 - clone a remote repository to a new directory named hg/::
1397 - clone a remote repository to a new directory named hg/::
1395
1398
1396 hg clone https://www.mercurial-scm.org/repo/hg/
1399 hg clone https://www.mercurial-scm.org/repo/hg/
1397
1400
1398 - create a lightweight local clone::
1401 - create a lightweight local clone::
1399
1402
1400 hg clone project/ project-feature/
1403 hg clone project/ project-feature/
1401
1404
1402 - clone from an absolute path on an ssh server (note double-slash)::
1405 - clone from an absolute path on an ssh server (note double-slash)::
1403
1406
1404 hg clone ssh://user@server//home/projects/alpha/
1407 hg clone ssh://user@server//home/projects/alpha/
1405
1408
1406 - do a streaming clone while checking out a specified version::
1409 - do a streaming clone while checking out a specified version::
1407
1410
1408 hg clone --stream http://server/repo -u 1.5
1411 hg clone --stream http://server/repo -u 1.5
1409
1412
1410 - create a repository without changesets after a particular revision::
1413 - create a repository without changesets after a particular revision::
1411
1414
1412 hg clone -r 04e544 experimental/ good/
1415 hg clone -r 04e544 experimental/ good/
1413
1416
1414 - clone (and track) a particular named branch::
1417 - clone (and track) a particular named branch::
1415
1418
1416 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1419 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1417
1420
1418 See :hg:`help urls` for details on specifying URLs.
1421 See :hg:`help urls` for details on specifying URLs.
1419
1422
1420 Returns 0 on success.
1423 Returns 0 on success.
1421 """
1424 """
1422 opts = pycompat.byteskwargs(opts)
1425 opts = pycompat.byteskwargs(opts)
1423 if opts.get('noupdate') and opts.get('updaterev'):
1426 if opts.get('noupdate') and opts.get('updaterev'):
1424 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1427 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1425
1428
1426 r = hg.clone(ui, opts, source, dest,
1429 r = hg.clone(ui, opts, source, dest,
1427 pull=opts.get('pull'),
1430 pull=opts.get('pull'),
1428 stream=opts.get('stream') or opts.get('uncompressed'),
1431 stream=opts.get('stream') or opts.get('uncompressed'),
1429 rev=opts.get('rev'),
1432 rev=opts.get('rev'),
1430 update=opts.get('updaterev') or not opts.get('noupdate'),
1433 update=opts.get('updaterev') or not opts.get('noupdate'),
1431 branch=opts.get('branch'),
1434 branch=opts.get('branch'),
1432 shareopts=opts.get('shareopts'))
1435 shareopts=opts.get('shareopts'))
1433
1436
1434 return r is None
1437 return r is None
1435
1438
1436 @command('^commit|ci',
1439 @command('^commit|ci',
1437 [('A', 'addremove', None,
1440 [('A', 'addremove', None,
1438 _('mark new/missing files as added/removed before committing')),
1441 _('mark new/missing files as added/removed before committing')),
1439 ('', 'close-branch', None,
1442 ('', 'close-branch', None,
1440 _('mark a branch head as closed')),
1443 _('mark a branch head as closed')),
1441 ('', 'amend', None, _('amend the parent of the working directory')),
1444 ('', 'amend', None, _('amend the parent of the working directory')),
1442 ('s', 'secret', None, _('use the secret phase for committing')),
1445 ('s', 'secret', None, _('use the secret phase for committing')),
1443 ('e', 'edit', None, _('invoke editor on commit messages')),
1446 ('e', 'edit', None, _('invoke editor on commit messages')),
1444 ('i', 'interactive', None, _('use interactive mode')),
1447 ('i', 'interactive', None, _('use interactive mode')),
1445 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1448 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1446 _('[OPTION]... [FILE]...'),
1449 _('[OPTION]... [FILE]...'),
1447 inferrepo=True)
1450 inferrepo=True)
1448 def commit(ui, repo, *pats, **opts):
1451 def commit(ui, repo, *pats, **opts):
1449 """commit the specified files or all outstanding changes
1452 """commit the specified files or all outstanding changes
1450
1453
1451 Commit changes to the given files into the repository. Unlike a
1454 Commit changes to the given files into the repository. Unlike a
1452 centralized SCM, this operation is a local operation. See
1455 centralized SCM, this operation is a local operation. See
1453 :hg:`push` for a way to actively distribute your changes.
1456 :hg:`push` for a way to actively distribute your changes.
1454
1457
1455 If a list of files is omitted, all changes reported by :hg:`status`
1458 If a list of files is omitted, all changes reported by :hg:`status`
1456 will be committed.
1459 will be committed.
1457
1460
1458 If you are committing the result of a merge, do not provide any
1461 If you are committing the result of a merge, do not provide any
1459 filenames or -I/-X filters.
1462 filenames or -I/-X filters.
1460
1463
1461 If no commit message is specified, Mercurial starts your
1464 If no commit message is specified, Mercurial starts your
1462 configured editor where you can enter a message. In case your
1465 configured editor where you can enter a message. In case your
1463 commit fails, you will find a backup of your message in
1466 commit fails, you will find a backup of your message in
1464 ``.hg/last-message.txt``.
1467 ``.hg/last-message.txt``.
1465
1468
1466 The --close-branch flag can be used to mark the current branch
1469 The --close-branch flag can be used to mark the current branch
1467 head closed. When all heads of a branch are closed, the branch
1470 head closed. When all heads of a branch are closed, the branch
1468 will be considered closed and no longer listed.
1471 will be considered closed and no longer listed.
1469
1472
1470 The --amend flag can be used to amend the parent of the
1473 The --amend flag can be used to amend the parent of the
1471 working directory with a new commit that contains the changes
1474 working directory with a new commit that contains the changes
1472 in the parent in addition to those currently reported by :hg:`status`,
1475 in the parent in addition to those currently reported by :hg:`status`,
1473 if there are any. The old commit is stored in a backup bundle in
1476 if there are any. The old commit is stored in a backup bundle in
1474 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1477 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1475 on how to restore it).
1478 on how to restore it).
1476
1479
1477 Message, user and date are taken from the amended commit unless
1480 Message, user and date are taken from the amended commit unless
1478 specified. When a message isn't specified on the command line,
1481 specified. When a message isn't specified on the command line,
1479 the editor will open with the message of the amended commit.
1482 the editor will open with the message of the amended commit.
1480
1483
1481 It is not possible to amend public changesets (see :hg:`help phases`)
1484 It is not possible to amend public changesets (see :hg:`help phases`)
1482 or changesets that have children.
1485 or changesets that have children.
1483
1486
1484 See :hg:`help dates` for a list of formats valid for -d/--date.
1487 See :hg:`help dates` for a list of formats valid for -d/--date.
1485
1488
1486 Returns 0 on success, 1 if nothing changed.
1489 Returns 0 on success, 1 if nothing changed.
1487
1490
1488 .. container:: verbose
1491 .. container:: verbose
1489
1492
1490 Examples:
1493 Examples:
1491
1494
1492 - commit all files ending in .py::
1495 - commit all files ending in .py::
1493
1496
1494 hg commit --include "set:**.py"
1497 hg commit --include "set:**.py"
1495
1498
1496 - commit all non-binary files::
1499 - commit all non-binary files::
1497
1500
1498 hg commit --exclude "set:binary()"
1501 hg commit --exclude "set:binary()"
1499
1502
1500 - amend the current commit and set the date to now::
1503 - amend the current commit and set the date to now::
1501
1504
1502 hg commit --amend --date now
1505 hg commit --amend --date now
1503 """
1506 """
1504 wlock = lock = None
1507 wlock = lock = None
1505 try:
1508 try:
1506 wlock = repo.wlock()
1509 wlock = repo.wlock()
1507 lock = repo.lock()
1510 lock = repo.lock()
1508 return _docommit(ui, repo, *pats, **opts)
1511 return _docommit(ui, repo, *pats, **opts)
1509 finally:
1512 finally:
1510 release(lock, wlock)
1513 release(lock, wlock)
1511
1514
1512 def _docommit(ui, repo, *pats, **opts):
1515 def _docommit(ui, repo, *pats, **opts):
1513 if opts.get(r'interactive'):
1516 if opts.get(r'interactive'):
1514 opts.pop(r'interactive')
1517 opts.pop(r'interactive')
1515 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1518 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1516 cmdutil.recordfilter, *pats,
1519 cmdutil.recordfilter, *pats,
1517 **opts)
1520 **opts)
1518 # ret can be 0 (no changes to record) or the value returned by
1521 # ret can be 0 (no changes to record) or the value returned by
1519 # commit(), 1 if nothing changed or None on success.
1522 # commit(), 1 if nothing changed or None on success.
1520 return 1 if ret == 0 else ret
1523 return 1 if ret == 0 else ret
1521
1524
1522 opts = pycompat.byteskwargs(opts)
1525 opts = pycompat.byteskwargs(opts)
1523 if opts.get('subrepos'):
1526 if opts.get('subrepos'):
1524 if opts.get('amend'):
1527 if opts.get('amend'):
1525 raise error.Abort(_('cannot amend with --subrepos'))
1528 raise error.Abort(_('cannot amend with --subrepos'))
1526 # Let --subrepos on the command line override config setting.
1529 # Let --subrepos on the command line override config setting.
1527 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1530 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1528
1531
1529 cmdutil.checkunfinished(repo, commit=True)
1532 cmdutil.checkunfinished(repo, commit=True)
1530
1533
1531 branch = repo[None].branch()
1534 branch = repo[None].branch()
1532 bheads = repo.branchheads(branch)
1535 bheads = repo.branchheads(branch)
1533
1536
1534 extra = {}
1537 extra = {}
1535 if opts.get('close_branch'):
1538 if opts.get('close_branch'):
1536 extra['close'] = 1
1539 extra['close'] = 1
1537
1540
1538 if not bheads:
1541 if not bheads:
1539 raise error.Abort(_('can only close branch heads'))
1542 raise error.Abort(_('can only close branch heads'))
1540 elif opts.get('amend'):
1543 elif opts.get('amend'):
1541 if repo[None].parents()[0].p1().branch() != branch and \
1544 if repo[None].parents()[0].p1().branch() != branch and \
1542 repo[None].parents()[0].p2().branch() != branch:
1545 repo[None].parents()[0].p2().branch() != branch:
1543 raise error.Abort(_('can only close branch heads'))
1546 raise error.Abort(_('can only close branch heads'))
1544
1547
1545 if opts.get('amend'):
1548 if opts.get('amend'):
1546 if ui.configbool('ui', 'commitsubrepos'):
1549 if ui.configbool('ui', 'commitsubrepos'):
1547 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1550 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1548
1551
1549 old = repo['.']
1552 old = repo['.']
1550 rewriteutil.precheck(repo, [old.rev()], 'amend')
1553 rewriteutil.precheck(repo, [old.rev()], 'amend')
1551
1554
1552 # Currently histedit gets confused if an amend happens while histedit
1555 # Currently histedit gets confused if an amend happens while histedit
1553 # is in progress. Since we have a checkunfinished command, we are
1556 # is in progress. Since we have a checkunfinished command, we are
1554 # temporarily honoring it.
1557 # temporarily honoring it.
1555 #
1558 #
1556 # Note: eventually this guard will be removed. Please do not expect
1559 # Note: eventually this guard will be removed. Please do not expect
1557 # this behavior to remain.
1560 # this behavior to remain.
1558 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1561 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1559 cmdutil.checkunfinished(repo)
1562 cmdutil.checkunfinished(repo)
1560
1563
1561 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1564 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1562 if node == old.node():
1565 if node == old.node():
1563 ui.status(_("nothing changed\n"))
1566 ui.status(_("nothing changed\n"))
1564 return 1
1567 return 1
1565 else:
1568 else:
1566 def commitfunc(ui, repo, message, match, opts):
1569 def commitfunc(ui, repo, message, match, opts):
1567 overrides = {}
1570 overrides = {}
1568 if opts.get('secret'):
1571 if opts.get('secret'):
1569 overrides[('phases', 'new-commit')] = 'secret'
1572 overrides[('phases', 'new-commit')] = 'secret'
1570
1573
1571 baseui = repo.baseui
1574 baseui = repo.baseui
1572 with baseui.configoverride(overrides, 'commit'):
1575 with baseui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1576 with ui.configoverride(overrides, 'commit'):
1574 editform = cmdutil.mergeeditform(repo[None],
1577 editform = cmdutil.mergeeditform(repo[None],
1575 'commit.normal')
1578 'commit.normal')
1576 editor = cmdutil.getcommiteditor(
1579 editor = cmdutil.getcommiteditor(
1577 editform=editform, **pycompat.strkwargs(opts))
1580 editform=editform, **pycompat.strkwargs(opts))
1578 return repo.commit(message,
1581 return repo.commit(message,
1579 opts.get('user'),
1582 opts.get('user'),
1580 opts.get('date'),
1583 opts.get('date'),
1581 match,
1584 match,
1582 editor=editor,
1585 editor=editor,
1583 extra=extra)
1586 extra=extra)
1584
1587
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1588 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1586
1589
1587 if not node:
1590 if not node:
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1591 stat = cmdutil.postcommitstatus(repo, pats, opts)
1589 if stat[3]:
1592 if stat[3]:
1590 ui.status(_("nothing changed (%d missing files, see "
1593 ui.status(_("nothing changed (%d missing files, see "
1591 "'hg status')\n") % len(stat[3]))
1594 "'hg status')\n") % len(stat[3]))
1592 else:
1595 else:
1593 ui.status(_("nothing changed\n"))
1596 ui.status(_("nothing changed\n"))
1594 return 1
1597 return 1
1595
1598
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1599 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1597
1600
1598 @command('config|showconfig|debugconfig',
1601 @command('config|showconfig|debugconfig',
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1602 [('u', 'untrusted', None, _('show untrusted configuration options')),
1600 ('e', 'edit', None, _('edit user config')),
1603 ('e', 'edit', None, _('edit user config')),
1601 ('l', 'local', None, _('edit repository config')),
1604 ('l', 'local', None, _('edit repository config')),
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1605 ('g', 'global', None, _('edit global config'))] + formatteropts,
1603 _('[-u] [NAME]...'),
1606 _('[-u] [NAME]...'),
1604 optionalrepo=True, cmdtype=readonly)
1607 optionalrepo=True, cmdtype=readonly)
1605 def config(ui, repo, *values, **opts):
1608 def config(ui, repo, *values, **opts):
1606 """show combined config settings from all hgrc files
1609 """show combined config settings from all hgrc files
1607
1610
1608 With no arguments, print names and values of all config items.
1611 With no arguments, print names and values of all config items.
1609
1612
1610 With one argument of the form section.name, print just the value
1613 With one argument of the form section.name, print just the value
1611 of that config item.
1614 of that config item.
1612
1615
1613 With multiple arguments, print names and values of all config
1616 With multiple arguments, print names and values of all config
1614 items with matching section names.
1617 items with matching section names.
1615
1618
1616 With --edit, start an editor on the user-level config file. With
1619 With --edit, start an editor on the user-level config file. With
1617 --global, edit the system-wide config file. With --local, edit the
1620 --global, edit the system-wide config file. With --local, edit the
1618 repository-level config file.
1621 repository-level config file.
1619
1622
1620 With --debug, the source (filename and line number) is printed
1623 With --debug, the source (filename and line number) is printed
1621 for each config item.
1624 for each config item.
1622
1625
1623 See :hg:`help config` for more information about config files.
1626 See :hg:`help config` for more information about config files.
1624
1627
1625 Returns 0 on success, 1 if NAME does not exist.
1628 Returns 0 on success, 1 if NAME does not exist.
1626
1629
1627 """
1630 """
1628
1631
1629 opts = pycompat.byteskwargs(opts)
1632 opts = pycompat.byteskwargs(opts)
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1633 if opts.get('edit') or opts.get('local') or opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1634 if opts.get('local') and opts.get('global'):
1632 raise error.Abort(_("can't use --local and --global together"))
1635 raise error.Abort(_("can't use --local and --global together"))
1633
1636
1634 if opts.get('local'):
1637 if opts.get('local'):
1635 if not repo:
1638 if not repo:
1636 raise error.Abort(_("can't use --local outside a repository"))
1639 raise error.Abort(_("can't use --local outside a repository"))
1637 paths = [repo.vfs.join('hgrc')]
1640 paths = [repo.vfs.join('hgrc')]
1638 elif opts.get('global'):
1641 elif opts.get('global'):
1639 paths = rcutil.systemrcpath()
1642 paths = rcutil.systemrcpath()
1640 else:
1643 else:
1641 paths = rcutil.userrcpath()
1644 paths = rcutil.userrcpath()
1642
1645
1643 for f in paths:
1646 for f in paths:
1644 if os.path.exists(f):
1647 if os.path.exists(f):
1645 break
1648 break
1646 else:
1649 else:
1647 if opts.get('global'):
1650 if opts.get('global'):
1648 samplehgrc = uimod.samplehgrcs['global']
1651 samplehgrc = uimod.samplehgrcs['global']
1649 elif opts.get('local'):
1652 elif opts.get('local'):
1650 samplehgrc = uimod.samplehgrcs['local']
1653 samplehgrc = uimod.samplehgrcs['local']
1651 else:
1654 else:
1652 samplehgrc = uimod.samplehgrcs['user']
1655 samplehgrc = uimod.samplehgrcs['user']
1653
1656
1654 f = paths[0]
1657 f = paths[0]
1655 fp = open(f, "wb")
1658 fp = open(f, "wb")
1656 fp.write(util.tonativeeol(samplehgrc))
1659 fp.write(util.tonativeeol(samplehgrc))
1657 fp.close()
1660 fp.close()
1658
1661
1659 editor = ui.geteditor()
1662 editor = ui.geteditor()
1660 ui.system("%s \"%s\"" % (editor, f),
1663 ui.system("%s \"%s\"" % (editor, f),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1664 onerr=error.Abort, errprefix=_("edit failed"),
1662 blockedtag='config_edit')
1665 blockedtag='config_edit')
1663 return
1666 return
1664 ui.pager('config')
1667 ui.pager('config')
1665 fm = ui.formatter('config', opts)
1668 fm = ui.formatter('config', opts)
1666 for t, f in rcutil.rccomponents():
1669 for t, f in rcutil.rccomponents():
1667 if t == 'path':
1670 if t == 'path':
1668 ui.debug('read config from: %s\n' % f)
1671 ui.debug('read config from: %s\n' % f)
1669 elif t == 'items':
1672 elif t == 'items':
1670 for section, name, value, source in f:
1673 for section, name, value, source in f:
1671 ui.debug('set config by: %s\n' % source)
1674 ui.debug('set config by: %s\n' % source)
1672 else:
1675 else:
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1676 raise error.ProgrammingError('unknown rctype: %s' % t)
1674 untrusted = bool(opts.get('untrusted'))
1677 untrusted = bool(opts.get('untrusted'))
1675 if values:
1678 if values:
1676 sections = [v for v in values if '.' not in v]
1679 sections = [v for v in values if '.' not in v]
1677 items = [v for v in values if '.' in v]
1680 items = [v for v in values if '.' in v]
1678 if len(items) > 1 or items and sections:
1681 if len(items) > 1 or items and sections:
1679 raise error.Abort(_('only one config item permitted'))
1682 raise error.Abort(_('only one config item permitted'))
1680 matched = False
1683 matched = False
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1684 for section, name, value in ui.walkconfig(untrusted=untrusted):
1682 source = ui.configsource(section, name, untrusted)
1685 source = ui.configsource(section, name, untrusted)
1683 value = pycompat.bytestr(value)
1686 value = pycompat.bytestr(value)
1684 if fm.isplain():
1687 if fm.isplain():
1685 source = source or 'none'
1688 source = source or 'none'
1686 value = value.replace('\n', '\\n')
1689 value = value.replace('\n', '\\n')
1687 entryname = section + '.' + name
1690 entryname = section + '.' + name
1688 if values:
1691 if values:
1689 for v in values:
1692 for v in values:
1690 if v == section:
1693 if v == section:
1691 fm.startitem()
1694 fm.startitem()
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1695 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1696 fm.write('name value', '%s=%s\n', entryname, value)
1694 matched = True
1697 matched = True
1695 elif v == entryname:
1698 elif v == entryname:
1696 fm.startitem()
1699 fm.startitem()
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1700 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1698 fm.write('value', '%s\n', value)
1701 fm.write('value', '%s\n', value)
1699 fm.data(name=entryname)
1702 fm.data(name=entryname)
1700 matched = True
1703 matched = True
1701 else:
1704 else:
1702 fm.startitem()
1705 fm.startitem()
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1706 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1707 fm.write('name value', '%s=%s\n', entryname, value)
1705 matched = True
1708 matched = True
1706 fm.end()
1709 fm.end()
1707 if matched:
1710 if matched:
1708 return 0
1711 return 0
1709 return 1
1712 return 1
1710
1713
1711 @command('copy|cp',
1714 @command('copy|cp',
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1715 [('A', 'after', None, _('record a copy that has already occurred')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1716 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1714 ] + walkopts + dryrunopts,
1717 ] + walkopts + dryrunopts,
1715 _('[OPTION]... [SOURCE]... DEST'))
1718 _('[OPTION]... [SOURCE]... DEST'))
1716 def copy(ui, repo, *pats, **opts):
1719 def copy(ui, repo, *pats, **opts):
1717 """mark files as copied for the next commit
1720 """mark files as copied for the next commit
1718
1721
1719 Mark dest as having copies of source files. If dest is a
1722 Mark dest as having copies of source files. If dest is a
1720 directory, copies are put in that directory. If dest is a file,
1723 directory, copies are put in that directory. If dest is a file,
1721 the source must be a single file.
1724 the source must be a single file.
1722
1725
1723 By default, this command copies the contents of files as they
1726 By default, this command copies the contents of files as they
1724 exist in the working directory. If invoked with -A/--after, the
1727 exist in the working directory. If invoked with -A/--after, the
1725 operation is recorded, but no copying is performed.
1728 operation is recorded, but no copying is performed.
1726
1729
1727 This command takes effect with the next commit. To undo a copy
1730 This command takes effect with the next commit. To undo a copy
1728 before that, see :hg:`revert`.
1731 before that, see :hg:`revert`.
1729
1732
1730 Returns 0 on success, 1 if errors are encountered.
1733 Returns 0 on success, 1 if errors are encountered.
1731 """
1734 """
1732 opts = pycompat.byteskwargs(opts)
1735 opts = pycompat.byteskwargs(opts)
1733 with repo.wlock(False):
1736 with repo.wlock(False):
1734 return cmdutil.copy(ui, repo, pats, opts)
1737 return cmdutil.copy(ui, repo, pats, opts)
1735
1738
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1739 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1737 def debugcommands(ui, cmd='', *args):
1740 def debugcommands(ui, cmd='', *args):
1738 """list all available commands and options"""
1741 """list all available commands and options"""
1739 for cmd, vals in sorted(table.iteritems()):
1742 for cmd, vals in sorted(table.iteritems()):
1740 cmd = cmd.split('|')[0].strip('^')
1743 cmd = cmd.split('|')[0].strip('^')
1741 opts = ', '.join([i[1] for i in vals[1]])
1744 opts = ', '.join([i[1] for i in vals[1]])
1742 ui.write('%s: %s\n' % (cmd, opts))
1745 ui.write('%s: %s\n' % (cmd, opts))
1743
1746
1744 @command('debugcomplete',
1747 @command('debugcomplete',
1745 [('o', 'options', None, _('show the command options'))],
1748 [('o', 'options', None, _('show the command options'))],
1746 _('[-o] CMD'),
1749 _('[-o] CMD'),
1747 norepo=True)
1750 norepo=True)
1748 def debugcomplete(ui, cmd='', **opts):
1751 def debugcomplete(ui, cmd='', **opts):
1749 """returns the completion list associated with the given command"""
1752 """returns the completion list associated with the given command"""
1750
1753
1751 if opts.get(r'options'):
1754 if opts.get(r'options'):
1752 options = []
1755 options = []
1753 otables = [globalopts]
1756 otables = [globalopts]
1754 if cmd:
1757 if cmd:
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1758 aliases, entry = cmdutil.findcmd(cmd, table, False)
1756 otables.append(entry[1])
1759 otables.append(entry[1])
1757 for t in otables:
1760 for t in otables:
1758 for o in t:
1761 for o in t:
1759 if "(DEPRECATED)" in o[3]:
1762 if "(DEPRECATED)" in o[3]:
1760 continue
1763 continue
1761 if o[0]:
1764 if o[0]:
1762 options.append('-%s' % o[0])
1765 options.append('-%s' % o[0])
1763 options.append('--%s' % o[1])
1766 options.append('--%s' % o[1])
1764 ui.write("%s\n" % "\n".join(options))
1767 ui.write("%s\n" % "\n".join(options))
1765 return
1768 return
1766
1769
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1770 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1768 if ui.verbose:
1771 if ui.verbose:
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1772 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1773 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1771
1774
1772 @command('^diff',
1775 @command('^diff',
1773 [('r', 'rev', [], _('revision'), _('REV')),
1776 [('r', 'rev', [], _('revision'), _('REV')),
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1777 ('c', 'change', '', _('change made by revision'), _('REV'))
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1778 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1779 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1777 inferrepo=True, cmdtype=readonly)
1780 inferrepo=True, cmdtype=readonly)
1778 def diff(ui, repo, *pats, **opts):
1781 def diff(ui, repo, *pats, **opts):
1779 """diff repository (or selected files)
1782 """diff repository (or selected files)
1780
1783
1781 Show differences between revisions for the specified files.
1784 Show differences between revisions for the specified files.
1782
1785
1783 Differences between files are shown using the unified diff format.
1786 Differences between files are shown using the unified diff format.
1784
1787
1785 .. note::
1788 .. note::
1786
1789
1787 :hg:`diff` may generate unexpected results for merges, as it will
1790 :hg:`diff` may generate unexpected results for merges, as it will
1788 default to comparing against the working directory's first
1791 default to comparing against the working directory's first
1789 parent changeset if no revisions are specified.
1792 parent changeset if no revisions are specified.
1790
1793
1791 When two revision arguments are given, then changes are shown
1794 When two revision arguments are given, then changes are shown
1792 between those revisions. If only one revision is specified then
1795 between those revisions. If only one revision is specified then
1793 that revision is compared to the working directory, and, when no
1796 that revision is compared to the working directory, and, when no
1794 revisions are specified, the working directory files are compared
1797 revisions are specified, the working directory files are compared
1795 to its first parent.
1798 to its first parent.
1796
1799
1797 Alternatively you can specify -c/--change with a revision to see
1800 Alternatively you can specify -c/--change with a revision to see
1798 the changes in that changeset relative to its first parent.
1801 the changes in that changeset relative to its first parent.
1799
1802
1800 Without the -a/--text option, diff will avoid generating diffs of
1803 Without the -a/--text option, diff will avoid generating diffs of
1801 files it detects as binary. With -a, diff will generate a diff
1804 files it detects as binary. With -a, diff will generate a diff
1802 anyway, probably with undesirable results.
1805 anyway, probably with undesirable results.
1803
1806
1804 Use the -g/--git option to generate diffs in the git extended diff
1807 Use the -g/--git option to generate diffs in the git extended diff
1805 format. For more information, read :hg:`help diffs`.
1808 format. For more information, read :hg:`help diffs`.
1806
1809
1807 .. container:: verbose
1810 .. container:: verbose
1808
1811
1809 Examples:
1812 Examples:
1810
1813
1811 - compare a file in the current working directory to its parent::
1814 - compare a file in the current working directory to its parent::
1812
1815
1813 hg diff foo.c
1816 hg diff foo.c
1814
1817
1815 - compare two historical versions of a directory, with rename info::
1818 - compare two historical versions of a directory, with rename info::
1816
1819
1817 hg diff --git -r 1.0:1.2 lib/
1820 hg diff --git -r 1.0:1.2 lib/
1818
1821
1819 - get change stats relative to the last change on some date::
1822 - get change stats relative to the last change on some date::
1820
1823
1821 hg diff --stat -r "date('may 2')"
1824 hg diff --stat -r "date('may 2')"
1822
1825
1823 - diff all newly-added files that contain a keyword::
1826 - diff all newly-added files that contain a keyword::
1824
1827
1825 hg diff "set:added() and grep(GNU)"
1828 hg diff "set:added() and grep(GNU)"
1826
1829
1827 - compare a revision and its parents::
1830 - compare a revision and its parents::
1828
1831
1829 hg diff -c 9353 # compare against first parent
1832 hg diff -c 9353 # compare against first parent
1830 hg diff -r 9353^:9353 # same using revset syntax
1833 hg diff -r 9353^:9353 # same using revset syntax
1831 hg diff -r 9353^2:9353 # compare against the second parent
1834 hg diff -r 9353^2:9353 # compare against the second parent
1832
1835
1833 Returns 0 on success.
1836 Returns 0 on success.
1834 """
1837 """
1835
1838
1836 opts = pycompat.byteskwargs(opts)
1839 opts = pycompat.byteskwargs(opts)
1837 revs = opts.get('rev')
1840 revs = opts.get('rev')
1838 change = opts.get('change')
1841 change = opts.get('change')
1839 stat = opts.get('stat')
1842 stat = opts.get('stat')
1840 reverse = opts.get('reverse')
1843 reverse = opts.get('reverse')
1841
1844
1842 if revs and change:
1845 if revs and change:
1843 msg = _('cannot specify --rev and --change at the same time')
1846 msg = _('cannot specify --rev and --change at the same time')
1844 raise error.Abort(msg)
1847 raise error.Abort(msg)
1845 elif change:
1848 elif change:
1846 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1849 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1847 node2 = scmutil.revsingle(repo, change, None).node()
1850 node2 = scmutil.revsingle(repo, change, None).node()
1848 node1 = repo[node2].p1().node()
1851 node1 = repo[node2].p1().node()
1849 else:
1852 else:
1850 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1853 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1851 node1, node2 = scmutil.revpair(repo, revs)
1854 node1, node2 = scmutil.revpair(repo, revs)
1852
1855
1853 if reverse:
1856 if reverse:
1854 node1, node2 = node2, node1
1857 node1, node2 = node2, node1
1855
1858
1856 diffopts = patch.diffallopts(ui, opts)
1859 diffopts = patch.diffallopts(ui, opts)
1857 m = scmutil.match(repo[node2], pats, opts)
1860 m = scmutil.match(repo[node2], pats, opts)
1858 ui.pager('diff')
1861 ui.pager('diff')
1859 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1862 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1860 listsubrepos=opts.get('subrepos'),
1863 listsubrepos=opts.get('subrepos'),
1861 root=opts.get('root'))
1864 root=opts.get('root'))
1862
1865
1863 @command('^export',
1866 @command('^export',
1864 [('o', 'output', '',
1867 [('o', 'output', '',
1865 _('print output to file with formatted name'), _('FORMAT')),
1868 _('print output to file with formatted name'), _('FORMAT')),
1866 ('', 'switch-parent', None, _('diff against the second parent')),
1869 ('', 'switch-parent', None, _('diff against the second parent')),
1867 ('r', 'rev', [], _('revisions to export'), _('REV')),
1870 ('r', 'rev', [], _('revisions to export'), _('REV')),
1868 ] + diffopts,
1871 ] + diffopts,
1869 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1872 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1870 def export(ui, repo, *changesets, **opts):
1873 def export(ui, repo, *changesets, **opts):
1871 """dump the header and diffs for one or more changesets
1874 """dump the header and diffs for one or more changesets
1872
1875
1873 Print the changeset header and diffs for one or more revisions.
1876 Print the changeset header and diffs for one or more revisions.
1874 If no revision is given, the parent of the working directory is used.
1877 If no revision is given, the parent of the working directory is used.
1875
1878
1876 The information shown in the changeset header is: author, date,
1879 The information shown in the changeset header is: author, date,
1877 branch name (if non-default), changeset hash, parent(s) and commit
1880 branch name (if non-default), changeset hash, parent(s) and commit
1878 comment.
1881 comment.
1879
1882
1880 .. note::
1883 .. note::
1881
1884
1882 :hg:`export` may generate unexpected diff output for merge
1885 :hg:`export` may generate unexpected diff output for merge
1883 changesets, as it will compare the merge changeset against its
1886 changesets, as it will compare the merge changeset against its
1884 first parent only.
1887 first parent only.
1885
1888
1886 Output may be to a file, in which case the name of the file is
1889 Output may be to a file, in which case the name of the file is
1887 given using a format string. The formatting rules are as follows:
1890 given using a format string. The formatting rules are as follows:
1888
1891
1889 :``%%``: literal "%" character
1892 :``%%``: literal "%" character
1890 :``%H``: changeset hash (40 hexadecimal digits)
1893 :``%H``: changeset hash (40 hexadecimal digits)
1891 :``%N``: number of patches being generated
1894 :``%N``: number of patches being generated
1892 :``%R``: changeset revision number
1895 :``%R``: changeset revision number
1893 :``%b``: basename of the exporting repository
1896 :``%b``: basename of the exporting repository
1894 :``%h``: short-form changeset hash (12 hexadecimal digits)
1897 :``%h``: short-form changeset hash (12 hexadecimal digits)
1895 :``%m``: first line of the commit message (only alphanumeric characters)
1898 :``%m``: first line of the commit message (only alphanumeric characters)
1896 :``%n``: zero-padded sequence number, starting at 1
1899 :``%n``: zero-padded sequence number, starting at 1
1897 :``%r``: zero-padded changeset revision number
1900 :``%r``: zero-padded changeset revision number
1898
1901
1899 Without the -a/--text option, export will avoid generating diffs
1902 Without the -a/--text option, export will avoid generating diffs
1900 of files it detects as binary. With -a, export will generate a
1903 of files it detects as binary. With -a, export will generate a
1901 diff anyway, probably with undesirable results.
1904 diff anyway, probably with undesirable results.
1902
1905
1903 Use the -g/--git option to generate diffs in the git extended diff
1906 Use the -g/--git option to generate diffs in the git extended diff
1904 format. See :hg:`help diffs` for more information.
1907 format. See :hg:`help diffs` for more information.
1905
1908
1906 With the --switch-parent option, the diff will be against the
1909 With the --switch-parent option, the diff will be against the
1907 second parent. It can be useful to review a merge.
1910 second parent. It can be useful to review a merge.
1908
1911
1909 .. container:: verbose
1912 .. container:: verbose
1910
1913
1911 Examples:
1914 Examples:
1912
1915
1913 - use export and import to transplant a bugfix to the current
1916 - use export and import to transplant a bugfix to the current
1914 branch::
1917 branch::
1915
1918
1916 hg export -r 9353 | hg import -
1919 hg export -r 9353 | hg import -
1917
1920
1918 - export all the changesets between two revisions to a file with
1921 - export all the changesets between two revisions to a file with
1919 rename information::
1922 rename information::
1920
1923
1921 hg export --git -r 123:150 > changes.txt
1924 hg export --git -r 123:150 > changes.txt
1922
1925
1923 - split outgoing changes into a series of patches with
1926 - split outgoing changes into a series of patches with
1924 descriptive names::
1927 descriptive names::
1925
1928
1926 hg export -r "outgoing()" -o "%n-%m.patch"
1929 hg export -r "outgoing()" -o "%n-%m.patch"
1927
1930
1928 Returns 0 on success.
1931 Returns 0 on success.
1929 """
1932 """
1930 opts = pycompat.byteskwargs(opts)
1933 opts = pycompat.byteskwargs(opts)
1931 changesets += tuple(opts.get('rev', []))
1934 changesets += tuple(opts.get('rev', []))
1932 if not changesets:
1935 if not changesets:
1933 changesets = ['.']
1936 changesets = ['.']
1934 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1937 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
1935 revs = scmutil.revrange(repo, changesets)
1938 revs = scmutil.revrange(repo, changesets)
1936 if not revs:
1939 if not revs:
1937 raise error.Abort(_("export requires at least one changeset"))
1940 raise error.Abort(_("export requires at least one changeset"))
1938 if len(revs) > 1:
1941 if len(revs) > 1:
1939 ui.note(_('exporting patches:\n'))
1942 ui.note(_('exporting patches:\n'))
1940 else:
1943 else:
1941 ui.note(_('exporting patch:\n'))
1944 ui.note(_('exporting patch:\n'))
1942 ui.pager('export')
1945 ui.pager('export')
1943 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1946 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1944 switch_parent=opts.get('switch_parent'),
1947 switch_parent=opts.get('switch_parent'),
1945 opts=patch.diffallopts(ui, opts))
1948 opts=patch.diffallopts(ui, opts))
1946
1949
1947 @command('files',
1950 @command('files',
1948 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1951 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1949 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1952 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1950 ] + walkopts + formatteropts + subrepoopts,
1953 ] + walkopts + formatteropts + subrepoopts,
1951 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1954 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1952 def files(ui, repo, *pats, **opts):
1955 def files(ui, repo, *pats, **opts):
1953 """list tracked files
1956 """list tracked files
1954
1957
1955 Print files under Mercurial control in the working directory or
1958 Print files under Mercurial control in the working directory or
1956 specified revision for given files (excluding removed files).
1959 specified revision for given files (excluding removed files).
1957 Files can be specified as filenames or filesets.
1960 Files can be specified as filenames or filesets.
1958
1961
1959 If no files are given to match, this command prints the names
1962 If no files are given to match, this command prints the names
1960 of all files under Mercurial control.
1963 of all files under Mercurial control.
1961
1964
1962 .. container:: verbose
1965 .. container:: verbose
1963
1966
1964 Examples:
1967 Examples:
1965
1968
1966 - list all files under the current directory::
1969 - list all files under the current directory::
1967
1970
1968 hg files .
1971 hg files .
1969
1972
1970 - shows sizes and flags for current revision::
1973 - shows sizes and flags for current revision::
1971
1974
1972 hg files -vr .
1975 hg files -vr .
1973
1976
1974 - list all files named README::
1977 - list all files named README::
1975
1978
1976 hg files -I "**/README"
1979 hg files -I "**/README"
1977
1980
1978 - list all binary files::
1981 - list all binary files::
1979
1982
1980 hg files "set:binary()"
1983 hg files "set:binary()"
1981
1984
1982 - find files containing a regular expression::
1985 - find files containing a regular expression::
1983
1986
1984 hg files "set:grep('bob')"
1987 hg files "set:grep('bob')"
1985
1988
1986 - search tracked file contents with xargs and grep::
1989 - search tracked file contents with xargs and grep::
1987
1990
1988 hg files -0 | xargs -0 grep foo
1991 hg files -0 | xargs -0 grep foo
1989
1992
1990 See :hg:`help patterns` and :hg:`help filesets` for more information
1993 See :hg:`help patterns` and :hg:`help filesets` for more information
1991 on specifying file patterns.
1994 on specifying file patterns.
1992
1995
1993 Returns 0 if a match is found, 1 otherwise.
1996 Returns 0 if a match is found, 1 otherwise.
1994
1997
1995 """
1998 """
1996
1999
1997 opts = pycompat.byteskwargs(opts)
2000 opts = pycompat.byteskwargs(opts)
1998 rev = opts.get('rev')
2001 rev = opts.get('rev')
1999 if rev:
2002 if rev:
2000 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2003 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2001 ctx = scmutil.revsingle(repo, rev, None)
2004 ctx = scmutil.revsingle(repo, rev, None)
2002
2005
2003 end = '\n'
2006 end = '\n'
2004 if opts.get('print0'):
2007 if opts.get('print0'):
2005 end = '\0'
2008 end = '\0'
2006 fmt = '%s' + end
2009 fmt = '%s' + end
2007
2010
2008 m = scmutil.match(ctx, pats, opts)
2011 m = scmutil.match(ctx, pats, opts)
2009 ui.pager('files')
2012 ui.pager('files')
2010 with ui.formatter('files', opts) as fm:
2013 with ui.formatter('files', opts) as fm:
2011 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2014 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2012
2015
2013 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2016 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2014 def forget(ui, repo, *pats, **opts):
2017 def forget(ui, repo, *pats, **opts):
2015 """forget the specified files on the next commit
2018 """forget the specified files on the next commit
2016
2019
2017 Mark the specified files so they will no longer be tracked
2020 Mark the specified files so they will no longer be tracked
2018 after the next commit.
2021 after the next commit.
2019
2022
2020 This only removes files from the current branch, not from the
2023 This only removes files from the current branch, not from the
2021 entire project history, and it does not delete them from the
2024 entire project history, and it does not delete them from the
2022 working directory.
2025 working directory.
2023
2026
2024 To delete the file from the working directory, see :hg:`remove`.
2027 To delete the file from the working directory, see :hg:`remove`.
2025
2028
2026 To undo a forget before the next commit, see :hg:`add`.
2029 To undo a forget before the next commit, see :hg:`add`.
2027
2030
2028 .. container:: verbose
2031 .. container:: verbose
2029
2032
2030 Examples:
2033 Examples:
2031
2034
2032 - forget newly-added binary files::
2035 - forget newly-added binary files::
2033
2036
2034 hg forget "set:added() and binary()"
2037 hg forget "set:added() and binary()"
2035
2038
2036 - forget files that would be excluded by .hgignore::
2039 - forget files that would be excluded by .hgignore::
2037
2040
2038 hg forget "set:hgignore()"
2041 hg forget "set:hgignore()"
2039
2042
2040 Returns 0 on success.
2043 Returns 0 on success.
2041 """
2044 """
2042
2045
2043 opts = pycompat.byteskwargs(opts)
2046 opts = pycompat.byteskwargs(opts)
2044 if not pats:
2047 if not pats:
2045 raise error.Abort(_('no files specified'))
2048 raise error.Abort(_('no files specified'))
2046
2049
2047 m = scmutil.match(repo[None], pats, opts)
2050 m = scmutil.match(repo[None], pats, opts)
2048 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2051 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2049 return rejected and 1 or 0
2052 return rejected and 1 or 0
2050
2053
2051 @command(
2054 @command(
2052 'graft',
2055 'graft',
2053 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2056 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2054 ('c', 'continue', False, _('resume interrupted graft')),
2057 ('c', 'continue', False, _('resume interrupted graft')),
2055 ('e', 'edit', False, _('invoke editor on commit messages')),
2058 ('e', 'edit', False, _('invoke editor on commit messages')),
2056 ('', 'log', None, _('append graft info to log message')),
2059 ('', 'log', None, _('append graft info to log message')),
2057 ('f', 'force', False, _('force graft')),
2060 ('f', 'force', False, _('force graft')),
2058 ('D', 'currentdate', False,
2061 ('D', 'currentdate', False,
2059 _('record the current date as commit date')),
2062 _('record the current date as commit date')),
2060 ('U', 'currentuser', False,
2063 ('U', 'currentuser', False,
2061 _('record the current user as committer'), _('DATE'))]
2064 _('record the current user as committer'), _('DATE'))]
2062 + commitopts2 + mergetoolopts + dryrunopts,
2065 + commitopts2 + mergetoolopts + dryrunopts,
2063 _('[OPTION]... [-r REV]... REV...'))
2066 _('[OPTION]... [-r REV]... REV...'))
2064 def graft(ui, repo, *revs, **opts):
2067 def graft(ui, repo, *revs, **opts):
2065 '''copy changes from other branches onto the current branch
2068 '''copy changes from other branches onto the current branch
2066
2069
2067 This command uses Mercurial's merge logic to copy individual
2070 This command uses Mercurial's merge logic to copy individual
2068 changes from other branches without merging branches in the
2071 changes from other branches without merging branches in the
2069 history graph. This is sometimes known as 'backporting' or
2072 history graph. This is sometimes known as 'backporting' or
2070 'cherry-picking'. By default, graft will copy user, date, and
2073 'cherry-picking'. By default, graft will copy user, date, and
2071 description from the source changesets.
2074 description from the source changesets.
2072
2075
2073 Changesets that are ancestors of the current revision, that have
2076 Changesets that are ancestors of the current revision, that have
2074 already been grafted, or that are merges will be skipped.
2077 already been grafted, or that are merges will be skipped.
2075
2078
2076 If --log is specified, log messages will have a comment appended
2079 If --log is specified, log messages will have a comment appended
2077 of the form::
2080 of the form::
2078
2081
2079 (grafted from CHANGESETHASH)
2082 (grafted from CHANGESETHASH)
2080
2083
2081 If --force is specified, revisions will be grafted even if they
2084 If --force is specified, revisions will be grafted even if they
2082 are already ancestors of, or have been grafted to, the destination.
2085 are already ancestors of, or have been grafted to, the destination.
2083 This is useful when the revisions have since been backed out.
2086 This is useful when the revisions have since been backed out.
2084
2087
2085 If a graft merge results in conflicts, the graft process is
2088 If a graft merge results in conflicts, the graft process is
2086 interrupted so that the current merge can be manually resolved.
2089 interrupted so that the current merge can be manually resolved.
2087 Once all conflicts are addressed, the graft process can be
2090 Once all conflicts are addressed, the graft process can be
2088 continued with the -c/--continue option.
2091 continued with the -c/--continue option.
2089
2092
2090 .. note::
2093 .. note::
2091
2094
2092 The -c/--continue option does not reapply earlier options, except
2095 The -c/--continue option does not reapply earlier options, except
2093 for --force.
2096 for --force.
2094
2097
2095 .. container:: verbose
2098 .. container:: verbose
2096
2099
2097 Examples:
2100 Examples:
2098
2101
2099 - copy a single change to the stable branch and edit its description::
2102 - copy a single change to the stable branch and edit its description::
2100
2103
2101 hg update stable
2104 hg update stable
2102 hg graft --edit 9393
2105 hg graft --edit 9393
2103
2106
2104 - graft a range of changesets with one exception, updating dates::
2107 - graft a range of changesets with one exception, updating dates::
2105
2108
2106 hg graft -D "2085::2093 and not 2091"
2109 hg graft -D "2085::2093 and not 2091"
2107
2110
2108 - continue a graft after resolving conflicts::
2111 - continue a graft after resolving conflicts::
2109
2112
2110 hg graft -c
2113 hg graft -c
2111
2114
2112 - show the source of a grafted changeset::
2115 - show the source of a grafted changeset::
2113
2116
2114 hg log --debug -r .
2117 hg log --debug -r .
2115
2118
2116 - show revisions sorted by date::
2119 - show revisions sorted by date::
2117
2120
2118 hg log -r "sort(all(), date)"
2121 hg log -r "sort(all(), date)"
2119
2122
2120 See :hg:`help revisions` for more about specifying revisions.
2123 See :hg:`help revisions` for more about specifying revisions.
2121
2124
2122 Returns 0 on successful completion.
2125 Returns 0 on successful completion.
2123 '''
2126 '''
2124 with repo.wlock():
2127 with repo.wlock():
2125 return _dograft(ui, repo, *revs, **opts)
2128 return _dograft(ui, repo, *revs, **opts)
2126
2129
2127 def _dograft(ui, repo, *revs, **opts):
2130 def _dograft(ui, repo, *revs, **opts):
2128 opts = pycompat.byteskwargs(opts)
2131 opts = pycompat.byteskwargs(opts)
2129 if revs and opts.get('rev'):
2132 if revs and opts.get('rev'):
2130 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2133 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2131 'revision ordering!\n'))
2134 'revision ordering!\n'))
2132
2135
2133 revs = list(revs)
2136 revs = list(revs)
2134 revs.extend(opts.get('rev'))
2137 revs.extend(opts.get('rev'))
2135
2138
2136 if not opts.get('user') and opts.get('currentuser'):
2139 if not opts.get('user') and opts.get('currentuser'):
2137 opts['user'] = ui.username()
2140 opts['user'] = ui.username()
2138 if not opts.get('date') and opts.get('currentdate'):
2141 if not opts.get('date') and opts.get('currentdate'):
2139 opts['date'] = "%d %d" % util.makedate()
2142 opts['date'] = "%d %d" % util.makedate()
2140
2143
2141 editor = cmdutil.getcommiteditor(editform='graft',
2144 editor = cmdutil.getcommiteditor(editform='graft',
2142 **pycompat.strkwargs(opts))
2145 **pycompat.strkwargs(opts))
2143
2146
2144 cont = False
2147 cont = False
2145 if opts.get('continue'):
2148 if opts.get('continue'):
2146 cont = True
2149 cont = True
2147 if revs:
2150 if revs:
2148 raise error.Abort(_("can't specify --continue and revisions"))
2151 raise error.Abort(_("can't specify --continue and revisions"))
2149 # read in unfinished revisions
2152 # read in unfinished revisions
2150 try:
2153 try:
2151 nodes = repo.vfs.read('graftstate').splitlines()
2154 nodes = repo.vfs.read('graftstate').splitlines()
2152 revs = [repo[node].rev() for node in nodes]
2155 revs = [repo[node].rev() for node in nodes]
2153 except IOError as inst:
2156 except IOError as inst:
2154 if inst.errno != errno.ENOENT:
2157 if inst.errno != errno.ENOENT:
2155 raise
2158 raise
2156 cmdutil.wrongtooltocontinue(repo, _('graft'))
2159 cmdutil.wrongtooltocontinue(repo, _('graft'))
2157 else:
2160 else:
2158 cmdutil.checkunfinished(repo)
2161 cmdutil.checkunfinished(repo)
2159 cmdutil.bailifchanged(repo)
2162 cmdutil.bailifchanged(repo)
2160 if not revs:
2163 if not revs:
2161 raise error.Abort(_('no revisions specified'))
2164 raise error.Abort(_('no revisions specified'))
2162 revs = scmutil.revrange(repo, revs)
2165 revs = scmutil.revrange(repo, revs)
2163
2166
2164 skipped = set()
2167 skipped = set()
2165 # check for merges
2168 # check for merges
2166 for rev in repo.revs('%ld and merge()', revs):
2169 for rev in repo.revs('%ld and merge()', revs):
2167 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2170 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2168 skipped.add(rev)
2171 skipped.add(rev)
2169 revs = [r for r in revs if r not in skipped]
2172 revs = [r for r in revs if r not in skipped]
2170 if not revs:
2173 if not revs:
2171 return -1
2174 return -1
2172
2175
2173 # Don't check in the --continue case, in effect retaining --force across
2176 # Don't check in the --continue case, in effect retaining --force across
2174 # --continues. That's because without --force, any revisions we decided to
2177 # --continues. That's because without --force, any revisions we decided to
2175 # skip would have been filtered out here, so they wouldn't have made their
2178 # skip would have been filtered out here, so they wouldn't have made their
2176 # way to the graftstate. With --force, any revisions we would have otherwise
2179 # way to the graftstate. With --force, any revisions we would have otherwise
2177 # skipped would not have been filtered out, and if they hadn't been applied
2180 # skipped would not have been filtered out, and if they hadn't been applied
2178 # already, they'd have been in the graftstate.
2181 # already, they'd have been in the graftstate.
2179 if not (cont or opts.get('force')):
2182 if not (cont or opts.get('force')):
2180 # check for ancestors of dest branch
2183 # check for ancestors of dest branch
2181 crev = repo['.'].rev()
2184 crev = repo['.'].rev()
2182 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2185 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2183 # XXX make this lazy in the future
2186 # XXX make this lazy in the future
2184 # don't mutate while iterating, create a copy
2187 # don't mutate while iterating, create a copy
2185 for rev in list(revs):
2188 for rev in list(revs):
2186 if rev in ancestors:
2189 if rev in ancestors:
2187 ui.warn(_('skipping ancestor revision %d:%s\n') %
2190 ui.warn(_('skipping ancestor revision %d:%s\n') %
2188 (rev, repo[rev]))
2191 (rev, repo[rev]))
2189 # XXX remove on list is slow
2192 # XXX remove on list is slow
2190 revs.remove(rev)
2193 revs.remove(rev)
2191 if not revs:
2194 if not revs:
2192 return -1
2195 return -1
2193
2196
2194 # analyze revs for earlier grafts
2197 # analyze revs for earlier grafts
2195 ids = {}
2198 ids = {}
2196 for ctx in repo.set("%ld", revs):
2199 for ctx in repo.set("%ld", revs):
2197 ids[ctx.hex()] = ctx.rev()
2200 ids[ctx.hex()] = ctx.rev()
2198 n = ctx.extra().get('source')
2201 n = ctx.extra().get('source')
2199 if n:
2202 if n:
2200 ids[n] = ctx.rev()
2203 ids[n] = ctx.rev()
2201
2204
2202 # check ancestors for earlier grafts
2205 # check ancestors for earlier grafts
2203 ui.debug('scanning for duplicate grafts\n')
2206 ui.debug('scanning for duplicate grafts\n')
2204
2207
2205 # The only changesets we can be sure doesn't contain grafts of any
2208 # The only changesets we can be sure doesn't contain grafts of any
2206 # revs, are the ones that are common ancestors of *all* revs:
2209 # revs, are the ones that are common ancestors of *all* revs:
2207 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2210 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2208 ctx = repo[rev]
2211 ctx = repo[rev]
2209 n = ctx.extra().get('source')
2212 n = ctx.extra().get('source')
2210 if n in ids:
2213 if n in ids:
2211 try:
2214 try:
2212 r = repo[n].rev()
2215 r = repo[n].rev()
2213 except error.RepoLookupError:
2216 except error.RepoLookupError:
2214 r = None
2217 r = None
2215 if r in revs:
2218 if r in revs:
2216 ui.warn(_('skipping revision %d:%s '
2219 ui.warn(_('skipping revision %d:%s '
2217 '(already grafted to %d:%s)\n')
2220 '(already grafted to %d:%s)\n')
2218 % (r, repo[r], rev, ctx))
2221 % (r, repo[r], rev, ctx))
2219 revs.remove(r)
2222 revs.remove(r)
2220 elif ids[n] in revs:
2223 elif ids[n] in revs:
2221 if r is None:
2224 if r is None:
2222 ui.warn(_('skipping already grafted revision %d:%s '
2225 ui.warn(_('skipping already grafted revision %d:%s '
2223 '(%d:%s also has unknown origin %s)\n')
2226 '(%d:%s also has unknown origin %s)\n')
2224 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2227 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2225 else:
2228 else:
2226 ui.warn(_('skipping already grafted revision %d:%s '
2229 ui.warn(_('skipping already grafted revision %d:%s '
2227 '(%d:%s also has origin %d:%s)\n')
2230 '(%d:%s also has origin %d:%s)\n')
2228 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2231 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2229 revs.remove(ids[n])
2232 revs.remove(ids[n])
2230 elif ctx.hex() in ids:
2233 elif ctx.hex() in ids:
2231 r = ids[ctx.hex()]
2234 r = ids[ctx.hex()]
2232 ui.warn(_('skipping already grafted revision %d:%s '
2235 ui.warn(_('skipping already grafted revision %d:%s '
2233 '(was grafted from %d:%s)\n') %
2236 '(was grafted from %d:%s)\n') %
2234 (r, repo[r], rev, ctx))
2237 (r, repo[r], rev, ctx))
2235 revs.remove(r)
2238 revs.remove(r)
2236 if not revs:
2239 if not revs:
2237 return -1
2240 return -1
2238
2241
2239 for pos, ctx in enumerate(repo.set("%ld", revs)):
2242 for pos, ctx in enumerate(repo.set("%ld", revs)):
2240 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2243 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2241 ctx.description().split('\n', 1)[0])
2244 ctx.description().split('\n', 1)[0])
2242 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2245 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2243 if names:
2246 if names:
2244 desc += ' (%s)' % ' '.join(names)
2247 desc += ' (%s)' % ' '.join(names)
2245 ui.status(_('grafting %s\n') % desc)
2248 ui.status(_('grafting %s\n') % desc)
2246 if opts.get('dry_run'):
2249 if opts.get('dry_run'):
2247 continue
2250 continue
2248
2251
2249 source = ctx.extra().get('source')
2252 source = ctx.extra().get('source')
2250 extra = {}
2253 extra = {}
2251 if source:
2254 if source:
2252 extra['source'] = source
2255 extra['source'] = source
2253 extra['intermediate-source'] = ctx.hex()
2256 extra['intermediate-source'] = ctx.hex()
2254 else:
2257 else:
2255 extra['source'] = ctx.hex()
2258 extra['source'] = ctx.hex()
2256 user = ctx.user()
2259 user = ctx.user()
2257 if opts.get('user'):
2260 if opts.get('user'):
2258 user = opts['user']
2261 user = opts['user']
2259 date = ctx.date()
2262 date = ctx.date()
2260 if opts.get('date'):
2263 if opts.get('date'):
2261 date = opts['date']
2264 date = opts['date']
2262 message = ctx.description()
2265 message = ctx.description()
2263 if opts.get('log'):
2266 if opts.get('log'):
2264 message += '\n(grafted from %s)' % ctx.hex()
2267 message += '\n(grafted from %s)' % ctx.hex()
2265
2268
2266 # we don't merge the first commit when continuing
2269 # we don't merge the first commit when continuing
2267 if not cont:
2270 if not cont:
2268 # perform the graft merge with p1(rev) as 'ancestor'
2271 # perform the graft merge with p1(rev) as 'ancestor'
2269 try:
2272 try:
2270 # ui.forcemerge is an internal variable, do not document
2273 # ui.forcemerge is an internal variable, do not document
2271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2274 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2272 'graft')
2275 'graft')
2273 stats = mergemod.graft(repo, ctx, ctx.p1(),
2276 stats = mergemod.graft(repo, ctx, ctx.p1(),
2274 ['local', 'graft'])
2277 ['local', 'graft'])
2275 finally:
2278 finally:
2276 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2279 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2277 # report any conflicts
2280 # report any conflicts
2278 if stats and stats[3] > 0:
2281 if stats and stats[3] > 0:
2279 # write out state for --continue
2282 # write out state for --continue
2280 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2283 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2281 repo.vfs.write('graftstate', ''.join(nodelines))
2284 repo.vfs.write('graftstate', ''.join(nodelines))
2282 extra = ''
2285 extra = ''
2283 if opts.get('user'):
2286 if opts.get('user'):
2284 extra += ' --user %s' % util.shellquote(opts['user'])
2287 extra += ' --user %s' % util.shellquote(opts['user'])
2285 if opts.get('date'):
2288 if opts.get('date'):
2286 extra += ' --date %s' % util.shellquote(opts['date'])
2289 extra += ' --date %s' % util.shellquote(opts['date'])
2287 if opts.get('log'):
2290 if opts.get('log'):
2288 extra += ' --log'
2291 extra += ' --log'
2289 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2292 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2290 raise error.Abort(
2293 raise error.Abort(
2291 _("unresolved conflicts, can't continue"),
2294 _("unresolved conflicts, can't continue"),
2292 hint=hint)
2295 hint=hint)
2293 else:
2296 else:
2294 cont = False
2297 cont = False
2295
2298
2296 # commit
2299 # commit
2297 node = repo.commit(text=message, user=user,
2300 node = repo.commit(text=message, user=user,
2298 date=date, extra=extra, editor=editor)
2301 date=date, extra=extra, editor=editor)
2299 if node is None:
2302 if node is None:
2300 ui.warn(
2303 ui.warn(
2301 _('note: graft of %d:%s created no changes to commit\n') %
2304 _('note: graft of %d:%s created no changes to commit\n') %
2302 (ctx.rev(), ctx))
2305 (ctx.rev(), ctx))
2303
2306
2304 # remove state when we complete successfully
2307 # remove state when we complete successfully
2305 if not opts.get('dry_run'):
2308 if not opts.get('dry_run'):
2306 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2309 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2307
2310
2308 return 0
2311 return 0
2309
2312
2310 @command('grep',
2313 @command('grep',
2311 [('0', 'print0', None, _('end fields with NUL')),
2314 [('0', 'print0', None, _('end fields with NUL')),
2312 ('', 'all', None, _('print all revisions that match')),
2315 ('', 'all', None, _('print all revisions that match')),
2313 ('a', 'text', None, _('treat all files as text')),
2316 ('a', 'text', None, _('treat all files as text')),
2314 ('f', 'follow', None,
2317 ('f', 'follow', None,
2315 _('follow changeset history,'
2318 _('follow changeset history,'
2316 ' or file history across copies and renames')),
2319 ' or file history across copies and renames')),
2317 ('i', 'ignore-case', None, _('ignore case when matching')),
2320 ('i', 'ignore-case', None, _('ignore case when matching')),
2318 ('l', 'files-with-matches', None,
2321 ('l', 'files-with-matches', None,
2319 _('print only filenames and revisions that match')),
2322 _('print only filenames and revisions that match')),
2320 ('n', 'line-number', None, _('print matching line numbers')),
2323 ('n', 'line-number', None, _('print matching line numbers')),
2321 ('r', 'rev', [],
2324 ('r', 'rev', [],
2322 _('only search files changed within revision range'), _('REV')),
2325 _('only search files changed within revision range'), _('REV')),
2323 ('u', 'user', None, _('list the author (long with -v)')),
2326 ('u', 'user', None, _('list the author (long with -v)')),
2324 ('d', 'date', None, _('list the date (short with -q)')),
2327 ('d', 'date', None, _('list the date (short with -q)')),
2325 ] + formatteropts + walkopts,
2328 ] + formatteropts + walkopts,
2326 _('[OPTION]... PATTERN [FILE]...'),
2329 _('[OPTION]... PATTERN [FILE]...'),
2327 inferrepo=True, cmdtype=readonly)
2330 inferrepo=True, cmdtype=readonly)
2328 def grep(ui, repo, pattern, *pats, **opts):
2331 def grep(ui, repo, pattern, *pats, **opts):
2329 """search revision history for a pattern in specified files
2332 """search revision history for a pattern in specified files
2330
2333
2331 Search revision history for a regular expression in the specified
2334 Search revision history for a regular expression in the specified
2332 files or the entire project.
2335 files or the entire project.
2333
2336
2334 By default, grep prints the most recent revision number for each
2337 By default, grep prints the most recent revision number for each
2335 file in which it finds a match. To get it to print every revision
2338 file in which it finds a match. To get it to print every revision
2336 that contains a change in match status ("-" for a match that becomes
2339 that contains a change in match status ("-" for a match that becomes
2337 a non-match, or "+" for a non-match that becomes a match), use the
2340 a non-match, or "+" for a non-match that becomes a match), use the
2338 --all flag.
2341 --all flag.
2339
2342
2340 PATTERN can be any Python (roughly Perl-compatible) regular
2343 PATTERN can be any Python (roughly Perl-compatible) regular
2341 expression.
2344 expression.
2342
2345
2343 If no FILEs are specified (and -f/--follow isn't set), all files in
2346 If no FILEs are specified (and -f/--follow isn't set), all files in
2344 the repository are searched, including those that don't exist in the
2347 the repository are searched, including those that don't exist in the
2345 current branch or have been deleted in a prior changeset.
2348 current branch or have been deleted in a prior changeset.
2346
2349
2347 Returns 0 if a match is found, 1 otherwise.
2350 Returns 0 if a match is found, 1 otherwise.
2348 """
2351 """
2349 opts = pycompat.byteskwargs(opts)
2352 opts = pycompat.byteskwargs(opts)
2350 reflags = re.M
2353 reflags = re.M
2351 if opts.get('ignore_case'):
2354 if opts.get('ignore_case'):
2352 reflags |= re.I
2355 reflags |= re.I
2353 try:
2356 try:
2354 regexp = util.re.compile(pattern, reflags)
2357 regexp = util.re.compile(pattern, reflags)
2355 except re.error as inst:
2358 except re.error as inst:
2356 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2359 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2357 return 1
2360 return 1
2358 sep, eol = ':', '\n'
2361 sep, eol = ':', '\n'
2359 if opts.get('print0'):
2362 if opts.get('print0'):
2360 sep = eol = '\0'
2363 sep = eol = '\0'
2361
2364
2362 getfile = util.lrucachefunc(repo.file)
2365 getfile = util.lrucachefunc(repo.file)
2363
2366
2364 def matchlines(body):
2367 def matchlines(body):
2365 begin = 0
2368 begin = 0
2366 linenum = 0
2369 linenum = 0
2367 while begin < len(body):
2370 while begin < len(body):
2368 match = regexp.search(body, begin)
2371 match = regexp.search(body, begin)
2369 if not match:
2372 if not match:
2370 break
2373 break
2371 mstart, mend = match.span()
2374 mstart, mend = match.span()
2372 linenum += body.count('\n', begin, mstart) + 1
2375 linenum += body.count('\n', begin, mstart) + 1
2373 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2376 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2374 begin = body.find('\n', mend) + 1 or len(body) + 1
2377 begin = body.find('\n', mend) + 1 or len(body) + 1
2375 lend = begin - 1
2378 lend = begin - 1
2376 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2379 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2377
2380
2378 class linestate(object):
2381 class linestate(object):
2379 def __init__(self, line, linenum, colstart, colend):
2382 def __init__(self, line, linenum, colstart, colend):
2380 self.line = line
2383 self.line = line
2381 self.linenum = linenum
2384 self.linenum = linenum
2382 self.colstart = colstart
2385 self.colstart = colstart
2383 self.colend = colend
2386 self.colend = colend
2384
2387
2385 def __hash__(self):
2388 def __hash__(self):
2386 return hash((self.linenum, self.line))
2389 return hash((self.linenum, self.line))
2387
2390
2388 def __eq__(self, other):
2391 def __eq__(self, other):
2389 return self.line == other.line
2392 return self.line == other.line
2390
2393
2391 def findpos(self):
2394 def findpos(self):
2392 """Iterate all (start, end) indices of matches"""
2395 """Iterate all (start, end) indices of matches"""
2393 yield self.colstart, self.colend
2396 yield self.colstart, self.colend
2394 p = self.colend
2397 p = self.colend
2395 while p < len(self.line):
2398 while p < len(self.line):
2396 m = regexp.search(self.line, p)
2399 m = regexp.search(self.line, p)
2397 if not m:
2400 if not m:
2398 break
2401 break
2399 yield m.span()
2402 yield m.span()
2400 p = m.end()
2403 p = m.end()
2401
2404
2402 matches = {}
2405 matches = {}
2403 copies = {}
2406 copies = {}
2404 def grepbody(fn, rev, body):
2407 def grepbody(fn, rev, body):
2405 matches[rev].setdefault(fn, [])
2408 matches[rev].setdefault(fn, [])
2406 m = matches[rev][fn]
2409 m = matches[rev][fn]
2407 for lnum, cstart, cend, line in matchlines(body):
2410 for lnum, cstart, cend, line in matchlines(body):
2408 s = linestate(line, lnum, cstart, cend)
2411 s = linestate(line, lnum, cstart, cend)
2409 m.append(s)
2412 m.append(s)
2410
2413
2411 def difflinestates(a, b):
2414 def difflinestates(a, b):
2412 sm = difflib.SequenceMatcher(None, a, b)
2415 sm = difflib.SequenceMatcher(None, a, b)
2413 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2416 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2414 if tag == 'insert':
2417 if tag == 'insert':
2415 for i in xrange(blo, bhi):
2418 for i in xrange(blo, bhi):
2416 yield ('+', b[i])
2419 yield ('+', b[i])
2417 elif tag == 'delete':
2420 elif tag == 'delete':
2418 for i in xrange(alo, ahi):
2421 for i in xrange(alo, ahi):
2419 yield ('-', a[i])
2422 yield ('-', a[i])
2420 elif tag == 'replace':
2423 elif tag == 'replace':
2421 for i in xrange(alo, ahi):
2424 for i in xrange(alo, ahi):
2422 yield ('-', a[i])
2425 yield ('-', a[i])
2423 for i in xrange(blo, bhi):
2426 for i in xrange(blo, bhi):
2424 yield ('+', b[i])
2427 yield ('+', b[i])
2425
2428
2426 def display(fm, fn, ctx, pstates, states):
2429 def display(fm, fn, ctx, pstates, states):
2427 rev = ctx.rev()
2430 rev = ctx.rev()
2428 if fm.isplain():
2431 if fm.isplain():
2429 formatuser = ui.shortuser
2432 formatuser = ui.shortuser
2430 else:
2433 else:
2431 formatuser = str
2434 formatuser = str
2432 if ui.quiet:
2435 if ui.quiet:
2433 datefmt = '%Y-%m-%d'
2436 datefmt = '%Y-%m-%d'
2434 else:
2437 else:
2435 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2438 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2436 found = False
2439 found = False
2437 @util.cachefunc
2440 @util.cachefunc
2438 def binary():
2441 def binary():
2439 flog = getfile(fn)
2442 flog = getfile(fn)
2440 return util.binary(flog.read(ctx.filenode(fn)))
2443 return util.binary(flog.read(ctx.filenode(fn)))
2441
2444
2442 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2445 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2443 if opts.get('all'):
2446 if opts.get('all'):
2444 iter = difflinestates(pstates, states)
2447 iter = difflinestates(pstates, states)
2445 else:
2448 else:
2446 iter = [('', l) for l in states]
2449 iter = [('', l) for l in states]
2447 for change, l in iter:
2450 for change, l in iter:
2448 fm.startitem()
2451 fm.startitem()
2449 fm.data(node=fm.hexfunc(ctx.node()))
2452 fm.data(node=fm.hexfunc(ctx.node()))
2450 cols = [
2453 cols = [
2451 ('filename', fn, True),
2454 ('filename', fn, True),
2452 ('rev', rev, True),
2455 ('rev', rev, True),
2453 ('linenumber', l.linenum, opts.get('line_number')),
2456 ('linenumber', l.linenum, opts.get('line_number')),
2454 ]
2457 ]
2455 if opts.get('all'):
2458 if opts.get('all'):
2456 cols.append(('change', change, True))
2459 cols.append(('change', change, True))
2457 cols.extend([
2460 cols.extend([
2458 ('user', formatuser(ctx.user()), opts.get('user')),
2461 ('user', formatuser(ctx.user()), opts.get('user')),
2459 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2462 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2460 ])
2463 ])
2461 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2464 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2462 for name, data, cond in cols:
2465 for name, data, cond in cols:
2463 field = fieldnamemap.get(name, name)
2466 field = fieldnamemap.get(name, name)
2464 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2467 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2465 if cond and name != lastcol:
2468 if cond and name != lastcol:
2466 fm.plain(sep, label='grep.sep')
2469 fm.plain(sep, label='grep.sep')
2467 if not opts.get('files_with_matches'):
2470 if not opts.get('files_with_matches'):
2468 fm.plain(sep, label='grep.sep')
2471 fm.plain(sep, label='grep.sep')
2469 if not opts.get('text') and binary():
2472 if not opts.get('text') and binary():
2470 fm.plain(_(" Binary file matches"))
2473 fm.plain(_(" Binary file matches"))
2471 else:
2474 else:
2472 displaymatches(fm.nested('texts'), l)
2475 displaymatches(fm.nested('texts'), l)
2473 fm.plain(eol)
2476 fm.plain(eol)
2474 found = True
2477 found = True
2475 if opts.get('files_with_matches'):
2478 if opts.get('files_with_matches'):
2476 break
2479 break
2477 return found
2480 return found
2478
2481
2479 def displaymatches(fm, l):
2482 def displaymatches(fm, l):
2480 p = 0
2483 p = 0
2481 for s, e in l.findpos():
2484 for s, e in l.findpos():
2482 if p < s:
2485 if p < s:
2483 fm.startitem()
2486 fm.startitem()
2484 fm.write('text', '%s', l.line[p:s])
2487 fm.write('text', '%s', l.line[p:s])
2485 fm.data(matched=False)
2488 fm.data(matched=False)
2486 fm.startitem()
2489 fm.startitem()
2487 fm.write('text', '%s', l.line[s:e], label='grep.match')
2490 fm.write('text', '%s', l.line[s:e], label='grep.match')
2488 fm.data(matched=True)
2491 fm.data(matched=True)
2489 p = e
2492 p = e
2490 if p < len(l.line):
2493 if p < len(l.line):
2491 fm.startitem()
2494 fm.startitem()
2492 fm.write('text', '%s', l.line[p:])
2495 fm.write('text', '%s', l.line[p:])
2493 fm.data(matched=False)
2496 fm.data(matched=False)
2494 fm.end()
2497 fm.end()
2495
2498
2496 skip = {}
2499 skip = {}
2497 revfiles = {}
2500 revfiles = {}
2498 match = scmutil.match(repo[None], pats, opts)
2501 match = scmutil.match(repo[None], pats, opts)
2499 found = False
2502 found = False
2500 follow = opts.get('follow')
2503 follow = opts.get('follow')
2501
2504
2502 def prep(ctx, fns):
2505 def prep(ctx, fns):
2503 rev = ctx.rev()
2506 rev = ctx.rev()
2504 pctx = ctx.p1()
2507 pctx = ctx.p1()
2505 parent = pctx.rev()
2508 parent = pctx.rev()
2506 matches.setdefault(rev, {})
2509 matches.setdefault(rev, {})
2507 matches.setdefault(parent, {})
2510 matches.setdefault(parent, {})
2508 files = revfiles.setdefault(rev, [])
2511 files = revfiles.setdefault(rev, [])
2509 for fn in fns:
2512 for fn in fns:
2510 flog = getfile(fn)
2513 flog = getfile(fn)
2511 try:
2514 try:
2512 fnode = ctx.filenode(fn)
2515 fnode = ctx.filenode(fn)
2513 except error.LookupError:
2516 except error.LookupError:
2514 continue
2517 continue
2515
2518
2516 copied = flog.renamed(fnode)
2519 copied = flog.renamed(fnode)
2517 copy = follow and copied and copied[0]
2520 copy = follow and copied and copied[0]
2518 if copy:
2521 if copy:
2519 copies.setdefault(rev, {})[fn] = copy
2522 copies.setdefault(rev, {})[fn] = copy
2520 if fn in skip:
2523 if fn in skip:
2521 if copy:
2524 if copy:
2522 skip[copy] = True
2525 skip[copy] = True
2523 continue
2526 continue
2524 files.append(fn)
2527 files.append(fn)
2525
2528
2526 if fn not in matches[rev]:
2529 if fn not in matches[rev]:
2527 grepbody(fn, rev, flog.read(fnode))
2530 grepbody(fn, rev, flog.read(fnode))
2528
2531
2529 pfn = copy or fn
2532 pfn = copy or fn
2530 if pfn not in matches[parent]:
2533 if pfn not in matches[parent]:
2531 try:
2534 try:
2532 fnode = pctx.filenode(pfn)
2535 fnode = pctx.filenode(pfn)
2533 grepbody(pfn, parent, flog.read(fnode))
2536 grepbody(pfn, parent, flog.read(fnode))
2534 except error.LookupError:
2537 except error.LookupError:
2535 pass
2538 pass
2536
2539
2537 ui.pager('grep')
2540 ui.pager('grep')
2538 fm = ui.formatter('grep', opts)
2541 fm = ui.formatter('grep', opts)
2539 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2542 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2540 rev = ctx.rev()
2543 rev = ctx.rev()
2541 parent = ctx.p1().rev()
2544 parent = ctx.p1().rev()
2542 for fn in sorted(revfiles.get(rev, [])):
2545 for fn in sorted(revfiles.get(rev, [])):
2543 states = matches[rev][fn]
2546 states = matches[rev][fn]
2544 copy = copies.get(rev, {}).get(fn)
2547 copy = copies.get(rev, {}).get(fn)
2545 if fn in skip:
2548 if fn in skip:
2546 if copy:
2549 if copy:
2547 skip[copy] = True
2550 skip[copy] = True
2548 continue
2551 continue
2549 pstates = matches.get(parent, {}).get(copy or fn, [])
2552 pstates = matches.get(parent, {}).get(copy or fn, [])
2550 if pstates or states:
2553 if pstates or states:
2551 r = display(fm, fn, ctx, pstates, states)
2554 r = display(fm, fn, ctx, pstates, states)
2552 found = found or r
2555 found = found or r
2553 if r and not opts.get('all'):
2556 if r and not opts.get('all'):
2554 skip[fn] = True
2557 skip[fn] = True
2555 if copy:
2558 if copy:
2556 skip[copy] = True
2559 skip[copy] = True
2557 del matches[rev]
2560 del matches[rev]
2558 del revfiles[rev]
2561 del revfiles[rev]
2559 fm.end()
2562 fm.end()
2560
2563
2561 return not found
2564 return not found
2562
2565
2563 @command('heads',
2566 @command('heads',
2564 [('r', 'rev', '',
2567 [('r', 'rev', '',
2565 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2568 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2566 ('t', 'topo', False, _('show topological heads only')),
2569 ('t', 'topo', False, _('show topological heads only')),
2567 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2570 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2568 ('c', 'closed', False, _('show normal and closed branch heads')),
2571 ('c', 'closed', False, _('show normal and closed branch heads')),
2569 ] + templateopts,
2572 ] + templateopts,
2570 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2573 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2571 def heads(ui, repo, *branchrevs, **opts):
2574 def heads(ui, repo, *branchrevs, **opts):
2572 """show branch heads
2575 """show branch heads
2573
2576
2574 With no arguments, show all open branch heads in the repository.
2577 With no arguments, show all open branch heads in the repository.
2575 Branch heads are changesets that have no descendants on the
2578 Branch heads are changesets that have no descendants on the
2576 same branch. They are where development generally takes place and
2579 same branch. They are where development generally takes place and
2577 are the usual targets for update and merge operations.
2580 are the usual targets for update and merge operations.
2578
2581
2579 If one or more REVs are given, only open branch heads on the
2582 If one or more REVs are given, only open branch heads on the
2580 branches associated with the specified changesets are shown. This
2583 branches associated with the specified changesets are shown. This
2581 means that you can use :hg:`heads .` to see the heads on the
2584 means that you can use :hg:`heads .` to see the heads on the
2582 currently checked-out branch.
2585 currently checked-out branch.
2583
2586
2584 If -c/--closed is specified, also show branch heads marked closed
2587 If -c/--closed is specified, also show branch heads marked closed
2585 (see :hg:`commit --close-branch`).
2588 (see :hg:`commit --close-branch`).
2586
2589
2587 If STARTREV is specified, only those heads that are descendants of
2590 If STARTREV is specified, only those heads that are descendants of
2588 STARTREV will be displayed.
2591 STARTREV will be displayed.
2589
2592
2590 If -t/--topo is specified, named branch mechanics will be ignored and only
2593 If -t/--topo is specified, named branch mechanics will be ignored and only
2591 topological heads (changesets with no children) will be shown.
2594 topological heads (changesets with no children) will be shown.
2592
2595
2593 Returns 0 if matching heads are found, 1 if not.
2596 Returns 0 if matching heads are found, 1 if not.
2594 """
2597 """
2595
2598
2596 opts = pycompat.byteskwargs(opts)
2599 opts = pycompat.byteskwargs(opts)
2597 start = None
2600 start = None
2598 rev = opts.get('rev')
2601 rev = opts.get('rev')
2599 if rev:
2602 if rev:
2600 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2603 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2601 start = scmutil.revsingle(repo, rev, None).node()
2604 start = scmutil.revsingle(repo, rev, None).node()
2602
2605
2603 if opts.get('topo'):
2606 if opts.get('topo'):
2604 heads = [repo[h] for h in repo.heads(start)]
2607 heads = [repo[h] for h in repo.heads(start)]
2605 else:
2608 else:
2606 heads = []
2609 heads = []
2607 for branch in repo.branchmap():
2610 for branch in repo.branchmap():
2608 heads += repo.branchheads(branch, start, opts.get('closed'))
2611 heads += repo.branchheads(branch, start, opts.get('closed'))
2609 heads = [repo[h] for h in heads]
2612 heads = [repo[h] for h in heads]
2610
2613
2611 if branchrevs:
2614 if branchrevs:
2612 branches = set(repo[br].branch() for br in branchrevs)
2615 branches = set(repo[br].branch() for br in branchrevs)
2613 heads = [h for h in heads if h.branch() in branches]
2616 heads = [h for h in heads if h.branch() in branches]
2614
2617
2615 if opts.get('active') and branchrevs:
2618 if opts.get('active') and branchrevs:
2616 dagheads = repo.heads(start)
2619 dagheads = repo.heads(start)
2617 heads = [h for h in heads if h.node() in dagheads]
2620 heads = [h for h in heads if h.node() in dagheads]
2618
2621
2619 if branchrevs:
2622 if branchrevs:
2620 haveheads = set(h.branch() for h in heads)
2623 haveheads = set(h.branch() for h in heads)
2621 if branches - haveheads:
2624 if branches - haveheads:
2622 headless = ', '.join(b for b in branches - haveheads)
2625 headless = ', '.join(b for b in branches - haveheads)
2623 msg = _('no open branch heads found on branches %s')
2626 msg = _('no open branch heads found on branches %s')
2624 if opts.get('rev'):
2627 if opts.get('rev'):
2625 msg += _(' (started at %s)') % opts['rev']
2628 msg += _(' (started at %s)') % opts['rev']
2626 ui.warn((msg + '\n') % headless)
2629 ui.warn((msg + '\n') % headless)
2627
2630
2628 if not heads:
2631 if not heads:
2629 return 1
2632 return 1
2630
2633
2631 ui.pager('heads')
2634 ui.pager('heads')
2632 heads = sorted(heads, key=lambda x: -x.rev())
2635 heads = sorted(heads, key=lambda x: -x.rev())
2633 displayer = cmdutil.show_changeset(ui, repo, opts)
2636 displayer = cmdutil.show_changeset(ui, repo, opts)
2634 for ctx in heads:
2637 for ctx in heads:
2635 displayer.show(ctx)
2638 displayer.show(ctx)
2636 displayer.close()
2639 displayer.close()
2637
2640
2638 @command('help',
2641 @command('help',
2639 [('e', 'extension', None, _('show only help for extensions')),
2642 [('e', 'extension', None, _('show only help for extensions')),
2640 ('c', 'command', None, _('show only help for commands')),
2643 ('c', 'command', None, _('show only help for commands')),
2641 ('k', 'keyword', None, _('show topics matching keyword')),
2644 ('k', 'keyword', None, _('show topics matching keyword')),
2642 ('s', 'system', [], _('show help for specific platform(s)')),
2645 ('s', 'system', [], _('show help for specific platform(s)')),
2643 ],
2646 ],
2644 _('[-ecks] [TOPIC]'),
2647 _('[-ecks] [TOPIC]'),
2645 norepo=True, cmdtype=readonly)
2648 norepo=True, cmdtype=readonly)
2646 def help_(ui, name=None, **opts):
2649 def help_(ui, name=None, **opts):
2647 """show help for a given topic or a help overview
2650 """show help for a given topic or a help overview
2648
2651
2649 With no arguments, print a list of commands with short help messages.
2652 With no arguments, print a list of commands with short help messages.
2650
2653
2651 Given a topic, extension, or command name, print help for that
2654 Given a topic, extension, or command name, print help for that
2652 topic.
2655 topic.
2653
2656
2654 Returns 0 if successful.
2657 Returns 0 if successful.
2655 """
2658 """
2656
2659
2657 keep = opts.get(r'system') or []
2660 keep = opts.get(r'system') or []
2658 if len(keep) == 0:
2661 if len(keep) == 0:
2659 if pycompat.sysplatform.startswith('win'):
2662 if pycompat.sysplatform.startswith('win'):
2660 keep.append('windows')
2663 keep.append('windows')
2661 elif pycompat.sysplatform == 'OpenVMS':
2664 elif pycompat.sysplatform == 'OpenVMS':
2662 keep.append('vms')
2665 keep.append('vms')
2663 elif pycompat.sysplatform == 'plan9':
2666 elif pycompat.sysplatform == 'plan9':
2664 keep.append('plan9')
2667 keep.append('plan9')
2665 else:
2668 else:
2666 keep.append('unix')
2669 keep.append('unix')
2667 keep.append(pycompat.sysplatform.lower())
2670 keep.append(pycompat.sysplatform.lower())
2668 if ui.verbose:
2671 if ui.verbose:
2669 keep.append('verbose')
2672 keep.append('verbose')
2670
2673
2671 commands = sys.modules[__name__]
2674 commands = sys.modules[__name__]
2672 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2675 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2673 ui.pager('help')
2676 ui.pager('help')
2674 ui.write(formatted)
2677 ui.write(formatted)
2675
2678
2676
2679
2677 @command('identify|id',
2680 @command('identify|id',
2678 [('r', 'rev', '',
2681 [('r', 'rev', '',
2679 _('identify the specified revision'), _('REV')),
2682 _('identify the specified revision'), _('REV')),
2680 ('n', 'num', None, _('show local revision number')),
2683 ('n', 'num', None, _('show local revision number')),
2681 ('i', 'id', None, _('show global revision id')),
2684 ('i', 'id', None, _('show global revision id')),
2682 ('b', 'branch', None, _('show branch')),
2685 ('b', 'branch', None, _('show branch')),
2683 ('t', 'tags', None, _('show tags')),
2686 ('t', 'tags', None, _('show tags')),
2684 ('B', 'bookmarks', None, _('show bookmarks')),
2687 ('B', 'bookmarks', None, _('show bookmarks')),
2685 ] + remoteopts + formatteropts,
2688 ] + remoteopts + formatteropts,
2686 _('[-nibtB] [-r REV] [SOURCE]'),
2689 _('[-nibtB] [-r REV] [SOURCE]'),
2687 optionalrepo=True, cmdtype=readonly)
2690 optionalrepo=True, cmdtype=readonly)
2688 def identify(ui, repo, source=None, rev=None,
2691 def identify(ui, repo, source=None, rev=None,
2689 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2692 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2690 """identify the working directory or specified revision
2693 """identify the working directory or specified revision
2691
2694
2692 Print a summary identifying the repository state at REV using one or
2695 Print a summary identifying the repository state at REV using one or
2693 two parent hash identifiers, followed by a "+" if the working
2696 two parent hash identifiers, followed by a "+" if the working
2694 directory has uncommitted changes, the branch name (if not default),
2697 directory has uncommitted changes, the branch name (if not default),
2695 a list of tags, and a list of bookmarks.
2698 a list of tags, and a list of bookmarks.
2696
2699
2697 When REV is not given, print a summary of the current state of the
2700 When REV is not given, print a summary of the current state of the
2698 repository.
2701 repository.
2699
2702
2700 Specifying a path to a repository root or Mercurial bundle will
2703 Specifying a path to a repository root or Mercurial bundle will
2701 cause lookup to operate on that repository/bundle.
2704 cause lookup to operate on that repository/bundle.
2702
2705
2703 .. container:: verbose
2706 .. container:: verbose
2704
2707
2705 Examples:
2708 Examples:
2706
2709
2707 - generate a build identifier for the working directory::
2710 - generate a build identifier for the working directory::
2708
2711
2709 hg id --id > build-id.dat
2712 hg id --id > build-id.dat
2710
2713
2711 - find the revision corresponding to a tag::
2714 - find the revision corresponding to a tag::
2712
2715
2713 hg id -n -r 1.3
2716 hg id -n -r 1.3
2714
2717
2715 - check the most recent revision of a remote repository::
2718 - check the most recent revision of a remote repository::
2716
2719
2717 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2720 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2718
2721
2719 See :hg:`log` for generating more information about specific revisions,
2722 See :hg:`log` for generating more information about specific revisions,
2720 including full hash identifiers.
2723 including full hash identifiers.
2721
2724
2722 Returns 0 if successful.
2725 Returns 0 if successful.
2723 """
2726 """
2724
2727
2725 opts = pycompat.byteskwargs(opts)
2728 opts = pycompat.byteskwargs(opts)
2726 if not repo and not source:
2729 if not repo and not source:
2727 raise error.Abort(_("there is no Mercurial repository here "
2730 raise error.Abort(_("there is no Mercurial repository here "
2728 "(.hg not found)"))
2731 "(.hg not found)"))
2729
2732
2730 if ui.debugflag:
2733 if ui.debugflag:
2731 hexfunc = hex
2734 hexfunc = hex
2732 else:
2735 else:
2733 hexfunc = short
2736 hexfunc = short
2734 default = not (num or id or branch or tags or bookmarks)
2737 default = not (num or id or branch or tags or bookmarks)
2735 output = []
2738 output = []
2736 revs = []
2739 revs = []
2737
2740
2738 if source:
2741 if source:
2739 source, branches = hg.parseurl(ui.expandpath(source))
2742 source, branches = hg.parseurl(ui.expandpath(source))
2740 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2743 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2741 repo = peer.local()
2744 repo = peer.local()
2742 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2745 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2743
2746
2744 fm = ui.formatter('identify', opts)
2747 fm = ui.formatter('identify', opts)
2745 fm.startitem()
2748 fm.startitem()
2746
2749
2747 if not repo:
2750 if not repo:
2748 if num or branch or tags:
2751 if num or branch or tags:
2749 raise error.Abort(
2752 raise error.Abort(
2750 _("can't query remote revision number, branch, or tags"))
2753 _("can't query remote revision number, branch, or tags"))
2751 if not rev and revs:
2754 if not rev and revs:
2752 rev = revs[0]
2755 rev = revs[0]
2753 if not rev:
2756 if not rev:
2754 rev = "tip"
2757 rev = "tip"
2755
2758
2756 remoterev = peer.lookup(rev)
2759 remoterev = peer.lookup(rev)
2757 hexrev = hexfunc(remoterev)
2760 hexrev = hexfunc(remoterev)
2758 if default or id:
2761 if default or id:
2759 output = [hexrev]
2762 output = [hexrev]
2760 fm.data(id=hexrev)
2763 fm.data(id=hexrev)
2761
2764
2762 def getbms():
2765 def getbms():
2763 bms = []
2766 bms = []
2764
2767
2765 if 'bookmarks' in peer.listkeys('namespaces'):
2768 if 'bookmarks' in peer.listkeys('namespaces'):
2766 hexremoterev = hex(remoterev)
2769 hexremoterev = hex(remoterev)
2767 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2770 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2768 if bmr == hexremoterev]
2771 if bmr == hexremoterev]
2769
2772
2770 return sorted(bms)
2773 return sorted(bms)
2771
2774
2772 bms = getbms()
2775 bms = getbms()
2773 if bookmarks:
2776 if bookmarks:
2774 output.extend(bms)
2777 output.extend(bms)
2775 elif default and not ui.quiet:
2778 elif default and not ui.quiet:
2776 # multiple bookmarks for a single parent separated by '/'
2779 # multiple bookmarks for a single parent separated by '/'
2777 bm = '/'.join(bms)
2780 bm = '/'.join(bms)
2778 if bm:
2781 if bm:
2779 output.append(bm)
2782 output.append(bm)
2780
2783
2781 fm.data(node=hex(remoterev))
2784 fm.data(node=hex(remoterev))
2782 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2785 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2783 else:
2786 else:
2784 if rev:
2787 if rev:
2785 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2788 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2786 ctx = scmutil.revsingle(repo, rev, None)
2789 ctx = scmutil.revsingle(repo, rev, None)
2787
2790
2788 if ctx.rev() is None:
2791 if ctx.rev() is None:
2789 ctx = repo[None]
2792 ctx = repo[None]
2790 parents = ctx.parents()
2793 parents = ctx.parents()
2791 taglist = []
2794 taglist = []
2792 for p in parents:
2795 for p in parents:
2793 taglist.extend(p.tags())
2796 taglist.extend(p.tags())
2794
2797
2795 dirty = ""
2798 dirty = ""
2796 if ctx.dirty(missing=True, merge=False, branch=False):
2799 if ctx.dirty(missing=True, merge=False, branch=False):
2797 dirty = '+'
2800 dirty = '+'
2798 fm.data(dirty=dirty)
2801 fm.data(dirty=dirty)
2799
2802
2800 hexoutput = [hexfunc(p.node()) for p in parents]
2803 hexoutput = [hexfunc(p.node()) for p in parents]
2801 if default or id:
2804 if default or id:
2802 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2805 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2803 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2806 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2804
2807
2805 if num:
2808 if num:
2806 numoutput = ["%d" % p.rev() for p in parents]
2809 numoutput = ["%d" % p.rev() for p in parents]
2807 output.append("%s%s" % ('+'.join(numoutput), dirty))
2810 output.append("%s%s" % ('+'.join(numoutput), dirty))
2808
2811
2809 fn = fm.nested('parents')
2812 fn = fm.nested('parents')
2810 for p in parents:
2813 for p in parents:
2811 fn.startitem()
2814 fn.startitem()
2812 fn.data(rev=p.rev())
2815 fn.data(rev=p.rev())
2813 fn.data(node=p.hex())
2816 fn.data(node=p.hex())
2814 fn.context(ctx=p)
2817 fn.context(ctx=p)
2815 fn.end()
2818 fn.end()
2816 else:
2819 else:
2817 hexoutput = hexfunc(ctx.node())
2820 hexoutput = hexfunc(ctx.node())
2818 if default or id:
2821 if default or id:
2819 output = [hexoutput]
2822 output = [hexoutput]
2820 fm.data(id=hexoutput)
2823 fm.data(id=hexoutput)
2821
2824
2822 if num:
2825 if num:
2823 output.append(pycompat.bytestr(ctx.rev()))
2826 output.append(pycompat.bytestr(ctx.rev()))
2824 taglist = ctx.tags()
2827 taglist = ctx.tags()
2825
2828
2826 if default and not ui.quiet:
2829 if default and not ui.quiet:
2827 b = ctx.branch()
2830 b = ctx.branch()
2828 if b != 'default':
2831 if b != 'default':
2829 output.append("(%s)" % b)
2832 output.append("(%s)" % b)
2830
2833
2831 # multiple tags for a single parent separated by '/'
2834 # multiple tags for a single parent separated by '/'
2832 t = '/'.join(taglist)
2835 t = '/'.join(taglist)
2833 if t:
2836 if t:
2834 output.append(t)
2837 output.append(t)
2835
2838
2836 # multiple bookmarks for a single parent separated by '/'
2839 # multiple bookmarks for a single parent separated by '/'
2837 bm = '/'.join(ctx.bookmarks())
2840 bm = '/'.join(ctx.bookmarks())
2838 if bm:
2841 if bm:
2839 output.append(bm)
2842 output.append(bm)
2840 else:
2843 else:
2841 if branch:
2844 if branch:
2842 output.append(ctx.branch())
2845 output.append(ctx.branch())
2843
2846
2844 if tags:
2847 if tags:
2845 output.extend(taglist)
2848 output.extend(taglist)
2846
2849
2847 if bookmarks:
2850 if bookmarks:
2848 output.extend(ctx.bookmarks())
2851 output.extend(ctx.bookmarks())
2849
2852
2850 fm.data(node=ctx.hex())
2853 fm.data(node=ctx.hex())
2851 fm.data(branch=ctx.branch())
2854 fm.data(branch=ctx.branch())
2852 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2855 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2853 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2856 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2854 fm.context(ctx=ctx)
2857 fm.context(ctx=ctx)
2855
2858
2856 fm.plain("%s\n" % ' '.join(output))
2859 fm.plain("%s\n" % ' '.join(output))
2857 fm.end()
2860 fm.end()
2858
2861
2859 @command('import|patch',
2862 @command('import|patch',
2860 [('p', 'strip', 1,
2863 [('p', 'strip', 1,
2861 _('directory strip option for patch. This has the same '
2864 _('directory strip option for patch. This has the same '
2862 'meaning as the corresponding patch option'), _('NUM')),
2865 'meaning as the corresponding patch option'), _('NUM')),
2863 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2866 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2864 ('e', 'edit', False, _('invoke editor on commit messages')),
2867 ('e', 'edit', False, _('invoke editor on commit messages')),
2865 ('f', 'force', None,
2868 ('f', 'force', None,
2866 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2869 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2867 ('', 'no-commit', None,
2870 ('', 'no-commit', None,
2868 _("don't commit, just update the working directory")),
2871 _("don't commit, just update the working directory")),
2869 ('', 'bypass', None,
2872 ('', 'bypass', None,
2870 _("apply patch without touching the working directory")),
2873 _("apply patch without touching the working directory")),
2871 ('', 'partial', None,
2874 ('', 'partial', None,
2872 _('commit even if some hunks fail')),
2875 _('commit even if some hunks fail')),
2873 ('', 'exact', None,
2876 ('', 'exact', None,
2874 _('abort if patch would apply lossily')),
2877 _('abort if patch would apply lossily')),
2875 ('', 'prefix', '',
2878 ('', 'prefix', '',
2876 _('apply patch to subdirectory'), _('DIR')),
2879 _('apply patch to subdirectory'), _('DIR')),
2877 ('', 'import-branch', None,
2880 ('', 'import-branch', None,
2878 _('use any branch information in patch (implied by --exact)'))] +
2881 _('use any branch information in patch (implied by --exact)'))] +
2879 commitopts + commitopts2 + similarityopts,
2882 commitopts + commitopts2 + similarityopts,
2880 _('[OPTION]... PATCH...'))
2883 _('[OPTION]... PATCH...'))
2881 def import_(ui, repo, patch1=None, *patches, **opts):
2884 def import_(ui, repo, patch1=None, *patches, **opts):
2882 """import an ordered set of patches
2885 """import an ordered set of patches
2883
2886
2884 Import a list of patches and commit them individually (unless
2887 Import a list of patches and commit them individually (unless
2885 --no-commit is specified).
2888 --no-commit is specified).
2886
2889
2887 To read a patch from standard input (stdin), use "-" as the patch
2890 To read a patch from standard input (stdin), use "-" as the patch
2888 name. If a URL is specified, the patch will be downloaded from
2891 name. If a URL is specified, the patch will be downloaded from
2889 there.
2892 there.
2890
2893
2891 Import first applies changes to the working directory (unless
2894 Import first applies changes to the working directory (unless
2892 --bypass is specified), import will abort if there are outstanding
2895 --bypass is specified), import will abort if there are outstanding
2893 changes.
2896 changes.
2894
2897
2895 Use --bypass to apply and commit patches directly to the
2898 Use --bypass to apply and commit patches directly to the
2896 repository, without affecting the working directory. Without
2899 repository, without affecting the working directory. Without
2897 --exact, patches will be applied on top of the working directory
2900 --exact, patches will be applied on top of the working directory
2898 parent revision.
2901 parent revision.
2899
2902
2900 You can import a patch straight from a mail message. Even patches
2903 You can import a patch straight from a mail message. Even patches
2901 as attachments work (to use the body part, it must have type
2904 as attachments work (to use the body part, it must have type
2902 text/plain or text/x-patch). From and Subject headers of email
2905 text/plain or text/x-patch). From and Subject headers of email
2903 message are used as default committer and commit message. All
2906 message are used as default committer and commit message. All
2904 text/plain body parts before first diff are added to the commit
2907 text/plain body parts before first diff are added to the commit
2905 message.
2908 message.
2906
2909
2907 If the imported patch was generated by :hg:`export`, user and
2910 If the imported patch was generated by :hg:`export`, user and
2908 description from patch override values from message headers and
2911 description from patch override values from message headers and
2909 body. Values given on command line with -m/--message and -u/--user
2912 body. Values given on command line with -m/--message and -u/--user
2910 override these.
2913 override these.
2911
2914
2912 If --exact is specified, import will set the working directory to
2915 If --exact is specified, import will set the working directory to
2913 the parent of each patch before applying it, and will abort if the
2916 the parent of each patch before applying it, and will abort if the
2914 resulting changeset has a different ID than the one recorded in
2917 resulting changeset has a different ID than the one recorded in
2915 the patch. This will guard against various ways that portable
2918 the patch. This will guard against various ways that portable
2916 patch formats and mail systems might fail to transfer Mercurial
2919 patch formats and mail systems might fail to transfer Mercurial
2917 data or metadata. See :hg:`bundle` for lossless transmission.
2920 data or metadata. See :hg:`bundle` for lossless transmission.
2918
2921
2919 Use --partial to ensure a changeset will be created from the patch
2922 Use --partial to ensure a changeset will be created from the patch
2920 even if some hunks fail to apply. Hunks that fail to apply will be
2923 even if some hunks fail to apply. Hunks that fail to apply will be
2921 written to a <target-file>.rej file. Conflicts can then be resolved
2924 written to a <target-file>.rej file. Conflicts can then be resolved
2922 by hand before :hg:`commit --amend` is run to update the created
2925 by hand before :hg:`commit --amend` is run to update the created
2923 changeset. This flag exists to let people import patches that
2926 changeset. This flag exists to let people import patches that
2924 partially apply without losing the associated metadata (author,
2927 partially apply without losing the associated metadata (author,
2925 date, description, ...).
2928 date, description, ...).
2926
2929
2927 .. note::
2930 .. note::
2928
2931
2929 When no hunks apply cleanly, :hg:`import --partial` will create
2932 When no hunks apply cleanly, :hg:`import --partial` will create
2930 an empty changeset, importing only the patch metadata.
2933 an empty changeset, importing only the patch metadata.
2931
2934
2932 With -s/--similarity, hg will attempt to discover renames and
2935 With -s/--similarity, hg will attempt to discover renames and
2933 copies in the patch in the same way as :hg:`addremove`.
2936 copies in the patch in the same way as :hg:`addremove`.
2934
2937
2935 It is possible to use external patch programs to perform the patch
2938 It is possible to use external patch programs to perform the patch
2936 by setting the ``ui.patch`` configuration option. For the default
2939 by setting the ``ui.patch`` configuration option. For the default
2937 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2940 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2938 See :hg:`help config` for more information about configuration
2941 See :hg:`help config` for more information about configuration
2939 files and how to use these options.
2942 files and how to use these options.
2940
2943
2941 See :hg:`help dates` for a list of formats valid for -d/--date.
2944 See :hg:`help dates` for a list of formats valid for -d/--date.
2942
2945
2943 .. container:: verbose
2946 .. container:: verbose
2944
2947
2945 Examples:
2948 Examples:
2946
2949
2947 - import a traditional patch from a website and detect renames::
2950 - import a traditional patch from a website and detect renames::
2948
2951
2949 hg import -s 80 http://example.com/bugfix.patch
2952 hg import -s 80 http://example.com/bugfix.patch
2950
2953
2951 - import a changeset from an hgweb server::
2954 - import a changeset from an hgweb server::
2952
2955
2953 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2956 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2954
2957
2955 - import all the patches in an Unix-style mbox::
2958 - import all the patches in an Unix-style mbox::
2956
2959
2957 hg import incoming-patches.mbox
2960 hg import incoming-patches.mbox
2958
2961
2959 - import patches from stdin::
2962 - import patches from stdin::
2960
2963
2961 hg import -
2964 hg import -
2962
2965
2963 - attempt to exactly restore an exported changeset (not always
2966 - attempt to exactly restore an exported changeset (not always
2964 possible)::
2967 possible)::
2965
2968
2966 hg import --exact proposed-fix.patch
2969 hg import --exact proposed-fix.patch
2967
2970
2968 - use an external tool to apply a patch which is too fuzzy for
2971 - use an external tool to apply a patch which is too fuzzy for
2969 the default internal tool.
2972 the default internal tool.
2970
2973
2971 hg import --config ui.patch="patch --merge" fuzzy.patch
2974 hg import --config ui.patch="patch --merge" fuzzy.patch
2972
2975
2973 - change the default fuzzing from 2 to a less strict 7
2976 - change the default fuzzing from 2 to a less strict 7
2974
2977
2975 hg import --config ui.fuzz=7 fuzz.patch
2978 hg import --config ui.fuzz=7 fuzz.patch
2976
2979
2977 Returns 0 on success, 1 on partial success (see --partial).
2980 Returns 0 on success, 1 on partial success (see --partial).
2978 """
2981 """
2979
2982
2980 opts = pycompat.byteskwargs(opts)
2983 opts = pycompat.byteskwargs(opts)
2981 if not patch1:
2984 if not patch1:
2982 raise error.Abort(_('need at least one patch to import'))
2985 raise error.Abort(_('need at least one patch to import'))
2983
2986
2984 patches = (patch1,) + patches
2987 patches = (patch1,) + patches
2985
2988
2986 date = opts.get('date')
2989 date = opts.get('date')
2987 if date:
2990 if date:
2988 opts['date'] = util.parsedate(date)
2991 opts['date'] = util.parsedate(date)
2989
2992
2990 exact = opts.get('exact')
2993 exact = opts.get('exact')
2991 update = not opts.get('bypass')
2994 update = not opts.get('bypass')
2992 if not update and opts.get('no_commit'):
2995 if not update and opts.get('no_commit'):
2993 raise error.Abort(_('cannot use --no-commit with --bypass'))
2996 raise error.Abort(_('cannot use --no-commit with --bypass'))
2994 try:
2997 try:
2995 sim = float(opts.get('similarity') or 0)
2998 sim = float(opts.get('similarity') or 0)
2996 except ValueError:
2999 except ValueError:
2997 raise error.Abort(_('similarity must be a number'))
3000 raise error.Abort(_('similarity must be a number'))
2998 if sim < 0 or sim > 100:
3001 if sim < 0 or sim > 100:
2999 raise error.Abort(_('similarity must be between 0 and 100'))
3002 raise error.Abort(_('similarity must be between 0 and 100'))
3000 if sim and not update:
3003 if sim and not update:
3001 raise error.Abort(_('cannot use --similarity with --bypass'))
3004 raise error.Abort(_('cannot use --similarity with --bypass'))
3002 if exact:
3005 if exact:
3003 if opts.get('edit'):
3006 if opts.get('edit'):
3004 raise error.Abort(_('cannot use --exact with --edit'))
3007 raise error.Abort(_('cannot use --exact with --edit'))
3005 if opts.get('prefix'):
3008 if opts.get('prefix'):
3006 raise error.Abort(_('cannot use --exact with --prefix'))
3009 raise error.Abort(_('cannot use --exact with --prefix'))
3007
3010
3008 base = opts["base"]
3011 base = opts["base"]
3009 wlock = dsguard = lock = tr = None
3012 wlock = dsguard = lock = tr = None
3010 msgs = []
3013 msgs = []
3011 ret = 0
3014 ret = 0
3012
3015
3013
3016
3014 try:
3017 try:
3015 wlock = repo.wlock()
3018 wlock = repo.wlock()
3016
3019
3017 if update:
3020 if update:
3018 cmdutil.checkunfinished(repo)
3021 cmdutil.checkunfinished(repo)
3019 if (exact or not opts.get('force')):
3022 if (exact or not opts.get('force')):
3020 cmdutil.bailifchanged(repo)
3023 cmdutil.bailifchanged(repo)
3021
3024
3022 if not opts.get('no_commit'):
3025 if not opts.get('no_commit'):
3023 lock = repo.lock()
3026 lock = repo.lock()
3024 tr = repo.transaction('import')
3027 tr = repo.transaction('import')
3025 else:
3028 else:
3026 dsguard = dirstateguard.dirstateguard(repo, 'import')
3029 dsguard = dirstateguard.dirstateguard(repo, 'import')
3027 parents = repo[None].parents()
3030 parents = repo[None].parents()
3028 for patchurl in patches:
3031 for patchurl in patches:
3029 if patchurl == '-':
3032 if patchurl == '-':
3030 ui.status(_('applying patch from stdin\n'))
3033 ui.status(_('applying patch from stdin\n'))
3031 patchfile = ui.fin
3034 patchfile = ui.fin
3032 patchurl = 'stdin' # for error message
3035 patchurl = 'stdin' # for error message
3033 else:
3036 else:
3034 patchurl = os.path.join(base, patchurl)
3037 patchurl = os.path.join(base, patchurl)
3035 ui.status(_('applying %s\n') % patchurl)
3038 ui.status(_('applying %s\n') % patchurl)
3036 patchfile = hg.openpath(ui, patchurl)
3039 patchfile = hg.openpath(ui, patchurl)
3037
3040
3038 haspatch = False
3041 haspatch = False
3039 for hunk in patch.split(patchfile):
3042 for hunk in patch.split(patchfile):
3040 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3043 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3041 parents, opts,
3044 parents, opts,
3042 msgs, hg.clean)
3045 msgs, hg.clean)
3043 if msg:
3046 if msg:
3044 haspatch = True
3047 haspatch = True
3045 ui.note(msg + '\n')
3048 ui.note(msg + '\n')
3046 if update or exact:
3049 if update or exact:
3047 parents = repo[None].parents()
3050 parents = repo[None].parents()
3048 else:
3051 else:
3049 parents = [repo[node]]
3052 parents = [repo[node]]
3050 if rej:
3053 if rej:
3051 ui.write_err(_("patch applied partially\n"))
3054 ui.write_err(_("patch applied partially\n"))
3052 ui.write_err(_("(fix the .rej files and run "
3055 ui.write_err(_("(fix the .rej files and run "
3053 "`hg commit --amend`)\n"))
3056 "`hg commit --amend`)\n"))
3054 ret = 1
3057 ret = 1
3055 break
3058 break
3056
3059
3057 if not haspatch:
3060 if not haspatch:
3058 raise error.Abort(_('%s: no diffs found') % patchurl)
3061 raise error.Abort(_('%s: no diffs found') % patchurl)
3059
3062
3060 if tr:
3063 if tr:
3061 tr.close()
3064 tr.close()
3062 if msgs:
3065 if msgs:
3063 repo.savecommitmessage('\n* * *\n'.join(msgs))
3066 repo.savecommitmessage('\n* * *\n'.join(msgs))
3064 if dsguard:
3067 if dsguard:
3065 dsguard.close()
3068 dsguard.close()
3066 return ret
3069 return ret
3067 finally:
3070 finally:
3068 if tr:
3071 if tr:
3069 tr.release()
3072 tr.release()
3070 release(lock, dsguard, wlock)
3073 release(lock, dsguard, wlock)
3071
3074
3072 @command('incoming|in',
3075 @command('incoming|in',
3073 [('f', 'force', None,
3076 [('f', 'force', None,
3074 _('run even if remote repository is unrelated')),
3077 _('run even if remote repository is unrelated')),
3075 ('n', 'newest-first', None, _('show newest record first')),
3078 ('n', 'newest-first', None, _('show newest record first')),
3076 ('', 'bundle', '',
3079 ('', 'bundle', '',
3077 _('file to store the bundles into'), _('FILE')),
3080 _('file to store the bundles into'), _('FILE')),
3078 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3081 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3079 ('B', 'bookmarks', False, _("compare bookmarks")),
3082 ('B', 'bookmarks', False, _("compare bookmarks")),
3080 ('b', 'branch', [],
3083 ('b', 'branch', [],
3081 _('a specific branch you would like to pull'), _('BRANCH')),
3084 _('a specific branch you would like to pull'), _('BRANCH')),
3082 ] + logopts + remoteopts + subrepoopts,
3085 ] + logopts + remoteopts + subrepoopts,
3083 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3086 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3084 def incoming(ui, repo, source="default", **opts):
3087 def incoming(ui, repo, source="default", **opts):
3085 """show new changesets found in source
3088 """show new changesets found in source
3086
3089
3087 Show new changesets found in the specified path/URL or the default
3090 Show new changesets found in the specified path/URL or the default
3088 pull location. These are the changesets that would have been pulled
3091 pull location. These are the changesets that would have been pulled
3089 by :hg:`pull` at the time you issued this command.
3092 by :hg:`pull` at the time you issued this command.
3090
3093
3091 See pull for valid source format details.
3094 See pull for valid source format details.
3092
3095
3093 .. container:: verbose
3096 .. container:: verbose
3094
3097
3095 With -B/--bookmarks, the result of bookmark comparison between
3098 With -B/--bookmarks, the result of bookmark comparison between
3096 local and remote repositories is displayed. With -v/--verbose,
3099 local and remote repositories is displayed. With -v/--verbose,
3097 status is also displayed for each bookmark like below::
3100 status is also displayed for each bookmark like below::
3098
3101
3099 BM1 01234567890a added
3102 BM1 01234567890a added
3100 BM2 1234567890ab advanced
3103 BM2 1234567890ab advanced
3101 BM3 234567890abc diverged
3104 BM3 234567890abc diverged
3102 BM4 34567890abcd changed
3105 BM4 34567890abcd changed
3103
3106
3104 The action taken locally when pulling depends on the
3107 The action taken locally when pulling depends on the
3105 status of each bookmark:
3108 status of each bookmark:
3106
3109
3107 :``added``: pull will create it
3110 :``added``: pull will create it
3108 :``advanced``: pull will update it
3111 :``advanced``: pull will update it
3109 :``diverged``: pull will create a divergent bookmark
3112 :``diverged``: pull will create a divergent bookmark
3110 :``changed``: result depends on remote changesets
3113 :``changed``: result depends on remote changesets
3111
3114
3112 From the point of view of pulling behavior, bookmark
3115 From the point of view of pulling behavior, bookmark
3113 existing only in the remote repository are treated as ``added``,
3116 existing only in the remote repository are treated as ``added``,
3114 even if it is in fact locally deleted.
3117 even if it is in fact locally deleted.
3115
3118
3116 .. container:: verbose
3119 .. container:: verbose
3117
3120
3118 For remote repository, using --bundle avoids downloading the
3121 For remote repository, using --bundle avoids downloading the
3119 changesets twice if the incoming is followed by a pull.
3122 changesets twice if the incoming is followed by a pull.
3120
3123
3121 Examples:
3124 Examples:
3122
3125
3123 - show incoming changes with patches and full description::
3126 - show incoming changes with patches and full description::
3124
3127
3125 hg incoming -vp
3128 hg incoming -vp
3126
3129
3127 - show incoming changes excluding merges, store a bundle::
3130 - show incoming changes excluding merges, store a bundle::
3128
3131
3129 hg in -vpM --bundle incoming.hg
3132 hg in -vpM --bundle incoming.hg
3130 hg pull incoming.hg
3133 hg pull incoming.hg
3131
3134
3132 - briefly list changes inside a bundle::
3135 - briefly list changes inside a bundle::
3133
3136
3134 hg in changes.hg -T "{desc|firstline}\\n"
3137 hg in changes.hg -T "{desc|firstline}\\n"
3135
3138
3136 Returns 0 if there are incoming changes, 1 otherwise.
3139 Returns 0 if there are incoming changes, 1 otherwise.
3137 """
3140 """
3138 opts = pycompat.byteskwargs(opts)
3141 opts = pycompat.byteskwargs(opts)
3139 if opts.get('graph'):
3142 if opts.get('graph'):
3140 cmdutil.checkunsupportedgraphflags([], opts)
3143 cmdutil.checkunsupportedgraphflags([], opts)
3141 def display(other, chlist, displayer):
3144 def display(other, chlist, displayer):
3142 revdag = cmdutil.graphrevs(other, chlist, opts)
3145 revdag = cmdutil.graphrevs(other, chlist, opts)
3143 cmdutil.displaygraph(ui, repo, revdag, displayer,
3146 cmdutil.displaygraph(ui, repo, revdag, displayer,
3144 graphmod.asciiedges)
3147 graphmod.asciiedges)
3145
3148
3146 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3149 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3147 return 0
3150 return 0
3148
3151
3149 if opts.get('bundle') and opts.get('subrepos'):
3152 if opts.get('bundle') and opts.get('subrepos'):
3150 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3153 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3151
3154
3152 if opts.get('bookmarks'):
3155 if opts.get('bookmarks'):
3153 source, branches = hg.parseurl(ui.expandpath(source),
3156 source, branches = hg.parseurl(ui.expandpath(source),
3154 opts.get('branch'))
3157 opts.get('branch'))
3155 other = hg.peer(repo, opts, source)
3158 other = hg.peer(repo, opts, source)
3156 if 'bookmarks' not in other.listkeys('namespaces'):
3159 if 'bookmarks' not in other.listkeys('namespaces'):
3157 ui.warn(_("remote doesn't support bookmarks\n"))
3160 ui.warn(_("remote doesn't support bookmarks\n"))
3158 return 0
3161 return 0
3159 ui.pager('incoming')
3162 ui.pager('incoming')
3160 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3163 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3161 return bookmarks.incoming(ui, repo, other)
3164 return bookmarks.incoming(ui, repo, other)
3162
3165
3163 repo._subtoppath = ui.expandpath(source)
3166 repo._subtoppath = ui.expandpath(source)
3164 try:
3167 try:
3165 return hg.incoming(ui, repo, source, opts)
3168 return hg.incoming(ui, repo, source, opts)
3166 finally:
3169 finally:
3167 del repo._subtoppath
3170 del repo._subtoppath
3168
3171
3169
3172
3170 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3173 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3171 norepo=True)
3174 norepo=True)
3172 def init(ui, dest=".", **opts):
3175 def init(ui, dest=".", **opts):
3173 """create a new repository in the given directory
3176 """create a new repository in the given directory
3174
3177
3175 Initialize a new repository in the given directory. If the given
3178 Initialize a new repository in the given directory. If the given
3176 directory does not exist, it will be created.
3179 directory does not exist, it will be created.
3177
3180
3178 If no directory is given, the current directory is used.
3181 If no directory is given, the current directory is used.
3179
3182
3180 It is possible to specify an ``ssh://`` URL as the destination.
3183 It is possible to specify an ``ssh://`` URL as the destination.
3181 See :hg:`help urls` for more information.
3184 See :hg:`help urls` for more information.
3182
3185
3183 Returns 0 on success.
3186 Returns 0 on success.
3184 """
3187 """
3185 opts = pycompat.byteskwargs(opts)
3188 opts = pycompat.byteskwargs(opts)
3186 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3189 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3187
3190
3188 @command('locate',
3191 @command('locate',
3189 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3192 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3190 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3193 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3191 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3194 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3192 ] + walkopts,
3195 ] + walkopts,
3193 _('[OPTION]... [PATTERN]...'))
3196 _('[OPTION]... [PATTERN]...'))
3194 def locate(ui, repo, *pats, **opts):
3197 def locate(ui, repo, *pats, **opts):
3195 """locate files matching specific patterns (DEPRECATED)
3198 """locate files matching specific patterns (DEPRECATED)
3196
3199
3197 Print files under Mercurial control in the working directory whose
3200 Print files under Mercurial control in the working directory whose
3198 names match the given patterns.
3201 names match the given patterns.
3199
3202
3200 By default, this command searches all directories in the working
3203 By default, this command searches all directories in the working
3201 directory. To search just the current directory and its
3204 directory. To search just the current directory and its
3202 subdirectories, use "--include .".
3205 subdirectories, use "--include .".
3203
3206
3204 If no patterns are given to match, this command prints the names
3207 If no patterns are given to match, this command prints the names
3205 of all files under Mercurial control in the working directory.
3208 of all files under Mercurial control in the working directory.
3206
3209
3207 If you want to feed the output of this command into the "xargs"
3210 If you want to feed the output of this command into the "xargs"
3208 command, use the -0 option to both this command and "xargs". This
3211 command, use the -0 option to both this command and "xargs". This
3209 will avoid the problem of "xargs" treating single filenames that
3212 will avoid the problem of "xargs" treating single filenames that
3210 contain whitespace as multiple filenames.
3213 contain whitespace as multiple filenames.
3211
3214
3212 See :hg:`help files` for a more versatile command.
3215 See :hg:`help files` for a more versatile command.
3213
3216
3214 Returns 0 if a match is found, 1 otherwise.
3217 Returns 0 if a match is found, 1 otherwise.
3215 """
3218 """
3216 opts = pycompat.byteskwargs(opts)
3219 opts = pycompat.byteskwargs(opts)
3217 if opts.get('print0'):
3220 if opts.get('print0'):
3218 end = '\0'
3221 end = '\0'
3219 else:
3222 else:
3220 end = '\n'
3223 end = '\n'
3221 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3224 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3222
3225
3223 ret = 1
3226 ret = 1
3224 ctx = repo[rev]
3227 ctx = repo[rev]
3225 m = scmutil.match(ctx, pats, opts, default='relglob',
3228 m = scmutil.match(ctx, pats, opts, default='relglob',
3226 badfn=lambda x, y: False)
3229 badfn=lambda x, y: False)
3227
3230
3228 ui.pager('locate')
3231 ui.pager('locate')
3229 for abs in ctx.matches(m):
3232 for abs in ctx.matches(m):
3230 if opts.get('fullpath'):
3233 if opts.get('fullpath'):
3231 ui.write(repo.wjoin(abs), end)
3234 ui.write(repo.wjoin(abs), end)
3232 else:
3235 else:
3233 ui.write(((pats and m.rel(abs)) or abs), end)
3236 ui.write(((pats and m.rel(abs)) or abs), end)
3234 ret = 0
3237 ret = 0
3235
3238
3236 return ret
3239 return ret
3237
3240
3238 @command('^log|history',
3241 @command('^log|history',
3239 [('f', 'follow', None,
3242 [('f', 'follow', None,
3240 _('follow changeset history, or file history across copies and renames')),
3243 _('follow changeset history, or file history across copies and renames')),
3241 ('', 'follow-first', None,
3244 ('', 'follow-first', None,
3242 _('only follow the first parent of merge changesets (DEPRECATED)')),
3245 _('only follow the first parent of merge changesets (DEPRECATED)')),
3243 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3246 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3244 ('C', 'copies', None, _('show copied files')),
3247 ('C', 'copies', None, _('show copied files')),
3245 ('k', 'keyword', [],
3248 ('k', 'keyword', [],
3246 _('do case-insensitive search for a given text'), _('TEXT')),
3249 _('do case-insensitive search for a given text'), _('TEXT')),
3247 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3250 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3248 ('L', 'line-range', [],
3251 ('L', 'line-range', [],
3249 _('follow line range of specified file (EXPERIMENTAL)'),
3252 _('follow line range of specified file (EXPERIMENTAL)'),
3250 _('FILE,RANGE')),
3253 _('FILE,RANGE')),
3251 ('', 'removed', None, _('include revisions where files were removed')),
3254 ('', 'removed', None, _('include revisions where files were removed')),
3252 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3255 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3253 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3256 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3254 ('', 'only-branch', [],
3257 ('', 'only-branch', [],
3255 _('show only changesets within the given named branch (DEPRECATED)'),
3258 _('show only changesets within the given named branch (DEPRECATED)'),
3256 _('BRANCH')),
3259 _('BRANCH')),
3257 ('b', 'branch', [],
3260 ('b', 'branch', [],
3258 _('show changesets within the given named branch'), _('BRANCH')),
3261 _('show changesets within the given named branch'), _('BRANCH')),
3259 ('P', 'prune', [],
3262 ('P', 'prune', [],
3260 _('do not display revision or any of its ancestors'), _('REV')),
3263 _('do not display revision or any of its ancestors'), _('REV')),
3261 ] + logopts + walkopts,
3264 ] + logopts + walkopts,
3262 _('[OPTION]... [FILE]'),
3265 _('[OPTION]... [FILE]'),
3263 inferrepo=True, cmdtype=readonly)
3266 inferrepo=True, cmdtype=readonly)
3264 def log(ui, repo, *pats, **opts):
3267 def log(ui, repo, *pats, **opts):
3265 """show revision history of entire repository or files
3268 """show revision history of entire repository or files
3266
3269
3267 Print the revision history of the specified files or the entire
3270 Print the revision history of the specified files or the entire
3268 project.
3271 project.
3269
3272
3270 If no revision range is specified, the default is ``tip:0`` unless
3273 If no revision range is specified, the default is ``tip:0`` unless
3271 --follow is set, in which case the working directory parent is
3274 --follow is set, in which case the working directory parent is
3272 used as the starting revision.
3275 used as the starting revision.
3273
3276
3274 File history is shown without following rename or copy history of
3277 File history is shown without following rename or copy history of
3275 files. Use -f/--follow with a filename to follow history across
3278 files. Use -f/--follow with a filename to follow history across
3276 renames and copies. --follow without a filename will only show
3279 renames and copies. --follow without a filename will only show
3277 ancestors or descendants of the starting revision.
3280 ancestors or descendants of the starting revision.
3278
3281
3279 By default this command prints revision number and changeset id,
3282 By default this command prints revision number and changeset id,
3280 tags, non-trivial parents, user, date and time, and a summary for
3283 tags, non-trivial parents, user, date and time, and a summary for
3281 each commit. When the -v/--verbose switch is used, the list of
3284 each commit. When the -v/--verbose switch is used, the list of
3282 changed files and full commit message are shown.
3285 changed files and full commit message are shown.
3283
3286
3284 With --graph the revisions are shown as an ASCII art DAG with the most
3287 With --graph the revisions are shown as an ASCII art DAG with the most
3285 recent changeset at the top.
3288 recent changeset at the top.
3286 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3289 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3287 and '+' represents a fork where the changeset from the lines below is a
3290 and '+' represents a fork where the changeset from the lines below is a
3288 parent of the 'o' merge on the same line.
3291 parent of the 'o' merge on the same line.
3289 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3292 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3290 of a '|' indicates one or more revisions in a path are omitted.
3293 of a '|' indicates one or more revisions in a path are omitted.
3291
3294
3292 .. container:: verbose
3295 .. container:: verbose
3293
3296
3294 Use -L/--line-range FILE,M:N options to follow the history of lines
3297 Use -L/--line-range FILE,M:N options to follow the history of lines
3295 from M to N in FILE. With -p/--patch only diff hunks affecting
3298 from M to N in FILE. With -p/--patch only diff hunks affecting
3296 specified line range will be shown. This option requires --follow;
3299 specified line range will be shown. This option requires --follow;
3297 it can be specified multiple times. Currently, this option is not
3300 it can be specified multiple times. Currently, this option is not
3298 compatible with --graph. This option is experimental.
3301 compatible with --graph. This option is experimental.
3299
3302
3300 .. note::
3303 .. note::
3301
3304
3302 :hg:`log --patch` may generate unexpected diff output for merge
3305 :hg:`log --patch` may generate unexpected diff output for merge
3303 changesets, as it will only compare the merge changeset against
3306 changesets, as it will only compare the merge changeset against
3304 its first parent. Also, only files different from BOTH parents
3307 its first parent. Also, only files different from BOTH parents
3305 will appear in files:.
3308 will appear in files:.
3306
3309
3307 .. note::
3310 .. note::
3308
3311
3309 For performance reasons, :hg:`log FILE` may omit duplicate changes
3312 For performance reasons, :hg:`log FILE` may omit duplicate changes
3310 made on branches and will not show removals or mode changes. To
3313 made on branches and will not show removals or mode changes. To
3311 see all such changes, use the --removed switch.
3314 see all such changes, use the --removed switch.
3312
3315
3313 .. container:: verbose
3316 .. container:: verbose
3314
3317
3315 .. note::
3318 .. note::
3316
3319
3317 The history resulting from -L/--line-range options depends on diff
3320 The history resulting from -L/--line-range options depends on diff
3318 options; for instance if white-spaces are ignored, respective changes
3321 options; for instance if white-spaces are ignored, respective changes
3319 with only white-spaces in specified line range will not be listed.
3322 with only white-spaces in specified line range will not be listed.
3320
3323
3321 .. container:: verbose
3324 .. container:: verbose
3322
3325
3323 Some examples:
3326 Some examples:
3324
3327
3325 - changesets with full descriptions and file lists::
3328 - changesets with full descriptions and file lists::
3326
3329
3327 hg log -v
3330 hg log -v
3328
3331
3329 - changesets ancestral to the working directory::
3332 - changesets ancestral to the working directory::
3330
3333
3331 hg log -f
3334 hg log -f
3332
3335
3333 - last 10 commits on the current branch::
3336 - last 10 commits on the current branch::
3334
3337
3335 hg log -l 10 -b .
3338 hg log -l 10 -b .
3336
3339
3337 - changesets showing all modifications of a file, including removals::
3340 - changesets showing all modifications of a file, including removals::
3338
3341
3339 hg log --removed file.c
3342 hg log --removed file.c
3340
3343
3341 - all changesets that touch a directory, with diffs, excluding merges::
3344 - all changesets that touch a directory, with diffs, excluding merges::
3342
3345
3343 hg log -Mp lib/
3346 hg log -Mp lib/
3344
3347
3345 - all revision numbers that match a keyword::
3348 - all revision numbers that match a keyword::
3346
3349
3347 hg log -k bug --template "{rev}\\n"
3350 hg log -k bug --template "{rev}\\n"
3348
3351
3349 - the full hash identifier of the working directory parent::
3352 - the full hash identifier of the working directory parent::
3350
3353
3351 hg log -r . --template "{node}\\n"
3354 hg log -r . --template "{node}\\n"
3352
3355
3353 - list available log templates::
3356 - list available log templates::
3354
3357
3355 hg log -T list
3358 hg log -T list
3356
3359
3357 - check if a given changeset is included in a tagged release::
3360 - check if a given changeset is included in a tagged release::
3358
3361
3359 hg log -r "a21ccf and ancestor(1.9)"
3362 hg log -r "a21ccf and ancestor(1.9)"
3360
3363
3361 - find all changesets by some user in a date range::
3364 - find all changesets by some user in a date range::
3362
3365
3363 hg log -k alice -d "may 2008 to jul 2008"
3366 hg log -k alice -d "may 2008 to jul 2008"
3364
3367
3365 - summary of all changesets after the last tag::
3368 - summary of all changesets after the last tag::
3366
3369
3367 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3370 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3368
3371
3369 - changesets touching lines 13 to 23 for file.c::
3372 - changesets touching lines 13 to 23 for file.c::
3370
3373
3371 hg log -L file.c,13:23
3374 hg log -L file.c,13:23
3372
3375
3373 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3376 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3374 main.c with patch::
3377 main.c with patch::
3375
3378
3376 hg log -L file.c,13:23 -L main.c,2:6 -p
3379 hg log -L file.c,13:23 -L main.c,2:6 -p
3377
3380
3378 See :hg:`help dates` for a list of formats valid for -d/--date.
3381 See :hg:`help dates` for a list of formats valid for -d/--date.
3379
3382
3380 See :hg:`help revisions` for more about specifying and ordering
3383 See :hg:`help revisions` for more about specifying and ordering
3381 revisions.
3384 revisions.
3382
3385
3383 See :hg:`help templates` for more about pre-packaged styles and
3386 See :hg:`help templates` for more about pre-packaged styles and
3384 specifying custom templates. The default template used by the log
3387 specifying custom templates. The default template used by the log
3385 command can be customized via the ``ui.logtemplate`` configuration
3388 command can be customized via the ``ui.logtemplate`` configuration
3386 setting.
3389 setting.
3387
3390
3388 Returns 0 on success.
3391 Returns 0 on success.
3389
3392
3390 """
3393 """
3391 opts = pycompat.byteskwargs(opts)
3394 opts = pycompat.byteskwargs(opts)
3392 linerange = opts.get('line_range')
3395 linerange = opts.get('line_range')
3393
3396
3394 if linerange and not opts.get('follow'):
3397 if linerange and not opts.get('follow'):
3395 raise error.Abort(_('--line-range requires --follow'))
3398 raise error.Abort(_('--line-range requires --follow'))
3396
3399
3397 if linerange and pats:
3400 if linerange and pats:
3398 raise error.Abort(
3401 raise error.Abort(
3399 _('FILE arguments are not compatible with --line-range option')
3402 _('FILE arguments are not compatible with --line-range option')
3400 )
3403 )
3401
3404
3402 if opts.get('follow') and opts.get('rev'):
3405 if opts.get('follow') and opts.get('rev'):
3403 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3406 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3404 del opts['follow']
3407 del opts['follow']
3405
3408
3406 if opts.get('graph'):
3409 if opts.get('graph'):
3407 if linerange:
3410 if linerange:
3408 raise error.Abort(_('graph not supported with line range patterns'))
3411 raise error.Abort(_('graph not supported with line range patterns'))
3409 return cmdutil.graphlog(ui, repo, pats, opts)
3412 return cmdutil.graphlog(ui, repo, pats, opts)
3410
3413
3411 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3414 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3412 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3415 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3413 hunksfilter = None
3416 hunksfilter = None
3414
3417
3415 if linerange:
3418 if linerange:
3416 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3419 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3417 repo, revs, opts)
3420 repo, revs, opts)
3418
3421
3419 if filematcher is not None and lrfilematcher is not None:
3422 if filematcher is not None and lrfilematcher is not None:
3420 basefilematcher = filematcher
3423 basefilematcher = filematcher
3421
3424
3422 def filematcher(rev):
3425 def filematcher(rev):
3423 files = (basefilematcher(rev).files()
3426 files = (basefilematcher(rev).files()
3424 + lrfilematcher(rev).files())
3427 + lrfilematcher(rev).files())
3425 return scmutil.matchfiles(repo, files)
3428 return scmutil.matchfiles(repo, files)
3426
3429
3427 elif filematcher is None:
3430 elif filematcher is None:
3428 filematcher = lrfilematcher
3431 filematcher = lrfilematcher
3429
3432
3430 limit = cmdutil.loglimit(opts)
3433 limit = cmdutil.loglimit(opts)
3431 count = 0
3434 count = 0
3432
3435
3433 getrenamed = None
3436 getrenamed = None
3434 if opts.get('copies'):
3437 if opts.get('copies'):
3435 endrev = None
3438 endrev = None
3436 if opts.get('rev'):
3439 if opts.get('rev'):
3437 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3440 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3438 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3441 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3439
3442
3440 ui.pager('log')
3443 ui.pager('log')
3441 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3444 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3442 for rev in revs:
3445 for rev in revs:
3443 if count == limit:
3446 if count == limit:
3444 break
3447 break
3445 ctx = repo[rev]
3448 ctx = repo[rev]
3446 copies = None
3449 copies = None
3447 if getrenamed is not None and rev:
3450 if getrenamed is not None and rev:
3448 copies = []
3451 copies = []
3449 for fn in ctx.files():
3452 for fn in ctx.files():
3450 rename = getrenamed(fn, rev)
3453 rename = getrenamed(fn, rev)
3451 if rename:
3454 if rename:
3452 copies.append((fn, rename[0]))
3455 copies.append((fn, rename[0]))
3453 if filematcher:
3456 if filematcher:
3454 revmatchfn = filematcher(ctx.rev())
3457 revmatchfn = filematcher(ctx.rev())
3455 else:
3458 else:
3456 revmatchfn = None
3459 revmatchfn = None
3457 if hunksfilter:
3460 if hunksfilter:
3458 revhunksfilter = hunksfilter(rev)
3461 revhunksfilter = hunksfilter(rev)
3459 else:
3462 else:
3460 revhunksfilter = None
3463 revhunksfilter = None
3461 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3464 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3462 hunksfilterfn=revhunksfilter)
3465 hunksfilterfn=revhunksfilter)
3463 if displayer.flush(ctx):
3466 if displayer.flush(ctx):
3464 count += 1
3467 count += 1
3465
3468
3466 displayer.close()
3469 displayer.close()
3467
3470
3468 @command('manifest',
3471 @command('manifest',
3469 [('r', 'rev', '', _('revision to display'), _('REV')),
3472 [('r', 'rev', '', _('revision to display'), _('REV')),
3470 ('', 'all', False, _("list files from all revisions"))]
3473 ('', 'all', False, _("list files from all revisions"))]
3471 + formatteropts,
3474 + formatteropts,
3472 _('[-r REV]'), cmdtype=readonly)
3475 _('[-r REV]'), cmdtype=readonly)
3473 def manifest(ui, repo, node=None, rev=None, **opts):
3476 def manifest(ui, repo, node=None, rev=None, **opts):
3474 """output the current or given revision of the project manifest
3477 """output the current or given revision of the project manifest
3475
3478
3476 Print a list of version controlled files for the given revision.
3479 Print a list of version controlled files for the given revision.
3477 If no revision is given, the first parent of the working directory
3480 If no revision is given, the first parent of the working directory
3478 is used, or the null revision if no revision is checked out.
3481 is used, or the null revision if no revision is checked out.
3479
3482
3480 With -v, print file permissions, symlink and executable bits.
3483 With -v, print file permissions, symlink and executable bits.
3481 With --debug, print file revision hashes.
3484 With --debug, print file revision hashes.
3482
3485
3483 If option --all is specified, the list of all files from all revisions
3486 If option --all is specified, the list of all files from all revisions
3484 is printed. This includes deleted and renamed files.
3487 is printed. This includes deleted and renamed files.
3485
3488
3486 Returns 0 on success.
3489 Returns 0 on success.
3487 """
3490 """
3488 opts = pycompat.byteskwargs(opts)
3491 opts = pycompat.byteskwargs(opts)
3489 fm = ui.formatter('manifest', opts)
3492 fm = ui.formatter('manifest', opts)
3490
3493
3491 if opts.get('all'):
3494 if opts.get('all'):
3492 if rev or node:
3495 if rev or node:
3493 raise error.Abort(_("can't specify a revision with --all"))
3496 raise error.Abort(_("can't specify a revision with --all"))
3494
3497
3495 res = []
3498 res = []
3496 prefix = "data/"
3499 prefix = "data/"
3497 suffix = ".i"
3500 suffix = ".i"
3498 plen = len(prefix)
3501 plen = len(prefix)
3499 slen = len(suffix)
3502 slen = len(suffix)
3500 with repo.lock():
3503 with repo.lock():
3501 for fn, b, size in repo.store.datafiles():
3504 for fn, b, size in repo.store.datafiles():
3502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3505 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3503 res.append(fn[plen:-slen])
3506 res.append(fn[plen:-slen])
3504 ui.pager('manifest')
3507 ui.pager('manifest')
3505 for f in res:
3508 for f in res:
3506 fm.startitem()
3509 fm.startitem()
3507 fm.write("path", '%s\n', f)
3510 fm.write("path", '%s\n', f)
3508 fm.end()
3511 fm.end()
3509 return
3512 return
3510
3513
3511 if rev and node:
3514 if rev and node:
3512 raise error.Abort(_("please specify just one revision"))
3515 raise error.Abort(_("please specify just one revision"))
3513
3516
3514 if not node:
3517 if not node:
3515 node = rev
3518 node = rev
3516
3519
3517 char = {'l': '@', 'x': '*', '': ''}
3520 char = {'l': '@', 'x': '*', '': ''}
3518 mode = {'l': '644', 'x': '755', '': '644'}
3521 mode = {'l': '644', 'x': '755', '': '644'}
3519 if node:
3522 if node:
3520 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3523 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3521 ctx = scmutil.revsingle(repo, node)
3524 ctx = scmutil.revsingle(repo, node)
3522 mf = ctx.manifest()
3525 mf = ctx.manifest()
3523 ui.pager('manifest')
3526 ui.pager('manifest')
3524 for f in ctx:
3527 for f in ctx:
3525 fm.startitem()
3528 fm.startitem()
3526 fl = ctx[f].flags()
3529 fl = ctx[f].flags()
3527 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3530 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3528 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3531 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3529 fm.write('path', '%s\n', f)
3532 fm.write('path', '%s\n', f)
3530 fm.end()
3533 fm.end()
3531
3534
3532 @command('^merge',
3535 @command('^merge',
3533 [('f', 'force', None,
3536 [('f', 'force', None,
3534 _('force a merge including outstanding changes (DEPRECATED)')),
3537 _('force a merge including outstanding changes (DEPRECATED)')),
3535 ('r', 'rev', '', _('revision to merge'), _('REV')),
3538 ('r', 'rev', '', _('revision to merge'), _('REV')),
3536 ('P', 'preview', None,
3539 ('P', 'preview', None,
3537 _('review revisions to merge (no merge is performed)'))
3540 _('review revisions to merge (no merge is performed)'))
3538 ] + mergetoolopts,
3541 ] + mergetoolopts,
3539 _('[-P] [[-r] REV]'))
3542 _('[-P] [[-r] REV]'))
3540 def merge(ui, repo, node=None, **opts):
3543 def merge(ui, repo, node=None, **opts):
3541 """merge another revision into working directory
3544 """merge another revision into working directory
3542
3545
3543 The current working directory is updated with all changes made in
3546 The current working directory is updated with all changes made in
3544 the requested revision since the last common predecessor revision.
3547 the requested revision since the last common predecessor revision.
3545
3548
3546 Files that changed between either parent are marked as changed for
3549 Files that changed between either parent are marked as changed for
3547 the next commit and a commit must be performed before any further
3550 the next commit and a commit must be performed before any further
3548 updates to the repository are allowed. The next commit will have
3551 updates to the repository are allowed. The next commit will have
3549 two parents.
3552 two parents.
3550
3553
3551 ``--tool`` can be used to specify the merge tool used for file
3554 ``--tool`` can be used to specify the merge tool used for file
3552 merges. It overrides the HGMERGE environment variable and your
3555 merges. It overrides the HGMERGE environment variable and your
3553 configuration files. See :hg:`help merge-tools` for options.
3556 configuration files. See :hg:`help merge-tools` for options.
3554
3557
3555 If no revision is specified, the working directory's parent is a
3558 If no revision is specified, the working directory's parent is a
3556 head revision, and the current branch contains exactly one other
3559 head revision, and the current branch contains exactly one other
3557 head, the other head is merged with by default. Otherwise, an
3560 head, the other head is merged with by default. Otherwise, an
3558 explicit revision with which to merge with must be provided.
3561 explicit revision with which to merge with must be provided.
3559
3562
3560 See :hg:`help resolve` for information on handling file conflicts.
3563 See :hg:`help resolve` for information on handling file conflicts.
3561
3564
3562 To undo an uncommitted merge, use :hg:`update --clean .` which
3565 To undo an uncommitted merge, use :hg:`update --clean .` which
3563 will check out a clean copy of the original merge parent, losing
3566 will check out a clean copy of the original merge parent, losing
3564 all changes.
3567 all changes.
3565
3568
3566 Returns 0 on success, 1 if there are unresolved files.
3569 Returns 0 on success, 1 if there are unresolved files.
3567 """
3570 """
3568
3571
3569 opts = pycompat.byteskwargs(opts)
3572 opts = pycompat.byteskwargs(opts)
3570 if opts.get('rev') and node:
3573 if opts.get('rev') and node:
3571 raise error.Abort(_("please specify just one revision"))
3574 raise error.Abort(_("please specify just one revision"))
3572 if not node:
3575 if not node:
3573 node = opts.get('rev')
3576 node = opts.get('rev')
3574
3577
3575 if node:
3578 if node:
3576 node = scmutil.revsingle(repo, node).node()
3579 node = scmutil.revsingle(repo, node).node()
3577
3580
3578 if not node:
3581 if not node:
3579 node = repo[destutil.destmerge(repo)].node()
3582 node = repo[destutil.destmerge(repo)].node()
3580
3583
3581 if opts.get('preview'):
3584 if opts.get('preview'):
3582 # find nodes that are ancestors of p2 but not of p1
3585 # find nodes that are ancestors of p2 but not of p1
3583 p1 = repo.lookup('.')
3586 p1 = repo.lookup('.')
3584 p2 = repo.lookup(node)
3587 p2 = repo.lookup(node)
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3588 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3586
3589
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3590 displayer = cmdutil.show_changeset(ui, repo, opts)
3588 for node in nodes:
3591 for node in nodes:
3589 displayer.show(repo[node])
3592 displayer.show(repo[node])
3590 displayer.close()
3593 displayer.close()
3591 return 0
3594 return 0
3592
3595
3593 try:
3596 try:
3594 # ui.forcemerge is an internal variable, do not document
3597 # ui.forcemerge is an internal variable, do not document
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3598 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3596 force = opts.get('force')
3599 force = opts.get('force')
3597 labels = ['working copy', 'merge rev']
3600 labels = ['working copy', 'merge rev']
3598 return hg.merge(repo, node, force=force, mergeforce=force,
3601 return hg.merge(repo, node, force=force, mergeforce=force,
3599 labels=labels)
3602 labels=labels)
3600 finally:
3603 finally:
3601 ui.setconfig('ui', 'forcemerge', '', 'merge')
3604 ui.setconfig('ui', 'forcemerge', '', 'merge')
3602
3605
3603 @command('outgoing|out',
3606 @command('outgoing|out',
3604 [('f', 'force', None, _('run even when the destination is unrelated')),
3607 [('f', 'force', None, _('run even when the destination is unrelated')),
3605 ('r', 'rev', [],
3608 ('r', 'rev', [],
3606 _('a changeset intended to be included in the destination'), _('REV')),
3609 _('a changeset intended to be included in the destination'), _('REV')),
3607 ('n', 'newest-first', None, _('show newest record first')),
3610 ('n', 'newest-first', None, _('show newest record first')),
3608 ('B', 'bookmarks', False, _('compare bookmarks')),
3611 ('B', 'bookmarks', False, _('compare bookmarks')),
3609 ('b', 'branch', [], _('a specific branch you would like to push'),
3612 ('b', 'branch', [], _('a specific branch you would like to push'),
3610 _('BRANCH')),
3613 _('BRANCH')),
3611 ] + logopts + remoteopts + subrepoopts,
3614 ] + logopts + remoteopts + subrepoopts,
3612 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3615 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3613 def outgoing(ui, repo, dest=None, **opts):
3616 def outgoing(ui, repo, dest=None, **opts):
3614 """show changesets not found in the destination
3617 """show changesets not found in the destination
3615
3618
3616 Show changesets not found in the specified destination repository
3619 Show changesets not found in the specified destination repository
3617 or the default push location. These are the changesets that would
3620 or the default push location. These are the changesets that would
3618 be pushed if a push was requested.
3621 be pushed if a push was requested.
3619
3622
3620 See pull for details of valid destination formats.
3623 See pull for details of valid destination formats.
3621
3624
3622 .. container:: verbose
3625 .. container:: verbose
3623
3626
3624 With -B/--bookmarks, the result of bookmark comparison between
3627 With -B/--bookmarks, the result of bookmark comparison between
3625 local and remote repositories is displayed. With -v/--verbose,
3628 local and remote repositories is displayed. With -v/--verbose,
3626 status is also displayed for each bookmark like below::
3629 status is also displayed for each bookmark like below::
3627
3630
3628 BM1 01234567890a added
3631 BM1 01234567890a added
3629 BM2 deleted
3632 BM2 deleted
3630 BM3 234567890abc advanced
3633 BM3 234567890abc advanced
3631 BM4 34567890abcd diverged
3634 BM4 34567890abcd diverged
3632 BM5 4567890abcde changed
3635 BM5 4567890abcde changed
3633
3636
3634 The action taken when pushing depends on the
3637 The action taken when pushing depends on the
3635 status of each bookmark:
3638 status of each bookmark:
3636
3639
3637 :``added``: push with ``-B`` will create it
3640 :``added``: push with ``-B`` will create it
3638 :``deleted``: push with ``-B`` will delete it
3641 :``deleted``: push with ``-B`` will delete it
3639 :``advanced``: push will update it
3642 :``advanced``: push will update it
3640 :``diverged``: push with ``-B`` will update it
3643 :``diverged``: push with ``-B`` will update it
3641 :``changed``: push with ``-B`` will update it
3644 :``changed``: push with ``-B`` will update it
3642
3645
3643 From the point of view of pushing behavior, bookmarks
3646 From the point of view of pushing behavior, bookmarks
3644 existing only in the remote repository are treated as
3647 existing only in the remote repository are treated as
3645 ``deleted``, even if it is in fact added remotely.
3648 ``deleted``, even if it is in fact added remotely.
3646
3649
3647 Returns 0 if there are outgoing changes, 1 otherwise.
3650 Returns 0 if there are outgoing changes, 1 otherwise.
3648 """
3651 """
3649 opts = pycompat.byteskwargs(opts)
3652 opts = pycompat.byteskwargs(opts)
3650 if opts.get('graph'):
3653 if opts.get('graph'):
3651 cmdutil.checkunsupportedgraphflags([], opts)
3654 cmdutil.checkunsupportedgraphflags([], opts)
3652 o, other = hg._outgoing(ui, repo, dest, opts)
3655 o, other = hg._outgoing(ui, repo, dest, opts)
3653 if not o:
3656 if not o:
3654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3657 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3655 return
3658 return
3656
3659
3657 revdag = cmdutil.graphrevs(repo, o, opts)
3660 revdag = cmdutil.graphrevs(repo, o, opts)
3658 ui.pager('outgoing')
3661 ui.pager('outgoing')
3659 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3662 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3660 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3663 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3664 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3662 return 0
3665 return 0
3663
3666
3664 if opts.get('bookmarks'):
3667 if opts.get('bookmarks'):
3665 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3668 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3666 dest, branches = hg.parseurl(dest, opts.get('branch'))
3669 dest, branches = hg.parseurl(dest, opts.get('branch'))
3667 other = hg.peer(repo, opts, dest)
3670 other = hg.peer(repo, opts, dest)
3668 if 'bookmarks' not in other.listkeys('namespaces'):
3671 if 'bookmarks' not in other.listkeys('namespaces'):
3669 ui.warn(_("remote doesn't support bookmarks\n"))
3672 ui.warn(_("remote doesn't support bookmarks\n"))
3670 return 0
3673 return 0
3671 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3674 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3672 ui.pager('outgoing')
3675 ui.pager('outgoing')
3673 return bookmarks.outgoing(ui, repo, other)
3676 return bookmarks.outgoing(ui, repo, other)
3674
3677
3675 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3678 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3676 try:
3679 try:
3677 return hg.outgoing(ui, repo, dest, opts)
3680 return hg.outgoing(ui, repo, dest, opts)
3678 finally:
3681 finally:
3679 del repo._subtoppath
3682 del repo._subtoppath
3680
3683
3681 @command('parents',
3684 @command('parents',
3682 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3685 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3683 ] + templateopts,
3686 ] + templateopts,
3684 _('[-r REV] [FILE]'),
3687 _('[-r REV] [FILE]'),
3685 inferrepo=True)
3688 inferrepo=True)
3686 def parents(ui, repo, file_=None, **opts):
3689 def parents(ui, repo, file_=None, **opts):
3687 """show the parents of the working directory or revision (DEPRECATED)
3690 """show the parents of the working directory or revision (DEPRECATED)
3688
3691
3689 Print the working directory's parent revisions. If a revision is
3692 Print the working directory's parent revisions. If a revision is
3690 given via -r/--rev, the parent of that revision will be printed.
3693 given via -r/--rev, the parent of that revision will be printed.
3691 If a file argument is given, the revision in which the file was
3694 If a file argument is given, the revision in which the file was
3692 last changed (before the working directory revision or the
3695 last changed (before the working directory revision or the
3693 argument to --rev if given) is printed.
3696 argument to --rev if given) is printed.
3694
3697
3695 This command is equivalent to::
3698 This command is equivalent to::
3696
3699
3697 hg log -r "p1()+p2()" or
3700 hg log -r "p1()+p2()" or
3698 hg log -r "p1(REV)+p2(REV)" or
3701 hg log -r "p1(REV)+p2(REV)" or
3699 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3702 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3700 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3703 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3701
3704
3702 See :hg:`summary` and :hg:`help revsets` for related information.
3705 See :hg:`summary` and :hg:`help revsets` for related information.
3703
3706
3704 Returns 0 on success.
3707 Returns 0 on success.
3705 """
3708 """
3706
3709
3707 opts = pycompat.byteskwargs(opts)
3710 opts = pycompat.byteskwargs(opts)
3708 rev = opts.get('rev')
3711 rev = opts.get('rev')
3709 if rev:
3712 if rev:
3710 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3713 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3711 ctx = scmutil.revsingle(repo, rev, None)
3714 ctx = scmutil.revsingle(repo, rev, None)
3712
3715
3713 if file_:
3716 if file_:
3714 m = scmutil.match(ctx, (file_,), opts)
3717 m = scmutil.match(ctx, (file_,), opts)
3715 if m.anypats() or len(m.files()) != 1:
3718 if m.anypats() or len(m.files()) != 1:
3716 raise error.Abort(_('can only specify an explicit filename'))
3719 raise error.Abort(_('can only specify an explicit filename'))
3717 file_ = m.files()[0]
3720 file_ = m.files()[0]
3718 filenodes = []
3721 filenodes = []
3719 for cp in ctx.parents():
3722 for cp in ctx.parents():
3720 if not cp:
3723 if not cp:
3721 continue
3724 continue
3722 try:
3725 try:
3723 filenodes.append(cp.filenode(file_))
3726 filenodes.append(cp.filenode(file_))
3724 except error.LookupError:
3727 except error.LookupError:
3725 pass
3728 pass
3726 if not filenodes:
3729 if not filenodes:
3727 raise error.Abort(_("'%s' not found in manifest!") % file_)
3730 raise error.Abort(_("'%s' not found in manifest!") % file_)
3728 p = []
3731 p = []
3729 for fn in filenodes:
3732 for fn in filenodes:
3730 fctx = repo.filectx(file_, fileid=fn)
3733 fctx = repo.filectx(file_, fileid=fn)
3731 p.append(fctx.node())
3734 p.append(fctx.node())
3732 else:
3735 else:
3733 p = [cp.node() for cp in ctx.parents()]
3736 p = [cp.node() for cp in ctx.parents()]
3734
3737
3735 displayer = cmdutil.show_changeset(ui, repo, opts)
3738 displayer = cmdutil.show_changeset(ui, repo, opts)
3736 for n in p:
3739 for n in p:
3737 if n != nullid:
3740 if n != nullid:
3738 displayer.show(repo[n])
3741 displayer.show(repo[n])
3739 displayer.close()
3742 displayer.close()
3740
3743
3741 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3744 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3742 cmdtype=readonly)
3745 cmdtype=readonly)
3743 def paths(ui, repo, search=None, **opts):
3746 def paths(ui, repo, search=None, **opts):
3744 """show aliases for remote repositories
3747 """show aliases for remote repositories
3745
3748
3746 Show definition of symbolic path name NAME. If no name is given,
3749 Show definition of symbolic path name NAME. If no name is given,
3747 show definition of all available names.
3750 show definition of all available names.
3748
3751
3749 Option -q/--quiet suppresses all output when searching for NAME
3752 Option -q/--quiet suppresses all output when searching for NAME
3750 and shows only the path names when listing all definitions.
3753 and shows only the path names when listing all definitions.
3751
3754
3752 Path names are defined in the [paths] section of your
3755 Path names are defined in the [paths] section of your
3753 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3756 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3754 repository, ``.hg/hgrc`` is used, too.
3757 repository, ``.hg/hgrc`` is used, too.
3755
3758
3756 The path names ``default`` and ``default-push`` have a special
3759 The path names ``default`` and ``default-push`` have a special
3757 meaning. When performing a push or pull operation, they are used
3760 meaning. When performing a push or pull operation, they are used
3758 as fallbacks if no location is specified on the command-line.
3761 as fallbacks if no location is specified on the command-line.
3759 When ``default-push`` is set, it will be used for push and
3762 When ``default-push`` is set, it will be used for push and
3760 ``default`` will be used for pull; otherwise ``default`` is used
3763 ``default`` will be used for pull; otherwise ``default`` is used
3761 as the fallback for both. When cloning a repository, the clone
3764 as the fallback for both. When cloning a repository, the clone
3762 source is written as ``default`` in ``.hg/hgrc``.
3765 source is written as ``default`` in ``.hg/hgrc``.
3763
3766
3764 .. note::
3767 .. note::
3765
3768
3766 ``default`` and ``default-push`` apply to all inbound (e.g.
3769 ``default`` and ``default-push`` apply to all inbound (e.g.
3767 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3770 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3768 and :hg:`bundle`) operations.
3771 and :hg:`bundle`) operations.
3769
3772
3770 See :hg:`help urls` for more information.
3773 See :hg:`help urls` for more information.
3771
3774
3772 Returns 0 on success.
3775 Returns 0 on success.
3773 """
3776 """
3774
3777
3775 opts = pycompat.byteskwargs(opts)
3778 opts = pycompat.byteskwargs(opts)
3776 ui.pager('paths')
3779 ui.pager('paths')
3777 if search:
3780 if search:
3778 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3781 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3779 if name == search]
3782 if name == search]
3780 else:
3783 else:
3781 pathitems = sorted(ui.paths.iteritems())
3784 pathitems = sorted(ui.paths.iteritems())
3782
3785
3783 fm = ui.formatter('paths', opts)
3786 fm = ui.formatter('paths', opts)
3784 if fm.isplain():
3787 if fm.isplain():
3785 hidepassword = util.hidepassword
3788 hidepassword = util.hidepassword
3786 else:
3789 else:
3787 hidepassword = str
3790 hidepassword = str
3788 if ui.quiet:
3791 if ui.quiet:
3789 namefmt = '%s\n'
3792 namefmt = '%s\n'
3790 else:
3793 else:
3791 namefmt = '%s = '
3794 namefmt = '%s = '
3792 showsubopts = not search and not ui.quiet
3795 showsubopts = not search and not ui.quiet
3793
3796
3794 for name, path in pathitems:
3797 for name, path in pathitems:
3795 fm.startitem()
3798 fm.startitem()
3796 fm.condwrite(not search, 'name', namefmt, name)
3799 fm.condwrite(not search, 'name', namefmt, name)
3797 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3800 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3798 for subopt, value in sorted(path.suboptions.items()):
3801 for subopt, value in sorted(path.suboptions.items()):
3799 assert subopt not in ('name', 'url')
3802 assert subopt not in ('name', 'url')
3800 if showsubopts:
3803 if showsubopts:
3801 fm.plain('%s:%s = ' % (name, subopt))
3804 fm.plain('%s:%s = ' % (name, subopt))
3802 fm.condwrite(showsubopts, subopt, '%s\n', value)
3805 fm.condwrite(showsubopts, subopt, '%s\n', value)
3803
3806
3804 fm.end()
3807 fm.end()
3805
3808
3806 if search and not pathitems:
3809 if search and not pathitems:
3807 if not ui.quiet:
3810 if not ui.quiet:
3808 ui.warn(_("not found!\n"))
3811 ui.warn(_("not found!\n"))
3809 return 1
3812 return 1
3810 else:
3813 else:
3811 return 0
3814 return 0
3812
3815
3813 @command('phase',
3816 @command('phase',
3814 [('p', 'public', False, _('set changeset phase to public')),
3817 [('p', 'public', False, _('set changeset phase to public')),
3815 ('d', 'draft', False, _('set changeset phase to draft')),
3818 ('d', 'draft', False, _('set changeset phase to draft')),
3816 ('s', 'secret', False, _('set changeset phase to secret')),
3819 ('s', 'secret', False, _('set changeset phase to secret')),
3817 ('f', 'force', False, _('allow to move boundary backward')),
3820 ('f', 'force', False, _('allow to move boundary backward')),
3818 ('r', 'rev', [], _('target revision'), _('REV')),
3821 ('r', 'rev', [], _('target revision'), _('REV')),
3819 ],
3822 ],
3820 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3823 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3821 def phase(ui, repo, *revs, **opts):
3824 def phase(ui, repo, *revs, **opts):
3822 """set or show the current phase name
3825 """set or show the current phase name
3823
3826
3824 With no argument, show the phase name of the current revision(s).
3827 With no argument, show the phase name of the current revision(s).
3825
3828
3826 With one of -p/--public, -d/--draft or -s/--secret, change the
3829 With one of -p/--public, -d/--draft or -s/--secret, change the
3827 phase value of the specified revisions.
3830 phase value of the specified revisions.
3828
3831
3829 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3832 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3830 lower phase to a higher phase. Phases are ordered as follows::
3833 lower phase to a higher phase. Phases are ordered as follows::
3831
3834
3832 public < draft < secret
3835 public < draft < secret
3833
3836
3834 Returns 0 on success, 1 if some phases could not be changed.
3837 Returns 0 on success, 1 if some phases could not be changed.
3835
3838
3836 (For more information about the phases concept, see :hg:`help phases`.)
3839 (For more information about the phases concept, see :hg:`help phases`.)
3837 """
3840 """
3838 opts = pycompat.byteskwargs(opts)
3841 opts = pycompat.byteskwargs(opts)
3839 # search for a unique phase argument
3842 # search for a unique phase argument
3840 targetphase = None
3843 targetphase = None
3841 for idx, name in enumerate(phases.phasenames):
3844 for idx, name in enumerate(phases.phasenames):
3842 if opts[name]:
3845 if opts[name]:
3843 if targetphase is not None:
3846 if targetphase is not None:
3844 raise error.Abort(_('only one phase can be specified'))
3847 raise error.Abort(_('only one phase can be specified'))
3845 targetphase = idx
3848 targetphase = idx
3846
3849
3847 # look for specified revision
3850 # look for specified revision
3848 revs = list(revs)
3851 revs = list(revs)
3849 revs.extend(opts['rev'])
3852 revs.extend(opts['rev'])
3850 if not revs:
3853 if not revs:
3851 # display both parents as the second parent phase can influence
3854 # display both parents as the second parent phase can influence
3852 # the phase of a merge commit
3855 # the phase of a merge commit
3853 revs = [c.rev() for c in repo[None].parents()]
3856 revs = [c.rev() for c in repo[None].parents()]
3854
3857
3855 revs = scmutil.revrange(repo, revs)
3858 revs = scmutil.revrange(repo, revs)
3856
3859
3857 lock = None
3860 lock = None
3858 ret = 0
3861 ret = 0
3859 if targetphase is None:
3862 if targetphase is None:
3860 # display
3863 # display
3861 for r in revs:
3864 for r in revs:
3862 ctx = repo[r]
3865 ctx = repo[r]
3863 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3866 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3864 else:
3867 else:
3865 tr = None
3868 tr = None
3866 lock = repo.lock()
3869 lock = repo.lock()
3867 try:
3870 try:
3868 tr = repo.transaction("phase")
3871 tr = repo.transaction("phase")
3869 # set phase
3872 # set phase
3870 if not revs:
3873 if not revs:
3871 raise error.Abort(_('empty revision set'))
3874 raise error.Abort(_('empty revision set'))
3872 nodes = [repo[r].node() for r in revs]
3875 nodes = [repo[r].node() for r in revs]
3873 # moving revision from public to draft may hide them
3876 # moving revision from public to draft may hide them
3874 # We have to check result on an unfiltered repository
3877 # We have to check result on an unfiltered repository
3875 unfi = repo.unfiltered()
3878 unfi = repo.unfiltered()
3876 getphase = unfi._phasecache.phase
3879 getphase = unfi._phasecache.phase
3877 olddata = [getphase(unfi, r) for r in unfi]
3880 olddata = [getphase(unfi, r) for r in unfi]
3878 phases.advanceboundary(repo, tr, targetphase, nodes)
3881 phases.advanceboundary(repo, tr, targetphase, nodes)
3879 if opts['force']:
3882 if opts['force']:
3880 phases.retractboundary(repo, tr, targetphase, nodes)
3883 phases.retractboundary(repo, tr, targetphase, nodes)
3881 tr.close()
3884 tr.close()
3882 finally:
3885 finally:
3883 if tr is not None:
3886 if tr is not None:
3884 tr.release()
3887 tr.release()
3885 lock.release()
3888 lock.release()
3886 getphase = unfi._phasecache.phase
3889 getphase = unfi._phasecache.phase
3887 newdata = [getphase(unfi, r) for r in unfi]
3890 newdata = [getphase(unfi, r) for r in unfi]
3888 changes = sum(newdata[r] != olddata[r] for r in unfi)
3891 changes = sum(newdata[r] != olddata[r] for r in unfi)
3889 cl = unfi.changelog
3892 cl = unfi.changelog
3890 rejected = [n for n in nodes
3893 rejected = [n for n in nodes
3891 if newdata[cl.rev(n)] < targetphase]
3894 if newdata[cl.rev(n)] < targetphase]
3892 if rejected:
3895 if rejected:
3893 ui.warn(_('cannot move %i changesets to a higher '
3896 ui.warn(_('cannot move %i changesets to a higher '
3894 'phase, use --force\n') % len(rejected))
3897 'phase, use --force\n') % len(rejected))
3895 ret = 1
3898 ret = 1
3896 if changes:
3899 if changes:
3897 msg = _('phase changed for %i changesets\n') % changes
3900 msg = _('phase changed for %i changesets\n') % changes
3898 if ret:
3901 if ret:
3899 ui.status(msg)
3902 ui.status(msg)
3900 else:
3903 else:
3901 ui.note(msg)
3904 ui.note(msg)
3902 else:
3905 else:
3903 ui.warn(_('no phases changed\n'))
3906 ui.warn(_('no phases changed\n'))
3904 return ret
3907 return ret
3905
3908
3906 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3909 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3907 """Run after a changegroup has been added via pull/unbundle
3910 """Run after a changegroup has been added via pull/unbundle
3908
3911
3909 This takes arguments below:
3912 This takes arguments below:
3910
3913
3911 :modheads: change of heads by pull/unbundle
3914 :modheads: change of heads by pull/unbundle
3912 :optupdate: updating working directory is needed or not
3915 :optupdate: updating working directory is needed or not
3913 :checkout: update destination revision (or None to default destination)
3916 :checkout: update destination revision (or None to default destination)
3914 :brev: a name, which might be a bookmark to be activated after updating
3917 :brev: a name, which might be a bookmark to be activated after updating
3915 """
3918 """
3916 if modheads == 0:
3919 if modheads == 0:
3917 return
3920 return
3918 if optupdate:
3921 if optupdate:
3919 try:
3922 try:
3920 return hg.updatetotally(ui, repo, checkout, brev)
3923 return hg.updatetotally(ui, repo, checkout, brev)
3921 except error.UpdateAbort as inst:
3924 except error.UpdateAbort as inst:
3922 msg = _("not updating: %s") % str(inst)
3925 msg = _("not updating: %s") % str(inst)
3923 hint = inst.hint
3926 hint = inst.hint
3924 raise error.UpdateAbort(msg, hint=hint)
3927 raise error.UpdateAbort(msg, hint=hint)
3925 if modheads > 1:
3928 if modheads > 1:
3926 currentbranchheads = len(repo.branchheads())
3929 currentbranchheads = len(repo.branchheads())
3927 if currentbranchheads == modheads:
3930 if currentbranchheads == modheads:
3928 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3931 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3929 elif currentbranchheads > 1:
3932 elif currentbranchheads > 1:
3930 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3933 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3931 "merge)\n"))
3934 "merge)\n"))
3932 else:
3935 else:
3933 ui.status(_("(run 'hg heads' to see heads)\n"))
3936 ui.status(_("(run 'hg heads' to see heads)\n"))
3934 elif not ui.configbool('commands', 'update.requiredest'):
3937 elif not ui.configbool('commands', 'update.requiredest'):
3935 ui.status(_("(run 'hg update' to get a working copy)\n"))
3938 ui.status(_("(run 'hg update' to get a working copy)\n"))
3936
3939
3937 @command('^pull',
3940 @command('^pull',
3938 [('u', 'update', None,
3941 [('u', 'update', None,
3939 _('update to new branch head if new descendants were pulled')),
3942 _('update to new branch head if new descendants were pulled')),
3940 ('f', 'force', None, _('run even when remote repository is unrelated')),
3943 ('f', 'force', None, _('run even when remote repository is unrelated')),
3941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3944 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3942 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3945 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3943 ('b', 'branch', [], _('a specific branch you would like to pull'),
3946 ('b', 'branch', [], _('a specific branch you would like to pull'),
3944 _('BRANCH')),
3947 _('BRANCH')),
3945 ] + remoteopts,
3948 ] + remoteopts,
3946 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3949 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3947 def pull(ui, repo, source="default", **opts):
3950 def pull(ui, repo, source="default", **opts):
3948 """pull changes from the specified source
3951 """pull changes from the specified source
3949
3952
3950 Pull changes from a remote repository to a local one.
3953 Pull changes from a remote repository to a local one.
3951
3954
3952 This finds all changes from the repository at the specified path
3955 This finds all changes from the repository at the specified path
3953 or URL and adds them to a local repository (the current one unless
3956 or URL and adds them to a local repository (the current one unless
3954 -R is specified). By default, this does not update the copy of the
3957 -R is specified). By default, this does not update the copy of the
3955 project in the working directory.
3958 project in the working directory.
3956
3959
3957 Use :hg:`incoming` if you want to see what would have been added
3960 Use :hg:`incoming` if you want to see what would have been added
3958 by a pull at the time you issued this command. If you then decide
3961 by a pull at the time you issued this command. If you then decide
3959 to add those changes to the repository, you should use :hg:`pull
3962 to add those changes to the repository, you should use :hg:`pull
3960 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3963 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3961
3964
3962 If SOURCE is omitted, the 'default' path will be used.
3965 If SOURCE is omitted, the 'default' path will be used.
3963 See :hg:`help urls` for more information.
3966 See :hg:`help urls` for more information.
3964
3967
3965 Specifying bookmark as ``.`` is equivalent to specifying the active
3968 Specifying bookmark as ``.`` is equivalent to specifying the active
3966 bookmark's name.
3969 bookmark's name.
3967
3970
3968 Returns 0 on success, 1 if an update had unresolved files.
3971 Returns 0 on success, 1 if an update had unresolved files.
3969 """
3972 """
3970
3973
3971 opts = pycompat.byteskwargs(opts)
3974 opts = pycompat.byteskwargs(opts)
3972 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3975 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3973 msg = _('update destination required by configuration')
3976 msg = _('update destination required by configuration')
3974 hint = _('use hg pull followed by hg update DEST')
3977 hint = _('use hg pull followed by hg update DEST')
3975 raise error.Abort(msg, hint=hint)
3978 raise error.Abort(msg, hint=hint)
3976
3979
3977 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3980 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3978 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3981 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3979 other = hg.peer(repo, opts, source)
3982 other = hg.peer(repo, opts, source)
3980 try:
3983 try:
3981 revs, checkout = hg.addbranchrevs(repo, other, branches,
3984 revs, checkout = hg.addbranchrevs(repo, other, branches,
3982 opts.get('rev'))
3985 opts.get('rev'))
3983
3986
3984
3987
3985 pullopargs = {}
3988 pullopargs = {}
3986 if opts.get('bookmark'):
3989 if opts.get('bookmark'):
3987 if not revs:
3990 if not revs:
3988 revs = []
3991 revs = []
3989 # The list of bookmark used here is not the one used to actually
3992 # The list of bookmark used here is not the one used to actually
3990 # update the bookmark name. This can result in the revision pulled
3993 # update the bookmark name. This can result in the revision pulled
3991 # not ending up with the name of the bookmark because of a race
3994 # not ending up with the name of the bookmark because of a race
3992 # condition on the server. (See issue 4689 for details)
3995 # condition on the server. (See issue 4689 for details)
3993 remotebookmarks = other.listkeys('bookmarks')
3996 remotebookmarks = other.listkeys('bookmarks')
3994 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3997 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3995 pullopargs['remotebookmarks'] = remotebookmarks
3998 pullopargs['remotebookmarks'] = remotebookmarks
3996 for b in opts['bookmark']:
3999 for b in opts['bookmark']:
3997 b = repo._bookmarks.expandname(b)
4000 b = repo._bookmarks.expandname(b)
3998 if b not in remotebookmarks:
4001 if b not in remotebookmarks:
3999 raise error.Abort(_('remote bookmark %s not found!') % b)
4002 raise error.Abort(_('remote bookmark %s not found!') % b)
4000 revs.append(hex(remotebookmarks[b]))
4003 revs.append(hex(remotebookmarks[b]))
4001
4004
4002 if revs:
4005 if revs:
4003 try:
4006 try:
4004 # When 'rev' is a bookmark name, we cannot guarantee that it
4007 # When 'rev' is a bookmark name, we cannot guarantee that it
4005 # will be updated with that name because of a race condition
4008 # will be updated with that name because of a race condition
4006 # server side. (See issue 4689 for details)
4009 # server side. (See issue 4689 for details)
4007 oldrevs = revs
4010 oldrevs = revs
4008 revs = [] # actually, nodes
4011 revs = [] # actually, nodes
4009 for r in oldrevs:
4012 for r in oldrevs:
4010 node = other.lookup(r)
4013 node = other.lookup(r)
4011 revs.append(node)
4014 revs.append(node)
4012 if r == checkout:
4015 if r == checkout:
4013 checkout = node
4016 checkout = node
4014 except error.CapabilityError:
4017 except error.CapabilityError:
4015 err = _("other repository doesn't support revision lookup, "
4018 err = _("other repository doesn't support revision lookup, "
4016 "so a rev cannot be specified.")
4019 "so a rev cannot be specified.")
4017 raise error.Abort(err)
4020 raise error.Abort(err)
4018
4021
4019 pullopargs.update(opts.get('opargs', {}))
4022 pullopargs.update(opts.get('opargs', {}))
4020 modheads = exchange.pull(repo, other, heads=revs,
4023 modheads = exchange.pull(repo, other, heads=revs,
4021 force=opts.get('force'),
4024 force=opts.get('force'),
4022 bookmarks=opts.get('bookmark', ()),
4025 bookmarks=opts.get('bookmark', ()),
4023 opargs=pullopargs).cgresult
4026 opargs=pullopargs).cgresult
4024
4027
4025 # brev is a name, which might be a bookmark to be activated at
4028 # brev is a name, which might be a bookmark to be activated at
4026 # the end of the update. In other words, it is an explicit
4029 # the end of the update. In other words, it is an explicit
4027 # destination of the update
4030 # destination of the update
4028 brev = None
4031 brev = None
4029
4032
4030 if checkout:
4033 if checkout:
4031 checkout = str(repo.changelog.rev(checkout))
4034 checkout = str(repo.changelog.rev(checkout))
4032
4035
4033 # order below depends on implementation of
4036 # order below depends on implementation of
4034 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4037 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4035 # because 'checkout' is determined without it.
4038 # because 'checkout' is determined without it.
4036 if opts.get('rev'):
4039 if opts.get('rev'):
4037 brev = opts['rev'][0]
4040 brev = opts['rev'][0]
4038 elif opts.get('branch'):
4041 elif opts.get('branch'):
4039 brev = opts['branch'][0]
4042 brev = opts['branch'][0]
4040 else:
4043 else:
4041 brev = branches[0]
4044 brev = branches[0]
4042 repo._subtoppath = source
4045 repo._subtoppath = source
4043 try:
4046 try:
4044 ret = postincoming(ui, repo, modheads, opts.get('update'),
4047 ret = postincoming(ui, repo, modheads, opts.get('update'),
4045 checkout, brev)
4048 checkout, brev)
4046
4049
4047 finally:
4050 finally:
4048 del repo._subtoppath
4051 del repo._subtoppath
4049
4052
4050 finally:
4053 finally:
4051 other.close()
4054 other.close()
4052 return ret
4055 return ret
4053
4056
4054 @command('^push',
4057 @command('^push',
4055 [('f', 'force', None, _('force push')),
4058 [('f', 'force', None, _('force push')),
4056 ('r', 'rev', [],
4059 ('r', 'rev', [],
4057 _('a changeset intended to be included in the destination'),
4060 _('a changeset intended to be included in the destination'),
4058 _('REV')),
4061 _('REV')),
4059 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4062 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4060 ('b', 'branch', [],
4063 ('b', 'branch', [],
4061 _('a specific branch you would like to push'), _('BRANCH')),
4064 _('a specific branch you would like to push'), _('BRANCH')),
4062 ('', 'new-branch', False, _('allow pushing a new branch')),
4065 ('', 'new-branch', False, _('allow pushing a new branch')),
4063 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4066 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4064 ] + remoteopts,
4067 ] + remoteopts,
4065 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4068 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4066 def push(ui, repo, dest=None, **opts):
4069 def push(ui, repo, dest=None, **opts):
4067 """push changes to the specified destination
4070 """push changes to the specified destination
4068
4071
4069 Push changesets from the local repository to the specified
4072 Push changesets from the local repository to the specified
4070 destination.
4073 destination.
4071
4074
4072 This operation is symmetrical to pull: it is identical to a pull
4075 This operation is symmetrical to pull: it is identical to a pull
4073 in the destination repository from the current one.
4076 in the destination repository from the current one.
4074
4077
4075 By default, push will not allow creation of new heads at the
4078 By default, push will not allow creation of new heads at the
4076 destination, since multiple heads would make it unclear which head
4079 destination, since multiple heads would make it unclear which head
4077 to use. In this situation, it is recommended to pull and merge
4080 to use. In this situation, it is recommended to pull and merge
4078 before pushing.
4081 before pushing.
4079
4082
4080 Use --new-branch if you want to allow push to create a new named
4083 Use --new-branch if you want to allow push to create a new named
4081 branch that is not present at the destination. This allows you to
4084 branch that is not present at the destination. This allows you to
4082 only create a new branch without forcing other changes.
4085 only create a new branch without forcing other changes.
4083
4086
4084 .. note::
4087 .. note::
4085
4088
4086 Extra care should be taken with the -f/--force option,
4089 Extra care should be taken with the -f/--force option,
4087 which will push all new heads on all branches, an action which will
4090 which will push all new heads on all branches, an action which will
4088 almost always cause confusion for collaborators.
4091 almost always cause confusion for collaborators.
4089
4092
4090 If -r/--rev is used, the specified revision and all its ancestors
4093 If -r/--rev is used, the specified revision and all its ancestors
4091 will be pushed to the remote repository.
4094 will be pushed to the remote repository.
4092
4095
4093 If -B/--bookmark is used, the specified bookmarked revision, its
4096 If -B/--bookmark is used, the specified bookmarked revision, its
4094 ancestors, and the bookmark will be pushed to the remote
4097 ancestors, and the bookmark will be pushed to the remote
4095 repository. Specifying ``.`` is equivalent to specifying the active
4098 repository. Specifying ``.`` is equivalent to specifying the active
4096 bookmark's name.
4099 bookmark's name.
4097
4100
4098 Please see :hg:`help urls` for important details about ``ssh://``
4101 Please see :hg:`help urls` for important details about ``ssh://``
4099 URLs. If DESTINATION is omitted, a default path will be used.
4102 URLs. If DESTINATION is omitted, a default path will be used.
4100
4103
4101 .. container:: verbose
4104 .. container:: verbose
4102
4105
4103 The --pushvars option sends strings to the server that become
4106 The --pushvars option sends strings to the server that become
4104 environment variables prepended with ``HG_USERVAR_``. For example,
4107 environment variables prepended with ``HG_USERVAR_``. For example,
4105 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4108 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4106 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4109 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4107
4110
4108 pushvars can provide for user-overridable hooks as well as set debug
4111 pushvars can provide for user-overridable hooks as well as set debug
4109 levels. One example is having a hook that blocks commits containing
4112 levels. One example is having a hook that blocks commits containing
4110 conflict markers, but enables the user to override the hook if the file
4113 conflict markers, but enables the user to override the hook if the file
4111 is using conflict markers for testing purposes or the file format has
4114 is using conflict markers for testing purposes or the file format has
4112 strings that look like conflict markers.
4115 strings that look like conflict markers.
4113
4116
4114 By default, servers will ignore `--pushvars`. To enable it add the
4117 By default, servers will ignore `--pushvars`. To enable it add the
4115 following to your configuration file::
4118 following to your configuration file::
4116
4119
4117 [push]
4120 [push]
4118 pushvars.server = true
4121 pushvars.server = true
4119
4122
4120 Returns 0 if push was successful, 1 if nothing to push.
4123 Returns 0 if push was successful, 1 if nothing to push.
4121 """
4124 """
4122
4125
4123 opts = pycompat.byteskwargs(opts)
4126 opts = pycompat.byteskwargs(opts)
4124 if opts.get('bookmark'):
4127 if opts.get('bookmark'):
4125 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4128 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4126 for b in opts['bookmark']:
4129 for b in opts['bookmark']:
4127 # translate -B options to -r so changesets get pushed
4130 # translate -B options to -r so changesets get pushed
4128 b = repo._bookmarks.expandname(b)
4131 b = repo._bookmarks.expandname(b)
4129 if b in repo._bookmarks:
4132 if b in repo._bookmarks:
4130 opts.setdefault('rev', []).append(b)
4133 opts.setdefault('rev', []).append(b)
4131 else:
4134 else:
4132 # if we try to push a deleted bookmark, translate it to null
4135 # if we try to push a deleted bookmark, translate it to null
4133 # this lets simultaneous -r, -b options continue working
4136 # this lets simultaneous -r, -b options continue working
4134 opts.setdefault('rev', []).append("null")
4137 opts.setdefault('rev', []).append("null")
4135
4138
4136 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4139 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4137 if not path:
4140 if not path:
4138 raise error.Abort(_('default repository not configured!'),
4141 raise error.Abort(_('default repository not configured!'),
4139 hint=_("see 'hg help config.paths'"))
4142 hint=_("see 'hg help config.paths'"))
4140 dest = path.pushloc or path.loc
4143 dest = path.pushloc or path.loc
4141 branches = (path.branch, opts.get('branch') or [])
4144 branches = (path.branch, opts.get('branch') or [])
4142 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4145 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4143 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4146 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4144 other = hg.peer(repo, opts, dest)
4147 other = hg.peer(repo, opts, dest)
4145
4148
4146 if revs:
4149 if revs:
4147 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4150 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4148 if not revs:
4151 if not revs:
4149 raise error.Abort(_("specified revisions evaluate to an empty set"),
4152 raise error.Abort(_("specified revisions evaluate to an empty set"),
4150 hint=_("use different revision arguments"))
4153 hint=_("use different revision arguments"))
4151 elif path.pushrev:
4154 elif path.pushrev:
4152 # It doesn't make any sense to specify ancestor revisions. So limit
4155 # It doesn't make any sense to specify ancestor revisions. So limit
4153 # to DAG heads to make discovery simpler.
4156 # to DAG heads to make discovery simpler.
4154 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4157 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4155 revs = scmutil.revrange(repo, [expr])
4158 revs = scmutil.revrange(repo, [expr])
4156 revs = [repo[rev].node() for rev in revs]
4159 revs = [repo[rev].node() for rev in revs]
4157 if not revs:
4160 if not revs:
4158 raise error.Abort(_('default push revset for path evaluates to an '
4161 raise error.Abort(_('default push revset for path evaluates to an '
4159 'empty set'))
4162 'empty set'))
4160
4163
4161 repo._subtoppath = dest
4164 repo._subtoppath = dest
4162 try:
4165 try:
4163 # push subrepos depth-first for coherent ordering
4166 # push subrepos depth-first for coherent ordering
4164 c = repo['']
4167 c = repo['']
4165 subs = c.substate # only repos that are committed
4168 subs = c.substate # only repos that are committed
4166 for s in sorted(subs):
4169 for s in sorted(subs):
4167 result = c.sub(s).push(opts)
4170 result = c.sub(s).push(opts)
4168 if result == 0:
4171 if result == 0:
4169 return not result
4172 return not result
4170 finally:
4173 finally:
4171 del repo._subtoppath
4174 del repo._subtoppath
4172
4175
4173 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4176 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4174 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4177 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4175
4178
4176 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4179 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4177 newbranch=opts.get('new_branch'),
4180 newbranch=opts.get('new_branch'),
4178 bookmarks=opts.get('bookmark', ()),
4181 bookmarks=opts.get('bookmark', ()),
4179 opargs=opargs)
4182 opargs=opargs)
4180
4183
4181 result = not pushop.cgresult
4184 result = not pushop.cgresult
4182
4185
4183 if pushop.bkresult is not None:
4186 if pushop.bkresult is not None:
4184 if pushop.bkresult == 2:
4187 if pushop.bkresult == 2:
4185 result = 2
4188 result = 2
4186 elif not result and pushop.bkresult:
4189 elif not result and pushop.bkresult:
4187 result = 2
4190 result = 2
4188
4191
4189 return result
4192 return result
4190
4193
4191 @command('recover', [])
4194 @command('recover', [])
4192 def recover(ui, repo):
4195 def recover(ui, repo):
4193 """roll back an interrupted transaction
4196 """roll back an interrupted transaction
4194
4197
4195 Recover from an interrupted commit or pull.
4198 Recover from an interrupted commit or pull.
4196
4199
4197 This command tries to fix the repository status after an
4200 This command tries to fix the repository status after an
4198 interrupted operation. It should only be necessary when Mercurial
4201 interrupted operation. It should only be necessary when Mercurial
4199 suggests it.
4202 suggests it.
4200
4203
4201 Returns 0 if successful, 1 if nothing to recover or verify fails.
4204 Returns 0 if successful, 1 if nothing to recover or verify fails.
4202 """
4205 """
4203 if repo.recover():
4206 if repo.recover():
4204 return hg.verify(repo)
4207 return hg.verify(repo)
4205 return 1
4208 return 1
4206
4209
4207 @command('^remove|rm',
4210 @command('^remove|rm',
4208 [('A', 'after', None, _('record delete for missing files')),
4211 [('A', 'after', None, _('record delete for missing files')),
4209 ('f', 'force', None,
4212 ('f', 'force', None,
4210 _('forget added files, delete modified files')),
4213 _('forget added files, delete modified files')),
4211 ] + subrepoopts + walkopts,
4214 ] + subrepoopts + walkopts,
4212 _('[OPTION]... FILE...'),
4215 _('[OPTION]... FILE...'),
4213 inferrepo=True)
4216 inferrepo=True)
4214 def remove(ui, repo, *pats, **opts):
4217 def remove(ui, repo, *pats, **opts):
4215 """remove the specified files on the next commit
4218 """remove the specified files on the next commit
4216
4219
4217 Schedule the indicated files for removal from the current branch.
4220 Schedule the indicated files for removal from the current branch.
4218
4221
4219 This command schedules the files to be removed at the next commit.
4222 This command schedules the files to be removed at the next commit.
4220 To undo a remove before that, see :hg:`revert`. To undo added
4223 To undo a remove before that, see :hg:`revert`. To undo added
4221 files, see :hg:`forget`.
4224 files, see :hg:`forget`.
4222
4225
4223 .. container:: verbose
4226 .. container:: verbose
4224
4227
4225 -A/--after can be used to remove only files that have already
4228 -A/--after can be used to remove only files that have already
4226 been deleted, -f/--force can be used to force deletion, and -Af
4229 been deleted, -f/--force can be used to force deletion, and -Af
4227 can be used to remove files from the next revision without
4230 can be used to remove files from the next revision without
4228 deleting them from the working directory.
4231 deleting them from the working directory.
4229
4232
4230 The following table details the behavior of remove for different
4233 The following table details the behavior of remove for different
4231 file states (columns) and option combinations (rows). The file
4234 file states (columns) and option combinations (rows). The file
4232 states are Added [A], Clean [C], Modified [M] and Missing [!]
4235 states are Added [A], Clean [C], Modified [M] and Missing [!]
4233 (as reported by :hg:`status`). The actions are Warn, Remove
4236 (as reported by :hg:`status`). The actions are Warn, Remove
4234 (from branch) and Delete (from disk):
4237 (from branch) and Delete (from disk):
4235
4238
4236 ========= == == == ==
4239 ========= == == == ==
4237 opt/state A C M !
4240 opt/state A C M !
4238 ========= == == == ==
4241 ========= == == == ==
4239 none W RD W R
4242 none W RD W R
4240 -f R RD RD R
4243 -f R RD RD R
4241 -A W W W R
4244 -A W W W R
4242 -Af R R R R
4245 -Af R R R R
4243 ========= == == == ==
4246 ========= == == == ==
4244
4247
4245 .. note::
4248 .. note::
4246
4249
4247 :hg:`remove` never deletes files in Added [A] state from the
4250 :hg:`remove` never deletes files in Added [A] state from the
4248 working directory, not even if ``--force`` is specified.
4251 working directory, not even if ``--force`` is specified.
4249
4252
4250 Returns 0 on success, 1 if any warnings encountered.
4253 Returns 0 on success, 1 if any warnings encountered.
4251 """
4254 """
4252
4255
4253 opts = pycompat.byteskwargs(opts)
4256 opts = pycompat.byteskwargs(opts)
4254 after, force = opts.get('after'), opts.get('force')
4257 after, force = opts.get('after'), opts.get('force')
4255 if not pats and not after:
4258 if not pats and not after:
4256 raise error.Abort(_('no files specified'))
4259 raise error.Abort(_('no files specified'))
4257
4260
4258 m = scmutil.match(repo[None], pats, opts)
4261 m = scmutil.match(repo[None], pats, opts)
4259 subrepos = opts.get('subrepos')
4262 subrepos = opts.get('subrepos')
4260 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4263 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4261
4264
4262 @command('rename|move|mv',
4265 @command('rename|move|mv',
4263 [('A', 'after', None, _('record a rename that has already occurred')),
4266 [('A', 'after', None, _('record a rename that has already occurred')),
4264 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4267 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4265 ] + walkopts + dryrunopts,
4268 ] + walkopts + dryrunopts,
4266 _('[OPTION]... SOURCE... DEST'))
4269 _('[OPTION]... SOURCE... DEST'))
4267 def rename(ui, repo, *pats, **opts):
4270 def rename(ui, repo, *pats, **opts):
4268 """rename files; equivalent of copy + remove
4271 """rename files; equivalent of copy + remove
4269
4272
4270 Mark dest as copies of sources; mark sources for deletion. If dest
4273 Mark dest as copies of sources; mark sources for deletion. If dest
4271 is a directory, copies are put in that directory. If dest is a
4274 is a directory, copies are put in that directory. If dest is a
4272 file, there can only be one source.
4275 file, there can only be one source.
4273
4276
4274 By default, this command copies the contents of files as they
4277 By default, this command copies the contents of files as they
4275 exist in the working directory. If invoked with -A/--after, the
4278 exist in the working directory. If invoked with -A/--after, the
4276 operation is recorded, but no copying is performed.
4279 operation is recorded, but no copying is performed.
4277
4280
4278 This command takes effect at the next commit. To undo a rename
4281 This command takes effect at the next commit. To undo a rename
4279 before that, see :hg:`revert`.
4282 before that, see :hg:`revert`.
4280
4283
4281 Returns 0 on success, 1 if errors are encountered.
4284 Returns 0 on success, 1 if errors are encountered.
4282 """
4285 """
4283 opts = pycompat.byteskwargs(opts)
4286 opts = pycompat.byteskwargs(opts)
4284 with repo.wlock(False):
4287 with repo.wlock(False):
4285 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4288 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4286
4289
4287 @command('resolve',
4290 @command('resolve',
4288 [('a', 'all', None, _('select all unresolved files')),
4291 [('a', 'all', None, _('select all unresolved files')),
4289 ('l', 'list', None, _('list state of files needing merge')),
4292 ('l', 'list', None, _('list state of files needing merge')),
4290 ('m', 'mark', None, _('mark files as resolved')),
4293 ('m', 'mark', None, _('mark files as resolved')),
4291 ('u', 'unmark', None, _('mark files as unresolved')),
4294 ('u', 'unmark', None, _('mark files as unresolved')),
4292 ('n', 'no-status', None, _('hide status prefix'))]
4295 ('n', 'no-status', None, _('hide status prefix'))]
4293 + mergetoolopts + walkopts + formatteropts,
4296 + mergetoolopts + walkopts + formatteropts,
4294 _('[OPTION]... [FILE]...'),
4297 _('[OPTION]... [FILE]...'),
4295 inferrepo=True)
4298 inferrepo=True)
4296 def resolve(ui, repo, *pats, **opts):
4299 def resolve(ui, repo, *pats, **opts):
4297 """redo merges or set/view the merge status of files
4300 """redo merges or set/view the merge status of files
4298
4301
4299 Merges with unresolved conflicts are often the result of
4302 Merges with unresolved conflicts are often the result of
4300 non-interactive merging using the ``internal:merge`` configuration
4303 non-interactive merging using the ``internal:merge`` configuration
4301 setting, or a command-line merge tool like ``diff3``. The resolve
4304 setting, or a command-line merge tool like ``diff3``. The resolve
4302 command is used to manage the files involved in a merge, after
4305 command is used to manage the files involved in a merge, after
4303 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4306 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4304 working directory must have two parents). See :hg:`help
4307 working directory must have two parents). See :hg:`help
4305 merge-tools` for information on configuring merge tools.
4308 merge-tools` for information on configuring merge tools.
4306
4309
4307 The resolve command can be used in the following ways:
4310 The resolve command can be used in the following ways:
4308
4311
4309 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4312 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4310 files, discarding any previous merge attempts. Re-merging is not
4313 files, discarding any previous merge attempts. Re-merging is not
4311 performed for files already marked as resolved. Use ``--all/-a``
4314 performed for files already marked as resolved. Use ``--all/-a``
4312 to select all unresolved files. ``--tool`` can be used to specify
4315 to select all unresolved files. ``--tool`` can be used to specify
4313 the merge tool used for the given files. It overrides the HGMERGE
4316 the merge tool used for the given files. It overrides the HGMERGE
4314 environment variable and your configuration files. Previous file
4317 environment variable and your configuration files. Previous file
4315 contents are saved with a ``.orig`` suffix.
4318 contents are saved with a ``.orig`` suffix.
4316
4319
4317 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4320 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4318 (e.g. after having manually fixed-up the files). The default is
4321 (e.g. after having manually fixed-up the files). The default is
4319 to mark all unresolved files.
4322 to mark all unresolved files.
4320
4323
4321 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4324 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4322 default is to mark all resolved files.
4325 default is to mark all resolved files.
4323
4326
4324 - :hg:`resolve -l`: list files which had or still have conflicts.
4327 - :hg:`resolve -l`: list files which had or still have conflicts.
4325 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4328 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4326 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4329 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4327 the list. See :hg:`help filesets` for details.
4330 the list. See :hg:`help filesets` for details.
4328
4331
4329 .. note::
4332 .. note::
4330
4333
4331 Mercurial will not let you commit files with unresolved merge
4334 Mercurial will not let you commit files with unresolved merge
4332 conflicts. You must use :hg:`resolve -m ...` before you can
4335 conflicts. You must use :hg:`resolve -m ...` before you can
4333 commit after a conflicting merge.
4336 commit after a conflicting merge.
4334
4337
4335 Returns 0 on success, 1 if any files fail a resolve attempt.
4338 Returns 0 on success, 1 if any files fail a resolve attempt.
4336 """
4339 """
4337
4340
4338 opts = pycompat.byteskwargs(opts)
4341 opts = pycompat.byteskwargs(opts)
4339 flaglist = 'all mark unmark list no_status'.split()
4342 flaglist = 'all mark unmark list no_status'.split()
4340 all, mark, unmark, show, nostatus = \
4343 all, mark, unmark, show, nostatus = \
4341 [opts.get(o) for o in flaglist]
4344 [opts.get(o) for o in flaglist]
4342
4345
4343 if (show and (mark or unmark)) or (mark and unmark):
4346 if (show and (mark or unmark)) or (mark and unmark):
4344 raise error.Abort(_("too many options specified"))
4347 raise error.Abort(_("too many options specified"))
4345 if pats and all:
4348 if pats and all:
4346 raise error.Abort(_("can't specify --all and patterns"))
4349 raise error.Abort(_("can't specify --all and patterns"))
4347 if not (all or pats or show or mark or unmark):
4350 if not (all or pats or show or mark or unmark):
4348 raise error.Abort(_('no files or directories specified'),
4351 raise error.Abort(_('no files or directories specified'),
4349 hint=('use --all to re-merge all unresolved files'))
4352 hint=('use --all to re-merge all unresolved files'))
4350
4353
4351 if show:
4354 if show:
4352 ui.pager('resolve')
4355 ui.pager('resolve')
4353 fm = ui.formatter('resolve', opts)
4356 fm = ui.formatter('resolve', opts)
4354 ms = mergemod.mergestate.read(repo)
4357 ms = mergemod.mergestate.read(repo)
4355 m = scmutil.match(repo[None], pats, opts)
4358 m = scmutil.match(repo[None], pats, opts)
4356
4359
4357 # Labels and keys based on merge state. Unresolved path conflicts show
4360 # Labels and keys based on merge state. Unresolved path conflicts show
4358 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4361 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4359 # resolved conflicts.
4362 # resolved conflicts.
4360 mergestateinfo = {
4363 mergestateinfo = {
4361 'u': ('resolve.unresolved', 'U'),
4364 'u': ('resolve.unresolved', 'U'),
4362 'r': ('resolve.resolved', 'R'),
4365 'r': ('resolve.resolved', 'R'),
4363 'pu': ('resolve.unresolved', 'P'),
4366 'pu': ('resolve.unresolved', 'P'),
4364 'pr': ('resolve.resolved', 'R'),
4367 'pr': ('resolve.resolved', 'R'),
4365 'd': ('resolve.driverresolved', 'D'),
4368 'd': ('resolve.driverresolved', 'D'),
4366 }
4369 }
4367
4370
4368 for f in ms:
4371 for f in ms:
4369 if not m(f):
4372 if not m(f):
4370 continue
4373 continue
4371
4374
4372 label, key = mergestateinfo[ms[f]]
4375 label, key = mergestateinfo[ms[f]]
4373 fm.startitem()
4376 fm.startitem()
4374 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4377 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4375 fm.write('path', '%s\n', f, label=label)
4378 fm.write('path', '%s\n', f, label=label)
4376 fm.end()
4379 fm.end()
4377 return 0
4380 return 0
4378
4381
4379 with repo.wlock():
4382 with repo.wlock():
4380 ms = mergemod.mergestate.read(repo)
4383 ms = mergemod.mergestate.read(repo)
4381
4384
4382 if not (ms.active() or repo.dirstate.p2() != nullid):
4385 if not (ms.active() or repo.dirstate.p2() != nullid):
4383 raise error.Abort(
4386 raise error.Abort(
4384 _('resolve command not applicable when not merging'))
4387 _('resolve command not applicable when not merging'))
4385
4388
4386 wctx = repo[None]
4389 wctx = repo[None]
4387
4390
4388 if ms.mergedriver and ms.mdstate() == 'u':
4391 if ms.mergedriver and ms.mdstate() == 'u':
4389 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4392 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4390 ms.commit()
4393 ms.commit()
4391 # allow mark and unmark to go through
4394 # allow mark and unmark to go through
4392 if not mark and not unmark and not proceed:
4395 if not mark and not unmark and not proceed:
4393 return 1
4396 return 1
4394
4397
4395 m = scmutil.match(wctx, pats, opts)
4398 m = scmutil.match(wctx, pats, opts)
4396 ret = 0
4399 ret = 0
4397 didwork = False
4400 didwork = False
4398 runconclude = False
4401 runconclude = False
4399
4402
4400 tocomplete = []
4403 tocomplete = []
4401 for f in ms:
4404 for f in ms:
4402 if not m(f):
4405 if not m(f):
4403 continue
4406 continue
4404
4407
4405 didwork = True
4408 didwork = True
4406
4409
4407 # don't let driver-resolved files be marked, and run the conclude
4410 # don't let driver-resolved files be marked, and run the conclude
4408 # step if asked to resolve
4411 # step if asked to resolve
4409 if ms[f] == "d":
4412 if ms[f] == "d":
4410 exact = m.exact(f)
4413 exact = m.exact(f)
4411 if mark:
4414 if mark:
4412 if exact:
4415 if exact:
4413 ui.warn(_('not marking %s as it is driver-resolved\n')
4416 ui.warn(_('not marking %s as it is driver-resolved\n')
4414 % f)
4417 % f)
4415 elif unmark:
4418 elif unmark:
4416 if exact:
4419 if exact:
4417 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4420 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4418 % f)
4421 % f)
4419 else:
4422 else:
4420 runconclude = True
4423 runconclude = True
4421 continue
4424 continue
4422
4425
4423 # path conflicts must be resolved manually
4426 # path conflicts must be resolved manually
4424 if ms[f] in ("pu", "pr"):
4427 if ms[f] in ("pu", "pr"):
4425 if mark:
4428 if mark:
4426 ms.mark(f, "pr")
4429 ms.mark(f, "pr")
4427 elif unmark:
4430 elif unmark:
4428 ms.mark(f, "pu")
4431 ms.mark(f, "pu")
4429 elif ms[f] == "pu":
4432 elif ms[f] == "pu":
4430 ui.warn(_('%s: path conflict must be resolved manually\n')
4433 ui.warn(_('%s: path conflict must be resolved manually\n')
4431 % f)
4434 % f)
4432 continue
4435 continue
4433
4436
4434 if mark:
4437 if mark:
4435 ms.mark(f, "r")
4438 ms.mark(f, "r")
4436 elif unmark:
4439 elif unmark:
4437 ms.mark(f, "u")
4440 ms.mark(f, "u")
4438 else:
4441 else:
4439 # backup pre-resolve (merge uses .orig for its own purposes)
4442 # backup pre-resolve (merge uses .orig for its own purposes)
4440 a = repo.wjoin(f)
4443 a = repo.wjoin(f)
4441 try:
4444 try:
4442 util.copyfile(a, a + ".resolve")
4445 util.copyfile(a, a + ".resolve")
4443 except (IOError, OSError) as inst:
4446 except (IOError, OSError) as inst:
4444 if inst.errno != errno.ENOENT:
4447 if inst.errno != errno.ENOENT:
4445 raise
4448 raise
4446
4449
4447 try:
4450 try:
4448 # preresolve file
4451 # preresolve file
4449 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4452 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4450 'resolve')
4453 'resolve')
4451 complete, r = ms.preresolve(f, wctx)
4454 complete, r = ms.preresolve(f, wctx)
4452 if not complete:
4455 if not complete:
4453 tocomplete.append(f)
4456 tocomplete.append(f)
4454 elif r:
4457 elif r:
4455 ret = 1
4458 ret = 1
4456 finally:
4459 finally:
4457 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4460 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4458 ms.commit()
4461 ms.commit()
4459
4462
4460 # replace filemerge's .orig file with our resolve file, but only
4463 # replace filemerge's .orig file with our resolve file, but only
4461 # for merges that are complete
4464 # for merges that are complete
4462 if complete:
4465 if complete:
4463 try:
4466 try:
4464 util.rename(a + ".resolve",
4467 util.rename(a + ".resolve",
4465 scmutil.origpath(ui, repo, a))
4468 scmutil.origpath(ui, repo, a))
4466 except OSError as inst:
4469 except OSError as inst:
4467 if inst.errno != errno.ENOENT:
4470 if inst.errno != errno.ENOENT:
4468 raise
4471 raise
4469
4472
4470 for f in tocomplete:
4473 for f in tocomplete:
4471 try:
4474 try:
4472 # resolve file
4475 # resolve file
4473 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4476 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4474 'resolve')
4477 'resolve')
4475 r = ms.resolve(f, wctx)
4478 r = ms.resolve(f, wctx)
4476 if r:
4479 if r:
4477 ret = 1
4480 ret = 1
4478 finally:
4481 finally:
4479 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4482 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4480 ms.commit()
4483 ms.commit()
4481
4484
4482 # replace filemerge's .orig file with our resolve file
4485 # replace filemerge's .orig file with our resolve file
4483 a = repo.wjoin(f)
4486 a = repo.wjoin(f)
4484 try:
4487 try:
4485 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4488 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4486 except OSError as inst:
4489 except OSError as inst:
4487 if inst.errno != errno.ENOENT:
4490 if inst.errno != errno.ENOENT:
4488 raise
4491 raise
4489
4492
4490 ms.commit()
4493 ms.commit()
4491 ms.recordactions()
4494 ms.recordactions()
4492
4495
4493 if not didwork and pats:
4496 if not didwork and pats:
4494 hint = None
4497 hint = None
4495 if not any([p for p in pats if p.find(':') >= 0]):
4498 if not any([p for p in pats if p.find(':') >= 0]):
4496 pats = ['path:%s' % p for p in pats]
4499 pats = ['path:%s' % p for p in pats]
4497 m = scmutil.match(wctx, pats, opts)
4500 m = scmutil.match(wctx, pats, opts)
4498 for f in ms:
4501 for f in ms:
4499 if not m(f):
4502 if not m(f):
4500 continue
4503 continue
4501 flags = ''.join(['-%s ' % o[0] for o in flaglist
4504 flags = ''.join(['-%s ' % o[0] for o in flaglist
4502 if opts.get(o)])
4505 if opts.get(o)])
4503 hint = _("(try: hg resolve %s%s)\n") % (
4506 hint = _("(try: hg resolve %s%s)\n") % (
4504 flags,
4507 flags,
4505 ' '.join(pats))
4508 ' '.join(pats))
4506 break
4509 break
4507 ui.warn(_("arguments do not match paths that need resolving\n"))
4510 ui.warn(_("arguments do not match paths that need resolving\n"))
4508 if hint:
4511 if hint:
4509 ui.warn(hint)
4512 ui.warn(hint)
4510 elif ms.mergedriver and ms.mdstate() != 's':
4513 elif ms.mergedriver and ms.mdstate() != 's':
4511 # run conclude step when either a driver-resolved file is requested
4514 # run conclude step when either a driver-resolved file is requested
4512 # or there are no driver-resolved files
4515 # or there are no driver-resolved files
4513 # we can't use 'ret' to determine whether any files are unresolved
4516 # we can't use 'ret' to determine whether any files are unresolved
4514 # because we might not have tried to resolve some
4517 # because we might not have tried to resolve some
4515 if ((runconclude or not list(ms.driverresolved()))
4518 if ((runconclude or not list(ms.driverresolved()))
4516 and not list(ms.unresolved())):
4519 and not list(ms.unresolved())):
4517 proceed = mergemod.driverconclude(repo, ms, wctx)
4520 proceed = mergemod.driverconclude(repo, ms, wctx)
4518 ms.commit()
4521 ms.commit()
4519 if not proceed:
4522 if not proceed:
4520 return 1
4523 return 1
4521
4524
4522 # Nudge users into finishing an unfinished operation
4525 # Nudge users into finishing an unfinished operation
4523 unresolvedf = list(ms.unresolved())
4526 unresolvedf = list(ms.unresolved())
4524 driverresolvedf = list(ms.driverresolved())
4527 driverresolvedf = list(ms.driverresolved())
4525 if not unresolvedf and not driverresolvedf:
4528 if not unresolvedf and not driverresolvedf:
4526 ui.status(_('(no more unresolved files)\n'))
4529 ui.status(_('(no more unresolved files)\n'))
4527 cmdutil.checkafterresolved(repo)
4530 cmdutil.checkafterresolved(repo)
4528 elif not unresolvedf:
4531 elif not unresolvedf:
4529 ui.status(_('(no more unresolved files -- '
4532 ui.status(_('(no more unresolved files -- '
4530 'run "hg resolve --all" to conclude)\n'))
4533 'run "hg resolve --all" to conclude)\n'))
4531
4534
4532 return ret
4535 return ret
4533
4536
4534 @command('revert',
4537 @command('revert',
4535 [('a', 'all', None, _('revert all changes when no arguments given')),
4538 [('a', 'all', None, _('revert all changes when no arguments given')),
4536 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4539 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4537 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4540 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4538 ('C', 'no-backup', None, _('do not save backup copies of files')),
4541 ('C', 'no-backup', None, _('do not save backup copies of files')),
4539 ('i', 'interactive', None, _('interactively select the changes')),
4542 ('i', 'interactive', None, _('interactively select the changes')),
4540 ] + walkopts + dryrunopts,
4543 ] + walkopts + dryrunopts,
4541 _('[OPTION]... [-r REV] [NAME]...'))
4544 _('[OPTION]... [-r REV] [NAME]...'))
4542 def revert(ui, repo, *pats, **opts):
4545 def revert(ui, repo, *pats, **opts):
4543 """restore files to their checkout state
4546 """restore files to their checkout state
4544
4547
4545 .. note::
4548 .. note::
4546
4549
4547 To check out earlier revisions, you should use :hg:`update REV`.
4550 To check out earlier revisions, you should use :hg:`update REV`.
4548 To cancel an uncommitted merge (and lose your changes),
4551 To cancel an uncommitted merge (and lose your changes),
4549 use :hg:`update --clean .`.
4552 use :hg:`update --clean .`.
4550
4553
4551 With no revision specified, revert the specified files or directories
4554 With no revision specified, revert the specified files or directories
4552 to the contents they had in the parent of the working directory.
4555 to the contents they had in the parent of the working directory.
4553 This restores the contents of files to an unmodified
4556 This restores the contents of files to an unmodified
4554 state and unschedules adds, removes, copies, and renames. If the
4557 state and unschedules adds, removes, copies, and renames. If the
4555 working directory has two parents, you must explicitly specify a
4558 working directory has two parents, you must explicitly specify a
4556 revision.
4559 revision.
4557
4560
4558 Using the -r/--rev or -d/--date options, revert the given files or
4561 Using the -r/--rev or -d/--date options, revert the given files or
4559 directories to their states as of a specific revision. Because
4562 directories to their states as of a specific revision. Because
4560 revert does not change the working directory parents, this will
4563 revert does not change the working directory parents, this will
4561 cause these files to appear modified. This can be helpful to "back
4564 cause these files to appear modified. This can be helpful to "back
4562 out" some or all of an earlier change. See :hg:`backout` for a
4565 out" some or all of an earlier change. See :hg:`backout` for a
4563 related method.
4566 related method.
4564
4567
4565 Modified files are saved with a .orig suffix before reverting.
4568 Modified files are saved with a .orig suffix before reverting.
4566 To disable these backups, use --no-backup. It is possible to store
4569 To disable these backups, use --no-backup. It is possible to store
4567 the backup files in a custom directory relative to the root of the
4570 the backup files in a custom directory relative to the root of the
4568 repository by setting the ``ui.origbackuppath`` configuration
4571 repository by setting the ``ui.origbackuppath`` configuration
4569 option.
4572 option.
4570
4573
4571 See :hg:`help dates` for a list of formats valid for -d/--date.
4574 See :hg:`help dates` for a list of formats valid for -d/--date.
4572
4575
4573 See :hg:`help backout` for a way to reverse the effect of an
4576 See :hg:`help backout` for a way to reverse the effect of an
4574 earlier changeset.
4577 earlier changeset.
4575
4578
4576 Returns 0 on success.
4579 Returns 0 on success.
4577 """
4580 """
4578
4581
4579 opts = pycompat.byteskwargs(opts)
4582 opts = pycompat.byteskwargs(opts)
4580 if opts.get("date"):
4583 if opts.get("date"):
4581 if opts.get("rev"):
4584 if opts.get("rev"):
4582 raise error.Abort(_("you can't specify a revision and a date"))
4585 raise error.Abort(_("you can't specify a revision and a date"))
4583 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4586 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4584
4587
4585 parent, p2 = repo.dirstate.parents()
4588 parent, p2 = repo.dirstate.parents()
4586 if not opts.get('rev') and p2 != nullid:
4589 if not opts.get('rev') and p2 != nullid:
4587 # revert after merge is a trap for new users (issue2915)
4590 # revert after merge is a trap for new users (issue2915)
4588 raise error.Abort(_('uncommitted merge with no revision specified'),
4591 raise error.Abort(_('uncommitted merge with no revision specified'),
4589 hint=_("use 'hg update' or see 'hg help revert'"))
4592 hint=_("use 'hg update' or see 'hg help revert'"))
4590
4593
4591 rev = opts.get('rev')
4594 rev = opts.get('rev')
4592 if rev:
4595 if rev:
4593 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4596 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4594 ctx = scmutil.revsingle(repo, rev)
4597 ctx = scmutil.revsingle(repo, rev)
4595
4598
4596 if (not (pats or opts.get('include') or opts.get('exclude') or
4599 if (not (pats or opts.get('include') or opts.get('exclude') or
4597 opts.get('all') or opts.get('interactive'))):
4600 opts.get('all') or opts.get('interactive'))):
4598 msg = _("no files or directories specified")
4601 msg = _("no files or directories specified")
4599 if p2 != nullid:
4602 if p2 != nullid:
4600 hint = _("uncommitted merge, use --all to discard all changes,"
4603 hint = _("uncommitted merge, use --all to discard all changes,"
4601 " or 'hg update -C .' to abort the merge")
4604 " or 'hg update -C .' to abort the merge")
4602 raise error.Abort(msg, hint=hint)
4605 raise error.Abort(msg, hint=hint)
4603 dirty = any(repo.status())
4606 dirty = any(repo.status())
4604 node = ctx.node()
4607 node = ctx.node()
4605 if node != parent:
4608 if node != parent:
4606 if dirty:
4609 if dirty:
4607 hint = _("uncommitted changes, use --all to discard all"
4610 hint = _("uncommitted changes, use --all to discard all"
4608 " changes, or 'hg update %s' to update") % ctx.rev()
4611 " changes, or 'hg update %s' to update") % ctx.rev()
4609 else:
4612 else:
4610 hint = _("use --all to revert all files,"
4613 hint = _("use --all to revert all files,"
4611 " or 'hg update %s' to update") % ctx.rev()
4614 " or 'hg update %s' to update") % ctx.rev()
4612 elif dirty:
4615 elif dirty:
4613 hint = _("uncommitted changes, use --all to discard all changes")
4616 hint = _("uncommitted changes, use --all to discard all changes")
4614 else:
4617 else:
4615 hint = _("use --all to revert all files")
4618 hint = _("use --all to revert all files")
4616 raise error.Abort(msg, hint=hint)
4619 raise error.Abort(msg, hint=hint)
4617
4620
4618 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4621 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4619 **pycompat.strkwargs(opts))
4622 **pycompat.strkwargs(opts))
4620
4623
4621 @command('rollback', dryrunopts +
4624 @command('rollback', dryrunopts +
4622 [('f', 'force', False, _('ignore safety measures'))])
4625 [('f', 'force', False, _('ignore safety measures'))])
4623 def rollback(ui, repo, **opts):
4626 def rollback(ui, repo, **opts):
4624 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4627 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4625
4628
4626 Please use :hg:`commit --amend` instead of rollback to correct
4629 Please use :hg:`commit --amend` instead of rollback to correct
4627 mistakes in the last commit.
4630 mistakes in the last commit.
4628
4631
4629 This command should be used with care. There is only one level of
4632 This command should be used with care. There is only one level of
4630 rollback, and there is no way to undo a rollback. It will also
4633 rollback, and there is no way to undo a rollback. It will also
4631 restore the dirstate at the time of the last transaction, losing
4634 restore the dirstate at the time of the last transaction, losing
4632 any dirstate changes since that time. This command does not alter
4635 any dirstate changes since that time. This command does not alter
4633 the working directory.
4636 the working directory.
4634
4637
4635 Transactions are used to encapsulate the effects of all commands
4638 Transactions are used to encapsulate the effects of all commands
4636 that create new changesets or propagate existing changesets into a
4639 that create new changesets or propagate existing changesets into a
4637 repository.
4640 repository.
4638
4641
4639 .. container:: verbose
4642 .. container:: verbose
4640
4643
4641 For example, the following commands are transactional, and their
4644 For example, the following commands are transactional, and their
4642 effects can be rolled back:
4645 effects can be rolled back:
4643
4646
4644 - commit
4647 - commit
4645 - import
4648 - import
4646 - pull
4649 - pull
4647 - push (with this repository as the destination)
4650 - push (with this repository as the destination)
4648 - unbundle
4651 - unbundle
4649
4652
4650 To avoid permanent data loss, rollback will refuse to rollback a
4653 To avoid permanent data loss, rollback will refuse to rollback a
4651 commit transaction if it isn't checked out. Use --force to
4654 commit transaction if it isn't checked out. Use --force to
4652 override this protection.
4655 override this protection.
4653
4656
4654 The rollback command can be entirely disabled by setting the
4657 The rollback command can be entirely disabled by setting the
4655 ``ui.rollback`` configuration setting to false. If you're here
4658 ``ui.rollback`` configuration setting to false. If you're here
4656 because you want to use rollback and it's disabled, you can
4659 because you want to use rollback and it's disabled, you can
4657 re-enable the command by setting ``ui.rollback`` to true.
4660 re-enable the command by setting ``ui.rollback`` to true.
4658
4661
4659 This command is not intended for use on public repositories. Once
4662 This command is not intended for use on public repositories. Once
4660 changes are visible for pull by other users, rolling a transaction
4663 changes are visible for pull by other users, rolling a transaction
4661 back locally is ineffective (someone else may already have pulled
4664 back locally is ineffective (someone else may already have pulled
4662 the changes). Furthermore, a race is possible with readers of the
4665 the changes). Furthermore, a race is possible with readers of the
4663 repository; for example an in-progress pull from the repository
4666 repository; for example an in-progress pull from the repository
4664 may fail if a rollback is performed.
4667 may fail if a rollback is performed.
4665
4668
4666 Returns 0 on success, 1 if no rollback data is available.
4669 Returns 0 on success, 1 if no rollback data is available.
4667 """
4670 """
4668 if not ui.configbool('ui', 'rollback'):
4671 if not ui.configbool('ui', 'rollback'):
4669 raise error.Abort(_('rollback is disabled because it is unsafe'),
4672 raise error.Abort(_('rollback is disabled because it is unsafe'),
4670 hint=('see `hg help -v rollback` for information'))
4673 hint=('see `hg help -v rollback` for information'))
4671 return repo.rollback(dryrun=opts.get(r'dry_run'),
4674 return repo.rollback(dryrun=opts.get(r'dry_run'),
4672 force=opts.get(r'force'))
4675 force=opts.get(r'force'))
4673
4676
4674 @command('root', [], cmdtype=readonly)
4677 @command('root', [], cmdtype=readonly)
4675 def root(ui, repo):
4678 def root(ui, repo):
4676 """print the root (top) of the current working directory
4679 """print the root (top) of the current working directory
4677
4680
4678 Print the root directory of the current repository.
4681 Print the root directory of the current repository.
4679
4682
4680 Returns 0 on success.
4683 Returns 0 on success.
4681 """
4684 """
4682 ui.write(repo.root + "\n")
4685 ui.write(repo.root + "\n")
4683
4686
4684 @command('^serve',
4687 @command('^serve',
4685 [('A', 'accesslog', '', _('name of access log file to write to'),
4688 [('A', 'accesslog', '', _('name of access log file to write to'),
4686 _('FILE')),
4689 _('FILE')),
4687 ('d', 'daemon', None, _('run server in background')),
4690 ('d', 'daemon', None, _('run server in background')),
4688 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4691 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4689 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4692 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4690 # use string type, then we can check if something was passed
4693 # use string type, then we can check if something was passed
4691 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4694 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4692 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4695 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4693 _('ADDR')),
4696 _('ADDR')),
4694 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4697 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4695 _('PREFIX')),
4698 _('PREFIX')),
4696 ('n', 'name', '',
4699 ('n', 'name', '',
4697 _('name to show in web pages (default: working directory)'), _('NAME')),
4700 _('name to show in web pages (default: working directory)'), _('NAME')),
4698 ('', 'web-conf', '',
4701 ('', 'web-conf', '',
4699 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4702 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4700 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4703 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4701 _('FILE')),
4704 _('FILE')),
4702 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4705 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4703 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4706 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4704 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4707 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4705 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4708 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4706 ('', 'style', '', _('template style to use'), _('STYLE')),
4709 ('', 'style', '', _('template style to use'), _('STYLE')),
4707 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4710 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4708 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4711 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4709 + subrepoopts,
4712 + subrepoopts,
4710 _('[OPTION]...'),
4713 _('[OPTION]...'),
4711 optionalrepo=True)
4714 optionalrepo=True)
4712 def serve(ui, repo, **opts):
4715 def serve(ui, repo, **opts):
4713 """start stand-alone webserver
4716 """start stand-alone webserver
4714
4717
4715 Start a local HTTP repository browser and pull server. You can use
4718 Start a local HTTP repository browser and pull server. You can use
4716 this for ad-hoc sharing and browsing of repositories. It is
4719 this for ad-hoc sharing and browsing of repositories. It is
4717 recommended to use a real web server to serve a repository for
4720 recommended to use a real web server to serve a repository for
4718 longer periods of time.
4721 longer periods of time.
4719
4722
4720 Please note that the server does not implement access control.
4723 Please note that the server does not implement access control.
4721 This means that, by default, anybody can read from the server and
4724 This means that, by default, anybody can read from the server and
4722 nobody can write to it by default. Set the ``web.allow-push``
4725 nobody can write to it by default. Set the ``web.allow-push``
4723 option to ``*`` to allow everybody to push to the server. You
4726 option to ``*`` to allow everybody to push to the server. You
4724 should use a real web server if you need to authenticate users.
4727 should use a real web server if you need to authenticate users.
4725
4728
4726 By default, the server logs accesses to stdout and errors to
4729 By default, the server logs accesses to stdout and errors to
4727 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4730 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4728 files.
4731 files.
4729
4732
4730 To have the server choose a free port number to listen on, specify
4733 To have the server choose a free port number to listen on, specify
4731 a port number of 0; in this case, the server will print the port
4734 a port number of 0; in this case, the server will print the port
4732 number it uses.
4735 number it uses.
4733
4736
4734 Returns 0 on success.
4737 Returns 0 on success.
4735 """
4738 """
4736
4739
4737 opts = pycompat.byteskwargs(opts)
4740 opts = pycompat.byteskwargs(opts)
4738 if opts["stdio"] and opts["cmdserver"]:
4741 if opts["stdio"] and opts["cmdserver"]:
4739 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4742 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4740
4743
4741 if opts["stdio"]:
4744 if opts["stdio"]:
4742 if repo is None:
4745 if repo is None:
4743 raise error.RepoError(_("there is no Mercurial repository here"
4746 raise error.RepoError(_("there is no Mercurial repository here"
4744 " (.hg not found)"))
4747 " (.hg not found)"))
4745 s = sshserver.sshserver(ui, repo)
4748 s = sshserver.sshserver(ui, repo)
4746 s.serve_forever()
4749 s.serve_forever()
4747
4750
4748 service = server.createservice(ui, repo, opts)
4751 service = server.createservice(ui, repo, opts)
4749 return server.runservice(opts, initfn=service.init, runfn=service.run)
4752 return server.runservice(opts, initfn=service.init, runfn=service.run)
4750
4753
4751 @command('^status|st',
4754 @command('^status|st',
4752 [('A', 'all', None, _('show status of all files')),
4755 [('A', 'all', None, _('show status of all files')),
4753 ('m', 'modified', None, _('show only modified files')),
4756 ('m', 'modified', None, _('show only modified files')),
4754 ('a', 'added', None, _('show only added files')),
4757 ('a', 'added', None, _('show only added files')),
4755 ('r', 'removed', None, _('show only removed files')),
4758 ('r', 'removed', None, _('show only removed files')),
4756 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4759 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4757 ('c', 'clean', None, _('show only files without changes')),
4760 ('c', 'clean', None, _('show only files without changes')),
4758 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4761 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4759 ('i', 'ignored', None, _('show only ignored files')),
4762 ('i', 'ignored', None, _('show only ignored files')),
4760 ('n', 'no-status', None, _('hide status prefix')),
4763 ('n', 'no-status', None, _('hide status prefix')),
4761 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4764 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4762 ('C', 'copies', None, _('show source of copied files')),
4765 ('C', 'copies', None, _('show source of copied files')),
4763 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4766 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4764 ('', 'rev', [], _('show difference from revision'), _('REV')),
4767 ('', 'rev', [], _('show difference from revision'), _('REV')),
4765 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4768 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4766 ] + walkopts + subrepoopts + formatteropts,
4769 ] + walkopts + subrepoopts + formatteropts,
4767 _('[OPTION]... [FILE]...'),
4770 _('[OPTION]... [FILE]...'),
4768 inferrepo=True, cmdtype=readonly)
4771 inferrepo=True, cmdtype=readonly)
4769 def status(ui, repo, *pats, **opts):
4772 def status(ui, repo, *pats, **opts):
4770 """show changed files in the working directory
4773 """show changed files in the working directory
4771
4774
4772 Show status of files in the repository. If names are given, only
4775 Show status of files in the repository. If names are given, only
4773 files that match are shown. Files that are clean or ignored or
4776 files that match are shown. Files that are clean or ignored or
4774 the source of a copy/move operation, are not listed unless
4777 the source of a copy/move operation, are not listed unless
4775 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4778 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4776 Unless options described with "show only ..." are given, the
4779 Unless options described with "show only ..." are given, the
4777 options -mardu are used.
4780 options -mardu are used.
4778
4781
4779 Option -q/--quiet hides untracked (unknown and ignored) files
4782 Option -q/--quiet hides untracked (unknown and ignored) files
4780 unless explicitly requested with -u/--unknown or -i/--ignored.
4783 unless explicitly requested with -u/--unknown or -i/--ignored.
4781
4784
4782 .. note::
4785 .. note::
4783
4786
4784 :hg:`status` may appear to disagree with diff if permissions have
4787 :hg:`status` may appear to disagree with diff if permissions have
4785 changed or a merge has occurred. The standard diff format does
4788 changed or a merge has occurred. The standard diff format does
4786 not report permission changes and diff only reports changes
4789 not report permission changes and diff only reports changes
4787 relative to one merge parent.
4790 relative to one merge parent.
4788
4791
4789 If one revision is given, it is used as the base revision.
4792 If one revision is given, it is used as the base revision.
4790 If two revisions are given, the differences between them are
4793 If two revisions are given, the differences between them are
4791 shown. The --change option can also be used as a shortcut to list
4794 shown. The --change option can also be used as a shortcut to list
4792 the changed files of a revision from its first parent.
4795 the changed files of a revision from its first parent.
4793
4796
4794 The codes used to show the status of files are::
4797 The codes used to show the status of files are::
4795
4798
4796 M = modified
4799 M = modified
4797 A = added
4800 A = added
4798 R = removed
4801 R = removed
4799 C = clean
4802 C = clean
4800 ! = missing (deleted by non-hg command, but still tracked)
4803 ! = missing (deleted by non-hg command, but still tracked)
4801 ? = not tracked
4804 ? = not tracked
4802 I = ignored
4805 I = ignored
4803 = origin of the previous file (with --copies)
4806 = origin of the previous file (with --copies)
4804
4807
4805 .. container:: verbose
4808 .. container:: verbose
4806
4809
4807 The -t/--terse option abbreviates the output by showing only the directory
4810 The -t/--terse option abbreviates the output by showing only the directory
4808 name if all the files in it share the same status. The option takes an
4811 name if all the files in it share the same status. The option takes an
4809 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4812 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4810 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4813 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4811 for 'ignored' and 'c' for clean.
4814 for 'ignored' and 'c' for clean.
4812
4815
4813 It abbreviates only those statuses which are passed. Note that clean and
4816 It abbreviates only those statuses which are passed. Note that clean and
4814 ignored files are not displayed with '--terse ic' unless the -c/--clean
4817 ignored files are not displayed with '--terse ic' unless the -c/--clean
4815 and -i/--ignored options are also used.
4818 and -i/--ignored options are also used.
4816
4819
4817 The -v/--verbose option shows information when the repository is in an
4820 The -v/--verbose option shows information when the repository is in an
4818 unfinished merge, shelve, rebase state etc. You can have this behavior
4821 unfinished merge, shelve, rebase state etc. You can have this behavior
4819 turned on by default by enabling the ``commands.status.verbose`` option.
4822 turned on by default by enabling the ``commands.status.verbose`` option.
4820
4823
4821 You can skip displaying some of these states by setting
4824 You can skip displaying some of these states by setting
4822 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4825 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4823 'histedit', 'merge', 'rebase', or 'unshelve'.
4826 'histedit', 'merge', 'rebase', or 'unshelve'.
4824
4827
4825 Examples:
4828 Examples:
4826
4829
4827 - show changes in the working directory relative to a
4830 - show changes in the working directory relative to a
4828 changeset::
4831 changeset::
4829
4832
4830 hg status --rev 9353
4833 hg status --rev 9353
4831
4834
4832 - show changes in the working directory relative to the
4835 - show changes in the working directory relative to the
4833 current directory (see :hg:`help patterns` for more information)::
4836 current directory (see :hg:`help patterns` for more information)::
4834
4837
4835 hg status re:
4838 hg status re:
4836
4839
4837 - show all changes including copies in an existing changeset::
4840 - show all changes including copies in an existing changeset::
4838
4841
4839 hg status --copies --change 9353
4842 hg status --copies --change 9353
4840
4843
4841 - get a NUL separated list of added files, suitable for xargs::
4844 - get a NUL separated list of added files, suitable for xargs::
4842
4845
4843 hg status -an0
4846 hg status -an0
4844
4847
4845 - show more information about the repository status, abbreviating
4848 - show more information about the repository status, abbreviating
4846 added, removed, modified, deleted, and untracked paths::
4849 added, removed, modified, deleted, and untracked paths::
4847
4850
4848 hg status -v -t mardu
4851 hg status -v -t mardu
4849
4852
4850 Returns 0 on success.
4853 Returns 0 on success.
4851
4854
4852 """
4855 """
4853
4856
4854 opts = pycompat.byteskwargs(opts)
4857 opts = pycompat.byteskwargs(opts)
4855 revs = opts.get('rev')
4858 revs = opts.get('rev')
4856 change = opts.get('change')
4859 change = opts.get('change')
4857 terse = opts.get('terse')
4860 terse = opts.get('terse')
4858
4861
4859 if revs and change:
4862 if revs and change:
4860 msg = _('cannot specify --rev and --change at the same time')
4863 msg = _('cannot specify --rev and --change at the same time')
4861 raise error.Abort(msg)
4864 raise error.Abort(msg)
4862 elif revs and terse:
4865 elif revs and terse:
4863 msg = _('cannot use --terse with --rev')
4866 msg = _('cannot use --terse with --rev')
4864 raise error.Abort(msg)
4867 raise error.Abort(msg)
4865 elif change:
4868 elif change:
4866 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4869 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
4867 node2 = scmutil.revsingle(repo, change, None).node()
4870 node2 = scmutil.revsingle(repo, change, None).node()
4868 node1 = repo[node2].p1().node()
4871 node1 = repo[node2].p1().node()
4869 else:
4872 else:
4870 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4873 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
4871 node1, node2 = scmutil.revpair(repo, revs)
4874 node1, node2 = scmutil.revpair(repo, revs)
4872
4875
4873 if pats or ui.configbool('commands', 'status.relative'):
4876 if pats or ui.configbool('commands', 'status.relative'):
4874 cwd = repo.getcwd()
4877 cwd = repo.getcwd()
4875 else:
4878 else:
4876 cwd = ''
4879 cwd = ''
4877
4880
4878 if opts.get('print0'):
4881 if opts.get('print0'):
4879 end = '\0'
4882 end = '\0'
4880 else:
4883 else:
4881 end = '\n'
4884 end = '\n'
4882 copy = {}
4885 copy = {}
4883 states = 'modified added removed deleted unknown ignored clean'.split()
4886 states = 'modified added removed deleted unknown ignored clean'.split()
4884 show = [k for k in states if opts.get(k)]
4887 show = [k for k in states if opts.get(k)]
4885 if opts.get('all'):
4888 if opts.get('all'):
4886 show += ui.quiet and (states[:4] + ['clean']) or states
4889 show += ui.quiet and (states[:4] + ['clean']) or states
4887
4890
4888 if not show:
4891 if not show:
4889 if ui.quiet:
4892 if ui.quiet:
4890 show = states[:4]
4893 show = states[:4]
4891 else:
4894 else:
4892 show = states[:5]
4895 show = states[:5]
4893
4896
4894 m = scmutil.match(repo[node2], pats, opts)
4897 m = scmutil.match(repo[node2], pats, opts)
4895 if terse:
4898 if terse:
4896 # we need to compute clean and unknown to terse
4899 # we need to compute clean and unknown to terse
4897 stat = repo.status(node1, node2, m,
4900 stat = repo.status(node1, node2, m,
4898 'ignored' in show or 'i' in terse,
4901 'ignored' in show or 'i' in terse,
4899 True, True, opts.get('subrepos'))
4902 True, True, opts.get('subrepos'))
4900
4903
4901 stat = cmdutil.tersedir(stat, terse)
4904 stat = cmdutil.tersedir(stat, terse)
4902 else:
4905 else:
4903 stat = repo.status(node1, node2, m,
4906 stat = repo.status(node1, node2, m,
4904 'ignored' in show, 'clean' in show,
4907 'ignored' in show, 'clean' in show,
4905 'unknown' in show, opts.get('subrepos'))
4908 'unknown' in show, opts.get('subrepos'))
4906
4909
4907 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4910 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4908
4911
4909 if (opts.get('all') or opts.get('copies')
4912 if (opts.get('all') or opts.get('copies')
4910 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4913 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4911 copy = copies.pathcopies(repo[node1], repo[node2], m)
4914 copy = copies.pathcopies(repo[node1], repo[node2], m)
4912
4915
4913 ui.pager('status')
4916 ui.pager('status')
4914 fm = ui.formatter('status', opts)
4917 fm = ui.formatter('status', opts)
4915 fmt = '%s' + end
4918 fmt = '%s' + end
4916 showchar = not opts.get('no_status')
4919 showchar = not opts.get('no_status')
4917
4920
4918 for state, char, files in changestates:
4921 for state, char, files in changestates:
4919 if state in show:
4922 if state in show:
4920 label = 'status.' + state
4923 label = 'status.' + state
4921 for f in files:
4924 for f in files:
4922 fm.startitem()
4925 fm.startitem()
4923 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4926 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4924 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4927 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4925 if f in copy:
4928 if f in copy:
4926 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4929 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4927 label='status.copied')
4930 label='status.copied')
4928
4931
4929 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4932 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4930 and not ui.plain()):
4933 and not ui.plain()):
4931 cmdutil.morestatus(repo, fm)
4934 cmdutil.morestatus(repo, fm)
4932 fm.end()
4935 fm.end()
4933
4936
4934 @command('^summary|sum',
4937 @command('^summary|sum',
4935 [('', 'remote', None, _('check for push and pull'))],
4938 [('', 'remote', None, _('check for push and pull'))],
4936 '[--remote]', cmdtype=readonly)
4939 '[--remote]', cmdtype=readonly)
4937 def summary(ui, repo, **opts):
4940 def summary(ui, repo, **opts):
4938 """summarize working directory state
4941 """summarize working directory state
4939
4942
4940 This generates a brief summary of the working directory state,
4943 This generates a brief summary of the working directory state,
4941 including parents, branch, commit status, phase and available updates.
4944 including parents, branch, commit status, phase and available updates.
4942
4945
4943 With the --remote option, this will check the default paths for
4946 With the --remote option, this will check the default paths for
4944 incoming and outgoing changes. This can be time-consuming.
4947 incoming and outgoing changes. This can be time-consuming.
4945
4948
4946 Returns 0 on success.
4949 Returns 0 on success.
4947 """
4950 """
4948
4951
4949 opts = pycompat.byteskwargs(opts)
4952 opts = pycompat.byteskwargs(opts)
4950 ui.pager('summary')
4953 ui.pager('summary')
4951 ctx = repo[None]
4954 ctx = repo[None]
4952 parents = ctx.parents()
4955 parents = ctx.parents()
4953 pnode = parents[0].node()
4956 pnode = parents[0].node()
4954 marks = []
4957 marks = []
4955
4958
4956 ms = None
4959 ms = None
4957 try:
4960 try:
4958 ms = mergemod.mergestate.read(repo)
4961 ms = mergemod.mergestate.read(repo)
4959 except error.UnsupportedMergeRecords as e:
4962 except error.UnsupportedMergeRecords as e:
4960 s = ' '.join(e.recordtypes)
4963 s = ' '.join(e.recordtypes)
4961 ui.warn(
4964 ui.warn(
4962 _('warning: merge state has unsupported record types: %s\n') % s)
4965 _('warning: merge state has unsupported record types: %s\n') % s)
4963 unresolved = []
4966 unresolved = []
4964 else:
4967 else:
4965 unresolved = list(ms.unresolved())
4968 unresolved = list(ms.unresolved())
4966
4969
4967 for p in parents:
4970 for p in parents:
4968 # label with log.changeset (instead of log.parent) since this
4971 # label with log.changeset (instead of log.parent) since this
4969 # shows a working directory parent *changeset*:
4972 # shows a working directory parent *changeset*:
4970 # i18n: column positioning for "hg summary"
4973 # i18n: column positioning for "hg summary"
4971 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4974 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4972 label=cmdutil._changesetlabels(p))
4975 label=cmdutil._changesetlabels(p))
4973 ui.write(' '.join(p.tags()), label='log.tag')
4976 ui.write(' '.join(p.tags()), label='log.tag')
4974 if p.bookmarks():
4977 if p.bookmarks():
4975 marks.extend(p.bookmarks())
4978 marks.extend(p.bookmarks())
4976 if p.rev() == -1:
4979 if p.rev() == -1:
4977 if not len(repo):
4980 if not len(repo):
4978 ui.write(_(' (empty repository)'))
4981 ui.write(_(' (empty repository)'))
4979 else:
4982 else:
4980 ui.write(_(' (no revision checked out)'))
4983 ui.write(_(' (no revision checked out)'))
4981 if p.obsolete():
4984 if p.obsolete():
4982 ui.write(_(' (obsolete)'))
4985 ui.write(_(' (obsolete)'))
4983 if p.isunstable():
4986 if p.isunstable():
4984 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4987 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4985 for instability in p.instabilities())
4988 for instability in p.instabilities())
4986 ui.write(' ('
4989 ui.write(' ('
4987 + ', '.join(instabilities)
4990 + ', '.join(instabilities)
4988 + ')')
4991 + ')')
4989 ui.write('\n')
4992 ui.write('\n')
4990 if p.description():
4993 if p.description():
4991 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4994 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4992 label='log.summary')
4995 label='log.summary')
4993
4996
4994 branch = ctx.branch()
4997 branch = ctx.branch()
4995 bheads = repo.branchheads(branch)
4998 bheads = repo.branchheads(branch)
4996 # i18n: column positioning for "hg summary"
4999 # i18n: column positioning for "hg summary"
4997 m = _('branch: %s\n') % branch
5000 m = _('branch: %s\n') % branch
4998 if branch != 'default':
5001 if branch != 'default':
4999 ui.write(m, label='log.branch')
5002 ui.write(m, label='log.branch')
5000 else:
5003 else:
5001 ui.status(m, label='log.branch')
5004 ui.status(m, label='log.branch')
5002
5005
5003 if marks:
5006 if marks:
5004 active = repo._activebookmark
5007 active = repo._activebookmark
5005 # i18n: column positioning for "hg summary"
5008 # i18n: column positioning for "hg summary"
5006 ui.write(_('bookmarks:'), label='log.bookmark')
5009 ui.write(_('bookmarks:'), label='log.bookmark')
5007 if active is not None:
5010 if active is not None:
5008 if active in marks:
5011 if active in marks:
5009 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5012 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5010 marks.remove(active)
5013 marks.remove(active)
5011 else:
5014 else:
5012 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5015 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5013 for m in marks:
5016 for m in marks:
5014 ui.write(' ' + m, label='log.bookmark')
5017 ui.write(' ' + m, label='log.bookmark')
5015 ui.write('\n', label='log.bookmark')
5018 ui.write('\n', label='log.bookmark')
5016
5019
5017 status = repo.status(unknown=True)
5020 status = repo.status(unknown=True)
5018
5021
5019 c = repo.dirstate.copies()
5022 c = repo.dirstate.copies()
5020 copied, renamed = [], []
5023 copied, renamed = [], []
5021 for d, s in c.iteritems():
5024 for d, s in c.iteritems():
5022 if s in status.removed:
5025 if s in status.removed:
5023 status.removed.remove(s)
5026 status.removed.remove(s)
5024 renamed.append(d)
5027 renamed.append(d)
5025 else:
5028 else:
5026 copied.append(d)
5029 copied.append(d)
5027 if d in status.added:
5030 if d in status.added:
5028 status.added.remove(d)
5031 status.added.remove(d)
5029
5032
5030 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5033 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5031
5034
5032 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5035 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5033 (ui.label(_('%d added'), 'status.added'), status.added),
5036 (ui.label(_('%d added'), 'status.added'), status.added),
5034 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5037 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5035 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5038 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5036 (ui.label(_('%d copied'), 'status.copied'), copied),
5039 (ui.label(_('%d copied'), 'status.copied'), copied),
5037 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5040 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5038 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5041 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5039 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5042 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5040 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5043 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5041 t = []
5044 t = []
5042 for l, s in labels:
5045 for l, s in labels:
5043 if s:
5046 if s:
5044 t.append(l % len(s))
5047 t.append(l % len(s))
5045
5048
5046 t = ', '.join(t)
5049 t = ', '.join(t)
5047 cleanworkdir = False
5050 cleanworkdir = False
5048
5051
5049 if repo.vfs.exists('graftstate'):
5052 if repo.vfs.exists('graftstate'):
5050 t += _(' (graft in progress)')
5053 t += _(' (graft in progress)')
5051 if repo.vfs.exists('updatestate'):
5054 if repo.vfs.exists('updatestate'):
5052 t += _(' (interrupted update)')
5055 t += _(' (interrupted update)')
5053 elif len(parents) > 1:
5056 elif len(parents) > 1:
5054 t += _(' (merge)')
5057 t += _(' (merge)')
5055 elif branch != parents[0].branch():
5058 elif branch != parents[0].branch():
5056 t += _(' (new branch)')
5059 t += _(' (new branch)')
5057 elif (parents[0].closesbranch() and
5060 elif (parents[0].closesbranch() and
5058 pnode in repo.branchheads(branch, closed=True)):
5061 pnode in repo.branchheads(branch, closed=True)):
5059 t += _(' (head closed)')
5062 t += _(' (head closed)')
5060 elif not (status.modified or status.added or status.removed or renamed or
5063 elif not (status.modified or status.added or status.removed or renamed or
5061 copied or subs):
5064 copied or subs):
5062 t += _(' (clean)')
5065 t += _(' (clean)')
5063 cleanworkdir = True
5066 cleanworkdir = True
5064 elif pnode not in bheads:
5067 elif pnode not in bheads:
5065 t += _(' (new branch head)')
5068 t += _(' (new branch head)')
5066
5069
5067 if parents:
5070 if parents:
5068 pendingphase = max(p.phase() for p in parents)
5071 pendingphase = max(p.phase() for p in parents)
5069 else:
5072 else:
5070 pendingphase = phases.public
5073 pendingphase = phases.public
5071
5074
5072 if pendingphase > phases.newcommitphase(ui):
5075 if pendingphase > phases.newcommitphase(ui):
5073 t += ' (%s)' % phases.phasenames[pendingphase]
5076 t += ' (%s)' % phases.phasenames[pendingphase]
5074
5077
5075 if cleanworkdir:
5078 if cleanworkdir:
5076 # i18n: column positioning for "hg summary"
5079 # i18n: column positioning for "hg summary"
5077 ui.status(_('commit: %s\n') % t.strip())
5080 ui.status(_('commit: %s\n') % t.strip())
5078 else:
5081 else:
5079 # i18n: column positioning for "hg summary"
5082 # i18n: column positioning for "hg summary"
5080 ui.write(_('commit: %s\n') % t.strip())
5083 ui.write(_('commit: %s\n') % t.strip())
5081
5084
5082 # all ancestors of branch heads - all ancestors of parent = new csets
5085 # all ancestors of branch heads - all ancestors of parent = new csets
5083 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5086 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5084 bheads))
5087 bheads))
5085
5088
5086 if new == 0:
5089 if new == 0:
5087 # i18n: column positioning for "hg summary"
5090 # i18n: column positioning for "hg summary"
5088 ui.status(_('update: (current)\n'))
5091 ui.status(_('update: (current)\n'))
5089 elif pnode not in bheads:
5092 elif pnode not in bheads:
5090 # i18n: column positioning for "hg summary"
5093 # i18n: column positioning for "hg summary"
5091 ui.write(_('update: %d new changesets (update)\n') % new)
5094 ui.write(_('update: %d new changesets (update)\n') % new)
5092 else:
5095 else:
5093 # i18n: column positioning for "hg summary"
5096 # i18n: column positioning for "hg summary"
5094 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5097 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5095 (new, len(bheads)))
5098 (new, len(bheads)))
5096
5099
5097 t = []
5100 t = []
5098 draft = len(repo.revs('draft()'))
5101 draft = len(repo.revs('draft()'))
5099 if draft:
5102 if draft:
5100 t.append(_('%d draft') % draft)
5103 t.append(_('%d draft') % draft)
5101 secret = len(repo.revs('secret()'))
5104 secret = len(repo.revs('secret()'))
5102 if secret:
5105 if secret:
5103 t.append(_('%d secret') % secret)
5106 t.append(_('%d secret') % secret)
5104
5107
5105 if draft or secret:
5108 if draft or secret:
5106 ui.status(_('phases: %s\n') % ', '.join(t))
5109 ui.status(_('phases: %s\n') % ', '.join(t))
5107
5110
5108 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5111 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5109 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5112 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5110 numtrouble = len(repo.revs(trouble + "()"))
5113 numtrouble = len(repo.revs(trouble + "()"))
5111 # We write all the possibilities to ease translation
5114 # We write all the possibilities to ease translation
5112 troublemsg = {
5115 troublemsg = {
5113 "orphan": _("orphan: %d changesets"),
5116 "orphan": _("orphan: %d changesets"),
5114 "contentdivergent": _("content-divergent: %d changesets"),
5117 "contentdivergent": _("content-divergent: %d changesets"),
5115 "phasedivergent": _("phase-divergent: %d changesets"),
5118 "phasedivergent": _("phase-divergent: %d changesets"),
5116 }
5119 }
5117 if numtrouble > 0:
5120 if numtrouble > 0:
5118 ui.status(troublemsg[trouble] % numtrouble + "\n")
5121 ui.status(troublemsg[trouble] % numtrouble + "\n")
5119
5122
5120 cmdutil.summaryhooks(ui, repo)
5123 cmdutil.summaryhooks(ui, repo)
5121
5124
5122 if opts.get('remote'):
5125 if opts.get('remote'):
5123 needsincoming, needsoutgoing = True, True
5126 needsincoming, needsoutgoing = True, True
5124 else:
5127 else:
5125 needsincoming, needsoutgoing = False, False
5128 needsincoming, needsoutgoing = False, False
5126 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5129 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5127 if i:
5130 if i:
5128 needsincoming = True
5131 needsincoming = True
5129 if o:
5132 if o:
5130 needsoutgoing = True
5133 needsoutgoing = True
5131 if not needsincoming and not needsoutgoing:
5134 if not needsincoming and not needsoutgoing:
5132 return
5135 return
5133
5136
5134 def getincoming():
5137 def getincoming():
5135 source, branches = hg.parseurl(ui.expandpath('default'))
5138 source, branches = hg.parseurl(ui.expandpath('default'))
5136 sbranch = branches[0]
5139 sbranch = branches[0]
5137 try:
5140 try:
5138 other = hg.peer(repo, {}, source)
5141 other = hg.peer(repo, {}, source)
5139 except error.RepoError:
5142 except error.RepoError:
5140 if opts.get('remote'):
5143 if opts.get('remote'):
5141 raise
5144 raise
5142 return source, sbranch, None, None, None
5145 return source, sbranch, None, None, None
5143 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5146 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5144 if revs:
5147 if revs:
5145 revs = [other.lookup(rev) for rev in revs]
5148 revs = [other.lookup(rev) for rev in revs]
5146 ui.debug('comparing with %s\n' % util.hidepassword(source))
5149 ui.debug('comparing with %s\n' % util.hidepassword(source))
5147 repo.ui.pushbuffer()
5150 repo.ui.pushbuffer()
5148 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5151 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5149 repo.ui.popbuffer()
5152 repo.ui.popbuffer()
5150 return source, sbranch, other, commoninc, commoninc[1]
5153 return source, sbranch, other, commoninc, commoninc[1]
5151
5154
5152 if needsincoming:
5155 if needsincoming:
5153 source, sbranch, sother, commoninc, incoming = getincoming()
5156 source, sbranch, sother, commoninc, incoming = getincoming()
5154 else:
5157 else:
5155 source = sbranch = sother = commoninc = incoming = None
5158 source = sbranch = sother = commoninc = incoming = None
5156
5159
5157 def getoutgoing():
5160 def getoutgoing():
5158 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5161 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5159 dbranch = branches[0]
5162 dbranch = branches[0]
5160 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5163 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5161 if source != dest:
5164 if source != dest:
5162 try:
5165 try:
5163 dother = hg.peer(repo, {}, dest)
5166 dother = hg.peer(repo, {}, dest)
5164 except error.RepoError:
5167 except error.RepoError:
5165 if opts.get('remote'):
5168 if opts.get('remote'):
5166 raise
5169 raise
5167 return dest, dbranch, None, None
5170 return dest, dbranch, None, None
5168 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5171 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5169 elif sother is None:
5172 elif sother is None:
5170 # there is no explicit destination peer, but source one is invalid
5173 # there is no explicit destination peer, but source one is invalid
5171 return dest, dbranch, None, None
5174 return dest, dbranch, None, None
5172 else:
5175 else:
5173 dother = sother
5176 dother = sother
5174 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5177 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5175 common = None
5178 common = None
5176 else:
5179 else:
5177 common = commoninc
5180 common = commoninc
5178 if revs:
5181 if revs:
5179 revs = [repo.lookup(rev) for rev in revs]
5182 revs = [repo.lookup(rev) for rev in revs]
5180 repo.ui.pushbuffer()
5183 repo.ui.pushbuffer()
5181 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5184 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5182 commoninc=common)
5185 commoninc=common)
5183 repo.ui.popbuffer()
5186 repo.ui.popbuffer()
5184 return dest, dbranch, dother, outgoing
5187 return dest, dbranch, dother, outgoing
5185
5188
5186 if needsoutgoing:
5189 if needsoutgoing:
5187 dest, dbranch, dother, outgoing = getoutgoing()
5190 dest, dbranch, dother, outgoing = getoutgoing()
5188 else:
5191 else:
5189 dest = dbranch = dother = outgoing = None
5192 dest = dbranch = dother = outgoing = None
5190
5193
5191 if opts.get('remote'):
5194 if opts.get('remote'):
5192 t = []
5195 t = []
5193 if incoming:
5196 if incoming:
5194 t.append(_('1 or more incoming'))
5197 t.append(_('1 or more incoming'))
5195 o = outgoing.missing
5198 o = outgoing.missing
5196 if o:
5199 if o:
5197 t.append(_('%d outgoing') % len(o))
5200 t.append(_('%d outgoing') % len(o))
5198 other = dother or sother
5201 other = dother or sother
5199 if 'bookmarks' in other.listkeys('namespaces'):
5202 if 'bookmarks' in other.listkeys('namespaces'):
5200 counts = bookmarks.summary(repo, other)
5203 counts = bookmarks.summary(repo, other)
5201 if counts[0] > 0:
5204 if counts[0] > 0:
5202 t.append(_('%d incoming bookmarks') % counts[0])
5205 t.append(_('%d incoming bookmarks') % counts[0])
5203 if counts[1] > 0:
5206 if counts[1] > 0:
5204 t.append(_('%d outgoing bookmarks') % counts[1])
5207 t.append(_('%d outgoing bookmarks') % counts[1])
5205
5208
5206 if t:
5209 if t:
5207 # i18n: column positioning for "hg summary"
5210 # i18n: column positioning for "hg summary"
5208 ui.write(_('remote: %s\n') % (', '.join(t)))
5211 ui.write(_('remote: %s\n') % (', '.join(t)))
5209 else:
5212 else:
5210 # i18n: column positioning for "hg summary"
5213 # i18n: column positioning for "hg summary"
5211 ui.status(_('remote: (synced)\n'))
5214 ui.status(_('remote: (synced)\n'))
5212
5215
5213 cmdutil.summaryremotehooks(ui, repo, opts,
5216 cmdutil.summaryremotehooks(ui, repo, opts,
5214 ((source, sbranch, sother, commoninc),
5217 ((source, sbranch, sother, commoninc),
5215 (dest, dbranch, dother, outgoing)))
5218 (dest, dbranch, dother, outgoing)))
5216
5219
5217 @command('tag',
5220 @command('tag',
5218 [('f', 'force', None, _('force tag')),
5221 [('f', 'force', None, _('force tag')),
5219 ('l', 'local', None, _('make the tag local')),
5222 ('l', 'local', None, _('make the tag local')),
5220 ('r', 'rev', '', _('revision to tag'), _('REV')),
5223 ('r', 'rev', '', _('revision to tag'), _('REV')),
5221 ('', 'remove', None, _('remove a tag')),
5224 ('', 'remove', None, _('remove a tag')),
5222 # -l/--local is already there, commitopts cannot be used
5225 # -l/--local is already there, commitopts cannot be used
5223 ('e', 'edit', None, _('invoke editor on commit messages')),
5226 ('e', 'edit', None, _('invoke editor on commit messages')),
5224 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5227 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5225 ] + commitopts2,
5228 ] + commitopts2,
5226 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5229 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5227 def tag(ui, repo, name1, *names, **opts):
5230 def tag(ui, repo, name1, *names, **opts):
5228 """add one or more tags for the current or given revision
5231 """add one or more tags for the current or given revision
5229
5232
5230 Name a particular revision using <name>.
5233 Name a particular revision using <name>.
5231
5234
5232 Tags are used to name particular revisions of the repository and are
5235 Tags are used to name particular revisions of the repository and are
5233 very useful to compare different revisions, to go back to significant
5236 very useful to compare different revisions, to go back to significant
5234 earlier versions or to mark branch points as releases, etc. Changing
5237 earlier versions or to mark branch points as releases, etc. Changing
5235 an existing tag is normally disallowed; use -f/--force to override.
5238 an existing tag is normally disallowed; use -f/--force to override.
5236
5239
5237 If no revision is given, the parent of the working directory is
5240 If no revision is given, the parent of the working directory is
5238 used.
5241 used.
5239
5242
5240 To facilitate version control, distribution, and merging of tags,
5243 To facilitate version control, distribution, and merging of tags,
5241 they are stored as a file named ".hgtags" which is managed similarly
5244 they are stored as a file named ".hgtags" which is managed similarly
5242 to other project files and can be hand-edited if necessary. This
5245 to other project files and can be hand-edited if necessary. This
5243 also means that tagging creates a new commit. The file
5246 also means that tagging creates a new commit. The file
5244 ".hg/localtags" is used for local tags (not shared among
5247 ".hg/localtags" is used for local tags (not shared among
5245 repositories).
5248 repositories).
5246
5249
5247 Tag commits are usually made at the head of a branch. If the parent
5250 Tag commits are usually made at the head of a branch. If the parent
5248 of the working directory is not a branch head, :hg:`tag` aborts; use
5251 of the working directory is not a branch head, :hg:`tag` aborts; use
5249 -f/--force to force the tag commit to be based on a non-head
5252 -f/--force to force the tag commit to be based on a non-head
5250 changeset.
5253 changeset.
5251
5254
5252 See :hg:`help dates` for a list of formats valid for -d/--date.
5255 See :hg:`help dates` for a list of formats valid for -d/--date.
5253
5256
5254 Since tag names have priority over branch names during revision
5257 Since tag names have priority over branch names during revision
5255 lookup, using an existing branch name as a tag name is discouraged.
5258 lookup, using an existing branch name as a tag name is discouraged.
5256
5259
5257 Returns 0 on success.
5260 Returns 0 on success.
5258 """
5261 """
5259 opts = pycompat.byteskwargs(opts)
5262 opts = pycompat.byteskwargs(opts)
5260 wlock = lock = None
5263 wlock = lock = None
5261 try:
5264 try:
5262 wlock = repo.wlock()
5265 wlock = repo.wlock()
5263 lock = repo.lock()
5266 lock = repo.lock()
5264 rev_ = "."
5267 rev_ = "."
5265 names = [t.strip() for t in (name1,) + names]
5268 names = [t.strip() for t in (name1,) + names]
5266 if len(names) != len(set(names)):
5269 if len(names) != len(set(names)):
5267 raise error.Abort(_('tag names must be unique'))
5270 raise error.Abort(_('tag names must be unique'))
5268 for n in names:
5271 for n in names:
5269 scmutil.checknewlabel(repo, n, 'tag')
5272 scmutil.checknewlabel(repo, n, 'tag')
5270 if not n:
5273 if not n:
5271 raise error.Abort(_('tag names cannot consist entirely of '
5274 raise error.Abort(_('tag names cannot consist entirely of '
5272 'whitespace'))
5275 'whitespace'))
5273 if opts.get('rev') and opts.get('remove'):
5276 if opts.get('rev') and opts.get('remove'):
5274 raise error.Abort(_("--rev and --remove are incompatible"))
5277 raise error.Abort(_("--rev and --remove are incompatible"))
5275 if opts.get('rev'):
5278 if opts.get('rev'):
5276 rev_ = opts['rev']
5279 rev_ = opts['rev']
5277 message = opts.get('message')
5280 message = opts.get('message')
5278 if opts.get('remove'):
5281 if opts.get('remove'):
5279 if opts.get('local'):
5282 if opts.get('local'):
5280 expectedtype = 'local'
5283 expectedtype = 'local'
5281 else:
5284 else:
5282 expectedtype = 'global'
5285 expectedtype = 'global'
5283
5286
5284 for n in names:
5287 for n in names:
5285 if not repo.tagtype(n):
5288 if not repo.tagtype(n):
5286 raise error.Abort(_("tag '%s' does not exist") % n)
5289 raise error.Abort(_("tag '%s' does not exist") % n)
5287 if repo.tagtype(n) != expectedtype:
5290 if repo.tagtype(n) != expectedtype:
5288 if expectedtype == 'global':
5291 if expectedtype == 'global':
5289 raise error.Abort(_("tag '%s' is not a global tag") % n)
5292 raise error.Abort(_("tag '%s' is not a global tag") % n)
5290 else:
5293 else:
5291 raise error.Abort(_("tag '%s' is not a local tag") % n)
5294 raise error.Abort(_("tag '%s' is not a local tag") % n)
5292 rev_ = 'null'
5295 rev_ = 'null'
5293 if not message:
5296 if not message:
5294 # we don't translate commit messages
5297 # we don't translate commit messages
5295 message = 'Removed tag %s' % ', '.join(names)
5298 message = 'Removed tag %s' % ', '.join(names)
5296 elif not opts.get('force'):
5299 elif not opts.get('force'):
5297 for n in names:
5300 for n in names:
5298 if n in repo.tags():
5301 if n in repo.tags():
5299 raise error.Abort(_("tag '%s' already exists "
5302 raise error.Abort(_("tag '%s' already exists "
5300 "(use -f to force)") % n)
5303 "(use -f to force)") % n)
5301 if not opts.get('local'):
5304 if not opts.get('local'):
5302 p1, p2 = repo.dirstate.parents()
5305 p1, p2 = repo.dirstate.parents()
5303 if p2 != nullid:
5306 if p2 != nullid:
5304 raise error.Abort(_('uncommitted merge'))
5307 raise error.Abort(_('uncommitted merge'))
5305 bheads = repo.branchheads()
5308 bheads = repo.branchheads()
5306 if not opts.get('force') and bheads and p1 not in bheads:
5309 if not opts.get('force') and bheads and p1 not in bheads:
5307 raise error.Abort(_('working directory is not at a branch head '
5310 raise error.Abort(_('working directory is not at a branch head '
5308 '(use -f to force)'))
5311 '(use -f to force)'))
5309 r = scmutil.revsingle(repo, rev_).node()
5312 r = scmutil.revsingle(repo, rev_).node()
5310
5313
5311 if not message:
5314 if not message:
5312 # we don't translate commit messages
5315 # we don't translate commit messages
5313 message = ('Added tag %s for changeset %s' %
5316 message = ('Added tag %s for changeset %s' %
5314 (', '.join(names), short(r)))
5317 (', '.join(names), short(r)))
5315
5318
5316 date = opts.get('date')
5319 date = opts.get('date')
5317 if date:
5320 if date:
5318 date = util.parsedate(date)
5321 date = util.parsedate(date)
5319
5322
5320 if opts.get('remove'):
5323 if opts.get('remove'):
5321 editform = 'tag.remove'
5324 editform = 'tag.remove'
5322 else:
5325 else:
5323 editform = 'tag.add'
5326 editform = 'tag.add'
5324 editor = cmdutil.getcommiteditor(editform=editform,
5327 editor = cmdutil.getcommiteditor(editform=editform,
5325 **pycompat.strkwargs(opts))
5328 **pycompat.strkwargs(opts))
5326
5329
5327 # don't allow tagging the null rev
5330 # don't allow tagging the null rev
5328 if (not opts.get('remove') and
5331 if (not opts.get('remove') and
5329 scmutil.revsingle(repo, rev_).rev() == nullrev):
5332 scmutil.revsingle(repo, rev_).rev() == nullrev):
5330 raise error.Abort(_("cannot tag null revision"))
5333 raise error.Abort(_("cannot tag null revision"))
5331
5334
5332 tagsmod.tag(repo, names, r, message, opts.get('local'),
5335 tagsmod.tag(repo, names, r, message, opts.get('local'),
5333 opts.get('user'), date, editor=editor)
5336 opts.get('user'), date, editor=editor)
5334 finally:
5337 finally:
5335 release(lock, wlock)
5338 release(lock, wlock)
5336
5339
5337 @command('tags', formatteropts, '', cmdtype=readonly)
5340 @command('tags', formatteropts, '', cmdtype=readonly)
5338 def tags(ui, repo, **opts):
5341 def tags(ui, repo, **opts):
5339 """list repository tags
5342 """list repository tags
5340
5343
5341 This lists both regular and local tags. When the -v/--verbose
5344 This lists both regular and local tags. When the -v/--verbose
5342 switch is used, a third column "local" is printed for local tags.
5345 switch is used, a third column "local" is printed for local tags.
5343 When the -q/--quiet switch is used, only the tag name is printed.
5346 When the -q/--quiet switch is used, only the tag name is printed.
5344
5347
5345 Returns 0 on success.
5348 Returns 0 on success.
5346 """
5349 """
5347
5350
5348 opts = pycompat.byteskwargs(opts)
5351 opts = pycompat.byteskwargs(opts)
5349 ui.pager('tags')
5352 ui.pager('tags')
5350 fm = ui.formatter('tags', opts)
5353 fm = ui.formatter('tags', opts)
5351 hexfunc = fm.hexfunc
5354 hexfunc = fm.hexfunc
5352 tagtype = ""
5355 tagtype = ""
5353
5356
5354 for t, n in reversed(repo.tagslist()):
5357 for t, n in reversed(repo.tagslist()):
5355 hn = hexfunc(n)
5358 hn = hexfunc(n)
5356 label = 'tags.normal'
5359 label = 'tags.normal'
5357 tagtype = ''
5360 tagtype = ''
5358 if repo.tagtype(t) == 'local':
5361 if repo.tagtype(t) == 'local':
5359 label = 'tags.local'
5362 label = 'tags.local'
5360 tagtype = 'local'
5363 tagtype = 'local'
5361
5364
5362 fm.startitem()
5365 fm.startitem()
5363 fm.write('tag', '%s', t, label=label)
5366 fm.write('tag', '%s', t, label=label)
5364 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5367 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5365 fm.condwrite(not ui.quiet, 'rev node', fmt,
5368 fm.condwrite(not ui.quiet, 'rev node', fmt,
5366 repo.changelog.rev(n), hn, label=label)
5369 repo.changelog.rev(n), hn, label=label)
5367 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5370 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5368 tagtype, label=label)
5371 tagtype, label=label)
5369 fm.plain('\n')
5372 fm.plain('\n')
5370 fm.end()
5373 fm.end()
5371
5374
5372 @command('tip',
5375 @command('tip',
5373 [('p', 'patch', None, _('show patch')),
5376 [('p', 'patch', None, _('show patch')),
5374 ('g', 'git', None, _('use git extended diff format')),
5377 ('g', 'git', None, _('use git extended diff format')),
5375 ] + templateopts,
5378 ] + templateopts,
5376 _('[-p] [-g]'))
5379 _('[-p] [-g]'))
5377 def tip(ui, repo, **opts):
5380 def tip(ui, repo, **opts):
5378 """show the tip revision (DEPRECATED)
5381 """show the tip revision (DEPRECATED)
5379
5382
5380 The tip revision (usually just called the tip) is the changeset
5383 The tip revision (usually just called the tip) is the changeset
5381 most recently added to the repository (and therefore the most
5384 most recently added to the repository (and therefore the most
5382 recently changed head).
5385 recently changed head).
5383
5386
5384 If you have just made a commit, that commit will be the tip. If
5387 If you have just made a commit, that commit will be the tip. If
5385 you have just pulled changes from another repository, the tip of
5388 you have just pulled changes from another repository, the tip of
5386 that repository becomes the current tip. The "tip" tag is special
5389 that repository becomes the current tip. The "tip" tag is special
5387 and cannot be renamed or assigned to a different changeset.
5390 and cannot be renamed or assigned to a different changeset.
5388
5391
5389 This command is deprecated, please use :hg:`heads` instead.
5392 This command is deprecated, please use :hg:`heads` instead.
5390
5393
5391 Returns 0 on success.
5394 Returns 0 on success.
5392 """
5395 """
5393 opts = pycompat.byteskwargs(opts)
5396 opts = pycompat.byteskwargs(opts)
5394 displayer = cmdutil.show_changeset(ui, repo, opts)
5397 displayer = cmdutil.show_changeset(ui, repo, opts)
5395 displayer.show(repo['tip'])
5398 displayer.show(repo['tip'])
5396 displayer.close()
5399 displayer.close()
5397
5400
5398 @command('unbundle',
5401 @command('unbundle',
5399 [('u', 'update', None,
5402 [('u', 'update', None,
5400 _('update to new branch head if changesets were unbundled'))],
5403 _('update to new branch head if changesets were unbundled'))],
5401 _('[-u] FILE...'))
5404 _('[-u] FILE...'))
5402 def unbundle(ui, repo, fname1, *fnames, **opts):
5405 def unbundle(ui, repo, fname1, *fnames, **opts):
5403 """apply one or more bundle files
5406 """apply one or more bundle files
5404
5407
5405 Apply one or more bundle files generated by :hg:`bundle`.
5408 Apply one or more bundle files generated by :hg:`bundle`.
5406
5409
5407 Returns 0 on success, 1 if an update has unresolved files.
5410 Returns 0 on success, 1 if an update has unresolved files.
5408 """
5411 """
5409 fnames = (fname1,) + fnames
5412 fnames = (fname1,) + fnames
5410
5413
5411 with repo.lock():
5414 with repo.lock():
5412 for fname in fnames:
5415 for fname in fnames:
5413 f = hg.openpath(ui, fname)
5416 f = hg.openpath(ui, fname)
5414 gen = exchange.readbundle(ui, f, fname)
5417 gen = exchange.readbundle(ui, f, fname)
5415 if isinstance(gen, streamclone.streamcloneapplier):
5418 if isinstance(gen, streamclone.streamcloneapplier):
5416 raise error.Abort(
5419 raise error.Abort(
5417 _('packed bundles cannot be applied with '
5420 _('packed bundles cannot be applied with '
5418 '"hg unbundle"'),
5421 '"hg unbundle"'),
5419 hint=_('use "hg debugapplystreamclonebundle"'))
5422 hint=_('use "hg debugapplystreamclonebundle"'))
5420 url = 'bundle:' + fname
5423 url = 'bundle:' + fname
5421 try:
5424 try:
5422 txnname = 'unbundle'
5425 txnname = 'unbundle'
5423 if not isinstance(gen, bundle2.unbundle20):
5426 if not isinstance(gen, bundle2.unbundle20):
5424 txnname = 'unbundle\n%s' % util.hidepassword(url)
5427 txnname = 'unbundle\n%s' % util.hidepassword(url)
5425 with repo.transaction(txnname) as tr:
5428 with repo.transaction(txnname) as tr:
5426 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5429 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5427 url=url)
5430 url=url)
5428 except error.BundleUnknownFeatureError as exc:
5431 except error.BundleUnknownFeatureError as exc:
5429 raise error.Abort(
5432 raise error.Abort(
5430 _('%s: unknown bundle feature, %s') % (fname, exc),
5433 _('%s: unknown bundle feature, %s') % (fname, exc),
5431 hint=_("see https://mercurial-scm.org/"
5434 hint=_("see https://mercurial-scm.org/"
5432 "wiki/BundleFeature for more "
5435 "wiki/BundleFeature for more "
5433 "information"))
5436 "information"))
5434 modheads = bundle2.combinechangegroupresults(op)
5437 modheads = bundle2.combinechangegroupresults(op)
5435
5438
5436 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5439 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5437
5440
5438 @command('^update|up|checkout|co',
5441 @command('^update|up|checkout|co',
5439 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5442 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5440 ('c', 'check', None, _('require clean working directory')),
5443 ('c', 'check', None, _('require clean working directory')),
5441 ('m', 'merge', None, _('merge uncommitted changes')),
5444 ('m', 'merge', None, _('merge uncommitted changes')),
5442 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5445 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5443 ('r', 'rev', '', _('revision'), _('REV'))
5446 ('r', 'rev', '', _('revision'), _('REV'))
5444 ] + mergetoolopts,
5447 ] + mergetoolopts,
5445 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5448 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5446 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5449 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5447 merge=None, tool=None):
5450 merge=None, tool=None):
5448 """update working directory (or switch revisions)
5451 """update working directory (or switch revisions)
5449
5452
5450 Update the repository's working directory to the specified
5453 Update the repository's working directory to the specified
5451 changeset. If no changeset is specified, update to the tip of the
5454 changeset. If no changeset is specified, update to the tip of the
5452 current named branch and move the active bookmark (see :hg:`help
5455 current named branch and move the active bookmark (see :hg:`help
5453 bookmarks`).
5456 bookmarks`).
5454
5457
5455 Update sets the working directory's parent revision to the specified
5458 Update sets the working directory's parent revision to the specified
5456 changeset (see :hg:`help parents`).
5459 changeset (see :hg:`help parents`).
5457
5460
5458 If the changeset is not a descendant or ancestor of the working
5461 If the changeset is not a descendant or ancestor of the working
5459 directory's parent and there are uncommitted changes, the update is
5462 directory's parent and there are uncommitted changes, the update is
5460 aborted. With the -c/--check option, the working directory is checked
5463 aborted. With the -c/--check option, the working directory is checked
5461 for uncommitted changes; if none are found, the working directory is
5464 for uncommitted changes; if none are found, the working directory is
5462 updated to the specified changeset.
5465 updated to the specified changeset.
5463
5466
5464 .. container:: verbose
5467 .. container:: verbose
5465
5468
5466 The -C/--clean, -c/--check, and -m/--merge options control what
5469 The -C/--clean, -c/--check, and -m/--merge options control what
5467 happens if the working directory contains uncommitted changes.
5470 happens if the working directory contains uncommitted changes.
5468 At most of one of them can be specified.
5471 At most of one of them can be specified.
5469
5472
5470 1. If no option is specified, and if
5473 1. If no option is specified, and if
5471 the requested changeset is an ancestor or descendant of
5474 the requested changeset is an ancestor or descendant of
5472 the working directory's parent, the uncommitted changes
5475 the working directory's parent, the uncommitted changes
5473 are merged into the requested changeset and the merged
5476 are merged into the requested changeset and the merged
5474 result is left uncommitted. If the requested changeset is
5477 result is left uncommitted. If the requested changeset is
5475 not an ancestor or descendant (that is, it is on another
5478 not an ancestor or descendant (that is, it is on another
5476 branch), the update is aborted and the uncommitted changes
5479 branch), the update is aborted and the uncommitted changes
5477 are preserved.
5480 are preserved.
5478
5481
5479 2. With the -m/--merge option, the update is allowed even if the
5482 2. With the -m/--merge option, the update is allowed even if the
5480 requested changeset is not an ancestor or descendant of
5483 requested changeset is not an ancestor or descendant of
5481 the working directory's parent.
5484 the working directory's parent.
5482
5485
5483 3. With the -c/--check option, the update is aborted and the
5486 3. With the -c/--check option, the update is aborted and the
5484 uncommitted changes are preserved.
5487 uncommitted changes are preserved.
5485
5488
5486 4. With the -C/--clean option, uncommitted changes are discarded and
5489 4. With the -C/--clean option, uncommitted changes are discarded and
5487 the working directory is updated to the requested changeset.
5490 the working directory is updated to the requested changeset.
5488
5491
5489 To cancel an uncommitted merge (and lose your changes), use
5492 To cancel an uncommitted merge (and lose your changes), use
5490 :hg:`update --clean .`.
5493 :hg:`update --clean .`.
5491
5494
5492 Use null as the changeset to remove the working directory (like
5495 Use null as the changeset to remove the working directory (like
5493 :hg:`clone -U`).
5496 :hg:`clone -U`).
5494
5497
5495 If you want to revert just one file to an older revision, use
5498 If you want to revert just one file to an older revision, use
5496 :hg:`revert [-r REV] NAME`.
5499 :hg:`revert [-r REV] NAME`.
5497
5500
5498 See :hg:`help dates` for a list of formats valid for -d/--date.
5501 See :hg:`help dates` for a list of formats valid for -d/--date.
5499
5502
5500 Returns 0 on success, 1 if there are unresolved files.
5503 Returns 0 on success, 1 if there are unresolved files.
5501 """
5504 """
5502 if rev and node:
5505 if rev and node:
5503 raise error.Abort(_("please specify just one revision"))
5506 raise error.Abort(_("please specify just one revision"))
5504
5507
5505 if ui.configbool('commands', 'update.requiredest'):
5508 if ui.configbool('commands', 'update.requiredest'):
5506 if not node and not rev and not date:
5509 if not node and not rev and not date:
5507 raise error.Abort(_('you must specify a destination'),
5510 raise error.Abort(_('you must specify a destination'),
5508 hint=_('for example: hg update ".::"'))
5511 hint=_('for example: hg update ".::"'))
5509
5512
5510 if rev is None or rev == '':
5513 if rev is None or rev == '':
5511 rev = node
5514 rev = node
5512
5515
5513 if date and rev is not None:
5516 if date and rev is not None:
5514 raise error.Abort(_("you can't specify a revision and a date"))
5517 raise error.Abort(_("you can't specify a revision and a date"))
5515
5518
5516 if len([x for x in (clean, check, merge) if x]) > 1:
5519 if len([x for x in (clean, check, merge) if x]) > 1:
5517 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5520 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5518 "or -m/--merge"))
5521 "or -m/--merge"))
5519
5522
5520 updatecheck = None
5523 updatecheck = None
5521 if check:
5524 if check:
5522 updatecheck = 'abort'
5525 updatecheck = 'abort'
5523 elif merge:
5526 elif merge:
5524 updatecheck = 'none'
5527 updatecheck = 'none'
5525
5528
5526 with repo.wlock():
5529 with repo.wlock():
5527 cmdutil.clearunfinished(repo)
5530 cmdutil.clearunfinished(repo)
5528
5531
5529 if date:
5532 if date:
5530 rev = cmdutil.finddate(ui, repo, date)
5533 rev = cmdutil.finddate(ui, repo, date)
5531
5534
5532 # if we defined a bookmark, we have to remember the original name
5535 # if we defined a bookmark, we have to remember the original name
5533 brev = rev
5536 brev = rev
5534 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5537 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5535 ctx = scmutil.revsingle(repo, rev, rev)
5538 ctx = scmutil.revsingle(repo, rev, rev)
5536 rev = ctx.rev()
5539 rev = ctx.rev()
5537 if ctx.hidden():
5540 if ctx.hidden():
5538 ui.warn(_("updating to a hidden changeset %s\n") % ctx.hex()[:12])
5541 ui.warn(_("updating to a hidden changeset %s\n") % ctx.hex()[:12])
5539
5542
5540 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5543 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5541
5544
5542 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5545 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5543 updatecheck=updatecheck)
5546 updatecheck=updatecheck)
5544
5547
5545 @command('verify', [])
5548 @command('verify', [])
5546 def verify(ui, repo):
5549 def verify(ui, repo):
5547 """verify the integrity of the repository
5550 """verify the integrity of the repository
5548
5551
5549 Verify the integrity of the current repository.
5552 Verify the integrity of the current repository.
5550
5553
5551 This will perform an extensive check of the repository's
5554 This will perform an extensive check of the repository's
5552 integrity, validating the hashes and checksums of each entry in
5555 integrity, validating the hashes and checksums of each entry in
5553 the changelog, manifest, and tracked files, as well as the
5556 the changelog, manifest, and tracked files, as well as the
5554 integrity of their crosslinks and indices.
5557 integrity of their crosslinks and indices.
5555
5558
5556 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5559 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5557 for more information about recovery from corruption of the
5560 for more information about recovery from corruption of the
5558 repository.
5561 repository.
5559
5562
5560 Returns 0 on success, 1 if errors are encountered.
5563 Returns 0 on success, 1 if errors are encountered.
5561 """
5564 """
5562 return hg.verify(repo)
5565 return hg.verify(repo)
5563
5566
5564 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5567 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5565 def version_(ui, **opts):
5568 def version_(ui, **opts):
5566 """output version and copyright information"""
5569 """output version and copyright information"""
5567 opts = pycompat.byteskwargs(opts)
5570 opts = pycompat.byteskwargs(opts)
5568 if ui.verbose:
5571 if ui.verbose:
5569 ui.pager('version')
5572 ui.pager('version')
5570 fm = ui.formatter("version", opts)
5573 fm = ui.formatter("version", opts)
5571 fm.startitem()
5574 fm.startitem()
5572 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5575 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5573 util.version())
5576 util.version())
5574 license = _(
5577 license = _(
5575 "(see https://mercurial-scm.org for more information)\n"
5578 "(see https://mercurial-scm.org for more information)\n"
5576 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5579 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5577 "This is free software; see the source for copying conditions. "
5580 "This is free software; see the source for copying conditions. "
5578 "There is NO\nwarranty; "
5581 "There is NO\nwarranty; "
5579 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5582 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5580 )
5583 )
5581 if not ui.quiet:
5584 if not ui.quiet:
5582 fm.plain(license)
5585 fm.plain(license)
5583
5586
5584 if ui.verbose:
5587 if ui.verbose:
5585 fm.plain(_("\nEnabled extensions:\n\n"))
5588 fm.plain(_("\nEnabled extensions:\n\n"))
5586 # format names and versions into columns
5589 # format names and versions into columns
5587 names = []
5590 names = []
5588 vers = []
5591 vers = []
5589 isinternals = []
5592 isinternals = []
5590 for name, module in extensions.extensions():
5593 for name, module in extensions.extensions():
5591 names.append(name)
5594 names.append(name)
5592 vers.append(extensions.moduleversion(module) or None)
5595 vers.append(extensions.moduleversion(module) or None)
5593 isinternals.append(extensions.ismoduleinternal(module))
5596 isinternals.append(extensions.ismoduleinternal(module))
5594 fn = fm.nested("extensions")
5597 fn = fm.nested("extensions")
5595 if names:
5598 if names:
5596 namefmt = " %%-%ds " % max(len(n) for n in names)
5599 namefmt = " %%-%ds " % max(len(n) for n in names)
5597 places = [_("external"), _("internal")]
5600 places = [_("external"), _("internal")]
5598 for n, v, p in zip(names, vers, isinternals):
5601 for n, v, p in zip(names, vers, isinternals):
5599 fn.startitem()
5602 fn.startitem()
5600 fn.condwrite(ui.verbose, "name", namefmt, n)
5603 fn.condwrite(ui.verbose, "name", namefmt, n)
5601 if ui.verbose:
5604 if ui.verbose:
5602 fn.plain("%s " % places[p])
5605 fn.plain("%s " % places[p])
5603 fn.data(bundled=p)
5606 fn.data(bundled=p)
5604 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5607 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5605 if ui.verbose:
5608 if ui.verbose:
5606 fn.plain("\n")
5609 fn.plain("\n")
5607 fn.end()
5610 fn.end()
5608 fm.end()
5611 fm.end()
5609
5612
5610 def loadcmdtable(ui, name, cmdtable):
5613 def loadcmdtable(ui, name, cmdtable):
5611 """Load command functions from specified cmdtable
5614 """Load command functions from specified cmdtable
5612 """
5615 """
5613 overrides = [cmd for cmd in cmdtable if cmd in table]
5616 overrides = [cmd for cmd in cmdtable if cmd in table]
5614 if overrides:
5617 if overrides:
5615 ui.warn(_("extension '%s' overrides commands: %s\n")
5618 ui.warn(_("extension '%s' overrides commands: %s\n")
5616 % (name, " ".join(overrides)))
5619 % (name, " ".join(overrides)))
5617 table.update(cmdtable)
5620 table.update(cmdtable)
@@ -1,178 +1,183 b''
1 Tests for access level on hidden commits by various commands on based of their
1 Tests for access level on hidden commits by various commands on based of their
2 type.
2 type.
3
3
4 Setting the required config to start this
4 Setting the required config to start this
5
5
6 $ cat >> $HGRCPATH <<EOF
6 $ cat >> $HGRCPATH <<EOF
7 > [experimental]
7 > [experimental]
8 > evolution=createmarkers, allowunstable
8 > evolution=createmarkers, allowunstable
9 > directaccess=True
9 > directaccess=True
10 > directaccess.revnums=True
10 > directaccess.revnums=True
11 > [extensions]
11 > [extensions]
12 > amend =
12 > amend =
13 > EOF
13 > EOF
14
14
15 $ hg init repo
15 $ hg init repo
16 $ cd repo
16 $ cd repo
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
17 $ for ch in a b c; do touch $ch; echo "foo" >> $ch; hg ci -Aqm "Added "$ch; done
18
18
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
19 $ hg log -G -T '{rev}:{node} {desc}' --hidden
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
20 @ 2:28ad74487de9599d00d81085be739c61fc340652 Added c
21 |
21 |
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
22 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
23 |
23 |
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
24 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
25
25
26 $ echo "bar" >> c
26 $ echo "bar" >> c
27 $ hg amend
27 $ hg amend
28
28
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
29 $ hg log -G -T '{rev}:{node} {desc}' --hidden
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
30 @ 3:2443a0e664694756d8b435d06b6ad84f941b6fc0 Added c
31 |
31 |
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
32 | x 2:28ad74487de9599d00d81085be739c61fc340652 Added c
33 |/
33 |/
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
34 o 1:29becc82797a4bc11ec8880b58eaecd2ab3e7760 Added b
35 |
35 |
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
36 o 0:18d04c59bb5d2d4090ad9a5b59bd6274adb63add Added a
37
37
38 Testing read only commands on the hidden revision
38 Testing read only commands on the hidden revision
39
39
40 Testing with rev number
40 Testing with rev number
41
41
42 $ hg exp 2 --config experimental.directaccess.revnums=False
42 $ hg exp 2 --config experimental.directaccess.revnums=False
43 abort: hidden revision '2'!
43 abort: hidden revision '2'!
44 (use --hidden to access hidden revisions)
44 (use --hidden to access hidden revisions)
45 [255]
45 [255]
46
46
47 $ hg exp 2
47 $ hg exp 2
48 # HG changeset patch
48 # HG changeset patch
49 # User test
49 # User test
50 # Date 0 0
50 # Date 0 0
51 # Thu Jan 01 00:00:00 1970 +0000
51 # Thu Jan 01 00:00:00 1970 +0000
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
52 # Node ID 28ad74487de9599d00d81085be739c61fc340652
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
53 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
54 Added c
54 Added c
55
55
56 diff -r 29becc82797a -r 28ad74487de9 c
56 diff -r 29becc82797a -r 28ad74487de9 c
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
58 +++ b/c Thu Jan 01 00:00:00 1970 +0000
59 @@ -0,0 +1,1 @@
59 @@ -0,0 +1,1 @@
60 +foo
60 +foo
61
61
62 $ hg log -r 2
62 $ hg log -r 2
63 changeset: 2:28ad74487de9
63 changeset: 2:28ad74487de9
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:00 1970 +0000
65 date: Thu Jan 01 00:00:00 1970 +0000
66 obsolete: rewritten using amend as 3:2443a0e66469
66 obsolete: rewritten using amend as 3:2443a0e66469
67 summary: Added c
67 summary: Added c
68
68
69 $ hg identify -r 2
69 $ hg identify -r 2
70 28ad74487de9
70 28ad74487de9
71
71
72 $ hg status --change 2
72 $ hg status --change 2
73 A c
73 A c
74
74
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
75 $ hg status --change 2 --config experimental.directaccess.revnums=False
76 abort: hidden revision '2'!
76 abort: hidden revision '2'!
77 (use --hidden to access hidden revisions)
77 (use --hidden to access hidden revisions)
78 [255]
78 [255]
79
79
80 $ hg diff -c 2
80 $ hg diff -c 2
81 diff -r 29becc82797a -r 28ad74487de9 c
81 diff -r 29becc82797a -r 28ad74487de9 c
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
83 +++ b/c Thu Jan 01 00:00:00 1970 +0000
84 @@ -0,0 +1,1 @@
84 @@ -0,0 +1,1 @@
85 +foo
85 +foo
86
86
87 Testing with hash
87 Testing with hash
88
88
89 `hg export`
89 `hg export`
90
90
91 $ hg exp 28ad74
91 $ hg exp 28ad74
92 # HG changeset patch
92 # HG changeset patch
93 # User test
93 # User test
94 # Date 0 0
94 # Date 0 0
95 # Thu Jan 01 00:00:00 1970 +0000
95 # Thu Jan 01 00:00:00 1970 +0000
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
96 # Node ID 28ad74487de9599d00d81085be739c61fc340652
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
97 # Parent 29becc82797a4bc11ec8880b58eaecd2ab3e7760
98 Added c
98 Added c
99
99
100 diff -r 29becc82797a -r 28ad74487de9 c
100 diff -r 29becc82797a -r 28ad74487de9 c
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
102 +++ b/c Thu Jan 01 00:00:00 1970 +0000
103 @@ -0,0 +1,1 @@
103 @@ -0,0 +1,1 @@
104 +foo
104 +foo
105
105
106 `hg log`
106 `hg log`
107
107
108 $ hg log -r 28ad74
108 $ hg log -r 28ad74
109 changeset: 2:28ad74487de9
109 changeset: 2:28ad74487de9
110 user: test
110 user: test
111 date: Thu Jan 01 00:00:00 1970 +0000
111 date: Thu Jan 01 00:00:00 1970 +0000
112 obsolete: rewritten using amend as 3:2443a0e66469
112 obsolete: rewritten using amend as 3:2443a0e66469
113 summary: Added c
113 summary: Added c
114
114
115 `hg cat`
115 `hg cat`
116
116
117 $ hg cat -r 28ad74 c
117 $ hg cat -r 28ad74 c
118 foo
118 foo
119
119
120 `hg diff`
120 `hg diff`
121
121
122 $ hg diff -c 28ad74
122 $ hg diff -c 28ad74
123 diff -r 29becc82797a -r 28ad74487de9 c
123 diff -r 29becc82797a -r 28ad74487de9 c
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
125 +++ b/c Thu Jan 01 00:00:00 1970 +0000
126 @@ -0,0 +1,1 @@
126 @@ -0,0 +1,1 @@
127 +foo
127 +foo
128
128
129 `hg files`
129 `hg files`
130
130
131 $ hg files -r 28ad74
131 $ hg files -r 28ad74
132 a
132 a
133 b
133 b
134 c
134 c
135
135
136 `hg identify`
136 `hg identify`
137
137
138 $ hg identify -r 28ad74
138 $ hg identify -r 28ad74
139 28ad74487de9
139 28ad74487de9
140
140
141 `hg annotate`
142
143 $ hg annotate -r 28ad74 a
144 0: foo
145
141 `hg status`
146 `hg status`
142
147
143 $ hg status --change 28ad74
148 $ hg status --change 28ad74
144 A c
149 A c
145
150
146 `hg update`
151 `hg update`
147
152
148 $ hg up 28ad74
153 $ hg up 28ad74
149 updating to a hidden changeset 28ad74487de9
154 updating to a hidden changeset 28ad74487de9
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
151
156
152 $ hg up 3
157 $ hg up 3
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154
159
155 `hg revert`
160 `hg revert`
156
161
157 $ hg revert -r 28ad74 --all
162 $ hg revert -r 28ad74 --all
158 reverting c
163 reverting c
159
164
160 $ hg diff
165 $ hg diff
161 diff -r 2443a0e66469 c
166 diff -r 2443a0e66469 c
162 --- a/c Thu Jan 01 00:00:00 1970 +0000
167 --- a/c Thu Jan 01 00:00:00 1970 +0000
163 +++ b/c Thu Jan 01 00:00:00 1970 +0000
168 +++ b/c Thu Jan 01 00:00:00 1970 +0000
164 @@ -1,2 +1,1 @@
169 @@ -1,2 +1,1 @@
165 foo
170 foo
166 -bar
171 -bar
167
172
168 Commands with undefined cmdtype should not work right now
173 Commands with undefined cmdtype should not work right now
169
174
170 $ hg phase -r 28ad74
175 $ hg phase -r 28ad74
171 abort: hidden revision '28ad74'!
176 abort: hidden revision '28ad74'!
172 (use --hidden to access hidden revisions)
177 (use --hidden to access hidden revisions)
173 [255]
178 [255]
174
179
175 $ hg phase -r 2
180 $ hg phase -r 2
176 abort: hidden revision '2'!
181 abort: hidden revision '2'!
177 (use --hidden to access hidden revisions)
182 (use --hidden to access hidden revisions)
178 [255]
183 [255]
General Comments 0
You need to be logged in to leave comments. Login now